Skip to content


上級実装ガイド

このオプションの上級実装ガイドでは、アプリ内メッセージコードに関する考慮事項、Braze チームが作成した 3 つのカスタムユースケース、付属のコードスニペットについて説明します。Braze Demo リポジトリにはこちらからアクセスできます。この実装ガイドは、Kotlin 実装を中心に扱っていますが、興味のある方のために Java のスニペットが提供されています。HTML の実装をお探しですか?Braze のHTML テンプレートリポジトリをご確認ください。

コードに関する考慮事項

次のガイドでは、デフォルトのアプリ内メッセージに加えてオプションで使用できる、開発者向けカスタム統合機能について説明します。各ユースケースにはカスタムビューコンポーネントとファクトリーが必要に応じて含まれており、機能を拡張したり、アプリ内メッセージの外観をネイティブにカスタマイズしたりするためのサンプルが用意されています。同様の結果を得る方法が複数ある場合があります。最適な実装は、特定のユースケースによって異なります。

カスタムファクトリー

Braze SDK を使用すると、開発者はカスタムファクトリーオブジェクトを通じて多くのデフォルトをオーバーライドできます。カスタムファクトリーオブジェクトを必要に応じて Braze SDK に登録して、目的の結果を得ることができます。ただし、ほとんどの場合、ファクトリーをオーバーライドする場合は、明示的にデフォルトに従うか、Braze デフォルトで提供される機能を再実装する必要があります。次のコードスニペットは、IInAppMessageViewFactory および IInAppMessageViewWrapperFactory インターフェイスのカスタム実装を提供する方法を示しています。デフォルトファクトリーのオーバーライドの背後にある概念をしっかりと理解したら、ユースケースを確認してカスタムのアプリ内メッセージング機能の実装を開始してください。

アプリ内メッセージのタイプ

1
2
3
4
5
6
7
8
class BrazeDemoApplication : Application(){
 override fun onCreate() {
    super.onCreate()
    registerActivityLifecycleCallbacks(BrazeActivityLifecycleCallbackListener(true, true))
    BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewWrapperFactory(CustomInAppMessageViewWrapperFactory())
    BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewFactory(CustomInAppMessageViewFactory())
  }
}

アプリ内メッセージのタイプ

1
2
3
4
5
6
7
8
9
public class BrazeDemoApplication extends Application {
  @Override
  public void onCreate{
    super.onCreate();
    registerActivityLifecycleCallbacks(new BrazeActivityLifecycleCallbackListener(true, true));
    BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewWrapperFactory(new CustomInAppMessageViewWrapperFactory());
    BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewFactory(new CustomInAppMessageViewFactory());
  }
}

ユースケース

私たちは以下に3つのユースケースを提供しました。各ユースケースにはコードスニペットが含まれており、アプリ内メッセージがBrazeダッシュボードでどのように表示され、使用されるかを確認できます。

カスタムスライドアップアプリ内メッセージ

スライドアップのアプリ内メッセージを作成しているときに、デフォルトの方法ではメッセージの配置を変更できないことに気付くかもしれません。このような変更は、DefaultInAppMessageViewWrapper クラスをサブクラス化してレイアウトパラメーターを調整することで可能になります。画面上の最終位置を調整するには、変更された LayoutParams を返す getLayoutParams メソッドを独自のカスタム位置決め値でオーバーライドします。開始するには、CustomSlideUpInAppMessageViewWrapper をご覧ください。

カスタムビューラッパー

カスタムレイアウトパラメーターをオーバーライドして返す
getLayoutParams メソッド内では、スーパークラスメソッドを使用して、アプリ内メッセージの元の LayoutParameters にアクセスできます。次に、必要に応じて加算または減算して位置を調整できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CustomSlideUpInAppMessageViewWrapper(inAppMessageView: View?,
                                           inAppMessage: IInAppMessage?,
                                           inAppMessageViewLifecycleListener: IInAppMessageViewLifecycleListener?,
                                           configurationProvider: BrazeConfigurationProvider?,
                                           openingAnimation: Animation?,
                                           closingAnimation: Animation?,
                                           clickableInAppMessageView: View?) : DefaultInAppMessageViewWrapper(inAppMessageView,
    inAppMessage,
    inAppMessageViewLifecycleListener,
    configurationProvider,
    openingAnimation,
    closingAnimation,
    clickableInAppMessageView) {

    override fun getLayoutParams(inAppMessage: IInAppMessage?): ViewGroup.LayoutParams {
        val params = super.getLayoutParams(inAppMessage) as FrameLayout.LayoutParams
        params.bottomMargin = params.bottomMargin + 500 //move the view up by 500 pixels
        return params
    }
}

