【2018年版】Amazon Pinpoint で iOS のサンプルアプリ(Swift)にセグメントプッシュを送る

2018.12.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Amazon Pinpoint を利用したセグメントプッシュを iOS アプリに対して実施する機会がありました。諏訪が記事を書いていたのでこれ幸いと手順に沿って進めようとしたのですが… 当時からいろいろ変わっていることもあり、手間取りました。現時点でどのようにすればよいか、メモしておきます。

ちなみに私は、もともとサーバーサイドの開発を行っており、iOSを触ったのはこのタイミングが初めてでした。調べていく中で感じたのは、もともとモバイルアプリなど開発した方が AWS ないし Firebase を使ってクラウド連携する、という視点の記事はたくさんあるのですが、サーバーサイドに携わっていた人がモバイルアプリを作ってつなげてみるという状況は少ない印象です。アプリならではの証明書がらみや、プッシュ通知の概念などとても良い勉強機会になりました。

登場人物の整理

手順の話に入る前に、誰がどのような役割を担っているのか整理しておきます。

iOS アプリ

Amazon Pinpoint からプッシュ通知を受け取ります。プッシュ通知を受け取るための 証明書作成 手順があり、苦労しました。モバイルアプリサービス部のみなさんありがとうございました。

Amazon Pinpoint

以下 Pinpoint と表記します。ユーザーの行動を分析し、ユーザーに対して複数のチャネルを駆使してメッセージを送信できるサービスです。もともと、ユーザーの行動については Amazon Mobile Analytics というサービスがあったのですが、 Pinpoint に統合されました。

Pinpoint のうち、行動分析を担う部分はほぼ Mobile Analytics の機能、それに加えて セグメントの定義やキャンペーン作成、それらをもとにしたメッセージ送信(プッシュ通知、Eメール、SMS)ができるようなイメージです。このプッシュ通知機能を使って、iOS アプリに通知してみます。

AWS Mobile Hub (AWS Mobile)

この記事では以下 Mobile Hub で表記します。 Mobile Hub は、モバイルアプリケーションと AWS サービスを統合するためのサービスです。モバイルアプリ開発者の立場からみたとき、実現したいユースケースに対して、AWSのサービスをどう使い、どう構築するかというのを考えるのは、かなり骨が折れる作業です。Mobile Hub を使うことで、「ユーザーのストレージを追加したい」「認証機能を追加したい」といった具合にAWSサービスを立ち上げられます。

最近だと Amplify Framework というCLIツールを使って Mobile Hub を制御するのが推されているようですが、ここで新しいCLIツールを出すと私がさらに混乱するので、今回は画面上での操作とさせてください。

Mobile Hub を使うことで、

  • ユースケースに応じて簡単にAWSサービスを立ち上げられる
  • モバイルアプリで利用する設定情報をダウンロードできる

といったことができます。

ここまでの話をまとめて、これから作業していく手順は以下のようになります。

  1. iOS のサンプルアプリケーションを起動する
  2. Mobile Hub を使って Pinpoint を作成する
  3. iOS Pinpoint にエンドポイントを登録する
  4. iOS の本番用証明書を作成し、Pinpoint からプッシュ通知が送れるようにする
  5. Pinpoint で セグメントとキャンペーンを作成し、プッシュ通知を送る

バージョン情報

  • macOS mojave 10.14.2
  • Xcode 10.1

iOS のサンプルアプリケーションを起動する

現時点では、以下のドキュメントが一番良いと思います。

このチュートリアルによると、サンプルはGitHubにあるみたいですね。

私は fork して、clone しました。この後ですが、GitHub にもチュートリアルがあり、どちらに沿うか迷いますね…。もともとAWSドキュメントから始まったのでドキュメントの方に従うこととします。

clone したディレクトリに移動し、Xcode を開きます。

open MyNotes.Xcodeproj/

Xcode を開いたら、適当なシミュレータを指定して起動してみます。

sample-launch.png

ノート一覧が出現すれば成功です。ビルド時、Swift4.2にあげないかと警告されますが無視します。

