Skip to content

8 アプリ内メッセージの実装

8.1 アプリ内メッセージとは

アプリ内メッセージとは、アプリ起動中のユーザーに向けてポップアップなどのメッセージを表示させることができる機能です。

この機能を使用することで、下記のようなことが実現できます。

  • お知らせを OFF にしているユーザーに対してアプローチを行う
    • (お知らせを ON にするように設定画面への遷移を促す、など)
  • アプリのトップ画面を開いた際、キャンペーンなどのバナーを表示させる
  • 商品をカートに入れたユーザーに対しクーポンを付与するようなバナーを表示させる

アプリ内メッセージはイベントトラッキングをつけた契機でメッセージの表示を行います。

そのため、事前にイベントトラッキングをつけておくようにしておけば必要になったタイミングで自由にメッセージの表示を行うことができます。

また、現在使用されておりますイベントトラッキングがありましたらそちらを対象にしたメッセージの表示も行えます。

8.1.1 推奨するイベント

アプリ内メッセージには、「推奨イベント」と呼ばれるイベントプリセットがあります。
「ログイン後」や「チュートリアル完了後」といったタイミングでは、新しくイベントを定義するよりも、上記プリセットをご利用いただくとスムーズに実装できます。

8.1.2 ご利用上の注意

8.1.2.1 組み込みに関する注意

本バージョンのSDKにおいて、アプリ内メッセージは SceneDelegate を使用する App 上では正常に動作しません。

原理上、実装を工夫することで表示できる可能性がありますが、本バージョンのSDKでは SceneDelegate 上の組み込みに関しては、各種検証が十分に行えていないこともあり、サポート対象外とさせていただきます。

8.1.2.2 通信に関する注意

アプリ内メッセージは表示の際にサーバーとの通信が発生します。
そのため、通信状況などによって表示が遅れたり、まれに表示自体が失敗することがあります。

アプリ内メッセージをトリガーにしないでください

アプリ内メッセージが表示されていないとログインが行われない」といったように、後続処理のトリガーとしてアプリ内メッセージを利用した場合、 通信状況によってはアプリに対するユーザーエクスペリエンスを著しく低下させてしまう場合があります ので、そのような実装は行わないでください。

8.2 アプリ内メッセージの仕様

8.2.1 イベントアクション条件リスト

アプリ内メッセージは、任意のイベントが発生したことを契機に、ユーザーに対してメッセージの表示を行います。
この契機の一覧は内部で管理されており、以後この一覧を「イベントアクション条件リスト」と呼びます。

すなわち「イベントアクション条件リスト」には、どのメッセージがどのタイミングで表示されるべきであるか、が管理されています。

本ドキュメントでは、「イベントアクション条件リスト」を「条件リスト」と略記することがあります。

ただし、条件リストはメッセージのIDのみを管理しており、具体的なメッセージの内容は保持していません。
メッセージを表示するタイミングになった段階で初めてサーバーにIDを通知し、実際にアプリ内メッセージで表示するコンテンツを取得します。

8.2.2 処理の流れ

アプリ内メッセージが表示されるまでのおおまかな流れを以下に示します。
なお、図中の黒丸内数字は、説明のカッコ内の数値と対応しています。
また、図中の※印は省略可能な処理です。

バージョン 6.1.0 のガイドにおいて図をより詳しいものに変更しましたため、図中の一部の番号がバージョン 6.0.3 以前のものとは異なるものに変更されております。

sequenceDiagram autonumber participant A as アプリ participant D as SDK participant L as ローカルストレージ participant S as サーバー Note over A,S: アプリ起動時 A->>D: 条件リスト更新要求 D->>S: 条件リスト要求 S->>D: 条件リスト取得 D->>L: 条件リスト保存 Note over A,S: トリガーとなるイベントが発生したとき A->>D: 特定イベント発生通知 D->>L: 条件リストフェッチ要求 L->>D: 条件リスト取得 D->>D: 条件合致チェック(表示回数、期間など) D->>A: 表示可否確認(※) A->>D: 表示可否結果(※) Note over A,L: ここでアプリ側が「NO」を戻した場合は、処理終了 D->>S: 条件合致通知 opt サーバーエラー発生時 S->>D: エラー処理 D->>A: エラーを通知(※) Note over D,S: リトライ回数が残っていれば「条件合致通知」に戻る Note over D,S: リトライ回数上限を超えた場合は、処理終了 end opt セグメント配信 かつ 配信対象でない場合 Note over A,S: アプリ側に通知を行わず、処理終了 end S->>D: コンテンツ取得 D->>A: 表示コンテンツの校閲(※) A->>D: 校閲結果を連携(※) D->>A: アプリ内メッセージ表示