カスタムレイアウトパラメーターをオーバーライドして返す
getLayoutParams メソッド内では、スーパークラスメソッドを使用して、アプリ内メッセージの元の LayoutParameters にアクセスできます。次に、必要に応じて加算または減算して位置を調整できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class CustomSlideUpInAppMessageViewWrapper extends DefaultInAppMessageViewWrapper {

    public CustomInAppMessageViewWrapper(View inAppMessageView,
                                           IInAppMessage inAppMessage,
                                           IInAppMessageViewLifecycleListener inAppMessageViewLifecycleListener,
                                           BrazeConfigurationProvider configurationProvider,
                                           Animation openingAnimation,
                                           Animation closingAnimation,
                                           View clickableInAppMessageView){
        super(inAppMessageView,
                inAppMessage,
                inAppMessageViewLifecycleListener,
                configurationProvider,
                openingAnimation,
                closingAnimation,
                clickableInAppMessageView)

    }
    
    @Override
    public ViewGroup.LayoutParams getLayoutParams(IInAppMessage inAppMessage){
        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)super.getLayoutParams(inAppMessage)
        params.bottomMargin = params.bottomMargin + 500 //move the view up by 500 pixels
        return params
    }
}

カスタムラッパーを返すためのカスタムファクトリーを指定する
Braze SDK でカスタムラッパーを使用するには、カスタムラッパーを返すカスタム IInAppMessageViewWrapperFactory 実装も指定する必要があります。IInAppMessageViewWrapperFactory を直接実装することも、BrazeInAppMessageViewWrapperFactory をサブクラス化して createInAppMessageViewWrapper メソッドのみをオーバーライドすることもできます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class CustomInAppMessageViewWrapperFactory : BrazeInAppMessageViewWrapperFactory() {

    override fun createInAppMessageViewWrapper(
        inAppMessageView: View?,
        inAppMessage: IInAppMessage?,
        inAppMessageViewLifecycleListener: IInAppMessageViewLifecycleListener?,
        configurationProvider: BrazeConfigurationProvider?,
        openingAnimation: Animation?,
        closingAnimation: Animation?,
        clickableInAppMessageView: View?
    ): IInAppMessageViewWrapper {
        return if (inAppMessage is InAppMessageSlideup) {
            CustomSlideUpInAppMessageViewWrapper( //return our custom view wrapper only for slideups
                inAppMessageView,
                inAppMessage,
                inAppMessageViewLifecycleListener,
                configurationProvider,
                openingAnimation,
                closingAnimation,
                clickableInAppMessageView
            )
        } else {
            super.createInAppMessageViewWrapper( //defer to the default implementation for all other IAM types
                inAppMessageView,
                inAppMessage,
                inAppMessageViewLifecycleListener,
                configurationProvider,
                openingAnimation,
                closingAnimation,
                clickableInAppMessageView
            )
        }
    }
}

カスタムラッパーを返すためのカスタムファクトリーを指定する
Braze SDK でカスタムラッパーを使用するには、カスタムラッパーを返すカスタム IInAppMessageViewWrapperFactory 実装を指定する必要があります。IInAppMessageViewWrapperFactory を直接実装することも、BrazeInAppMessageViewWrapperFactory をサブクラス化して createInAppMessageViewWrapper メソッドのみをオーバーライドすることもできます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class CustomInAppMessageViewWrapperFactory extends BrazeInAppMessageViewWrapperFactory {
    @Override
    public IInAppMessageViewWrapper createInAppMessageViewWrapper(View inAppMessageView, 
        IInAppMessage inAppMessage, 
        IInAppMessageViewLifecycleListener inAppMessageViewLifecycleListener, 
        BrazeConfigurationProvider configurationProvider, 
        Animation openingAnimation, 
        Animation closingAnimation, 
        View clickableInAppMessageView){
        if (inAppMessage instanceof InAppMessageSlideup){
            return new CustomSlideUpInAppMessageViewWrapper( //return our custom view wrapper only for slideups
                inAppMessageView,
                inAppMessage,
                inAppMessageViewLifecycleListener,
                configurationProvider,
                openingAnimation,
                closingAnimation,
                clickableInAppMessageView);
        }else{
            return super.createInAppMessageViewWrapper(//defer to the default implementation for all other IAM types
                inAppMessageView,
                inAppMessage,
                inAppMessageViewLifecycleListener,
                configurationProvider,
                openingAnimation,
                closingAnimation,
                clickableInAppMessageView);
        }
    }
}

ファクトリーを Braze に登録する
カスタムラッパーファクトリーを作成したら、BrazeInAppMessageManager を使用して Braze SDK に登録します。

