すっさんぽ
  1. Posts/

[iOS] バックグラウンドプッシュのセットアップと実装するメソッドまとめ

·

iOSには、バックグラウンドプッシュやサイレントプッシュと呼ばれる、ポップアップなどのユーザー通知を伴わない通知方法があります。 今回はその、バックグラウンドプッシュを実現する方法をまとめます。

事前準備 #

プッシュ通知のセットアップを行います。 以前投稿した「プッシュ通知のセットアップから実装するメソッドまとめ」の内容を済ませておきます。なお、バックグラウンドプッシュだけ対応する場合は、ユーザー通知の許可を求める必要はありません。

準備が済んだら、バックグラウンドプッシュに対応していきます。

CapabilityにBackground Modeを追加する #

ここから先は、Appleの公式ドキュメントを参考にしながら進めていきます。

まず、アプリのターゲットのCapabilityに「Background Mode」を追加します。このCapabilityには複数のモードが用意されていますが、今回は「Remote notifications」をチェックします。これを有効化ことで、プッシュ通知を受け取ったときに、アプリをバックグランドで起動できるようになります。

プッシュ通知を受け取ったときの処理を実装する #

プッシュ通知を受信すると、UIApplicationDelegateのapplication(_:didReceiveRemoteNotification:fetchCompletionHandler:)メソッドが呼ばれます。AppDelegateで、以下のような実装を行います。

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    // 以下は、通常UNUserNotificationCenter.current().requestAuthorizationでauthorizedになったときに行う処理だが、
    // ユーザー通知の許可がなくても、Remote Notificationへの登録はできる
    UIApplication.shared.registerForRemoteNotifications()
}

func application(_ application: UIApplication,
                 didReceiveRemoteNotification userInfo: [AnyHashable : Any],
                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    // ユーザー通知の許可がなくても、Remote Notificationを受信したらここが実行される。
    // Remote Notificationのペイロードに `"content-available": 1` が入っていると、バックグラウンドからここが呼ばれる

    // UserNotificationCenterDelegateも実装していた場合、
    // アプリがフォアグラウンドで実行中は、
    // このメソッドと合わせて、`userNotificationCenter(_:willPresent:withCompletionHandler:)`も呼ばれる。
    // → 処理が重複しないように注意する必要がある
    // → バックグラウンド判定には、UIApplication.shared.applicationState == .background が使えそう

    // ここで処理する内容は、
    // userInfoからカスタムペイロードを取り出したり……
    let isNewDataAvailable = userInfo["new-data-available"] as! Bool
    // UserDefaultsにセットして、次回の起動時にフェッチさせるようにしたり……
    UserDefaults.standard.set(isNewDataAvailable, forKey: "new-data-available")
    // サーバと同期したり
    if isNewDataAvailable {
        let remote = MyServiceRepository()  // あくまでサンプル
        let newData = remote.fetch()  // 非同期処理しているとする
        MyLocalStorage().setApplicationData(newData)
    }

    // そして30秒以内に、completionHandlerを呼ぶ(必須)
    completionHandler(.newData)
}

受信したプッシュ通知のペイロードに "content-available": 1が含まれているとき、アプリが suspended, background でも、このメソッドが呼び出されます。ただし、ユーザーがアプリをキルしていた場合は起動しません。

また、バックグラウンドでこのメソッドが呼ばれた場合、アプリに許可された処理時間は30秒です。 30秒以内に、completionHandlerを呼ばなければなりません。

プッシュ通知のペイロードの例 #

以下のように、aps内に"content-available": 1が含まれていると、バックグラウンドでアプリが起動します。

{
    "aps":{
      "alert" : {
         "title" : "Game Request",
         "subtitle" : "Five Card Draw",
         "body" : "Bob wants to play poker"
      },
      "badge" : 0,
      "sound" : "default",
      "content-available": 1
    }
}

ペイロードの作成方法は、以下のドキュメントあたりが参考になります。


まとめ #

iOSアプリのバックグラウンド通知の実現方法について、そのセットアップ方法と実装するメソッドを記載しました。 バックグラウンドプッシュは、ユーザーへの通知を伴わずに、アプリに対してデータを送ることができます。 工夫次第でいろんな活用方法があります。例えば、サーバとの事前同期であったり、次回起動時の変数をセットしたり、キャッシュクリアのためのフラグを立てたりするなどです。

新規アプリなら初期から対応しておくと、何かと便利なことが多いでしょう。まずは初期のバージョンからバックグラウンド通知だけは対応させて、APNsへの登録・Remote NotificationのTokenの収集はしておくと良さそうです。 ユーザー通知の許可がなくてもAPNsへの登録は可能なので、ここまでは済ませておくと都合が良いでしょう。

さて次回は、Notification Service Extensionを使用して、ユーザーへの通知表示前に処理を差し込む方法をまとめます。