ナウいマジ卍なiOSアプリを作る上で欠かせないPush通知を実現する、Apple Push Notification Service: APNsについて、久しぶりに実装しようとしたら転がってる情報が古かったりアレなので備忘録的な感じで自分でまとめます
- 執筆日: 2018年2月18日
- 対象OS: iOS 10以降
通知許可のリクエスト
iOS 10で登場したUser Notifications Frameworkでリクエストをする
<Swift>iOS 10 User Notifications Framework実装まとめ - Qiita
import UserNotifications UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in print(granted, error ?? "error") }
DeviceTokenの取得
DeviceTokenの取得は、これをViewController#viewDidLoad
とかで呼んで
UIApplication.shared.registerForRemoteNotifications()
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined() print(token) }
ここで取れる
先の通知許可は、バナーを出すかどうかの許可なので、registerForRemoteNotifications
は通知の許可されているかどうかに関わらず走るし、DeviceTokenも取得できる
また、通知が不許可になっていてもバナーは出ないがAPNsは送れて、アプリが起動していれば(バックグラウンドでもフォアグラウンドでも、ただしcontent_available=1にしておかないと、バックグラウンドでは届かない)
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
が呼ばれてuserInfoにapns情報は入っている
テストでAPNsを送る
僕はPythonが好き
PyAPNs2は死んでいた(?)ので、PyAPNs2を使う
$ pip install apns2
from apns2.client import APNsClient from apns2.payload import Payload def app(): token = '1ec6097efd6b3fa7a1e147d86a4ba1643dc89da7f0786dc951512b3b7d1a86df' custom_payload = { "hoge": { "piyo": 1, "aaa": "bbb" } } payload = Payload(alert="Hello World!", sound="default", badge=1, content_available=True, custom=custom_payload) topic = 'com.hayashikun.TestApp' client = APNsClient('secret.pem', use_sandbox=True, use_alternative_port=False) client.send_notification(token, payload, topic) app()
これを送って、print
すると、
[AnyHashable("aps"): { alert = "Hello World!"; badge = 1; "content-available" = 1; sound = default; }, AnyHashable("hoge"): { aaa = bbb; piyo = 1; }]
こんな感じ
アプリを起動・フォアグラウンドにしても消えない通知を消す
通知エリアにバナーが表示されている状態で、バナーではなくホームからアプリアイコンタップで起動しても普通はバナーは消えないし、通知も取れない
通知エリアに残ってるとウザいから消したいときは
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
をすれば消えてくれる
ちなみにbadgeの数字は
UIApplication.shared.applicationIconBadgeNumber = 0
にすれば消える