1
BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewWrapperFactory(CustomInAppMessageViewWrapperFactory())

ファクトリーを Braze に登録する
カスタムラッパーファクトリーを作成したら、BrazeInAppMessageManager を使用して Braze SDK に登録します。

1
BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewWrapperFactory(new CustomInAppMessageViewWrapperFactory());

カスタムモーダルアプリ内メッセージ

BrazeInAppMessageModalView をサブクラス化すると、貴重なユーザー属性を収集する魅力的な方法となる Spinner を活用できます。次の例は、コネクテッドコンテンツを使用して項目の動的リストからカスタム属性をキャプチャする方法を示しています。開始するには、TeamPickerView にアクセスしてください。

UI 表示動作に view_type を使用
IInAppMessage オブジェクトの extras ディクショナリをクエリすると、view_type キー (ある場合) を検索して正しいタイプのビューを表示できます。アプリ内メッセージはメッセージごとに設定されるため、カスタムとデフォルトのモーダルビューが調和して機能することに注意してください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
override fun createInAppMessageView(activity: Activity, inAppMessage: IInAppMessage): View {
  return when {
      inAppMessage.extras?.get("view_type") == "picker" -> {
          getCustomPickerView(activity, inAppMessage)
      }
      //...
      else -> {
          //Defer to default
          BrazeInAppMessageManager
              .getInstance()
              .getDefaultInAppMessageViewFactory(inAppMessage).createInAppMessageView(activity, inAppMessage)
      }
  }
}

UI 表示動作に view_type を使用
IInAppMessage オブジェクトの extras ディクショナリをクエリすると、view_type キー (ある場合) を検索して正しいタイプのビューを表示できます。アプリ内メッセージはメッセージごとに設定されるため、カスタムとデフォルトのモーダルビューが調和して機能することに注意してください。

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public View createInAppMessageView(Activity activity, IInAppMessage inAppMessage) {
    if("picker".equals(inAppMessage.getExtras().get("view_type"))){
        return getCustomPickerView(activity, inAppMessage);
    } else {
        //Defer to default
        BrazeInAppMessageManager
          .getInstance()
          .getDefaultInAppMessageViewFactory(inAppMessage)
          .createInAppMessageView(activity, inAppMessage);
    }
}

オーバーライドしてカスタムビューを提供する
標準のモーダルアプリ内メッセージを模倣したレイアウトを提供しますが、ビューをルート要素として指定し、そのレイアウトをインフレートします

1
2
3
4
5
6
7
8
9
10
11
<com.braze.advancedsamples.inapp.modal.TeamPickerView xmlns:android="http://schemas.android.com/apk/res/android"
                                                      xmlns:tools="http://schemas.android.com/tools"
                                                      android:layout_width="match_parent"
                                                      android:layout_height="match_parent"
                                                      android:padding="0.0dp"
                                                      android:id="@+id/team_picker_view">
    <!-- ... -->
    <Spinner android:layout_width="match_parent" android:layout_height="wrap_content"
                     android:id="@+id/team_spinner"/>
    <!-- ... -->                                                      
</com.braze.advancedsamples.inapp.modal.TeamPickerView>

ビューをインフレートしてカスタマイズする
Spinner コンポーネントをリロードする前に、inAppMessage メッセージ変数は文字列として出力されます。正しく表示するには、このメッセージを項目の配列としてフォーマットする必要があります。例として、これは String.split(",") を使用して実現できます。

1
2
3
4
5
6
private fun getCustomView(activity: Activity, inAppMessage: IInAppMessage): TeamPickerView {
        val view = activity.layoutInflater.inflate(R.layout.team_picker_dialog, null) as TeamPickerView
        val teams = inAppMessage.message.split(",")
        view.setTeams(teams)
        return view
    }

ビューをインフレートしてカスタマイズする
Spinner コンポーネントをリロードする前に、inAppMessage メッセージ変数は_文字列_として出力されます。正しく表示するには、このメッセージを項目の配列としてフォーマットする必要があります。例として、これは String.split(",") を使用して実現できます。

1
2
3
4
5
6
private TeamPickerView getCustomView(Activity activity, IInAppMessage inAppMessage) {
        TeamPickerView view = (TeamPickerView) activity.getLayoutInflater().inflate(R.layout.team_picker_dialog, null);
        String[] teams = inAppMessage.getMessage().split(",");
        view.setTeams(teams);
        return view
    }

カスタム属性を割り当てる
ユーザーが [送信] を押した後、ビューサブクラスを使用して、属性とそれに対応する選択済みの値を Braze に渡し、messageClickableView.performClick() を呼び出してアプリ内メッセージを閉じます。