アプリ起動時等に 条件リスト を取得します。(1)(2)(3)(4)
特定のイベントが発生すると、このイベントを契機とするアプリ内メッセージが 条件リスト に存在するかどうかを確認します。(5)(6)(7)
発生したイベントが 条件リスト に存在していた場合、以下のようなチェックを行い、表示することが確定した場合、サーバーにその旨を通知します。この通知を 条件合致通知 とします。(10)

チェックの一例

  • 配信期間と回数制限などの条件を満足しているか(8)
  • アプリがフォアグラウンド状態であるか
  • 組み込み側からのチェック(9)(10) 後述の「デリゲート」の項を参照

条件合致通知のレスポンスとして、実際にユーザーに表示するアプリ内メッセージのコンテンツ(HTML)を取得します。(14)

エラーが発生した場合は、図では一部省略していますが、組み込み側でリトライ処理を制御できます。

組み込み側のチェックを経て、ユーザーにアプリ内メッセージが表示されます。(15)(16)(17)

組み込み側のチェックについては後述の「デリゲート」の項をご参照ください。

8.3 ご利用方法

8.3.1 受信処理の組み込み

アプリ内メッセージは、契機となる イベントトラッキングの付与 が正しく組み込まれていれば、本SDKを組み込むだけで受信できるようになります。

CoreData バージョンにご注意ください

主に SDK を旧バージョンからアップデートした場合において、CoreDataモデルバージョンが最新になっていない場合があります。
CoreData モデルバージョンは必ず 最新バージョン に設定してください
最新になっていない場合、アプリ内メッセージを正常に受け取れないだけでなく、App実行時にクラッシュを引き起こす原因にもなります。

アプリ内メッセージの表示処理に割り込み処理を追加したい場合は、後述の 8.3.3 デリゲート に記した実装が必要です。

8.3.2 イベントトラッキングの付与

アプリ内メッセージを表示させるためには、必ずイベントトラッキングを付与する必要があります。
イベントトラッキングの付与には下記のメソッドを呼び出してください。

[[PopinfoReceiver sharedReceiver] trackEvent:@"イベントキー名" value:@{
    @"testName1": @"testVal1",
    @"testName2": @"testVal2"
}];
PopinfoReceiver.shared.trackEvent("イベントキー名", value: [
    "testName1": "testVal1",
    "testName2": "testVal2"
])

第1引数には、イベントのキー名を指定します。
第2引数には、イベントのキーに対する値を辞書型で格納します。

付与を行うイベントにつきましては「推奨イベント」も参考に組み込んでください。

また、推奨イベント app.topapp.firstapp.update を付与するサンプルコードを以下に示します。

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    if (IS_FIRST_INSTALL && IS_AFTER_TUTORIAL) {
        // チュートリアル突破後に初めてトップ画面を開いた場合
        [[PopinfoReceiver sharedReceiver] trackEvent:@"app.first" value:nil];
    } else if (IS_APP_UPDATED) {
        // アプリをアップデート後にトップ画面を開いた場合
        [[PopinfoReceiver sharedReceiver] trackEvent:@"app.update" value:nil];
    } else {
        // 通常時、トップ画面を開いた場合
        [[PopinfoReceiver sharedReceiver] trackEvent:@"app.top" value:nil];
    }

@end
class ViewController: UIViewController {
    override func viewDidLoad() {

        super.viewDidLoad()

        if isFirstInstall() && isAfterTutorial() {
            // チュートリアル突破後に初めてトップ画面を開いた場合
            PopinfoReceiver.shared.trackEvent("app.first", value: nil)
        } else if isAppUpdated() {
            // アプリをアップデート後にトップ画面を開いた場合
            PopinfoReceiver.shared.trackEvent("app.update", value: nil)
        } else {
            // 通常時、トップ画面を開いた場合
            PopinfoReceiver.shared.trackEvent("app.top", value: nil)
        }
    }
}

このサンプルではトップ画面を開いた際のアプリの状態によって、付与するイベントを分けています。

