[AWS/Swift4] AWS SNS + Cognito + iOS10でサーバレスでAPNsをpushする方法

AWS SNS + Cognito + iOS10でサーバレスでAPNsをpushする方法は以下の通り

環境:xcode9, swift4, iOS10

目次

APNs証明書の準備

まずは通常のAPNsと同じく、p12証明書を入手する

CSRファイルの作成

Mac上で「キーチェーンアクセス」を起動させ、メニューバーの「キーチェーンアクセス」→「証明書アシスタント」→「認証局に証明書を要求」をクリック

スクリーンショット 2017-12-29 0.37.31

要求の処理を「ディスクに保存」を選択して、場所はどこでもよいのでCSR証明書を保存

スクリーンショット 2017-12-29 0.39.15

開発用証明書(.cer)の作成

https://developer.apple.com/にアクセスし、「Certificates, Identifiers & Profiles」を開く

スクリーンショット 2017-12-29 0.44.17

「Certificates」→「All」をクリックして、「iOS App Development」にチェックをして、「Continue」→「Continue」をクリック

スクリーンショット 2017-12-29 0.45.49

 

先ほど作成したCSR証明書を選択して、「Continue」をクリック

スクリーンショット 2017-12-29 0.47.34

 

開発者用証明書が作成されるので、「Download」をクリックしてわかりやすい場所に保存しておく。

AppIDの作成

次は「Identifiers」→「AppIDs」をクリックして、右上の「+」をクリック

「Bundle ID」はXcodeで作成したアプリと同じものを指定。

スクリーンショット 2017-12-29 0.55.06

画面の下に「Push Notification」があるのでチェック

既にApp IDを作成している場合は、EditでPush Notificationにチェックを入れること

スクリーンショット 2017-12-29 0.56.25

 

テスト端末の登録

実機テストを行う端末を登録する

「Devices」→「All」をクリックして、右上の「+」をクリック

スクリーンショット 2017-12-29 1.00.19

 

一意の名前をテスト端末のUDIDを入力する。

スクリーンショット 2017-12-29 1.01.12

UDIDは端末をテスト端末が接続されている状態でxcodeを起動し、「Window」→「Devices and Simulators」を選択。端末情報が表示されるので、「identifer」を参照すること

スクリーンショット 2017-12-29 1.03.28

 

UDIDを入力したら、「Continue」をクリック、「Register」で登録する。

 

APNs Provisioning Profilesを作成

「Provisioning Profiles」→「All」をクリックして、右上の「+」をクリック

スクリーンショット 2017-12-29 1.06.42

 

App IDリストが表示されるので、該当アプリのApp IDを選択

証明書選択画面になるので、先程作成した開発用証明書を選択

次に端末リストが表示されるのでテスト用実機を選択

最後に証明書名を記入するので「アプリ名_dev」などの名前を付けるとわかりやすい

スクリーンショット 2017-12-29 1.11.20

「Download」をクリックして、わかりやすい場所に保存しておく。

 

APNs用証明書(.cer)の作成

「Certificates」→「All」をクリックして、右上の「+」をクリック

今度は「Apple Push Notification service SSL (Sandbox)」を選択

スクリーンショット 2017-12-29 1.16.37

AppIDとCSRファイルを選択

APNs用証明書(.cer)が作成されるので、「Download」をクリックしてわかりやすい場所に保存しておく

 

APNs用証明書(.p12)の作成

「APNs用証明書(.cer)」をダブルクリックで開く

キーチェーンアクセスが起動するので、先程ダブルクリックした証明書を探し、右クリック→「書き出す」を選択

スクリーンショット 2017-12-29 1.20.46

パスワードを求められるが空欄でも問題ない、もしパスワードを設定したら覚えておくこと。

APNs用証明書(.p12)が書き出されるので、わかり易い場所に保存しておくこと。

これで証明書関連の作業は終了

 

AWS SNSの設定

プラットフォームアプリケーションの作成

AWS SNSのコンソールを開き、「アプリケーション」→「プラットフォームアプリケーションの作成」を選択。

プラットフォームアプリケーションの作成画面では、以下のように設定する

アプリケーション名 適当に
プッシュ通知プラットフォーム Apple Development
p12ファイル 先程作成したp12ファイルをアップロード
プッシュ証明書タイプ iOSプッシュ証明書
パスワード 証明書を書き出す時に設定していれば

スクリーンショット 2017-12-29 9.45.04

入力したら、「認証情報をファイルから読み込み」をクリックすると「証明書」と「プライベートキー」欄に自動に値が入力される

