のぴぴのメモ

自分用のLinuxとかの技術メモ

Amazon SNSとiOSでモバイルプッシュを試してみる

検証環境のモバイルプッシュ通知の流れ

Appleのプッシュ通知サービス

Apple製品のプッシュ通知は、Apple Push Notification Service(APNs)と呼ばるAppleが提供するプッシュ通知サービスを利用して各デバイスにプッシュ通知を送ります。*1

プッシュ通知をする時は、Provider(要はサーバ)からAPNsに要求を送り、要求を受けたAPNsが指定されたデバイスにプッシュ通知を送付します。ProviderからAPNsへの要求では、通知先のデバイスの情報(デバイストークンという、デバイス+アプリの組み合わせで一意に生成されるトークン)とプッシュ通知の内容を送ります。

f:id:nopipi:20190216233223p:plain:w400

Amazon SNSモバイルプッシュとは

Amazon Simple Notification Service(SNS)の機能の一つで、様々な種類のモバイルデバイスのアプリケーションにプッシュ通知メッセージを送付するための抽象化されたサービスです。*2

先ほどのAppleのプッシュ通知の概要図のProvider部分を担うサービスになります。

f:id:nopipi:20190216234056p:plain:w400

プッシュ通知の流れ

プッシュ通知は大きく、(1)デバイストークンの取得と、(2)プッシュ通知の実行、に区分されます。ここではこの記事で作成する検証環境でのプッシュ通知の流れを説明します。

f:id:nopipi:20190206042218p:plain:w500

  1. バイストークンの取得(下図の緑吹き出し)
    1. iOSで検証用アプリケーションでAPNsからデバイストークンを取得
      1. バイストークンは、デバイスとアプリの組み合わせで一意に生成されるトークンです
      2. バイストークンはAppleのドキュメントでは、アプリ起動毎に取得することが推奨されてます*3
    2. 取得したデバイストークンをSNSに登録
  2. プッシュ通知(下図のオレンジ吹き出し)
    1. アプリケーションからSNSに通知の実行を指示(publish)
    2. SNSは、APNsにプッシュ要求を送付
    3. 要求を受けたAPNsは、指定されたデバイスにプッシュを通知

開発環境

この記事でのアプリケーション開発環境は以下の通りです

  • 開発言語: Swift(Swift4.2)
  • Xcode: Version 10.1 (10B61)
  • OS: macOS Mojave 10.14.3

クライアントアプリケーションの開発と実行

APNs設定

クライアントアプリケーションの開発前に、APNsへの設定が必要になります(APNsへの登録には、Apple Developer Programへの登録(有償)が必要です)。下記の記事を参考にAPNsの設定を行い、開発用プロビショニングプロファイルと、NotificationsのSSL証明書作成と登録、を準備してください。
nopipi.hatenablog.com

簡易クライアントアプリ作成

ここでは、プッシュ通知に必要となるDeviceTokenをAPNsから取得するのみの簡易的なアプリを作成します。

取得したDeviceTokenは、この検証環境ではXcodeのデバイスコンソールにログ出力させた上で手動でSNSに登録させます。(本来はサーバを立ててそのサーバに通知させてSNS登録させます)

Xcodeでプロジェクトを作成しセッティングする

まずはXcodeでSwift開発のプロジェクトを作成して、必要なセッティングをします。

  • (1) プロジェクトの作成
    • Xcodeを起動し"Create a new Xcode project"を選択します。

f:id:nopipi:20190216191753p:plain:w450

  • (2) テンプレートの選択
    • シンプルな”Single View App”を選択します。

f:id:nopipi:20190216191806p:plain:w450

  • (3) プロジェクトの設定
    • プロジェクトの設定を行います。注意しなければならないのは、以下の3点です。
      • Organization Name: APNs登録で作成した「iOSアプリ開発用証明書」を選択
      • Organization Identifier: APNs登録で作成したApp IDの「Bundle ID」を指定する(異なる指定を指定するとBuildでエラーになる)
      • Language: Swiftを選択

f:id:nopipi:20190216220918p:plain:w450

  • (4) 開発用プロビショニングプロファイルの設定
    • ProjectNavigator(左のバー)のトップ(図のSnsTest部分)をクリック
    • 「General」タブを選択
    • 「Automatically manage signing」無効化する
    • 下記2箇所に事前に作成した開発用プロビショニングプロファイルを指定します。
      • Signing(debug)
      • Signing(Release)
    • プロビジョニングファイルは、事前にダウンロードしたもののインポートと、XcodeがDeveloperからダウンロードする、のいずれかの方法で設定します。

f:id:nopipi:20190217002555p:plain:w450

  • (5) Notificationの有効化
  • プロジェクトのターゲット設定画面のタグで「Capabilities」を選択
  • 「Push Notifications」をONにする

f:id:nopipi:20190217002612p:plain:w450]

Device Token取得コードの追加

アプリケーション起動時にデバイストークンを取得するコードを追加します。

  • 「AppDelegate.swift」を開く
  • 下記の図の部分に、デバイストークン取得とコンソールへのデバイストークン出力用のコードを追加します。