コード内において、 IS_FIRST_INSTALLisFirstInstall() のような各種条件判定メソッドの具体的な実装は省略しています。

OSダイアログにご注意ください

許諾ダイアログのようなiOS由来のダイアログと、アプリ内メッセージが両方表示されてしまわないよう、 イベントを付与するタイミング にはご注意ください。
たとえば、loadSettings をコールするタイミングで上記のようなイベントをつけた場合、iOS のダイアログと同時にアプリ内メッセージが表示されてしまいます。

8.3.3 デリゲート

公開されている各種デリゲートを利用し、アプリ内メッセージの一部の処理に割り込むことが出来ます。
デリゲートメソッドを利用するためには、まず以下のように実装を行います。

  • PopinfoReceiver と同様に PopinfoEventActionReceiver のクラスのインスタンスとプロトコルの宣言を行います。
  • App 起動時にコールされる application:didFinishLaunchingWithOptions: 内で同クラスのインスタンスを生成します。
@interface AppDelegate : NSObject <UIApplicationDelegate, UNUserNotificationCenterDelegate, PopinfoReceiverDelegate> {
    PopinfoReceiver *popinfoReceiver;
    PopinfoEventActionReceiver *popinfoEventActionReceiver;
}
// ...
@end

@implementation AppDelegate
// ...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    popinfoReceiver = [PopinfoReceiver sharedReceiver];
    popinfoReceiver.delegate = self;

    popinfoEventActionReceiver = [PopinfoEventActionReceiver sharedReceiver];
    popinfoEventActionReceiver.delegate = self;

    // ...省略...
}
// ...
@end
class AppDelegate: UIApplicationDelegate, UNUserNotificationCenterDelegate, PopinfoReceiverDelegate, PopinfoEventActionReceiverDelegate {

    var popinfoReceiver: PopinfoReceiver!
    var popinfoEventActionReceiver: PopinfoEventActionReceiver!

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        self.popinfoReceiver = PopinfoReceiver.shared
        self.popinfoReceiver.delegate = self

        self.popinfoEventActionReceiver = PopinfoEventActionReceiver.shared
        self.popinfoEventActionReceiver.delegate = self

        // ...省略...
    }
    // ...省略...
}

これで、デリゲートメソッドを利用するための準備が整いました。

詳細については、 PopinfoEventActionReceiver.h およびAPIドキュメントをご参照ください。

本項において「条件」は、特に説明がない限り「アプリ内メッセージを表示するための条件」を指すものとします。

8.3.3.1 アプリ内メッセージの組み込み側承認

SDK でのアプリ内メッセージ判定が終わった後(シーケンス図における(9))に以下がコールバックされます。

- (BOOL)popinfoEventActionReceiver:(PopinfoEventActionReceiver *__nonnull)popinfoEventActionReceiver
           shouldFireActionByEvent:(NSString *__nonnull)event
                    withCategories:(NSArray<NSString *> *__nonnull)categories;

これを実装すると、アプリ側でアプリ内メッセージを表示させるかの最終判断を行うことができます。

- (BOOL)popinfoEventActionReceiver:(PopinfoEventActionReceiver *__nonnull)popinfoEventActionReceiver
           shouldFireActionByEvent:(NSString *__nonnull)event
                    withCategories:(NSArray<NSString *> *__nonnull)categories
{
    // ORIGINAL_CHECK_RESULT_FOR の実装は省略
    return ORIGINAL_CHECK_RESULT_FOR(event, categories);
}
func popinfoEventActionReceiver(_ popinfoEventActionReceiver: PopinfoEventActionReceiver, shouldFireActionByEvent event: String, withCategories categories: [String]) -> Bool {
    // originalCheckResult の実装は省略
    originalCheckResult(event: event, categories: categories)
}

実装しなかった場合は、 YES が返却されたものとして取り扱われます。

8.3.3.2 条件合致通知エラー時の処理

条件合致通知に失敗した際(シーケンス図における(13))に、下記がコールバックされます。

- (BOOL)popinfoEventActionReceiver:(PopinfoEventActionReceiver *__nonnull)popinfoEventActionReceiver
     shouldRetryOnErrorAtSendEvent:(NSString *__nonnull)event
                    withCategories:(NSArray<NSString *> *__nonnull)categories
                      onRetryCount:(NSInteger)retryCount;