「プラットフォームアプリケーションの作成」をクリックで確定。

スクリーンショット 2017-12-29 9.58.16

作成完了したら、プラットフォームアプリケーションのARNを控える。

 

トピックの作成

AWS SNSで「トピック」→「新しいトピックを作成」をクリック

トピック名と表示名に適当な名前を入力する

スクリーンショット 2017-12-29 9.56.51

 

作成されたトピックのARNを控える

スクリーンショット 2017-12-29 9.59.50

 

 

Cognitoの設定

フェデレーティッドアイデンティティの作成

AWS Cognitoを開き「フェデレーティッドアイデンティティ」→「新しいプールを作成」を選択

IDプール名を入力し、「認証されていないIDに対してアクセスを有効にする」にチェックを入れる。認証プロバイダーの入力は不要。

スクリーンショット 2017-12-29 10.03.10

IAMロールの追加を要求してくるので、そのまま「許可」を押す

作成されるロール名を覚えておくこと。

スクリーンショット 2017-12-29 10.05.39

「Amazon Cognito での作業開始」画面になるので、「プラットフォーム」を「ios – swift」を選択し、identityPoolIdを控える

SDKはあとでPodでインストールするので、この時はダウンロードしなくてよい。

スクリーンショット 2017-12-29 10.07.11

IAMの設定

AWSのIAMを開き、先程作成されたCognito用のUnauth用IAMにAWS SNSへのアクセスの許可ポリシーを追加する

これによりCognitoで受信したユーザデバイス情報をAWS SNSに渡すことができる。

先程作成されたCognito用のUnauth用IAMをクリック。2つできているはずなので「Unauth」の名前がついているものを選択すること。

スクリーンショット 2017-12-29 10.11.46

 

「アクセス権限」タブを開き、ポリシー名をクリックすると、JSONコードが表示されるので、「ポリシーの編集」をクリック

スクリーンショット 2017-12-29 10.14.04

おそらく、下記の図のようになっていると思われるので、「さらにアクセス許可を追加する」をクリック

スクリーンショット 2017-12-29 10.16.13

サービスにSNSを指定し、アクションは「すべて」を選択、リソースは「すべてのトピック」を指定した。

スクリーンショット 2017-12-29 10.17.23

確定をクリックして、変更を反映させる。

これでAWS側の設定は終了。

 

アプリ側設定

AWSSNSとAWSCognitoをインストール

PodFileに下記コードを追加し、pod installコマンドでモジュールをインストールする

target 'app name' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!

# Pods for app name
pod 'AWSSNS'
pod 'AWSCognito'

 

xcode上でNotificationを有効に

xcodeの「capabilities」でPush Notificationを有効にする。

スクリーンショット 2017-12-29 10.54.43

 

バックグラウンドでも通知を受け取ったら処理したい場合は「Background Modes」の「Remote notifications」も有効にしておく。

スクリーンショット 2017-12-29 10.56.34

 

AppDelegate.swiftにコードを追加

AppDelegate.swiftにコードを追加していく。

 

Import

AWSCognitoとAWSSNSをインポート

import AWSCognito
import AWSSNS
import UserNotifications

iOS10以上の場合はimport UserNotificationsも追記しておくこと

 

didFinishLaunchingWithOptions

didFinishLaunchingWithOptionsにユーザから通知の許可をもらうコードを追記

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
 // Override point for customization after application launch.
 
 // ユーザからPush Notification通知の許可をもらう
 if #available(iOS 10.0, *) {
 // iOS 10 以降の設定
 UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
 
 let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
 UNUserNotificationCenter.current().requestAuthorization(
 options: authOptions,
 completionHandler: {granted, error in
 if error != nil {
 // エラー時の処理
 return
 }
 if granted {
 // デバイストークンの要求
 UIApplication.shared.registerForRemoteNotifications()
 }
 })

 } else {
 // iOS 10 より前の設定
 let settings: UIUserNotificationSettings =
 UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
 application.registerUserNotificationSettings(settings)
 UIApplication.shared.registerForRemoteNotifications()

 }

 return true
 }

 

didRegisterForRemoteNotificationsWithDeviceToken

didRegisterForRemoteNotificationsWithDeviceTokenにTokenをAWSCognitoとAWS SNSに送信するコードを追記