f:id:nopipi:20190217011255p:plain

//
//  AppDelegate.swift
//  SnsTest
//
//  Created by NF on 2019/02/16.
//  Copyright © 2019 NopipiDevTeam. All rights reserved.
//

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        // デバイストークンの要求
        if #available(iOS 10.0, *){
            /** iOS10以上 **/
            let center = UNUserNotificationCenter.current()
            center.requestAuthorization(options: [.alert, .badge, .sound]) {granted, error in
                if error != nil {
                    // エラー時の処理
                    return
                }
                if granted {
                    // デバイストークンの要求
                    print("Get a device token.")
                    UIApplication.shared.registerForRemoteNotifications()
                    print("Done to get a device token.")
                }
            }
        } else {
            /** iOS8以上iOS10未満 **/
            //通知のタイプを設定したsettingを用意
            let setting = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            //通知のタイプを設定
            application.registerUserNotificationSettings(setting)
            //DevoceTokenを要求
            application.registerForRemoteNotifications()
        }
        
        return true
    }

    // デバイストークン取得が成功した場合呼び出される関数
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        
        let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
        print("DeviceToken: " + token)
    }

    // デバイストークン取得が失敗した場合呼び出される関数
    func application(_ application: UIApplication,
                     didFailToRegisterForRemoteNotificationsWithError error: Error) {
        // Try again later.
        print("Can not get Device token")
    }

   以下略
  • バイストークン取得で重要なコードは以下の部分です
    • "import UserNotifications" ・・・UserNotificationsライブラリのインポート
    • UIApplication.shared.registerForRemoteNotifications() ・・デバイストークン取得を実行するメソッド
    • func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) ・・・デバイストークン取得が成功した場合に良い出される関数
      • let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined() ・・・デバイストークン情報を16進数の文字列に変換する
      • print("Done to get a device token.")のコンソール出力

アプリケーションの実行とデバイストークン確認

  • (1) 実行用デバイス(iPhone)の準備
    • テストに利用するiPhoneXcodeを動かしているMacにUSB接続します
    • iPhoneの画面ロックがかかっている状態の場合はロック解除します
    • 右上の停止ボタン右側をクリックします
    • ”No devices connected to 'My Mac'を選択し、_UBS接続したデバイスを登録&選択します(既にデバイスが表示されている場合はそれを選択)
    • USB接続したデバイスをアプリケーションの実行環境として選択します

f:id:nopipi:20190217014514p:plain:w400

  • (2)Active Consoleの表示
    • 「View」->「Debug Area」->「Active Console」で)Active Consoleを開きます(Shift+Command+Cでも可)

f:id:nopipi:20190217014708p:plain:w400

  • (3)アプリケーションの実行
    • 左上の再生ボタンを押してアプリケーションを実行します
    • バイストークン取得が成功すると右下のコンソールにデバイス情報が出力されます

f:id:nopipi:20190217015729p:plain:w500

Amazon SNSへの登録とプッシュ通知の実行

Amazon SNSのアプリケーションプラットホーム作成

  • マネージメントコンソールにログインし、Amazon SNSの画面に移動します
  • 左のナビゲーションバーから「アプリケーション」を選択し
  • 「プラットホームアプリケーショの作成」を選択
  • 必要な情報を入力します
    • アプリケーション名:わかりやすい名称を指定
    • プッシュ通知プラットホーム:今回はAPNsのDevelopmentなので「Apple Development」を選択
    • プッシュ証明書タイプ:「iOSプッシュ証明書」を選択
    • P12ファイル:
      • ファイル選択こちらの最後で作成した、APNs用個人情報交換ファイル(.p12) を指定(ファイル名が日本語だとエラーになるようです)
      • パスワードの入力:P12ファイル生成時に指定したパスワードを指定します
      • 「認証情報」をファイルから読み込みを実行し、証明書・プライベートキーに表示されることを確認

f:id:nopipi:20190217020649p:plain:w500

バイストークン情報の登録

  • (1)プラットフォームエンドポイントの作成
    • 作成したアプリケーションプラットホームに移動し、「プラットフォームエンドポイントの作成」をクリックする
    • アプリケーションで取得したデバイストークンを登録する
    • 「エンドポイントの追加」をする

f:id:nopipi:20190217021508p:plain:w500

  • (2)プッシュ通知の実行
  • アプリケーションプラットフォームで、送信したいデバイスを選択します

f:id:nopipi:20190217023437p:plain:w500

f:id:nopipi:20190217023452p:plain:w500

  • ペイローの内容は以下の通りです。
{
"APNS_SANDBOX":"{\"aps\": {\"alert\": {\"title\":\"テスト\",\"body\":\"これはテストメッセージです\"}, \"sound\": \"default\", \"badge\":1}}"
}
  • こんな感じに送れます。

f:id:nopipi:20190217023907p:plain:w300

プッシュ通知のペイロードの詳細についてはこちらを参照
nopipi.hatenablog.com