これを実装することで、条件合致通知失敗時にリトライを行うことが出来ます。

- (BOOL)popinfoEventActionReceiver:(PopinfoEventActionReceiver *__nonnull)popinfoEventActionReceiver
     shouldRetryOnErrorAtSendEvent:(NSString *__nonnull)event
                    withCategories:(NSArray<NSString *> *__nonnull)categories
                      onRetryCount:(NSInteger)retryCount
{
    // ORIGINAL_POLICY_OF_RETRY_WITH の実装は省略
    return ORIGINAL_POLICY_OF_RETRY_WITH(event, categories, retryCount);
}
func popinfoEventActionReceiver(_ popinfoEventActionReceiver: PopinfoEventActionReceiver, shouldRetryOnErrorAtSendEvent event: String, withCategories categories: [String], onRetryCount retryCount: Int) -> Bool {
    // originalPolicyOfRetryWith の実装は省略
    originalPolicyOfRetryWith(event: event, categories: categories, retryCount: retryCount)
}

8.3.5 APIの設定値変更 にて、設定された最大回数を超えて、リトライが行われることはありません。

イベントアクションの発火が行われなかった場合、発火回数のカウントはされません。

実装しなかった場合は、NO が返却されたものとして取り扱われ、リトライ処理は行われません。

8.3.3.3 アプリ内メッセージ表示直前の校閲

アプリ内メッセージが表示される直前(シーケンス図における(15))にて、以下がコールバックされます。

- (NSString *__nonnull)popinfoEventActionReceiver:(PopinfoEventActionReceiver *__nonnull)popinfoEventActionReceiver
                       copyeditInAppMsgHtmlString:(NSString *__nonnull)htmlString
                                        withEvent:(NSString *__nonnull)event
                                       categories:(NSArray<NSString *> *__nonnull)categories;

これを実装すると、アプリ内メッセージを表示する直前にコンテンツを編集することが出来ます。

たとえば、コンテンツに$userのような仮置の文字列を入れ、デバイスに登録したユーザー情報(氏名など)と置き換えることで、個人宛のメッセージを表示するような実装ができます。

- (NSString *__nonnull)popinfoEventActionReceiver:(PopinfoEventActionReceiver *__nonnull)popinfoEventActionReceiver
                       copyeditInAppMsgHtmlString:(NSString *__nonnull)htmlString
                                        withEvent:(NSString *__nonnull)event
                                       categories:(NSArray<NSString *> *__nonnull)categories
{
    // userName はすでに定義されているものとします 
    return [htmlString stringByReplacingOccurrencesOfString: @"{$user}さん、こんにちは" withString: [NSString stringWithFormat:@"%@さん、こんにちは", userName]]);
}
func popinfoEventActionReceiver(_ popinfoEventActionReceiver: PopinfoEventActionReceiver, copyeditInAppMsgHtmlString htmlString: String, withEvent event: String, categories: [String]) -> String {
    // userName はすでに定義されているものとします
    htmlString.replacingOccurrences(of: "{$user}さん、こんにちは", with: "\(userName)さん、こんにちは")
}

実装しなかった場合は、受け取ったコンテンツをそのままユーザーに表示します。

8.3.3.4 コンテンツ内のボタン押下時処理

アプリ内メッセージのボタンが押された際に以下がコールされます。

- (void)popinfoEventActionReceiver:(PopinfoEventActionReceiver *__nonnull)popinfoEventActionReceiver
        receivedTapActionAndGetUrl:(NSString *__nonnull)url;

これを実装することで、ボタンに指定した URL を受け取り、アプリ側でその内容によって処理を分けたりすることができます。

- (void)popinfoEventActionReceiver:(PopinfoEventActionReceiver *__nonnull)popinfoEventActionReceiver
        receivedTapActionAndGetUrl:(NSString *__nonnull)url
{
    // START_PROCESS_USING はすでに定義されているものとします
    START_PROCESS_USING(url);
}
func popinfoEventActionReceiver(_ popinfoEventActionReceiver: PopinfoEventActionReceiver, receivedTapActionAndGetUrl url: String) {
    // startProcessUsing はすでに定義されているものとします
    startProcessUsing(url: url)
}

実装しなかった場合は、ボタンに定義された処理のみが実行されます。

8.3.4 デバッグモード

