2015-10-31

バックグラウンドの Location update で、local notification を出す iOS アプリ

移動中に、地理的な条件によって、ユーザーに指示をだす iOS アプリを作ろとうしている。

地理的な位置を管理する CoreLocation サービスは、バックグラウンドでも動き続けるので、これを使うことにした。いろいろ情報があったけれど、集約してひとつのアプリとして動かすのに時間がかかったのでメモしておく。


  • XCode Version 7.1 (7B91b) on OS X El Capitan 10.11.1
  • Xcode で File → New → Project → iOS Application → Single View Application
  • CoreLocation framework をプロジェクトに追加
  • Background の "Location updates" を有効にする
  • info.plist に NSLocationAlwaysUsageDescription キーを追加。値はユーザーに許可を求めるときの文字列。
  • この例では ViewController.swift には触らない。けれど、以下のコードを ViewController クラスに実装しても動く。
  • AppDelegate.swift を以下のように編集する

import UIKit
import CoreLocation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
    var window: UIWindow?
    lazy var locationManager: CLLocationManager! = {
        let manager = CLLocationManager()
        manager.desiredAccuracy = kCLLocationAccuracyBest
        manager.pausesLocationUpdatesAutomatically = false
        manager.allowBackgroundLocationupdates = true
        manager.delegate = self
        manager.requestAlwaysAuthorization()
        return manager
    }()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        let settings = UIUserNotificationSettings(forTypes: [.Alert], categories: nil)
        UIApplication.sharedApplication().registerUserNotificationSettings(settings)
        locationManager.startUpdatingLocation()
        return true
    }

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let cond = true  // 何か条件判定をいれる。常に true だと通知しまくるので注意。
        if cond == true {
            let notification = UILocalNotification()
            notification.alertBody = "Hello"
            UIApplication.sharedApplication().presentLocalNotificationNow(notification)
        }
    }
    // 他のメソッドはそのまま触らない
}

allowBackgroundLocationupdates を true にすることに気づかなくて長い時間を費やしてしまったデフォルトの false のときアプリが foreground と background のときにはデリゲート関数が呼ばれるけれどsuspend 状態では呼ばれないなので最初は通知が出るがしばらくすると出ないという現象が起こるそのように見えた気がする

ざっとでもいいから、ドキュメントを読む癖をつけねば。