1
2
3
4
5
6
7
    override fun onClick(v: View?) {
        val selectedTeam = spinner.selectedItem as String
        messageClickableView.performClick()
        Braze.getInstance(ctx).getCurrentUser { brazeUser ->
            brazeUser?.setCustomUserAttribute("FavoriteTeam", selectedTeam)
        }
    }

カスタム属性を割り当てる
ユーザーが [送信] を押した後、ビューサブクラスを使用して、属性とそれに対応する選択済みの値を Braze に渡し、messageClickableView.performClick() を呼び出してアプリ内メッセージを閉じます。

1
2
3
4
5
6
7
8
    @Override
    public void onClick(View v) {
        String selectedTeam = (String) spinner.getSelectedItem();
        messageClickableView.performClick();
        Braze.getInstance(ctx).getCurrentUser(brazeUser -> {
            brazeUser.setCustomUserAttribute("FavoriteTeam", selectedTeam);
        });
    }

カスタムフルアプリ内メッセージ

完全にカスタムの没入型 (全画面) アプリ内メッセージを実装するには、カスタマイズされたモーダルアプリ内メッセージの実装に関するセクションで説明したのと同様のアプローチが必要です。ただし、この例では、単に BrazeInAppMessageFullView を拡張し、必要に応じてカスタマイズします。ビューはアプリケーション UI 上に表示され、Android のビューはデフォルトで透明であることに注意してください。つまり、アプリ内メッセージによって背景の内容が見えにくくなるような背景を定義する必要があります。BrazeInAppMessageFullView を拡張することにより、Braze SDK はビュー上のタッチイベントのインターセプトを処理し、適切なアクションを実行します。モーダルの例と同様に、特定のコントロール (Switch コントロールなど) でこの動作をオーバーライドして、ユーザーからのフィードバックを収集できます。

UI 表示動作に view_type を使用
新しい没入型カスタマイズのために、view_type エクストラをもう 1 つ追加します。createInAppMessageView メソッドをもう一度見直して、「スイッチ」UI のオプションを追加します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
override fun createInAppMessageView(activity: Activity, inAppMessage: IInAppMessage): View {
    return when {
        inAppMessage.extras?.get("view_type") == "picker" -> {
            getCustomPickerView(activity, inAppMessage)
        }
        inAppMessage.extras?.get("view_type") == "switches" -> {
            getCustomImmersiveView(activity, inAppMessage) // new customization
        }
        else -> {
            //Defer to default
            BrazeInAppMessageManager
                .getInstance()
                .getDefaultInAppMessageViewFactory(inAppMessage).createInAppMessageView(activity, inAppMessage)
        }
    }
}

UI 表示動作に view_type を使用
新しい没入型カスタマイズのために、view_type エクストラをもう 1 つ追加します。createInAppMessageView メソッドをもう一度見直して、「スイッチ」UI のオプションを追加します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public View createInAppMessageView(Activity activity, IInAppMessage inAppMessage) {
    if("picker".equals(inAppMessage.getExtras().get("view_type"))){
        return getCustomPickerView(activity, inAppMessage);
    } else if ("switches".equals(inAppMessage.getExtras().get("view_type"))) {
        return getCustomImmersiveView(activity, inAppMessage); // new customization
    } else {
        //Defer to default
        BrazeInAppMessageManager
          .getInstance()
          .getDefaultInAppMessageViewFactory(inAppMessage)
          .createInAppMessageView(activity, inAppMessage);
    }
}

オーバーライドしてカスタムビューを提供する
標準のモーダルアプリ内メッセージを模倣したレイアウトを提供しますが、ビューをルート要素として指定し、そのレイアウトをインフレートします

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<com.braze.advancedsamples.immersive.CustomImmersiveInAppMessage
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
        android:layout_height="wrap_content">
    <!-- giving the parent layout a white backround color will obscure the app behind the IAM. You could also do this within your custom view -->
    <LinearLayout android:background="@color/white" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> 
        <!-- ... -->
        <androidx.recyclerview.widget.RecyclerView android:layout_width="match_parent"
                                                       android:layout_height="wrap_content"
                                                       android:id="@+id/option_list"/>
        <!-- ... -->
    </LinearLayout>
</com.braze.advancedsamples.immersive.CustomImmersiveInAppMessage>

ビューをインフレートしてカスタマイズする
RecyclerView コンポーネントのオプションを設定する前に、inAppMessage メッセージ変数が_文字列_として出力されます。正しく表示するには、このメッセージを項目の配列としてフォーマットする必要があります。例として、これは String.split(",") を使用して実現できます。titlesubtitleextrasバンドルから抽出されます。