PopinfoConfiguration.m において popinfoTestLogUseYES に設定すると、アプリ内メッセージを表示するためのイベントが発生したタイミングで、コンソールにイベントのキー名を表示することが出来ます。

コンソール表示の書式

<キー名> matched. (現在の1日の表示回数,1日の最大表示回数)(トータル表示回数、トータル最大表示回数)

コンソール表示の例

<app.top> matched. (1,5)(1,-)

これはapp.top がマッチした際の例です。- は無制限を表します。

8.3.5 APIの設定値変更

アプリ内メッセージにおいては、 以下の設定値を変更することができます。
付属のファイル SdkSettings.plist において、該当箇所を下記条件に従って変更してください。

キー 説明 初期値 最小値 最大値
EventActionApiCallMaxWaitSec アプリ内メッセージ用のAPIコールにおけるタイムアウト値(単位: 秒) 10 5 60
EventActionApiRetryCountLimit アプリ内メッセージ用APIのコールが失敗した際に、再試行を行う回数の最大値 5 0 10

変更後の値がそれぞれの最小値以下または最大値以上だった場合は、初期値が適用されますのでご注意ください。

8.4 イベントトラッキングで推奨するイベント

アプリでイベントをつける際、推奨するイベントの一覧となります。
なお、イベントを付与する方法については「追加機能 8.イベントトラッキングのカスタマイズ」をご参照ください。

パラメータの付与は、必須ではありません。

推奨イベントの付与例

例として、商品をカートに入れたときのイベント場合は、以下のような実装になります。
パラメータが複数のイベントを付与する際は下記のように追加してください。

[[PopinfoReceiver sharedReceiver] trackEvent:@"shop.add_to_cart" value:@{
    @"item_name": @"name",
    @"quantity": @"1",
    @"price": @"500",
    @"currency": @"jpy"
}];
PopinfoReceiver.shared.trackEvent("shop.add_to_cart", value: [
    "item_name": "name",
    "quantity":"1",
    "price": "500",
    "currency": "jpy"
])

8.4.1 アプリ共通イベント

イベントタイミング イベント名 パラメータ 備考
チュートリアル開始時 app.tutorial_begin
チュートリアル終了時 app.tutorial_complete
チュートリアル突破後、トップ画面に到達 app.first トップ画面でユーザーの任意操作が可能になったとき。初回起動判定はアプリ側で行う必要がある
アプリ更新後にトップ画面を開いたとき app.update トップ画面でユーザーの任意操作が可能になったとき。アプリ更新判定はアプリ側で行う必要がある
アプリのトップ画面を開いたとき app.top トップ画面でユーザーの任意操作を可能になったとき。初回時、更新時と重ならないよう注意
ログインしたとき app.login ログインが完了したあと
会員登録が完了したとき app.sign_up 会員登録が完了したあと
マイページを開いたとき app.mypage ユーザー専用のページがある場合
お気に入り登録をしたとき app.favorite お気に入り登録が完了したあと
アプリのお知らせページを開いたとき app.news news_id 任意のお知らせを確認した場合(プッシュ通知とは別)
お問い合わせページを開いたとき app.generate_lead

8.4.2 ショッピング系アプリ

イベントタイミング イベント名 パラメータ 備考
支払い情報を追加したとき shop.add_payment_info
商品の詳細を確認したとき shop.detail item_id
商品をカートに入れたとき shop.add_to_cart item_id, quantity, item_name, price
商品の購入手続きを開始時 shop.begin_checkout item_id, quantity, item_name, price
商品の購入手続きが完了時 shop.ecommerce_purchase item_id, quantity, item_name, price, transaction_id
商品の購入をキャンセルとき shop.purchase_cancel item_id, quantity, item_name, price
払い戻しが行われたとき shop.purchase_refund transaction_id
商品の検索を行ったとき shop.search search_term
クーポンのページを開いたとき shop.coupon_view coupon_id
クーポンを利用した時 shop.coupon_use coupon_id

8.4.3 鉄道系アプリ

イベントタイミング イベント名 パラメータ 備考
運行状況を確認したとき train.info train_line
乗り換え案内を開いたとき train.transfer_guide boarding_station, getting_off_station
時刻表を確認したとき train.timetable train_line
路線図を確認したとき train.route_map train_line
駅構内図を確認したとき train.station_map statioin
マイ駅設定を追加したとき train.add_station statioin