Mobile Hub を使って Pinpoint を作成する

われわれは直接 Pinpoint を作成しません。Mobile Hub に作成してもらいます。いろいろ理由はあるのですが、一番はプッシュ通知証明書を設定するのが Mobile Hub 側だからです。

Create Project

mobilehub-create_project.png Mobile Hub の画面にアクセスして新しいプロジェクトを作成します。

mobilehub-region.png ここで早速注意です。可能な限り東京リージョンでリソースを作成する よう編集します。小さくて見逃しがちです。Pinpoint は東京リージョンに対応していないのでバージニアリージョンに作成されますが、認証やストレージ機能を追加していくこと考慮して、Cognito Identity Pool, S3 バケットといったリソースが東京リージョンへ作成されるようにします。

Select app platform

iOS を選択します。

Set up your backend, Connect your backend

後からでも対応できるのでスキップします。Next、Doneとして新しいプロジェクトの作成を完了してください。この手順が終わると Pinpoint が自動で作成されています。

iOS Pinpoint にエンドポイントを登録する

次は iOS アプリと Pinpoint とをつないでみましょう。まだプッシュ通知を送る段階ではありません。さきほど Mobile Hub で作成した Pinpoint の画面にアクセスします。 バージニア北部リージョン に作成されていることを注意してください。

pinpoint-created.png

ここから、iOSのノートアプリにPinpoint のライブラリを追加し、接続先を指定して Pinpoint とつないでいきます。

設定ファイルをプロジェクトに配置する

まず、Mobile Hub から設定ファイルをダウンロードしましょう。Moble Hub のトップページで Integrate > Donwnload Cloud Config とします。

mobilehub-integrate.png

ダウンロードした awsconfiguration.json を、 Info.plist と同じディレクトリに Xcode 上でコピーします。

ios-add_awsconfig.png

このように設定してコピーします。これで、AWS SDK が接続先情報を利用する準備ができました。

Pinpoint のライブラリを追加する

Pinpoint のSDK を導入します。プロジェクトルートにて作業を行います。

pod init

その後、Podfileを編集して、Pinpointを追加します。

# Uncomment the next line to define a global platform for your project
platform :ios, '9.0'

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

  # Pods for MyNotes
  # Analytics dependency
  pod 'AWSPinpoint'

end
pod install --repo-update

一度 Xcode を閉じ、再度開きます。

open MyNotes.xcworkspace/

iOSコードで Pinpoint との接続を有効にする

ここなんですが…残念ながら落としてきたコードと ドキュメント記載のコードに差異があります。私が取得したサンプルコードは AnalyticsService という抽象化されたサービスを利用しており、これをもともとの LocalAnalyticsService から実際にAWSと接続する AWSAnalyticsService を作成します。実はこのクラスは GitHub の手順のほうには記載があります。このあたり本当に混乱しました…。

Create Analytics Service Class

Xcode で、MyNotes グループにおいて New File > Swift File > AWSAnalyticsService として Swift ファイルを作成します。GitHubの記載に従い以下のようにします。

AWSAnalyticsService.swift

import Foundation
import AWSCore
import AWSPinpoint

class AWSAnalyticsService : AnalyticsService {
    var pinpoint: AWSPinpoint?
    
    init() {
        let config = AWSPinpointConfiguration.defaultPinpointConfiguration(launchOptions: nil)
        pinpoint = AWSPinpoint(configuration: config)
    }
    
    func recordEvent(_ eventName: String, parameters: [String : String]?, metrics: [String : Double]?) {
        let event = pinpoint?.analyticsClient.createEvent(withEventType: eventName)
        if (parameters != nil) {
            for (key, value) in parameters! {
                event?.addAttribute(value, forKey: key)
            }
        }
        if (metrics != nil) {
            for (key, value) in metrics! {
                event?.addMetric(NSNumber(value: value), forKey: key)
            }
        }
        pinpoint?.analyticsClient.record(event!)
        pinpoint?.analyticsClient.submitEvents()
    }
}

