[AWS/Swift4] AWS SNS + Cognito + iOS10でサーバレスでAPNsをpushする方法
AWS SNS + Cognito + iOS10でサーバレスでAPNsをpushする方法は以下の通り
環境:xcode9, swift4, iOS10
目次
APNs証明書の準備
まずは通常のAPNsと同じく、p12証明書を入手する
CSRファイルの作成
Mac上で「キーチェーンアクセス」を起動させ、メニューバーの「キーチェーンアクセス」→「証明書アシスタント」→「認証局に証明書を要求」をクリック

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

開発用証明書(.cer)の作成
https://developer.apple.com/にアクセスし、「Certificates, Identifiers & Profiles」を開く

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

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

開発者用証明書が作成されるので、「Download」をクリックしてわかりやすい場所に保存しておく。
AppIDの作成
次は「Identifiers」→「AppIDs」をクリックして、右上の「+」をクリック
「Bundle ID」はXcodeで作成したアプリと同じものを指定。

画面の下に「Push Notification」があるのでチェック
既にApp IDを作成している場合は、EditでPush Notificationにチェックを入れること

テスト端末の登録
実機テストを行う端末を登録する
「Devices」→「All」をクリックして、右上の「+」をクリック

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

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

UDIDを入力したら、「Continue」をクリック、「Register」で登録する。
APNs Provisioning Profilesを作成
「Provisioning Profiles」→「All」をクリックして、右上の「+」をクリック

App IDリストが表示されるので、該当アプリのApp IDを選択
証明書選択画面になるので、先程作成した開発用証明書を選択
次に端末リストが表示されるのでテスト用実機を選択
最後に証明書名を記入するので「アプリ名_dev」などの名前を付けるとわかりやすい

「Download」をクリックして、わかりやすい場所に保存しておく。
APNs用証明書(.cer)の作成
「Certificates」→「All」をクリックして、右上の「+」をクリック
今度は「Apple Push Notification service SSL (Sandbox)」を選択

AppIDとCSRファイルを選択
APNs用証明書(.cer)が作成されるので、「Download」をクリックしてわかりやすい場所に保存しておく
APNs用証明書(.p12)の作成
「APNs用証明書(.cer)」をダブルクリックで開く
キーチェーンアクセスが起動するので、先程ダブルクリックした証明書を探し、右クリック→「書き出す」を選択

パスワードを求められるが空欄でも問題ない、もしパスワードを設定したら覚えておくこと。
APNs用証明書(.p12)が書き出されるので、わかり易い場所に保存しておくこと。
これで証明書関連の作業は終了
AWS SNSの設定
プラットフォームアプリケーションの作成
AWS SNSのコンソールを開き、「アプリケーション」→「プラットフォームアプリケーションの作成」を選択。
プラットフォームアプリケーションの作成画面では、以下のように設定する
| アプリケーション名 | 適当に |
| プッシュ通知プラットフォーム | Apple Development |
| p12ファイル | 先程作成したp12ファイルをアップロード |
| プッシュ証明書タイプ | iOSプッシュ証明書 |
| パスワード | 証明書を書き出す時に設定していれば |

入力したら、「認証情報をファイルから読み込み」をクリックすると「証明書」と「プライベートキー」欄に自動に値が入力される
「プラットフォームアプリケーションの作成」をクリックで確定。

作成完了したら、プラットフォームアプリケーションのARNを控える。
トピックの作成
AWS SNSで「トピック」→「新しいトピックを作成」をクリック
トピック名と表示名に適当な名前を入力する

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

Cognitoの設定
フェデレーティッドアイデンティティの作成
AWS Cognitoを開き「フェデレーティッドアイデンティティ」→「新しいプールを作成」を選択
IDプール名を入力し、「認証されていないIDに対してアクセスを有効にする」にチェックを入れる。認証プロバイダーの入力は不要。

IAMロールの追加を要求してくるので、そのまま「許可」を押す
作成されるロール名を覚えておくこと。

「Amazon Cognito での作業開始」画面になるので、「プラットフォーム」を「ios – swift」を選択し、identityPoolIdを控える
SDKはあとでPodでインストールするので、この時はダウンロードしなくてよい。

IAMの設定
AWSのIAMを開き、先程作成されたCognito用のUnauth用IAMにAWS SNSへのアクセスの許可ポリシーを追加する
これによりCognitoで受信したユーザデバイス情報をAWS SNSに渡すことができる。
先程作成されたCognito用のUnauth用IAMをクリック。2つできているはずなので「Unauth」の名前がついているものを選択すること。

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

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

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

確定をクリックして、変更を反映させる。
これで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を有効にする。

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

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のアプリケーション上にデバイスが登録されているのが確認できる

AWS SNSで通知の発行
AWS SNSのアプリケーションを選択して、通知を発行したいエンドポイントを選択し、「エンドポイントへの発行」をクリック
メッセージはJSON形式で送信する。「JSON message generator」で作成するのがカンタン。
準備ができたら「メッセージの発行」で通知送信

すべての設定がうまく行っていれば、テストデバイスに通知が届き、ログにも表示されるはず。
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と入れ替える。
以上。
Pingback: [aws/php] AWS SDK for PHP + AWS SNSを使用してAPNsをiOSデバイスに送信する方法 | BlueBear I/O