1
2
3
4
5
6
7
8
private fun getCustomImmersiveView(activity: Activity, inAppMessage: IInAppMessage): CustomImmersiveInAppMessage{
    val view = activity.layoutInflater.inflate(R.layout.full_screen_iam, null) as CustomImmersiveInAppMessage
    val options = inAppMessage.message.split(",")
    view.setOptions(options)
    inAppMessage.extras?.get("title").let { view.setTitle(it) }
    inAppMessage.extras?.get("subtitle").let {view.setSubtitle(it) }
    return view
}

ビューをインフレートしてカスタマイズする
RecyclerView コンポーネントのオプションを設定する前に、inAppMessage メッセージ変数が_文字列_として出力されます。正しく表示するには、このメッセージを項目の配列としてフォーマットする必要があります。例として、これは String.split(",") を使用して実現できます。titlesubtitleextrasバンドルから抽出されます。

1
2
3
4
5
6
7
8
9
10
private CustomImmersiveInAppMessage getCustomImmersiveView(Activity activity, IInAppMessage inAppMessage) {
    CustomImmersiveInAppMessage view = (CustomImmersiveInAppMessage) activity.layoutInflater.inflate(R.layout.full_screen_iam, null);
    String[] options = inAppMessage.message.split(",");
    view.setOptions(options);
    String title = inAppMessage.getExtras().get("title");
    view.setTitle(title);
    String subtitle = inAppMessage.getExtras().get("subtitle"); 
    view.setSubtitle(subtitle);
    return view;
}

カスタム属性を割り当てる
ユーザーがいずれかのスイッチを切り替えた後、ビューサブクラスを使用して、関連する属性とトグルステータスを Braze に渡します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fun logClick(value:String, checked:Boolean){
    Braze.getInstance(ctx).logCustomEvent("SwitchChanged", BrazeProperties())
}

inner class OptionViewHolder(item: View): RecyclerView.ViewHolder(item), View.OnClickListener{

    var value: String = ""

    override fun onClick(p0: View?) {
        if (p0 is Switch){
            val checked = p0.isChecked
            p0.isChecked = !p0.isChecked
            logClick(value, checked)
        }
    }
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OptionViewHolder {
    return OptionViewHolder(mInflater.inflate(R.layout.switch_cell, null))
}

override fun onBindViewHolder(holder: OptionViewHolder, position: Int) {
    holder.itemView.findViewById<TextView>(R.id.label).text = options[position]
    holder.value = options[position]
}

カスタム属性を割り当てる
ユーザーがいずれかのスイッチを切り替えた後、ビューサブクラスを使用して、関連する属性とトグルステータスを Braze に渡します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private void logClick(String value, boolean checked){
    Braze.getInstance(ctx).logCustomEvent("SwitchChanged", new BrazeProperties());
}

private class OptionViewHolder extends RecyclerView.ViewHolder, implements View.OnClickListener{

    private String value = "";

    public OptionViewHolder(View item){
        super(item);
    }

   
    @Override
    public void onClick(View view) {
        if (view instanceof Switch){
            Switch switchView = (Switch) view;
            boolean checked = switchView.isChecked;
            switchView.isChecked = !switchView.isChecked;
            logClick(value, checked)
        }
    }
}

@Override
public OptionViewHolder onCreateViewHolder(ViewGroup parent, Int viewType) {
    return new OptionViewHolder(mInflater.inflate(R.layout.switch_cell, null));
}

@Override
public void onBindViewHolder(OptionViewHolder holder, Int position) {
    ((TextView)holder.getItemView().findViewById(R.id.label)).setText(options.get(position));
    holder.value = options.get(position);
}

アプリ内メッセージタッチのインターセプト

Androidデバイスが設定とトグルの行を表示しています。カスタムビューはボタンを処理し、ボタンコントロールの外側のタッチはアプリ内メッセージによって処理され、削除されます。 カスタムフルアプリ内メッセージボタンを正しく機能させるには、アプリ内メッセージのタッチをインターセプトすることが重要です。デフォルトでは、すべてのアプリ内メッセージビューにonClickリスナーが追加されるため、ユーザーはボタンなしでメッセージを閉じることができます。カスタムボタンなど、ユーザー入力に応答するカスタムコントロールを追加する場合は、通常どおりビューにonClickリスナーを登録できます。カスタムコントロールの外側をタッチすると、通常通りアプリ内メッセージが閉じられ、カスタムコントロールが受け取ったタッチはあなたのonClickリスナーを呼び出します。

「このページはどの程度役に立ちましたか?」
New Stuff!