さらに、AppDelegate.swift で定義している AnalyticsService のインスタンスはモックサービスになっているので、これを上で定義したものに差し替えます。

AppDelegate.swift

// Initialize the analytics service
// analyticsService = LocalAnalyticsService()
analyticsService = AWSAnalyticsService()

以上で修正は終わりです。シミュレータを起動します。いくつかメモ帳を操作をした後、Pinpoint のコンソールを開きます。

pinpoint-demograpics.png

新しいエンドポイントとしてひとつでも認識されていればOKです。

iOS の本番用証明書を作成し、Pinpoint からプッシュ通知が送れるようにする

ノートアプリと Pinpoint が接続できたことを確認できました。プッシュ通知を送るわけですが、注意点があります。

  • Pinpoint のセグメントプッシュには 本番用 プッシュ通知証明書が必要
  • ワイルドカードアプリIDは利用不可。プッシュ通知が届きません
  • 本番用の プロビジョニングプロファイルが必要となり、Apple Developer Program への登録が必要
  • CertificateSigningRequest を作成する際、署名は 半角英数字が良い
  • プッシュ通知証明書のP12を生成する際、パスワードを設定する

アプリ開発に慣れていたらすぐにわかるのかもしれませんが、ここでかなり時間を使ってしまいました。さらに、ここからは Mobile Hub のチュートリアルはありません。Pinpoint のチュートリアルになります。

この手順に従って証明書を作成してください。手元のマシンは以下のような状態になるはずです。

  • 本番用の APN プッシュ通知証明書が、キーチェーンにインストールされている
  • 本番用の APN プッシュ通知証明書 P12ファイルが生成されている(パスワード付!)
  • iOS ディストリビューション証明書が、キーチェーンにインストールされている
  • 本番用プロビジョニングプロファイルが Xcode にインストールされている

ここまで行った後、 Xcode での作業に移ります。

Bundle Identifier を修正する

App Id で指定したものに修正します。Buld Settings > Targets(MyNotes) > General で、 Bundle Identifierを修正します。

push-xcode_build_bundleid.png

さらにこの状態で 画面下にある 「Automatically Manage sigining」を有効にします。上記、証明書の準備が正しく行われれていれば、エラーにはならないはずです。

ノートアプリの プッシュ 通知を有効にする

同じく Buld Settings > Targets(MyNotes) で、こんどは Capabilities タブを選びます。Push Notification があるのでそれを有効にします。

ユーザーに通知の許可を求め、デバイストークンを Pinpoint に送信する実装を追加

AppDelegate の applicaiton に以下の処理を追加します。

AppDelegate.swift

// Push notifications
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .badge, .sound], completionHandler: {
    (granted, error) in
    if granted {
        print("Allowed")
        application.registerForRemoteNotifications()
    } else {
        print("Didn't allowed")
    }
})

さらに、Pinpoint がプッシュ通知を送れるよう、デバイストークンを送信します。まず、AnalyticsServce, AWSAnalyticsServce にデバイストークンを送信する処理を追加します。

AnalyticsService.swift

import Foundation

protocol AnalyticsService {
    func recordEvent(_ eventName: String, parameters: [String:String]?, metrics: [String:Double]?) -> Void
    func registerDevice(_ deviceToken: Data)
}

AWSAnalyticsService.swift

func registerDevice(_ deviceToken: Data) {
    pinpoint?.notificationManager.interceptDidRegisterForRemoteNotifications(withDeviceToken: deviceToken)
    let token = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
    print("deviceToken: \(token)")
}

これを、AppDelegate から使います。

AppDelegate.swift

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    analyticsService?.registerDevice(deviceToken)
}

ビルドして実機へインストールする

Pinpoint は本番プッシュ証明書を利用する関係上、プロビジョニングプロファイルも本番用でなくてはいけません。まず、ターゲットのスキーマが、App ID 作成時に指定したiOSの実機になっていることを確認してください。

push-scheme.png

その後、Xcode 上部メニュー Product > Archive としてアーカイブを作ります。Archivesウィンドウで、 Distribute App とします。distribution method は、Ad hoc です。

