はやし雑記

はやしです

ナウいマジ卍なiOSアプリを作るためのAPNsまとめ (iOS10対応, 2018年2月)

ナウいマジ卍な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

GitHub - Pr0Ger/PyAPNs2: Python library for interacting with the Apple Push Notification service (APNs) via HTTP/2 protocol

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

にすれば消える