先程AWS上で設定時に控えた「identityPoolId」や「アプリケーションARN」「トピックARN」を入力する

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
 //Tokenの文字成形
 var token = String(format: "%@", deviceToken as CVarArg) as String
 let characterSet: CharacterSet = CharacterSet.init(charactersIn: "<>")
 token = token.trimmingCharacters(in: characterSet)
 token = token.replacingOccurrences(of: " ", with: "")
 print("deviceToken: \(token)")
 
 // Initialize the Amazon Cognito credentials provider
 let credentialsProvider = AWSCognitoCredentialsProvider(regionType:.APNortheast1,
 identityPoolId:"先程作成したidentityPoolIdを追加")
 let configuration = AWSServiceConfiguration(region:.APNortheast1, credentialsProvider:credentialsProvider)
 AWSServiceManager.default().defaultServiceConfiguration = configuration
 
 let sns = AWSSNS.default()
 let request = AWSSNSCreatePlatformEndpointInput()
 request?.token = token
 request?.platformApplicationArn = "先程作成したAWS SNSのアプリケーションARNを追加"
 request?.customUserData = "Memo"
 
 sns.createPlatformEndpoint(request!).continueWith(executor: AWSExecutor.mainThread(), block: { (task: AWSTask!) -> AnyObject! in
 if task.error != nil {
 print("Error: \(task.error)")
 } else {
 let result = task.result as! AWSSNSCreateEndpointResponse
 let subscribeInput = AWSSNSSubscribeInput()
 subscribeInput?.topicArn = "先程作成したAWS SNSのトピックARNを追加"
 subscribeInput?.endpoint = result.endpointArn
 subscribeInput?.protocols = "Application"
 sns.subscribe(subscribeInput!)
 
 //self.saveEndpointArn(result.endpointArn)
 }
 return nil
 })
 }

 

通知受信時のコードを追加

iOS9以前であれば、以下のコードを追加

//iOS9以前の通知メソッド
 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
 // アプリが起動している間に通知を受け取った場合の処理を行う。
 print("didReceiveRemoteNotification")
 print(userInfo)
 if application.applicationState == .active {
 //write your code here when app is in foreground
 print("get the push notification on foreground")
 } else {
 //write your code here for other state
 print("get the push notification on foreground in other")
 }
 }
 
 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
 // アプリがバックグラウンド状態の時に通知を受け取った場合の処理を行う。
 print("get the push notification on background")
 completionHandler(UIBackgroundFetchResult.newData)
 }
 
 func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
 // システムへのプッシュ通知の登録が失敗した時の処理を行う。
 print("fail to push notification")
 }

iOS10以上であれば、以下のコードを追加

@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
 
 // iOS 10 以降では通知を受け取るとこちらのデリゲートメソッドが呼ばれる。
 //foreground
 func userNotificationCenter(_ center: UNUserNotificationCenter,
 willPresent notification: UNNotification,
 withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
 print("notification is \(notification)")
 //write your action here
 completionHandler(UNNotificationPresentationOptions.alert)
 }
 
 //background
 func userNotificationCenter(_ center: UNUserNotificationCenter,
 didReceive response: UNNotificationResponse,
 withCompletionHandler completionHandler: @escaping () -> Void) {
 print("response is \(response)")
 //write your action here
 completionHandler()
 }
}

completionHandler(UNNotificationPresentationOptions.alert)でフォアグラウンドでもアラートを表示することができる

 

アプリを起動して、通知許可を行うとAWS SNSのアプリケーション上にデバイスが登録されているのが確認できる

スクリーンショット 2017-12-29 11.07.57

 

AWS SNSで通知の発行

AWS SNSのアプリケーションを選択して、通知を発行したいエンドポイントを選択し、「エンドポイントへの発行」をクリック

メッセージはJSON形式で送信する。「JSON message generator」で作成するのがカンタン。

準備ができたら「メッセージの発行」で通知送信

 

スクリーンショット 2017-12-29 11.09.27

すべての設定がうまく行っていれば、テストデバイスに通知が届き、ログにも表示されるはず。

 

 

Product Push Notificationの設定

キーチェーンアクセスでdevelopmentで使用した証明書とは別に再度認証機関に証明書を要求する。

https://developer.apple.com/にアクセスし、「Certificates, Identifiers & Profiles」を開く

iOS Provisioning ProfilesのiOS Distribution版を作成

「Certificates」でApple Push Servicesを作成。APNs用証明書(.cer)をダウンロード

APNs用証明書(.cer)をダブルクリック、対象APNs用証明書(.cer)からp12証明書を書き出し

AWS SNSで新しいアプリケーションを作成し、証明書に先程のp12証明書を設定。

AWS SNSのアプリケーションARNをswift上のアプリケーションARNと入れ替える。

以上。

 

One thought on “[AWS/Swift4] AWS SNS + Cognito + iOS10でサーバレスでAPNsをpushする方法

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です