push-archive-app.png

オプション設定は特に何もせずにNext、re-sign の設定では Automatically manage signing とします。これで、ipaファイルを含むフォルダが生成されるので、適当な場所に置きます。このipaファイルを実機へインストールします。Xcode 上部メニュー Window > Devices and Simulators と選んでください。この画面で、+ ボタンを押して先程作成したipaファイルを選択することでインストールできます。

push-devices_and_simulators.png

iOS の実機で、アプリが起動することを確認してください。このとき、「プッシュ通知を許可しますか?」と聞かれるはずです。

push-device_app.png

「許可」します。これでアプリ側は準備OKです。

Mobile Hub に 本番プッシュ証明書のP12ファイルを登録する

Mobile Hub でプッシュ通知の設定を行います。AWSマネジメントコンソール、Mobile Hub の test-note トップ画面で Messaging and Analytics を選択してください。

push-setting_message.png

その後、Messaging > Mobile push > iOS とクリックしていきます。P12ファイルを選ぶUIになると思うので、パスワードを設定した P12ファイルを選択、パスワードを入力してアップロードします。その後、画面下部Enableボタンをおします。

push-mobilehub_settings.png

これでプッシュ通知を行う準備ができました。

Pinpoint で セグメントとキャンペーンを作成し、プッシュ通知を送る

それではプッシュ通知を送ります。Pinpoint では、「セグメント」と「キャンペーン」を作って、セグメントプッシュを送っていきます。

セグメントを作る

Pinpoint のtestnote画面で、左メニュー Segments から新しいセグメントを作成してください。名前は何でもOKです。Segment group の設定ですが、本来はここでユーザーの属性だったり、モバイルOSの種類でセグメント対象を絞ることができます。今回は1端末しか登録していないので、「メッセージチャネルがPUSH通知になっているものすべて」という設定にしてみましょう。

segment-create_segment.png

このとき、右側のSegment estimateで 対象になっているエンドポイントが少なくとも1つ以上あることを確認してください。ここで対象エンドポイントがない場合、デバイストークンが正しく送信されていない可能性があります。問題ないことを確認したら、「Create Segment」としてください。これでセグメントの作成は完了です。

キャンペーンを作る

キャンペーンとは、メッセージ送信計画のようなものです。A/Bテストを行ったり、定期的な配信の設定が行えます。プッシュ通知はキャンペーン設定のもとを送信されるため、セグメントに続きこちらも作っていきます。左メニューCampaings > Create a campaign としてください。

Create a campaign

名前は適当、Campaign type は Standard campaign でOKです。

Choose a segment

Use an exiting segment とします。Segment は、先程作成したものを指定します。

Create your message

以下のように設定します。

  • Specifications: Push notifications
  • Push notification details
    • Notification type: Standard notification
    • Message content: Create a new message
    • Title: ノートアプリへのプッシュテスト
    • Body: Pinpointのセグメントプッシュです
    • Action: Open your app

segment-create_your_message.png

Choose when to send the campaign
  • At a specific time
  • Immediately

とします。発射します。

segment-send.png

頼む…!

segment-recieve.png

無事届きました!

まとめ

なにもないところからスタートすると、ずいぶんと長い道のりに感じました。Mobile Hub によって、モバイルアプリからAWSを使うハードルが大幅に下がり、一人のエンジニアでもアプリ・サーバを一緒に組み上げられるようになりました。モバイルアプリとPinpointを使うなら、「じゃあプッシュ通知も」となるのは自然な流れだと思います。この記事は、自分自身のために書いたところが大きく、今後、ふたたびプッシュ通知をPinpointで行うことになった場合に読み返そうと思います。どなたかの参考になれば幸いです。

今回は、Pinpoint のセグメントはほとんど形だけ、1デバイスに対して送るというものでした。Pinpointはまだまだいろいろなことができると思います。連携できることがわかった以上、機能を調べて、どのようなプッシュ通知が送れるか、今後試していくのが楽しみです。

参考