BLOG

ブログ

2021/08/23 技術系

iOSでのPush通知について

この記事を書いた人 T.O

はじめまして、T.Oと申します。
業務でiOSでのPush通知の機能を実装した際に、学んだことについて
備忘録をかねてご紹介いたします。
検証環境は以下の通りです。

  • macOS Big Sur 11.4
  • Xcode 12.5.1
  • iOS14.3

Push通知の仕組み

iOSのPush通信では、APNs(Apple Push Notification)にデバイストークンを送信し、
Push要求を行うことでメッセージを端末に配信する仕組みになっています。

リクエストの流れ

  1. APNsサーバにデバイス登録を行いAPNsサーバからデバイストークンを発行する
  2. Push通知の配信要求を行うサーバ(FirebaseやMicrosoft Azureなど)にデバイストークンを登録する
  3. APNsサーバにPush要求を行う
  4. リクエストされたデバイストークンが登録されている端末に、APNsサーバからPush通知を送信する

Push証明書

Push通知を行う際に、APNsとの認証でp12形式の証明書もしくは、
p8形式の証明書が必要になってきます。
この二つの方式の違いについてみてみましょう。

今回は、証明書の作成方法については省略します。
以下のリンクに証明書の作成手順の参考となる情報を載せておきます。
p12証明書作成方法
p8形式証明書作成方法

p12形式の証明書

  • App ID単位で管理する
  • 本番環境と開発環境で別々に証明書を発行する必要がある
  • 年1年で証明書を更新する必要がある
  • 証明書自体を再ダウンロード可能

p8形式の証明書

  • Apple Developer Programで登録しているApple IDで管理している全てのアプリで使用可能
  • 本番環境と開発環境で同じ証明書を使用できる
  • 有効期限は無期限
  • 証明書は一度しかダウンロードできない(再度作成することは可能)
  • 一つのApple IDで2つまでしか証明書を作成できない

違いをまとめてみましたが、証明書の管理の点でp8形式の証明書のほうが優れている印象です。
Push送信サービスによっては、p12証明書にしか対応してない場合もあるので、 用途に応じて
使いわけるほうが良さそうです。

Push通知

通常のPush通知とVoIPによるPush通知の2種類があります。
通常のPush通知を受け取りたい場合は、通常Push通知で問題ないのですが、
VoIPサービスで電話を受信する機能を実装する場合は、VoIPPush通知で実装する必要があります。

通常Push通知

Push通知の登録時の処理
import UserNotifications

...

func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    // 通知の使用許可をリクエスト
    let center = UNUserNotificationCenter.current()
    center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in

        if((error) != nil) {
          return
        }

        guard granted else { return }
            
       // ユーザが通知の使用を許可してた場合APNsサーバにデバイスを登録
            DispatchQueue.main.async {
                UIApplication.shared.registerForRemoteNotifications()
            }
        }
        return true
}
通知時の処理
extension AppDelegate {
    func application(_ application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        // APNsへのデバイス登録成功時に呼ばれる

        // デバイストークンを取得する
        let tokenBytes = deviceToken.map { (byte: UInt8) in String(format: "%02.2hhx", byte) }
        NSLog("Device token: \\\\(tokenBytes.joined())")
    }

    func application(_ application: UIApplication,
                     didFailToRegisterForRemoteNotificationsWithError error: Error) {

        // APNsへのデバイス登録失敗時に呼ばれる
        NSLog("Failed to register to APNs: \\\\(error)")
    }

    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
        
     // Push通知が届いた際に呼ばれる
        NSLog("Received notification : \\\\(userInfo)")
    }
}

Notificationsフレームワークを利用するのでUserNotificationsをimportします。
アプリの起動時に、ユーザが通知の使用を許可した場合のみに、APNsサーバにデバイスを登録する。
APNsへの登録後に呼ばれるコールバックを実装することで、Push通知の受信が可能になります。

VoIPPush通知

VoIPのPush通知を受信するには、PushKitライブラリを使用することでVoIP通信を使用して
Push通知を受け取ることができます。
通知を受けた際標準電話アプリのUIの表示をCallKitライブラリを使うことで可能になります。
これらを組み合わせることで通話機能を持ったアプリが作成できます。
今回はCallKitライブラリの使用方法は省略します。

デバイス登録時の処理
import PushKit

...

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
				// PushRegistryの初期化
        // APNsサーバにデバイスを登録
        let voipRegistry: PKPushRegistry = PKPushRegistry(queue: .main)
        voipRegistry.delegate = self
        voipRegistry.desiredPushTypes = [PKPushType.voIP]
        return true
 }

VoIP通知時の処理
extension AppDelegate: PKPushRegistryDelegate {
    func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {		        // デバイストークンを取得する
				
     // ここでPush通知サーバ等にデバイストークンを送信させる
        let newToken = credentials.token.map { String(format: "%02.2hhx", $0) }.joined()
	        NSLog("token:\\\\(newToken)")
		}
    func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
        // Push通知設定を無効にした時に呼ばれる
    }

    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
        
     // VoIPのPush通知が届いた時に呼ばれる
				NSLog("pushRegistry type:\\\\(type) payload:\\\\(payload.dictionaryPayload)")
    }
}

PushKitをimportしPushRegistryを利用してAPNsサーバにデバイスを登録を登録し
PKPushRegistryDelegateを継承してPush通知サーバや Push通知時の処理を実装します。

参考

iOSにおけるPush通知の基本1(通知の受信まで)
プッシュ通知の仕組み
Responding to VoIP Notifications from PushKit
Implementing VoIP push notifications using PushKit

アーカイブ