AWS CognitoとAWS SNSでDBレスで構築するiOS向けPush Notification



# iOS関連  
## iOSの開発用証明書を作成

Apple Developerのページに移動する。
https://developer.apple.com/account/

![iosdev001.png](https://qiita-image-store.s3.amazonaws.com/0/63450/8a90a2b6-d12e-7171-6ace-86ccde15e386.png)

Certificates, IDs & Profilesのページに移動。

![iosdev002.png](https://qiita-image-store.s3.amazonaws.com/0/63450/b366ae02-8d1e-da8e-5d72-915aa4b541a6.png)

CertificationのDevelopmentから、[+]を選択し、今回使用する証明書を作成する。

![apple001.png](https://qiita-image-store.s3.amazonaws.com/0/63450/7d60c74e-7d95-e3a8-6bf5-cde847d76969.png)

今回は、開発用の証明書を作成する。
"Apple Push Notification service SSL(Sandbox)"
を選択する。

![apple002.png](https://qiita-image-store.s3.amazonaws.com/0/63450/1e9eacd7-4799-b900-7e97-6c0dd79b1265.png)

App IDを選択する。各アプリのBundle identifierを元に、事前に作成しておく。

![apple003.png](https://qiita-image-store.s3.amazonaws.com/0/63450/45f6b0c5-ab10-1e4f-8b67-4485325f35d4.png)

![apple004.png](https://qiita-image-store.s3.amazonaws.com/0/63450/30f680a5-48ed-2306-bf12-193067bcd479.png)

[アプリケーション]-[ユーティリティ]から、キーチェーンアクセスを起動する。

![key001.png](https://qiita-image-store.s3.amazonaws.com/0/63450/649c02bb-198e-e063-9a47-b2ccd60b7775.png)

[キーチェーンアクセス]-[証明書アシスタント]-[認証局に証明書を要求]を選択。

![key002.png](https://qiita-image-store.s3.amazonaws.com/0/63450/473dea9d-b7f6-ecf5-d965-149ec3e29cd4.png)

ユーザのメールアドレス、通称を編集し、ディスクに保存を選択。証明書関係は、日本語は一切使わないようにする。日本語を使うと、AWS SNSでうまく読み込めなくなる。

![key003.png](https://qiita-image-store.s3.amazonaws.com/0/63450/b33e6cfb-695c-0b07-1e51-794d93094b9a.png)

証明書要求を保存。ファイル名にも日本語は使わない。

![key004.png](https://qiita-image-store.s3.amazonaws.com/0/63450/72df5a2c-2521-3fe2-a363-ccf9891fef80.png)

![key_finish.png](https://qiita-image-store.s3.amazonaws.com/0/63450/f3680740-379d-df39-c2cc-46da3c3e09bb.png)

CertificateSigningRequest.certSigningRequest が生成されるので、再び、iOS Dev Centerに戻り、Upload CSR fileに、今作成したCSRを選択する。

![apple005.png](https://qiita-image-store.s3.amazonaws.com/0/63450/d6469080-3ed5-3b8b-0b77-80503993aee4.png)

証明書が生成されるので、[Download]でローカルに保存し、ダブルクリックし[キーチェーンアクセス]に追加する。

![push_002.png](https://qiita-image-store.s3.amazonaws.com/0/63450/148f857d-f456-41b6-4fc4-170d31af5844.png)


[キーチェーンアクセス]に先ほど作成した証明書が追加される。

![key005_002.png](https://qiita-image-store.s3.amazonaws.com/0/63450/e11803e6-ea17-38d4-f394-afb4392ce7e4.png)

P12形式のファイルを生成書き出す。

![key006.png](https://qiita-image-store.s3.amazonaws.com/0/63450/3d83a948-6c27-b23d-ec0e-638716d3ba46.png)

ファイル名には日本語は使わない。

![key007.png](https://qiita-image-store.s3.amazonaws.com/0/63450/c5573cfc-4985-d1db-4449-314668dbaa6a.png)

# AWS関連
## AWS SNSの設定

リージョンを確認し、SNSを選択する。

![sns001.png](https://qiita-image-store.s3.amazonaws.com/0/63450/d1bb8273-7dc4-240f-71e8-8a8041e8c985.png)

Application Platformを新規で作成するために、Applicationを選択。

![sns002.png](https://qiita-image-store.s3.amazonaws.com/0/63450/a1f4717b-f4b6-2dd5-cfd9-6b5b7e5d9e23.png)

[Create Platform Application]でPlatform Applicationを作成する。

![awssns003.png](https://qiita-image-store.s3.amazonaws.com/0/63450/010e48e3-740f-cd54-55e3-e64c69d96e84.png)

Application名は任意の名称、Push Notification Platformは、Apple Developmentを選択。Choose P12 Fileの箇所で先ほど作成したP12ファイルを選択し、Load Credentials from Fileを選択する。

![awssns004.png](https://qiita-image-store.s3.amazonaws.com/0/63450/7d36c0cf-e620-2b82-d5e9-45772cb493d4.png)

Application Platformが作成される。アクセスする際は、ARNをアプリ等で使用する。

![awssns005.png](https://qiita-image-store.s3.amazonaws.com/0/63450/2b178715-66c8-4e2e-b07d-126aac7c24c8.png)

[Topics]をから、Create new topicを選択し、 Topicを作成する。

![awssns006.png](https://qiita-image-store.s3.amazonaws.com/0/63450/4c3149d6-9f21-7443-fe9f-d5562fea64a3.png)

![awssns007.png](https://qiita-image-store.s3.amazonaws.com/0/63450/db58b1dd-1a7e-1d5a-b549-f5172e2cebc6.png)

Topicで生成されたArnは、Topic Arnとして、Topicの呼び出しに使用する。

![awssns008.png](https://qiita-image-store.s3.amazonaws.com/0/63450/4f75931d-3465-c399-7520-4d1543c3fe3c.png)

## AWS Cognitoの設定

![awscognito001.png](https://qiita-image-store.s3.amazonaws.com/0/63450/ad2cb367-0b54-8285-6efb-fdd941bb2099.png)

![awscognito002.png](https://qiita-image-store.s3.amazonaws.com/0/63450/3d6876bf-3eec-77bb-bcbc-e8445a5a4de6.png)

![awscontigo003.png](https://qiita-image-store.s3.amazonaws.com/0/63450/0edea074-9f41-666b-60e2-eec8dbde2fb6.png)

![awscontigo004.png](https://qiita-image-store.s3.amazonaws.com/0/63450/500542cf-d230-3871-a93a-f5bf5329c5c5.png)

![awscognito007.png](https://qiita-image-store.s3.amazonaws.com/0/63450/d72be291-3978-2009-6e88-777302245d05.png)

![awsiam001.png](https://qiita-image-store.s3.amazonaws.com/0/63450/ff40ddf5-51a0-cb4f-6486-a8663a637be8.png)

![cognito_plus.png](https://qiita-image-store.s3.amazonaws.com/0/63450/3d04b4fd-45b7-67c3-37d8-72b7a6ccf977.png)


![awsiam003.png](https://qiita-image-store.s3.amazonaws.com/0/63450/1682b7a2-9927-75c8-d55e-d52a55ca6186.png)

![awsiam004.png](https://qiita-image-store.s3.amazonaws.com/0/63450/e30debcd-3114-f2f7-adcc-b21662272750.png)

![awsim005.png](https://qiita-image-store.s3.amazonaws.com/0/63450/6090a785-9f33-c3c4-58ff-1537b0568f27.png)

# Swift

## CocoaPod

```
pod 'AWSSNS'
pod 'AWSCognito'
```

> $ pod install

## importするライブラリ

```
import CoreData
import AWSCognito
import AWSSNS
```

## UserからPushの許可をもらう
```swift:AppDelegate.swift
     func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        
        // ユーザからPush Notification通知の許可をもらう
        let types: UIUserNotificationType = [UIUserNotificationType.Badge, UIUserNotificationType.Alert, UIUserNotificationType.Sound]
        let settings: UIUserNotificationSettings = UIUserNotificationSettings( forTypes: types, categories: nil )
        
        application.registerUserNotificationSettings( settings )
        application.registerForRemoteNotifications()
        
        return true
    }
```

## Tokenを登録

```swift:AppDelegate.swift
 // Device Token を取得
    func application( application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData ) {
    
        // <>と" "(空白)を取る
        let characterSet: NSCharacterSet = NSCharacterSet( charactersInString: "<>" )
        
        // Device Tokeの取得
        let deviceTokenString: String = ( deviceToken.description as NSString )
            .stringByTrimmingCharactersInSet( characterSet )
            .stringByReplacingOccurrencesOfString( " ", withString: "" ) as String
     
        // Initialize the Amazon Cognito credentials provider
        let credentialsProvider = AWSCognitoCredentialsProvider(regionType:.APNortheast1,
                                                                identityPoolId:"Identity Pool IDを記載")
        let configuration = AWSServiceConfiguration(region:.APNortheast1, credentialsProvider:credentialsProvider)
        AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
        
        let sns = AWSSNS.defaultSNS()
        let request = AWSSNSCreatePlatformEndpointInput()
        request.token = deviceTokenString
        request.platformApplicationArn = "Application Arnを記載"
        request.customUserData = "Memo"

        sns.createPlatformEndpoint(request).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: { (task: AWSTask!) -> AnyObject! in
            if task.error != nil {
                print("Error: \(task.error)")
            } else {
                let result = task.result as! AWSSNSCreateEndpointResponse
                let subscribeInput = AWSSNSSubscribeInput()
                subscribeInput.topicArn = "Topic Arnを記載"
                subscribeInput.endpoint = result.endpointArn
                subscribeInput.protocols = "Application"
                sns.subscribe(subscribeInput)
                
                self.saveEndpointArn(result.endpointArn)
            }
            return nil
        })
}
```

## Pushを受信

```swift:AppDelegate.swift
// プッシュを受け取ったとき
    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
        log.debug("UserInfo:\(userInfo)")
        let appState: UIApplicationState = application.applicationState;
        var appStateString: String = "";
        if (appState == .Active) {
            appStateString = "active";
        } else if (appState == .Inactive) {
            appStateString = "inactive";
        } else if (appState == .Background) {
            appStateString = "background";
        }
        
        let notifiAlert = UIAlertView()
        if let aps = userInfo["aps"] as? NSDictionary {
            let msg: NSString = aps["alert"] as! NSString
            notifiAlert.title = "PushTest"
            notifiAlert.message = msg
            notifiAlert.addButtonWithTitle("OK")
            notifiAlert.show()
        }
    }

```

## Pushのフォーマット

```xml:RemotePush
{
"APNS_SANDBOX":"{\"aps\":{\"alert\":\"test\"}}"
}
```


```xml:SilentPush
{
"APNS_SANDBOX":"{\"aps\":{\"content-available\":\"1\"}}"
}
```

## Remote Push Payload

The Remote Notification Payload
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH107-SW1