# Braze Developer Guide Full Text Consolidated full markdown text for all pages in the Developer Guide collection. # Braze 開発者ガイド Source: /docs/ja/developer_guide/home/index.md Braze 開発者ガイド ここでは、開発者がBraze SDKについて知る必要のあるすべての情報を得ることができます。各SDKは独自のGitHub公開リポジトリでホストされており、Brazeの機能をテストしたり、独自のアプリケーションと一緒に実装したりするために使用できる、完全にビルド可能なサンプルアプリが含まれています。詳しくは、 参照資料、リポジトリ、サンプルアプリ をご覧ください。 Brazeを使って開発している他の開発者とつながり、学び、刺激を受けませんか? Braze 開発者コミュニティ にぜひご参加ください! このランディングページでは、開発者がBrazeで利用可能なすべての統合を確認できます。 Featured: - Web - Android - Swift # はじめに Source: /docs/ja/developer_guide/getting_started/index.md
このガイドに沿って進めることもできますし、[Braze Learning](https://learning.braze.com)で[マーケター](https://learning.braze.com/path/marketer)や[開発者](https://learning.braze.com/path/developer)の学習パスなどのガイド付きコースをチェックすることもできます。

# 開発者向けのSDK概要 Source: /docs/ja/developer_guide/getting_started/sdk_overview/index.md # [![Brazeラーニングコース](https://www.braze.com/docs/ja/ja/assets/img/bl_icon3.png?5f6465f63e399dec15d7020b6f4d2452)](https://learning.braze.com/path/developer/sdk-integration-basics){: style="float:right;width:120px;border:0;" class="noimgborder"}開発者向けSDKの概要 {#braze-learning-course-image_buster-assetsimgbl_icon3png-httpslearningbrazecompathdevelopersdk-integration-basics-stylefloatrightwidth120pxborder0-classnoimgbordersdk-overview-for-developers} > Braze SDKの統合を開始する前に、正確に何を構築および統合するのかを疑問に思うかもしれません。また、ニーズに応じてSDKをより詳細にカスタマイズする方法に興味があるかもしれません。この記事は、SDKに関するすべての疑問を解決するのに役立ちます。 SDKの基本的な概要を探しているマーケターは、代わりに[マーケター向けの概要](https://www.braze.com/docs/ja/ja/user_guide/get_started/sdk_overview)をご覧ください。 Braze SDKを簡単に説明すると、次のとおりです。 * ユーザーデータを収集し、統合ユーザープロファイルに同期します * セッションデータ、デバイス情報、プッシュトークンを自動的に収集します * マーケティングエンゲージメントデータとビジネスに固有のカスタムデータを取得します * プッシュ通知、**In-App Messages**、コンテンツカードメッセージングチャネルを強化します 以下の動画で、Braze SDKの統合の基本とコア機能について簡単に紹介しています。 ## アプリのパフォーマンス {#app-performance} Brazeがアプリのパフォーマンスに悪影響を及ぼすことはありません。 Braze SDKのフットプリントは非常に小さいです。手動のネットワーク制御が許可されるのに加え、ネットワークの品質に応じ、ユーザーデータをフラッシュするレートの自動変更が実行されます。SDKからのAPIリクエストを自動的にバッチ処理して、ネットワーク効率を常に最大化しながらデータが迅速にロギングされるようにします。最後に、各API呼び出し内でクライアントからBrazeに送信されるデータは非常に少量です。 ## SDKの互換性 {#sdk-compatibility} Braze SDKは非常に円滑に動作し、アプリ内に存在する他のSDKに干渉しないよう設計されています。他のSDKとの互換性不足が原因と思われる問題が発生している場合は、Brazeサポートにお問い合わせください。 ## デフォルトの分析とセッション処理 {#default-analytics-and-session-handling} 最初に使用したアプリ、最後に使用したアプリ、合計セッション数、デバイスOSなど、特定のユーザーデータはSDKで自動的に収集されます。統合ガイドに従ってSDKを実装すると、この[デフォルトデータ収集](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/sdk_data_collection)を利用できるようになります。このリストを確認することで、ユーザーに関する同じ情報を複数回保存しなくて済みます。セッション開始とセッション終了を除き、その他の自動的にトラッキングされるデータは、データポイント使用量にはカウントされません。 **Note:** すべての機能が構成可能ですが、デフォルトのデータ収集モデルを完全に実装することをお勧めします。
ユースケースで必要な場合は、統合の完了後に[特定のデータの収集を制限](#blocking-data-collection)できます。 ## データのアップロードとダウンロード {#data-upload-and-download} Braze SDKでは、データ(セッション、カスタムイベントなど)がキャッシュされ、定期的にアップロードされます。データがアップロードされた後でのみ、ダッシュボード上で値が更新されます。アップロード間隔は、デバイスの状態を考慮し、ネットワーク接続の品質に基づいて決定されます。 | ネットワーク接続品質 | データフラッシュ間隔 | |---|---| | 素晴らしい | 10秒 | | 良好 | 30秒 | | 不良 | 60秒 | {: .reset-td-br-1 .reset-td-br-2 aria-label="データのアップロードとダウンロード" } ネットワーク接続がない場合、ネットワーク接続が再確立されるまで、データはデバイスのローカルにキャッシュされます。接続が再確立されると、データがBrazeにアップロードされます。 セッションの時点でユーザーが属するセグメントに基づいて、セッションの開始時にBrazeからSDKにデータが送信されます。新しいアプリ内メッセージはセッション中に更新されません。ただし、セッション中のユーザーデータは、クライアントから送信されると継続的に処理されます。たとえば、離脱ユーザー(アプリを最後に使用してから7日以上経過)には、アプリに戻ってから最初のセッションで、離脱ユーザーをターゲットにしたコンテンツが提供されます。 ## データ収集のブロック {#blocking-data-collection} SDK統合からの特定のデータの自動収集をブロックしたり、そのプロセスを許可リストに登録したりすることは(推奨はされませんが)可能です。 分析データを削除すると、プラットフォームのパーソナライゼーションとターゲット設定の能力が低下するため、データ収集をブロックすることは推奨されません。以下はその例です。 - いずれかのSDKで位置情報を完全に統合しないことを選択した場合、言語や位置情報に基づいてメッセージングをパーソナライズできません。 - タイムゾーンを統合しないことを選択した場合、ユーザーのタイムゾーン内でメッセージを送信できない可能性があります。 - 特定のデバイスビジュアル情報を統合しないことを選択した場合、メッセージのコンテンツがそのデバイス向けに最適化されない可能性があります。 製品の機能を最大限に活用するには、SDKを完全に統合することを強くお勧めします。 SDKの特定の部分を統合しないことも、ユーザーに対して[`disableSDK`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#disablesdk)を使用することもできます。このメソッドにより、`disableSDK()`の呼び出し前にロギングされたデータが同期され、このページと将来のページの読み込みに対するその後のBraze Web SDKの呼び出しはすべて無視されます。後の時点でデータ収集を再開するには、[`enableSDK()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#enablesdk)メソッドを使用できます。この詳細については、[Webトラッキングの無効化](https://www.braze.com/docs/ja/ja/developer_guide/analytics/managing_data_collection?sdktab=web)に関する記事をご覧ください。 [`setDeviceObjectAllowlist`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-device-object-allowlist.html?query=fun%20setDeviceObjectAllowlist(deviceObjectAllowlist:%20EnumSet%3CDeviceKey%3E):%20BrazeConfig.Builder)を使用し、設定された許可リストに従ってデバイスオブジェクトのキーまたは値のサブセットのみを送信するようSDKを構成できます。これは[`setDeviceObjectAllowlistEnabled`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-device-object-allowlist-enabled.html?query=fun%20setDeviceObjectAllowlistEnabled(enabled:%20Boolean):%20BrazeConfig.Builder)を介して有効にする必要があります。 **Important:** 許可リストが空の場合、デバイスデータはBrazeに送信**されません**。 `Braze.Configuration`で対象となるフィールドのセットを[`configuration.devicePropertyAllowList`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/devicepropertyallowlist)に割り当て、SDKで収集されるデバイスフィールドの許可リストを指定することができます。フィールドの完全なリストは[`Braze.Configuration.DeviceProperty`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/deviceproperty)で定義されます。すべてのデバイスフィールドの収集をオフにするには、このプロパティの値を空のセット (`[]`) に設定します。 **Important:** デフォルトでは、Braze Swift SDKですべてのフィールドが収集されます。一部のデバイスプロパティを削除すると、SDK機能が無効になる場合があります。 使用の詳細については、Swift SDKドキュメントの[ストレージ](https://www.braze.com/docs/ja/ja/developer_guide/storage?tab=swift)を参照してください。 ## 使用しているSDKバージョンの確認 {#what-version-of-the-sdk-am-i-on} ダッシュボードを使用して、**設定** > **アプリ設定**から特定のアプリのSDKバージョンを確認できます。**ライブSDKバージョン**には、ユーザーの5%以上を対象とする最新のライブアプリケーションで使用されている最上位のBraze SDKバージョンが表示されます。 ![ワークスペースのSwiftyという名前のアプリ。ライブSDKバージョンは6.6.0です。](https://www.braze.com/docs/ja/ja/assets/img/live-sdk-version.png?a647431a93a71779132d1868f65c6003){: style="max-width:80%"} **Tip:** iOSアプリをお持ちの場合、**ライブSDKバージョン**が5.0.0(最初にリリースされたSwift SDKのバージョン)以降であれば、従来の[Objective-C iOS SDK](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/overview)の代わりに[Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=swift)を使用していることを確認できます。 # プラットフォームの概要 Source: /docs/ja/developer_guide/getting_started/platform_overview/index.md # [![Brazeラーニングコース](https://www.braze.com/docs/ja/ja/assets/img/bl_icon3.png?5f6465f63e399dec15d7020b6f4d2452)](https://learning.braze.com/path/developer){: style="float:right;width:120px;border:0;" class="noimgborder"}はじめに:プラットフォームの概要 {#braze-learning-course-image_buster-assetsimgbl_icon3png-httpslearningbrazecompathdeveloper-stylefloatrightwidth120pxborder0-classnoimgbordergetting-started-platform-overview} > この記事では、Brazeプラットフォームの基本的なパーツと機能について説明します。この記事からのリンクは、Brazeの重要なトピックにつながっています。 **Tip:** これらの記事とあわせて、無料の[開発者ラーニングパス](https://learning.braze.com/path/developer)コースもぜひご覧ください。 ## Brazeとは {#what-is-braze} Brazeはカスタマーエンゲージメントプラットフォームです。ユーザーデータを取り込み、ユーザーのアクションや行動を可視化し、それらに基づいてアクションを実行できるようにします。このプラットフォームは主に3つの構成要素から成っています:SDK、ダッシュボード、そしてREST APIです。 Brazeのより一般的な概要を知りたいマーケターの方は、代わりに[マーケター向けの「はじめに」セクション](https://www.braze.com/docs/ja/ja/user_guide/get_started)をご覧ください。 ![Brazeにはさまざまなレイヤーがあります。全体として、SDK、API、ダッシュボード、およびパートナー連携から構成されています。これらはそれぞれ、データインジェストレイヤー、分類レイヤー、オーケストレーションレイヤー、パーソナライゼーションレイヤー、およびアクションレイヤーの一部を構成します。アクションレイヤーには、プッシュ、アプリ内メッセージ、コネクテッドカタログ、Webhook、SMS、メールなど、さまざまなチャネルがあります。](https://www.braze.com/docs/ja/ja/assets/img/getting-started/getting-started-vertically-integrated-stack.png?7db6090d44479dae3468b2bc7ef53b82){: style="max-width:55%;float:right;margin-left:15px;"} ### SDK [Braze SDK](#integrating-braze)をモバイルアプリケーションおよびWebアプリケーションに統合して、強力なマーケティング、ユーザー管理、および分析ツールを提供できます。 つまり、完全に統合されると、SDKは次を行います。 * ユーザーデータを収集し、統合されたユーザープロファイルに同期します * セッションデータ、デバイス情報、プッシュトークンを自動的に収集します * マーケティングエンゲージメントデータとお客様のビジネスに特化したカスタムデータを取得します * セキュリティを重視した設計で、サードパーティによる侵入テストが実施されています * 低バッテリーや低速ネットワークのデバイスに最適化されています * セキュリティを強化するため、サーバー側のJWT署名をサポートします * システムへの書き込み専用アクセス権を持ちます(ユーザーデータを取得できません) * プッシュ通知、アプリ内メッセージ、Content Cardsのメッセージングチャネルを強化します ### ダッシュボードのユーザーインターフェイス {#dashboard-user-interface} ダッシュボードは、Brazeプラットフォームの中心にあるすべてのデータとインタラクションを制御するUIです。マーケターはダッシュボードを使って業務を行い、コンテンツを作成します。開発者はダッシュボードを使い、APIキーやプッシュ通知の認証情報など、アプリを統合するための設定を管理します。 始めたばかりの場合は、チーム管理者がダッシュボードであなた(およびBrazeへのアクセスが必要な他のチームメンバー全員)を[ユーザーとして追加](https://www.braze.com/docs/ja/ja/user_guide/administer/personal)する必要があります。 ### REST API Braze APIを使えば、Brazeからデータを大規模に出し入れすることができます。APIを使用して、バックエンド、データウェアハウス、その他のファーストパーティソースおよびサードパーティソースから更新を取り込みます。さらに、APIを使って、Webベースのアプリケーションから直接、セグメンテーション目的のカスタムイベントを追加することもできます。APIを通じてメッセージをトリガーしたり送信したりできるので、テクニカルリソースはキャンペーンの一部として複雑なJSONメタデータを含めることができます。 また、このAPIは、モバイルおよびWeb SDKを経由せず、HTTP経由で直接ユーザーが実行したアクションを記録できるWebサービスも提供します。webhookと組み合わせることで、アプリ体験の内外でユーザーのアクションを追跡し、アクティビティをトリガーできます。[APIガイド](https://www.braze.com/docs/ja/ja/api/home)には、利用可能なBraze APIエンドポイントとその用途が記載されています。 Brazeの構成要素については、以下を確認してください:[はじめに:アーキテクチャの概要](https://www.braze.com/docs/ja/ja/developer_guide/getting_started/architecture_overview) ## データ分析とアクション {#data-analysis-and-action} Brazeに保存されたデータは、Brazeの顧客である限り保持され、セグメンテーション、パーソナライゼーション、およびターゲティングに使用できます。これにより、その情報を廃止することを選択するまで、ユーザープロファイルデータ(たとえば、セッションアクティビティや購入)に対して操作を行うことができます。例えば、ストリーミングサービスは、各サブスクライバーがサービス利用開始日から(それが何年も前であっても)視聴したコンテンツを追跡し、そのデータを使用して関連するメッセージングを強化できます。 ![Brazeダッシュボードにある「最近の購入者」というセグメントと、「リンダへのおすすめ」というメールが表示された電話画面が並んでいる。](https://www.braze.com/docs/ja/ja/assets/img/getting-started/getting-started-segment.png?49ccc2dc1192203b8b8c942cc1899a61){: style="max-width:80%"} ### アプリ分析 {#app-analytics} Brazeダッシュボードは、分析指標と設定したカスタムイベントに基づき、リアルタイムで更新されるグラフを表示します。ABテスト、カスタムレポート、分析、自動インテリジェンスを用いた一貫した測定と最適化は、カスタマーエンゲージメントと差別化を支援します。 ### ユーザーセグメンテーション {#user-segmentation} セグメンテーションを利用することで、アプリ内での行動やユーザー層データなどの強力なフィルターに基づいて、ユーザーのグループを作成できます。また、Brazeでは、希望するアクションがデフォルトでキャプチャされない場合、任意のアプリ内ユーザーアクションを「カスタムイベント」として定義できます。同じことが、「カスタム属性」によるユーザー特性にも当てはまります。ダッシュボード上でユーザーセグメントが作成されると、ユーザーは定義された基準を満たす(または満たさない)ごとにセグメントを出たり入ったりします。例えば、アプリ内でお金を使い、最後にアプリを使ったのが2週間以上前であるすべてのユーザーを含むセグメントを作成できます。 データモデルについては、こちらをご覧ください:[はじめに:分析の概要](https://www.braze.com/docs/ja/ja/developer_guide/getting_started/architecture_overview) ## マルチチャネルメッセージング {#multichannel-messaging} セグメントを定義した後、Brazeのメッセージングツールを使えば、ダイナミックでパーソナライズされた方法でユーザーに働きかけることができます。Brazeはチャネルにとらわれないユーザー中心のデータモデルで設計されています。メッセージングは、アプリやサイトの内部(アプリ内メッセージの送信や、Content Cardsのカルーセルやバナーなどのグラフィック要素)で行われることもあれば、アプリの外部(プッシュ通知やメールの送信など)で行われることもあります。例えば、マーケターは、前のセクションで定義した例のセグメントにプッシュ通知とメールを送ることができます。 ![アプリやWebサイトの外でも内でも、あらゆるチャネルでパーソナライズされたメッセージを作成し、トリガーする。](https://www.braze.com/docs/ja/ja/assets/img/getting-started/messaging-channels.png?984cc41c1b4056ebc839f99e21797d1d){: style="border:none" } | チャネル | 説明 | | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | [Content Cards](https://www.braze.com/docs/ja/ja/user_guide/channels/content_cards)* | 顧客の作業を中断することなく、高度にターゲットを絞ったダイナミックなアプリ内通知を送信します。 | | [メール](https://www.braze.com/docs/ja/ja/user_guide/channels/email) | リッチテキストエディター、ドラッグ&ドロップエディター、または既存のHTMLテンプレートをアップロードしてメールを作成し、リッチなHTMLメッセージを送信します。 | | [アプリ内メッセージ](https://www.braze.com/docs/ja/ja/in-app_messages) | Brazeが独自に構築したネイティブユーザーインターフェイスを使用して、控えめなアプリ内通知を送信します。 | | [プッシュ](https://www.braze.com/docs/ja/ja/user_guide/channels/push) | iOS用のApple Push Notification Service(APNs)またはAndroid用のFirebase Cloud Messaging(FCM)を使用して、メッセージングキャンペーンまたはニュースアイテムから自動的にプッシュ通知をトリガーします。 | | [SMS、MMS、およびRCS](https://www.braze.com/docs/ja/ja/user_guide/channels/sms_mms_and_rcs)* | SMS、MMS、またはRCSを使用して、取引通知、プロモーションの共有、リマインダーの送信などを行います。 | | [Webプッシュ](https://www.braze.com/docs/ja/ja/user_guide/channels/push/platform_specific_resources/web) | ユーザーが現在サイトでアクティブでない場合でも、Webブラウザー通知を送信します。 | | [Webhook](https://www.braze.com/docs/ja/ja/about_webhooks) | webhookを使ってアプリ以外のアクションをトリガーし、他のシステムやアプリケーションにリアルタイムデータを提供します。 | | [WhatsApp](https://www.braze.com/docs/ja/ja/user_guide/channels/whatsapp/whatsapp_setup)* | 広く普及しているピアツーピアメッセージングプラットフォームであるWhatsAppを活用して、ユーザーや顧客と直接つながります。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="マルチチャネルメッセージング" } *アドオン機能として利用できます。* ### カスタマイズ可能なコンポーネント {#customizable-components}

## Brazeを統合する {#integrating-braze} Brazeは迅速な統合のために設計されています。顧客ベース全体での平均的な価値実現までの期間は6週間です。統合プロセスに関する詳細は、[はじめに:統合の概要](https://www.braze.com/docs/ja/ja/developer_guide/getting_started/integration_overview)を参照してください。 ## ブックマークすべきリソース {#resources-to-bookmark} テクニカルリソースとして、Brazeの肝心な部分の多くに携わることになります。ドキュメント以外でブックマークしておくとよいリソースを以下に紹介します。今後、Brazeの用語について質問がある場合は、[用語集](https://www.braze.com/docs/ja/ja/user_guide/get_started/terms_to_know)を手元に置いておくとよいでしょう。 | リソース | 学べる内容 | |---|---| | [SDKのデバッグ](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/debugging) | 統合をトラブルシューティングする際には、SDKデバッグツールが役に立ちます。必ず手元に置いておきましょう。 | | [Braze Public GitHub](https://github.com/braze-inc/) | 統合に関する詳細な情報とサンプルコードについては、GitHubリポジトリを参照してください。 | | [Android SDK GitHubリポジトリ](https://github.com/braze-inc/braze-android-sdk/) | Android SDKのGitHubリポジトリです。 | | [Android SDKリファレンス](https://appboy.github.io/appboy-android-sdk/kdoc/index.html) | Android SDKのクラスドキュメントです。 | | [iOS(Swift)SDK GitHubリポジトリ](https://github.com/braze-inc/braze-swift-sdk) | Swift SDKのGitHubリポジトリです。 | | [iOS(Swift)SDKリファレンス](https://braze-inc.github.io/braze-swift-sdk/) | iOS SDKのクラスドキュメントです。 | | [Web SDK GitHubリポジトリ](https://github.com/braze-inc/braze-web-sdk) | Web SDKのGitHubリポジトリです。 | | [Web SDKリファレンス](https://js.appboycdn.com/web-sdk/5.0/doc/modules/braze.html) | iOS SDKのクラスドキュメントです。 | | [SDK変更ログ](https://www.braze.com/docs/ja/ja/developer_guide/changelogs) | Brazeは、重要な問題や主要なOS更新のリリースに加えて、予測可能な毎月のリリースを提供しています。 | | [Braze API Postman Collection](https://documenter.getpostman.com/view/4689407/SVYrsdsG?version=latest) | Postman Collectionはこちらからダウンロードできます。 | | [Braze System Status Monitor](https://braze.statuspage.io/) | ステータスページは、インシデントや障害が発生するたびに更新されます。アラートをサブスクライブするには、このページにアクセスしてください。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="ブックマークすべきリソース" } # 統合の概要 Source: /docs/ja/developer_guide/getting_started/integration_overview/index.md # [![Brazeラーニングコース](https://www.braze.com/docs/ja/ja/assets/img/bl_icon3.png?5f6465f63e399dec15d7020b6f4d2452)](https://learning.braze.com/sdk-integration-basics){: style="float:right;width:120px;border:0;" class="noimgborder"}はじめに:統合の概要 {#braze-learning-course-image_buster-assetsimgbl_icon3png-httpslearningbrazecomsdk-integration-basics-stylefloatrightwidth120pxborder0-classnoimgbordergetting-started-integration-overview} > この記事では、オンボーディングプロセスの基本的な概要を説明します。 ![発見、統合、品質保証、保守という4つの円のベン図。中心に「価値実現までの時間」が配置されています。](https://www.braze.com/docs/ja/ja/assets/img/getting-started/getting-started-integrate-flower.png?ea5115f1b341c19262b76cbc61681a7f){: style="max-width:50%;float:right;margin-left:15px;border:none;"} 技術リソースとして、Brazeを技術スタックに統合することでチームを強化できます。オンボーディングは大きく4つのステップに分けられます。 * [発見と計画](#discovery):チームと協力してスコープを調整し、データとキャンペーンの構造を計画し、適切なワークスペース構造を作成します。 * [統合](#integration):SDKとAPIを統合し、メッセージングチャネルを有効にし、データのインポートとエクスポートを設定することで計画を実行します。 * [品質保証](#qa):Brazeプラットフォームとアプリまたはサイト間のデータとメッセージングのループが期待通りに機能していることを確認します。 * [メンテナンス](#maintenance):Brazeをマーケティングチームに引き渡した後も、すべてがスムーズに実行されるよう引き続き確認します。
**Tip:** すべての組織には固有のニーズがあることを認識しており、Brazeはお客様の特定の要件に合わせてカスタマイズできる多様なオプションに対応するよう構築されています。統合にかかる時間はユースケースによって異なります。 ## 発見と計画 {#discovery} このフェーズでは、チームと協力してオンボーディングタスクの範囲を設定し、すべての利害関係者が共通の目標に向けて足並みを揃えていることを確認します。 チームはユースケースのエンドツーエンドの計画を行い、すべてが期待通りに構築でき、そのために適切なデータが利用できることを確認します。このフェーズには、プロジェクトリード、CRMリード、フロントエンドとバックエンドのエンジニアリング、プロダクトオーナー、マーケターが含まれます。 発見と計画のフェーズには、平均して約6週間かかります。エンジニアリングリードはこのフェーズで週に2〜4時間を費やすことが予想されます。製品に携わる開発者は、発見と計画のフェーズで週に10〜20時間をBrazeに費やすことが予想されます。 **Tip:** 御社のオンボーディング期間中、Brazeは技術概要セッションを開催します。エンジニアにはこれらのセッションに参加することを強く推奨します。技術概要セッションでは、プラットフォームアーキテクチャのスケーラビリティについて話し合ったり、同規模の企業が同様のユースケースで過去にどのように成功したかという実践的な事例を見たりする機会が得られます。 ![メール、ショッピングカート、画像、ジオロケーションなど、さまざまなチャネルのアイコン。](https://www.braze.com/docs/ja/ja/assets/img/getting-started/data-graphic-2.png?4857888e3b2e88b8212850d9df985318){: style="max-width:40%;float:right;margin-left:15px;"} ### キャンペーン計画 {#campaign-planning} CRMチームは、近い将来に立ち上げるメッセージングのユースケースを計画します。これには以下が含まれます。 * [チャネル](https://www.braze.com/docs/ja/ja/user_guide/channels)(例:プッシュ通知やアプリ内メッセージ) * [配信方法](https://www.braze.com/docs/ja/ja/user_guide/messaging/campaigns/schedule_your_campaign)(例:スケジュール配信やアクションベースの配信) * [ターゲットオーディエンス](https://www.braze.com/docs/ja/ja/user_guide/audience/segments) * [成功指標](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/conversion_events) 例えば、新規顧客向けキャンペーンは、昨日最初のセッションを記録した顧客のセグメントに毎日午前10時にメールを送信するものです。コンバージョンイベント(成功指標)はセッションの記録です。
**Important:** キャンペーン計画のステップが完了するまで、統合を開始することはできません。このステップでは、統合フェーズで構成する必要があるBrazeの構成要素を決定します。 ### データ要件の作成 {#creating-data-requirements} 次に、CRMチームは計画したキャンペーンを実施するために必要なデータを定義し、データ要件を作成します。 名前、メール、生年月日、国など、多くの一般的なユーザー属性は、Braze SDKが統合された後に自動的に追跡されます。その他のタイプのデータはカスタムデータとして定義する必要があります。 開発者として、チームと協力して追跡する価値のある追加のカスタムデータを定義します。カスタムデータは、ユーザー群がどのように分類され、セグメント化されるかに影響します。成長スタック全体でイベント分類法を設定し、データがBrazeに出入りする際にシステムとの互換性を確保するよう構造化します。 **Tip:** ツール間でデータの命名法を統一してください。例えば、データウェアハウスは「期間限定オファーの購入」を特定の方法で記録する場合があります。このフォーマットに合わせてBrazeのカスタムイベントが必要かどうかを決める必要があります。 [自動収集されたデータとカスタムデータ](https://www.braze.com/docs/ja/ja/developer_guide/analytics)の詳細を参照してください。 ### カスタマイズの計画 {#customizations-planning} マーケティング担当者に、希望するカスタマイズについて相談してください。例えば、デフォルトのBraze Content Cardsを実装しますか?ブランドガイドラインに合うようにルック&フィールを少し調整しますか?コンポーネントのためにまったく新しいUIを開発し、Brazeにその分析を追跡させますか?カスタマイズのレベルが異なれば、必要なスコープのレベルも異なります。 ### ダッシュボードへのアクセス {#getting-dashboard-access} BrazeダッシュボードはウェブUIインターフェイスです。マーケティング担当者はダッシュボードを使って仕事をし、コンテンツを作成します。開発者はダッシュボードを使い、APIキーやプッシュ通知の認証情報など、アプリを統合するための設定を管理します。 チーム管理者は、ダッシュボードであなた(およびBrazeへのアクセスが必要な他のチームメンバー全員)をユーザーとして追加する必要があります。 ### ワークスペースとAPIキー {#workspaces-and-api-keys} チーム管理者はまた、さまざまな[ワークスペース](https://www.braze.com/docs/ja/ja/user_guide/administer/global/create_and_manage_workspaces)を作成します。ワークスペースは、ユーザー、セグメント、APIキーなどのデータを1つの場所にグループ化します。ベストプラクティスとして、同じアプリやよく似たアプリの異なるバージョンのみを1つのワークスペースにまとめることをお勧めします。 重要なのは、ワークスペースが複数のプラットフォーム(iOSやAndroidなど)用のAPIキーを提供することです。SDKデータを特定のワークスペースに関連付けるには、対応するAPIキーを使用します。ワークスペースに移動して、各アプリのAPIキーにアクセスしてください。各APIキーがスコープした作業を実行するための正しい権限を持っていることを確認してください。詳細は[APIプロビジョニングの記事](https://www.braze.com/docs/ja/ja/api/basics#rest-api-key)を参照してください。 **Important:** 開発用と本番用で異なる環境を設定することが重要です。テスト環境を設定することで、オンボーディングやQAで実際にお金を使うことを防ぐことができます。テスト環境を作成するには、テスト用ワークスペースをセットアップし、本番用ワークスペースにテストデータを入力しないように、必ずそのAPIキーを使用してください。 ## 統合 {#integration} ![データソースからユーザーデバイスへの情報の流れを表す抽象的なピラミッド図形。](https://www.braze.com/docs/ja/ja/assets/img/getting-started/data-graphic.png?de1762afab01f3ce2b61da8f5c8d8f3a){: style="max-width:45%;float:right;margin-left:15px;"} BrazeはiOSアプリ、Androidアプリ、ウェブアプリなどをサポートしています。また、React NativeやUnityのようなクロスプラットフォームのラッパーSDKを使うこともできます。通常、顧客は1〜6週間で統合を完了します。多くの顧客は、技術スキルと帯域幅の広さにもよりますが、たった1人のエンジニアでBrazeを統合しています。これは具体的な統合の範囲と、チームがBrazeプロジェクトに費やす時間に完全に依存します。 以下に精通した開発者が必要です。 * アプリやサイトのネイティブレイヤーでの作業 * REST APIにアクセスするプロセスの作成 * 統合テスト * JSONウェブトークン認証 * 一般的なデータ管理スキル * DNSレコードの設定 ### CDP統合パートナー {#cdp-integration-partners} 多くの顧客は、Brazeのオンボーディングを、統合パートナーとして顧客データプラットフォーム(CDP)とも統合する機会として利用しています。Brazeはデータの追跡と分析を提供し、CDPは追加のデータルーティングとオーケストレーションを提供できます。Brazeは、[mParticle](https://www.braze.com/docs/ja/ja/partners/data_and_analytics/customer_data_platform/mparticle/mparticle)や[セグメント](https://www.braze.com/docs/ja/ja/partners/data_and_analytics/customer_data_platform/segment/segment)など多くのCDPとシームレスに統合できます。 CDPとサイドバイサイドの統合を行う場合は、CDPのSDKからの呼び出しをBraze SDKにマッピングします。基本的に、以下を実行します。 * 識別呼び出しを`changeUser`([Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/change-user.html)、[iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/changeuser(userid:sdkauthsignature:fileid:line:)/)、[web](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#changeuser))にマッピングし、属性を設定します。 * データフラッシュ呼び出しを`requestImmediateDataFlush`([Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/request-immediate-data-flush.html?query=abstract%20fun%20requestImmediateDataFlush())、[iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/requestimmediatedataflush())、[web](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#requestimmediatedataflush))にマッピングします。 * カスタムイベントや購入を記録します。 選択したプラットフォームによっては、Braze SDKと選択したCDP間の統合例を利用できる場合があります。詳細は[CDPテクノロジーパートナーのリスト](https://www.braze.com/docs/ja/ja/partners/data_and_analytics)を参照してください。 ### Braze SDKの統合 {#braze-sdk-integration} Braze SDKは2つの重要な機能を提供します。ユーザーデータを収集し統合されたユーザープロファイルに同期することと、プッシュ通知、アプリ内メッセージ、Content Cardsなどのメッセージングチャネルを強化することです。 **Tip:** Braze SDKはアプリやサイトと完全に統合されると、完全に実現されたレベルの高度なマーケティングを提供します。Braze SDKの統合を延期すると、ドキュメントに記載されている機能の一部が利用できなくなります。 **Note:** セキュリティを強化するため、[SDK認証](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/authentication)を有効にして不正なSDKリクエストを防ぐことができます。この機能は、Web、iOS、Android、React Native、Flutter、Unity、Cordova、.NET MAUI(Xamarin)、Expoを含むすべての主要プラットフォームで利用できます。 SDKの実装では、以下を行います。 * サポートしたいプラットフォームごとにSDK統合コードを記述します。 * 各プラットフォームのメッセージングチャネルを有効にし、Braze SDKがメール、SMS、プッシュ通知、その他のチャネルにわたる顧客とのインタラクションのデータを追跡するようにします。 * 予定されているUIコンポーネントのカスタマイズ(例:カスタムContent Cards)を作成します。完全にカスタム化されたコンテンツの場合、SDKの自動データ収集では新しいコンポーネントを認識できないため、分析のログを取る必要があります。この実装はデフォルトのコンポーネントをパターンとして利用できます。 ### Braze APIの使用 {#using-the-braze-api} Brazeを使用している間、さまざまな場面でさまざまなタスクにREST APIを使用します。Braze APIは次のような用途に役立ちます。 1. 過去のデータをインポートする。 2. Brazeではトリガーされない継続的な更新。例えば、アプリにログインせずにユーザープロファイルがVIPにアップグレードされる場合、APIはこの情報をBrazeに伝える必要があります。 [Braze API](https://www.braze.com/docs/ja/ja/api/basics)を使い始めましょう。 **Important:** APIを使用する際は、リクエストをバッチ処理し、デルタ値のみを送信するようにしてください。Brazeは送信されたすべての属性を書き直します。カスタム属性の値が変更されていない場合は更新しないでください。 ### 製品分析の設定 {#setting-up-product-analytics} Brazeはデータがすべてです。Brazeのデータはユーザープロファイルに保存されます。 データポイントとは、マーケティング担当者にとって適切なデータを確実に取得するための仕組みであり、単に「どんな」データでも集めればいいというものではありません。[データポイント](https://www.braze.com/docs/ja/ja/user_guide/data/infrastructure/data_points)について理解を深めてください。 ### レガシーユーザーデータの移行 {#migrating-legacy-user-data} Brazeの[`/users/track`エンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)を使用して、Brazeの外部で記録された履歴データを移行できます。よくインポートされるデータの例としては、プッシュトークンや過去の購入履歴などがあります。このエンドポイントは、単発のインポートや定期的なバッチ更新に使用できます。 また、ダッシュボードに一度だけ[CSVをアップロード](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/user_data_collection/user_import#importing-a-csv)することで、ユーザーをインポートし、顧客の属性値を更新することもできます。CSVのアップロードはマーケティング担当者にとって便利ですが、REST APIを使えばより柔軟に対応できます。 ### セッショントラッキングの設定 {#setting-up-session-tracking} Braze SDKは「セッション開始」と「セッション終了」のデータポイントを生成します。また、Braze SDKは定期的にデータをフラッシュします。セッショントラッキングのデフォルト値(いずれもカスタマイズ可能)については、以下のリンクを参照してください([Android](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions?tab=android)、[iOS](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions?tab=swift)、[web](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions?tab=web))。 ### カスタムイベント、属性、購入イベントの追跡 {#tracking-custom-events-attributes-and-purchase-events} カスタムイベント、ユーザー属性、購入イベントなど、計画したデータスキーマを設定するためにチームと調整してください。[カスタムデータスキーム](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/custom_events)はダッシュボードを使用して入力され、SDK統合中に実装したものと完全に一致しなければなりません。 **Tip:** ユーザーID(Brazeでは`external_id`と呼ばれます)は、既知のすべてのユーザーに対して設定する必要があります。これらは不変であるべきで、ユーザーがアプリを開いたときにアクセスできるようにし、デバイスやプラットフォームを超えてユーザーを追跡できるようにします。ベストプラクティスについては、[ユーザーライフサイクル](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/user_profile_lifecycle)の記事を参照してください。 ### その他のツール {#other-tools} ユースケースによっては、他にも設定が必要なツールがある場合があります。例えば、ユーザーストーリーを実現するために[ジオフェンス](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/locations_and_geofences#about-locations-and-geofences)のようなツールを設定する必要がある場合があります。重要な統合ステップを完了した後にこれらの追加ツールをセットアップできる顧客が最も成功していることが明らかになっています。 ## 品質保証 {#qa} 統合を実行する際には、設定したすべてが期待通りに機能していることを確認するため、品質保証を行います。このQAは、データインジェストとメッセージチャネルの2つに大別されます。 **Important:** QAを始める前に、本番環境とテスト環境がセットアップされていることを確認してください。 | **QAデータインジェスト** | **QAメッセージング** | |---------------------------|---------------------------------------------------------------| | データのインジェスト、保存、エクスポートの方法について品質保証を行います。 | メッセージがユーザーに正しく送信され、すべてが適切に表示されることを確認します。 | | データが正しく保存されていることを確認するためにテストを実行します。 | ユーザーのセグメントを作成します。 | | セッションデータがBraze内の意図したワークスペースに正しく帰属していることを確認します。 | キャンペーンとキャンバスを正常に起動します。 | | セッションの開始と終了が記録されていることを確認します。 | 正しいキャンペーンが正しいユーザーセグメントに表示されていることを確認します。 | | ユーザー属性情報がユーザープロファイルに対して正しく記録されていることを確認します。 | プッシュトークンが正しく登録されていることを確認します。 | | ユーザープロファイルに対してカスタムデータが正しく記録されていることをテストします。 | プッシュトークンが正しく削除されていることを確認します。 | | 匿名ユーザープロファイルを作成します。 | プッシュキャンペーンがデバイスに正しく送信され、エンゲージメントが記録されているかテストします。 | | `changeUser()`メソッドが呼び出されたときに、匿名ユーザープロファイルが既知のユーザープロファイルになることを確認します。 | アプリ内メッセージが配信され、指標が記録されることをテストします。 | | | Content Cardsが配信され、指標が記録されていることをテストします。 | | | コネクテッドコンテンツを促進します(例:AccuWeather)。 | | | すべてのメッセージチャネルの統合が正しく連携していることを確認します。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="品質保証" } **Note:** SDK統合のQAを行う際、[SDKデバッガー](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/debugging)を使用すれば、アプリの冗長ロギングをオンにすることなく問題のトラブルシューティングを行うことができます。 ### Brazeをマーケターに引き継ぐ {#passing-braze-off-to-marketers} プラットフォームやサイトを統合したら、マーケティングチームを関与させてプラットフォームの所有権を引き渡しましょう。このプロセスは企業によって異なりますが、以下のようなものが含まれる場合があります。 * 複雑な[Liquidロジック](https://www.braze.com/docs/ja/ja/user_guide/personalization_and_dynamic_content/liquid#about-liquid)を構成する * [メールのIPウォームアップ](https://www.braze.com/docs/ja/ja/user_guide/channels/email/email_setup/ip_warming)を支援する * 他の利害関係者に追跡されるデータの種類を理解させる ### 未来のために開発する {#develop-for-the-future} コードベースを受け継いだが、最初の開発者が何を考えていたのかまったく分からなかったことはありませんか?さらに悪いことに、コードを書いて完全に理解したのに、1年後にそのコードに戻ってきたときにまったく不可解に感じたことはありませんか? Brazeのオンボーディング時には、データ、ユーザープロファイル、対象となる統合と対象外の統合、カスタマイズの動作方法などに関して下した決断の積み重ねが新鮮に感じられ、それゆえに明白なものとなります。チームがBrazeを拡張したいとき、または他の技術リソースがBrazeプロジェクトに割り当てられたとき、この情報は不明瞭になります。 技術概要セッションで学んだ情報を定着させるためのリソースを作成してください。このリソースは、チームに加わる新しい開発者をオンボードする時間を短縮するのに役立ちます(あるいは、現在のBraze実装を拡張する必要があるときに自分自身へのリマインダーとして役立ちます)。 ## メンテナンス {#maintenance} マーケターに引き継がれた後も、メンテナンスのためのリソースとしての役割を果たし続けます。Braze SDKに影響を与える可能性のあるiOSとAndroidのアップデートに注意を払い、サードパーティベンダーが最新であることを確認してください。 Brazeの[GitHub](https://github.com/braze-inc/)を通じて、Brazeプラットフォームへの更新を追跡します。時折、緊急アップデートやバグフィックスに関するメールがBrazeから管理者に直接届くこともあります。 ## SDKレート制限 {#sdk-rate-limits} ### 月間アクティブユーザー数(CY 24-25)、ユニバーサルMAU、Web MAU、モバイルMAU {#monthly-active-users-cy-24-25-universal-mau-web-mau-and-mobile-mau} 月間アクティブユーザー数(CY 24-25)、ユニバーサルMAU、Web MAU、モバイルMAUを購入した顧客に対して、Brazeはセッション、ユーザー属性、イベント、その他のユーザープロファイルデータを更新するためにSDKが使用するAPIリクエストに対し、サーバーサイドのレート制限を適用します。これはプラットフォームの安定性を確保し、高速で信頼性の高いサービスを維持するためです。 * 時間単位のレート制限は、購入した月間アクティブユーザー数(MAU)、業界、季節性、またはその他の要因に対応する、アカウントで予想されるSDKトラフィックに応じて設定されます。時間あたりのレート制限に達すると、Brazeは次の時間までリクエストをスロットルします。 * すべてのレート制限されたリクエストはSDKによって自動的に再試行されます。 * SDKリクエストは、実装で収集されるカスタムデータの量と相関します。常に時間あたりのレート制限に近いか、制限に達している場合は、以下を検討してください。 * SDKの統合を見直し、過剰なデータ収集を減らす。 * マーケティングのユースケースに不可欠でないカスタムデータをブロックリスト化する。 * バーストレート制限とは、非常に短時間(つまり数秒以内)に大量のリクエストが到着した場合に適用される、短時間のレート制限です。バースト制限が発生してもアクションを起こす必要はなく、SDKは直後に再試行します。 * 定常レート制限は、バーストウィンドウよりも長いローリングウィンドウ(例えば数分間)における持続的なリクエスト量をコントロールし、バースト制限と時間単位のレート制限の間で継続的なトラフィックを平滑化するのに役立ちます。 ### レート制限の確認 {#finding-your-rate-limits} 予想されるSDKスループットに基づく現在の制限を確認するには、**設定** > **APIキー** > **APIとSDKの制限**に進みます。 過去の使用状況については、**設定** > **APIキー** > **APIとSDKのダッシュボード**を参照してください。 ### より高いレート制限のリクエスト {#requesting-higher-rate-limits} より高いBrazeレート制限が必要な場合は、Brazeサポートまたはカスタマーサクセスマネージャーに連絡し、以下の詳細を記載してください。 * 一時的な増加か恒久的な増加か。 * 増加が必要な理由。 * 影響を受けるエンドポイントと環境。 * おおよそのトラフィック量とスケジュール(開始日、期間、ピーク時間帯を含む)。 * 呼び出しをバッチ処理できるか、またはトラフィックを時間をかけて分散できるか。 リクエストを送信した後、Brazeが確認し、結果をお知らせします。 ### 変更とサポート {#changes-and-support} Brazeは、システムの安定性を保護するため、またはアカウントのデータスループットを向上させるために、レート制限を変更することがあります。レート制限に関するご質問やご不明な点、レート制限がビジネスに与える影響については、Brazeサポートまたはカスタマーサクセスマネージャーまでお問い合わせください。 # アーキテクチャの概要 Source: /docs/ja/developer_guide/getting_started/architecture_overview/index.md # 入門:アーキテクチャの概要 {#getting-started-architectural-overview} > この記事では、Brazeテクノロジースタックのさまざまな部分と構成要素について説明し、関連する記事へのリンクを提供します。 大まかに言えば、Brazeはデータに関するものです。BrazeプラットフォームにはSDK、REST API、パートナー連携が備わっており、データを集計したり、データに基づいて処理を行ったりできます。 ![Brazeにはさまざまなレイヤーがあります。全体として、SDK、API、ダッシュボード、およびパートナー連携から構成されています。これらはそれぞれ、データ取り込みレイヤー、分類レイヤー、オーケストレーションレイヤー、パーソナライゼーションレイヤー、およびアクションレイヤーの一部を構成します。アクションレイヤーには、プッシュ、アプリ内メッセージ、コネクテッドカタログ、Webhook、SMS、メールなど、さまざまなチャネルがあります。](https://www.braze.com/docs/ja/ja/assets/img/getting-started/braze_listen_understand_act.png?e78b24fbe4134b6d2666eddda17e18dc){: style="display:block;margin:auto;" } * [データ取り込み](#ingestion):Brazeはさまざまなソースからデータを取り込みます。 * [分類](#classification):マーケティングチームは、これらの指標を使用してユーザー群を動的にセグメント化します。 * [オーケストレーション](#orchestration):Brazeは、異なるオーディエンスセグメントへのメッセージを最適なタイミングでインテリジェントに調整します。 * [アクション](#action):マーケティングチームはデータに基づいて行動し、SMSやメールなどのさまざまなメッセージングチャネルを通じてコンテンツを作成します。 * [パーソナライゼーション](#personalization):データは、オーディエンスに関するパーソナライズされた情報でリアルタイムに変換されます。 * [エクスポート](#exporting-data):次に、Brazeはこのメッセージングに対するユーザーのエンゲージメントを追跡し、それをプラットフォームにフィードバックしてループを作成します。リアルタイムレポートと分析を通じて、このデータに関するインサイトを得ることができます。 これらすべてが連携して、ユーザー群とブランドの間で成功したやり取りを生み出し、目標を達成できるようにします。Brazeは、私たちが垂直統合スタックと呼ぶものの中でこれをすべて行います。各レイヤーを1つずつ掘り下げていきましょう。 ## データの取り込み {#ingestion} Brazeは、Snowflake、Kafka、MongoDB、およびRedisを活用したストリーミングデータアーキテクチャ上に構築されています。多くのデータソースからのデータは、SDKやAPIを通じてBrazeに読み込むことができます。プラットフォームは、データがどのようにネストまたは構造化されているかに関係なく、あらゆるデータをリアルタイムで処理できます。Brazeのデータはユーザープロファイルに保存されます。 **Tip:** Brazeは、ユーザーが匿名である時点から、アプリにログインして既知の状態になるまで、ユーザーのデータを追跡できます。ユーザーIDは、Brazeでは`external_id`と呼ばれ、各ユーザーに設定する必要があります。これらは変更されず、ユーザーがアプリを開いたときにアクセスできるようにする必要があり、デバイスやプラットフォームを超えてユーザーを追跡できるようにします。ベストプラクティスについては、[ユーザーライフサイクルに関する記事](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/user_profile_lifecycle)を参照してください。 ![BrazeはAPIからバックエンドデータソースを、SDKからフロントエンドデータソースを、Brazeクラウドデータ取り込みからデータウェアハウスのデータを、そしてパートナー連携からデータをインポートします。このデータはBraze APIを通じてエクスポートされます。](https://www.braze.com/docs/ja/ja/assets/img/getting-started/import-export.png?781820845d13ad1965129e15392f0605){: style="display:block;margin:auto;" } **Note:** このユーザー中心のユーザープロファイルデータベースにより、リアルタイムでインタラクティブなスピードが実現します。Brazeはデータが到着したときに値を事前に計算し、結果を高速に取得するために軽量なドキュメント形式で保存します。そして、プラットフォームは最初からこのように設計されているため、ほとんどのメッセージングのユースケースに理想的です。特に、コネクテッドコンテンツ、製品カタログ、ネストされた属性などの他のデータ概念と組み合わせると効果的です。 ### データソースの内訳 {#data-source-breakdown} Brazeはさまざまな機能に対して異なるデータストレージシステムを使用しています。どの機能がどのデータソースを使用しているかを理解することは、データ管理とトラブルシューティングにおいて重要です。 #### MongoDBを活用した機能 {#mongodb-powered-features} - カスタムイベント(SDKとAPIによってトラッキングされる) - カスタム属性 - ユーザープロファイル - 購入イベント - ほとんどのセグメンテーションとターゲティング機能 #### Snowflakeを活用した機能 {#snowflake-powered-features} - [SQLセグメントエクステンション](https://www.braze.com/docs/ja/ja/user_guide/audience/segments/segment_extension/sql_segments) - [予測スイート](https://www.braze.com/docs/ja/ja/user_guide/brazeai) - [パーソナライズされたパス](https://www.braze.com/docs/ja/ja/user_guide/messaging/canvas/canvas_components/experiment_step/personalized_paths)と[パーソナライズされたバリアント](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/testing/multivariant_testing/optimizations#personalized-variant) - [AIによるパーソナライズされた商品レコメンデーション](https://www.braze.com/docs/ja/ja/user_guide/brazeai/item_recommendations/creating_recommendations/ai) - [推定実開封率](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/reporting_and_analytics/email_reporting#estimated-real-open-rate)(カスタムイベントを使用しません) **Important:** **データ削除に関する考慮事項:** カスタムイベントはMongoDBに保存され、Snowflakeのデータとは別物です。誤ったカスタムイベントデータを削除する必要がある場合、MongoDBで対処しなければなりません。Snowflakeを活用した機能(SQLセグメントエクステンションやその他のSnowflakeを活用した機能など)は、Snowflakeのデータを使用しており、別途扱われます。一方のシステムからデータを削除しても、もう一方のシステムから自動的に削除されるわけではありません。 ### Braze APIを介したバックエンドデータソース {#backend-data-sources-through-the-braze-api} Brazeは、[REST API](https://www.braze.com/docs/ja/ja/api/endpoints/user_data)を使用して、ユーザーデータベース、オフライントランザクション、およびデータウェアハウスからデータを取得できます。 ### Braze SDKを介したフロントエンドデータソース {#frontend-data-sources-through-braze-sdk} Brazeは、[Braze SDK](https://www.braze.com/docs/ja/ja/user_guide/get_started/sdk_overview)を使用して、ユーザーのデバイスなどのフロントエンドデータソースからファーストパーティデータを自動的にキャプチャします。SDKは新しい(匿名の)ユーザーを処理し、ライフサイクル全体にわたってユーザープロファイルのデータを管理します。 ### パートナー連携 {#partner-integrations} Brazeには150を超えるテクノロジーパートナーがあり、私たちはそれを「Alloys」と呼んでいます。[相互運用可能な技術とデータAPI](https://www.braze.com/docs/ja/ja/partners/home)の堅牢なネットワークを通じて、データフィードを補完できます。 ### Brazeクラウドデータ取り込みを介したデータウェアハウスとの直接接続 {#direct-warehouse-connection-through-braze-cloud-data-ingestion} [Brazeクラウドデータ取り込み](https://www.braze.com/docs/ja/ja/user_guide/data/unification/cloud_ingestion)を使用すると、データウェアハウスからプラットフォームに顧客データをわずか数分でストリームでき、関連するユーザー属性、イベント、購入を同期できます。クラウドデータ取り込みの統合は、ネストされたJSONやオブジェクトの配列を含む複雑なデータ構造をサポートしています。 クラウドデータ取り込みは、Snowflake、Amazon Redshift、Databricks、およびGoogle BigQueryからデータを同期できます。 ## 分類 {#classification} 分類レイヤーにより、チームはBrazeを通過するデータに基づいて[セグメント](https://www.braze.com/docs/ja/ja/user_guide/audience/segments)と呼ばれるオーディエンスを動的に分類および構築できます。 **Note:** 分類、オーケストレーション、パーソナライゼーションのレイヤーは、マーケティングチームが多くの作業を行う場所です。これらのレイヤーとのやり取りは、BrazeダッシュボードというWebインターフェイスを通じて最も頻繁に行われます。開発者はこれらのレイヤーの設定とカスタマイズに役割を果たします。 名前、メール、生年月日、国名など、多くの一般的な種類のユーザー属性は、デフォルトでSDKによって自動的に追跡されます。開発者は、チームと協力して、ユースケースで追跡する価値のある追加のカスタムデータを定義します。カスタムデータは、ユーザー群の分類とセグメント化に影響を与えます。実装プロセス中にこのデータモデルを設定します。 [自動収集されたデータとカスタムデータ](https://www.braze.com/docs/ja/ja/developer_guide/analytics)の詳細を参照してください。 ## オーケストレーション {#orchestration} オーケストレーションレイヤーにより、マーケティングチームはユーザーデータと以前のエンゲージメントに基づいてユーザージャーニーを設計できます。この作業は、ほとんどの場合ダッシュボードインターフェイスを使用して行われますが、[APIを使用してキャンペーンを起動する](https://www.braze.com/docs/ja/ja/api/api_campaigns#api-campaigns)オプションもあります。例えば、バックエンドがBrazeに対して、マーケターがダッシュボードで設計したメッセージやキャンペーンをいつ送信するかを指示し、バックエンドのロジックに従ってトリガーすることができます。APIトリガーメッセージの例としては、パスワードリセットや配送確認があります。 **Note:** APIトリガーキャンペーンは、より高度なトランザクションユースケースに最適です。これを使用すると、マーケターはキャンペーンのコピー、多変量テスト、再適格性ルールをBrazeダッシュボード内で管理しながら、サーバーやシステムからそのコンテンツの配信をトリガーできます。メッセージをトリガーするAPIリクエストには、メッセージにリアルタイムでテンプレート化する追加データを含めることもできます。 ### フィーチャーフラグ {#feature-flags} Brazeでは、[フィーチャーフラグ](https://www.braze.com/docs/ja/ja/developer_guide/feature_flags)を使用して、選択したユーザーに対して機能をリモートで有効または無効にすることができます。これにより、マーケターは、まだ全オーディエンスに展開していない機能のメッセージングを使用して、ユーザー群の正しいセグメントをターゲットにすることができます。さらに、フィーチャーフラグは追加のコードデプロイやアプリストアの更新なしに、本番環境で機能をオンおよびオフにするために使用できます。これにより、新しい機能を安全かつ確信を持ってロールアウトできます。 ## パーソナライゼーション {#personalization} パーソナライゼーションレイヤーは、メッセージ内でダイナミックなコンテンツを提供する機能を表します。広く使用されているパーソナライゼーション言語であるLiquidを使用すると、チームは既存のデータを動的に取得して、各受信者に合わせたメッセージを表示できます。さらに、[コネクテッドコンテンツ](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize/connected_content)を使用すれば、ウェブサーバー上でアクセス可能な情報やAPI経由で取得した情報を、プッシュ通知やメールなどの送信メッセージに直接挿入できます。コネクテッドコンテンツはLiquidの上に構築され、おなじみの構文を使用します。 そして、このダイナミックなコンテンツはプログラム可能であるため、マーケターは計算された値、他の呼び出しからの応答、または製品カタログアイテムを含めることができます。これらのシステムを実装中に設定した後、マーケティングチームは技術チームからのサポートがほとんどなくてもこれを行うことができます。 ## アクション {#action} アクションレイヤーは、ユーザーへの実際のメッセージングを可能にします。アクションレイヤーの目的は、前述のすべてのレイヤーを通じて利用可能なデータに基づいて、適切なタイミングで適切なメッセージを適切なユーザーに送信することです。メッセージングは、アプリやサイト内(アプリ内メッセージの送信やContent Cardsのカルーセルやバナーなどのグラフィック要素を通じて)、またはアプリ外の体験(プッシュ通知やメールの送信など)を通じて行われます。 ### メッセージングチャネル {#messaging-channels} Brazeは、チャネルに依存しないユーザー中心のデータモデルによって、進化する技術的状況に対応するように設計されています。ダッシュボードはメッセージ配信とトランザクショントリガーを管理します。例えば、マーケターは、ユーザーがこの場所の近くに設定されたジオフェンスに入ると、新しくオープンした店舗のクーポンを提供するSMSメッセージをトリガーしたり、ユーザーにメールを送信してお気に入りの番組の新シーズンが始まったことを知らせたりすることができます。 [Braze SDK](https://www.braze.com/docs/ja/ja/user_guide/get_started/sdk_overview)は、プッシュ、In-App Messages、Content Cardsなど、追加のメッセージングチャネルを提供します。SDKをアプリまたはサイトと統合すると、マーケティングチームはBrazeダッシュボードを使用して、サポートされているすべてのメッセージングチャネルでキャンペーンを調整できます。 ![SDKを通じて利用可能なBrazeメッセージングチャネルの図](https://www.braze.com/docs/ja/ja/assets/img/getting_started/channels.png?eb6bc0b731b35124297603041fba54ed) ## データのエクスポート {#exporting-data} 重要なことに、すべてのエンドユーザーのBrazeとのやり取りが追跡されるため、エンゲージメントとアウトリーチを測定できます。そして、Brazeがこれらすべてのソースからデータを集約した後、さまざまなツールを使用してテックスタックにデータをエクスポートし、ループを閉じることができます。 ### Currents [Currents](https://www.braze.com/docs/ja/ja/user_guide/data/distribution/braze_currents)は、スタックの他の送信先に継続的にフィードするきめ細かいストリーミングエクスポートを提供するオプションのBrazeアドオンです。Currentsは、ユーザーごとのイベントごとの生データフィードで、5分ごと、または15,000イベントごとにデータをエクスポートします(どちらか早い方)。Currentsの下流の送信先の例としては、セグメント、S3、Redshift、Mixpanelなどがあります。 ### Snowflakeデータ共有 {#snowflake-data-sharing} Snowflakeの[Secure Data Sharing](https://www.braze.com/docs/ja/ja/partners/data_and_analytics/data_warehouses/snowflake)機能により、Brazeは、ワークフローの摩擦、障害ポイント、一般的なデータプロバイダー関係に伴う不要なコストを気にせずに、Snowflakeポータルのデータに安全にアクセスできるようになります。共有はすべてSnowflakeのユニークなサービスレイヤーとメタデータストアを通じて行われます。データは実際にはアカウント間でコピーまたは転送されません。共有データは消費者アカウントのストレージを一切使用しないため、これは重要な概念です。したがって、毎月のデータストレージ料金には影響しません。消費者に請求されるのは、共有データをクエリするために使用されるコンピューティングリソース(つまり、仮想ウェアハウス)のみです。 ### BrazeエクスポートAPI {#braze-export-apis} Braze APIには、プログラムで集約分析をエクスポートしたり、個々のユーザーデータをエクスポートしたりできる[エンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/export)が用意されています。このデータは、あらゆるサイズのオーディエンスおよびセグメントに対してエクスポートできます。 ### CSV {#csvs} 最後に、ダッシュボードから直接[CSV](https://www.braze.com/docs/ja/ja/user_guide/data/distribution/export_braze_data)として集約レベルのデータをダウンロードするオプションがあります。CSVオプションを使用すると、チームメンバーはBrazeからデータを簡単にエクスポートできます。 **Tip:** CSVエクスポートには500,000行の基本制限がありますが、APIにはこの点に関して制限がありません。 ## すべてをまとめる {#putting-it-all-together} あなたのユーザーの一人(メルと呼びましょう)がちょうどあなたの製品に関する通知を受け取ったところです。舞台裏では、Brazeプラットフォームのすべてのレイヤーが連携して、このプロセスがスムーズに進むようにしました。 メルの情報はCSVインポートを通じて、従来のカスタマーエンゲージメントプラットフォームからBrazeに取り込まれました。統合後、メルがアプリを操作するたびに、彼女の顧客プロファイルにより多くのデータが追加されました。 あなたの製品に関する通知は、アプリで類似のアイテムに「いいね」を付けたすべての顧客に送信されました。このデータをカスタムイベントとして定義しました。SDKはこのイベントを追跡し、ユーザー群をそれに応じてセグメント化しました。Brazeはこの通知を送信する最適な時間帯を調整し、メルを彼女の好みの名前で呼ぶことで通知をパーソナライズしました。 メルが通知を開くと、彼女はあなたの新しい製品をウィッシュリストに追加します。Brazeは彼女がメールをクリックしたことを自動的に追跡します。SDKは、彼女があなたの新製品をウィッシュリストに追加したことを追跡します。ブランドと関わりを持つたびに、あなたとあなたのユーザーはお互いについてより多くのことを学んでいます。 ![メッセージングチャネル全体でユーザーアクションをBrazeがどのように追跡するかを示す図](https://www.braze.com/docs/ja/ja/assets/img/getting-started/putting-it-all-together.png?2de8ff7b0d97c99fb7f38a3bc32c7e0b) # LLMを用いた構築 Source: /docs/ja/developer_guide/getting_started/build_with_llm/index.md # LLMを用いた構築 {#building-with-an-llm} > AIコーディングアシスタントを使って、Brazeの統合ワークフローを加速させましょう。Context7を介してIDEをBraze Docs MCPサーバーに接続し、開発環境内で正確かつ最新のSDKガイダンスを直接入手できます。 AIコーディングアシスタントは、統合コードの記述や問題のトラブルシューティング、Braze SDKの機能探索を支援できます。ただし、適切なコンテキストが与えられている場合に限ります。Braze Docs MCPサーバーは、AIアシスタントにBrazeドキュメントへの直接アクセスを提供するため、最新のSDKリファレンスに基づいて正確なコードスニペットを生成し、技術的な質問に回答できます。 ## Braze Docs MCPへの接続 {#connecting-to-the-braze-docs-mcp} [Context7](https://context7.com/braze-inc/braze-docs)は、AIアシスタントとBrazeドキュメントライブラリーをつなぐ橋渡し役です。IDEのMCP設定にContext7を追加すると、AIアシスタントがBrazeの全ドキュメントセットにクエリを実行し、関連するSDKリファレンス、コード例、統合ガイドをオンデマンドで取得できるようになります。 ### Context7の設定 {#setting-up-context7} Context7を通じてAIアシスタントをBraze Docs MCPに接続するには、IDEの`mcp.json`ファイルに以下の設定を追加します。 [Cursor](https://cursor.com/)で、**Settings** > **Tools and Integrations** > **MCP Tools** > **Add Custom MCP**へ移動し、以下のスニペットを追加します。 ```json { "mcpServers": { "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp@latest"] } } } ``` 設定を保存し、Cursorを再起動します。プロンプトに`use context7`を含めることで、AIアシスタントがContext7経由でBrazeドキュメントにアクセスできるようになります。 Claude Desktopで、**Settings** > **Developer** > **Edit Config**へ移動し、`claude_desktop_config.json`ファイルに以下を追加します。 ```json { "mcpServers": { "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp@latest"] } } } ``` 設定を保存し、Claude Desktopを再起動します。 VS Codeの`settings.json`または`.vscode/mcp.json`ファイルに以下を追加します。 ```json { "mcpServers": { "context7": { "command": "npx", "args": ["-y", "@upstash/context7-mcp@latest"] } } } ``` 設定を保存し、VS Codeを再起動します。 **Note:** Context7は[Braze MCPサーバー](https://www.braze.com/docs/ja/ja/developer_guide/mcp_server)とは異なります。Context7はAIアシスタントに**Brazeドキュメント**へのアクセスを提供し、Braze MCPサーバーは**Brazeワークスペースデータ**(キャンペーン、セグメント、分析など)への読み取り専用アクセスを提供します。両方を併用することで、より充実したAI支援開発体験を得られます。 ## Braze SDK開発向けのプロンプト作成 {#writing-prompts-for-braze-sdk-development} Context7を設定した後、プロンプトに`use context7`を含めることで、AIアシスタントにBrazeドキュメントをコンテキストとして取り込むよう指示します。以下の例は、一般的なSDKタスクに対して効果的なプロンプトを作成する方法を示しています。 ### React Native SDK {#react-native-sdk} これらのプロンプトは、[Braze React Native SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=react%20native)の一般的な統合タスクを示しています。 #### SDKの初期化 {#initializing-the-sdk} ```text Using the Braze React Native SDK, show me how to initialize the SDK in my App.tsx with an API key and custom endpoint. Include the configuration for automatic session tracking. Use context7. ``` #### プロパティ付きカスタムイベントの記録 {#logging-custom-events-with-properties} ```text I need to track user activity in my React Native app using the Braze React Native SDK. Show me how to log a custom event called "ProductViewed" with properties for product_id, category, and price. Use context7. ``` #### プッシュ通知の設定 {#setting-up-push-notifications} ```text Using the Braze React Native SDK, walk me through requesting push notification permissions on both iOS and Android 13+. Include the code for registering the push token with Braze. Use context7. ``` #### アプリ内メッセージの処理 {#handling-in-app-messages} ```text Show me how to subscribe to in-app messages using the Braze React Native SDK, including how to log impressions and button clicks programmatically. Use context7. ``` ### Web SDK {#web-sdk} これらのプロンプトは、[Braze Web SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=web)の一般的な統合タスクを示しています。 #### SDKの初期化 ```text Using the Braze Web SDK, show me how to initialize the SDK with braze.initialize(), including the API key, base URL, and options for enabling logging and automatic in-app message display. Use context7. ``` #### カスタムイベントと購入のトラッキング {#tracking-custom-events-and-purchases} ```text Using the Braze Web SDK, create a JavaScript module that logs a custom event called "VideoPlayed" with properties for video_id, duration_seconds, and completion_percentage. Also show how to log a purchase with product ID, price, currency code, and quantity. Use context7. ``` #### Webプッシュの登録 {#registering-for-web-push} ```text Using the Braze Web SDK, provide the HTML and JavaScript needed to register a user for web push notifications after they click a "Subscribe to updates" button. Include the service worker setup. Use context7. ``` #### ユーザー属性の管理 {#managing-user-attributes} ```text Using the Braze Web SDK, show me how to set standard user attributes (first name, email, country) and custom user attributes (favorite_genre, subscription_tier) for the current user. Use context7. ``` ## プレーンテキストドキュメント {#plain-text-documentation} Braze開発者ガイドのドキュメントは、AIツールやLLM向けに最適化されたプレーンテキストファイルとしてアクセスできます。これらのファイルは、HTMLレンダリングのオーバーヘッドなしにAIアシスタントが解析・理解できる形式でBrazeドキュメントを提供します。 | ファイル | 説明 | |------|-------------| | [llms.txt](https://www.braze.com/docs/ja/ja/developer_guide/llms.txt) | Braze開発者向けドキュメントページのタイトルと説明のインデックスです。利用可能なドキュメントを見つけるための出発点として使用できます。 | | [llms-full.txt](https://www.braze.com/docs/ja/ja/developer_guide/llms-full.txt) | Braze開発者向けドキュメントの完全版を、LLMが利用しやすい形式でフォーマットした単一のプレーンテキストファイルです。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="プレーンテキストドキュメント" } これらのファイルは[llms.txt標準](https://llmstxt.org/)に準拠しています。これはAIツールがドキュメントにアクセスしやすくするための新しい規約です。プロンプト内でこれらのファイルを直接参照したり、内容をLLMに貼り付けてコンテキストとして使用したりできます。 # カスタマイズの概要 Source: /docs/ja/developer_guide/getting_started/customization_overview/index.md # カスタマイズの概要 {#customization-overview} > Brazeでは、ほとんどすべてがカスタマイズ可能です。このカスタマイズガイドの記事では、設定とカスタマイズを組み合わせてBrazeでの体験を洗練させる方法を紹介します。このプロセスでは、マーケティングチームとエンジニアリングチームが緊密に連携し、Brazeのメッセージングチャネルをどのようにカスタマイズするかを正確に調整する必要があります。 **Note:** Braze SDKは強力なツールキットですが、大まかに言えば2つの重要な機能を提供しています。1つは、プラットフォーム間でユーザーデータを収集し、統合されたユーザープロファイルに同期すること、もう1つは、アプリ内メッセージ、プッシュ通知、Content Cardsなどのメッセージングチャネルを処理することです。カスタマイズガイドの記事は、すでに[SDKの実装プロセス](https://www.braze.com/docs/ja/ja/developer_guide/home)を完了していることを前提としています。 すべてのBrazeコンポーネントは、アクセシブルで、適応性があり、カスタマイズできるように作られています。そのため、デフォルトの`BrazeUI`コンポーネントから始め、ブランドのニーズやユースケースに合わせてカスタマイズすることをお勧めします。Brazeでは、カスタマイズを、関連する労力と提供される柔軟性のレベルに基づいて、3つの異なるアプローチに分類しています。これらのアプローチは「ハイハイ」、「歩く」、「走る」と呼ばれています。 - **ハイハイ:** 基本的なスタイリングオプションを活用して、手間をかけずに素早く実装します。 - **歩く:** デフォルトのテンプレートにカスタムスタイルを追加して、ブランド体験によりマッチさせます。 - **走る:** スタイルから動作、クロスチャネル接続まで、メッセージングのあらゆる部分をカスタマイズします。 ![キャプション付き画像と画像のみのContent Cardsを表示するサンプル金融アプリ](https://www.braze.com/docs/ja/ja/assets/img_archive/cc_pyrite_crawl.png?5178761170e9c604d535a626ebb023b9){: style="max-width:35%;float:right;margin-left:15px;border:none;"} 「ハイハイ」のアプローチは、マーケターに直接カスタマイズの力を与えます。Brazeのメッセージングチャネルをアプリやサイトに統合するには、前もって軽い開発作業が必要ですが、この方法であればすぐに稼働させることができます。 マーケターはダッシュボードを通じて、メッセージのコンテンツ、オーディエンス、タイミングを決定します。しかし、スタイリングの選択肢は限られています。このアプローチは、開発者のリソースが限られているチームや、シンプルなコンテンツを素早く共有したいチームに最適です。
カスタマイズの概要
カスタマイズ 説明
労力
開発者の作業 0~1時間
カードスタイル デフォルトのBrazeテンプレートを使用します。
動作 デフォルトの動作オプションから選択します。
分析トラッキング 分析はBrazeでキャプチャされます。
キーと値のペア オプションで、UI/UXをさらにカスタマイズできます。
![カスタマイズされたContent Cardsを表示するサンプル金融アプリ](https://www.braze.com/docs/ja/ja/assets/img_archive/cc_pyrite_walk.png?f4e47488e8475fff8cc3d02d4241de74){: style="max-width:35%;float:right;margin-left:15px;border:none;"} ハイブリッドな実装アプローチである「歩く」では、アプリやサイトのブランディングに合わせて、マーケティングチームと開発チームの両方が参加します。 実装プロセスでは、開発者がカスタムコードを記述し、メッセージチャネルのルックアンドフィールをブランドにより近いものに更新します。これには、フォントの種類、フォントサイズ、角丸、色の変更が含まれます。このアプローチでもデフォルトのオプションを使用しますが、プログラムによるテンプレートスタイリングが適用されます。 マーケターは、Brazeのダッシュボードで直接、オーディエンス、コンテンツ、クリック動作、有効期限をコントロールできます。
カスタマイズの概要
カスタマイズ 説明
労力
開発者の作業 0~4時間
UI Brazeのテンプレートを使用するか、開発者が作成した独自のテンプレートを使用します。
動作 デフォルトの動作オプションから選択します。
分析トラッキング デフォルトの分析はBrazeでキャプチャされます。
キーと値のペア オプションで、UI/UXをさらにカスタマイズできます。
![メール収集機能付きのカスタムContent Cardsを表示するサンプル金融アプリ](https://www.braze.com/docs/ja/ja/assets/img_archive/cc_pyrite_run.png?571e20da6976b22e1c63ba76529a87f9){: style="max-width:35%;float:right;margin-left:15px;border:none;"} 「走る」のアプローチでは、開発者が主導権を握り、ユーザーエクスペリエンスを完全にコントロールします。カスタムコードによって、メッセージがどのように見えるか、どのように動作するか、他のメッセージングチャネルとどのように相互作用するか(例えば、プッシュ通知に基づいてContent Cardをトリガーするなど)を指定します。 新しいタイプのContent Cardsや特注UIのアプリ内メッセージなど、完全に新しいカスタムコンテンツを作成する場合、Braze SDKは自動的に[分析をトラッキング](https://www.braze.com/docs/ja/ja/developer_guide/analytics)しません。マーケターがBrazeのダッシュボードでインプレッション、クリック数、離脱などの指標に引き続きアクセスできるように、プログラムで分析を処理する必要があります。Braze SDKの分析メソッドを呼び出して、SDKがこのデータをBrazeに返すようにしてください。各メッセージングチャネルには、これを容易にするための分析に関する記事があります。
カスタマイズの概要
カスタマイズ 説明
労力 ユースケースによります。
開発者の作業 低労力:1~4時間
中労力:4~8時間
高労力:8時間以上
UI カスタム
動作 カスタム
分析トラッキング カスタム
キーと値のペア 必須
**Tip:** 開発者や実装担当者がBrazeのカスタムコンテンツを作成する際には、マーケターと部門を超えたコラボレーションを行う機会があります。例えば、新しいUIや特定のコンポーネントの新機能を開発する場合、新しい動作とバックエンドとの統合方法を文書化することで、チームを成功に導くことができます。 # Braze SDK チュートリアル Source: /docs/ja/developer_guide/tutorials/index.md
# Braze SDKを統合する Source: /docs/ja/developer_guide/sdk_integration/index.md # ![Brazeロゴ](https://www.braze.com/docs/ja/ja/assets/Braze_Primary_Icon_BLACK.svg?919c4e99e8ae11eafc3470e63b4fedce){: style="float:right;width:120px;border:0;" class="noimgborder"}Braze SDKを統合する {#braze-logo-image_buster-assetsbraze_primary_icon_blacksvg-stylefloatrightwidth120pxborder0-classnoimgborderintegrate-the-braze-sdk} > Braze SDKの統合方法について説明します。各SDKは独自のGitHub公開リポジトリでホストされており、Brazeの機能をテストしたり、独自のアプリケーションと一緒に実装したりするために使用できる、完全にビルド可能なサンプルアプリが含まれています。詳しくは、[参照資料、リポジトリ、サンプルアプリ](https://www.braze.com/docs/ja/ja/developer_guide/references)を参照してください。SDKに関する一般的な情報については、[はじめに:統合の概要](https://www.braze.com/docs/ja/ja/developer_guide/getting_started/integration_overview)を参照してください。 ドキュメント内のミラーされたSDK READMEコンテンツについては、[リポジトリガイド](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides)を参照してください。 **Tip:** SDKを統合した後、[SDK認証](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/authentication)を有効にすることで、不正なSDKリクエストを防止し、セキュリティをさらに強化できます。SDK認証は、Web、Android、Swift、React Native、Flutter、Unity、Cordova、.NET MAUI(Xamarin)、Expoで利用可能です。 ## About the Web Braze SDK The Web Braze SDK lets you collect analytics and display rich in-app messages, push, and Content Card messages to your web users. For more information, see [Braze JavaScript reference documentation](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html). **Note:** This guide uses code samples from the Braze Web SDK 4.0.0+. To upgrade to the latest Web SDK version, see [SDK Upgrade Guide](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md). ## Integrate the Web SDK You can integrate the Web Braze SDK using the following methods. For additional options, see [other integration methods](#web_other-integration-methods). - **Code-based integration:** Integrate the Web Braze SDK directly in your codebase using your preferred package manager or the Braze CDN. This gives you full control over how the SDK is loaded and configured. - **Google Tag Manager:** A no-code solution that lets you integrate the Web Braze SDK without modifying your site's code. For more information, see [Google Tag Manager with the Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/google_tag_manager/). **Important:** We recommend using the [NPM integration method](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?subtab=package%20manager&sdktab=web). Benefits include storing SDK libraries locally on your website, providing immunity from ad-blocker extensions, and contributing to faster load times as part of bundler support. ### Step 1: Install the Braze library You can install the Braze library using one of the following methods. However, if your website uses a `Content-Security-Policy`, review the [Content Security Policy](https://www.braze.com/docs/ja/ja/developer_guide/platforms/web/content_security_policy/) before continuing. **Important:** While most ad blockers do not block the Braze Web SDK, some more-restrictive ad blockers are known to cause issues. If your site uses NPM or Yarn package managers, you can add the [Braze NPM package](https://www.npmjs.com/package/@braze/web-sdk) as a dependency. Typescript definitions are now included as of v3.0.0. For notes on upgrading from 2.x to 3.x, see our [changelog](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md). ```bash npm install --save @braze/web-sdk # or, using yarn: # yarn add @braze/web-sdk ``` Once installed, you can `import` or `require` the library in the typical fashion: ```typescript import * as braze from "@braze/web-sdk"; // or, using `require` const braze = require("@braze/web-sdk"); ``` Add the Braze Web SDK directly to your HTML by referencing our CDN-hosted script, which loads the library asynchronously. **Important:** The default **Prevent Cross-Site Tracking** setting in Safari can prevent in-app message types like Banners and Content Cards from displaying when you use the CDN integration method. To avoid this issue, use the NPM integration method so that Safari does not classify these messages as cross-site traffic and your web users can see them in all supported browsers. ### Step 2: Initialize the SDK After the Braze Web SDK is added to your website, initialize the library with the API key and [SDK endpoint URL](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/sdk_endpoints) found in **Settings** > **App Settings** within your Braze dashboard. For a complete list of options for `braze.initialize()`, along with our other JavaScript methods, see [Braze JavaScript documentation](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initialize). **Note:** **Custom domains for Web SDK requests are not supported**: The Web SDK `baseUrl` must be a Braze SDK endpoint (for example, `sdk.iad-05.braze.com`). Braze does not support routing Web SDK traffic through a customer-owned domain via CNAME records. If you need Web SDK requests to originate from your own domain, contact Braze support. ```javascript // initialize the SDK braze.initialize('YOUR-API-KEY-HERE', { baseUrl: "YOUR-SDK-ENDPOINT-HERE", enableLogging: false, // set to `true` for debugging allowUserSuppliedJavascript: false, // set to `true` to support custom HTML messages }); // Enable automatic display of in-app messages // Required if you want in-app messages to display automatically when triggered braze.automaticallyShowInAppMessages(); // if you use Content Cards braze.subscribeToContentCardsUpdates(function(cards){ // cards have been updated }); // optionally set the current user's external ID before starting a new session // you can also call `changeUser` later in the session after the user logs in if (isLoggedIn){ braze.changeUser(userIdentifier); } // `openSession` should be called last - after `changeUser` and `automaticallyShowInAppMessages` braze.openSession(); ``` **Important:** **In-App Message Display**: To display in-app messages automatically when they're triggered, you must call `braze.automaticallyShowInAppMessages()`. Without this call, in-app messages don't display automatically. If you want to manage message display manually, remove this call and use `braze.subscribeToInAppMessage()` instead. For more information, see [In-app message delivery](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/delivery/). #### Troubleshooting missing sessions for anonymous users If you're seeing "Session missing" behavior, or you're not able to track the session for users who stay anonymous on web, make sure your integration calls `braze.openSession()` during initialization. - **Scenario:** Anonymous users can return a Braze ID, but session data is blank or missing. - **Cause:** The implementation doesn't call `braze.openSession()`. - **Resolution:** Always call `braze.openSession()` after initialization (and after `braze.changeUser()` if you set an external ID). For more information, see [Step 2: Initialize the SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web&tab=code-based%20integration#step-2-initialize-the-sdk). **Important:** Anonymous users on mobile or web devices may be counted towards your [MAU](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/reporting/understanding_your_app_usage_data/#monthly-active-users). As a result, you may want to conditionally load or initialize the SDK to exclude these users from your MAU count. ### Prerequisites Before you can use this integration method, you'll need to [create an account and container for Google Tag Manager](https://support.google.com/tagmanager/answer/14842164). ### Step 1: Open the tag template gallery In [Google Tag Manager](https://tagmanager.google.com/), choose your workspace, then select **Templates**. In the **Tag Template** pane, select **Search Gallery**. ![The templates page for an example workspace in Google Tag Manager.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/search_tag_template_gallery.png?3f889b02db28eee130a2e6afd58a27f4){: style="max-width:95%;"} ### Step 2: Add the initialization tag template In the template gallery, search for `braze-inc`, then select **Braze Initialization Tag**. ![The template gallery showing the various 'braze-inc' templates.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/template_gallery_results.png?166c46fcb5f46eeff8bd50727b6bf3ed){: style="max-width:80%;"} Select **Add to workspace** > **Add**. ![The 'Braze Initialization Tag' page in Google Tag Manager.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/add_to_workspace.png?426a14d8047898ccb343ac4476d38e3b){: style="max-width:70%;"} ### Step 3: Configure the tag From the **Templates** section, select your newly added template. ![The "Templates" page in Google Tag Manager showing the Braze Initialization Tag template.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/select_tag_template.png?54a3dd6d14a80b1b1f45d57a67134b24){: style="max-width:95%;"} Select the pencil icon to open the **Tag Configuration** dropdown. ![The Tag Configuration tile with the 'pencil' icon shown.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-initialization-tag.png?18e7bc10a22d55f5c681ee7a7266c767) Enter the minimum required information: | Field | Description | | ------------- | ----------- | | **API Key** | Your [Braze API Key](https://www.braze.com/docs/ja/ja/api/basics/#about-rest-api-keys), found in the Braze dashboard under **Settings** > **App Settings**. | | **API Endpoint** | Your REST endpoint URL. Your endpoint will depend on the Braze URL for [your instance](https://www.braze.com/docs/ja/ja/api/basics/#endpoints). | | **SDK Version** | The most recent `MAJOR.MINOR` version of the Web Braze SDK listed in the [changelog](https://www.braze.com/docs/ja/ja/developer_guide/changelogs/?sdktab=web). For example, if the latest version is `4.1.2`, enter `4.1`. For more information, see [About SDK version management](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/version_management/). | {: .reset-td-br-1 .reset-td-br-2 aria-label="Step 3: Configure the tag" } For additional initialization settings, select **Braze Initialization Options** and choose any options you need. ![The list of Braze Initialization Options in under 'Tag Configuration'.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/braze_initialization_options.png?7081bcb24b9eda18d19d4b8634dd59e8){: style="max-width:65%;"} ### Step 4: Choose initialization options The Braze Initialization Tag exposes the following options. Most of these map directly to the [Web SDK `InitializationOptions`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initializationoptions), and some correspond to Web SDK methods that the tag will call during initialization. Select the options that match your integration needs: | GTM option | Web SDK configuration or method | Description | | --- | --- | --- | | **Allow HTML In-App Messages** | `allowUserSuppliedJavascript` | Enables HTML in-app messages, Banners, and user-supplied JavaScript click actions. Required for [HTML in-app messages](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/message_types/custom_html/) and [Banners](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements/?sdktab=web) that use custom HTML. Only enable this when you trust the HTML and JavaScript content, as it allows user-supplied JavaScript execution. | | **App Version Number** | `appVersion`, `appVersionNumber` | App version for segmentation (for example, `1.2.3.4`). | | **Automatically Open New Session** | `braze.openSession()` | Opens a new session after the SDK is initialized by calling this method for you. | | **Automatically show new in app messages** | `braze.automaticallyShowInAppMessages()` | Automatically displays new in-app messages when they arrive from the server by calling this method after initialization. | | **Disable Automatic Push Token Maintenance** | `disablePushTokenMaintenance` | Stops the SDK from syncing push tokens with the Braze backend on new sessions. | | **Disable Automatic Service Worker Registration** | `manageServiceWorkerExternally` | Use if you register and control the service worker yourself. | | **Disable Cookies** | `noCookies` | Uses localStorage instead of cookies for user/session data. Prevents cross-subdomain recognition. | | **Disable Font Awesome** | `doNotLoadFontAwesome` | Prevents the SDK from loading Font Awesome from the CDN. Use if your site has its own Font Awesome. | | **Enable SDK Authentication** | `enableSdkAuthentication` | Enables [SDK Authentication](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/authentication/). | | **Enable Web SDK Logging** | `enableLogging` | Enables console logging for debugging. Remove before production. | | **Minimum Interval Between Triggered Messages** | `minimumIntervalBetweenTriggerActionsInSeconds` | Minimum seconds between trigger actions (default: 30). | | **Open Cards in New Tab** | `openCardsInNewTab` | Opens Content Card links in a new tab when using the default Feed UI. | | **Service Worker Location** | `serviceWorkerLocation` | Custom path for the service worker file (default: `/service-worker.js`). | | **Session Timeout (seconds)** | `sessionTimeoutInSeconds` | Session timeout in seconds (default: 1800). | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Step 4: Choose initialization options" } **Note:** To enable [Custom HTML in-app messages](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/message_types/custom_html/) when using the Google Tag Manager Braze Initialization Tag, select **Allow HTML In-App Messages** in **Braze Initialization Options**. This checkbox maps to the `allowUserSuppliedJavascript` initialization option in `braze.initialize()` and sets it to `true`. The Google Tag Manager Braze Initialization Tag uses this label instead of the option name. For options not exposed in the GTM template (such as `contentSecurityNonce`, `localization`, or `devicePropertyAllowlist`), use [runtime initialization](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web) instead. ### Step 5: Set to Trigger on *all pages* The initialization tag should be run on all pages of your site. This allows you to use Braze SDK methods and record web push analytics. ### Step 6: Verify your integration You can verify your integration using either of the following options: - **Option 1:** Using Google Tag Manager's [debugging tool](https://support.google.com/tagmanager/answer/6107056?hl=en), you can check if the Braze Initialization Tag is triggering correctly on your configured pages or events. - **Option 2:** Check for any network requests made to Braze from your web page. Additionally, the global `window.braze` library should now be defined. ## Filtering bot traffic {#bot-filtering} MAU can include a percentage of bot users, which inflates your monthly active user count. While the Braze Web SDK includes built-in detection for some common web crawlers (such as search engine bots and social media preview bots), it is especially important to stay proactive with robust solutions to detect bots, as SDK updates alone cannot consistently detect every new bot. ### Limitations of SDK-side bot detection The Web SDK includes basic user-agent-based bot detection that filters out known crawlers. However, this approach has limitations: - **New bots emerge constantly**: AI companies and other actors regularly create new bots that may disguise themselves to avoid detection. - **User-agent spoofing**: Sophisticated bots can mimic legitimate browser user-agents. - **Custom bots**: Non-technical users can now easily create bots using large language models (LLMs), making bot behavior unpredictable. ### Implementing bot filtering **Important:** The solutions outlined below are general suggestions. Tailor bot filtering logic to your unique environment and traffic patterns. The most robust solution is to implement your own bot filtering logic before initializing the Braze SDK. Common approaches include: #### Require user interaction Consider delaying SDK initialization until a user performs a meaningful interaction, such as accepting a cookie consent banner, scrolling, or clicking. This approach is often easier to implement and can be highly effective at filtering bot traffic. **Important:** Delaying SDK initialization until user interaction might cause Banners and Content Cards to also not display until that interaction occurs. #### Custom bot detection Implement custom detection based on your specific bot traffic patterns, such as: - Analyzing user-agent strings for patterns you've identified in your traffic - Checking for headless browser indicators - Using third-party bot detection services - Monitoring behavioral signals specific to your site **Example of conditional initialization:** ```javascript // Only initialize Braze if your custom bot detection determines this is not a bot if (!isLikelyBot()) { braze.initialize('YOUR-API-KEY-HERE', { baseUrl: "YOUR-SDK-ENDPOINT-HERE" }); braze.automaticallyShowInAppMessages(); braze.openSession(); } ``` ### Best practices - Regularly analyze your MAU data and web traffic patterns to identify new bot behavior. - Test thoroughly to ensure your bot filtering doesn't prevent legitimate users from being tracked. - Update your filtering logic based on the bot traffic patterns you observe in your environment. ## Optional configurations ### Logging To quickly enable logging, you can add `?brazeLogging=true` as a parameter to your website URL. Alternatively, you can enable [basic](#web_basic-logging) or [custom](#web_custom-logging) logging. For a centralized overview across all platforms, see [Verbose logging](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging). #### Basic logging Use `enableLogging` to log basic debugging messages to the JavaScript console before the SDK is initialized. ```javascript enableLogging: true ``` Your method should be similar to the following: ```javascript braze.initialize('API-KEY', { baseUrl: 'API-ENDPOINT', enableLogging: true }); braze.openSession(); ``` Use `braze.toggleLogging()` to log basic debugging messages to the JavaScript console after the SDK is initialized. Your method should be similar to the following: ```javascript braze.initialize('API-KEY', { baseUrl: 'API-ENDPOINT', }); braze.openSession(); ... braze.toggleLogging(); ``` **Important:** Basic logs are visible to all users, so consider disabling, or switch to [`setLogger`](#web_custom-logging), before releasing your code to production. #### Custom logging Use `setLogger` to log custom debugging messages to the JavaScript console. Unlike basic logs, these logs are not visible to users. ```javascript setLogger(loggerFunction: (message: STRING) => void): void ``` Replace `STRING` with your message as a single string parameter. Your method should be similar to the following: ```javascript braze.initialize('API-KEY'); braze.setLogger(function(message) { console.log("Braze Custom Logger: " + message); }); braze.openSession(); ``` ## Upgrading the SDK **Note:** This guide uses code samples from the Braze Web SDK 4.0.0+. To upgrade to the latest Web SDK version, see [SDK Upgrade Guide](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md). When you reference the Braze Web SDK from our content delivery network, for example, `https://js.appboycdn.com/web-sdk/a.a/braze.min.js` (as recommended by our default integration instructions), your users receive minor updates (bug fixes and backward compatible features, versions `a.a.a` through `a.a.z` in the above examples) automatically when they refresh your site. However, when we release major changes, we require you to upgrade the Braze Web SDK manually to ensure that breaking changes do not impact your integration. Additionally, if you download our SDK and host it yourself, you don't receive any version updates automatically and should upgrade manually to receive the latest features and bug fixes. You can keep up-to-date with our latest release [following our release feed](https://github.com/braze-inc/braze-web-sdk/tags.atom) with the RSS Reader or service of your choice, and see [our changelog](https://github.com/braze-inc/braze-web-sdk/blob/master/CHANGELOG.md) for a full accounting of our Web SDK release history. To upgrade the Braze Web SDK: - Update the Braze library version by changing the version number of `https://js.appboycdn.com/web-sdk/[OLD VERSION NUMBER]/braze.min.js`, or in your package manager's dependencies. - If you have web push integrated, update the service worker file on your site - by default, this is located at `/service-worker.js` at your site's root directory, but the location may be customized in some integrations. You must access the root directory to host a service worker file. You must update these two files in coordination with each other for proper functionality. ## Other integration methods ### Accelerated Mobile Pages (AMP) **See more** #### Step 1: Include AMP web push script Add the following async script tag to your head: ```js ``` #### Step 2: Add subscription widgets Add a widget to the body of your HTML that allows users to subscribe and unsubscribe from push. ```js ``` #### Step 3: Add `helper-iframe` and `permission-dialog` The AMP Web Push component creates a popup to handle push subscriptions, so you must add the following helper files to your project to enable this feature: - [`helper-iframe.html`](https://cdn.ampproject.org/v0/amp-web-push-helper-frame.html) - [`permission-dialog.html`](https://cdn.ampproject.org/v0/amp-web-push-permission-dialog.html) #### Step 4: Create a service worker file Create a `service-worker.js` file in the root directory of your website and add the following snippet: #### Step 5: Configure the AMP web push HTML element Add the following `amp-web-push` HTML element to your HTML body. Keep in mind, you need to append your [`apiKey` and `baseUrl`](https://documenter.getpostman.com/view/4689407/SVYrsdsG) as query parameters to `service-worker-URL`. ```js ``` ### Asynchronous Module Definition (AMD) #### Disable support If your site uses RequireJS or another AMD module-loader, but you prefer to load the Braze Web SDK through one of the other options in this list, you can load a version of the library that does not include AMD support. This version of the library can be loaded from the following CDN location: #### Module loader If you use RequireJS or other AMD module-loaders we recommend self-hosting a copy of our library and referencing it as you would with other resources: ```javascript require(['path/to/braze.min.js'], function(braze) { braze.initialize('YOUR-API-KEY-HERE', { baseUrl: 'YOUR-SDK-ENDPOINT' }); // Required if you want in-app messages to display automatically braze.automaticallyShowInAppMessages(); braze.openSession(); }); ``` ### Electron {#electron} Electron does not officially support web push notifications (see: this [GitHub issue](https://github.com/electron/electron/issues/6697)). There are other [open source workarounds](https://github.com/MatthieuLemoine/electron-push-receiver) you may try that have not been tested by Braze. ### Jest framework {#jest} When using Jest, you may see an error similar to `SyntaxError: Unexpected token 'export'`. To fix this, adjust your configuration in `package.json` to ignore the Braze SDK: ``` "jest": { "transformIgnorePatterns": [ "/node_modules/(?!@braze)" ] } ``` ### SSR frameworks {#ssr} The Web SDK runs in a browser environment. In SSR frameworks, initialize Braze in a client-only component so your server never executes SDK code. #### Framework-agnostic dynamic import If your framework isn't listed in this section, you can dynamically import Braze from a client-only lifecycle hook. ```javascript // MyComponent/braze-exports.js // Export the parts of the SDK that you need. export { initialize, openSession } from "@braze/web-sdk"; // MyComponent/MyComponent.js useEffect(() => { import("./braze-exports.js").then(({ initialize, openSession }) => { initialize("YOUR-API-KEY-HERE", { baseUrl: "YOUR-SDK-ENDPOINT", enableLogging: true, }); openSession(); }); }, []); ``` If you're using webpack, you can dynamically import only specific SDK exports. ```javascript // MyComponent.js useEffect(() => { import( /* webpackExports: ["initialize", "openSession"] */ "@braze/web-sdk" ).then(({ initialize, openSession }) => { initialize("YOUR-API-KEY-HERE", { baseUrl: "YOUR-SDK-ENDPOINT", enableLogging: true, }); openSession(); }); }, []); ``` #### Shared hook for Next.js and Remix Create a reusable `useBraze` hook and call it near your app root. ```tsx // hooks/useBraze.ts import { useEffect, useRef } from "react"; export function useBraze() { const didInit = useRef(false); useEffect(() => { if (didInit.current) { return; } didInit.current = true; import("@braze/web-sdk") .then((braze) => { const initialized = braze.initialize("YOUR-API-KEY-HERE", { // Use your Braze Web SDK endpoint, such as sdk.iad-01.braze.com. baseUrl: "YOUR-SDK-ENDPOINT", enableLogging: false, }); if (!initialized) { return; } // Optional: Identify signed-in users before opening a session. // braze.changeUser("external-id"); // Optional: Automatically display in-app messages. // braze.automaticallyShowInAppMessages(); braze.openSession(); }) .catch((error) => { console.error("Unable to load Braze SDK:", error); }); }, []); } ``` #### Next.js (App Router) Call `useBraze` in a client component that wraps your app. ```tsx // app/components/AppRoot.tsx "use client"; import type { ReactNode } from "react"; import { useBraze } from "../hooks/useBraze"; export function AppRoot({ children }: { children: ReactNode }) { useBraze(); return <>{children}; } ``` ```tsx // app/layout.tsx import type { ReactNode } from "react"; import { AppRoot } from "./components/AppRoot"; export default function RootLayout({ children, }: { children: ReactNode; }) { return ( {children} ); } ``` #### Next.js (Pages Router) Call `useBraze` at the top of your custom app component. ```tsx // pages/_app.tsx import type { AppProps } from "next/app"; import { useBraze } from "../hooks/useBraze"; export default function App({ Component, pageProps }: AppProps) { useBraze(); return ( ); } ``` #### Remix Call `useBraze` at the top of your root route component. For local Remix validation examples, run `PORT=4013 npm run dev`. ```tsx // app/root.tsx import { Outlet } from "@remix-run/react"; import { useBraze } from "./hooks/useBraze"; export default function App() { useBraze(); return ; } ``` #### Logging events and updating users After `useBraze` initializes the SDK at your app root, other client components can call Braze methods. A common pattern is to call them inside user actions, such as `onClick` or `onSubmit`. In the example, the SDK methods are loaded inside the click handler instead of at the top of the file. This keeps the Web SDK out of server code and loads only what that action needs. The `webpackExports` comment tells webpack which methods to include, so your bundle stays smaller. ```tsx // app/components/BuyButton.tsx "use client"; export function BuyButton() { const handleClick = async () => { const { logCustomEvent, logPurchase, getUser } = await import( /* webpackExports: ["logCustomEvent", "logPurchase", "getUser"] */ "@braze/web-sdk" ); getUser()?.setCustomUserAttribute("last_purchase_date", "2026-05-04"); logCustomEvent("clicked_buy", { source: "product_page" }); logPurchase("sku_123", 19.99, "USD"); }; return ; } ``` This example shows a `BuyButton` component that logs activity when someone clicks **Buy**. First, it imports only `logCustomEvent`, `logPurchase`, and `getUser` at click time. Then it updates a user attribute, logs a custom event, and logs a purchase. This pattern helps you keep initialization centralized in `useBraze`, while still tracking meaningful actions from any client component. If you're using Remix with Vite and package-root imports fail at runtime, use the existing Vite workaround. For more information, see [Vite](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web#web_vite). For a full list of available methods, see the [Braze JavaScript reference documentation](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html). ### Tealium iQ Tealium iQ offers a basic turnkey Braze integration. To configure the integration, search for Braze in the Tealium Tag Management interface, and provide the Web SDK API key from your dashboard. For more details or in-depth Tealium configuration support, check out our [integration documentation](https://www.braze.com/docs/ja/ja/partners/data_and_infrastructure_agility/customer_data_platform/tealium/#about-tealium) or contact your Tealium account manager. ### Vite {#vite} If you use Vite and see a warning around circular dependencies or `Uncaught TypeError: Class extends value undefined is not a constructor or null`, you may need to exclude the Braze SDK from its [dependency discovery](https://vitejs.dev/guide/dep-pre-bundling.html#customizing-the-behavior): ``` optimizeDeps: { exclude: ['@braze/web-sdk'] }, ``` ### Other tag managers Braze may also be compatible with other tag management solutions by following our integration instructions within a custom HTML tag. Contact a Braze representative if you need help evaluating these solutions. ## Integrating the Android SDK ### Step 1: Update your Gradle build configuration In your project's repository configuration (for example, `settings.gradle`, `settings.gradle.kts`, or top-level `build.gradle`), add [`mavenCentral()`](https://docs.gradle.org/current/kotlin-dsl/gradle/org.gradle.api.artifacts.dsl/-repository-handler/maven-central.html) to your list of repositories. This syntax is the same for both Groovy and Kotlin DSL. ```groovy repositories { mavenCentral() } ``` Next, add Braze to your dependencies. In the following examples, replace `SDK_VERSION` with the current version of your Android Braze SDK. For the full list of versions, see [Changelogs](https://www.braze.com/docs/ja/ja/developer_guide/changelogs/?sdktab=android). **Note:** - For Kotlin DSL (`build.gradle.kts`), use the `implementation("...")` syntax. - For Groovy (`build.gradle`), use the `implementation '...'` syntax. - For [version catalogs](https://developer.android.com/build/migrate-to-catalogs), add entries to your `gradle/libs.versions.toml` file and reference them using the generated accessors. If you don't plan on using Braze UI components, add the following to your dependencies. ```groovy dependencies { implementation 'com.braze:android-sdk-base:SDK_VERSION' // (Required) Adds dependencies for the base Braze SDK. implementation 'com.braze:android-sdk-location:SDK_VERSION' // (Optional) Adds dependencies for Braze location services. } ``` ```kotlin dependencies { implementation("com.braze:android-sdk-base:SDK_VERSION") // (Required) Adds dependencies for the base Braze SDK. implementation("com.braze:android-sdk-location:SDK_VERSION") // (Optional) Adds dependencies for Braze location services. } ``` In your `gradle/libs.versions.toml` file: ```toml [versions] braze = "SDK_VERSION" [libraries] braze-android-sdk-base = { group = "com.braze", name = "android-sdk-base", version.ref = "braze" } braze-android-sdk-location = { group = "com.braze", name = "android-sdk-location", version.ref = "braze" } ``` Then, in your `build.gradle` or `build.gradle.kts` file, add the following dependencies. This syntax is the same for both Groovy and Kotlin DSL. ```groovy dependencies { implementation(libs.braze.android.sdk.base) // (Required) Adds dependencies for the base Braze SDK. implementation(libs.braze.android.sdk.location) // (Optional) Adds dependencies for Braze location services. } ``` If you plan on using Braze UI components, add the following to your dependencies. ```groovy dependencies { implementation 'com.braze:android-sdk-ui:SDK_VERSION' // (Required) Adds dependencies for the Braze SDK and Braze UI components. implementation 'com.braze:android-sdk-location:SDK_VERSION' // (Optional) Adds dependencies for Braze location services. } ``` ```kotlin dependencies { implementation("com.braze:android-sdk-ui:SDK_VERSION") // (Required) Adds dependencies for the Braze SDK and Braze UI components. implementation("com.braze:android-sdk-location:SDK_VERSION") // (Optional) Adds dependencies for Braze location services. } ``` In your `gradle/libs.versions.toml` file: ```toml [versions] braze = "SDK_VERSION" [libraries] braze-android-sdk-ui = { group = "com.braze", name = "android-sdk-ui", version.ref = "braze" } braze-android-sdk-location = { group = "com.braze", name = "android-sdk-location", version.ref = "braze" } ``` Then, in your `build.gradle` or `build.gradle.kts` file, add the following dependencies. This syntax is the same for both Groovy and Kotlin DSL. ```groovy dependencies { implementation(libs.braze.android.sdk.ui) // (Required) Adds dependencies for the Braze SDK and Braze UI components. implementation(libs.braze.android.sdk.location) // (Optional) Adds dependencies for Braze location services. } ``` ### Step 2: Configure your `braze.xml` **Note:** As of December 2019, custom endpoints are no longer given out, if you have a pre-existing custom endpoint, you may continue to use it. For more details, refer to our list of available endpoints. Create a `braze.xml` file in your project's `res/values` folder. If you are on a specific data cluster or have a pre-existing custom endpoint, you need to specify the endpoint in your `braze.xml` file as well. The contents of that file should resemble the following code snippet. Make sure to substitute `YOUR_APP_IDENTIFIER_API_KEY` with the identifier found in the **Manage Settings** page of the Braze dashboard. Log in at [dashboard.braze.com](https://dashboard.braze.com) to find your [cluster address](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/sdk_endpoints). ```xml YOUR_APP_IDENTIFIER_API_KEY YOUR_CUSTOM_ENDPOINT_OR_CLUSTER ``` ### Step 3: Add permissions to `AndroidManifest.xml` Next, add the following permissions to your `AndroidManifest.xml`: ```xml ``` **Note:** With the release of Android M, Android switched from an install-time to a runtime permissions model. However, both of these permissions are normal permissions and are granted automatically if listed in the app manifest. For more information, visit Android's [permission documentation](https://developer.android.com/training/permissions/index.html). ### Step 4: Enable delayed initialization (optional) To use delayed initialization, the minimum Braze SDK version is required: **Note:** While delayed initialization is enabled, all network connections are canceled, preventing the SDK from sending data to the Braze servers. #### Step 4.1: Update your `braze.xml` Delayed initialization is disabled by default. To enable, use one of the following options: In your project's `braze.xml` file, set `com_braze_enable_delayed_initialization` to `true`. ```xml true ``` To enable delayed initialization at runtime, use the following method. ```java Braze.enableDelayedInitialization(context); ``` ```kotlin Braze.enableDelayedInitialization(context) ``` **Note:** When delayed initialization is enabled and a push notification contains a deep link action, the deep link does not resolve. #### Step 4.2: Configure push analytics (optional) When delayed initialization is enabled, push analytics are queued by default. However, you can choose to [explicitly queue](#explicitly-queue-push-analytics) or [drop](#drop-push-analytics) push analytics instead. ##### Explicitly queue {#explicitly-queue-push-analytics} To explicitly queue push analytics, choose one of the following options: In your `braze.xml` file, set `com_braze_delayed_initialization_analytics_behavior` to `QUEUE`: ```xml QUEUE ``` Add `QUEUE` to your [`Braze.enableDelayedInitialization()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/enable-delayed-initialization.html) method: ```java Braze.enableDelayedInitialization(context, DelayedInitializationAnalyticsBehavior.QUEUE); ``` ```kotlin Braze.enableDelayedInitialization(context, DelayedInitializationAnalyticsBehavior.QUEUE) ``` ##### Drop {#drop-push-analytics} To drop push analytics, choose one of the following options: In your `braze.xml` file, set `com_braze_delayed_initialization_analytics_behavior` to `DROP`: ```xml DROP ``` Add `DROP` to the [`Braze.enableDelayedInitialization()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/enable-delayed-initialization.html) method: ```java Braze.enableDelayedInitialization(context, DelayedInitializationAnalyticsBehavior.DROP); ``` ```kotlin Braze.enableDelayedInitialization(context, DelayedInitializationAnalyticsBehavior.DROP) ``` #### Step 4.3: Manually initialize the SDK After your chosen delay period, use the [`Braze.disableDelayedInitialization()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/disable-delayed-initialization.html) method to manually initialize the SDK. ```java Braze.disableDelayedInitialization(context); ``` ```kotlin Braze.disableDelayedInitialization(context) ``` ### Step 5: Enable user session tracking When you enable user session tracking, calls to `openSession()`, `closeSession()`,[`ensureSubscribedToInAppMessageEvents()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-braze-in-app-message-manager/ensure-subscribed-to-in-app-message-events.html), and `InAppMessageManager` registration can be handled automatically. To register activity lifecycle callbacks, add the following code to the `onCreate()` method of your `Application` class. ```java public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); registerActivityLifecycleCallbacks(new BrazeActivityLifecycleCallbackListener()); } } ``` ```kotlin class MyApplication : Application() { override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(BrazeActivityLifecycleCallbackListener()) } } ``` For the list of available parameters, see [`BrazeActivityLifecycleCallbackListener`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze-activity-lifecycle-callback-listener/index.html). ## Testing session tracking **Tip:** You can also use the [SDK Debugger](https://www.braze.com/docs/ja/ja/developer_guide/debugging) to diagnose SDK issues. If you experience issues while testing, enable [verbose logging](#android_enabling-logs), then use logcat to detect missing `openSession` and `closeSession` calls in your activities. 1. In Braze, go to **Overview**, select your app, then in the **Display Data For** dropdown choose **Today**. ![The "Overview" page in Braze, with the "Display Data For" field set to "Today".](https://www.braze.com/docs/ja/ja/assets/img_archive/android_sessions.png?a80518af3562397d27154b59f66b87f1) 2. Open your app, then refresh the Braze dashboard. Verify that your metrics have increased by 1. 3. Navigate through your app and verify that only one session has been logged to Braze. 4. Send the app to the background for at least 10 seconds, then bring it to the foreground. Verify that a new session was logged. ## Optional configurations ### Runtime configuration To set your Braze options in code rather than your `braze.xml` file, use [runtime configuration](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/configure.html). If a value exists in both places, the runtime value will be used instead. After all required settings are supplied at runtime, you can delete your `braze.xml` file. In the following example, a [builder object](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/index.html) is created and then passed to [`Braze.configure()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/configure.html). Note that only some of the available runtime options are shown—refer to our [KDoc](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/index.html) for the full list. ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setApiKey("api-key-here") .setCustomEndpoint("YOUR_CUSTOM_ENDPOINT_OR_CLUSTER") .setSessionTimeout(60) .setHandlePushDeepLinksAutomatically(true) .setGreatNetworkDataFlushInterval(10) .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setApiKey("api-key-here") .setCustomEndpoint("YOUR_CUSTOM_ENDPOINT_OR_CLUSTER") .setSessionTimeout(60) .setHandlePushDeepLinksAutomatically(true) .setGreatNetworkDataFlushInterval(10) .build() Braze.configure(this, brazeConfig) ``` **Tip:** Looking for another example? Check out our [Hello Braze sample app](https://github.com/braze-inc/braze-android-sdk/blob/master/samples/hello-braze/src/main/java/com/braze/helloworld/CustomApplication.java). ### Google Advertising ID The [Google Advertising ID (GAID)](https://support.google.com/googleplay/android-developer/answer/6048248/advertising-id?hl=en) is an optional user-specific, anonymous, unique, and resettable ID for advertising, provided by Google Play services. GAID gives users the power to reset their identifier, opt-out of interest-based ads within Google Play apps, and provides developers with a simple, standard system to continue to monetize their apps. The Google Advertising ID is not automatically collected by the Braze SDK and must be set manually via the [`Braze.setGoogleAdvertisingId()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/set-google-advertising-id.html) method. ```java new Thread(new Runnable() { @Override public void run() { try { AdvertisingIdClient.Info idInfo = AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext()); Braze.getInstance(getApplicationContext()).setGoogleAdvertisingId(idInfo.getId(), idInfo.isLimitAdTrackingEnabled()); } catch (Exception e) { e.printStackTrace(); } } }).start(); ``` ```kotlin suspend fun fetchAndSetAdvertisingId( context: Context, scope: CoroutineScope = GlobalScope ) { scope.launch(Dispatchers.IO) { try { val idInfo = AdvertisingIdClient.getAdvertisingIdInfo(context) Braze.getInstance(context).setGoogleAdvertisingId( idInfo.id, idInfo.isLimitAdTrackingEnabled ) } catch (e: Exception) { e.printStackTrace() } } } ``` **Important:** Google requires the Advertising ID to be collected on a non-UI thread. ### Location tracking To enable Braze location collection, set `com_braze_enable_location_collection` to `true` in your `braze.xml` file: ```xml true ``` **Important:** Starting with Braze Android SDK version 3.6.0, Braze location collection is disabled by default. ### Logging By default, the Braze Android SDK log level is set to `INFO`. You can [suppress these logs](#android_suppressing-logs) or [set a different log level](#android_enabling-logs), such as `VERBOSE`, `DEBUG`, or `WARN`. #### Enabling logs To help troubleshoot issues in your app, or reduce turnaround times with Braze Support, you can enable verbose logs for the SDK. When you send verbose logs to Braze Support, ensure they begin as soon as you launch your application and end far after your issue occurs. For a centralized overview, see [Verbose logging](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging). To learn how to interpret log output, see [Reading verbose logs](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/reading_verbose_logs). Keep in mind, verbose logs are only intended for your development environment, so you'll want to disable them before releasing your app. **Important:** Enable verbose logs before any other calls in `Application.onCreate()` to ensure your logs are as complete as possible. To enable logs directly in your app, add the following to your application's `onCreate()` method before any other methods. ```java BrazeLogger.setLogLevel(Log.MIN_LOG_LEVEL); ``` ```kotlin BrazeLogger.logLevel = Log.MIN_LOG_LEVEL ``` Replace `MIN_LOG_LEVEL` with the **Constant** of the log level you'd like to set as your minimum log level. Any logs at a level `>=` to your set `MIN_LOG_LEVEL` will be forwarded to Android's default [`Log`](https://developer.android.com/reference/android/util/Log) method. Any logs `<` your set `MIN_LOG_LEVEL` will be discarded. | Constant | Value | Description | |-------------|----------------|---------------------------------------------------------------------------| | `VERBOSE` | 2 | Logs the most detailed messages for debugging and development. | | `DEBUG` | 3 | Logs descriptive messages for debugging and development. | | `INFO` | 4 | Logs informational messages for general highlights. | | `WARN` | 5 | Logs warning messages for identifying potentially harmful situations. | | `ERROR` | 6 | Logs error messages for indicating application failure or serious issues. | | `ASSERT` | 7 | Logs assertion messages when conditions are false during development. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Enabling logs" } For example, the following code will forward log levels `2`, `3`, `4`, `5`, `6`, and `7` to the `Log` method. ```java BrazeLogger.setLogLevel(Log.VERBOSE); ``` ```kotlin BrazeLogger.logLevel = Log.VERBOSE ``` To enable logs in the `braze.xml`, add the following to your file: ```xml MIN_LOG_LEVEL ``` Replace `MIN_LOG_LEVEL` with the **Value** of the log level you'd like to set as your minimum log level. Any logs at a level `>=` to your set `MIN_LOG_LEVEL` will be forwarded to Android's default [`Log`](https://developer.android.com/reference/android/util/Log) method. Any logs `<` your set `MIN_LOG_LEVEL` will be discarded. | Constant | Value | Description | |-------------|----------------|---------------------------------------------------------------------------| | `VERBOSE` | 2 | Logs the most detailed messages for debugging and development. | | `DEBUG` | 3 | Logs descriptive messages for debugging and development. | | `INFO` | 4 | Logs informational messages for general highlights. | | `WARN` | 5 | Logs warning messages for identifying potentially harmful situations. | | `ERROR` | 6 | Logs error messages for indicating application failure or serious issues. | | `ASSERT` | 7 | Logs assertion messages when conditions are false during development. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Enabling logs" } For example, the following code will forward log levels `2`, `3`, `4`, `5`, `6`, and `7` to the `Log` method. ```xml 2 ``` #### Verifying verbose logs To verify that your logs are set to `VERBOSE`, check if `V/Braze` occurs somewhere in your logs. If it does, then verbose logs have been successfully enabled. For example: ``` 2077-11-19 16:22:49.591 ? V/Braze v9.0.01 .bo.app.d3: Request started ``` #### Suppressing logs To suppress all logs for the Braze Android SDK, set the log level to `BrazeLogger.SUPPRESS` in your application's `onCreate()` method _before_ any other methods. ```java BrazeLogger.setLogLevel(BrazeLogger.SUPPRESS); ``` ```kotlin BrazeLogger.setLogLevel(BrazeLogger.SUPPRESS) ``` ### Multiple API keys The most common use case for multiple API keys is separating API keys for debug and release build variants. To easily switch between multiple API keys in your builds, we recommend creating a separate `braze.xml` file for each relevant [build variant](https://developer.android.com/studio/build/build-variants.html). A build variant is a combination of build type and product flavor. By default, new Android projects are configured with [`debug` and `release` build types](https://developer.android.com/reference/tools/gradle-api/8.3/null/com/android/build/api/dsl/BuildType) and no product flavors. For each relevant build variant, create a new `braze.xml` in the `src//res/values/` directory. When the build variant is compiled, it will use the new API key. ```xml REPLACE_WITH_YOUR_BUILD_VARIANT_API_KEY ``` **Tip:** To learn how to set up the API key in your code, see [Runtime configuration](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization/?sdktab=android). ### Exclusive in-app message TalkBack In adherence to the [Android accessibility guidelines](https://developer.android.com/guide/topics/ui/accessibility), the Braze Android SDK offers Android Talkback by default. To ensure that only the contents of in-app messages are read out loud—without including other screen elements like the app title bar or navigation—you can enable exclusive mode for TalkBack. To enable exclusive mode for in-app messages: ```xml true ``` ```kotlin val brazeConfigBuilder = BrazeConfig.Builder() brazeConfigBuilder.setIsInAppMessageAccessibilityExclusiveModeEnabled(true) Braze.configure(this, brazeConfigBuilder.build()) ``` ```java BrazeConfig.Builder brazeConfigBuilder = new BrazeConfig.Builder() brazeConfigBuilder.setIsInAppMessageAccessibilityExclusiveModeEnabled(true); Braze.configure(this, brazeConfigBuilder.build()); ``` ### R8 and ProGuard [Code shrinking](https://developer.android.com/build/shrink-code) configuration is automatically included with your Braze integration. Client apps that obfuscate Braze code must store release mapping files for Braze to interpret stack traces. If you want to continue to keep all Braze code, add the following to your ProGuard file: ``` -keep class bo.app.** { *; } -keep class com.braze.** { *; } ``` ## Integrating the Swift SDK You can integrate and customize the Braze Swift SDK using the Swift Package Manager (SPM), CocoaPods, or manual integration methods. For more information about the various SDK symbols, see [Braze Swift reference documentation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/). ### Prerequisites Before you start, verify your environment is supported by the [latest Braze Swift SDK version](https://github.com/braze-inc/braze-swift-sdk#version-information). ### Step 1: Install the Braze Swift SDK We recommend using the [Swift Package Manager (SwiftPM)](https://swift.org/package-manager/) or [CocoaPods](http://cocoapods.org/) to install the Braze Swift SDK. Alternatively, you can install the SDK manually. #### Step 1.1: Import SDK version Open your project and navigate to your project's settings. Select the **Swift Packages** tab and click on the add button below the packages list. ![](https://www.braze.com/docs/ja/ja/assets/img/swiftpackages.png?1987d5a2a722497bf1f2f38ab52aa14a) **Note:** Starting in version 7.4.0, the Braze Swift SDK has additional distribution channels as [static XCFrameworks](https://github.com/braze-inc/braze-swift-sdk-prebuilt-static) and [dynamic XCFrameworks](https://github.com/braze-inc/braze-swift-sdk-prebuilt-dynamic). If you'd like to use either of these formats instead, follow the installation instructions from its respective repository. Enter the URL of our iOS Swift SDK repository `https://github.com/braze-inc/braze-swift-sdk` in the text field. Under the **Dependency Rule** section, select the SDK version. Finally, click **Add Package**. ![](https://www.braze.com/docs/ja/ja/assets/img/importsdk_example.png?38a74eb0e009cc281bd78ac130e2089c) #### Step 1.2: Select your packages The Braze Swift SDK separates features into standalone libraries to provide developers with more control over which features to import into their projects. | Package | Details | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `BrazeKit` | Main SDK library providing support for analytics and push notifications. | | `BrazeLocation` | Location library providing support for location analytics and geofence monitoring. | | `BrazeUI` | Braze-provided user interface library for in-app messages, Content Cards, and Banners. Import this library if you intend to use the default UI components. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Step 1.2: Select your packages" } {: .ws-td-nw-1} ##### About Extension libraries **Warning:** [BrazeNotificationService](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b2-rich-push-notifications) and [BrazePushStory](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b3-push-stories) are extension modules that provide additional functionality and should not be added directly to your main application target. Instead follow the linked guides to integrate them separately into their respective target extensions. | Package | Details | | -------------------------- | ------------------------------------------------------------------------------------- | | `BrazeNotificationService` | Notification service extension library providing support for rich push notifications. | | `BrazePushStory` | Notification content extension library providing support for Push Stories. | {: .reset-td-br-1 .reset-td-br-2 aria-label="About Extension libraries" } {: .ws-td-nw-1} Select the package that best suits your needs and click **Add Package**. Make sure you select `BrazeKit` at a minimum. ![](https://www.braze.com/docs/ja/ja/assets/img/add_package.png?2fa980e608a800e7e3649f34d79f2ea7) #### Step 1.1: Install CocoaPods For a full walkthrough, see CocoaPods' [Getting Started Guide](https://guides.cocoapods.org/using/getting-started.html). Otherwise, you can run the following command to get started quickly: ```bash $ sudo gem install cocoapods ``` If you get stuck, checkout CocoaPods' [Troubleshooting Guide](http://guides.cocoapods.org/using/troubleshooting.html). #### Step 1.2: Constructing the Podfile Next, create a file in your Xcode project directory named `Podfile`. **Note:** Starting in version 7.4.0, the Braze Swift SDK has additional distribution channels as [static XCFrameworks](https://github.com/braze-inc/braze-swift-sdk-prebuilt-static) and [dynamic XCFrameworks](https://github.com/braze-inc/braze-swift-sdk-prebuilt-dynamic). If you'd like to use either of these formats instead, follow the installation instructions from its respective repository. Add the following line to your Podfile: ``` target 'YourAppTarget' do pod 'BrazeKit' end ``` `BrazeKit` contains the main SDK library, providing support for analytics and push notifications. We suggest you version Braze so pod updates automatically grab anything smaller than a minor version update. This looks like `pod 'BrazeKit' ~> Major.Minor.Build`. If you want to automatically integrate the latest Braze SDK version, even with major changes, you can use `pod 'BrazeKit'` in your Podfile. ##### About additional libraries The Braze Swift SDK separates features into standalone libraries to provide developers with more control over which features to import into their projects. In addition to `BrazeKit`, you may add the following libraries to your Podfile: | Library | Details | | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `pod 'BrazeLocation'` | Location library providing support for location analytics and geofence monitoring. | | `pod 'BrazeUI'` | Braze-provided user interface library for in-app messages, Content Cards, and Banners. Import this library if you intend to use the default UI components. | {: .reset-td-br-1 .reset-td-br-2 aria-label="About additional libraries" } {: .ws-td-nw-1} ###### Extension libraries [BrazeNotificationService](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b2-rich-push-notifications) and [BrazePushStory](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b3-push-stories) are extension modules that provide additional functionality and should not be added directly to your main application target. Instead, you will need to create separate extension targets for each of these modules and import the Braze modules into their corresponding targets. | Library | Details | | -------------------------------- | ------------------------------------------------------------------------------------- | | `pod 'BrazeNotificationService'` | Notification service extension library providing support for rich push notifications. | | `pod 'BrazePushStory'` | Notification content extension library providing support for Push Stories. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Extension libraries" } {: .ws-td-nw-1} #### Step 1.3: Install the SDK To install the Braze SDK CocoaPod, navigate to the directory of your Xcode app project within your terminal and run the following command: ``` pod install ``` At this point, you should be able to open the new Xcode project workspace created by CocoaPods. Make sure to use this Xcode workspace instead of your Xcode project. ![A Braze Example folder expanded to show the new `BrazeExample.workspace`.](https://www.braze.com/docs/ja/ja/assets/img/braze_example_workspace.png?67ad8a74ccb61f01df9949a0a37af957) #### Updating the SDK using CocoaPods To update a CocoaPod, simply run the following command within your project directory: ``` pod update ``` #### Step 1.1: Download the Braze SDK Go to the [Braze SDK release page on GitHub](https://github.com/braze-inc/braze-swift-sdk/releases), then download `braze-swift-sdk-prebuilt.zip`. !["The Braze SDK release page on GitHub."](https://www.braze.com/docs/ja/ja/assets/img/swift/sdk_integration/download-braze-swift-sdk-prebuilt.png?0498d856a092a68779f1bd3945e685ca) #### Step 1.2: Choose your frameworks The Braze Swift SDK contains a variety of standalone XCFrameworks, which gives you the freedom to integrate the features you want—without needing to integrate them all. Reference the following table to choose your XCFrameworks: | Package | Required? | Description | | -------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `BrazeKit` | Yes | Main SDK library that provides support for analytics and push notifications. | | `BrazeLocation` | No | Location library that provides support for location analytics and geofence monitoring. | | `BrazeUI` | No | Braze-provided user interface library for in-app messages, Content Cards, and Banners. Import this library if you intend to use the default UI components. | | `BrazeNotificationService` | No | Notification service extension library that provides support for rich push notifications. Do not add this library directly to your main application target, instead [add the `BrazeNotificationService` library separately](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b2-rich-push-notifications). | | `BrazePushStory` | No | Notification content extension library that provides support for Push Stories. Do not add this library directly to your main application target, instead [add the `BrazePushStory` library separately](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b3-push-stories). | | `BrazeKitCompat` | No | Compatibility library containing all the `Appboy` and `ABK*` classes and methods that were available in the `Appboy-iOS-SDK` version 4.X.X. For usage details, refer to the minimal migration scenario in the [migration guide](https://braze-inc.github.io/braze-swift-sdk/documentation/braze/appboy-migration-guide/). | | `BrazeUICompat` | No | Compatibility library containing all the `ABK*` classes and methods that were available in the `AppboyUI` library from `Appboy-iOS-SDK` version 4.X.X. For usage details, refer to the minimal migration scenario in the [migration guide](https://braze-inc.github.io/braze-swift-sdk/documentation/braze/appboy-migration-guide/). | | `SDWebImage` | No | Dependency used only by `BrazeUICompat` in the minimal migration scenario. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Step 1.2: Choose your frameworks" } {: .ws-td-nw-1 .reset-td-br-1 .reset-td-br-2 aria-label="Step 1.2: Choose your frameworks" } #### Step 1.3: Prepare your files Decide whether you want to use **Static** or **Dynamic** XCFrameworks, then prepare your files: 1. Create a temporary directory for your XCFrameworks. 2. In `braze-swift-sdk-prebuilt`, open the `dynamic` directory and move `BrazeKit.xcframework` into your directory. Your directory should be similar to the following: ```bash temp_dir └── BrazeKit.xcframework ``` 3. Move each of your [chosen XCFrameworks](#swift_step-2-choose-your-frameworks) into your temporary directory. Your directory should be similar to the following: ```bash temp_dir ├── BrazeKit.xcframework ├── BrazeKitCompat.xcframework ├── BrazeLocation.xcframework └── SDWebImage.xcframework ``` #### Step 1.4: Integrate your frameworks Next, integrate the **Dynamic** or **Static** XCFrameworks you [prepared previously](#swift_step-3-prepare-your-files): In your Xcode project, select your build target, then **General**. Under **Frameworks, Libraries, and Embedded Content**, drag and drop the [files you prepared previously](#swift_step-3-prepare-your-files). !["An example Xcode project with each Braze library set to 'Embed & Sign.'"](https://www.braze.com/docs/ja/ja/assets/img/swift/sdk_integration/embed-and-sign.png?43e0687cf39aa5ba7d61add4e7cee300) **Note:** Starting with the Swift SDK 12.0.0, you should always select **Embed & Sign** for the Braze XCFrameworks for both the static and dynamic variants. This ensures that the frameworks resources are properly embedded in your app bundle. **Tip:** To enable GIF support, add `SDWebImage.xcframework`, located in either `braze-swift-sdk-prebuilt/static` or `braze-swift-sdk-prebuilt/dynamic`. #### Common errors for Objective-C projects If your Xcode project only contains Objective-C files, you may get "missing symbol" errors when you try to build your project. To fix these errors, open your project and add an empty Swift file to your file tree. This will force your build toolchain to embed [Swift Runtime](https://support.apple.com/kb/dl1998) and link to the appropriate frameworks during build time. ```bash FILE_NAME.swift ``` Replace `FILE_NAME` with any non-spaced string. Your file should look similar to the following: ```bash empty_swift_file.swift ``` ### Step 2: Set up delayed initialization (optional) You can choose to delay when the Braze Swift SDK is initialized, which is useful if your app needs to load a configuration or wait for user consent before starting the SDK. Delayed initialization makes sure Braze push notifications and push tokens received before SDK initialization are enqueued and processed once the SDK is initialized. To use delayed initialization, the minimum Braze SDK version is required: #### Step 2.1: Prepare for delayed initialization Call `Braze.prepareForDelayedInitialization()` as early as possible in your app's lifecycle, ideally in or before `application(_:didFinishLaunchingWithOptions:)`. This makes sure that push notifications received before the SDK is initialized are properly captured and processed later. **Note:** This only applies to push notifications from Braze. Other push notifications are handled normally by system delegates. ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Prepare the SDK for delayed initialization Braze.prepareForDelayedInitialization() // ... Additional non-Braze setup code return true } ``` ```swift @main struct MyApp: App { @UIApplicationDelegateAdaptor var appDelegate: AppDelegate var body: some Scene { WindowGroup { ContentView() } } } class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { // Prepare the SDK for delayed initialization Braze.prepareForDelayedInitialization() // ... Additional non-Braze setup code return true } } ``` ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Prepare the SDK for delayed initialization [Braze prepareForDelayedInitialization]; // ... Additional non-Braze setup code return YES; } ``` When using delayed initialization, push notification automation is implicitly enabled. You can [customize the push automation](#swift_step-23-customize-push-automation-optional) configuration by passing a `pushAutomation` parameter. #### Step 2.2: Configure push analytics behavior (optional) When delayed initialization is enabled, push analytics are queued by default. However, you can choose to explicitly queue or drop push analytics instead. ##### Explicitly queue To explicitly queue push analytics (default behavior), pass `.queue` to the `analyticsBehavior` parameter. Push analytics events that are queued prior to initialization will be processed and flushed to the server upon initialization. ```swift Braze.prepareForDelayedInitialization(analyticsBehavior: .queue) ``` ```objc [Braze prepareForDelayedInitializationWithAnalyticsBehavior:BRZPushEnqueueBehaviorQueue]; ``` ##### Drop To drop push analytics received before SDK initialization, pass `.drop` to the `analyticsBehavior` parameter. With this option, any push analytics event that occurs while the SDK is not initialized will be ignored. ```swift Braze.prepareForDelayedInitialization(analyticsBehavior: .drop) ``` ```objc [Braze prepareForDelayedInitializationWithAnalyticsBehavior:BRZPushEnqueueBehaviorDrop]; ``` #### Step 2.3: Customize push automation (optional) You can customize the push automation configuration by passing a `pushAutomation` parameter. By default, all automation features are enabled except `requestAuthorizationAtLaunch`. ```swift // Enable all push automation featuresBraze.prepareForDelayedInitialization(pushAutomation: true) // Or customize specific automation options let automation = Braze.Configuration.Push.Automation() automation.automaticSetup = true automation.requestAuthorizationAtLaunch = false Braze.prepareForDelayedInitialization(pushAutomation: automation) ``` ```objc // Enable all push automation features [Braze prepareForDelayedInitializationWithPushAutomation:[[BRZConfigurationPushAutomation alloc] initWithAutomationEnabled:YES]]; // Or customize specific automation options BRZConfigurationPushAutomation *automation = [[BRZConfigurationPushAutomation alloc] init]; automation.automaticSetup = YES; automation.requestAuthorizationAtLaunch = NO; [Braze prepareForDelayedInitializationWithPushAutomation:automation analyticsBehavior:BRZPushEnqueueBehaviorQueue]; ``` #### Step 2.4: Initialize the SDK After your chosen delay period (for example, after fetching configuration from a server or after user consent), initialize the SDK as normal: ```swift func initializeBraze() { let configuration = Braze.Configuration(apiKey: "YOUR-API-KEY", endpoint: "YOUR-ENDPOINT") // Enable push automation to match the delayed initialization configuration configuration.push.automation = true let braze = Braze(configuration: configuration) // Store the Braze instance for later use AppDelegate.braze = braze } ``` ```objc - (void)initializeBraze { BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:@"YOUR-API-KEY" endpoint:@"YOUR-ENDPOINT"]; // Enable push automation to match the delayed initialization configuration configuration.push.automation = [[BRZConfigurationPushAutomation alloc] initWithAutomationEnabled:YES]; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; // Store the Braze instance for later use AppDelegate.braze = braze; } ``` **Note:** When the SDK is initialized, all queued push notifications, push tokens, and deep links are automatically processed. ### Step 3: Update your app delegate **Important:** The following assumes you've already added an `AppDelegate` to your project (which are not generated by default) and you are not using the delayed initialization feature. If you don't plan on using an `AppDelegate`, be sure to initialize the Braze SDK as early as possible, like during the app's launch. If you are using the delayed initialization feature, refer to [Step 2.4](#swift_step-24-initialize-the-sdk) for initializing the SDK and ignore this step. Add the following line of code to your `AppDelegate.swift` file to import the features included in the Braze Swift SDK: ```swift import BrazeKit ``` Next, add a static property to your `AppDelegate` class to keep a strong reference to the Braze instance throughout your application's lifetime: ```swift class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil } ``` The SDK requires your application to retain a strong reference to the Braze instance throughout its usage. To prevent any unexpected side effects, ensure that you have fully captured that reference before accessing or modifying any properties or methods on the Braze instance. Finally, in `AppDelegate.swift`, add the following snippet to your `application:didFinishLaunchingWithOptions:` method: ```swift let configuration = Braze.Configuration( apiKey: "YOUR-APP-IDENTIFIER-API-KEY", endpoint: "YOUR-BRAZE-ENDPOINT" ) let braze = Braze(configuration: configuration) AppDelegate.braze = braze ``` Update `YOUR-APP-IDENTIFIER-API-KEY` and `YOUR-BRAZE-ENDPOINT` with the correct value from your **App Settings** page. Check out our [API identifier types](https://www.braze.com/docs/ja/ja/api/identifier_types/?tab=app%20ids) for more information on where to find your app identifier API key. Add the following line of code to your `AppDelegate.m` file: ```objc @import BrazeKit; ``` Next, add a static variable to your `AppDelegate.m` file to keep a reference to the Braze instance throughout your application's lifetime: ```objc static Braze *_braze; @implementation AppDelegate + (Braze *)braze { return _braze; } + (void)setBraze:(Braze *)braze { _braze = braze; } @end ``` The SDK requires your application to retain a strong reference to the Braze instance throughout its usage. To prevent any unexpected side effects, ensure that you have fully captured that reference before accessing or modifying any properties or methods on the Braze instance. Finally, within your `AppDelegate.m` file, add the following snippet within your `application:didFinishLaunchingWithOptions:` method: ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:"YOUR-APP-IDENTIFIER-API-KEY" endpoint:"YOUR-BRAZE-ENDPOINT"]; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; AppDelegate.braze = braze; ``` Update `YOUR-APP-IDENTIFIER-API-KEY` and `YOUR-BRAZE-ENDPOINT` with the correct value from your **Manage Settings** page. Check out our [API documentation](https://www.braze.com/docs/ja/ja/api/api_key/#the-app-identifier-api-key) for more information on where to find your app identifier API key. ## Optional configurations ### Logging For a centralized overview across all platforms, see [Verbose logging](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging). To learn how to interpret log output, see [Reading verbose logs](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/reading_verbose_logs). #### Log levels The default log level for the Braze Swift SDK is `.error`—it's also the minimum supported level when logs are enabled. These are the full list of log levels: | Swift | Objective-C | Description | | ----------- | ------------------------ | ------------------------------------------------------------ | | `.debug` | `BRZLoggerLevelDebug` | Log debugging information + `.info` + `.error`. | | `.info` | `BRZLoggerLevelInfo` | Log general SDK information (user changes, etc.) + `.error`. | | `.error` | `BRZLoggerLevelError` | Log errors. | | `.disabled` | `BRZLoggerLevelDisabled` | No logging occurs. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Log levels" } {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Log levels" } #### Setting the log level You can assign the log level at runtime in your `Braze.Configuration` object. For complete usage details, see [`Braze.Configuration.Logger`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/logger-swift.class). ```swift let configuration = Braze.Configuration( apiKey: "", endpoint: "" ) // Enable logging of general SDK information (such as user changes, etc.) configuration.logger.level = .info let braze = Braze(configuration: configuration) ``` ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:self.APIKey endpoint:self.apiEndpoint]; // Enable logging of general SDK information (such as user changes, etc.) [configuration.logger setLevel:BRZLoggerLevelInfo]; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; ``` ## Integrating the Cordova SDK ### Prerequisites Before you start, verify your environment is supported by the [latest Braze Cordova SDK version](https://github.com/braze-inc/braze-cordova-sdk?tab=readme-ov-file#minimum-version-requirements). ### Step 1: Add the SDK to your project **Warning:** Only add the Braze Cordova SDK using the methods below. Do not attempt to install using other methods as it could lead to a security breach. If you're on Cordova 6 or later, you can add the SDK directly from GitHub. Alternatively, you can download a ZIP of the [GitHub repository](https://github.com/braze-inc/braze-cordova-sdk) and add the SDK manually. If you don't plan on using location collection and geofences, use the `master` branch from GitHub. ```bash cordova plugin add https://github.com/braze-inc/braze-cordova-sdk#master ``` If you plan on using location collection and geofences, use the `geofence-branch` from GitHub. ```bash cordova plugin add https://github.com/braze-inc/braze-cordova-sdk#geofence-branch ``` **Tip:** You can switch between `master` and `geofence-branch` at anytime by repeating this step. ### Step 2: Configure your project Next, adding the following preferences to the `platform` element in your project's `config.xml` file. ```xml ``` ```xml ``` Replace the following: | Value | Description | | --------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | `BRAZE_API_KEY` | Your [Braze REST API key](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/api_settings_tab/#rest-api-keys). | | `CUSTOM_API_ENDPOINT` | A custom API endpoint. This endpoint is used to route your Braze instance data to the correct App Group in your Braze dashboard. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Step 2: Configure your project" } The `platform` element in your `config.xml` file should be similar to the following: ```xml ``` ```xml ``` ## Platform-specific syntax The following section covers the platform-specific syntax when using Cordova with iOS or Android. ### Integers Integer preferences are read as string representations, like in the following example: ```xml ``` Due to how the Cordova 8.0.0+ framework handles preferences, integer-only preferences (such as sender IDs) must be set to strings prepended with `str_`, like in the following example: ```xml ``` ### Booleans Boolean preferences are read by the SDK using `YES` and `NO` keywords as a string representation, like in the following example: ```xml ``` Boolean preferences are read by the SDK using `true` and `false` keywords as a string representation, like in the following example: ```xml ``` ## Optional configurations {#optional} You can add any of the following preferences to the `platform` element in your project's `config.xml` file: | Method | Description | | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `ios_api_key` | Sets the API key for your application. | | `ios_api_endpoint` | Sets the [SDK endpoint](https://www.braze.com/docs/ja/ja/api/basics/#endpoints) for your application. | | `ios_disable_automatic_push_registration` | Sets whether automatic push registration should be disabled. | | `ios_disable_automatic_push_handling` | Sets whether automatic push handling should be disabled. | | `ios_enable_idfa_automatic_collection` | Sets whether the Braze SDK should automatically collect the IDFA information. For more information, see [the Braze IDFA method documentation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/set(identifierforadvertiser:)/). | | `enable_location_collection` | Sets whether the automatic location collection is enabled (if the user permits). The `geofence-branch` | | `geofences_enabled` | Sets whether geofences are enabled. | | `ios_session_timeout` | Sets the Braze session timeout for your application in seconds. Defaults to 10 seconds. | | `sdk_authentication_enabled` | Sets whether to enable the [SDK Authentication](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/sdk_authentication#sdk-authentication) feature. | | `display_foreground_push_notifications` | Sets whether push notifications should be displayed while the application is in the foreground. | | `ios_disable_un_authorization_option_provisional` | Sets whether `UNAuthorizationOptionProvisional` should be disabled. | | `trigger_action_minimum_time_interval_seconds` | Sets the minimum time interval in seconds between triggers. Defaults to 30 seconds. | | `ios_push_app_group` | Sets the app group ID for iOS push extensions. | | `ios_forward_universal_links` | Sets whether the SDK automatically recognizes and forwards universal links to the system methods. Required for deep links from push notifications to work on iOS. Defaults to disabled. | | `ios_log_level` | Sets the minimum logging level for `Braze.Configuration.Logger`. | | `ios_use_uuid_as_device_id` | Sets if a randomly generated UUID should be used as the device ID. | | `ios_flush_interval_seconds` | Sets the interval in seconds between automatic data flushes. Defaults to 10 seconds. | | `ios_use_automatic_request_policy` | Sets whether the request policy for `Braze.Configuration.Api` should be automatic or manual. | | `should_opt_in_when_push_authorized` | Sets if a user’s notification subscription state should automatically be set to `optedIn` when push permissions are authorized. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Optional configurations #optional" } **Tip:** For more detailed information, see [GitHub: Braze iOS Cordova plugin](https://github.com/braze-inc/braze-cordova-sdk/blob/master/src/ios/BrazePlugin.m). | Method | Description | | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `android_api_key` | Sets the API key for your application. | | `android_api_endpoint` | Sets the [SDK endpoint](https://www.braze.com/docs/ja/ja/api/basics/#endpoints) for your application. | | `android_small_notification_icon` | Sets the notification small icon. | | `android_large_notification_icon` | Sets the notification large icon. | | `android_notification_accent_color` | Sets the notification accent color using a hexadecimal representation. | | `android_default_session_timeout` | Sets the Braze session timeout for your application in seconds. Defaults to 10 seconds. | | `android_handle_push_deep_links_automatically` | Sets whether the Braze SDK automatically handles push deep links. Required for deep links from push notifications to work on Android. Defaults to disabled. | | `android_log_level` | Sets the log level for your application. The default log level is 4 and will minimally log info. To enable verbose logging for debugging, use log level 2. | | `firebase_cloud_messaging_registration_enabled` | Sets whether to use Firebase Cloud Messaging for push notifications. | | `android_fcm_sender_id` | Sets the Firebase Cloud Messaging sender ID. | | `enable_location_collection` | Sets whether the automatic location collection is enabled (if the user permits). | | `geofences_enabled` | Sets whether geofences are enabled. | | `android_disable_auto_session_tracking` | Disable the Android Cordova plugin from automatically tracking sessions. For more information, see [Disabling automatic session tracking](#cordova_disable-automatic-session-tracking) | | `sdk_authentication_enabled` | Sets whether to enable the [SDK Authentication](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/sdk_authentication#sdk-authentication) feature. | | `trigger_action_minimum_time_interval_seconds` | Sets the minimum time interval in seconds between triggers. Defaults to 30 seconds. | | `is_session_start_based_timeout_enabled` | Sets whether the session timeout behavior to be based either on session start or session end events. | | `default_notification_channel_name` | Sets the user-facing name as seen via `NotificationChannel.getName` for the Braze default `NotificationChannel`. | | `default_notification_channel_description` | Sets the user-facing description as seen via `NotificationChannel.getDescription` for the Braze default `NotificationChannel`. | | `does_push_story_dismiss_on_click` | Sets whether a Push Story is automatically dismissed when clicked. | | `is_fallback_firebase_messaging_service_enabled` | Sets whether the use of a fallback Firebase Cloud Messaging Service is enabled. | | `fallback_firebase_messaging_service_classpath` | Sets the classpath for the fallback Firebase Cloud Messaging Service. | | `is_content_cards_unread_visual_indicator_enabled` | Sets whether the Content Cards unread visual indication bar is enabled. | | `is_firebase_messaging_service_on_new_token_registration_enabled` | Sets whether the Braze SDK will automatically register tokens in `com.google.firebase.messaging.FirebaseMessagingService.onNewToken`. | | `is_push_deep_link_back_stack_activity_enabled` | Sets whether Braze will add an activity to the back stack when automatically following deep links for push. | | `push_deep_link_back_stack_activity_class_name` | Sets the activity that Braze will add to the back stack when automatically following deep links for push. | | `should_opt_in_when_push_authorized` | Sets if Braze should automatically opt-in the user when push is authorized. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Optional configurations #optional" } **Tip:** For more detailed information, see [GitHub: Braze Android Cordova plugin](https://github.com/braze-inc/braze-cordova-sdk/blob/master/src/android/BrazePlugin.kt). The following is an example `config.xml` file with additional configurations: ```xml ``` ```xml ``` ## Disabling automatic session tracking (Android only) {#disable-automatic-session-tracking} By default, the Android Cordova plugin automatically tracks sessions. To disable automatic session tracking, add the following preference to the `platform` element in your project's `config.xml` file: ```xml ``` To start tracking sessions again, call `BrazePlugin.startSessionTracking()`. Keep in mind, only sessions started after the next `Activity.onStart()` will be tracked. ## About the Flutter Braze SDK After you integrate the Braze Flutter SDK on Android and iOS, you'll be able to use the Braze API within your [Flutter apps](https://flutter.dev/) written in Dart. This plugin provides basic analytics functionality and lets you integrate in-app messages and Content Cards for both iOS and Android with a single codebase. ## Integrating the Flutter SDK ### Prerequisites Before you integrate the Braze Flutter SDK, you'll need to complete the following: | Prerequisite | Description | | --- | --- | | Braze API app identifier | To locate your app's identifier, go to **Settings** > **APIs and Identifiers** > **App Identifiers**. For more information see, [API Identifier Types](https://www.braze.com/docs/ja/ja/api/identifier_types/#app-identifier).| | Braze SDK endpoint | Your SDK endpoint URL (for example, `sdk..braze.com`). Your endpoint will depend on the [Braze URL for your instance](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/basics/#endpoints).| | Flutter SDK | Install the official [Flutter SDK](https://docs.flutter.dev/get-started/install) and ensure it meets the Braze Flutter SDK's [minimum supported version](https://github.com/braze-inc/braze-flutter-sdk#requirements). | {: .reset-td-br-1 .reset-td-br-2 aria-label="Prerequisites" } ### Step 1: Integrate the Braze library Add the Braze Flutter SDK package from the command line. This will add the appropriate line to your `pubspec.yaml`. ```bash flutter pub add braze_plugin ``` ### Step 2: Complete native SDK setup #### 2.1 Set up Android ##### Provide credentials at compile time Create a `braze.xml` file in your project's `android/res/values` folder. The API key and endpoint are provided at runtime from Dart, so they are not required in this file. To enable delayed initialization, add `com_braze_enable_delayed_initialization` to the file: ```xml true ``` ##### Provide credentials at runtime Alternatively, you can enable delayed initialization programmatically in your `MainActivity.kt`: ```kotlin import com.braze.Braze class MainActivity : FlutterActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Braze.enableDelayedInitialization(context = this) } } ``` Add the required permissions to your `AndroidManifest.xml` file: ```xml ``` #### 2.2 Set up iOS Within your existing `application(_:didFinishLaunchingWithOptions:)` method, add a call to `BrazePlugin.configure(_:postInitialization:)` to store your configuration. The Braze instance is created later when `initialize()` is called from Dart. The API key and endpoint are not set here. Add the following code to your `AppDelegate.swift`: ```swift import BrazeKit import braze_plugin // ... override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil ) -> Bool { // ... your existing didFinishLaunchingWithOptions setup ... BrazePlugin.configure( { configuration in configuration.logger.level = .info // Set other non-API-key configurations here, such as: // configuration.push.automation = true // configuration.sessionTimeout = 60 }, postInitialization: { braze in // Optional: Customize the Braze instance after creation. // For example, set a custom in-app message presenter: // let customPresenter = CustomInAppMessagePresenter() // braze.inAppMessagePresenter = customPresenter } ) return true } ``` Add the following code to your `AppDelegate.m`: ```objc @import BrazeKit; @import braze_plugin; // ... - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [BrazePlugin configure:^(BRZConfiguration *configuration) { configuration.logger.level = BRZLoggerLevelInfo; // Set other non-API-key configurations here, such as: // configuration.push.automation = ... // configuration.sessionTimeout = 60; } postInitialization:^(Braze *braze) { // Optional: customize the Braze instance after creation. }]; return YES; } ``` **Important:** `BrazePlugin.configure()` only stores your configuration. No Braze instance exists until `initialize()` is called from Dart, so do not call any Braze SDK methods in the AppDelegate after `configure()`. #### 2.1 Set up Android To connect to Braze servers, create a `braze.xml` file in your project's `android/res/values` folder. Paste the following code and replace the API identifier key and endpoint with your values: ```xml YOUR_APP_IDENTIFIER_API_KEY YOUR_CUSTOM_ENDPOINT_OR_CLUSTER ``` Add the required permissions to your `AndroidManifest.xml` file: ```xml ``` #### 2.2 Set up iOS Add the Braze SDK imports at the top of the `AppDelegate.swift` file: ```swift import BrazeKit import braze_plugin ``` In the same file, create the Braze configuration object in the `application(_:didFinishLaunchingWithOptions:)` method and replace the API key and endpoint with your app's values. Then, create the Braze instance using the configuration, and create a static property on the `AppDelegate` for easy access: ```swift static var braze: Braze? = nil override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil ) -> Bool { // Setup Braze let configuration = Braze.Configuration( apiKey: "", endpoint: "" ) // - Enable logging or customize configuration here configuration.logger.level = .info let braze = BrazePlugin.initBraze(configuration) AppDelegate.braze = braze return true } ``` Import the Braze SDK at the top of the `AppDelegate.m` file: ```objc @import BrazeKit; @import braze_plugin; ``` In the same file, create the Braze configuration object in the `application:didFinishLaunchingWithOptions:` method and replace the API key and endpoint with your app's values. Then, create the Braze instance using the configuration, and create a static property on the `AppDelegate` for easy access: ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Setup Braze BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:@"" endpoint:@""]; // - Enable logging or customize configuration here configuration.logger.level = BRZLoggerLevelInfo; Braze *braze = [BrazePlugin initBraze:configuration]; AppDelegate.braze = braze; [self.window makeKeyAndVisible]; return YES; } #pragma mark - AppDelegate.braze static Braze *_braze = nil; + (Braze *)braze { return _braze; } + (void)setBraze:(Braze *)braze { _braze = braze; } ``` ### Step 3: Set up the plugin Import the plugin and create a single instance of `BrazePlugin`: ```dart import 'package:braze_plugin/braze_plugin.dart'; final BrazePlugin braze = BrazePlugin(); ``` Then call `initialize()` with your app identifier API key and SDK endpoint to create the Braze instance. See the options below for where to call this method in your app. #### Standard initialization To initialize the SDK when your app starts, call `initialize()` in `initState()`: ```dart @override void initState() { super.initState(); braze.initialize("", ""); } ``` #### Delayed initialization To defer SDK initialization until a later point in the session — for example, after the user grants consent or completes login — call `initialize()` when you're ready: ```dart // ... void onUserConsent() { braze.initialize("", ""); } ``` **Warning:** Push notifications and deep links received before `initialize()` is called are not processed on iOS. On Android, deep links from push notifications do not resolve while the SDK is waiting to be initialized. If your app relies on push or deep links at launch, use [standard initialization](#standard-initialization) instead. #### Platform-specific API keys Since your Android and iOS apps use different API keys, use platform detection: ```dart import 'dart:io' show Platform; if (Platform.isAndroid) { braze.initialize("", ""); } else if (Platform.isIOS) { braze.initialize("", ""); } ``` #### Re-initialization You can call `initialize()` multiple times to re-initialize the SDK with a different API key and endpoint mid-session. Each call tears down the previous Braze instance and creates a new one. **Important:** To avoid undefined behaviors, only allocate and use a single instance of the `BrazePlugin` in your Dart code. All SDK method calls made before `initialize()` are ignored on iOS, so call `initialize()` before using any other Braze methods. To import the plugin into your Dart code, use the following: ```dart import 'package:braze_plugin/braze_plugin.dart'; ``` Then, initialize an instance of the Braze plugin by calling `new BrazePlugin()` like in [our sample app](https://github.com/braze-inc/braze-flutter-sdk/blob/master/example/lib/main.dart). **Important:** To avoid undefined behaviors, only allocate and use a single instance of the `BrazePlugin` in your Dart code. ## Testing the integration You can verify that the SDK is integrated by checking session statistics in the dashboard. If you run your application on either platform, you should see a new session in the dashboard (in the **Overview** section). Open a session for a particular user by calling the following code in your app. ```dart BrazePlugin braze = BrazePlugin(); braze.initialize("", ""); braze.changeUser("{some-user-id}"); ``` ```dart BrazePlugin braze = BrazePlugin(); braze.changeUser("{some-user-id}"); ``` Search for the user with `{some-user-id}` in the dashboard under **Audience** > **Search Users**. There, you can verify that session and device data have been logged. ## About the React Native Braze SDK Integrating the React Native Braze SDK provides basic analytics functionality and lets you integrate in-app messages and Content Cards for both iOS and Android with one codebase. ## New Architecture compatibility The following minimum SDK version is compatible with all apps using [React Native's New Architecture](https://reactnative.dev/docs/the-new-architecture/landing-page): Starting with SDK version 6.0.0, Braze uses a React Native Turbo Module, which is compatible with both the New Architecture and legacy bridge architecture. This means no additional setup is required. **Warning:** If your iOS app conforms to `RCTAppDelegate` and follows our previous `AppDelegate` setup, review the samples in [Complete native setup](#reactnative_step-2-complete-native-setup) to prevent crashes when subscribing to events in the Turbo Module. ## React and React Native version requirements Braze doesn't publish separate minimum React versions beyond what the React Native SDK supports. To integrate the SDK, use React Native version 0.71 or later. For the full list of supported React Native versions, see the [React Native SDK GitHub repository](https://github.com/braze-inc/braze-react-native-sdk?tab=readme-ov-file#version-support). When you upgrade React, React Native, or the Braze SDK, review the SDK [CHANGELOG](https://github.com/braze-inc/braze-react-native-sdk/blob/master/CHANGELOG.md) for breaking changes before you deploy. ## Integrating the React Native SDK ### Prerequisites For supported React Native versions and upgrade guidance, see [React and React Native version requirements](#react-and-react-native-version-requirements). ### Step 1: Integrate the Braze library ```bash npm install @braze/react-native-sdk ``` ```bash yarn add @braze/react-native-sdk ``` ### Step 2: Complete native setup If your app uses Expo, see [Using the Expo plugin](#reactnative-using-the-expo-plugin). If your app uses pure React Native, see [Using React Native CLI](#reactnative-using-react-native-cli). Choose one setup method in each version tab: Expo plugin or React Native CLI. #### Method 1: Using the Expo plugin {#reactnative-using-the-expo-plugin} ##### 2.1 Install the Braze Expo plugin Ensure that your version of the Braze Expo plugin is at least 4.1.0. For the full list of supported versions, see the [Braze Expo plugin repository](https://github.com/braze-inc/braze-expo-plugin?tab=readme-ov-file#version-support). The following code snippet shows the command to install the Braze Expo plugin: ```bash npx expo install @braze/expo-plugin ``` ##### 2.2 Add the plugin to your app.json In your `app.json`, add the Braze Expo plugin. The API key and endpoint are no longer set here. Provide them at runtime through `Braze.initialize()` from JavaScript. Add the following optional configuration parameters based on your implementation needs: | Method | Type | Description | | --------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enableBrazeIosPush` | boolean | iOS only. Whether to use Braze to handle push notifications on iOS. | | `enableFirebaseCloudMessaging` | boolean | Android only. Whether to use Firebase Cloud Messaging for push notifications. | | `firebaseCloudMessagingSenderId` | string | Android only. Your Firebase Cloud Messaging sender ID. | | `sessionTimeout` | integer | The Braze session timeout for your application in seconds. | | `enableSdkAuthentication` | boolean | Whether to enable the [SDK Authentication](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/sdk_authentication#sdk-authentication) feature. | | `logLevel` | integer | The log level for your application. The default log level is 8 and minimally logs info. To enable verbose logging for debugging, use log level 0. | | `minimumTriggerIntervalInSeconds` | integer | The minimum time interval in seconds between triggers. Defaults to 30 seconds. | | `enableAutomaticLocationCollection` | boolean | Whether automatic location collection is enabled (if the user permits). | | `enableGeofence` | boolean | Whether geofences are enabled. | | `enableAutomaticGeofenceRequests` | boolean | Whether geofence requests should be made automatically. | | `dismissModalOnOutsideTap` | boolean | iOS only. Whether a modal in-app message is dismissed when the user clicks outside of the in-app message. | | `androidHandlePushDeepLinksAutomatically` | boolean | Android only. Whether the Braze SDK should automatically handle push deep links. | | `androidPushNotificationHtmlRenderingEnabled` | boolean | Android only. Sets whether the text content in a push notification should be interpreted and rendered as HTML using `android.text.Html.fromHtml`. | | `androidNotificationAccentColor` | string | Android only. Sets the Android notification accent color. | | `androidNotificationLargeIcon` | string | Android only. Sets the Android notification large icon. | | `androidNotificationSmallIcon` | string | Android only. Sets the Android notification small icon. | | `iosRequestPushPermissionsAutomatically` | boolean | iOS only. Whether the user should automatically be prompted for push permissions on app launch. | | `enableBrazeIosRichPush` | boolean | iOS only. Whether to enable rich push features for iOS. | | `enableBrazeIosPushStories` | boolean | iOS only. Whether to enable Braze Push Stories for iOS. | | `iosPushStoryAppGroup` | string | iOS only. The app group used for iOS Push Stories. | | `iosUseUUIDAsDeviceId` | boolean | iOS only. Whether the device ID uses a randomly generated UUID. | | `iosForwardUniversalLinks` | boolean | iOS only. Specifies if the SDK should automatically recognize and forward universal links to the system methods (default: `false`). | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="2.2 Add the plugin to your app.json" } The following code snippet shows an example `app.json` configuration: ```json { "expo": { "plugins": [ [ "@braze/expo-plugin", { "sessionTimeout": 60, "enableGeofence": false, "enableBrazeIosPush": false, "enableFirebaseCloudMessaging": false, "firebaseCloudMessagingSenderId": "YOUR-FCM-SENDER-ID", "androidHandlePushDeepLinksAutomatically": true, "enableSdkAuthentication": false, "logLevel": 0, "minimumTriggerIntervalInSeconds": 0, "enableAutomaticLocationCollection": false, "enableAutomaticGeofenceRequests": false, "dismissModalOnOutsideTap": true, "androidPushNotificationHtmlRenderingEnabled": true, "androidNotificationAccentColor": "#ff3344", "androidNotificationLargeIcon": "@drawable/custom_app_large_icon", "androidNotificationSmallIcon": "@drawable/custom_app_small_icon", "iosRequestPushPermissionsAutomatically": false, "enableBrazeIosPushStories": true, "iosPushStoryAppGroup": "group.com.example.myapp.PushStories", "iosForwardUniversalLinks": false } ] ] } } ``` ###### Configuring Android push notification icons {#android-push-icons} When using `androidNotificationLargeIcon` and `androidNotificationSmallIcon`, follow these best practices for proper icon display: **Icon placement and format** To use custom push notification icons with the Braze Expo plugin: 1. Create your icon files following the Icon requirements listed below. 2. Place them in your project's Android native directories at `android/app/src/main/res/drawable-/`. For example, use `android/app/src/main/res/drawable-mdpi/` and `android/app/src/main/res/drawable-hdpi/`. 3. Alternatively, if you're managing assets in your React Native directory, you can use Expo's [app.json icon configuration](https://docs.expo.dev/versions/latest/config/app/#icon) or create an [Expo config plugin](https://docs.expo.dev/config-plugins/introduction/) to copy the icons to the Android drawable folders during prebuild. The Braze Expo plugin references these icons using Android's drawable resource system. **Icon requirements** - **Small icon:** Must be a white silhouette on a transparent background (this is an Android platform requirement) - **Large icon:** Can be a full-color image. - **Format:** PNG format is recommended. - **Naming:** Use lowercase letters, numbers, and underscores only (for example, `my_large_icon.png`) **Configuration in app.json** The following code snippet shows how to reference Android notification icons in `app.json` using the `@drawable/` prefix: ```json { "expo": { "plugins": [ [ "@braze/expo-plugin", { "androidNotificationLargeIcon": "@drawable/large_icon", "androidNotificationSmallIcon": "@drawable/small_icon" } ] ] } } ``` **Important:** Do not use relative file paths (such as `src/assets/images/icon.png`) or include the file extension when referencing icons. The Expo plugin requires the `@drawable/` prefix to properly locate the icons in the Android native folders after the prebuild process. **How it works** The Braze Expo plugin references your icon files from the Android `drawable` directories. When you run `npx expo prebuild`, Expo generates the native Android project structure. Your icons must be present in the Android `drawable` folders (either placed manually or copied through a config plugin) before the build process. The plugin then configures the Braze SDK to use these drawable resources by their names (without path or extension), which is why the `@drawable/` prefix is required in your configuration. For more information on Android notification icons, see [Android's notification icon guidelines](https://developer.android.com/develop/ui/views/notifications#icon). ##### 2.3 Build and run your application Prebuilding your application generates the native files necessary for the Braze Expo plugin to work. The following code snippet shows the command to prebuild your application: ```bash npx expo prebuild ``` Run your application as specified in the [Expo docs](https://docs.expo.dev/workflow/customizing/). If you make changes to the configuration options, prebuild and run the application again. #### Method 2: Using React Native CLI {#reactnative-using-react-native-cli} ##### Set up Android **2.1 Add the Kotlin Gradle plugin** The following code snippet shows how to add the Kotlin Gradle plugin in your top-level project `build.gradle` under `buildscript` > `dependencies`: ```groovy buildscript { dependencies { ... // Choose your Kotlin version classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10") } } ``` This adds Kotlin to your project. **2.2 Configure the Braze SDK** Create a `braze.xml` file in your project's `res/values` folder. The API key and endpoint are provided at runtime from JavaScript, so they are not required in this file. The following code snippet shows how to enable delayed initialization with `com_braze_enable_delayed_initialization`: ```xml true ``` **Note:** You can still add other native configuration values to `braze.xml` (such as push, session timeout, and logging settings). These are applied automatically when `Braze.initialize()` is called from JavaScript. The following code snippet shows the required permissions for your `AndroidManifest.xml` file: ```xml ``` **Tip:** On Braze Android SDK version 12.2.0 or later, you can automatically pull in the android-sdk-location library by setting `importBrazeLocationLibrary=true` in your `gradle.properties` file. **2.3 Implement user session tracking** The calls to `openSession()` and `closeSession()` are handled automatically. The following code snippet shows what to add to the `onCreate()` method of your `MainApplication` class: ```java import com.braze.BrazeActivityLifecycleCallbackListener; @Override public void onCreate() { super.onCreate(); ... registerActivityLifecycleCallbacks(new BrazeActivityLifecycleCallbackListener()); } ``` ```kotlin import com.braze.BrazeActivityLifecycleCallbackListener override fun onCreate() { super.onCreate() ... registerActivityLifecycleCallbacks(BrazeActivityLifecycleCallbackListener()) } ``` **2.4 Handle intent updates** If your MainActivity has `android:launchMode` set to `singleTask`, the following code snippet shows what to add to your `MainActivity` class: ```java @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); } ``` ```kotlin override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) } ``` ##### Set up iOS **2.5 (Optional) Configure Podfile for dynamic XCFrameworks** To import certain Braze libraries, such as BrazeUI, into an Objective-C++ file, you must use the `#import` syntax. Starting in version `7.4.0` of the Braze Swift SDK, binaries have an [optional distribution channel as dynamic XCFrameworks](https://github.com/braze-inc/braze-swift-sdk-prebuilt-dynamic), which are compatible with this syntax. If you'd like to use this distribution channel, manually override the CocoaPods source locations in your Podfile. Reference the sample below and replace `{your-version}` with the relevant version you wish to import: ```ruby pod 'BrazeKit', :podspec => 'https://raw.githubusercontent.com/braze-inc/braze-swift-sdk-prebuilt-dynamic/{your-version}/BrazeKit.podspec' pod 'BrazeUI', :podspec => 'https://raw.githubusercontent.com/braze-inc/braze-swift-sdk-prebuilt-dynamic/{your-version}/BrazeUI.podspec' pod 'BrazeLocation', :podspec => 'https://raw.githubusercontent.com/braze-inc/braze-swift-sdk-prebuilt-dynamic/{your-version}/BrazeLocation.podspec' ``` **2.6 Install pods** Since React Native automatically links the libraries to the native platform, you can install the SDK with the help of CocoaPods. The following code snippet shows how to install pods from the root folder of the project: ```bash # To install using the React Native New Architecture cd ios && pod install # To install using the React Native legacy architecture cd ios && RCT_NEW_ARCH_ENABLED=0 pod install ``` **2.7 Configure the Braze SDK** Use `BrazeReactInitializer.configure` in your `AppDelegate` to register native configuration. The closures you provide are stored and applied later when `Braze.initialize(apiKey, endpoint)` is called from JavaScript. The following code snippet shows how to import the Braze SDK at the top of the `AppDelegate.swift` file: ```swift import BrazeKit import braze_react_native_sdk ``` In the `application(_:didFinishLaunchingWithOptions:)` method, register your native configuration using `BrazeReactInitializer.configure`. Do not set the API key or endpoint here. They are provided from JavaScript through `Braze.initialize()`. - **`configure` closure**: Receives a `Braze.Configuration` and lets you set native configuration properties (logging, push, sessions, and more). - **`postInitialization` closure** _(optional)_: Receives the live `Braze` instance after creation, for setup that requires the instance (for example, storing a reference or setting delegates). The following code snippet shows an example `AppDelegate.swift` implementation that uses `BrazeReactInitializer.configure`: ```swift @main class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { BrazeReactInitializer.configure { configuration in configuration.logger.level = .info configuration.push.automation = true } postInitialization: { braze in AppDelegate.braze = braze } // ... React Native setup return true } } ``` The following code snippet shows how to import the Braze SDK at the top of the `AppDelegate.m` file: ```objc @import BrazeKit; @import braze_react_native_sdk; ``` In the `application:didFinishLaunchingWithOptions:` method, register your native configuration using `BrazeReactInitializer`. Do not set the API key or endpoint here. They are provided from JavaScript through `Braze.initialize()`. The following code snippet shows an example `AppDelegate.m` implementation that uses `BrazeReactInitializer`: ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [BrazeReactInitializer configure:^(BRZConfiguration *configuration) { configuration.logger.level = BRZLoggerLevelInfo; configuration.push.automation = [[BRZConfigurationPushAutomation alloc] initWithAutomationEnabled:YES]; } postInitialization:^(Braze *braze) { // Store the Braze instance for later use. }]; /* Other configuration */ return YES; } ``` **Important:** `BrazeReactInitializer.configure()` only stores your configuration. No Braze instance exists until `Braze.initialize()` is called from JavaScript, so do not call any Braze SDK methods in the AppDelegate after `configure()`. When you call `Braze.initialize()` again, the same `configure` and `postInitialization` blocks are applied to the new Braze instance. #### Method 1: Using the Expo plugin ##### Step 2.1: Install the Braze Expo plugin Ensure that your version of the Braze React Native SDK is at least 1.37.0. For the full list of supported versions, see the [Braze React Native repository](https://github.com/braze-inc/braze-react-native-sdk?tab=readme-ov-file#version-support). The following code snippet shows the command to install the Braze Expo plugin: ```bash npx expo install @braze/expo-plugin ``` ##### Step 2.2: Add the plugin to your app.json In your `app.json`, add the Braze Expo plugin. You can provide the following configuration options: | Method | Type | Description | | --------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `androidApiKey` | string | Required. The [API key](https://www.braze.com/docs/ja/ja/api/identifier_types/) for your Android application, located in your Braze dashboard under **Manage Settings**. | | `iosApiKey` | string | Required. The [API key](https://www.braze.com/docs/ja/ja/api/identifier_types/) for your iOS application, located in your Braze dashboard under **Manage Settings**. | | `baseUrl` | string | Required. The [SDK endpoint](https://www.braze.com/docs/ja/ja/api/basics/#endpoints) for your application, located in your Braze dashboard under **Manage Settings**. | | `enableBrazeIosPush` | boolean | iOS only. Whether to use Braze to handle push notifications on iOS. Introduced in React Native SDK v1.38.0 and Expo Plugin v0.4.0. | | `enableFirebaseCloudMessaging` | boolean | Android only. Whether to use Firebase Cloud Messaging for push notifications. Introduced in React Native SDK v1.38.0 and Expo Plugin v0.4.0. | | `firebaseCloudMessagingSenderId` | string | Android only. Your Firebase Cloud Messaging sender ID. Introduced in React Native SDK v1.38.0 and Expo Plugin v0.4.0. | | `sessionTimeout` | integer | The Braze session timeout for your application in seconds. | | `enableSdkAuthentication` | boolean | Whether to enable the [SDK Authentication](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/sdk_authentication#sdk-authentication) feature. | | `logLevel` | integer | The log level for your application. The default log level is 8 and minimally logs info. To enable verbose logging for debugging, use log level 0. | | `minimumTriggerIntervalInSeconds` | integer | The minimum time interval in seconds between triggers. Defaults to 30 seconds. | | `enableAutomaticLocationCollection` | boolean | Whether automatic location collection is enabled (if the user permits). | | `enableGeofence` | boolean | Whether geofences are enabled. | | `enableAutomaticGeofenceRequests` | boolean | Whether geofence requests should be made automatically. | | `dismissModalOnOutsideTap` | boolean | iOS only. Whether a modal in-app message is dismissed when the user clicks outside of the in-app message. | | `androidHandlePushDeepLinksAutomatically` | boolean | Android only. Whether the Braze SDK should automatically handle push deep links. | | `androidPushNotificationHtmlRenderingEnabled` | boolean | Android only. Sets whether the text content in a push notification should be interpreted and rendered as HTML using `android.text.Html.fromHtml`. | | `androidNotificationAccentColor` | string | Android only. Sets the Android notification accent color. | | `androidNotificationLargeIcon` | string | Android only. Sets the Android notification large icon. | | `androidNotificationSmallIcon` | string | Android only. Sets the Android notification small icon. | | `iosRequestPushPermissionsAutomatically` | boolean | iOS only. Whether the user should automatically be prompted for push permissions on app launch. | | `enableBrazeIosRichPush` | boolean | iOS only. Whether to enable rich push features for iOS. | | `enableBrazeIosPushStories` | boolean | iOS only. Whether to enable Braze Push Stories for iOS. | | `iosPushStoryAppGroup` | string | iOS only. The app group used for iOS Push Stories. | | `iosUseUUIDAsDeviceId` | boolean | iOS only. Whether the device ID will use a randomly generated UUID. | | `iosForwardUniversalLinks` | boolean | iOS only. Specifies if the SDK should automatically recognize and forward universal links to the system methods (default: `false`). When enabled, the SDK will automatically forward universal links to the system methods defined in [Supporting universal links in your app](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/forwarduniversallinks/). Introduced in React Native SDK v11.1.0 and Expo Plugin v3.2.0. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Step 2.2: Add the plugin to your app.json" } The following code snippet shows an example `app.json` configuration: ```json { "expo": { "plugins": [ [ "@braze/expo-plugin", { "androidApiKey": "YOUR-ANDROID-API-KEY", "iosApiKey": "YOUR-IOS-API-KEY", "baseUrl": "YOUR-SDK-ENDPOINT", "sessionTimeout": 60, "enableGeofence": false, "enableBrazeIosPush": false, "enableFirebaseCloudMessaging": false, "firebaseCloudMessagingSenderId": "YOUR-FCM-SENDER-ID", "androidHandlePushDeepLinksAutomatically": true, "enableSdkAuthentication": false, "logLevel": 0, "minimumTriggerIntervalInSeconds": 0, "enableAutomaticLocationCollection": false, "enableAutomaticGeofenceRequests": false, "dismissModalOnOutsideTap": true, "androidPushNotificationHtmlRenderingEnabled": true, "androidNotificationAccentColor": "#ff3344", "androidNotificationLargeIcon": "@drawable/custom_app_large_icon", "androidNotificationSmallIcon": "@drawable/custom_app_small_icon", "iosRequestPushPermissionsAutomatically": false, "enableBrazeIosPushStories": true, "iosPushStoryAppGroup": "group.com.example.myapp.PushStories", "iosForwardUniversalLinks": false } ], ] } } ``` ###### Configuring Android push notification icons When using `androidNotificationLargeIcon` and `androidNotificationSmallIcon`, follow these best practices for proper icon display: **Icon placement and format** To use custom push notification icons with the Braze Expo plugin: 1. Create your icon files following the Icon requirements listed below. 2. Place them in your project's Android native directories at `android/app/src/main/res/drawable-/` (for example, `android/app/src/main/res/drawable-mdpi/`, `drawable-hdpi/`, or similar.) 3. Alternatively, if you're managing assets in your React Native directory, you can use Expo's [app.json icon configuration](https://docs.expo.dev/versions/latest/config/app/#icon) or create an [Expo config plugin](https://docs.expo.dev/config-plugins/introduction/) to copy the icons to the Android drawable folders during prebuild. The Braze Expo plugin references these icons using Android's drawable resource system. **Icon requirements** - **Small icon:** Must be a white silhouette on a transparent background (this is an Android platform requirement) - **Large icon:** Can be a full-color image. - **Format:** PNG format is recommended. - **Naming:** Use lowercase letters, numbers, and underscores only (for example, `my_large_icon.png`) **Configuration in app.json** The following code snippet shows how to reference Android notification icons in `app.json` using the `@drawable/` prefix: ```json { "expo": { "plugins": [ [ "@braze/expo-plugin", { "androidNotificationLargeIcon": "@drawable/large_icon", "androidNotificationSmallIcon": "@drawable/small_icon" } ] ] } } ``` **Important:** Do not use relative file paths (such as `src/assets/images/icon.png`) or include the file extension when referencing icons. The Expo plugin requires the `@drawable/` prefix to properly locate the icons in the Android native folders after the prebuild process. **How it works** The Braze Expo plugin references your icon files from the Android `drawable` directories. When you run `npx expo prebuild`, Expo generates the native Android project structure. Your icons must be present in the Android `drawable` folders (either placed manually or copied through a config plugin) before the build process. The plugin then configures the Braze SDK to use these drawable resources by their names (without path or extension), which is why the `@drawable/` prefix is required in your configuration. For more information on Android notification icons, see [Android's notification icon guidelines](https://developer.android.com/develop/ui/views/notifications#icon). ##### Step 2.3: Build and run your application Prebuilding your application generates the native files necessary for the Braze Expo plugin to work. The following code snippet shows the command to prebuild your application: ```bash npx expo prebuild ``` Run your application as specified in the [Expo docs](https://docs.expo.dev/workflow/customizing/). Keep in mind, if you make any changes to the configuration options, you'll be required to prebuild and run the application again. #### Method 2: Using React Native CLI ##### Set up Android **Step 2.1: Add the Kotlin Gradle plugin** The following code snippet shows how to add the Kotlin Gradle plugin in your top-level project `build.gradle` under `buildscript` > `dependencies`: ```groovy buildscript { dependencies { ... // Choose your Kotlin version classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10") } } ``` This adds Kotlin to your project. **Step 2.2: Configure the Braze SDK** To connect to Braze servers, create a `braze.xml` file in your project's `res/values` folder. The following code snippet shows an example `braze.xml` configuration. Replace the API [key](https://www.braze.com/docs/ja/ja/api/identifier_types/) and [endpoint](https://www.braze.com/docs/ja/ja/api/basics/#endpoints) with your values: ```xml YOU_APP_IDENTIFIER_API_KEY YOUR_CUSTOM_ENDPOINT_OR_CLUSTER ``` The following code snippet shows the required permissions for your `AndroidManifest.xml` file: ```xml ``` **Tip:** On Braze Android SDK version 12.2.0 or later, you can automatically pull in the android-sdk-location library by setting `importBrazeLocationLibrary=true` in your `gradle.properties` file. **Step 2.3: Implement user session tracking** The calls to `openSession()` and `closeSession()` are handled automatically. The following code snippet shows what to add to the `onCreate()` method of your `MainApplication` class: ```java import com.braze.BrazeActivityLifecycleCallbackListener; @Override public void onCreate() { super.onCreate(); ... registerActivityLifecycleCallbacks(new BrazeActivityLifecycleCallbackListener()); } ``` ```kotlin import com.braze.BrazeActivityLifecycleCallbackListener override fun onCreate() { super.onCreate() ... registerActivityLifecycleCallbacks(BrazeActivityLifecycleCallbackListener()) } ``` **Step 2.4: Handle intent updates** If your MainActivity has `android:launchMode` set to `singleTask`, the following code snippet shows what to add to your `MainActivity` class: ```java @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); } ``` ```kotlin override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) } ``` ##### Set up iOS **Step 2.5: (Optional) Configure Podfile for dynamic XCFrameworks** To import certain Braze libraries, such as BrazeUI, into an Objective-C++ file, you must use the `#import` syntax. Starting in version `7.4.0` of the Braze Swift SDK, binaries have an [optional distribution channel as dynamic XCFrameworks](https://github.com/braze-inc/braze-swift-sdk-prebuilt-dynamic), which are compatible with this syntax. If you'd like to use this distribution channel, manually override the CocoaPods source locations in your Podfile. The following code snippet shows a sample override. Replace `{your-version}` with the relevant version you wish to import: ```ruby pod 'BrazeKit', :podspec => 'https://raw.githubusercontent.com/braze-inc/braze-swift-sdk-prebuilt-dynamic/{your-version}/BrazeKit.podspec' pod 'BrazeUI', :podspec => 'https://raw.githubusercontent.com/braze-inc/braze-swift-sdk-prebuilt-dynamic/{your-version}/BrazeUI.podspec' pod 'BrazeLocation', :podspec => 'https://raw.githubusercontent.com/braze-inc/braze-swift-sdk-prebuilt-dynamic/{your-version}/BrazeLocation.podspec' ``` **Step 2.6: Install pods** Since React Native automatically links the libraries to the native platform, you can install the SDK with the help of CocoaPods. The following code snippet shows how to install pods from the root folder of the project: ```bash # To install using the React Native New Architecture cd ios && pod install # To install using the React Native legacy architecture cd ios && RCT_NEW_ARCH_ENABLED=0 pod install ``` **Step 2.7: Configure the Braze SDK** The following code snippet shows how to import the Braze SDK at the top of the `AppDelegate.swift` file: ```swift import BrazeKit import braze_react_native_sdk ``` In the `application(_:didFinishLaunchingWithOptions:)` method, replace the API [key](https://www.braze.com/docs/ja/ja/api/identifier_types/) and [endpoint](https://www.braze.com/docs/ja/ja/api/basics/#endpoints) with your app's values. Then, create the Braze instance using the configuration, and create a static property on the `AppDelegate` for easy access. **Note:** Our example assumes an implementation of [RCTAppDelegate](https://github.com/facebook/react-native/blob/e64756ae5bb5c0607a4d97a134620fafcb132b3b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h), which provides a number of abstractions in the React Native setup. If you are using a different setup for your app, be sure to adjust your implementation as needed. The following code snippet shows an example `AppDelegate.swift` setup: ```swift func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil ) -> Bool { // Setup Braze let configuration = Braze.Configuration( apiKey: "{BRAZE_API_KEY}", endpoint: "{BRAZE_ENDPOINT}") // Enable logging and customize the configuration here. configuration.logger.level = .info let braze = BrazeReactBridge.perform( #selector(BrazeReactBridge.initBraze(_:)), with: configuration ).takeUnretainedValue() as! Braze AppDelegate.braze = braze /* Other configuration */ return true } // MARK: - AppDelegate.braze static var braze: Braze? = nil ``` The following code snippet shows how to import the Braze SDK at the top of the `AppDelegate.m` file: ```objc #import #import "BrazeReactBridge.h" ``` In the `application:didFinishLaunchingWithOptions:` method, replace the API [key](https://www.braze.com/docs/ja/ja/api/identifier_types/) and [endpoint](https://www.braze.com/docs/ja/ja/api/basics/#endpoints) with your app's values. Then, create the Braze instance using the configuration, and create a static property on the `AppDelegate` for easy access. **Note:** Our example assumes an implementation of [RCTAppDelegate](https://github.com/facebook/react-native/blob/e64756ae5bb5c0607a4d97a134620fafcb132b3b/packages/react-native/Libraries/AppDelegate/RCTAppDelegate.h), which provides a number of abstractions in the React Native setup. If you are using a different setup for your app, be sure to adjust your implementation as needed. The following code snippet shows an example `AppDelegate.m` setup: ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Setup Braze BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:@"{BRAZE_API_KEY}" endpoint:@"{BRAZE_ENDPOINT}"]; // Enable logging and customize the configuration here. configuration.logger.level = BRZLoggerLevelInfo; Braze *braze = [BrazeReactBridge initBraze:configuration]; AppDelegate.braze = braze; /* Other configuration */ return YES; } #pragma mark - AppDelegate.braze static Braze *_braze = nil; + (Braze *)braze { return _braze; } + (void)setBraze:(Braze *)braze { _braze = braze; } ``` ### Step 3: Initialize the SDK The following code snippet shows how to import the library in your React Native code: ```javascript import Braze from "@braze/react-native-sdk"; ``` Then call `Braze.initialize()` with your app identifier API key and SDK endpoint to create the Braze instance. See the options below for where to call this method in your app. #### Standard initialization The following code snippet shows how to initialize the SDK when your app starts by calling `Braze.initialize()` in a `useEffect`: ```javascript import React, { useEffect } from "react"; import Braze from "@braze/react-native-sdk"; const App = () => { useEffect(() => { Braze.initialize("YOUR-API-KEY", "YOUR-SDK-ENDPOINT"); }, []); return ( // Your app components ); }; ``` #### Delayed initialization The following code snippet shows how to defer SDK initialization until later in the session. For example, after the user grants consent or completes login: ```javascript function onUserConsent() { Braze.initialize("YOUR-API-KEY", "YOUR-SDK-ENDPOINT"); } ``` **Warning:** On iOS, push notifications received before `Braze.initialize()` are queued and processed after initialization. On Android, deep links from push notifications do not resolve while the SDK is waiting to be initialized. If your app relies on immediate deep link handling at launch, use [standard initialization](#standard-initialization) instead. #### Platform-specific API keys The following code snippet shows how to use platform detection when your Android and iOS apps use different API keys: ```javascript import { Platform } from "react-native"; import Braze from "@braze/react-native-sdk"; const apiKey = Platform.select({ android: "YOUR-ANDROID-API-KEY", ios: "YOUR-IOS-API-KEY", }) ?? ""; Braze.initialize(apiKey, "YOUR-SDK-ENDPOINT"); ``` #### Re-initialization You can call `Braze.initialize()` multiple times to re-initialize the SDK with a different API key and endpoint mid-session. Each call tears down the previous Braze instance and creates a new one. **Important:** All SDK method calls made before `Braze.initialize()` are ignored on iOS, so call `Braze.initialize()` before using any other Braze methods. For React Native SDK 19.1.0 and earlier, native initialization happens in Step 2. Import the library in your React Native code to call Braze methods. For more details, check out our [sample project](https://github.com/braze-inc/braze-react-native-sdk/tree/master/BrazeProject). ```javascript import Braze from "@braze/react-native-sdk"; ``` ### Step 4: Test the integration (optional) You can verify that the SDK is integrated by checking session statistics in the dashboard. If you run your application on either platform, you should see a new session in the dashboard (in the **Overview** section). The following code snippet shows how to open a session for a particular user in your app: ```javascript import Braze from "@braze/react-native-sdk"; Braze.initialize("YOUR-API-KEY", "YOUR-SDK-ENDPOINT"); Braze.changeUser("{some-user-id}"); ``` Search for the user with `{some-user-id}` in the dashboard under **Audience** > **Search Users**. There, you can verify that session and device data have been logged. To test your SDK integration, the following code snippet shows how to start a new session on either platform for a user. ```javascript Braze.changeUser("userId"); ``` The following code snippet shows an example of assigning the user ID at app startup: ```javascript import React, { useEffect } from "react"; import Braze from "@braze/react-native-sdk"; const App = () => { useEffect(() => { Braze.changeUser("some-user-id"); }, []); return (
...
) ``` In the Braze dashboard, go to [User Search](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/segments/using_user_search#using-user-search) and look for the user with the ID matching `some-user-id`. Here, you can verify that session and device data were logged. ## Next steps After integrating the Braze SDK, you can start implementing common messaging features: - [Push Notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/): Set up and send push notifications to your users. - [In-App Messages](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/): Display contextual messages within your app. - [Banners](https://www.braze.com/docs/ja/ja/developer_guide/banners/): Show persistent banners in your app interface. ## Integrating the Roku SDK ### Step 1: Add files Braze SDK files can be found in the `sdk_files` directory in the [Braze Roku SDK repository](https://github.com/braze-inc/braze-roku-sdk). 1. Add `BrazeSDK.brs` to your app in the `source` directory. 2. Add `BrazeTask.brs` and `BrazeTask.xml` to your app in the `components` directory. ### Step 2: Add references Add a reference to `BrazeSDK.brs` in your main scene using the following `script` element: ``` ``` 4. Under **Triggering**, select the trigger you created in step 2. 5. Save and publish your container. To include event properties, pass them as the second argument: ```html ``` ## Google's EU User Consent Policy **Important:** Google is updating their [EU User Consent Policy](https://www.google.com/about/company/user-consent-policy/) in response to changes to the [Digital Markets Act (DMA)](https://ads-developers.googleblog.com/2023/10/updates-to-customer-match-conversion.html), which is in effect as of March 6, 2024. This new change requires advertisers to disclose certain information to their EEA and UK end users, as well as obtain necessary consents from them. Review the following documentation to learn more. As part of Google's EU User Consent Policy, the following boolean custom attributes need to be logged to user profiles: - `$google_ad_user_data` - `$google_ad_personalization` If setting these via the GTM integration, custom attributes require creating a custom HTML tag. The following is an example of how to log these values as boolean data types (not as strings): ```js ``` For more information, refer to [Audience Sync to Google](https://www.braze.com/docs/ja/ja/partners/canvas_audience_sync/google_audience_sync/). ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Using Google Tag Manager for Android In the following example, a music streaming app wants to log different events as users listen to songs. Using Google Tag Manager for Android, they can control which of the Braze third-party vendors receive this event, and create tags specific to Braze. ### Step 1: Create a trigger for custom events Custom events are logged with `actionType` set to `logEvent`. The Braze custom tag provider in this example is expecting the custom event name to be set using `eventName`. To get started, create a trigger that looks for an "Event Name" that equals `played song` ![A custom trigger in Google Tag Manager set to trigger for some events when "event name" equals "played song".](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_trigger.png?ce7d5cd1e1ab6a285076d8429ac796bd) Next, create a new tag (also known as a "Function Call") and enter the class path of your [custom tag provider](#adding-android-google-tag-provider) described later in this article. This tag will be triggered when you log the `played song` event. In the tag's custom parameters (also known as the key-value pairs), set `eventName` to `played song`. This will be the custom event name logged to Braze. ![A tag in Google Tag Manager with classpath and key-value pair fields. This tag is set to trigger with the previously created "played song" trigger.](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_function_call_tag.png?40fad5b2a61b7d2183f635a10e290252) **Important:** When sending a custom event, be sure to set `actionType` to `logEvent`, and set a value for `eventName` so Braze receives the correct event name and action to take. You can also include additional key-value pair arguments to the tag, which will be sent as custom event properties to Braze. `eventName` and `actionType` will not be ignored for custom event properties. In the following example tag, `genre` is passed and defined using a tag variable in Google Tag Manager, which is sourced from the custom event logged in the app. Because Google Tag Manager for Android uses Firebase as the data layer, the `genre` event property is sent to Google Tag Manager as a "Firebase - Event Parameter" variable. ![A variable in Google Tag Manager where "genre" is added as an event parameter for the "Braze - Played Song Event" tag.](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_eventname_variable.png?abff82f38b65ae64ad0ae3842d2ea439) When a user plays a song in the app, an event will be logged through Firebase and Google Tag Manager using the Firebase analytics event name that matches the tag's trigger name, `played song`: ```java Bundle params = new Bundle(); params.putString("genre", "pop"); params.putInt("number of times listened", 42); mFirebaseAnalytics.logEvent("played song", params); ``` ```kotlin val params = Bundle() params.putString("genre", "pop") params.putInt("number of times listened", 42); mFirebaseAnalytics.logEvent("played song", params) ``` ### Step 2: Log custom attributes Custom attributes are set via an `actionType` set to `customAttribute`. The Braze custom tag provider is expecting the custom attribute key-value to be set via `customAttributeKey` and `customAttributeValue`: ```java Bundle params = new Bundle(); params.putString("customAttributeKey", "favorite song"); params.putString("customAttributeValue", "Private Eyes"); mFirebaseAnalytics.logEvent("customAttribute", params); ``` ```kotlin val params = Bundle() params.putString("customAttributeKey", "favorite song") params.putString("customAttributeValue", "Private Eyes") mFirebaseAnalytics.logEvent("customAttribute", params) ``` ### Step 3: Call `changeUser()` Calls to `changeUser()` are made via an `actionType` set to `changeUser`. The Braze custom tag provider is expecting the Braze user ID to be set via an `externalUserId` key-value pair within your tag: ```java Bundle params = new Bundle(); params.putString("externalUserId", userId); mFirebaseAnalytics.logEvent("changeUser", params); ``` ```kotlin val params = Bundle() params.putString("externalUserId", userId) mFirebaseAnalytics.logEvent("changeUser", params) ``` ### Step 4: Add a custom tag provider {#adding-android-google-tag-provider} With the tags and triggers set up, you will also need to implement Google Tag Manager in your Android app which can be found in Google's [documentation](https://developers.google.com/tag-manager/android/v5/). After the Google Tag Manager is installed in your app, add a custom tag provider to call Braze SDK methods based on the tags you've configured within Google Tag Manager. Be sure to note the "Class Path" to the file - this is what you'll enter when setting up a Tag in the [Google Tag Manager](https://tagmanager.google.com/) console. This example highlights one of many ways you can structure your custom tag provider. Specifically, it shows how to determine which Braze SDK method to call based on the `actionType` key-value pair sent from the GTM Tag. The `actionType` shown in this example are `logEvent`, `customAttribute`, and `changeUser`, but you may prefer to change how your tag provider handles data from Google Tag Manager. ```java public class BrazeGtmTagProvider implements CustomTagProvider { private static final String TAG = BrazeLogger.getBrazeLogTag(BrazeGtmTagProvider.class); private static final String ACTION_TYPE_KEY = "actionType"; // Custom Events private static final String LOG_EVENT_ACTION_TYPE = "logEvent"; private static final String EVENT_NAME_VARIABLE = "eventName"; // Custom Attributes private static final String CUSTOM_ATTRIBUTE_ACTION_TYPE = "customAttribute"; private static final String CUSTOM_ATTRIBUTE_KEY = "customAttributeKey"; private static final String CUSTOM_ATTRIBUTE_VALUE_KEY = "customAttributeValue"; // Change User private static final String CHANGE_USER_ACTION_TYPE = "changeUser"; private static final String CHANGE_USER_ID_VARIABLE = "externalUserId"; private static Context sApplicationContext; /** * Must be set before calling any of the following methods * so that the proper application context is available when needed. * * Recommended to be called in your {@link Application#onCreate()}. */ public static void setApplicationContext(Context applicationContext) { if (applicationContext != null) { sApplicationContext = applicationContext.getApplicationContext(); } } @Override public void execute(Map map) { BrazeLogger.i(TAG, "Got google tag manager parameters map: " + map); if (sApplicationContext == null) { BrazeLogger.w(TAG, "No application context provided to this tag provider."); return; } if (!map.containsKey(ACTION_TYPE_KEY)) { BrazeLogger.w(TAG, "Map does not contain the Braze action type key: " + ACTION_TYPE_KEY); return; } String actionType = String.valueOf(map.remove(ACTION_TYPE_KEY)); switch (actionType) { case LOG_EVENT_ACTION_TYPE: logEvent(map); break; case CUSTOM_ATTRIBUTE_ACTION_TYPE: setCustomAttribute(map); break; case CHANGE_USER_ACTION_TYPE: changeUser(map); break; default: BrazeLogger.w(TAG, "Got unknown action type: " + actionType); break; } } private void logEvent(Map tagParameterMap) { String eventName = String.valueOf(tagParameterMap.remove(EVENT_NAME_VARIABLE)); Braze.getInstance(sApplicationContext).logCustomEvent(eventName, parseMapIntoProperties(tagParameterMap)); } private BrazeProperties parseMapIntoProperties(Map map) { BrazeProperties brazeProperties = new BrazeProperties(); for (Map.Entry entry : map.entrySet()) { final Object value = entry.getValue(); final String key = entry.getKey(); if (value instanceof Boolean) { brazeProperties.addProperty(key, (Boolean) value); } else if (value instanceof Integer) { brazeProperties.addProperty(key, (Integer) value); } else if (value instanceof Date) { brazeProperties.addProperty(key, (Date) value); } else if (value instanceof Long) { brazeProperties.addProperty(key, (Long) value); } else if (value instanceof String) { brazeProperties.addProperty(key, (String) value); } else if (value instanceof Double) { brazeProperties.addProperty(key, (Double) value); } else { BrazeLogger.w(TAG, "Failed to parse value into an BrazeProperties " + "accepted type. Key: '" + key + "' Value: '" + value + "'"); } } return brazeProperties; } private void setCustomAttribute(Map tagParameterMap) { String key = String.valueOf(tagParameterMap.get(CUSTOM_ATTRIBUTE_KEY)); Object value = tagParameterMap.get(CUSTOM_ATTRIBUTE_VALUE_KEY); Braze.getInstance(sApplicationContext).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { if (value instanceof Boolean) { brazeUser.setCustomUserAttribute(key, (Boolean) value); } else if (value instanceof Integer) { brazeUser.setCustomUserAttribute(key, (Integer) value); } else if (value instanceof Long) { brazeUser.setCustomUserAttribute(key, (Long) value); } else if (value instanceof String) { brazeUser.setCustomUserAttribute(key, (String) value); } else if (value instanceof Double) { brazeUser.setCustomUserAttribute(key, (Double) value); } else if (value instanceof Float) { brazeUser.setCustomUserAttribute(key, (Float) value); } else { BrazeLogger.w(TAG, "Failed to parse value into a custom " + "attribute accepted type. Key: '" + key + "' Value: '" + value + "'"); } } }); } private void changeUser(Map tagParameterMap) { String userId = String.valueOf(tagParameterMap.get(CHANGE_USER_ID_VARIABLE)); Braze.getInstance(sApplicationContext).changeUser(userId); } } ``` ```kotlin class BrazeGtmTagProvider : CustomTagProvider { override fun execute(map: MutableMap) { BrazeLogger.i(TAG, "Got google tag manager parameters map: $map") if (sApplicationContext == null) { BrazeLogger.w(TAG, "No application context provided to this tag provider.") return } if (!map.containsKey(ACTION_TYPE_KEY)) { BrazeLogger.w(TAG, "Map does not contain the Braze action type key: $ACTION_TYPE_KEY") return } val actionType = map.remove(ACTION_TYPE_KEY).toString() when (actionType) { LOG_EVENT_ACTION_TYPE -> logEvent(map) CUSTOM_ATTRIBUTE_ACTION_TYPE -> setCustomAttribute(map) CHANGE_USER_ACTION_TYPE -> changeUser(map) else -> BrazeLogger.w(TAG, "Got unknown action type: $actionType") } } private fun logEvent(tagParameterMap: MutableMap) { val eventName = tagParameterMap.remove(EVENT_NAME_VARIABLE).toString() Braze.getInstance(sApplicationContext).logCustomEvent(eventName, parseMapIntoProperties(tagParameterMap)) } private fun parseMapIntoProperties(map: Map): BrazeProperties { val brazeProperties = BrazeProperties() map.forEach { param -> val key = param.key val value = param.value when (value) { is Boolean -> brazeProperties.addProperty(key, value) is Int -> brazeProperties.addProperty(key, value) is Date -> brazeProperties.addProperty(key, value) is Long -> brazeProperties.addProperty(key, value) is String -> brazeProperties.addProperty(key, value) is Double -> brazeProperties.addProperty(key, value) else -> BrazeLogger.w(TAG, "Failed to parse value into an BrazeProperties " + "accepted type. Key: '" + key + "' Value: '" + value + "'") } } return brazeProperties } private fun setCustomAttribute(tagParameterMap: Map) { val key = tagParameterMap[CUSTOM_ATTRIBUTE_KEY].toString() val value = tagParameterMap[CUSTOM_ATTRIBUTE_VALUE_KEY] Braze.getInstance(sApplicationContext).getCurrentUser { brazeUser -> when (value) { is Boolean -> brazeUser.setCustomUserAttribute(key, value) is Int -> brazeUser.setCustomUserAttribute(key, value) is Long -> brazeUser.setCustomUserAttribute(key, value) is String -> brazeUser.setCustomUserAttribute(key, value) is Double -> brazeUser.setCustomUserAttribute(key, value) is Float -> brazeUser.setCustomUserAttribute(key, value) else -> BrazeLogger.w( TAG, "Failed to parse value into a custom " + "attribute accepted type. Key: '" + key + "' Value: '" + value + "'" ) } } } private fun changeUser(tagParameterMap: Map) { val userId = tagParameterMap[CHANGE_USER_ID_VARIABLE].toString() Braze.getInstance(sApplicationContext).changeUser(userId) } companion object { private val TAG = BrazeLogger.getBrazeLogTag(BrazeGtmTagProvider::class.java) private val ACTION_TYPE_KEY = "actionType" // Custom Events private val LOG_EVENT_ACTION_TYPE = "logEvent" private val EVENT_NAME_VARIABLE = "eventName" // Custom Attributes private val CUSTOM_ATTRIBUTE_ACTION_TYPE = "customAttribute" private val CUSTOM_ATTRIBUTE_KEY = "customAttributeKey" private val CUSTOM_ATTRIBUTE_VALUE_KEY = "customAttributeValue" // Change User private val CHANGE_USER_ACTION_TYPE = "changeUser" private val CHANGE_USER_ID_VARIABLE = "externalUserId" private var sApplicationContext: Context? = null /** * Must be set before calling any of the following methods so * that the proper application context is available when needed. * * Recommended to be called in your [Application.onCreate]. */ fun setApplicationContext(applicationContext: Context?) { if (applicationContext != null) { sApplicationContext = applicationContext.applicationContext } } } } ``` In your `Application.onCreate()` be sure to add the following initialization for the previous snippet: ```java BrazeGtmTagProvider.setApplicationContext(this.getApplicationContext()); ``` ```kotlin BrazeGtmTagProvider.setApplicationContext(this.applicationContext) ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). ## Using Google Tag Manager for Swift In the following example, a music streaming app wants to log different events as users listen to songs. Using Google Tag Manager for iOS, they can control which of the Braze third-party vendors receive this event and create tags specific to Braze. ### Step 1: Create a trigger for custom events Custom events are logged with `actionType` set to `logEvent`. In this example, the Braze custom tag provider is expecting the custom event name to be set using `eventName`. First, create a trigger that looks for an `eventName` that equals `played song`. ![A custom trigger in Google Tag Manager set to trigger for some events when "eventName" equals "played song".](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_trigger.png?ce7d5cd1e1ab6a285076d8429ac796bd) Next, create a new Tag (also known as a "Function Call") and enter the class path of your [custom tag provider](#adding-ios-google-tag-provider) described later in this article. This tag will be triggered when you log the `played song` event. Because `eventName` is set to `played song` it will be used as custom event name that's logged to Braze. **Important:** When sending a custom event, set `actionType` to `logEvent`, and set a value for `eventName` so Braze receives the correct event name and action to take. ![A tag in Google Tag Manager with classpath and key-value pair fields. This tag is set to trigger with the previously created "played song" trigger.](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_function_call_tag.png?40fad5b2a61b7d2183f635a10e290252) You can also include additional key-value pair arguments to the tag, which will be sent as custom event properties to Braze. `eventName` and `actionType` will not be ignored for custom event properties. In the following example tag, pass in `genre`, which was defined using a tag variable in Google Tag Manager and sourced from the custom event logged in the app. The `genre` event property is sent to Google Tag Manager as a "Firebase - Event Parameter" variable since Google Tag Manager for iOS uses Firebase as the data layer. ![A variable in Google Tag Manager where "genre" is added as an event parameter for the "Braze - Played Song Event" tag.](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_eventname_variable.png?abff82f38b65ae64ad0ae3842d2ea439) When a user plays a song in the app, log an event through Firebase and Google Tag Manager using the Firebase analytics event name that matches the tag's trigger name, `played song`: ```swift let parameters: [String: Any] = ["genre": "pop", "number of times listened": 42] Analytics.logEvent("played song", parameters: parameters) ``` ```obj-c NSDictionary *parameters = @{@"genre" : @"pop", @"number of times listened" : @42}; [FIRAnalytics logEventWithName:@"played song" parameters:parameters]; ``` ### Step 2: Log custom attributes Custom attributes are set via an `actionType` set to `customAttribute`. The Braze custom tag provider is expecting the custom attribute key-value to be set via `customAttributeKey` and `customAttributeValue`: ```swift let parameters: [String: Any] = ["customAttributeKey": "favoriteSong", "customAttributeValue": "Private Eyes"] FIRAnalytics.logEvent(withName:"customAttribute", parameters: parameters) ``` ```obj-c NSDictionary *parameters = @{@"customAttributeKey" : @"favoriteSong", @"customAttributeValue" : @"Private Eyes"}; [FIRAnalytics logEventWithName:@"customAttribute" parameters:parameters]; ``` ### Step 3: Call `changeUser()` Calls to `changeUser()` are made via an `actionType` set to `changeUser`. The Braze custom tag provider is expecting the Braze user ID to be set via an `externalUserId` key-value pair within your tag: ```swift let parameters: [String: Any] = ["externalUserId": "favorite userId"] Analytics.logEvent(withName:"changeUser", parameters: parameters) ``` ```obj-c NSDictionary *parameters = @{@"externalUserId" : userId}; [FIRAnalytics logEventWithName:@"changeUser" parameters:parameters]; ``` ### Step 4: Add a custom tag provider {#adding-ios-google-tag-provider} With the tags and triggers set up, you will also need to implement Google Tag Manager in your iOS app which can be found in Google's [documentation](https://developers.google.com/tag-manager/ios/v5/). After Google Tag Manager is installed in your app, add a custom tag provider to call Braze SDK methods based on the tags you've configured within Google Tag Manager. Be sure to note the "Class Path" to the file - this is what you'll enter when setting up a tag in the [Google Tag Manager](https://tagmanager.google.com/) console. This example highlights one of many ways you can structure your custom tag provider. Specifically, it shows how to determine which Braze SDK method to call based on the `actionType` key-value pair sent from the GTM Tag. This example assumes you've assigned the Braze instance as a variable in the AppDelegate. The `actionType` supported in this example are `logEvent`, `customAttribute`, and `changeUser`, but you may prefer to change how your tag provider handles data from Google Tag Manager. Add the following code to your `BrazeGTMTagManager.swift` file. ```swift import FirebaseAnalytics import GoogleTagManager import BrazeKit let ActionTypeKey: String = "actionType" // Custom Events let LogEventAction: String = "logEvent" let LogEventName: String = "eventName" // Custom Attributes let CustomAttributeAction: String = "customAttribute" let CustomAttributeKey: String = "customAttributeKey" let CustomAttributeValueKey: String = "customAttributeValue" // Change User let ChangeUserAction: String = "changeUser" let ChangeUserExternalUserId: String = "externalUserId" @objc(BrazeGTMTagManager) final class BrazeGTMTagManager : NSObject, TAGCustomFunction { @objc func execute(withParameters parameters: [AnyHashable : Any]!) -> NSObject! { var parameters: [String : Any] = parameters as! [String : Any] guard let actionType: String = parameters[ActionTypeKey] as? String else { print("There is no Braze action type key in this call. Doing nothing.") return nil } parameters.removeValue(forKey: ActionTypeKey) if actionType == LogEventAction { logEvent(parameters: parameters) } else if actionType == CustomAttributeAction { logCustomAttribute(parameters: parameters) } else if actionType == ChangeUserAction { changeUser(parameters: parameters) } return nil } func logEvent(parameters: [String : Any]) { var parameters: [String : Any] = parameters guard let eventName: String = parameters[LogEventName] as? String else { return } parameters.removeValue(forKey: LogEventName) AppDelegate.braze?.logCustomEvent(name: eventName, properties: parameters) } func logCustomAttribute(parameters: [String: Any]) { guard let customAttributeKey = parameters[CustomAttributeKey] as? String else { return } let customAttributeValue = parameters[CustomAttributeValueKey] if let customAttributeValue = customAttributeValue as? String { AppDelegate.braze?.user.setCustomAttribute(key: customAttributeKey, value: customAttributeValue) } else if let customAttributeValue = customAttributeValue as? Date { AppDelegate.braze?.user.setCustomAttribute(key: customAttributeKey, value: customAttributeValue) } else if let customAttributeValue = customAttributeValue as? Double { AppDelegate.braze?.user.setCustomAttribute(key: customAttributeKey, value: customAttributeValue) } else if let customAttributeValue = customAttributeValue as? Bool { AppDelegate.braze?.user.setCustomAttribute(key: customAttributeKey, value: customAttributeValue) } else if let customAttributeValue = customAttributeValue as? Int { AppDelegate.braze?.user.setCustomAttribute(key: customAttributeKey, value: customAttributeValue) } else if let customAttibuteValue = customAttributeValue as? [String] { AppDelegate.braze?.user.setCustomAttributeArray(key: customAttributeKey, array: customAttibuteValue) } } func changeUser(parameters: [String: Any]) { guard let userId = parameters[ChangeUserExternalUserId] as? String else { return } AppDelegate.braze?.changeUser(userId: userId) } } ``` Add the following code to your `BrazeGTMTagManager.h` file: ```obj-c @import Firebase; @import GoogleTagManager; @interface BrazeGTMTagManager : NSObject @end ``` And add the following code to your `BrazeGTMTagManager.m` file: ```obj-c #import #import "BrazeGTMTagManager.h" #import "BrazeKit" #import "AppDelegate.h" static NSString *const ActionTypeKey = @"actionType"; // Custom Events static NSString *const LogEventAction = @"logEvent"; static NSString *const LogEventEventName = @"eventName"; // Custom Attributes static NSString *const CustomAttributeAction = @"customAttribute"; static NSString *const CustomAttributeKey = @"customAttributeKey"; static NSString *const CustomAttributeValueKey = @"customAttributeValue"; // Change User static NSString *const ChangeUserAction = @"changeUser"; static NSString *const ChangeUserExternalUserId = @"externalUserId"; @implementation BrazeGTMTagManager - (NSObject *)executeWithParameters:(NSDictionary *)parameters { NSMutableDictionary *mutableParameters = [parameters mutableCopy]; NSString *actionType = mutableParameters[ActionTypeKey]; if (!actionType) { NSLog(@"There is no Braze action type key in this call. Doing nothing.", nil); return nil; } [mutableParameters removeObjectForKey:ActionTypeKey]; if ([actionType isEqualToString:LogEventAction]) { [self logEvent:mutableParameters]; } else if ([actionType isEqualToString:CustomAttributeAction]) { [self logCustomAttribute:mutableParameters]; } else if ([actionType isEqualToString:ChangeUserAction]) { [self changeUser:mutableParameters]; } else { NSLog(@"Invalid action type. Doing nothing."); } return nil; } - (void)logEvent:(NSMutableDictionary *)parameters { NSString *eventName = parameters[LogEventEventName]; [parameters removeObjectForKey:LogEventEventName]; [AppDelegate.braze logCustomEvent:eventName properties:parameters]; } - (void)logCustomAttribute:(NSMutableDictionary *)parameters { NSString *customAttributeKey = parameters[CustomAttributeKey]; id customAttributeValue = parameters[CustomAttributeValueKey]; if ([customAttributeValue isKindOfClass:[NSString class]]) { [AppDelegate.braze logCustomEvent:customAttributeKey properties:parameters]; } else if ([customAttributeValue isKindOfClass:[NSDate class]]) { [AppDelegate.braze.user setCustomAttributeWithKey:customAttributeKey dateValue:customAttributeValue]; } else if ([customAttributeValue isKindOfClass:[NSNumber class]]) { if (strcmp([customAttributeValue objCType], [@(YES) objCType]) == 0) { [AppDelegate.braze.user setCustomAttributeWithKey:customAttributeKey boolValue:[(NSNumber *)customAttributeValue boolValue]]; } else if (strcmp([customAttributeValue objCType], @encode(short)) == 0 || strcmp([customAttributeValue objCType], @encode(int)) == 0 || strcmp([customAttributeValue objCType], @encode(long)) == 0) { [AppDelegate.braze.user setCustomAttributeWithKey:customAttributeKey intValue:[(NSNumber *)customAttributeValue integerValue]]; } else if (strcmp([customAttributeValue objCType], @encode(float)) == 0 || strcmp([customAttributeValue objCType], @encode(double)) == 0) { [AppDelegate.braze.user setCustomAttributeWithKey:customAttributeKey doubleValue:[(NSNumber *)customAttributeValue doubleValue]]; } else { NSLog(@"Could not map NSNumber value to Braze custom attribute:%@", customAttributeValue); } } else if ([customAttributeValue isKindOfClass:[NSArray class]]) { [AppDelegate.braze.user setCustomAttributeArrayWithKey:customAttributeKey array:customAttributeValue]; } } - (void)changeUser:(NSMutableDictionary *)parameters { NSString *userId = parameters[ChangeUserExternalUserId]; [AppDelegate.braze changeUser:userId]; } @end ``` ## トラブルシューティング {#troubleshooting} Brazeが初期化されない場合やイベントが期待どおりに表示されない場合は、GTMコンテナが公開されていること、トリガーとタグの発火順序がSDKの[ライフサイクルおよび初期化戦略](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration)と一致していること、テストデバイスがBrazeエンドポイントをブロックしていないことを確認してください。 初期化の失敗については、Brazeタグまたはカスタムタグプロバイダーが期待される`actionType`とパラメーターを受信しているかを確認してください(このページのAndroid、Swift、Webの各タブを参照)。GTMから発火されたイベントを検証する際に詳細なログを取得するには、各タブからリンクされているプラットフォーム統合ガイドの説明に従って、プラットフォームのSDKデバッグログを有効にしてください。 # Braze SDKの認証を設定する Source: /docs/ja/developer_guide/sdk_integration/authentication/index.md # SDK認証を設定する {#set-up-sdk-authentication} > SDK認証を使用すると、ログインしているユーザーの代わりに行われたSDKリクエストに対して(サーバー側で生成された)暗号証明を提供できます。 ## 仕組み {#how-it-works} アプリでこの機能を有効にした後、無効または欠落しているJSON Web Token(JWT)を含むリクエストを拒否するようにBrazeダッシュボードを設定できます。これには次のものが含まれます。 - カスタムイベント、属性、購入、セッションデータの送信 - Brazeワークスペースでの新規ユーザーの作成 - 標準ユーザープロファイル属性の更新 - メッセージの受信またはトリガー 認証されていないログインユーザーが、アプリのSDK APIキーを使って悪意のあるアクション(他のユーザーになりすますなど)を行うのを防げるようになります。 ## 認証のセットアップ {#setting-up-authentication} ### ステップ1:サーバーのセットアップ {#server-side-integration} #### ステップ1.1:公開鍵と秘密鍵のペアを生成する {#generate-keys} RSA256公開鍵/秘密鍵ペアを生成します。公開キーは最終的にBrazeのダッシュボードに追加されますが、秘密キーはサーバーに安全に保管する必要があります。 RS256 JWTアルゴリズムで使用する2048ビットのRSA鍵を推奨します。 **Warning:** 秘密キーは必ず_非公開_にしてください。アプリやWebサイトに秘密鍵を公開したり、ハードコードしたりしてはなりません。あなたの秘密キーを知っている人なら誰でも、あなたのアプリケーションに代わってユーザーになりすましたり、ユーザーを作成したりすることができます。 #### ステップ1.2:現在のユーザーのJSON Web Tokenを作成する {#create-jwt} 秘密キーが手に入ったら、サーバー側のアプリケーションはそれを使って、現在ログインしているユーザーのアプリまたはWebサイトにJWTを返す必要があります。 通常、このロジックは、アプリが通常現在のユーザーのプロファイルをリクエストする任意の場所に配置できます。たとえば、ログインエンドポイントや、アプリが現在のユーザープロファイルを更新する場所などです。 JWTを生成する際には、以下のフィールドが必要です: **JWTヘッダー** | フィールド | 必須 | 説明 | | ----- | -------- | ----------------------------------- | | `alg` | はい | サポートされているアルゴリズムは`RS256`です。 | | `typ` | はい | タイプは`JWT`と同じでなければなりません。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="ステップ1.2:現在のユーザーのJSON Web Tokenを作成する" } {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="ステップ1.2:現在のユーザーのJSON Web Tokenを作成する #create-jwt" } **JWTペイロード** | フィールド | 必須 | 説明 | | ----- | -------- | -------------------------------------------------------------------------------------- | | `sub` | はい | 「subject」は、`changeUser`の呼び出し時にBraze SDKに指定したユーザーIDと同じである必要があります。 | | `exp` | はい | このトークンをいつ期限切れにするかの「有効期限」(Unixタイムスタンプ(秒単位)で指定します。例:2030年1月1日の場合は`1893456000`)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="ステップ1.2:現在のユーザーのJSON Web Tokenを作成する" } {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="ステップ1.2:現在のユーザーのJSON Web Tokenを作成する #create-jwt" } **Tip:** JSON Web Tokenについての詳細や、この署名プロセスを簡素化する多くのオープンソースライブラリを参照するには、[https://jwt.io](https://jwt.io)をチェックしてください。 ### ステップ2:SDKの設定 {#sdk-integration} この機能は以下の[SDKバージョン](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/campaigns/ideas_and_strategies/new_features/#filtering-by-most-recent-app-versions)から利用可能です: **Note:** iOS統合については、このページでBraze Swift SDKのステップを詳しく説明します。レガシーAppboyKit iOS SDKでの使用例については、[このファイル](https://github.com/Appboy/appboy-ios-sdk/blob/master/Example/Stopwatch/Sources/AppDelegate.m)と[このファイル](https://github.com/Appboy/appboy-ios-sdk/blob/master/Example/Stopwatch/Sources/Utils/SdkAuthDelegate.m)を参照してください。 #### ステップ2.1:Braze SDKで認証を有効にする {#step-21-enable-authentication-in-the-braze-sdk} この機能が有効な場合、Braze SDKは、Brazeサーバーに対して行われたネットワークリクエストに、現在のユーザーの最新の既知のJWTを追加します。 **Note:** このオプションだけで初期化しても、Brazeダッシュボード内で[認証の適用を](#braze-dashboard)開始するまでは、データ収集には何の影響もないのでご心配なく。 `initialize`を呼び出す際には、オプションの`enableSdkAuthentication`プロパティを`true`に設定します。 ```javascript import * as braze from "@braze/web-sdk"; braze.initialize("YOUR-API-KEY-HERE", { baseUrl: "YOUR-SDK-ENDPOINT-HERE", enableSdkAuthentication: true, }); ``` ネイティブSDKの初期化時に、SDK認証を有効にする必要があります。ネイティブのiOSおよびAndroidコードに以下の設定を追加してください: **iOS (AppDelegate.swift)** ```swift import BrazeKit import braze_react_native_sdk let configuration = Braze.Configuration( apiKey: "{YOUR-BRAZE-API-KEY}", endpoint: "{YOUR-BRAZE-ENDPOINT}" ) configuration.api.sdkAuthentication = true let braze = BrazeReactBridge.perform( #selector(BrazeReactBridge.initBraze(_:)), with: configuration ).takeUnretainedValue() as! Braze ``` **Android (braze.xml)** ```xml true ``` ネイティブレイヤーでSDK認証を有効にした後、以下のステップに示すReact Native JavaScriptメソッドを使用できます。 Brazeインスタンスを設定するときは、`setIsSdkAuthenticationEnabled`を`true`に設定します。 ```java BrazeConfig.Builder brazeConfigBuilder = new BrazeConfig.Builder() .setIsSdkAuthenticationEnabled(true); Braze.configure(this, brazeConfigBuilder.build()); ``` あるいは、braze.xmlに`true`を追加することもできます。 Brazeインスタンスを設定するときは、`setIsSdkAuthenticationEnabled`を`true`に設定します。 ```kotlin BrazeConfig.Builder brazeConfigBuilder = BrazeConfig.Builder() .setIsSdkAuthenticationEnabled(true) Braze.configure(this, brazeConfigBuilder.build()) ``` あるいは、braze.xmlに`true`を追加することもできます。 SDK認証を有効にするには、Brazeインスタンスを初期化する前に、`BRZConfiguration`オブジェクトの`configuration.api.sdkAuthentication`プロパティを`YES`に設定します: ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:@"{BRAZE_API_KEY}" endpoint:@"{BRAZE_ENDPOINT}"]; configuration.api.sdkAuthentication = YES; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; AppDelegate.braze = braze; ``` SDK認証を有効にするには、SDKを初期化する際に、`Braze.Configuration`オブジェクトの`configuration.api.sdkAuthentication`プロパティを`true`に設定します: ```swift let configuration = Braze.Configuration(apiKey: "{YOUR-BRAZE-API-KEY}", endpoint: "{YOUR-BRAZE-ENDPOINT}") configuration.api.sdkAuthentication = true let braze = Braze(configuration: configuration) AppDelegate.braze = braze ``` 現在、SDK認証は、iOSとAndroidのネイティブコードでSDKを初期化する際に有効にする必要があります。Flutter SDKでSDK認証を有効にするには、他のタブのiOSとAndroidの統合に従ってください。SDK認証を有効にした後、残りの機能をDartに統合することができます。 ネイティブのiOSおよびAndroidコードにおいて、SDKの初期化の一環としてSDK認証を有効にする必要があります。ネイティブレイヤーで有効にすると、Flutter SDKのメソッドを使ってJWT署名を渡すことができます。 **iOS** SDK認証を有効にするには、ネイティブiOSコードで`configuration.api.sdkAuthentication`プロパティを`true`に設定します: ```swift let configuration = Braze.Configuration(apiKey: "{YOUR-BRAZE-API-KEY}", endpoint: "{YOUR-BRAZE-ENDPOINT}") configuration.api.sdkAuthentication = true let braze = Braze(configuration: configuration) ``` **Android (braze.xml)** ```xml true ``` ネイティブレイヤーでSDK認証を有効にした後、以下のステップで示すFlutter SDKメソッドを使用できます。 ネイティブSDKの初期化時に、SDK認証を有効にする必要があります。ネイティブのiOSおよびAndroidコードに以下の設定を追加してください: **iOS** 設定ファイルで`SDKAuthenticationEnabled`プロパティを`true`に設定します: ```xml SDKAuthenticationEnabled ``` **Android (braze.xml)** ```xml true ``` ネイティブレイヤーでSDK認証を有効にした後、以下のステップで示すUnity C#メソッドを使用できます。 ネイティブSDKの初期化時に、SDK認証を有効にする必要があります。ネイティブのiOSおよびAndroidコードに以下の設定を追加してください: **iOS** SDK認証を有効にするには、`config.xml`で`enableSDKAuthentication`プロパティを`true`に設定します: ```xml ``` **Android (braze.xml)** ```xml true ``` ネイティブレイヤーでSDK認証を有効にした後、以下のステップで示すCordova JavaScriptメソッドを使用できます。 ネイティブSDKの初期化時に、SDK認証を有効にする必要があります。iOSとAndroidではSDK認証を別々に設定します: **iOS** SDK認証を有効にするには、SDKを初期化する際に`configuration.Api.SdkAuthentication`プロパティを`true`に設定します: ```csharp var configuration = new BRZConfiguration("YOUR-API-KEY", "YOUR-ENDPOINT"); configuration.Api.SdkAuthentication = true; var braze = new Braze(configuration); ``` **Android (braze.xml)** ```xml true ``` SDK認証を有効にした後、以下のステップで示す.NET MAUIメソッドを使用できます。 Braze Expoプラグインを使用する際は、アプリ設定で`enableSdkAuthentication`プロパティを`true`に設定します。これにより、手動でのネイティブコードの変更を必要とせずに、ネイティブのiOSおよびAndroidレイヤーでSDK認証が自動的に設定されます。 **app.jsonあるいはapp.config.js** ```json { "expo": { "plugins": [ [ "@braze/expo-plugin", { "enableSdkAuthentication": true } ] ] } } ``` アプリ設定でSDK認証を有効にした後、React Nativeタブに表示されているReact Native JavaScriptメソッドを使用して、以下のステップを実行できます。 **Note:** 完全な実装例については、GitHub上の[Braze Expoプラグインサンプルアプリ](https://github.com/braze-inc/braze-expo-plugin/blob/main/example/components/Braze.tsx)を参照してください。 #### ステップ2.2:現在のユーザーのJWTを設定する {#step-22-set-the-current-users-jwt} アプリがBrazeの`changeUser`メソッドを呼び出すたびに、[サーバー側で生成された](#braze-dashboard)JWTも指定します。 また、トークンが現在のユーザーのセッションの途中でリフレッシュされるように設定することもできます。 **Note:** `changeUser`は、ユーザーIDが_実際に変更された_場合にのみ呼び出す必要があることに注意してください。ユーザーIDが変更されていない場合は、このメソッドを認証トークン(JWT)の更新手段として使用しないでください。 [`changeUser`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#changeuser)の呼び出し時にJWTを指定します: ```javascript import * as braze from "@braze/web-sdk"; braze.changeUser("NEW-USER-ID", "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```javascript import * as braze from "@braze/web-sdk"; braze.setSdkAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` [`changeUser`](https://braze-inc.github.io/braze-react-native-sdk/classes/Braze.Braze-1.html#changeUser)の呼び出し時にJWTを指定します: ```typescript import Braze from '@braze/react-native-sdk'; Braze.changeUser("NEW-USER-ID", "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```typescript import Braze from '@braze/react-native-sdk'; Braze.setSdkAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` [`changeUser`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/change-user.html)の呼び出し時にJWTを指定します: ```java Braze.getInstance(this).changeUser("NEW-USER-ID", "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```java Braze.getInstance(this).setSdkAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` [`changeUser`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/change-user.html)の呼び出し時にJWTを指定します: ```kotlin Braze.getInstance(this).changeUser("NEW-USER-ID", "JWT-FROM-SERVER") ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```kotlin Braze.getInstance(this).setSdkAuthenticationSignature("NEW-JWT-FROM-SERVER") ``` [`changeUser`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/changeuser(userid:sdkauthsignature:fileid:line:))の呼び出し時にJWTを指定します: ```objc [AppDelegate.braze changeUser:@"userId" sdkAuthSignature:@"JWT-FROM-SERVER"]; ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```objc [AppDelegate.braze setSDKAuthenticationSignature:@"NEW-JWT-FROM-SERVER"]; ``` [`changeUser`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/changeuser(userid:sdkauthsignature:fileid:line:))の呼び出し時にJWTを指定します: ```swift AppDelegate.braze?.changeUser(userId: "userId", sdkAuthSignature: "JWT-FROM-SERVER") ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```swift AppDelegate.braze?.set(sdkAuthenticationSignature: "NEW-JWT-FROM-SERVER") ``` [`changeUser`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#changeuser)の呼び出し時にJWTを指定します: ```dart braze.changeUser("userId", sdkAuthSignature: "JWT-FROM-SERVER") ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```dart braze.setSdkAuthenticationSignature("NEW-JWT-FROM-SERVER") ``` `changeUser`の呼び出し時にJWTを指定します: ```dart import 'package:braze_plugin/braze_plugin.dart'; BrazePlugin braze = BrazePlugin(); braze.changeUser("NEW-USER-ID", sdkAuthSignature: "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```dart import 'package:braze_plugin/braze_plugin.dart'; BrazePlugin braze = BrazePlugin(); braze.setSdkAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` `ChangeUser`の呼び出し時にJWTを指定します: ```csharp BrazeBinding.ChangeUser("NEW-USER-ID", "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```csharp BrazeBinding.SetSdkAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` `changeUser`の呼び出し時にJWTを指定します: ```javascript BrazePlugin.changeUser("NEW-USER-ID", "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```javascript BrazePlugin.setSdkAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` `ChangeUser`の呼び出し時にJWTを指定します: **iOS** ```csharp Braze.SharedInstance?.ChangeUser("NEW-USER-ID", "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```csharp Braze.SharedInstance?.SetSDKAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` **Android** ```csharp Braze.GetInstance(this).ChangeUser("NEW-USER-ID", "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```csharp Braze.GetInstance(this).SetSdkAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` Braze Expoプラグインを使用する際は、同じReact Native SDKメソッドを使います。`changeUser`の呼び出し時にJWTを指定します: ```typescript import Braze from '@braze/react-native-sdk'; Braze.changeUser("NEW-USER-ID", "JWT-FROM-SERVER"); ``` あるいは、セッションの途中でユーザーのトークンをリフレッシュした場合: ```typescript import Braze from '@braze/react-native-sdk'; Braze.setSdkAuthenticationSignature("NEW-JWT-FROM-SERVER"); ``` #### ステップ2.3:無効なトークンのコールバック関数を登録する {#sdk-callback} この機能が[必須](#enforcement-options)に設定されている場合、以下のシナリオでSDKリクエストがBrazeによって拒否されます: - Braze APIが受信した時点でJWTの有効期限が切れていた - JWTが空または欠落していた - Brazeダッシュボードにアップロードした公開鍵でJWTの検証に失敗した `subscribeToSdkAuthenticationFailures`を使用して、これらのいずれかの理由でSDKリクエストが失敗したときに通知を受け取るようにサブスクライブできます。コールバック関数には、関連する[`errorCode`](#error-codes)、エラーの`reason`、リクエストの`userId`(ユーザーは匿名にはなれません)、およびエラーを引き起こした認証トークン(JWT)を含むオブジェクトが渡されます。 失敗したリクエストは、アプリが新しい有効なJWTを提供するまで、定期的に再試行されます。そのユーザーがまだログインしている場合、このコールバックをサーバーに新しいJWTを要求する機会として使用し、この新しい有効なトークンをBraze SDKに提供することができます。 認証エラーが発生した場合は、エラー内の`userId`が現在ログイン中のユーザーと一致するか確認し、サーバーから新しい署名を取得してBraze SDKに提供してください。これらのエラーを監視サービスやエラーレポートサービスに記録することもできます。 **Tip:** これらのコールバックメソッドは、独自の監視サービスやエラーログサービスを追加して、Brazeリクエストが拒否される頻度を追跡するのに最適な場所です。 ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToSdkAuthenticationFailures((error) => { console.error("SDK authentication failed:", error); console.log("Error code:", error.errorCode); console.log("User ID:", error.userId); // Note: Do not log error.signature as it contains sensitive authentication credentials // Verify the error.userId matches the currently logged-in user // Fetch a new token from your server and set it fetchNewSignature(error.userId).then((newSignature) => { braze.setSdkAuthenticationSignature(newSignature); }); }); ``` ```typescript import Braze from '@braze/react-native-sdk'; const sdkAuthErrorSubscription = Braze.addListener( Braze.Events.SDK_AUTHENTICATION_ERROR, (error) => { console.log(`SDK Authentication for ${error.userId} failed with error code ${error.errorCode}.`); const updated_jwt = getNewTokenSomehow(error); Braze.setSdkAuthenticationSignature(updated_jwt); } ); // Don't forget to remove the listener when done // sdkAuthErrorSubscription.remove(); ``` ```java Braze.getInstance(this).subscribeToSdkAuthenticationFailures(error -> { String newToken = getNewTokenSomehow(error); Braze.getInstance(getContext()).setSdkAuthenticationSignature(newToken); }); ``` ```kotlin Braze.getInstance(this).subscribeToSdkAuthenticationFailures({ error: BrazeSdkAuthenticationErrorEvent -> val newToken: String = getNewTokenSomehow(error) Braze.getInstance(getContext()).setSdkAuthenticationSignature(newToken) }) ``` ```objc Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; braze.sdkAuthDelegate = delegate; AppDelegate.braze = braze; // Method to implement in delegate - (void)braze:(Braze *)braze sdkAuthenticationFailedWithError:(BRZSDKAuthenticationError *)error { NSLog(@"Invalid SDK Authentication Token."); NSString *newSignature = getNewTokenSomehow(error); [AppDelegate.braze setSDKAuthenticationSignature:newSignature]; } ``` ```swift let braze = Braze(configuration: configuration) braze.sdkAuthDelegate = delegate AppDelegate.braze = braze // Method to implement in delegate func braze(_ braze: Braze, sdkAuthenticationFailedWithError error: Braze.SDKAuthenticationError) { print("Invalid SDK Authentication Token.") let newSignature = getNewTokenSomehow(error) AppDelegate.braze?.set(sdkAuthenticationSignature: newSignature) } ``` ```dart braze.setBrazeSdkAuthenticationErrorCallback((BrazeSdkAuthenticationError error) async { print("Invalid SDK Authentication Token."); final newSignature = getNewTokenSomehow(error); braze.setSdkAuthenticationSignature(newSignature); }); ``` ```dart import 'package:braze_plugin/braze_plugin.dart'; BrazePlugin braze = BrazePlugin(); braze.setBrazeSdkAuthenticationErrorCallback((BrazeSdkAuthenticationError error) async { print("SDK Authentication for ${error.userId} failed with error code ${error.errorCode}."); String newSignature = getNewTokenSomehow(error); braze.setSdkAuthenticationSignature(newSignature); }); ``` **iOS** ネイティブのiOS実装でSDK認証デリゲートを設定します: ```csharp public class SdkAuthDelegate : BRZSdkAuthDelegate { public void Braze(Braze braze, BRZSDKAuthenticationError error) { Debug.Log("Invalid SDK Authentication Token."); string newSignature = GetNewTokenSomehow(error); BrazeBinding.SetSdkAuthenticationSignature(newSignature); } } ``` **Android** ```csharp Braze.GetInstance(this).SubscribeToSdkAuthenticationFailures((error) => { string newToken = GetNewTokenSomehow(error); Braze.GetInstance(this).SetSdkAuthenticationSignature(newToken); }); ``` ```javascript BrazePlugin.subscribeToSdkAuthenticationFailures((error) => { console.log(`SDK Authentication for ${error.user_id} failed with error code ${error.error_code}.`); const newSignature = getNewTokenSomehow(error); BrazePlugin.setSdkAuthenticationSignature(newSignature); }); ``` **iOS** `Braze`インスタンスにSDK認証デリゲートを設定します: ```csharp public class SdkAuthDelegate : BRZSdkAuthDelegate { public override void Braze(Braze braze, BRZSDKAuthenticationError error) { Console.WriteLine("Invalid SDK Authentication Token."); string newSignature = GetNewTokenSomehow(error); Braze.SharedInstance?.SetSDKAuthenticationSignature(newSignature); } } // Set the delegate during initialization var configuration = new BRZConfiguration("YOUR-API-KEY", "YOUR-ENDPOINT"); configuration.Api.SdkAuthentication = true; var braze = new Braze(configuration); braze.SdkAuthDelegate = new SdkAuthDelegate(); ``` **Android** ```csharp Braze.GetInstance(this).SubscribeToSdkAuthenticationFailures((error) => { string newToken = GetNewTokenSomehow(error); Braze.GetInstance(this).SetSdkAuthenticationSignature(newToken); }); ``` Braze Expoプラグインを使用する際は、同じReact Native SDKメソッドを使います: ```typescript import Braze from '@braze/react-native-sdk'; const sdkAuthErrorSubscription = Braze.addListener( Braze.Events.SDK_AUTHENTICATION_ERROR, (error) => { console.log(`SDK Authentication for ${error.userId} failed with error code ${error.errorCode}.`); const updated_jwt = getNewTokenSomehow(error); Braze.setSdkAuthenticationSignature(updated_jwt); } ); // Don't forget to remove the listener when done // sdkAuthErrorSubscription.remove(); ``` ### ステップ3:ダッシュボードで認証を有効にする {#braze-dashboard} 次に、前に設定したアプリのBrazeダッシュボードで認証を有効にできます。 BrazeダッシュボードでアプリのSDK認証設定が**必須**に設定されていない限り、SDKリクエストは認証なしで通常どおり処理され続けることに注意してください。 統合に何か問題が発生した場合(例えば、アプリがSDKにトークンを不正に渡している、またはサーバーが無効なトークンを生成している)、Brazeダッシュボードでこの機能を無効にすると、データは検証なしで通常通り流れるようになります。 #### 適用オプション {#enforcement-options} ダッシュボードの**設定の管理**ページでは、各アプリに3つのSDK認証ステートがあり、Brazeがどのようにリクエストを検証するかを制御します。 | 設定 | 説明 | | ------ | ---------- | | **無効** | Brazeは、ユーザーに提供されたJWTを検証しません。(デフォルト設定)| | **オプション** | Brazeは、ログインしているユーザーのリクエストを検証しますが、無効なリクエストは拒否しません。 | | **必須** | Brazeは、ログインしているユーザーのリクエストを検証し、無効なJWTは拒否します。| {: .reset-td-br-1 .reset-td-br-2 aria-label="適用オプション" } ![](https://www.braze.com/docs/ja/ja/assets/img/sdk-auth-settings.png?57ca6f4602ca213f2fc891c8c459c6f2) **オプション**設定は、この機能がアプリのSDKトラフィックに与える潜在的な影響を監視するのに便利な方法です。 無効なJWTは**オプション**と**必須**の両方の状態で報告されますが、**必須**状態でのみSDKリクエストが拒否され、アプリは再試行して新しいJWTをリクエストします。 ## 公開鍵の管理 {#key-management} ### 公開鍵を追加する {#adding-a-public-key} アプリごとに、プライマリ、セカンダリ、ターシャリの最大3つの公開キーを追加できます。必要に応じて、同じキーを複数のアプリに追加することもできます。公開鍵を追加するには: 1. Brazeダッシュボードに移動し、**設定** > **アプリ設定**を選択します。 2. 利用可能なアプリのリストからアプリを選びます。 3. **SDK認証**で、**公開キーを追加**を選択します。 4. オプションの説明を入力し、公開キーを貼り付け、**公開キーを追加**を選択します。 ### 新しいプライマリキーを割り当てる {#assign-a-new-primary-key} セカンダリキーまたはターシャリキーを新しいプライマリキーとして割り当てるには: 1. Brazeダッシュボードに移動し、**設定** > **アプリ設定**を選択します。 2. 利用可能なアプリのリストからアプリを選びます。 3. **SDK認証**でキーを選択し、**管理** > **プライマリキーに設定**を選択します。 ### キーを削除する {#deleting-a-key} プライマリキーを削除するには、まず[新たなプライマリキーを割り当て](#assign-a-new-primary-key)、それからキーを削除します。非プライマリキーを削除するには: 1. Brazeダッシュボードに移動し、**設定** > **アプリ設定**を選択します。 2. 利用可能なアプリのリストからアプリを選びます。 3. **SDK認証**でプライマリキー以外のキーを選択し、**管理** > **公開キーを削除**を選択します。 ## 分析 {#analytics} 各アプリには、この機能が**オプション**状態と**必須**状態にある間に収集されたSDK認証エラーの内訳が表示されます。 データはリアルタイムで利用でき、チャート上のポイントにカーソルを合わせると、指定した日付のエラーの内訳を確認できます。 ![認証エラーの発生件数を示すグラフ。また、エラーの総数、エラーの種類、調整可能な日付範囲も表示されます。](https://www.braze.com/docs/ja/ja/assets/img/sdk-auth-analytics.png?c6dc9b578383a57c21f77f032808930e){: style="max-width:80%"} ## エラーコード {#error-codes} | エラーコード | エラーの理由 | 説明 | 解決手順 | | -------- | ------------ | --------- | --------- | | 10 | `EXPIRATION_REQUIRED` | Brazeを使用する場合、有効期限は必須フィールドです。| JWT生成ロジックに`exp`または有効期限フィールドを追加してください。 | | 20 | `DECODING_ERROR` | 公開鍵が一致しないか、一般的な捕捉不能エラーが発生しました。| JWTをJWTテストツールにコピーして、JWTが無効な形式である理由を診断してください。 | | 21 | `SUBJECT_MISMATCH` | 期待されるサブジェクトと実際のサブジェクトが一致しません。| `sub`フィールドは、SDKの`changeUser`メソッドに渡されたユーザーIDと同じである必要があります。 | | 22 | `EXPIRED` | 提供されたトークンの有効期限が切れています。| 有効期限を延長するか、トークンが期限切れになる前に定期的に更新してください。 | | 23 | `INVALID_PAYLOAD` | トークンのペイロードが無効です。| JWTをJWTテストツールにコピーして、JWTが無効な形式である理由を診断してください。 | | 24 | `INCORRECT_ALGORITHM` | トークンのアルゴリズムはサポートされていません。| JWTを`RS256`暗号化方式に変更してください。その他のタイプはサポートされていません。 | | 25 | `PUBLIC_KEY_ERROR` | 公開鍵が適切な形式に変換できませんでした。| JWTをJWTテストツールにコピーして、JWTが無効な形式である理由を診断してください。 | | 26 | `MISSING_TOKEN` | リクエストにトークンが指定されていません。| `changeUser(id, token)`を呼び出す際にトークンを渡していることを確認し、そのトークンが空白でないことを確認してください。| | 27 | `NO_MATCHING_PUBLIC_KEYS` | 提供されたトークンに一致する公開鍵がありませんでした。| JWTで使用されている秘密キーは、アプリに設定されている公開キーのいずれとも一致しません。このAPIキーに対応するワークスペース内の正しいアプリに公開キーを追加したことを確認してください。| | 28 | `PAYLOAD_USER_ID_MISMATCH` | リクエストのペイロード内のユーザーIDがすべて、要求通りに一致しているわけではありません。| これは予期しないエラーであり、不正なペイロードを引き起こす可能性があります。サポートチケットを開いてお問い合わせください。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="エラーコード" } ## よくある質問(FAQ) {#faq} #### この機能はすべてのアプリで同時に有効にする必要がありますか? {#faq-app-by-app} いいえ、この機能は特定のアプリに対して有効にすることができ、すべてのアプリで一度に使用する必要はありません。 #### アプリの古いバージョンを使っているユーザーはどうなりますか? {#faq-sdk-backward-compatibility} この機能を適用し始めると、古いバージョンのアプリによるリクエストはBrazeによって拒否され、SDKによって再試行されます。ユーザーがアプリをサポートされたバージョンにアップグレードすると、キューに入れられたリクエストは再び受け入れられるようになります。 可能であれば、他の必須アップグレードと同様に、ユーザーにアップグレードを勧めてください。あるいは、許容できる割合のユーザーがアップグレードしたことを確認するまで、この機能を[オプション](#enforcement-options)にしておくこともできます。 #### JWTを生成するときには、どのような有効期限を使用する必要がありますか? {#faq-expiration} 平均セッション期間、セッションCookie/トークンの有効期限、またはアプリケーションが現在のユーザープロファイルを更新する頻度のうち、高い方の値を使用することをお勧めします。 #### ユーザーのセッションの途中でJWTの有効期限が切れた場合はどうなりますか? {#faq-jwt-expiration} ユーザーのトークンがセッション中に期限切れになると、SDKは[コールバック関数](#sdk-callback)を呼び出して、Brazeにデータを送信し続けるために新しいJWTが必要であることをアプリに知らせます。 #### サーバー側の統合が壊れ、JWTを作成できなくなった場合はどうなりますか? {#faq-server-downtime} サーバーがJWTを提供できない場合、または統合に問題がある場合は、Brazeダッシュボードでいつでも機能を無効にできます。 一度無効にすると、保留中の失敗したSDKリクエストは最終的にSDKによって再試行され、Brazeによって受け入れられます。 #### なぜこの機能では、共有シークレットではなく公開キー/秘密キーを使うのでしょうか? {#faq-shared-secrets} 共有シークレットを使う場合、Brazeのダッシュボードページなど、その共有シークレットにアクセスできる人なら誰でも、トークンを生成してエンドユーザーになりすますことができます。 代わりに、公開キーと秘密キーを使用します。これにより、Brazeの従業員でさえ(ましてや御社のユーザーは言うまでもなく)あなたの秘密キーにアクセスできません。 #### 拒否されたリクエストはどのように再試行されますか? {#faq-retry-logic} 認証エラーが原因でリクエストが拒否されると、SDKはユーザーのJWTを更新するために使用されるコールバックを呼び出します。 リクエストはエクスポネンシャルバックオフアプローチを使用して定期的に再試行されます。50回連続で失敗すると、次のセッション開始まで再試行は一時停止されます。各SDKには、手動でデータフラッシュをリクエストするメソッドもあります。 #### 匿名ユーザーに対してSDK認証は使えますか? {#faq-anonymous-users} いいえ。SDK認証はWebサイトが誰かのIDを主張することで機能するため、識別済みのユーザーにのみ適用されます。匿名ユーザーの場合、主張するIDがありません。 適用は`changeUser`が呼び出された後に開始されます。ユーザーが識別される前(例えば、サインアップ前に匿名で閲覧している間)は、SDKはJWTなしでBrazeにデータを送信できます。`changeUser`が呼び出された後、その識別済みプロファイルに対するリクエストには有効なJWTが必要になります。 つまり、一般的なユーザージャーニーは次のようになります: 1. ユーザーがWebサイトにアクセスするか、アプリを匿名で開きます。BrazeはJWTなしでこのアクティビティを収集します。 2. ユーザーがサインアップまたはログインし、アプリが`external_id`を指定して`changeUser`を呼び出します。 3. Brazeはそのユーザーのアクティビティの収集を続け、その識別済みプロファイルに対するリクエストにはSDK認証が適用されます。 #### SDK認証はユーザーエイリアスで機能しますか? {#faq-aliases} いいえ。SDK認証には`external_id`が必要です。`braze_id`または`alias_id`のみが利用可能な場合は設定できないため、エイリアスのみのプロファイルではSDK認証を使用できません。 #### SDK認証を有効にすると、未認証のアクティビティ収集がブロックされますか? {#faq-unauthenticated-collection} いいえ。SDK認証は正当な匿名アクティビティの収集をブロックしません。`changeUser`でプロファイルが識別された後にのみ適用されます。 # Braze SDKのデバッグ Source: /docs/ja/developer_guide/sdk_integration/debugging/index.md # Braze SDKのデバッグ {#debugging-the-braze-sdk} > Braze SDKの組み込みデバッガーを使用する方法を説明します。これにより、アプリで詳細ログを有効にする必要なく、SDK対応チャネルの問題をトラブルシューティングできます。 **Tip:** より詳細な調査のために、[詳細ログを有効にして](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging)詳細なSDK出力をキャプチャしたり、特定のチャネルに関する[詳細ログの読み方を学習](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/reading_verbose_logs)したりすることもできます。 ## 前提条件 {#prerequisites} Braze SDKデバッガーを使用するには、「View PII」および「View User Profiles (PII Redacted)」の権限が必要です。デバッグセッションのログをダウンロードするには、「Export User Data」権限も必要です。さらに、Braze SDKは以下の最小バージョンを満たしているか、参照している必要があります。 `Braze.configuration.logger.level`が`.disabled`の場合にデバッガーログを収集するには、Swift SDK 11.9.0以降を使用してください。詳細については、[Swift変更ログ](https://www.braze.com/docs/ja/ja/developer_guide/changelogs#swift_fixed-12)を参照してください。 ## Braze SDKのデバッグ **Tip:** Braze Web SDKのデバッグを有効にするには、[URLパラメーターを使用](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/initial_sdk_setup#logging)します。 ### ステップ 1: アプリを閉じる {#step-1-close-your-app} デバッグセッションを開始する前に、現在問題が発生しているアプリを閉じます。セッションの開始時にアプリを再起動できます。 ### ステップ 2: デバッグセッションを作成する {#step-2-create-a-debugging-session} Brazeで**設定**に移動し、**設定およびテスト**で**SDKデバッガー**を選択します。 ![「SDKデバッガー」がハイライトされた「設定およびテスト」セクション。](https://www.braze.com/docs/ja/ja/assets/img/sdk_debugger/select_sdk_debugger.png?2387a3520a04597abdb85a9a100baa87) **デバッグセッションを作成**を選択します。 ![「SDKデバッガー」ページ。](https://www.braze.com/docs/ja/ja/assets/img/sdk_debugger/select_create_debugging_session.png?b8edf96c40967f310493fcb8de32a9de) ### ステップ 3: ユーザーを選択する {#step-3-select-a-user} メールアドレス、`external_id`、ユーザーエイリアス、またはプッシュトークンを使用してユーザーを検索します。セッションを開始する準備ができたら、**ユーザーを選択**を選択します。 ![選択したユーザーのデバッグページ。](https://www.braze.com/docs/ja/ja/assets/img/sdk_debugger/search_and_select_user.png?bab3a4f1e879e4148badff07a76a1385){: style="max-width:85%;"} ### ステップ 4: アプリを再起動する {#step-4-relaunch-the-app} まずアプリを起動し、デバイスがペアリングされていることを確認します。ペアリングが成功した場合は、アプリを再起動します—これにより、アプリの初期化ログが完全にキャプチャされます。 ### ステップ 5: 再現ステップを完了する {#step-5-complete-the-reproduction-steps} アプリを再起動した後、手順に従ってエラーを再現します。 **Tip:** エラーを再現する際は、[高品質なログ](#step-6-export-your-session-logs-optional)を作成できるように、再現手順をできるだけ正確に実行してください。 ### ステップ 6: セッションを終了する {#step-6-end-your-session} 再現手順が完了したら、**End Session** > **Close**を選択します。 ![「End Session」ボタンが表示されているデバッグセッション。](https://www.braze.com/docs/ja/ja/assets/img/sdk_debugger/close_debugging_session.png?1acb6a88b82a111e7d69f7d7ccbd18b5){: style="max-width:85%;"} **Note:** セッションの長さとネットワーク接続状況に応じて、ログの生成に数分かかる場合があります。 ### ステップ 7: セッションを共有またはエクスポートする(オプション) {#step-7-share-or-export-your-session-optional} セッション終了後、セッションログをCSVファイルとしてエクスポートできます。また、他のユーザーは**Session ID**を使用してデバッグセッションを検索できるため、ログを直接送信する必要はありません。 ![セッション終了後に「Export Logs」と「Copy Session ID」が表示されたデバッグページ。](https://www.braze.com/docs/ja/ja/assets/img/sdk_debugger/copy_id_and_export_logs.png?6e9b1911ea1e119ed20a667f37ab535a) # 詳細なログ記録 Source: /docs/ja/developer_guide/sdk_integration/verbose_logging/index.md # 詳細なログ記録 > 詳細なログ出力は、Braze SDKからの詳細かつ低レベルな情報を提供する。これにより、SDKの初期化方法、サーバーとの通信方法、プッシュ通知、アプリ内メッセージ、コンテンツカードといったメッセージングチャネルの処理方法が可視化される。 何かが期待通りに動作しない場合——例えばプッシュ通知が届かない、アプリ内メッセージが表示されない、ユーザーデータが同期されない——詳細ログは根本原因の識別に役立つ。推測する代わりに、SDKが各ステップで何をしているかを正確に確認できる。 **Tip:** 手動で詳細ログのイネーブルメントをせずにデバッグしたい場合、[SDKデバッガー](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/debugging)を使ってBrazeダッシュボード内で直接デバッグセッションを作成できる。 ## 詳細ログを記録するタイミング 必要な時に詳細ログを有効にしろ: - **SDKの初期化を確認する**:SDKが正しいAPIキーとエンドポイントで正しく起動することを確認せよ。 - **メッセージ配信のトラブルシューティング**:プッシュトークンが登録されているか、アプリ内メッセージがトリガーされているか、コンテンツカードが同期されているかを確認する。 - **ディープリンクをデバッグする**:SDKがプッシュ通知、アプリ内メッセージ、またはコンテンツカードからのディープリンクを受信し、開封することを確認せよ。 - **セッショントラッキングを検証する**:セッションの開始と終了が予定通りであることを確認する。 - **接続の問題を診断する**:SDKとBrazeサーバー間のネットワークリクエストとレスポンスを検査する。 ## 詳細ログ記録のイネーブルメント **Important:** 詳細ログは開発者およびテスト環境でのみ使用することを意図している。本番環境へアプリを公開する前に詳細ログ記録を無効化し、機密情報が漏洩するのを防ぐこと。 メソッド`Application.onCreate()`内で他のSDK呼び出しを行う前に詳細ログ記録をイネーブルにすると、最も完全な出力を取得できる。 **コードでは:** ```java BrazeLogger.setLogLevel(Log.VERBOSE); ``` `````````kotlin BrazeLogger.logLevel = Log.VERBOSE ``` **In `braze.xml`:** `````````xml 2 ``` 詳細ログのイネーブルメントを確認するには、Logcat出力で\``V/Braze`verbose`を検索する。以下に例を示します。 ``` 2077-11-19 16:22:49.591 ? V/Braze v9.0.01 .bo.app.d3: Request started ``` 詳細については、[Android SDKのロギングを](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration#android_enabling-logs)参照せよ。 初期化時に、オブジェクト`Braze.Configuration`のログ`.debug`レベルを に設定する。 `````````swift let configuration = Braze.Configuration( apiKey: "", endpoint: "" ) configuration.logger.level = .debug let braze = Braze(configuration: configuration) ``` `````````objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:@"" endpoint:@""]; [configuration.logger setLevel:BRZLoggerLevelDebug]; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; ``` レベル`.debug`は最も詳細な出力を示すため、トラブルシューティングに推奨される。詳細については、[SWIFT SDKのロギングを](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration#swift_log-levels)参照せよ。 URLパラメータとして\`add`?brazeLogging=true``を追加するか、SDK初期化時にロギングのイネーブルメントを行う。 `````````javascript braze.initialize('YOUR-API-KEY', { baseUrl: 'YOUR-SDK-ENDPOINT', enableLogging: true }); ``` 初期化後にログ記録のオンオフを切り替えることもできる。 `````````javascript braze.toggleLogging(); ``` ログはブラウザの開発者の開発ツールのコンソールタブに表示される。詳細については、[Web SDKのログ記録を](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration#web_logging)参照せよ。 1. [**Braze**] > [**Braze 構成**] の順に移動して、[Braze 構成設定] を開きます。 2. **「Show Braze Android 設定**」ドロップダウンを選択する。 3. **SDK**ログレベルフィールドに「.」と入力する`0`。 SDK設定時にログレベルを設定する: `````````javascript const configuration = new Braze.BrazeConfiguration('YOUR-API-KEY', 'YOUR-SDK-ENDPOINT'); configuration.logLevel = Braze.LogLevel.Verbose; ``` ## ログの収集 詳細ログ記録のイネーブルメント後、トラブルシューティング対象の問題を再現し、プラットフォームのコンソールまたはデバッグツールからログを収集する。 Android Studioで**Logcat**を使ってログをキャプチャする: 1. デバイスを接続するか、エミュレータを起動する。 2. Android Studioで、下部のパネルから**Logcat**を開け。 3. または`V/Braze`でフィルターをかけて、`D/Braze`Braze SDKの出力を分離する。 4. 問題を再現する。 5. 関連するログをコピーして、テキストファイルに保存する。 MacOSの**コンソール**アプリを使ってログをキャプチャする: 1. 詳細ログ記録を有効にした状態で、アプリを端末にインストールせよ。 2. デバイスをMacに接続せよ。 3. **コンソール**アプリを開封し、**デバイスの**サイドバーから自分のデバイスを選ぶ。 4. 検索バーで `BrazeKit`または `Braze`でフィルターをかける。 5. 問題を再現する。 6. 関連するログをコピーして、テキストファイルに保存する。 ブラウザの開発者ツールを使え: 1. ブラウザの開発者ツールを開封(通常は**F12**キーかCmd+Option+Iキーだ)。 2. **コンソール**タブに移動する。 3. 問題を再現する。 4. コンソールの出力をコピーして、テキストファイルに保存しろ。 **Tip:** Brazeサポート向けにログを収集する際は、アプリ起動前からログ記録を開始し、問題発生後も十分に経過するまで継続すること。これにより、一連の出来事の全容を把握できる。 ## 冗長なログを読む 詳細ログは一貫した構造に従っているため、SDKの動作を追跡するのに役立つ。特定のチャネルのログ出力を学習する方法、具体的には確認すべきキーエントリや一般的なトラブルシューティングパターンについては、「[詳細ログの読み方](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/reading_verbose_logs)」を参照せよ。 ## Brazeサポートとのログ共有 SDKに関する問題でBrazeサポートに連絡する際は、以下の情報を含めてください: 1. **詳細なログファイル**:アプリ起動前から問題発生までの完全なログ記録。 2. **再現ステップ**:問題をトリガーするアクションの明確な説明。 3. **期待される動作と実際の動作**:君が予想していたことと、実際に起きたこと。 4. **SDKバージョン**:使用しているBraze SDKのバージョン。 5. **プラットフォームとOSのバージョン**:例えば、iOS 18.0、Android 14、あるいはChrome 120といったものだ。 # 詳細ログの読み取り Source: /docs/ja/developer_guide/sdk_integration/reading_verbose_logs/index.md # 詳細ログの読み取り {#reading-verbose-logs} > このページでは、Braze SDKからの詳細ログ出力を解釈する方法について説明します。各メッセージングチャネルについて、確認すべき主要なログエントリ、その意味、および注意すべき一般的な問題を紹介します。 始める前に、[詳細ログの有効化](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging)が完了していることと、お使いのプラットフォームでログを収集する方法を把握していることを確認してください。 ## セッション {#sessions} セッションはBrazeの分析とメッセージ配信の基盤です。アプリ内メッセージやContent Cardsを含む多くのメッセージング機能は、正常に動作するために有効なセッションが開始されている必要があります。セッションが正しく記録されていない場合は、まずこの問題を調査してください。セッショントラッキングの有効化に関する詳細については、[ステップ5: ユーザーセッショントラッキングを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=android#android_step-5-enable-user-session-tracking)を参照してください。 ### 主要なログエントリ {#key-log-entries} **セッション開始:** ``` Started user session (id: ) ``` **セッション終了:** ``` Ended user session (id: , duration: s) Logged event: - userId: - sessionId: - data: sessionEnd(duration: ) ``` **セッション開始:** 以下のエントリを確認してください: ``` New session created with ID: Session start event for new session received Completed the openSession call Opened session with activity: ``` 設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)へのネットワークリクエストをフィルターし、セッション開始(`ss`)イベントを確認します。 **セッション終了:** ``` Closed session with activity: Closed session with session ID: Requesting data flush on internal session close flush timer. ``` ### 確認すべき事項 {#what-to-check} - アプリ起動時にセッション開始ログが表示されることを確認してください。 - セッション開始が表示されない場合は、SDKが正しく初期化されていること、および`openSession`(Android)が呼び出されていることを確認してください。 - Androidでは、Brazeエンドポイントへのネットワークリクエストが行われていることを確認してください。表示されない場合は、APIキーとエンドポイントの設定を確認してください。 ## プッシュ通知 {#push-notifications} プッシュ通知ログは、デバイストークンが登録されていること、通知が配信されていること、クリックイベントがトラッキングされていることを確認するのに役立ちます。 ### トークン登録 {#token-registration} セッションが開始されると、SDKはデバイスのプッシュトークンをBrazeに登録します。 ``` Updated push notification authorization: - authorization: authorized Received remote notifications device token: ``` 設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)へのリクエストをフィルターし、リクエスト本体の属性内で`push_token`を探してください: ``` "attributes": [ { "push_token": "", "user_id": "" } ] ``` また、デバイス情報に以下が含まれていることを確認してください: ``` "device": { "ios_push_auth": "authorized", "remote_notification_enabled": 1 } ``` FCM登録ログを探してください: ``` Registering for Firebase Cloud Messaging token using sender id: ``` 以下を確認してください: - `com_braze_firebase_cloud_messaging_registration_enabled`が`true`であること。 - FCM送信者IDがFirebaseプロジェクトと一致していること。 よくあるエラーは`SENDER_ID_MISMATCH`で、設定された送信者IDがFirebaseプロジェクトと一致していないことを意味します。 ### 確認すべき事項 - リクエスト本体に`push_token`がない場合、トークンが取得されていません。アプリの設定でプッシュ通知の設定を確認してください。 - `ios_push_auth`が`denied`または`provisional`と表示される場合、ユーザーは完全なプッシュ権限を許可していません。 - Androidで`SENDER_ID_MISMATCH`が表示される場合は、FCM送信者IDをFirebaseプロジェクトと一致するように更新してください。 ### プッシュ配信とクリック {#push-delivery-and-click} プッシュ通知がタップされると、SDKは処理イベントとクリックイベントを記録します。 ``` Processing push notification: - date: - silent: false - userInfo: { "ab": { ... }, "ab_uri": "", "aps": { "alert": { "body": "", "title": "" } } } ``` 続いてクリックイベント: ``` Logged event: - userId: - sessionId: - data: pushClick(campaignId: ...) ``` プッシュ通知にディープリンクが含まれている場合、以下も表示されます: ``` Opening '': - channel: notification - useWebView: false - isUniversalLink: false ``` ``` BrazeFirebaseMessagingService: Got Remote Message from FCM ``` 続いてプッシュペイロードと表示ログが出力されます。ディープリンクについては、ディープリンクデリゲートまたは`UriAction`エントリを探してください。 ### 確認すべき事項 - プッシュペイロードに、期待される`title`、`body`、およびディープリンク(`ab_uri`)が含まれていることを確認してください。 - タップ後に`pushClick`イベントが記録されていることを確認してください。 - クリックイベントが記録されていない場合は、アプリデリゲートまたは通知ハンドラーがプッシュイベントをBraze SDKに正しく転送しているか確認してください。 ## アプリ内メッセージ {#in-app-messages} アプリ内メッセージのログは、サーバーからの配信、イベントに基づくトリガー、表示、インプレッションの記録、クリックのトラッキングという全ライフサイクルを示します。 ### メッセージ配信 {#message-delivery} ユーザーがセッションを開始し、アプリ内メッセージの受信対象である場合、SDKはサーバーからメッセージペイロードを受信します。 設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)からの応答で、アプリ内メッセージデータを含むものをフィルターしてください。 レスポンス本体にはメッセージペイロードが含まれており、以下の内容が含まれます: ``` "templated_message": { "data": { "message": "...", "type": "HTML", "message_close": "SWIPE", "trigger_id": "" }, "type": "inapp" } ``` トリガーイベントに一致するログを探してください: ``` Triggering action: ``` これは、アプリ内メッセージがトリガーイベントに一致したことを確認するものです。 ### メッセージ表示とインプレッション {#message-display-and-impression} ``` In-app message ready for display: - triggerId: (campaignId: , ...) - extras: { ... } ``` 続いてインプレッションログ: ``` Logged event: - userId: - sessionId: - data: inAppMessageImpression(triggerIds: [...]) ``` ``` handleExistingInAppMessagesInStackWithDelegate:: Displaying in-app message ``` ### クリックとボタンイベント {#click-and-button-events} ユーザーがボタンをタップするか、メッセージを閉じた場合: ``` Logged event: - userId: - sessionId: - data: inAppMessageButtonClick(triggerIds: [...], buttonId: "") ``` これ以上一致するトリガーメッセージがない場合、以下も表示されます: ``` No matching trigger for event. ``` このイベントに対して追加のアプリ内メッセージが設定されていない場合、これは想定される動作です。 設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)へのリクエストをフィルターし、リクエスト本体内でイベント名`sbc`(ボタンクリック)または`si`(インプレッション)を探してください。 ### 確認すべき事項 - アプリ内メッセージが表示されない場合は、まずセッション開始が記録されているか確認してください。 - 設定済みのBrazeエンドポイントからの応答をフィルターし、メッセージペイロードが配信されたことを確認してください。 - インプレッションが記録されていない場合は、ログ記録を抑制するカスタム`inAppMessageDisplay`デリゲートを実装していないか確認してください。 - 「No matching trigger for event」と表示される場合、これは正常であり、そのイベントに対して追加のアプリ内メッセージが設定されていないことを示しています。 ## Content Cards Content Cardsのログは、カードがデバイスに同期され、ユーザーに表示され、インタラクション(インプレッション、クリック、非表示操作)がトラッキングされていることを確認するのに役立ちます。 ### カード同期 {#card-sync} Content Cardsはセッション開始時と手動更新が要求された時に同期されます。セッションが記録されていない場合、Content Cardsは表示されません。 設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)からの応答で、カードデータを含むものをフィルターしてください。 レスポンス本体にはカードデータが含まれており、以下のような内容です: ``` "cards": [ { "id": "", "tt": "", "ds": "", "tp": "short_news", "v": 0, "cl": 0, "p": 1 } ] ``` 主要なフィールド: - `v`(閲覧済み):`0` = 未閲覧、`1` = 閲覧済み - `cl`(クリック済み):`0` = 未クリック、`1` = クリック済み - `p`(固定済み):`0` = 固定されていない、`1` = 固定されている - `tp`(タイプ):`short_news`、`captioned_image`、`classic`など ``` Requesting content cards sync. ``` 続いて、設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)へのPOSTリクエストが送信されます。このリクエストにはユーザー情報とデバイス情報が含まれます。 ### インプレッション、クリック、非表示 {#impressions-clicks-and-dismissals} **インプレッション:** ``` Logged event: - userId: - sessionId: - data: contentCardImpression(cardIds: [...]) ``` **クリック:** ``` Logged event: - userId: - sessionId: - data: contentCardClick(cardIds: [...]) ``` カードにURLがある場合、以下も表示されます: ``` Opening '': - channel: contentCard - useWebView: true ``` **非表示:** ``` Logged event: - userId: - sessionId: - data: contentCardDismissed(cardIds: [...]) ``` 設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)へのリクエストをフィルターし、リクエスト本体内のイベント名を確認してください: - `cci` — Content Cardsのインプレッション - `ccc` — Content Cardsのクリック - `ccd` — Content Cardsの非表示 ### 確認すべき事項 - **カードが表示されない**:セッション開始が記録されていることを確認してください。Content Cardsは同期するためにアクティブなセッションが必要です。 - **新規ユーザーにカードが表示されない**:新規ユーザーは初回セッションではContent Cardsが表示されない場合があります。次のセッションまでお待ちください。これは想定される動作です。 - **カードがサイズ制限を超えている**:2KBを超えるContent Cardsは表示されず、メッセージは中断されます。 - **キャンペーンを停止した後もカードが残る**:キャンペーンを停止した後に同期が完了したことを確認してください。同期が成功すると、Content Cardsはデバイスから削除されます。キャンペーンを停止する際は、ユーザーフィードからアクティブなカードを削除するオプションが選択されていることを確認してください。 ## ディープリンク {#deep-links} ディープリンクのログは、プッシュ通知、アプリ内メッセージ、Content Cardsに表示されます。ログ構造はソースチャネルに関係なく一貫しています。 SDKがディープリンクを処理する場合: ``` Opening '': - channel: - useWebView: false - isUniversalLink: false - extras: { ... } ``` ``は`notification`、`inAppMessage`、または`contentCard`のいずれかです。 ディープリンクについては、Logcat内の**Deep Link Delegate**または**UriAction**エントリを探してください。ディープリンクの解決を独立してテストするには、以下のコマンドを実行してください: ```bash adb shell am start -W -a android.intent.action.VIEW -d "" "" ``` これにより、Braze SDKの外部でディープリンクが正しく解決されるかどうかを確認できます。 ### 確認すべき事項 - ディープリンクURLがキャンペーンで設定した内容と一致していることを確認してください。 - あるチャネル(例:プッシュ通知)ではディープリンクが機能するが、別のチャネル(例:Content Cards)では機能しない場合は、ディープリンク処理の実装がすべてのチャネルに対応しているか確認してください。 - iOSでは、ユニバーサルリンクには追加の処理が必要です。Brazeチャネルからユニバーサルリンクが機能しない場合は、アプリがURL処理用の`BrazeDelegate`プロトコルを実装しているか確認してください。 - Androidでは、カスタムハンドラーを使用する場合、自動ディープリンク処理が無効になっていることを確認してください。そうでなければ、デフォルトのハンドラーが実装と競合する可能性があります。 ## ユーザー識別 {#user-identification} ユーザーが`external_id`で識別されると、SDKはユーザー変更イベントを記録します。 ``` changeUser called with: ``` 知っておくべき重要な点: - ユーザーがログインしたら、できるだけ早く`changeUser`を呼び出してください。 - ユーザーがログアウトした場合、`changeUser`を呼び出して匿名ユーザーに戻す方法はありません。 - 匿名ユーザーを許可したくない場合は、セッション開始時またはアプリ起動時に`changeUser`を呼び出してください。 設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)へのリクエストをフィルターし、リクエスト本体内でユーザー識別情報を探してください: ``` "user_id": "" ``` ## ネットワークリクエスト {#network-requests} 詳細ログには、SDKがBrazeサーバーと通信する際の完全なHTTPリクエストとレスポンスの詳細が含まれます。これらは接続の問題を診断するのに役立ちます。 ### リクエスト構造 {#request-structure} 設定済みのBrazeエンドポイント(例:sdk.iad-01.braze.com)へのリクエストをフィルターしてください。リクエスト構造には以下が含まれます: ``` [http] request POST: - Headers: - Content-Type: application/json - X-Braze-Api-Key: - X-Braze-Req-Attempt: 1 - X-Braze-Req-Tokens-Remaining: - Body: { ... } ``` ``` Making request(id = ) to ``` ### 確認すべき事項 - **APIキー**:`X-Braze-Api-Key`がワークスペースのAPIキーと一致していることを確認してください。 - **エンドポイント**:リクエストURLが設定済みのSDKエンドポイントと一致していることを確認してください。 - **再試行回数**:`X-Braze-Req-Attempt`が1より大きい場合、SDKが失敗したリクエストを再試行していることを示しており、接続の問題がある可能性があります。 - **レート制限**:`X-Braze-Req-Tokens-Remaining`は残りのリクエストトークン数を示します。カウントが低い場合、SDKがレート制限に近づいている可能性があります。 - **リクエストが見つからない**:Androidでは、セッション開始後にBrazeエンドポイントへのリクエストが表示されない場合は、APIキーとエンドポイントの設定を確認してください。 ## 一般的なイベントの略称 {#common-event-abbreviations} 詳細ログのペイロードにおいて、Brazeは省略形のイベント名を使用します。以下は参照用の一覧です: | 略称 | イベント | |---|---| | `ss` | セッション開始 | | `se` | セッション終了 | | `si` | アプリ内メッセージのインプレッション | | `sbc` | アプリ内メッセージのボタンクリック | | `cci` | Content Cardsのインプレッション | | `ccc` | Content Cardsのクリック | | `ccd` | Content Cardsの非表示 | | `lr` | 位置情報の記録 | {: .reset-td-br-1 .reset-td-br-2 aria-label="一般的なイベントの略称" } ## トラブルシューティング {#troubleshooting} ### ユーザープロファイルのセッション数が0と記録されるのはどのような場合ですか? {#when-might-a-user-have-0-sessions-recorded-against-their-profile} ユーザープロファイルのセッション数が0と表示されるのは、REST API([`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track))またはCSVインポートで**初回セッション**や**最終セッション**のフィールドを含めずにユーザーをインポートした場合です。セッションは、ユーザーがSDKを通じてアプリを操作した際に記録されます。詳細については、[ユーザープロファイルのセッション数が0](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions#user-profile-has-0-sessions)を参照してください。 ### SDKとREST APIを同時に使用した場合のユーザーデータの不一致 {#user-data-discrepancies-when-using-the-sdk-and-rest-api-together} SDKとREST APIを同時に使用すると、競合によりデータの不一致が発生する可能性があります。`changeUser()`を呼び出した後は、重要なREST API呼び出しを行う前にSDKが保留中のデータをフラッシュするのを待ち、時間的に重要な更新のバッチ処理を避け、SDKとAPIリクエストの間に短い遅延を入れることを検討してください。`changeUser()`の動作については、[changeUser()の仕組み](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_ids#how-changeuser-works)を参照してください。 ### データがBrazeに到達しない {#data-not-reaching-braze} データがBrazeに到達しない場合は、ファイアウォールがBraze APIエンドポイントおよびCDNプロバイダーへの送信トラフィックを許可していることを確認してください。問題が発生している間にMTRテストを実行し、[Fastly Debug](https://www.fastly-debug.com/)を使用してください。許可リストへの登録と接続のトラブルシューティングについては、[APIネットワーク接続の問題](https://www.braze.com/docs/ja/ja/api/network_connectivity_issues)を参照してください。 # Braze SDKのレート制限 Source: /docs/ja/developer_guide/sdk_integration/rate_limits/index.md # Braze SDKのレート制限 {#braze-sdk-rate-limits} > Braze SDKのインテリジェントなクライアントサイドレート制限について説明します。バッテリー寿命の最適化、帯域幅の使用量の削減、信頼性の高いデータ配信を実現します。 ## SDKのレート制限を理解する {#understanding-sdk-rate-limits} Braze SDKのレート制限は、以下の機能を用いてパフォーマンスを最適化し、バッテリー消費を最小限に抑え、データ使用量を削減し、信頼性の高いデータ配信を確保します。 ### 非同期処理 {#asynchronous-processing} Braze SDKはレート制限にトークンバケットアルゴリズムを使用します。この手法は、長期的なレートコントロールを維持しながら、アクティビティのバーストを可能にします。トークンバケットは、リクエストを厳密なキューで処理する代わりに、非同期的に動作します。 - **トークン生成**: トークンはバケットに一定の速度で補充されます。 - **リクエスト処理**: トークンが利用可能な時点で到着したSDK呼び出しは、他の呼び出しがいつ到着したかに関係なく、直ちに処理されます。 - **厳密な順序付けなし**: リクエストは順番待ちをしません。複数の呼び出しが次の利用可能なトークンを競い合うことがあります。 - **バースト処理**: リクエスト時に十分なトークンが利用可能であれば、短時間のアクティビティバーストが許可されます。 - **レートコントロール**: 長期的なスループットは、安定したトークンの補充レートによって制限されます。 この非同期フローにより、SDKは利用可能なネットワーク容量に素早く対応しつつ、予測可能な全体的なトラフィックレベルを維持できます。 ### 適応型レート制限 {#adaptive-rate-limiting} Braze SDKは、ネットワークインフラを保護し最適なパフォーマンスを維持するために、リアルタイムでレート制限を調整できます。このアプローチにより、以下が実現されます。 - **過負荷の防止**: ネットワークの混雑を避けるために制限を調整します。 - **パフォーマンスの最適化**: さまざまな条件下でもSDKの円滑な動作を維持します。 - **条件への適応**: 現在のネットワーク状況と使用パターンに基づいて適応します。 **Note:** 制限はリアルタイムで適応するため、正確なバケットサイズや静的な値は提供されません。ネットワークの状況や使用状況によって変わる可能性があります。 ### ネットワークの最適化 {#networking-optimizations} Braze SDKには、効率を向上させ、バッテリー消費を抑え、さまざまなネットワーク環境に対応するための組み込み機能がいくつか含まれています。 - **自動バッチ処理**: イベントをキューに入れ、効率的なバッチで送信します。 - **ネットワークを意識した動作**: 接続品質に基づいてフラッシュレートを調整します。 - **バッテリー最適化**: 無線の起動とネットワーク呼び出しを最小限に抑えます。 - **グレースフルデグラデーション**: ネットワーク状態が悪い場合でも機能を維持します。 - **バックグラウンド/フォアグラウンドの認識**: アプリのライフサイクルの変化に応じて動作を最適化します。 ## ベストプラクティス {#best-practices} レート制限の問題を避けるために、以下のベストプラクティスに従ってください。 | 推奨 | 非推奨 | | --- | --- | | 意味のあるユーザーアクションとマイルストーンをトラッキングする | あらゆる些細なインタラクションやUIイベントをトラッキングする | | 必要な場合にのみコンテンツを更新する | ユーザーアクション(スクロールイベントなど)のたびにコンテンツを更新する | | SDKにバッチ処理を自動的に行わせる | (どうしても必要な場合を除き)データの即時送信を強制する | | 分析に価値をもたらすイベントに焦点を当てる | 頻度を考慮せずにSDKメソッドを連続して呼び出す | {: .reset-td-br-1 .reset-td-br-2 aria-label="ベストプラクティス" } ## ヘルプを利用する {#getting-help} SDKのレート制限の問題が発生している場合は、以下のネットワーク関連メソッドを確認してください。 - `requestImmediateDataFlush()` - `requestContentCardsRefresh()` - `refreshFeatureFlags()` - `logCustomEvent()` - `logPurchase()` [Brazeサポート](https://www.braze.com/docs/ja/ja/user_guide/administer/personal/braze_support)に連絡する際は、使用している各ネットワークSDKメソッドについて以下の詳細を記載してください。 ```plaintext Method name: Frequency: [Describe how often this is called, e.g., at every app launch, once per session] Trigger/context: [Describe what causes it to be called, e.g., button click, scroll event] Code snippet: [Paste the exact code where this method is called, one snippet for each time it is called] Patterns in user flow that may cause bursts or excessive calls: [Describe here] ``` # BrazeをChatGPTアプリと統合する Source: /docs/ja/developer_guide/sdk_integration/chatgpt_apps/index.md # BrazeをChatGPTアプリと統合する {#integrate-braze-with-chatgpt-apps} > このガイドでは、BrazeをChatGPTアプリと統合し、AI搭載アプリケーション内で分析とイベントロギングを有効にする方法を説明します。 ![ChatGPTアプリに統合されたコンテンツカード。](https://www.braze.com/docs/ja/ja/assets/img/chatgpt_app_integration.png?78e00c2a0ba475aaf2cae479a9a5fa0b){: style="float:right;max-width:30%;border:none;" } ## 概要 {#overview} ChatGPTアプリは、AI対話型アプリケーションを構築するための強力なプラットフォームを提供します。BrazeをChatGPTアプリと統合することで、AI時代においてもファーストパーティデータのコントロールを維持し続けることができます。具体的には以下のことが可能です。 - ChatGPTアプリ内でのユーザーエンゲージメントと動作をトラッキングする(例:顧客がどの質問やチャット機能を利用しているかを特定する) - AIインタラクションパターンに基づいてBraze キャンペーンをセグメント化し、リターゲティングする(例:週に3回以上チャットを利用したユーザーにメールを送信する) ### 主な利点 {#key-benefits} - **カスタマージャーニーを自分のものに:** ユーザーがChatGPTを通じてブランドとやり取りする間も、その動作、好み、エンゲージメントパターンを把握し続けることができます。このデータはAIプラットフォームの分析だけでなく、Brazeユーザープロファイルに直接流れ込みます。 - **クロスプラットフォームリターゲティング:** ChatGPTアプリでのユーザーインタラクションをトラッキングし、AI利用パターンに基づいたパーソナライズ済みキャンペーンで、自社チャネル(メール、SMS、プッシュ通知、アプリ内メッセージ)全体でリターゲティングできます。 - **ChatGPTの会話に1:1のプロモーションコンテンツを返す:** チームがアプリ用に構築したカスタム対話型UIコンポーネントを使って、ChatGPT体験内で直接Brazeの[アプリ内メッセージ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages)、[Content Cards](https://www.braze.com/docs/ja/ja/user_guide/channels/content_cards)などを配信できます。 - **収益アトリビューション:** ChatGPTアプリのインタラクションから発生した購入とコンバージョンをトラッキングできます。 ## 前提条件 {#prerequisites} BrazeをChatGPTアプリと統合する前に、以下が必要です。 - Brazeワークスペースに新規のWebアプリとAPIキーが作成されていること - OpenAIプラットフォームで作成された[ChatGPTアプリ](https://openai.com/index/introducing-apps-in-chatgpt/)([OpenAIサンプルアプリ](https://github.com/openai/openai-apps-sdk-examples)) # ChatGPT app integration ## Setup ### Step 1: Get the Braze integration file Copy the `braze.js` file from our [ChatGPT apps integration repository](https://github.com/braze-inc/chatgpt-apps-braze-integration/blob/main/src/braze/braze.ts) to your project. This file contains all the necessary Braze SDK configuration and helper functions. ### Step 2: Install dependencies Install our Web SDK for Braze's most up-to-date set of features: **For client-side integration:** ```bash npm install @braze/web-sdk ``` ## Implementation There are two ways to integrate Braze with your ChatGPT app depending on your use case: ### Client-side integration (custom widgets) **Tip:** **Recommended Approach:** This method enables rich messaging experiences and real-time user interaction tracking within your ChatGPT app widgets. For displaying Braze messaging and tracking user interactions within your custom ChatGPT app widgets, use the Web SDK integration. A full messaging example can be found in our sample repository [here](https://github.com/braze-inc/chatgpt-apps-braze-integration/tree/main/src/inbox). #### Configure widget metadata Add the following metadata to your MCP server file to allow Braze domains, ensuring to update the CDN domain based on [your region](https://www.braze.com/docs/ja/ja/developer_guide/platforms/web/content_security_policy): ```javascript "openai/widgetCSP": { connect_domains: ["https://YOUR-SDK-ENDPOINT"], resource_domains: [ "https://appboy-images.com", "https://braze-images.com", "https://cdn.braze.eu", "https://use.fontawesome.com" ], } ``` Replace `YOUR-SDK-ENDPOINT` with your actual Braze SDK endpoint. #### Set up the useBraze hook ```javascript import { useBraze } from "./utils/braze"; function YourWidget() { const braze = useBraze({ apiKey: "your-braze-api-key", baseUrl: "your-braze-endpoint.braze.com", }); useEffect(() => { if (!braze.isInitialized) { return; } // Set user identity braze.changeUser("user-id-123"); // Log widget interactions braze.logCustomEvent("viewed_pizzaz_list"); }, [braze.isInitialized]); return ( // Your widget JSX ); } ``` #### Display Braze Content Cards ```javascript const [cards, setCards] = useState([]); useEffect(() => { // Get cached content cards setCards(braze.getCachedContentCards()?.cards ?? []); // Subscribe to content card updates braze.subscribeToContentCardsUpdates((contentCards) => { setCards(contentCards.cards); }); // Open session braze.openSession(); return () => { braze.removeAllSubscriptions(); } }, []); ``` #### Track widget events ```javascript // Track user interactions within your widget const handleButtonClick = () => { braze.logCustomEvent("widget_button_clicked", { button_type: "save_list", widget_name: "pizza_list" }); }; const handleItemInteraction = (itemId) => { braze.logCustomEvent("item_interacted", { item_id: itemId, interaction_type: "view_details" }); }; ``` ### Server-side integration (MCP server) If you also need a server-side integration for messaging functionality on your MCP server, contact `mcp-product@braze.com`. For tracking events and purchases from your MCP server, use our [REST API](https://www.braze.com/docs/ja/ja/api/home). # Braze SDKのバージョン管理について Source: /docs/ja/developer_guide/sdk_integration/version_management/index.md # バージョン管理について {#about-version-management} > Braze SDKのバージョン管理について説明します。これにより、アプリは最新の機能と品質の向上を維持できます。古いバージョンのSDKは最新のパッチ、バグフィックス、サポートを受け取らない場合があるため、継続的な開発ライフサイクルの一環として常に最新の状態に保つことをお勧めします。 ## バージョン管理の推奨事項 {#versioning-recommendations} すべてのBraze SDKは[Semantic Versioning Specification (SemVer)](https://semver.org/)に準拠しているため、バージョン番号`MAJOR.MINOR.PATCH`に基づき、以下を推奨します。 | バージョン | このバージョンについて | 推奨事項 | |-------|------------------|--------------| | `PATCH` | 更新は常に非破壊的であり、重要なバグ修正を含みます。常に安全です。 | 現在のメジャーバージョンとマイナーバージョンの最新パッチバージョンにすぐに更新してください。 | | `MINOR` | 更新は常に非破壊的であり、新しい機能が含まれます。アプリケーションコードの変更は不要です。 | すぐに行う必要はありませんが、できるだけ早く現在のメジャーバージョンの最新マイナーバージョンに更新してください。 | | `MAJOR` | 更新は破壊的変更であり、アプリケーションコードの変更が必要になる場合があります。 | コードの変更が必要な場合があるため、チームに最適なタイミングで最新のメジャーバージョンに更新してください。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="バージョン管理の推奨事項" } **Note:** 新しいAndroidまたはApple OSの更新により、Braze SDKの変更が必要になる場合があります。アプリを新しいデバイスと互換性のある状態に保つために、SDKを最新の状態に維持することが重要です。 ## 新しいリリースの通知を受け取る {#getting-notified-of-new-releases} 新しいSDKバージョンがリリースされたときに自動通知を受け取るには、任意のBraze SDKのGitHubリポジトリをウォッチできます。 1. SDKのGitHubリポジトリに移動します(例:[braze-android-sdk](https://github.com/braze-inc/braze-android-sdk)、[braze-swift-sdk](https://github.com/braze-inc/braze-swift-sdk)、[braze-web-sdk](https://github.com/braze-inc/braze-web-sdk))。 2. 右上の**Watch**をクリックします。 3. **Custom**をクリックし、**Releases**を選択して、**Apply**をクリックします。 新しいリリースが公開されるたびに、GitHub通知(および[通知設定](https://github.com/settings/notifications)に応じてメール)を受け取ります。SDKリポジトリの完全なリストについては、[参照、リポジトリ、サンプルアプリ](https://www.braze.com/docs/ja/ja/developer_guide/references)をご覧ください。 ## 既知の問題について {#about-known-issues} 変更によってビルドパイプラインが中断されないようにするため、特定のリリースに既知の問題がある場合でも、**ディストリビューションシステムに公開された後にリリースを変更または削除することはありません**—。 このような場合は、[Braze SDK変更ログ](https://www.braze.com/docs/ja/ja/developer_guide/changelogs)に問題を記録し、影響を受けるメジャーバージョンまたはマイナーバージョンの新しいパッチをできるだけ早くリリースします。 # Android 13アップグレードガイド Source: /docs/ja/developer_guide/platforms/android/android_13/index.md # Upgrading to Android 13 > This guide describes relevant changes introduced in Android 13 (2022) and the required upgrade steps for your Braze Android SDK integration. Refer to the [Android 13 developer documentation](https://developer.android.com/about/versions/13) for a full migration guide. ## Android 13 Braze SDK To prepare for Android 13, please upgrade your Braze SDK to the [latest version (v21.0.0+)](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2300). Doing so will give you access to our new ["no-code" push primer feature](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/best_practices/push_primer_messages/). ## Changes in Android 13 ### Push permission {#push-permission} Android 13 introduces a [major change](https://developer.android.com/about/versions/13/changes/notification-permission) in how users manage apps that send push notifications. In Android 13, apps are required to obtain permission before push notifications can be shown. ![An Android push message asking "Allow Kitchenerie to send you notifications?" with two buttons "Allow" and "Don't allow" at the bottom of the message.](https://www.braze.com/docs/ja/ja/assets/img/android/android-13-push-prompt.png?aa824eb39eb4947698a29f41affb97dc){: style="float:right;max-width:430px;width:50%;margin-left:15px;border:0"} This new permission follows a similar pattern to iOS and Web push, where you only have one attempt to obtain permission. If a user chooses `Don't Allow` or dismisses the prompt, your app cannot ask for permission again. Note that apps are granted an [exemption](https://developer.android.com/about/versions/13/changes/notification-permission#eligibility) for users who previously had push notifications enabled prior to updating to Android 13. These users [will remain eligible](https://developer.android.com/about/versions/13/changes/notification-permission#existing-apps) to receive push when they update to Android 13 without having to request permission. #### Permission prompt timing {#push-permission-timing} **Targeting Android 13** Apps targeting Android 13 can control when to request permission and show the native push prompt. If your user upgrades from Android 12 to 13, your app was previously installed, and you were already sending push, the system automatically pre-grants the new notification permission to all eligible apps. In other words, these apps can continue to send notifications to users, and users don't see a runtime permission prompt. For more details on this see Android's Developer Documentation for [effects on updates to existing apps](https://developer.android.com/about/versions/13/changes/notification-permission#existing-apps). **Targeting Android 12 or earlier** If your app does not yet target Android 13, then a new user on Android 13 installs your app, they will automatically see a push permission prompt when your app creates its first notification channel (via `notificationManager.createNotificationChannel`). Users who already have your app installed and then upgrade to Android 13 are never shown a prompt and are automatically granted push permission. **Note:** Braze SDK v23.0.0 automatically creates a default notification channel if one does not already exist when a push notification is received. If you don't target Android 13, this will cause the push permission prompt to be shown, which is required to show the notification. ## Preparing for Android 13 {#next-steps} It is strongly recommended that your app targets Android 13 in order to control when users are prompted for push permission. This will allow you to optimize your [push opt-in rates](https://www.braze.com/resources/articles/android-13-developer-preview-push-opt-ins-arrive-for-android-apps) by prompting users at more appropriate times and will lead to a better user experience in how and when your app asks for push permission. To start using our new ["no-code" push primer feature](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/best_practices/push_primer_messages/), upgrade your Android SDK to the [latest version (v23.0.0+)](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2300). # iOS 18 へのアップグレード Source: /docs/ja/developer_guide/platforms/swift/ios_18/index.md # iOS 18 へのアップグレード {#upgrading-to-ios-18} > Brazeが次のiOSリリースに向けてどのように準備しているか気になりますか?この記事では、iOS 18のリリースに関するインサイトをまとめており、あなたとユーザーのシームレスなエクスペリエンス作りに役立ちます。 Appleの[WWDC](https://developer.apple.com/wwdc24/)は、2024年6月9日〜11日に開催されました。発表の詳細については、[ブログ記事](https://www.braze.com/resources/articles/wwdc-announcements-bring-apple-intelligence-rcs-and-more-to-ios-18)をご覧ください。また、BrazeでiOS 18を活用する方法については、以下をお読みください。 ## iOS 18の変更点 {#changes-in-ios-18} ### Apple Watchでのライブアクティビティ {#live-activities-on-apple-watch} [ライブアクティビティ](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/live_notifications?sdktab=swift)はwatchOS 11でサポートされます。追加の設定は必要ありません。ただし、Appleではウォッチインターフェイスをカスタマイズするオプションが用意されています。 ### Apple Vision Pro Vision Proは現在、中国、日本、シンガポール、オーストラリア、カナダ、フランス、ドイツ、英国で販売されています。[BrazeがvisionOSをどのようにサポートしているか](https://www.braze.com/resources/articles/building-braze-a-new-era-of-customer-engagement-braze-announces-visionos-support)については、弊社のブログをご覧ください。 ### macOSでのiPhone通知 {#iphone-notifications-on-macos} Appleの新しい[iPhoneミラーリング](https://www.apple.com/newsroom/2024/06/macos-sequoia-takes-productivity-and-intelligence-on-mac-to-new-heights/)機能により、ユーザーはmacOSデバイスでiPhoneの通知を受け取ることができます。Push Storyの画像やGIFなど、一部のメディアタイプはmacOS通知としてレンダリングできないため、サポートされていない点にご注意ください。 ### Apple Intelligence [Apple Intelligence](https://developer.apple.com/documentation/Updates/Apple-Intelligence)は、iOS 18.1以降を実行しているデバイスで利用できるようになりました。 Brazeユーザーとして知っておくべき最も重要な新機能は[通知サマリー](https://support.apple.com/en-us/108781)です。これは、デバイス上の処理を使用して、1つのアプリから送信される関連するプッシュ通知を自動的にグループ化し、テキストサマリーを生成します。エンドユーザーはサマリーをタップして展開し、最初に送信されたときの各プッシュ通知を表示できます。 これらのサマリーの生成方法の性質上、特定の動作や生成されるテキストを制御することはできません。ただし、プッシュクリックのトラッキングなどの分析機能やレポート機能には影響しません。 ![プッシュ通知プレビューサマリーのサンプルスクリーンショット。](https://www.braze.com/docs/ja/ja/assets/img/apple/apple_intelligence/notification_preview_summary.png?1b8357db05ac28fe35dad65c78525987) # visionOSサポート Source: /docs/ja/developer_guide/platforms/swift/visionos/index.md # visionOSサポート {#visionos-support} > [Braze Swift SDK 8.0.0](https://github.com/braze-inc/braze-swift-sdk/blob/main/CHANGELOG.md#800)以降、Apple Vision Pro向けのApple空間コンピューティングプラットフォームである[visionOS](https://developer.apple.com/visionos/)でBrazeを活用できます。Brazeを使用したvisionOSサンプルアプリについては、[サンプルアプリ](https://www.braze.com/docs/ja/ja/developer_guide/references?tab=swift)を参照してください。 ## 完全にサポートされている機能 {#fully-supported-features} iOSで利用できるほとんどの機能は、visionOSでも利用できます。以下はその例です。 - 分析(セッション、カスタムイベント、購入など) - アプリ内メッセージング(データモデルとUI) - Content Cards(データモデルとUI) - プッシュ通知(アクションボタン付きのユーザー可視通知とサイレント通知) - フィーチャーフラグ - ロケーション分析 ## 部分的にサポートされている機能 {#partially-supported-features} 一部の機能はvisionOSでは部分的にしかサポートされていませんが、Appleが将来的にこれらに対応する可能性があります。 - リッチプッシュ通知 - 画像はサポートされています。 - GIFと動画はプレビューサムネイルが表示されますが、再生することはできません。 - オーディオ再生はサポートされていません。 - Push Stories - Push Storiesページのスクロールと選択はサポートされています。 - **Next**を使用したPush Storiesページ間のナビゲーションはサポートされていません。 ## サポートされていない機能 {#unsupported-features} - ジオフェンスモニタリングはサポートされていません。Appleは、リージョンモニタリング用のCore Location APIをvisionOSで利用可能にしていません。 - ライブアクティビティはサポートされていません。現在、ActivityKitはiOSとiPadOSでのみ利用可能です。 # iOS 14 SDKアップグレードガイド Source: /docs/ja/developer_guide/platforms/swift/_archived_updates/ios_14/index.md # iOS 14 SDKアップグレードガイド {#ios-14-sdk-upgrade-guide} > このガイドでは、iOS 14で導入されたBraze関連の変更と、Braze iOS SDK統合に必要なアップグレード手順について説明します。iOS 14の新しいアップデートの完全なリストについては、Appleの[iOS 14ページ](https://www.apple.com/ios/ios-14/)を参照してください。 **Tip:** iOS 14.5以降、**IDFA**の収集と[特定のデータ共有](https://developer.apple.com/app-store/user-privacy-and-data-use/#permission-to-track)には、新しい[AppTrackingTransparency](https://developer.apple.com/documentation/apptrackingtransparency)フレームワークの許可プロンプトが必要になります([IDFAの詳細はこちら](#idfa))。 ## iOS 14の破壊的変更のまとめ {#summary-of-ios-14-breaking-changes} - iOS 14 / Xcode 12を対象とするアプリは、[公式iOS 14リリース](https://github.com/Appboy/appboy-ios-sdk/releases/tag/3.27.0)を使用する必要があります。 - 新しい_おおよその位置情報_パーミッションを選択したユーザーに対して、ジオフェンスは[iOSでサポートされなくなりました](https://developer.apple.com/documentation/corelocation/cllocationmanager/3600215-accuracyauthorization)。 - 「Last Known Location」ターゲティング機能を使用するには、_おおよその位置情報_パーミッションとの互換性のため、Braze iOS SDK v3.26.1以降へのアップグレードが必要です。Xcode 12を使用している場合は、v3.27.0以降にアップグレードする必要があります。 - iOS 14.5以降、IDFAの収集と[特定のデータ共有](https://developer.apple.com/app-store/user-privacy-and-data-use/#permission-to-track)には、新しい[AppTrackingTransparency](https://developer.apple.com/documentation/apptrackingtransparency)フレームワークの許可プロンプトが必要になります。 - キャンペーンターゲティングや分析のために「Ad Tracking Enabled」フィールドを使用する場合は、Xcode 12にアップグレードし、新しいAppTrackingTransparencyフレームワークを使用してユーザーのオプトインステータスを報告する必要があります。 ## アップグレードの概要 {#upgrade-summary} | アプリの使用状況 | アップグレードの推奨 | 説明 | |------|--------|---| | Xcode 12 | **iOS SDK v3.27以降にアップグレードしてください** | Xcode 12を使用しているお客様は、互換性を確保するためにv3.27.0以降を使用する必要があります。iOS 14の互換性に関連する問題や質問がある場合は、新しい[GitHub issue](https://github.com/Appboy/appboy-ios-sdk/issues)を開いてください。| | 最新の位置情報 | **iOS SDK v3.26.1以降にアップグレードしてください** | 最新の位置情報ターゲティング機能を使用しており、まだXcode 11を使用している場合は、新しい_おおよその位置情報_機能をサポートするiOS SDK v3.26.1以降にアップグレードする必要があります。古いSDKでは、ユーザーがiOS 14にアップグレード_し_、おおよその位置情報を選択した場合、位置情報を確実に収集できません。

アプリがiOS 14をターゲットにしていなくても、ユーザーがiOS 14にアップグレードし、新しい位置情報精度オプションを使い始める可能性があります。iOS SDK v3.26.1以降にアップグレードしていないアプリでは、iOS 14デバイスでユーザーが_おおよその位置情報_を提供した場合、位置情報属性を確実に収集できません。| | IDFA広告トラッキングID | **Xcode 12とiOS SDK v3.27へのアップグレードが必要な場合があります** | 2021年のある時点で、AppleはIDFAの収集に許可プロンプトを要求し始める予定です。その時点で、IDFAの収集を続行するには、アプリをXcode 12にアップグレードし、新しい`AppTrackingTransparency`フレームワークを使用する必要があります。IDFAをBraze SDKに渡す場合は、その時点でv3.27.0以降にもアップグレードする必要があります。

新しいiOS 14のAPIを使用していないアプリは、2021年にAppleがこの変更を実施し始めた後、IDFAを収集できなくなり、代わりに空白のID(`00000000-0000-0000-0000-000000000000`)を収集することになります。アプリに適用されるかどうかの詳細については、[IDFAの詳細](#idfa)を参照してください。| {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="アップグレードの概要" } ## iOS 14の動作変更 {#ios-14-behavior-changes} ### おおよその位置情報の許可 {#approximate-location-permission} ![正確な位置情報](https://www.braze.com/docs/ja/ja/assets/img/ios/ios14-approximate-location.png?762985d2d9f36f73a39b9b49bb1c4884){: style="float:right;max-width:45%;margin-left:15px;"} #### 概要 {#overview} 位置情報の許可をリクエストする際、ユーザーは_正確な位置情報_(以前の動作)を提供するか、新しい_おおよその位置情報_を提供するかを選択できるようになりました。おおよその位置情報では、正確な座標ではなく、ユーザーがいるより広い半径が返されます。 #### ジオフェンス {#geofences} 新しい_おおよその位置情報_パーミッションを選択したユーザーに対して、ジオフェンスは[iOSでサポートされなくなりました](https://developer.apple.com/documentation/corelocation/cllocationmanager/3600215-accuracyauthorization)。Braze SDK統合にアップデートは必要ありませんが、ジオフェンスに依存するキャンペーンについては、[ロケーションベースのマーケティング戦略](https://www.braze.com/blog/geofencing-geo-targeting-beaconing-when-to-use/)を調整する必要があるかもしれません。 #### ロケーションターゲティング {#location-tracking} _おおよその位置情報_が付与されたときにユーザーの_最新の既知の位置情報_を引き続き収集するには、アプリをBraze iOS SDK v3.26.1以降にアップグレードする必要があります。ただし、位置情報の精度は低くなることに留意してください。当社のテストでは、最大で12,000メートル(7マイル以上)に達しました。Brazeダッシュボードの_最新の既知の位置情報_ターゲティングオプションを使用する際は、新しい_おおよその位置情報_を考慮して、位置の半径を必ず大きくしてください(少なくとも半径1マイル/1.6kmを推奨します)。 Braze iOS SDKをv3.26.1以降にアップグレードしていないアプリでは、iOS 14デバイスで_おおよその位置情報_が付与された場合、位置情報トラッキングを使用できなくなります。 すでに位置情報アクセスを許可しているユーザーは、アップグレード後も引き続き_正確な位置情報_を提供します。 Xcode 12を使用している場合は、v3.27.0以降にアップグレードする必要があります。 おおよその位置情報の詳細については、Appleの[What's New In Location](https://developer.apple.com/videos/play/wwdc2020/10660/) WWDCビデオを参照してください。 ### IDFAとアプリトラッキングの透明性 {#idfa} #### 概要 IDFA(Identifier for Advertisers)は、広告およびアトリビューションパートナーとのクロスデバイストラッキングのためにAppleが提供する識別子であり、個人のApple IDに紐付けられています。 iOS 14.5からは、IDFAに対する明示的なユーザーの同意を収集するために、新しい許可プロンプト(新しい`AppTrackingTransparency`フレームワークによって起動される)を表示する必要があります。「他社が所有するアプリやWebサイトでユーザーを追跡する」ためのこの許可プロンプトは、位置情報をリクエストするようにユーザーにプロンプトを出すのと同様にリクエストされます。 ユーザーがプロンプトを受け入れない場合、またはXcode 12の`AppTrackingTransparency`フレームワークにアップグレードしない場合、空白のIDFA値(`00000000-0000-0000-0000-000000000000`)が返され、アプリは再度ユーザーにプロンプトを出すことができなくなります。 **Important:** これらのIDFAアップデートは、エンドユーザーがデバイスをiOS 14.5にアップグレードした後に有効になります。IDFAの収集を計画している場合は、Xcode 12でアプリが新しい`AppTransparencyFramework`を使用していることを確認してください。 #### Braze IDFAコレクションの変更点 {#changes-to-braze-idfa-collection} ![IDFA](https://www.braze.com/docs/ja/ja/assets/img/ios/ios14-idfa.png?d088f91fda2277b22f9b32cdec6cbb5a){: style="float:right;max-width:25%;margin-left:15px;border:0"} 1. Brazeは、アプリがユーザーのIDFA値をBraze SDKに提供することを引き続き許可します。 2. オプションの自動IDFAコレクションで条件付きコンパイルを行う`ABK_ENABLE_IDFA_COLLECTION`コンパイルマクロは、iOS 14では機能しなくなり、3.27.0で削除されました。 3. キャンペーンターゲティングや分析のために「Ad Tracking Enabled」フィールドを使用する場合は、Xcode 12にアップグレードし、新しいAppTrackingTransparencyフレームワークを使用して、ユーザーのオプトインステータスを報告する必要があります。この変更の理由は、iOS 14では古い[`advertisingTrackingEnabled`](https://developer.apple.com/documentation/adsupport/asidentifiermanager/1614148-advertisingtrackingenabled)フィールドが常にNoを返すためです。 4. アプリがBrazeのexternal IDとしてIDFAまたはIDFVを使用していた場合、これらの識別子からUUIDに移行することを強く推奨します。external IDの移行に関する詳細については、[external ID移行APIエンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/external_id_migration)を参照してください。 Appleの[プライバシーに関する更新](https://developer.apple.com/app-store/user-privacy-and-data-use/)と新しい[アプリトラッキングの透明性フレームワーク](https://developer.apple.com/documentation/apptrackingtransparency)について詳しくはこちらをご覧ください。 ### プッシュ認証 {#push-provisional-auth} **Important:** iOS 14には、暫定プッシュ承認に関する変更は含まれていません。iOS 14の以前のベータ版で、Appleは変更を導入しましたが、その後以前の動作に戻されています。 ## iOS 14の新機能 {#ios-14-new-features} ### アプリのプライバシーとデータ収集の概要 {#app-privacy} 2020年12月8日以降、App Storeへのすべての提出には、[Appleの新しいApp Privacy基準](https://developer.apple.com/app-store/app-privacy-details/)を遵守するための追加のステップが必要となります。 #### Apple Developer Portalアンケート {#apple-developer-portal-questionnaire} _Apple Developer Portal_で: * アプリまたはサードパーティパートナーがデータを収集する方法を説明するアンケートに記入するよう求められます。 * このアンケートは、App Storeに掲載されている最新のリリースを常に反映したものであることが求められます。 * アンケートは、新しいアプリの提出がなくても更新される可能性があります。 * アプリのプライバシーポリシーURLへのリンクを貼り付ける必要があります。 アンケートに記入する際には、法務チームに相談し、以下の分野でのBrazeの使用が開示要件にどのように影響するかを検討してください。 #### Brazeのデフォルトのデータ収集 {#braze-default-data-collection} **識別子** - 匿名のデバイス識別子は、Braze SDKによって常に収集されます。これは現在、デバイスのIDFV(ベンダーの識別子)に設定されています。 **利用データ** - Brazeのセッションデータ、および製品のインタラクションを測定するために使用するイベントまたは属性収集が含まれます。 #### オプションのデータ収集 {#optional-data-collection} Brazeの使用を通じて任意に収集される可能性のあるデータ: **位置情報** - Braze SDKは、オプションで、おおよその位置情報と正確な位置情報の両方を収集できます。これらの機能はデフォルトでは無効になっています。 **連絡先情報** - これには、ユーザーのIDに関連するイベントや属性を含めることができます。 **購入** - これには、ユーザーの代わりに記録されたイベントや購入が含まれる可能性があります。 **Important:** これは網羅的なリストではないことに注意してください。Brazeでユーザーに関するその他の情報を手動で収集する場合に、その情報がApp Privacy Questionnaireの他のカテゴリに該当する場合は、それらも開示する必要があります。 この機能の詳細については、[Appleのプライバシーとデータ利用](https://developer.apple.com/app-store/user-privacy-and-data-use/)を参照してください。 # iOS 15 SDKアップグレードガイド Source: /docs/ja/developer_guide/platforms/swift/_archived_updates/ios_15/index.md # iOS 15 SDKアップグレードガイド {#ios-15-sdk-upgrade-guide} > このガイドでは、iOS 15 (WWDC21) で導入された変更点と、Braze iOS SDK統合に必要なアップグレードステップについて説明します。iOS 15の新しい更新の完全なリストについては、Appleの[iOS 15 リリースノート](https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-15-release-notes)を参照してください。 ## UIナビゲーションの透明性に関する変更 {#transparency-changes-to-ui-navigations} iOSベータ版の年次テストの一環として、特定のUIナビゲーションバーが不透明ではなく透明に表示されるAppleによる変更を確認しました。これは、Content Cards用のBrazeデフォルトUIを使用している場合、またはWebディープリンクが別のブラウザアプリではなくアプリ内で開かれている場合に、iOS 15で表示されます。 iOS 15でのこの視覚的な変更を回避するために、ユーザーが新しいiOS 15オペレーティングシステムにアップグレードを開始する前に、できるだけ早く[Braze iOS SDK v4.3.2](https://github.com/Appboy/appboy-ios-sdk/releases/tag/4.3.2)にアップグレードすることを強くお勧めします。 ## 新しい通知設定 {#notification-settings} iOS 15では新しい通知機能が導入され、ユーザーが1日を通して集中力を保ち、頻繁な中断を避けることができるようになりました。これらの新機能のサポートを提供できることを嬉しく思います。これらの機能は追加のSDKアップグレードを必要とせず、iOS 15デバイスのユーザーにのみ適用されます。 ### フォーカスモード {#focus-mode} iOS 15のユーザーは「フォーカスモード」を作成できるようになりました。これは、フォーカスを中断して目立つように表示する通知を指定するためのカスタムプロファイルです。 ![iOS 15のユーザーは「フォーカスモード」を作成できるようになりました。これは、フォーカスを中断して目立つように表示する通知を指定するためのカスタムプロファイルです。](https://www.braze.com/docs/ja/ja/assets/img/ios/ios15-notification-settings.png?821058a3051c6ec90473df1553398091){: style="float:right;max-width:25%;margin-left:15px;border:0"} ### 割り込みレベル {#interruption-levels} iOS 15では、プッシュ通知は次の4つの割り込みレベルのいずれかで送信できます。 * **パッシブ**(新規)- サウンドなし、バイブレーションなし、画面のスリープ解除なし、フォーカス設定の突破なし。 * **アクティブ**(デフォルト)- サウンド、バイブレーション、画面のスリープ解除を許可し、フォーカス設定の突破は許可しません。 * **時間的制約**(新規)- サウンド、バイブレーション、画面のスリープ解除を許可し、許可されている場合はシステムコントロールを突破できます。 * **重大** - サウンド、バイブレーション、画面のスリープ解除を許可し、システムコントロールを突破し、サイレントスイッチをバイパスできます。 iOSプッシュでこのオプションを設定する方法の詳細については、[iOS通知オプション](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/ios/notification_options#interruption-level)を参照してください。 ### 通知サマリー {#notification-summary} ![通知サマリーに関するスクリーンショット。](https://www.braze.com/docs/ja/ja/assets/img/ios/ios15-notification-summary.png?2fa3879f3f2600c850c6911da84c13a1){: style="float:right;max-width:25%;margin-left:15px;border:0"} iOS 15では、ユーザーは(オプションで)1日の中で特定の時間を選択して、通知のサマリーを受け取ることができます。即時の注意を必要としない通知(「パッシブ」として送信されたものや、ユーザーがフォーカスモード中のものなど)は、1日を通じて絶えず中断されないようにグループ化されます。 送信する通知ごとに、「関連性スコア」を指定して、どの通知をサマリーの先頭に表示するかをコントロールできるようになります。 通知の「関連性スコア」の設定方法については、[iOS通知オプション](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/ios/notification_options#relevance-score)を参照してください。 ## 位置情報ボタン {#location-buttons} iOS 15では、ユーザーがアプリ内で位置情報へのアクセスを一時的に許可する新しい便利な方法が導入されています。 新しい位置情報ボタンは、既存の「1度のみ許可」権限を基にしており、同じセッションで複数回クリックするユーザーに繰り返しプロンプトを表示することはありません。 詳細については、今年の世界開発者会議(WWDC)でのAppleの動画[Meet the Location Button](https://developer.apple.com/videos/play/wwdc2021/10102/)をご覧ください。 **Tip:** この機能により、ユーザーに権限を要求する追加の機会が得られます。iOS 15より前に位置情報の許可を拒否したことがあるユーザーには、位置情報ボタンをクリックした際に、拒否状態から権限をリセットする最後の機会としてプロンプトが表示されます。 ### Brazeで位置情報ボタンを利用する {#using-location-buttons-with-braze} Brazeで位置情報ボタンを使用する場合、追加の統合は必要ありません。アプリは、通常どおり(権限が付与されたら)ユーザーの位置情報を渡し続ける必要があります。 Appleによると、すでにバックグラウンドでの位置情報へのアクセスを共有しているユーザーについては、iOS 15にアップグレードした後も「アプリの使用中」オプションで引き続きそのレベルの権限が付与されます。 ## Appleメール {#mail} 今年、Appleはメールのトラッキングとプライバシーに関する多くの更新を発表しました。詳細については、[ブログ投稿](https://www.braze.com/resources/articles/9-ways-email-marketers-can-respond-to-apples-mail-privacy-protection-feature)をご覧ください。 ## SafariのIPアドレスによる位置情報 {#safari-ip-address-location} iOS 15では、ユーザーはIPアドレスから特定された位置情報を匿名化または一般化するようにSafariを設定できます。ロケーションベースのターゲティングまたはセグメンテーションを使用する場合は、このことに留意してください。 # iOS 16 アップグレードガイド Source: /docs/ja/developer_guide/platforms/swift/_archived_updates/ios_16/index.md # iOS 16 SDKアップグレードガイド {#ios-16-sdk-upgrade-guide} > このガイドでは、iOS 16 (2022) で導入された関連する変更と、Braze iOS SDKインテグレーションへの影響について説明します。完全な移行ガイドについては、[iOS 16 リリースノート](https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-16-release-notes)を参照してください。 ## iOS 16での変更点 {#changes-in-ios-16} ### Safari Webプッシュ {#safari-web-push} Appleは、Webプッシュ機能に対する2つの変更を発表しました。 #### デスクトップWebプッシュ (MacOS) {#macos-push} 以前、Appleは独自のSafariプッシュAPIを使用してmacOS (デスクトップ) でのプッシュ通知をサポートしていました。 macOS Ventura (2022年10月24日リリース) 以降、[SafariにはSafariプッシュに加えてWeb Push APIのサポートが追加されました](https://webkit.org/blog/12824/news-from-wwdc-webkit-features-in-safari-16-beta/#web-push-for-macos)。これは、他の一般的なブラウザで使用されている既存のクロスブラウザAPI標準です。 すでにBraze経由でSafari用Webプッシュを送信している場合は、変更する必要はありません。 #### モバイルWebプッシュ (iOSおよびiPadOS) {#ios-push} 以前は、iPhoneおよびiPadのSafariはプッシュ通知の受信をサポートしていませんでした。 2023年に、AppleはSafariを介したiPhoneおよびiPadデバイスでのWebプッシュのサポートを追加する予定です。 Brazeは、追加の変更やアップグレードを必要とせずに、この新しいiOSおよびiPadOSのWebプッシュをサポートします。 ## iOS 16への準備 {#next-steps} Braze iOS SDKをiOS 16用にアップグレードする必要はありませんが、他に2つの注目すべき更新があります。 1. Brazeは[新しいSwift SDK](https://github.com/braze-inc/braze-swift-sdk)をリリースしました。これにより、パフォーマンスの向上、新機能、および多くの改善がもたらされます。 2. Braze Swift SDKは、新しい[「ノーコード」プッシュプライマー機能](https://www.braze.com/docs/ja/ja/user_guide/channels/push/best_practices/push_primer_messages)をサポートしています。 # iOS 17 アップグレードガイド Source: /docs/ja/developer_guide/platforms/swift/_archived_updates/ios_17/index.md # iOS 17 アップグレードガイド {#ios-17-upgrade-guide} > BrazeがこれからのiOSリリースに向けてどのように準備しているか気になりますか?この記事では、iOS 17リリースに関するインサイトをまとめ、あなたとユーザーにシームレスな体験を提供するお手伝いをします。 ## iOS 17とXcode 15の互換性 {#ios-17-and-xcode-15-compatibility} Braze Swift SDKとObjective-C SDKはどちらもXcode 14およびXcode 15と下位互換性があり、iOS 17デバイスと互換性があります。 ## iOS 17の変更点 {#changes-in-ios-17} ### リンクトラッキングとUTMパラメータの削除 {#link-tracking-and-utm-parameter-stripping} iOS 17の重要な変更点の1つは、SafariでUTMパラメータをブロックすることです。UTMパラメータはURLに追加されるコードの一部であり、メール、SMS、その他のメッセージングチャネルの効果を測定するためにマーケティングキャンペーンで頻繁に使用されます。 この変更はBrazeメールのクリックトラッキングおよびSMSリンク短縮送信には影響しません。 ### App Tracking Transparency {#app-tracking-transparency} Appleは、ユーザーが他社のアプリやWebサイト上のアクティビティへのアプリのアクセスをコントロールできるようにする[Ad Tracking Transparency (ATT)](https://support.apple.com/en-us/HT212025)の範囲を拡大することを発表しました。iOS 17のリリースには、プライバシーマニフェストとコード署名という2つの重要なATT機能が含まれています。 #### プライバシーマニフェスト {#privacy-manifests} Appleでは、アプリとサードパーティのSDKがデータを収集する理由と、そのデータ収集方法を説明するプライバシーマニフェストファイルが必要になりました。iOS 17.2から、Appleはエンドユーザーが ATTプロンプトを受け入れるまで、アプリ内のすべての宣言されたトラッキングエンドポイントをブロックします。 Brazeは、宣言されたトラッキングデータを自動的に専用の`-tracking`エンドポイントにリルートする新しい柔軟なAPIとともに、独自のプライバシーマニフェストをリリースしました。詳細については、[Brazeプライバシーマニフェスト](https://www.braze.com/docs/ja/ja/developer_guide/analytics/managing_data_collection?sdktab=swift#swift_privacy-manifest)を参照してください。 #### コード署名 {#code-signing} コード署名により、サードパーティのSDKをアプリケーションで使用する開発者は、Xcodeで以前のバージョンと同じ開発者が署名したことを検証できます。 ### Braze SDKとプライバシー {#braze-sdk-and-privacy} Appleはまた、2023年後半に「プライバシーに影響を与える」と見なされるサードパーティSDKのリストを公開することも発表しました。これらのSDKは、Appleによってユーザーのプライバシーに特に大きな影響を与えると予想されています。 従来のトラッキングSDKが複数のWebサイトやアプリケーションにわたってユーザーを監視するように設計されているのに対し、Braze SDKはファーストパーティデータのメッセージングとユーザー体験に焦点を当てています。 Braze SDKがこのリストに含まれるとは予想していませんが、この状況を注意深く監視し、必要なアップデートをリリースする予定です。 # Webのブラウザ拡張機能統合 Source: /docs/ja/developer_guide/platforms/web/browser_extensions/index.md # ブラウザ拡張機能 {#browser-extension} > この記事では、Braze Web SDKをブラウザ拡張機能(Google Chrome、Firefox)内で使用する方法について説明します。 Braze Web SDKをブラウザ拡張機能内に統合し、分析を収集して、リッチなメッセージをユーザーに表示します。これには、**Google Chrome Extensions**と**Firefox Add-Ons**の両方が含まれます。 ## サポートされるもの {#whats-supported} 通常、拡張機能はHTMLおよびJavaScriptであるため、以下にBrazeを使用できます。 * **分析**:カスタムイベント、属性をキャプチャし、拡張機能内のリピートユーザーの識別も行います。これらのプロファイル特性を使用して、クロスチャネルメッセージングを強化します。 * **アプリ内メッセージ**:ネイティブまたはカスタムのHTMLメッセージングを使用して、ユーザーが拡張機能内でアクションを取ったときにアプリ内メッセージをトリガーします。 * **Content Cards**:オンボーディングまたはプロモーションコンテンツ用に、拡張機能にネイティブカードのフィードを追加します。 * **Webプッシュ**:Webページが現在開かれていない場合でも、タイムリーに通知を送信します。 ## サポートされていないもの {#whats-not-supported} * サービスワーカーはBraze Web SDKではサポートされていませんが、将来的なサポートについてはロードマップで検討されています。 ## 拡張機能の種類 {#extension-types} Brazeは、拡張機能の以下の領域に含めることができます。 | エリア | 詳細 | サポートされるもの | |--------|-------|------| | ポップアップページ | [ポップアップ](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface/Popups)ページは、ブラウザのツールバーで拡張機能のアイコンをクリックするとユーザーに表示されるダイアログです。| 分析、アプリ内メッセージ、およびContent Cards | | バックグラウンドスクリプト | [バックグラウンドスクリプト](https://developer.chrome.com/extensions/background_pages)(Manifest v2のみ)は、拡張機能でユーザーナビゲーションの調査および操作や、Webページの変更を行えるようにします(広告ブロッカーがページ上のコンテンツを検出および変更する方法など)。| 分析、アプリ内メッセージ、およびContent Cards。

バックグラウンドスクリプトはユーザーには表示されないため、メッセージングを行う場合は、メッセージを表示するときにブラウザのタブやポップアップページと通信する必要があります。| | オプションページ | [オプションページ](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface/Options_pages)を使用すると、ユーザーは拡張機能内で設定を切り替えることができます。これは、新しいタブを開くスタンドアロンのHTMLページです。| 分析、アプリ内メッセージ、およびContent Cards | {: .reset-td-br-1 .reset-td-br-2, .reset-td-br-3 aria-label="拡張機能の種類" } ## 権限 {#permissions} Braze SDK(`braze.min.js`)を拡張機能にバンドルされたローカルファイルとして統合する場合、`manifest.json`で追加の権限は必要ありません。 ただし、[Google Tag Manager](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/google_tag_manager/)を使用するか、外部URLからBraze SDKを参照するか、拡張機能に厳密なコンテンツセキュリティポリシーを設定した場合は、`manifest.json`の[`content_security_policy`](https://developer.chrome.com/extensions/contentSecurityPolicy)設定を調整して、リモートスクリプトソースを許可する必要があります。 ## はじめに {#getting-started} **Tip:** 作業を始める前に、Web SDKの[初期SDK設定ガイド](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=web)を読んで、JavaScriptの統合全般について理解してください。

また、[JavaScript SDKリファレンス](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html)をブックマークして、さまざまなSDKメソッドと設定オプションの詳細を確認することもお勧めします。 Braze Web SDKを統合するには、まず最新のJavaScriptライブラリーのコピーをダウンロードする必要があります。これは、NPMを使用するか、[Braze CDN](https://js.appboycdn.com/web-sdk/latest/braze.min.js)から直接ダウンロードすることで実行できます。 または、[Google Tag Manager](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/google_tag_manager/)を使用するか、Braze SDKの外部ホストされたコピーを使用する場合は、外部リソースを読み込むには`manifest.json`の[`content_security_policy`](https://developer.chrome.com/extensions/contentSecurityPolicy)設定を調整する必要があることに注意してください。 ダウンロードしたら、`braze.min.js`ファイルを拡張機能のディレクトリー内の任意の場所にコピーします。 ### 拡張機能ポップアップ {#popup} 拡張機能のポップアップにBrazeを追加するには、通常のWebサイトと同様に、`popup.html`でローカルJavaScriptファイルを参照します。Google Tag Managerを使用している場合は、代わりに[Google Tag Managerテンプレート](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/google_tag_manager/)を使用してBrazeを追加できます。 ```html popup.html ``` ### バックグラウンドスクリプト(Manifest v2のみ) {#background-script} 拡張機能のバックグラウンドスクリプト内でBrazeを使用するには、Brazeライブラリーを`manifest.json`の`background.scripts`配列に追加します。これにより、グローバル`braze`変数がバックグラウンドスクリプトコンテキストで使用できるようになります。 ```json { "manifest_version": 2, "background": { "scripts": [ "relative/path/to/braze.min.js", "background.js" ] } } ``` ### オプションページ {#options-page} オプションページを(`options`または`options_ui`マニフェストプロパティを介して)使用する場合、[`popup.html`の説明](#popup)と同じ方法でBrazeを組み込むことができます。 ## 初期化 {#initialization} SDKが組み込まれると、通常どおりにライブラリーを初期化できます。 Cookieはブラウザ拡張機能ではサポートされていないため、`noCookies: true`で初期化することでCookieを無効にできます。 ```javascript braze.initialize("YOUR-API-KEY-HERE", { baseUrl: "YOUR-API-ENDPOINT", enableLogging: true, noCookies: true }); ``` サポートされている初期化オプションの詳細については、[Web SDKリファレンス](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initialize)を参照してください。 ## プッシュ {#push} 拡張機能のポップアップダイアログではプッシュプロンプトを使用できません(ナビゲーションにURLバーがありません)。そのため、拡張機能のポップアップダイアログ内でプッシュ通知の権限を登録してリクエストするには、[代替プッシュドメイン](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/push_notifications/alternate_push_domain)で説明されているように、代替ドメインの回避策を使用する必要があります。 # Webのコンテンツセキュリティポリシーヘッダー Source: /docs/ja/developer_guide/platforms/web/content_security_policy/index.md # コンテンツセキュリティポリシーのヘッダー {#content-security-policy-headers} > Content-Security-Policyは、Webサイトでコンテンツを読み込む方法と場所を制限することで、追加のセキュリティを提供します。この参考記事では、Web SDKに必要なコンテンツセキュリティポリシーヘッダーについて説明します。 **Important:** この記事は、CSPルールを適用し、Brazeと統合するWebサイトに取り組む開発者を対象としています。セキュリティへのアプローチ方法に関する助言を目的としたものではありません。 **Note:** This guide uses code samples from the Braze Web SDK 4.0.0+. To upgrade to the latest Web SDK version, see [SDK Upgrade Guide](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md). ## Nonce属性 {#nonce} `script-src`または`style-src`ディレクティブで`nonce`値を使用する場合、その値を`contentSecurityNonce`初期化オプションに渡して、SDKによって新たに作成されるスクリプトやスタイルに伝播させます。 ```javascript import * as braze from "@braze/web-sdk"; braze.initialize(apiKey, { baseUrl: baseUrl, contentSecurityNonce: "YOUR-NONCE-HERE", // assumes a "nonce-YOUR-NONCE-HERE" CSP value }); ``` ## ディレクティブ {#directives} ### `connect-src` {#connect-src} **Warning:** URLは、選択した`baseUrl`初期化オプションの[API SDKエンドポイント](https://www.braze.com/docs/ja/ja/user_guide/administer/personal/sdk_endpoints)と一致する必要があります。 | URL | 情報 | |---|-----------| | `connect-src https://sdk.iad-01.braze.com` | SDKがBraze APIと通信できるようにします。このURLを、選択した`baseUrl`初期化オプションの[API SDKエンドポイント](https://www.braze.com/docs/ja/ja/user_guide/administer/personal/sdk_endpoints)に一致するように変更してください。| {: .reset-td-br-1 .reset-td-br-2 aria-label="connect-src #connect-src" } ### `script-src` {#script-src} | URL | 情報 | |---|-----------| | `script-src https://js.appboycdn.com` | CDNホスト統合を使用する場合に必要です。| | `script-src 'unsafe-eval'` | `appboyQueue`への参照を含む統合スニペットを使用する場合に必要です。このディレクティブの使用を避けるには、代わりに[NPMを使用してSDKを統合](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/initial_sdk_setup?tab=package%20manager)してください。| | `script-src 'nonce-...'`
または
`script-src 'unsafe-inline'` | カスタムHTMLなど、特定のアプリ内メッセージに必要です。| {: .reset-td-br-1 .reset-td-br-2 aria-label="script-src #script-src" } ### `img-src` {#img-src} | URL | 情報 | |---|-----------| | `img-src: appboy-images.com braze-images.com cdn.braze.eu` | Braze CDNホスト画像を使用する場合に必要です。ホスト名はダッシュボードクラスタによって異なる場合があります。

**重要:** カスタムフォントを使用している場合は、`font-src`も含める必要があります。| {: .reset-td-br-1 .reset-td-br-2 aria-label="img-src #img-src" } ## Font Awesome {#font-awesome} Font Awesomeの自動組み込みを無効にするには、`doNotLoadFontAwesome`初期化オプションを使用します。 ```javascript import * as braze from "@braze/web-sdk"; braze.initialize(apiKey, { baseUrl: baseUrl, doNotLoadFontAwesome: true, }); ``` Font Awesomeを使用する場合は、次のCSPディレクティブが必要です。 - `font-src https://use.fontawesome.com` - `style-src https://use.fontawesome.com` - `style-src 'nonce-...'`または`style-src 'unsafe-inline'` # アクセシビリティ Source: /docs/ja/developer_guide/platforms/web/accessibility/index.md # アクセシビリティ {#accessibility} > この記事では、Brazeが統合環境内でアクセシビリティをどのようにサポートしているかについて概説します。 Braze Web SDKは、[Webコンテンツアクセシビリティガイドライン(WCAG 2.1)](https://www.w3.org/TR/WCAG21/)が提供する標準をサポートしています。アクセシビリティ基準を維持するため、すべての新規ビルドにおいてContent Cardsとアプリ内メッセージに対して[100/100のLighthouseスコア](https://developer.chrome.com/docs/lighthouse/accessibility/scoring)を維持しています。 ## 前提条件 {#prerequisites} WCAG 2.1を満たす最小のSDKバージョンはv3.4.0に近いです。ただし、画像タグの重大な修正のため、少なくともv6.0.0へのアップグレードを推奨します。 ### 主なアクセシビリティの修正 {#notable-accessibility-fixes} | バージョン | タイプ | 主な変更点 | |---------|------|-------------| | **6.0.0** | **メジャー** | 画像の``タグ化、`imageAltText`または`language`フィールド、一般的なUIアクセシビリティの改善 | | **3.5.0** | マイナー | スクロール可能なテキストのアクセシビリティ改善 | | **3.4.0** | 修正 | Content Cardsの`article`ロール修正 | | **3.2.0** | マイナー | ボタンの最小タッチターゲット45×45px | | **3.1.2** | マイナー | 画像のデフォルト代替テキスト | | **2.4.1** | **メジャー** | セマンティックHTML(`h1`または`button`)、ARIA属性、キーボードナビゲーション、フォーカス管理 | | **2.0.5** | マイナー | フォーカス管理、キーボードナビゲーション、ラベル | {: .reset-td-br-1, .reset-td-br-2 aria-label="主なアクセシビリティの修正" } ## サポートされているアクセシビリティ機能 {#supported-accessibility-features} Content Cardsとアプリ内メッセージでは、以下の機能をサポートしています。 - ARIAロールとラベル - キーボードナビゲーションのサポート - フォーカス管理 - スクリーンリーダーによる読み上げ - 画像の代替テキスト対応 ## SDK統合のためのアクセシビリティガイドライン {#accessibility-guidelines-for-sdk-integrations} アクセシビリティに関する一般的なガイドラインについては、[Brazeでアクセシブルなメッセージを作成する](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/accessibility)を参照してください。このガイドでは、Braze Web SDKをWebアプリケーションに統合する際のアクセシビリティを最大限に高めるためのヒントとベストプラクティスを提供します。 ### Content Cards #### 最大高さの設定 {#setting-a-maximum-height} Content Cardsが縦方向のスペースを過剰に占めるのを防ぎ、アクセシビリティを向上させるために、フィードコンテナに最大高さを設定できます。以下はその例です。 ```css /* Limit the height of the Content Cards feed */ .ab-feed { max-height: 600px; /* Adjust to your needs */ overflow-y: auto; } /* For inline feeds (non-sidebar), you may want to limit individual cards */ .ab-card { max-height: 400px; /* Optional: limit individual card height */ overflow: hidden; } ``` #### ビューポートに関する考慮事項 {#viewport-considerations} インラインで表示されるContent Cardsについては、以下の例のようにビューポートの制約を考慮してください。 ```css /* Limit feed height on mobile to prevent covering too much screen */ @media (max-width: 768px) { body > .ab-feed { max-height: 80vh; /* Leave space for other content */ } } ``` ### アプリ内メッセージ {#in-app-messages} **Warning:** スライドアップ型のアプリ内メッセージに重要な情報を配置しないでください。スクリーンリーダーではアクセスできません。 ### モバイルに関する考慮事項 {#mobile-considerations} #### レスポンシブデザイン {#responsive-design} SDKにはレスポンシブブレークポイントが含まれています。カスタマイズがさまざまな画面サイズで正しく機能することを確認してください。以下はその例です。 ```css /* Mobile-specific accessibility considerations */ @media (max-width: 768px) { /* Ensure readable font sizes */ .ab-feed { font-size: 14px; /* Minimum 14px for mobile readability */ } /* Ensure sufficient touch targets */ .ab-card { padding: 16px; /* Adequate padding for touch */ } } ``` ### アクセシビリティのテスト {#testing-accessibility} #### 手動テストチェックリスト {#manual-test-checklist} 以下のタスクを実施して、アクセシビリティを手動でテストしてください。 - Content Cardsとアプリ内メッセージをキーボードのみ(Tab、Enter、Space)で操作する - スクリーンリーダー(NVDA、JAWS、VoiceOver)でテストする - すべての画像に代替テキストがあることを確認する - 色のコントラスト比を確認する(WebAIM Contrast Checkerなどのツールを使用する) - タッチ操作が可能なモバイルデバイスでテストする - フォーカスインジケーターが表示されていることを確認する - モーダルメッセージのフォーカストラッピングをテストする - すべてのインタラクティブな要素がキーボードで到達可能であることを確認する ### よくあるアクセシビリティの問題 {#common-accessibility-issues} よくあるアクセシビリティの問題を避けるために、以下を実施してください。 1. **フォーカススタイルを維持する:** SDKのフォーカスインジケーターはキーボードユーザーにとって不可欠です。 2. **`display: none`は非インタラクティブ要素にのみ使用する:** インタラクティブな要素を非表示にするには、`visibility: hidden`または`opacity: 0`を使用してください。 3. **ARIA属性をオーバーライドしない:** SDKは適切なARIAロールとラベルを設定します。 4. **`tabindex`属性を使用する:** これらはキーボードナビゲーションの順序を制御します。 5. **`overflow: hidden`を設定する場合はスクロールを提供する:** スクロール可能なコンテンツがアクセス可能であることを確認してください。 6. **組み込みのキーボードハンドラに干渉しない:** 既存のキーボードナビゲーションが正しく機能することを確認してください。 # Web Braze SDKのスマートTV対応 Source: /docs/ja/developer_guide/platforms/web/smart_tvs/index.md # スマートTV対応 {#smart-tv-support} > Braze Web SDKを使用すると、[Samsung Tizen TV](https://developer.samsung.com/smarttv/develop/specifications/tv-model-groups.html)や[LG TV (webOS)](https://webostv.developer.lge.com/discover)を含むスマートTVユーザーに対して、分析データを収集し、リッチなアプリ内メッセージやContent Cardsメッセージを表示できます。この記事では、Braze Web SDKを使用してスマートTVと統合する方法について説明します。 **Tip:** 完全なテクニカルリファレンスについては、[JavaScriptドキュメント](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html)または[サンプルアプリ](https://github.com/Appboy/smart-tv-sample-apps)をチェックして、TV上で動作するWeb SDKをご確認ください。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ## Web Braze SDKの設定 {#configuring-the-web-braze-sdk} スマートTVとの統合には、2つの変更が必要です。 1. Web SDKをダウンロードまたはインポートする際は、必ず「コア」バンドル(`https://js.appboycdn.com/web-sdk/x.y/braze.core.min.js`で入手可能、`x.y`は任意のバージョン)を使用してください。NPMバージョンはネイティブESモジュールで記述されているのに対し、CDNバージョンはES5にトランスパイルされるため、Web SDKのCDNバージョンを使用することをおすすめします。[NPMバージョン](https://www.npmjs.com/package/@braze/web-sdk)を使用する場合は、webpackのようなバンドラーを使用して未使用のコードを削除し、コードがES5にトランスパイルされていることを確認してください。 2. Web SDKを初期化する際には、`disablePushTokenMaintenance`と`manageServiceWorkerExternally`の初期化オプションを`true`に設定する必要があります。 ## 分析 {#analytics} 分析用のWeb SDKメソッドはすべて、スマートTVで使用できます。カスタムイベントやカスタム属性のトラッキングなど、詳細な手順については[分析](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions?tab=web)を参照してください。 ## アプリ内メッセージとContent Cards {#in-app-messages-and-content-cards} Braze Web SDKは、スマートTV上で[アプリ内メッセージ](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=web)と[Content Cards](https://www.braze.com/docs/ja/ja/developer_guide/content_cards?sdktab=web)の両方をサポートしています。アプリ内メッセージとContent Cardsのレンダリングは標準のUI表示ではサポートされていないため、[「Core」Web SDK](https://www.npmjs.com/package/@braze/web-sdk)を使用する必要があります。代わりに、TVアプリのエクスペリエンスに合わせてアプリでカスタマイズする必要があります。 スマートTVアプリがアプリ内メッセージを受信して表示する方法の詳細については、[メッセージのトリガー](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/triggering_messages?tab=web)を参照してください。 # Braze用TVとOTTの統合 Source: /docs/ja/developer_guide/platforms/tv_and_ott/index.md # TVとOTTの統合 {#tv-and-ott-integrations} > テクノロジーが新しいプラットフォームやデバイスへと進化するにつれて、Brazeを使ったメッセージングも進化します!Brazeは、さまざまなTVオペレーティングシステムおよびOver-the-Top(OTT)コンテンツ配信方法に対応した、さまざまなエンゲージメントチャネルを提供しています。 ## プラットフォームと機能 {#platforms-and-features} 以下は、現在サポートされている機能とメッセージングチャネルの一覧です。
プラットフォームと機能
デバイスタイプ データと分析 アプリ内メッセージ Content Cards プッシュ通知 キャンバス フィーチャーフラグ バナー
Amazon Fire TV
Kindle Fire
Android TV
LGテレビ(webOS) 該当なし
Samsung Tizen TV 該当なし
Roku 該当なし
Apple TV OS
Apple Vision Pro
- = サポート対象 - = 部分的にサポート - = Brazeではサポートされていません - 該当なし = OTTプラットフォームではサポートされていません ## 統合ガイド {#integration-guides} ### Amazon Fire TV {#fire-tv} Amazon Fire TVデバイスと統合するには、Braze Fire OS SDKを使用します。 以下の機能があります。 - クロスチャネルエンゲージメントのためのデータと分析の収集 - プッシュ通知([「ヘッドアップ通知」](https://developer.amazon.com/docs/fire-tv/notifications.html#headsup)とも呼ばれます) - これらを表示するには、優先度を「HIGH」に設定する必要があります。すべての通知はFire TVの設定メニューに表示されます。 - Content Cards - フィーチャーフラグ - アプリ内メッセージ - TVなどの非タッチ環境でHTMLメッセージを表示するには、`com.braze.configuration.BrazeConfig.Builder.setIsTouchModeRequiredForHtmlInAppMessages`を`false`に設定します([Android SDK v23.1.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2310)から利用可能) - バナー - [バナープレースメント](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements)を使用して、Fire TVアプリにメッセージを直接埋め込みます。 詳細については、[Fire OS統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=android)を参照してください。 ### Kindle Fire {#kindle-fire} Amazon Kindle Fireデバイスと統合するには、Braze Fire OS SDKを使用します。 以下の機能があります。 - クロスチャネルエンゲージメントのためのデータと分析の収集 - プッシュ通知 - Content Cards - フィーチャーフラグ - アプリ内メッセージ - バナー - [バナープレースメント](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements)を使用して、Kindle Fireにメッセージを直接埋め込みます。 詳細については、[Fire OS統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=android)を参照してください。 ### Android TV {#android-tv} Braze Android SDKを使用して、Android TVデバイスと統合します。 以下の機能があります。 - クロスチャネルエンゲージメントのためのデータと分析の収集 - Content Cards - フィーチャーフラグ - アプリ内メッセージ - TVなどの非タッチ環境でHTMLメッセージを表示するには、`com.braze.configuration.BrazeConfig.Builder.setIsTouchModeRequiredForHtmlInAppMessages`を`false`に設定します([Android SDK v23.1.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2310)から利用可能) - * プッシュ通知(手動統合が必要) - プッシュ通知はAndroid TVでネイティブにサポートされていません。理由については、Googleの[デザインガイドライン](https://designguidelines.withgoogle.com/android-tv/patterns/notifications.html)を参照してください。ただし、**プッシュ通知UIの手動統合を行うことでこれを実現できます**。設定方法については、[ドキュメント](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications?sdktab=android%20tv)を参照してください。 - バナー - [バナープレースメント](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements)を使用して、Android TVアプリにメッセージを直接埋め込みます。 詳細については、[Android SDK統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=android)を参照してください。 **Note:** Android OTT統合用に、ダッシュボードで新しいAndroidアプリを作成してください。 ### LG webOS {#lg-webos} Braze Web SDKを使用して[LG webOSテレビ](https://webostv.developer.lge.com/discover)と統合します。 以下の機能があります。 - クロスチャネルエンゲージメントのためのデータと分析の収集 - Content Cards([ヘッドレスUI](#custom-ui)経由) - フィーチャーフラグ - アプリ内メッセージ([ヘッドレスUI](#custom-ui)経由) - バナー - [バナープレースメント](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements)を使用して、webOSアプリにメッセージを直接埋め込みます。 詳細については、[Web Smart TV統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/web/smart_tvs)を参照してください。 ### Samsung Tizen {#tizen} Braze Web SDKを使用して[Samsung Tizenテレビ](https://developer.samsung.com/smarttv/develop/specifications/tv-model-groups.html)と統合します。 以下の機能があります。 - クロスチャネルエンゲージメントのためのデータと分析の収集 - Content Cards([ヘッドレスUI](#custom-ui)経由) - フィーチャーフラグ - アプリ内メッセージ([ヘッドレスUI](#custom-ui)経由) - バナー - [バナープレースメント](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements)を使用して、Tizenアプリにメッセージを直接埋め込みます。 詳細については、[Web Smart TV統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/web/smart_tvs)を参照してください。 ### Roku {#roku} Braze Roku SDKを使用して[Rokuテレビ](https://developer.roku.com/docs/developer-program/getting-started/roku-dev-prog.md)と統合します。 以下の機能があります。 - クロスチャネルエンゲージメントのためのデータと分析の収集 - アプリ内メッセージ([ヘッドレスUI](#custom-ui)経由) - RokuプラットフォームではWebviewがサポートされていないため、HTMLアプリ内メッセージもサポートされていません。 - フィーチャーフラグ 詳細については、[Roku統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=roku)を参照してください。 ### Apple TV OS {#tvos} tvOSと統合するにはBraze Swift SDKを使用します。Swift SDKにはtvOS用のデフォルトUIやビューが含まれていないため、独自に実装する必要があります。 以下の機能があります。 - クロスチャネルエンゲージメントのためのデータと分析の収集 - Content Cards([ヘッドレスUI](#custom-ui)経由) - フィーチャーフラグ - アプリ内メッセージ([ヘッドレスUI](#custom-ui)経由) - tvOSプラットフォームではWebviewがサポートされていないため、HTMLアプリ内メッセージもサポートされていません。 - tvOSでカスタマイズされたメッセージングにヘッドレスUIを使用する方法の詳細については、[サンプルアプリ](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples#inappmessages-custom-ui)を参照してください。 - サイレントプッシュ通知とバッジの更新 - バナー - [バナープレースメント](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements)を使用して、tvOSアプリにメッセージを直接埋め込みます。 詳細については、[iOS Swift SDK統合ガイド](https://github.com/braze-inc/braze-swift-sdk)を参照してください。 **Note:** TVユーザーにモバイルのアプリ内メッセージが表示されないようにするには、[アプリターゲティング](#app-targeting)を設定するか、キーと値のペアを使用してメッセージをフィルタリングしてください。例えば、特別な`tv = true`キーと値のペアが含まれている場合にのみtvOSメッセージを表示するようにします。 ### Apple Vision Pro {#vision-pro} Braze Swift SDKを使用してvisionOSと統合します。iOSで利用可能なほとんどの機能はvisionOSでも利用でき、以下が含まれます。 - 分析(セッション、カスタムイベント、購入など) - アプリ内メッセージング(データモデルとUI) - Content Cards(データモデルとUI) - プッシュ通知(アクションボタン付きのユーザー可視通知とサイレント通知) - フィーチャーフラグ - ロケーション分析 - バナー - [バナープレースメント](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements)を使用して、visionOSアプリにメッセージを直接埋め込みます。 詳細については、[iOS Swift SDK統合ガイド](https://github.com/braze-inc/braze-swift-sdk)を参照してください。 **Important:** 一部のiOS機能は部分的にサポートされているか、サポートされていません。完全なリストについては、[visionOSサポート](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/visionos)を参照してください。 ## アプリターゲティング {#app-targeting} メッセージングでOTTアプリをターゲットにするには、OTTアプリ専用のセグメントを作成することをお勧めします。 ![Android OTTアプリを使用して作成されたセグメント。](https://www.braze.com/docs/ja/ja/assets/img/android_ott.png?5835ec23ecf7848155d909dcfa1009c7) ## ヘッドレスUI {#custom-ui} **Important:** ヘッドレスUIを通じてアプリ内メッセージやContent Cardsをサポートするプラットフォームには、デフォルトのUIやビューは含まれて**いません**。独自のカスタムUI(アプリ内メッセージ用など)を構築し、SDKが提供するデータモデルを使用してそれらのUIにデータを表示してください。 ヘッドレスUIでは、BrazeがJSONなどのデータモデルを配信し、アプリが制御するUI内でアプリがそのデータを読み取って使用できます。このデータには、ダッシュボードで設定されたフィールド(タイトル、本文、ボタンテキスト、色など)が含まれており、アプリはその設定に従ってそれらを読み取り、表示できます。メッセージングのカスタム処理の詳細については、以下を参照してください。 **Android SDK** - [アプリ内メッセージのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization?sdktab=android#android_setting-custom-manager-listeners) - [Content Cardsのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/customizing_cards/style) **Swift SDK** - [アプリ内メッセージのカスタマイズ](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazeinappmessagepresenter/) - [ヘッドレスUIサンプルアプリ](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples#inappmessages-custom-ui) - [Content Cardsのカスタマイズ](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class/) **Web SDK** - [アプリ内メッセージのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/triggering_messages?tab=web) - [Content Cardsのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/customizing_cards/style) # iOSの統合の概要 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/overview/index.md

**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). Braze iOS SDKをインストールすると、基本的な分析機能(セッション処理)と基本的なアプリ内メッセージが提供されます。追加のチャネルと機能のために統合をさらにカスタマイズする必要があります。

Braze iOS SDKは、CocoaPods、Carthage、Swift Package Manager、または手動統合を使用してインストールまたは更新できます。

さらに、Braze iOS SDKはRubyMotionアプリを完全にサポートしています。 **Important:** iOS SDKは、APPファイルに加えて、アプリのIPAファイルに1 MBから2 MB、フレームワークに30 MBを追加します。 リストされているオプションのいずれかを使用して統合し、[統合を完了する](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/completing_integration)ための手順に従って、他のSDKのカスタマイズ(オプション)を有効にしたら、今後のキャンペーンのニーズに合わせて追加のチャネルと機能の統合、有効化、カスタマイズに進みます。
# iOS 用 Carthage 統合 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/carthage_integration/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # Carthage 統合 {#carthage-integration} ## SDKのインポート {#import-the-sdk} バージョン `4.4.0` から、Braze SDKは Carthage 経由での統合時に XCFrameworksをサポートしています。SDK全体をインポートするには、次の行を `Cartfile` に含めます。 ``` binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk.json" github "SDWebImage/SDWebImage" ``` SDKのインポートの詳細については、[Carthage クイックスタートガイド](https://github.com/Carthage/Carthage#quick-start)を参照してください。 `4.4.0` 以前のバージョンから移行する場合は、[XCFrameworks 用 Carthage 移行ガイド](https://github.com/Carthage/Carthage#migrating-a-project-from-framework-bundles-to-xcframeworks)を参照してください。 **Note:** `Cartfile` の構文やバージョンピン留めなどの機能の詳細については、[Carthage ドキュメント](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile)を参照してください。 Carthage のプラットフォーム固有の使用方法については、それぞれの[ユーザーガイド](https://github.com/Carthage/Carthage#if-youre-building-for-ios-tvos-or-watchos)を参照してください。 ### 以前のバージョン {#previous-versions} `3.24.0` から `4.3.4` のバージョンの場合は、次の内容を `Cartfile` に含めてください。 ``` binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk_full.json" ``` `3.24.0` 以前のバージョンをインポートするには、`Cartfile` に以下を含めます。 ``` github "Appboy/Appboy-iOS-SDK" "" ``` `` は「x.y.z」形式の Braze iOS SDKの[適切なバージョン](https://github.com/Appboy/appboy-ios-sdk/releases)に置き換えてください。 ## 次のステップ {#next-steps} 指示に従って[統合を完了](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/completing_integration)します。 ## コアのみの統合 {#core-only-integration} UIコンポーネントや依存関係なしで Core SDKを使用する場合は、以下の行を `Cartfile` に含めて Braze Carthage フレームワークのコアバージョンをインストールします。 ``` binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk_core.json" ``` # iOS 用 CocoaPods 統合 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/cocoapods/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # CocoaPods との統合 {#cocoapods-integration} ## ステップ 1:CocoaPods のインストール {#step-1-install-cocoapods} [CocoaPods](http://cocoapods.org/) 経由で iOS SDKをインストールすると、インストールプロセスの大部分が自動化されます。このプロセスを開始する前に、[Ruby バージョン 2.0.0](https://www.ruby-lang.org/en/installation/) 以降を使用していることを確認してください。このSDKのインストールに Ruby 構文の知識は必要ありませんのでご安心ください。 開始するには、次のコマンドを実行します。 ```bash $ sudo gem install cocoapods ``` CocoaPods に関して問題がある場合は、CocoaPods の[トラブルシューティングガイド](http://guides.cocoapods.org/using/troubleshooting.html)を参照してください。 **Note:** `rake` 実行可能ファイルを上書きするプロンプトが表示された場合、詳細については CocoaPods.org の [Getting started](http://guides.cocoapods.org/using/getting-started.html) を参照してください。 ## ステップ 2:Podfile の構築 {#step-2-constructing-the-podfile} CocoaPods Ruby Gem をインストールしたら、Xcode プロジェクトのディレクトリに `Podfile` という名前のファイルを作成する必要があります。 次の行を Podfile に追加します。 ``` target 'YourAppTarget' do pod 'Appboy-iOS-SDK' end ``` Pod の更新がマイナーバージョンの更新よりも小さいものを自動的に取得するように、Braze をバージョン管理することをお勧めします。これは `pod 'Appboy-iOS-SDK' ~> Major.Minor.Build` のようになります。大きな変更があっても、Braze SDKの最新バージョンを自動的に統合したい場合は、Podfile で `pod 'Appboy-iOS-SDK'` を使用できます。 ### サブスペック {#subspecs} インテグレーターは、完全なSDKをインポートすることをお勧めします。ただし、特定の Braze 機能のみを統合することが決まっている場合は、SDK全体ではなく、目的の UI サブスペックのみをインポートできます。 | サブスペック | 詳細 | | ------- | ------- | | `pod 'Appboy-iOS-SDK/InAppMessage'` | `InAppMessage` サブスペックには、Braze のアプリ内メッセージ UI と Core SDKが含まれています。| | `pod 'Appboy-iOS-SDK/ContentCards'` | `ContentCards` サブスペックには、Braze Content Card UI と Core SDKが含まれています。 | | `pod 'Appboy-iOS-SDK/NewsFeed'` | `NewsFeed` サブスペックには Braze Core SDKが含まれています。 | | `pod 'Appboy-iOS-SDK/Core'` | `Core` サブスペックは、カスタムイベントや属性などの分析をサポートしています。 | {: .ws-td-nw-1 aria-label="サブスペック" } ## ステップ 3:Braze SDKのインストール {#step-3-installing-the-braze-sdk} Braze SDK CocoaPods をインストールするには、ターミナル内で Xcode アプリプロジェクトのディレクトリに移動し、次のコマンドを実行します。 ``` pod install ``` この時点で、CocoaPods によって作成された新しい Xcode プロジェクトワークスペースを開くことができるはずです。Xcode プロジェクトの代わりに、必ずこの Xcode ワークスペースを使用してください。 ![Appboy Example フォルダが展開され、新しい `AppbpyExample.workspace` が表示されている様子。](https://www.braze.com/docs/ja/ja/assets/img_archive/podsworkspace.png?96819fcb60bb61e9a9b991e15b4ef6d6) ## 次のステップ {#next-steps} 指示に従って[統合を完了](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/completing_integration)します。 ## CocoaPods による Braze SDKの更新 {#updating-the-braze-sdk-via-cocoapods} CocoaPod を更新するには、プロジェクトディレクトリ内で以下のコマンドを実行するだけです。 ``` pod update ``` # iOS 向け Swift Package Manager の統合 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/swift_package_manager/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # Swift Package Manager の統合 {#swift-package-manager-integration} [Swift Package Manager](https://swift.org/package-manager/) (SPM) 経由で iOS SDKをインストールすると、インストールプロセスの大部分が自動化されます。このプロセスを開始する前に、Xcode 12 以降を使用していることを確認してください。 **Note:** tvOS は現在、Swift Package Manager 経由では利用できません。 ## ステップ 1:依存関係をプロジェクトに追加する {#step-1-adding-the-dependency-to-your-project} ### SDKバージョンのインポート {#import-sdk-version} プロジェクトを開き、プロジェクトの設定に移動します。**Swift Packages** タブを選択し、パッケージリストの下にある 追加ボタンをクリックします。 ![Swift Packages タブが選択された Xcode プロジェクト設定。](https://www.braze.com/docs/ja/ja/assets/img/ios/spm/swiftpackages.png?398868edc113b05736013ff65fe4371c) SDKバージョン `3.33.1` 以降をインポートする場合、iOS SDKリポジトリの URL (`https://github.com/braze-inc/braze-ios-sdk`) をテキストフィールドに入力し、**Next** をクリックします。 バージョン `3.29.0` から `3.32.0` の場合、URL `https://github.com/Appboy/Appboy-ios-sdk` を使用してください。 ![Braze iOS SDKリポジトリ URL の Xcode パッケージ依存関係追加ダイアログ。](https://www.braze.com/docs/ja/ja/assets/img/ios/spm/importsdk_example.png?10d54b223901ee4a41f1925772a9d042) 次の画面で、SDKバージョンを選択し、**Next** をクリックします。バージョン `3.29.0` 以降は Swift Package Manager と互換性があります。 ![Braze iOS SDKの Xcode パッケージバージョン選択画面。](https://www.braze.com/docs/ja/ja/assets/img/ios/spm/select_version.png?80ad4717f88ae2a3be660fc15eb50670) ### パッケージの選択 {#select-packages} ニーズに最も適したパッケージを選択し、**Finish** をクリックします。必ず `AppboyKit` または `AppboyUI` のどちらかを選択してください。両方のパッケージを含めると、望ましくない動作が発生する可能性があります。 - `AppboyUI` - Brazeが提供する UI コンポーネントを使用する場合に最適です。 - `AppboyKit` が自動的に含まれます。 - `AppboyKit` - Brazeが提供する UI コンポーネント (Content Cards、アプリ内メッセージなど) を使用する必要がない場合に最適です。 - `AppboyPushStory` - アプリに Push Stories を統合している場合は、このパッケージを含めます。これはバージョン `3.31.0` 以降でサポートされています。 - **Add to Target** のドロップダウンで、メインアプリのターゲットの代わりに `ContentExtension` ターゲットを選択してください。 ![Braze SDKライブラリターゲットを選択する Xcode パッケージ追加画面。](https://www.braze.com/docs/ja/ja/assets/img/ios/spm/add_package.png?740b02bd5b888a29365d9f2882fea061) ## ステップ 2:プロジェクトの構成 {#step-2-configuring-your-project} 次に、プロジェクトの**ビルド設定**に移動し、`-ObjC` フラグを **Other Linker Flags** 設定に追加します。SDKをさらに統合するには、このフラグを追加し、[エラー](https://developer.apple.com/library/archive/qa/qa1490/_index.html)を解決する必要があります。 ![Other Linker Flags フィールドが表示された Xcode ビルド設定。](https://www.braze.com/docs/ja/ja/assets/img/ios/spm/buildsettings.png?311ae2fec7fc6770507aaf37e6e3dc03) **Note:** `-ObjC` フラグを追加しない場合、API の一部が欠落し、動作が未定義になる可能性があります。「unrecognized selector sent to class」などの予期しないエラー、アプリケーションのクラッシュ、その他の問題が発生する可能性があります。 ## ステップ 3:ターゲットのスキームの編集 {#step-3-editing-the-targets-scheme} **Important:** Xcode 12.5 以降を使用している場合は、このステップをスキップしてください。 Xcode 12.4 以前を使用している場合は、Appboy パッケージを含むターゲットのスキームを編集します (**Product > Scheme > Edit Scheme** メニュー項目)。 1. **Build** メニューを展開し、**Post-actions** を選択します。プラス (+) ボタンを押して、**New Run Script Action** を選択します。 2. **Provide build settings from** ドロップダウンで、アプリのターゲットを選択します。 3. このスクリプトを開いたフィールドにコピーしてください: ```sh # iOS bash "$BUILT_PRODUCTS_DIR/Appboy_iOS_SDK_AppboyKit.bundle/Appboy.bundle/appboy-spm-cleanup.sh" # macOS (if applicable) bash "$BUILT_PRODUCTS_DIR/Appboy_iOS_SDK_AppboyKit.bundle/Contents/Resources/Appboy.bundle/appboy-spm-cleanup.sh" ``` ![実行スクリプトビルドフェーズを追加するための Xcode Build Phases メニュー。](https://www.braze.com/docs/ja/ja/assets/img/ios/spm/swiftmanager_buildmenu.png?22987f6735d16f8dbe868f2a7173f960) ## 次のステップ {#next-steps} 手順に従って[統合を完了](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/completing_integration)してください。 # iOS の手動統合オプション Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/manual_integration_options/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 手動統合 {#manual-integration} **Tip:** [Swift パッケージマネージャー](../swift_package_manager/)、[CocoaPods](../cocoapods/)、[Carthage](../carthage_integration/) などのパッケージマネージャーを使用してSDKを実装することを強くお勧めします。これにより、時間を大幅に節約し、プロセスの多くを自動化できます。ただし、それができない場合は、手順に従って手動で統合を完了することができます。 ## ステップ 1:Braze SDKのダウンロード {#step-1-downloading-the-braze-sdk} ### オプション 1:ダイナミック XCFramework {#option-1-dynamic-xcframework} 1. [リリースページ](https://github.com/appboy/appboy-ios-sdk/releases)から `Appboy_iOS_SDK.xcframework.zip` をダウンロードし、ファイルを展開します。 2. Xcode で、この `.xcframework` をプロジェクトにドラッグ&ドロップします。 3. プロジェクトの **General** タブで、`Appboy_iOS_SDK.xcframework` に **Embed & Sign** を選択します。 ### オプション 2:静的統合用の静的 XCFramework {#option-2-static-xcframework-for-static-integration} 1. [リリースページ](https://github.com/appboy/appboy-ios-sdk/releases)から `Appboy_iOS_SDK.zip` をダウンロードします。

2. Xcode のプロジェクトナビゲーターから、Brazeの送信先プロジェクトまたはグループを選択します。

3. **File > Add Files > Project_Name** に移動します。

4. `AppboyKit` と `AppboyUI` フォルダをグループとしてプロジェクトに追加します。 - 初めて統合する場合は、**Copy items into destination group's folder** オプションが選択されていることを確認してください。ファイルピッカーの **Options** を展開して、**Copy items if needed** と **Create groups** を選択します。 - `AppboyKit/include` と `AppboyUI/include` のディレクトリを削除します。

5. (オプション) 次のいずれかに該当する場合: - SDKのコア分析機能のみが必要で、UI 機能(アプリ内メッセージやContent Cardsなど)は使用しない。 - Braze UI 機能のカスタム UI があり、画像のダウンロードを自分で処理する。

SDKのコアバージョンは、`ABKSDWebImageProxy.m` および `Appboy.bundle` のファイルを削除することで使用できます。これにより、`SDWebImage` フレームワークの依存関係とUI関連のすべてのリソース(Nib ファイル、画像、ローカライゼーションファイルなど)がSDKから削除されます。 **Warning:** Braze UI 機能なしでコアバージョンのSDKを使用しようとしても、アプリ内メッセージは表示されません。コアバージョンで Braze Content CardsのUIを表示しようとすると、予期しない動作が発生します。 ## ステップ 2:必要な iOS ライブラリーの追加 {#step-2-adding-required-ios-libraries} 1. プロジェクトのターゲットをクリックし(左側のナビゲーションを使用)、**Build Phases** タブを選択します。

2. **Link Binary With Libraries** の下の ボタンをクリックします。

3. メニューで `SystemConfiguration.framework` を選択します。

4. `SystemConfiguration.framework` の横にあるプルダウンメニューを使用して、このライブラリーを必須としてマークします。

5. これを繰り返して、次の各必須フレームワークをプロジェクトに追加し、それぞれを「required」としてマークします。 - `QuartzCore.framework` - `libz.tbd` - `CoreImage.framework` - `CoreText.framework` - `WebKit.framework`

6. 次のフレームワークを追加し、オプションとしてマークします。 - `CoreTelephony.framework`

7. **Build Settings** タブを選択します。**Linking** セクションで、**Other Linker Flags** 設定を探し、`-ObjC` フラグを追加します。

8. Content Cardsとアプリ内メッセージングが正しく機能するには、`SDWebImage` フレームワークが必要です。`SDWebImage` はGIFを含む画像のダウンロードと表示に使用されます。Content Cardsまたはアプリ内メッセージを使用する場合は、SDWebImage の統合手順に従ってください。 ### SDWebImage 統合 {#sdwebimage-integration} `SDWebImage` をインストールするには、[手順](https://github.com/SDWebImage/SDWebImage/wiki/Installation-Guide#build-sdwebimage-as-xcframework)に従い、生成された `XCFramework` をプロジェクトにドラッグ&ドロップしてください。 ### オプションの位置情報の追跡 {#optional-location-tracking} 1. `CoreLocation.framework` を追加して位置情報の追跡を有効にします。 2. アプリで `CLLocationManager` を使用してユーザーの位置情報を認証する必要があります。 ## ステップ 3:Objective-C ブリッジヘッダー {#step-3-objective-c-bridging-header} **Note:** プロジェクトで Objective-C のみを使用する場合は、このステップをスキップしてください。 プロジェクトで Swift を使用している場合は、ブリッジヘッダーファイルが必要になります。 ブリッジヘッダーファイルがない場合は、**File > New > File > (iOS or OS X) > Source > Header File** を選択して作成し、`your-product-module-name-Bridging-Header.h` という名前を付けます。次に、ブリッジヘッダーファイルの先頭に次のコード行を追加します。 ``` #import "AppboyKit.h" ``` プロジェクトの **Build Settings** で、ヘッダーファイルの相対パスを `Swift Compiler - Code Generation` の下の `Objective-C Bridging Header` ビルド設定に追加します。 ## 次のステップ {#next-steps} 手順に従って[統合を完了](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/completing_integration)してください。 # iOS SDKの統合を完了する Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/completing_integration/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 統合を完了する {#complete-the-integration} これらの手順に従う前に、[Carthage](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/carthage_integration)、[CocoaPods](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/cocoapods)、[Swift Package Manager](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/swift_package_manager)、または[手動](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/manual_integration_options)統合のいずれかを使用してSDKを統合していることを確認してください。 ## ステップ 1:アプリデリゲートを更新する {#step-1-update-your-app-delegate} Braze SDKをCocoaPods、Carthage、または[ダイナミックな手動統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/manual_integration_options)で統合している場合は、次のコード行を`AppDelegate.m`ファイルに追加します。 ```objc #import "Appboy-iOS-SDK/AppboyKit.h" ``` Swift Package Managerまたは[静的な手動統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/manual_integration_options)を使用して統合している場合は、代わりに次の行を使用します。 ```objc #import "AppboyKit.h" ``` 次に、`AppDelegate.m`ファイル内の`application:didFinishLaunchingWithOptions:`メソッド内に以下のスニペットを追加します。 ```objc [Appboy startWithApiKey:@"YOUR-APP-IDENTIFIER-API-KEY" inApplication:application withLaunchOptions:launchOptions]; ``` **設定の管理**ページの正しい値で`YOUR-APP-IDENTIFIER-API-KEY`を更新してください。アプリ識別子APIキーの場所について詳しくは、[APIドキュメント](https://www.braze.com/docs/ja/ja/api/api_key#the-app-identifier-api-key)をご覧ください。 Braze SDKをCocoaPods、Carthage、または[ダイナミックな手動統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/manual_integration_options)で統合している場合は、次のコード行を`AppDelegate.swift`ファイルに追加します。 ```swift import Appboy_iOS_SDK ``` Swift Package Managerまたは[静的な手動統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/manual_integration_options)を使用して統合している場合は、代わりに次の行を使用します。 ```swift import AppboyKit ``` SwiftプロジェクトでのObjective-Cコードの使用の詳細については、[Apple開発者ドキュメント](https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html)を参照してください。 次に、`AppDelegate.swift`で、次のスニペットを`application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool`に追加します。 ```swift Appboy.start(withApiKey: "YOUR-APP-IDENTIFIER-API-KEY", in:application, withLaunchOptions:launchOptions) ``` **設定の管理**ページの正しい値で`YOUR-APP-IDENTIFIER-API-KEY`を更新してください。アプリ識別子APIキーの場所について詳しくは、[APIドキュメント](https://www.braze.com/docs/ja/ja/api/api_key#the-app-identifier-api-key)をご覧ください。 **Note:** `sharedInstance`シングルトンは、`startWithApiKey:`が呼び出される前はnilになります。これはBraze機能を使用するための前提条件です。 **Warning:** 必ずアプリケーションのメインスレッドでBrazeを初期化してください。非同期で初期化すると、機能が破損する可能性があります。 ## ステップ 2:データクラスターを指定する {#step-2-specify-your-data-cluster} **Note:** 2019年12月の時点で、カスタムエンドポイントは提供されなくなっていることに注意してください。既存のカスタムエンドポイントがある場合は、それを引き続き使用できます。詳細については、利用可能なエンドポイントのリスト を参照してください。 ### コンパイル時のエンドポイント設定(推奨) {#compile-time-endpoint-configuration-recommended} 既存のカスタムエンドポイントが指定されている場合: - Braze iOS SDK v3.0.2以降では、`Info.plist`ファイルを使用してカスタムエンドポイントを設定できます。`Braze`ディクショナリを`Info.plist`ファイルに追加します。`Braze`ディクショナリ内で、`Endpoint`文字列サブエントリを追加し、値をカスタムエンドポイントURLのオーソリティ(たとえば、`https://sdk.iad-01.braze.com`ではなく`sdk.iad-01.braze.com`)に設定します。Braze iOS SDK v4.0.2より前では、ディクショナリキー`Appboy`を`Braze`の代わりに使用する必要があります。 Braze担当者は、[正しいエンドポイント](https://www.braze.com/docs/ja/ja/user_guide/administer/personal/sdk_endpoints)についてすでに通知しているはずです。 ### ランタイムエンドポイント設定 {#runtime-endpoint-configuration} 既存のカスタムエンドポイントが指定されている場合: - Braze iOS SDK v3.17.0以降では、`startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions:`に渡される`appboyOptions`パラメーター内の`ABKEndpointKey`を使用してエンドポイントの設定をオーバーライドできます。値をカスタムエンドポイントURLのオーソリティ(たとえば、`https://sdk.iad-01.braze.com`ではなく`sdk.iad-01.braze.com`)に設定します。 ## SDKの統合が完了 {#sdk-integration-complete} これでBrazeはアプリケーションからデータを収集しており、基本的な統合は完了しているはずです。[カスタムイベントトラッキング](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=swift)、[プッシュメッセージング](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)、およびBraze機能の完全なスイートを有効にするには、次の記事を参照してください。 ## 起動時のBrazeのカスタマイズ {#customizing-braze-on-startup} 起動時にBrazeをカスタマイズする場合は、代わりにBraze初期化メソッド`startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions:`を使用し、オプションのBraze起動キーの`NSDictionary`を渡すことができます。 `AppDelegate.m`ファイルの`application:didFinishLaunchingWithOptions:`メソッド内に、次のBrazeメソッドを追加します。 ```objc [Appboy startWithApiKey:@"YOUR-APP-IDENTIFIER-API-KEY" inApplication:application withLaunchOptions:launchOptions withAppboyOptions:appboyOptions]; ``` このメソッドは`startWithApiKey:inApplication:withLaunchOptions:`初期化メソッドを置き換えることに注意してください。 `AppDelegate.swift`の`application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool`メソッド内に、次のBrazeメソッドを追加します。`appboyOptions`はスタートアップ設定値の`Dictionary`です。 ```swift Appboy.start(withApiKey: "YOUR-APP-IDENTIFIER-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:appboyOptions) ``` このメソッドは`startWithApiKey:inApplication:withLaunchOptions:`初期化メソッドを置き換えることに注意してください。 このメソッドは、次のパラメーターを使用して呼び出されます。 - `YOUR-APP-IDENTIFIER-API-KEY` – Brazeダッシュボードの[アプリ識別子](https://www.braze.com/docs/ja/ja/api/api_key#the-app-identifier-api-key)APIキー。 - `application` – 現在のアプリ。 - `launchOptions` – `application:didFinishLaunchingWithOptions:`から取得するオプション`NSDictionary`。 - `appboyOptions` – Brazeのスタートアップ設定値を持つオプションの`NSDictionary`。 Brazeのスタートアップキーのリストについては、[Appboy.h](https://github.com/braze-inc/braze-ios-sdk/blob/master/AppboyKit/include/Appboy.h)を参照してください。 ## Appboy.sharedInstance()とSwiftのnullability {#appboysharedinstance-and-swift-nullability} 一般的な慣例とは多少異なりますが、`Appboy.sharedInstance()`シングルトンはオプショナルです。これは、`startWithApiKey:`が呼び出される前は`sharedInstance`が`nil`であり、遅延初期化を使用できる非標準だが無効ではない実装がいくつかあるためです。 Appboyの`sharedInstance`(標準実装)にアクセスする前に`didFinishLaunchingWithOptions:`デリゲートで`startWithApiKey:`を呼び出すと、`Appboy.sharedInstance()?.changeUser("testUser")`のようなオプショナルチェーンを使用して、煩雑なチェックを回避できます。これは、非nullの`sharedInstance`を想定したObjective-C実装と同等になります。 ## その他のリソース {#additional-resources} [iOSクラスの完全なドキュメント](http://appboy.github.io/appboy-ios-sdk/docs/annotated.html)を参照して、SDKメソッドに関する追加のガイダンスを得ることができます。 # iOS向けのその他のSDKカスタマイズ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/other_sdk_customizations/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # その他のSDKカスタマイズ {#other-sdk-customizations} ## Brazeログレベル {#braze-log-level} Braze iOS SDKのデフォルトのログレベルは最小(次の表では `8`)です。このレベルではほとんどのロギングが抑制されるため、本番リリースのアプリケーションで機密情報がログに記録されることはありません。 次の使用可能なログレベルのリストを参照してください。 ### ログレベル {#log-levels} | レベル | 説明 | |----------|-------------| | 0 | 詳細。すべてのログ情報がiOSコンソールに記録されます。 | | 1 | デバッグ。デバッグ以上のログ情報がiOSコンソールに記録されます。 | | 2 | 警告。警告以上のログ情報がiOSコンソールに記録されます。 | | 4 | エラー。エラー以上のログ情報がiOSコンソールに記録されます。 | | 8 | 最小限。最小限の情報がiOSコンソールに記録されます。SDKのデフォルト設定です。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="ログレベル" } ### 詳細なログ記録 {#verbose-logging} ログレベルは、使用可能な任意の値に設定できます。ただし、ログレベルをverbose(`0`)に設定すると、統合に関する問題のデバッグに非常に役立ちます。このレベルは開発環境のみを対象としており、リリースされたアプリケーションでは設定しないでください。詳細なログ記録では、追加のユーザー情報や新しいユーザー情報がBrazeに送信されることはありません。 ### ログレベルの設定 {#setting-log-level} ログレベルはコンパイル時または実行時に割り当てることができます。 `Braze` という名前の辞書を `Info.plist` ファイルに追加します。`Braze` 辞書内で、`LogLevel` 文字列サブエントリを追加し、値を `0` に設定します。 **Note:** Braze iOS SDK v4.0.2より前では、辞書キー `Appboy` を `Braze` の代わりに使用する必要があります。 `Info.plist` コンテンツの例: ``` Braze LogLevel 0 ``` `startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions:` に渡される `appboyOptions` パラメーター内に `ABKLogLevelKey` を追加します。その値を整数 `0` に設定します。 ```objc NSMutableDictionary *appboyOptions = [NSMutableDictionary dictionary]; appboyOptions[ABKLogLevelKey] = @(0); [Appboy startWithApiKey:@"YOUR-API-KEY" inApplication:application withLaunchOptions:launchOptions withAppboyOptions:appboyOptions]; ``` ```swift let appboyOptions: [AnyHashable: Any] = [ ABKLogLevelKey : 0 ] Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:appboyOptions) ``` **Note:** ログレベルは、Braze iOS SDK v4.4.0以降で実行時にのみ設定できます。それ以前のバージョンのSDKを使用している場合は、代わりにコンパイル時にログレベルを設定してください。 ## オプションのIDFV収集 - Swift {#optional-idfv-collection-swift} Braze iOS Swift SDKの以前のバージョンでは、IDFV(Identifier for Vendor)フィールドがユーザーのデバイスIDとして自動的に収集されていました。 Swift SDK v5.7.0以降では、IDFVフィールドをオプションで無効にすることができ、代わりにBrazeはランダムなUUIDをデバイスIDとして設定します。詳細については、「[IDFVの収集](https://www.braze.com/docs/ja/ja/developer_guide/analytics/managing_data_collection?sdktab=swift)」を参照してください。 ## オプションのIDFA収集 {#optional-idfa-collection} IDFA収集はBraze SDK内ではオプションであり、デフォルトでは無効になっています。IDFA収集は、[インストールアトリビューション統合](https://www.braze.com/docs/ja/ja/partners/message_orchestration/attribution/adjust)を利用する場合にのみBraze内で必要になります。IDFAを保存することを選択した場合は、無料で保存されるため、追加の開発作業を行わずに、リリース後すぐにこれらのオプションを利用できます。 そのため、次の基準のいずれかを満たしている場合は、引き続きIDFAを収集することをお勧めします。 - アプリのインストールが以前に配信された広告に起因している - アプリケーション内のアクションが以前に配信された広告に起因している ### iOS 14.5 AppTrackingTransparency Appleは、IDFAを収集するためにユーザーが許可プロンプトを通じてオプトインすることを要求しています。 IDFAを収集するには、`ABKIDFADelegate` プロトコルを実装するだけでなく、アプリケーションではApp Tracking TransparencyフレームワークでAppleの `ATTrackingManager` を使用してユーザーから承認を要求する必要があります。詳細については、Appleの[ユーザープライバシーに関する記事](https://developer.apple.com/app-store/user-privacy-and-data-use/)を参照してください。 App Tracking Transparency承認のプロンプトには、識別子の使用法を説明する `Info.plist` エントリが必要です。 ``` NSUserTrackingUsageDescription To retarget ads and build a global profile to better serve you things you would like. ``` ### IDFA収集の実装 {#implementing-idfa-collection} IDFA収集を実装するには、次のステップに従います。 #### ステップ 1:ABKIDFADelegateを実装する {#step-1-implement-abkidfadelegate} [`ABKIDFADelegate`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKIDFADelegate.h) プロトコルに準拠したクラスを作成します。 ```objc #import "IDFADelegate.h" #import #import @implementation IDFADelegate - (NSString *)advertisingIdentifierString { return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString]; } - (BOOL)isAdvertisingTrackingEnabledOrATTAuthorized { if (@available(iOS 14, *)) { return [ATTrackingManager trackingAuthorizationStatus] == ATTrackingManagerAuthorizationStatusAuthorized; } return [[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled]; } @end ``` ```swift import Appboy_iOS_SDK import AdSupport import AppTrackingTransparency class IDFADelegate: NSObject, ABKIDFADelegate { func advertisingIdentifierString() -> String { return ASIdentifierManager.shared().advertisingIdentifier.uuidString } func isAdvertisingTrackingEnabledOrATTAuthorized() -> Bool { if #available(iOS 14, *) { return ATTrackingManager.trackingAuthorizationStatus == ATTrackingManager.AuthorizationStatus.authorized } return ASIdentifierManager.shared().isAdvertisingTrackingEnabled } } ``` ##### ステップ 2:Brazeの初期化中にデリゲートを設定する {#step-2-set-the-delegate-during-braze-initialization} `startWithApiKey:inApplication:withAppboyOptions:` に渡される `appboyOptions` 辞書で、`ABKIDFADelegateKey` キーを `ABKIDFADelegate` 準拠クラスのインスタンスに設定します。 ## iOS SDKのおおよそのサイズ {#ios-sdk-size} iOS SDKフレームワークファイルのおおよそのサイズは30 MBで、.ipa(アプリファイルへの追加)のおおよそのサイズは1 MBから2 MBです。 Brazeは、[アプリのサイズ設定に関するAppleの推奨事項](https://developer.apple.com/library/content/qa/qa1795/_index.html)に従って、SDKが `.ipa` のサイズに与える影響を観察することで、iOS SDKのサイズを測定しています。アプリケーションに追加されるiOS SDKのサイズを計算する場合は、[アプリサイズレポートの取得](https://developer.apple.com/library/content/qa/qa1795/_index.html)に従って、Braze iOS SDKを統合する前と後の `.ipa` のサイズの違いを比較することをお勧めします。App Thinningサイズレポートからサイズを比較する場合は、Thinningされた `.ipa` ファイルのアプリサイズを確認することもお勧めします。ユニバーサル `.ipa` ファイルは、App Storeからダウンロードしてユーザーのデバイスにインストールされたバイナリーよりも大きくなるためです。 **Note:** CocoaPods経由で `use_frameworks!` と統合する場合は、正確なサイズ測定のためにターゲットのビルド設定で `Enable Bitcode = NO` を設定してください。 # iOS 用 Braze SDK 統合ガイド(オプション) Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/ios_sdk_integration/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # Braze iOS SDK 統合ガイド {#braze-ios-sdk-integration-guide} > このオプションのiOS統合ガイドでは、iOS SDKとそのコアコンポーネントを初めてアプリケーションに統合する際のセットアップのベストプラクティスについて段階的に説明します。このガイドは、`BrazeManager.swift` ヘルパーファイルを作成する際に役立ちます。このヘルパーファイルは、Braze iOS SDKへの依存関係をプロダクションコードの残りの部分から切り離し、アプリケーション全体で `import AppboyUI` を1か所だけにします。このアプローチにより、過剰なSDKインポートから発生する問題が軽減され、コードの追跡、デバッグ、および変更が容易になります。 **Important:** このガイドでは、すでにXcodeプロジェクトに[SDKを追加](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/overview)していることを前提としています。 ## 統合の概要 {#integration-overview} 以下の手順は、プロダクションコードが呼び出す `BrazeManager` ヘルパーファイルの作成に役立ちます。このヘルパーファイルは、以下にリストされている統合トピックのさまざまなエクステンションを追加することで、Braze関連のすべての依存関係を処理します。各トピックには、SwiftとObjective-Cの両方の水平タブステップとコードスニペットが含まれます。アプリケーションでこれらのチャネルを使用する予定がない場合、Content Cardsとアプリ内メッセージのステップは統合に必要ありません。 - [BrazeManager.swiftの作成](#create-brazemanagerswift) - [SDKの初期化](#initialize-the-sdk) - [プッシュ通知](#push-notifications) - [ユーザー変数とメソッドへのアクセス](#access-user-variables-and-methods) - [分析のログ記録](#log-analytics) - [アプリ内メッセージ(オプション)](#in-app-messages) - [Content Cards(オプション)](#content-cards) - [次のステップ](#next-steps) ### BrazeManager.swiftの作成 {#create-brazemanagerswift} #### BrazeManager.swiftの作成 `BrazeManager.swift` ファイルを作成するには、_BrazeManager_ という名前の新しいSwiftファイルを作成し、プロジェクトの任意の場所に追加します。次に、`import Foundation` をSPMの場合は `import AppboyUI` に(CocoaPodsの場合は `import Appboy_iOS_SDK` に)置き換え、すべてのBraze関連のメソッドと変数をホストするための `BrazeManager` クラスを作成します。`Appboy_iOS_SDK` **Note:** - `BrazeManager` は構造体ではなく `NSObject` クラスであるため、`ABKInAppMessageUIDelegate` などのABKデリゲートに準拠できます。 - `BrazeManager` は設計上シングルトンクラスであり、このクラスのインスタンスは1つだけ使用されます。これは、オブジェクトへの統一されたアクセスポイントを提供するために行われます。 1. `BrazeManager` クラスを初期化する _shared_ という名前の静的変数を追加します。これは一度だけ遅延初期化されることが保証されています。 2. 次に、_apiKey_ という名前のプライベート定数変数を追加し、Brazeダッシュボードのワークスペースから取得したAPIキー値として設定します。 3. _appboyOptions_ という名前のプライベート計算変数を追加します。これにはSDKの設定値が格納されます。今のところ空です。 ```swift class BrazeManager: NSObject { // 1 static let shared = BrazeManager() // 2 private let apikey = "YOUR-API-KEY" // 3 private var appboyOptions: [String:Any] { return [:] } } ``` ```objc @implementation BrazeManager // 1 + (instancetype)shared { static BrazeManager *shared = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ shared = [[BrazeManager alloc] init]; // Do any other initialisation stuff here }); return shared; } // 2 - (NSString *)apiKey { return @"YOUR-API-KEY"; } // 3 - (NSDictionary *)appboyOptions { return [NSDictionary dictionary]; } ``` ### SDKの初期化 {#initialize-the-sdk} #### BrazeManager.swiftからSDKを初期化する {#initialize-sdk-from-brazemanagerswift} 次に、SDKを初期化する必要があります。このガイドでは、すでにXcodeプロジェクトに[SDKを追加](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/overview)していることを前提としています。また、[ワークスペースSDKエンドポイント](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/initial_sdk_setup/completing_integration#step-2-specify-your-data-cluster)および[`LogLevel`](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/initial_sdk_setup/other_sdk_customizations#braze-log-level)を `Info.plist` ファイルまたは `appboyOptions` に設定する必要があります。 `didFinishLaunchingWithOptions` メソッドを `AppDelegate.swift` ファイルから戻り値の型なしで `BrazeManager.swift` ファイルに追加します。`BrazeManager.swift` ファイルに同様のメソッドを作成することで、`AppDelegate.swift` ファイルに `import AppboyUI` ステートメントは不要になります。 次に、新しく宣言した `apiKey` および `appboyOptions` 変数を使用してSDKを初期化します。 **Important:** 初期化はメインスレッドで行う必要があります。 ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { Appboy.start(withApiKey: apikey, in: application, withLaunchOptions: launchOptions, withAppboyOptions: appboyOptions) } ``` ```objc - (void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Appboy startWithApiKey:[self apiKey] inApplication:application withLaunchOptions:launchOptions withAppboyOptions:[self appboyOptions]]; } ``` ##### AppDelegate.swiftでのAppboy初期化処理 {#handle-appboy-initialization-in-the-appdelegateswift} 次に、`AppDelegate.swift` ファイルに戻り、AppDelegateの `didFinishLaunchingWithOptions` メソッドに以下のコードスニペットを追加して、`BrazeManager.swift` ヘルパーファイルからAppboyの初期化を処理します。`AppDelegate.swift` に `import AppboyUI` ステートメントを追加する必要はありません。 ```swift func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Override point for customization after application launch BrazeManager.shared.application(application, didFinishLaunchingWithOptions: launchOptions) return true } ``` ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch [[BrazeManager shared] application:application didFinishLaunchingWithOptions:launchOptions]; return YES; } ``` **Checkpoint:** コードをコンパイルしてアプリケーションを実行してください。

この時点で、SDKが稼働しているはずです。ダッシュボードでセッションがログに記録されていることを確認してから、次に進んでください。 ### プッシュ通知 {#push-notifications} #### プッシュ証明書の追加 {#add-push-certificate} Brazeダッシュボードで既存のワークスペースに移動します。**プッシュ通知の設定**で、プッシュ証明書ファイルをBrazeダッシュボードにアップロードして保存します。 ![APNsキーのアップロードフィールドが表示されたBrazeダッシュボードのプッシュ通知設定。](https://www.braze.com/docs/ja/ja/assets/img/ios_sdk/ios_sdk2.png?6e92324225dd71128662df17dbf54d2b){: style="max-width:60%;"} **Important:** このステップの最後にある専用チェックポイントを見逃さないでください! ##### プッシュ通知の登録 {#register-for-push-notifications} 次に、プッシュ通知を登録します。このガイドでは、Apple開発者ポータルおよびXcodeプロジェクトで[プッシュ認証情報を正しく設定](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)していることを前提としています。 プッシュ通知を登録するコードは、`BrazeManager.swift` ファイルの `didFinishLaunching...` メソッドに追加されます。初期化コードは最終的に次のようになります。 1. ユーザーとのインタラクションの許可を要求するためのコンテンツを設定します。これらのオプションは例としてリストされています。 2. ユーザーにプッシュ通知を送信する許可を要求します。プッシュ通知を許可または拒否するユーザーの応答は、`granted` 変数で追跡されます。 3. ユーザーが通知プロンプトを操作した後、プッシュ承認の結果をBrazeに転送します。 4. APNsで登録プロセスを開始します。これはメインスレッドで行う必要があります。登録が成功すると、アプリは `AppDelegate` オブジェクトの `didRegisterForRemoteNotificationsWithDeviceToken` メソッドを呼び出します。 ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:[UIApplication.LaunchOptionsKey:Any]?) { Appboy.start(withAPIKey: apikey, in: application, withLaunchOptions: launchOptions, withAppboyOptions: appboyOptions) // 1 let options: UNAuthorizationOptions = [.alert, .sound, .badge] // 2 UNUserNotificationCenter.current().requestAuthorization(option: options) { (granted, error) in // 3 Appboy.sharedInstance()?.pushAuthorization(fromUserNotificationCenter: granted) } // 4 UIApplications.shared.registerForRemoteNotificiations() } ``` ```objc - (void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Appboy startWithApiKey:[self apiKey] inApplication:application withLaunchOptions:launchOptions withAppboyOptions:[self appboyOptions]]; // 1 UNAuthorizationOptions options = (UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge); // 2 [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) { // 3 [[Appboy sharedInstance] pushAuthorizationFromUserNotificationCenter:granted]; }]; // 4 [[UIApplication sharedApplication] registerForRemoteNotifications]; } ``` **Checkpoint:** コードをコンパイルしてアプリケーションを実行してください。 - アプリで、プッシュ通知の許可を求めるプロンプトが表示されていることを確認してから、先に進んでください。 - プロンプトが表示されない場合は、アプリを削除して再インストールし、プッシュ通知のプロンプトが以前に表示されていないことを確認してください。 プッシュ通知の許可を求めるプロンプトが表示されていることを確認してから、先に進んでください。 ##### プッシュ通知メソッドの転送 {#forward-push-notification-methods} 次に、システムのプッシュ通知メソッドを `AppDelegate.swift` から `BrazeManager.swift` に転送し、Braze iOS SDKで処理されるようにします。 ###### ステップ1: プッシュ通知コードのエクステンションを作成する {#step-1-create-extension-for-push-notification-code} `BrazeManager.swift` ファイルにプッシュ通知コードのエクステンションを作成し、ヘルパーファイルでどのような目的が果たされているかをより整理された形で読み取れるようにします。以下に例を示します。 1. `AppDelegate` に `import AppboyUI` ステートメントを含めないパターンに従って、`BrazeManager.swift` ファイルでプッシュ通知メソッドを処理します。ユーザーのデバイストークンは、`didRegisterForRemote...` メソッドからBrazeに渡される必要があります。このメソッドは、サイレントプッシュ通知を実装するために必要です。次に、`BrazeManager` クラスに `AppDelegate` と同じメソッドを追加します。 2. 以下の行をメソッド内に追加して、デバイストークンをBrazeに登録します。これは、Brazeがトークンを現在のデバイスに関連付けるために必要です。 ```swift // MARK - Push Notifications extension BrazeManager { // 1 func application( _ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data ) { // 2 Appboy.sharedInstance().?registerDeviceToken(deviceToken) } } ``` ```objc // MARK - Push Notifications // 1 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // 2 [[Appboy sharedInstance] registerDeviceToken:deviceToken]; } ``` ###### ステップ2: リモート通知のサポート {#step-2-support-remote-notifications} **Signing & Capabilities** タブで、**Background Modes** のサポートを追加し、**Remote notifications** を選択して、Brazeから発信されるリモートプッシュ通知のサポートを開始します。

![Signing & Capabilities](https://www.braze.com/docs/ja/ja/assets/img/ios_sdk/ios_sdk3.png?8064706b42f135ed57efdfbd6102a9a0) ###### ステップ3: リモート通知の処理 {#step-3-remote-notification-handling} Braze SDKは、Brazeから発信されるリモートプッシュ通知を処理できます。リモート通知をBrazeに転送してください。SDKはBrazeから発信されたものではないプッシュ通知を自動的に無視します。プッシュ通知エクステンション内の `BrazeManager.swift` ファイルに次のメソッドを追加します。 ```swift func application( _ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void ) { Appboy.sharedInstance()?.register( application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler ) } ``` ```objc - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { [[Appboy sharedInstance] registerApplication:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; } ``` ###### ステップ4: 通知応答の転送 {#step-4-forward-notification-responses} Braze SDKは、Brazeから発信されるプッシュ通知の応答を処理できます。通知の応答をBrazeに転送してください。SDKは、Brazeから発信されていないプッシュ通知からの応答を自動的に無視します。以下のメソッドを `BrazeManager.swift` ファイルに追加します。 ```swift func userNotificationCenter( _ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void ) { Appboy.sharedInstance()?.userNotificationCenter( center, didReceive: response, withCompletionHandler: completionHandler ) } ``` ```objc - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [[Appboy sharedInstance] userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; } ``` **Checkpoint:** コードをコンパイルしてアプリケーションを実行してください。

Brazeダッシュボードからプッシュ通知を送信してみて、プッシュ通知から分析がログに記録されていることを確認してから、次に進んでください。 ### ユーザー変数とメソッドへのアクセス {#access-user-variables-and-methods} #### ユーザー変数とメソッドの作成 {#create-user-variables-and-methods} 次に、`ABKUser` の変数とメソッドに簡単にアクセスできるようにします。`BrazeManager.swift` ファイルにユーザーコードのエクステンションを作成し、ヘルパーファイルでどのような目的が果たされているかをより整理された形で読み取れるようにします。以下に例を示します。 1. `ABKUser` オブジェクトは、iOSアプリケーションの既知または匿名ユーザーを表します。`ABKUser` を取得するための計算変数を追加します。この変数は、ユーザーに関する変数を取得するために再利用されます。 2. `userId` に簡単にアクセスするには、ユーザー変数をクエリします。他の変数の中で、`ABKUser` オブジェクトは(`firstName`、`lastName`、`phone`、`homeCity` など)を管理します。 3. 対応する `userId` で `changeUser()` を呼び出してユーザーを設定します。 ```swift // MARK: - User extension BrazeManager { // 1 var user: ABKUser? { return Appboy.sharedInstance()?.user } // 2 var userId: String? { return user?.userID } // 3 func changeUser(_ userId: String) { Appboy.sharedInstance()?.changeUser(userId) } } ``` ```objc // MARK: - User // 1 - (ABKUser *)user { return [[Appboy sharedInstance] user]; } // 2 - (NSString *)userId { return [self user].userID; } // 3 - (void)changeUser:(NSString *)userId { [[Appboy sharedInstance] changeUser:userId]; } ``` **Checkpoint:** コードをコンパイルしてアプリケーションを実行してください。

サインイン/サインアップに成功したユーザーを識別してみてください。何が適切なユーザー識別子であり、何が適切でないかをしっかりと理解してください。

ダッシュボードで、ユーザー識別子がログに記録されていることを確認してから、先に進んでください。 ### 分析のログ記録 {#log-analytics} #### カスタムイベント記録メソッドの作成 {#create-log-custom-event-method} 以下のBraze SDKの `logCustomEvent` メソッドに基づいて、一致するメソッドを作成します。 **Braze `logCustomEvent` 参照メソッド**
Braze iOS SDKのメソッドに直接アクセスできるのは `BrazeManager.swift` ファイルだけなので、これは仕様です。したがって、一致するメソッドを作成することで、結果は同じになり、プロダクションコード内でBraze iOS SDKに直接依存する必要がなくなります。 ``` open func logCustomEvent(_ eventName: String, withProperties properties: [AnyHashable : Any]?) ``` **一致するメソッド**
`Appboy` オブジェクトからBrazeにカスタムイベントを記録します。`Properties` はオプションのパラメータで、デフォルト値はnilです。カスタムイベントにはプロパティは必須ではありませんが、名前は必須です。 ```swift func logCustomEvent(_ eventName: String, withProperties properties: [AnyHashable: Any]? = nil) { Appboy.sharedInstance()?.logCustomEvent(eventName, withProperties: properties) } ``` ```objc - (void)logCustomEvent:(NSString *)eventName withProperties:(nullable NSDictionary *)properties { [[Appboy sharedInstance] logCustomEvent:eventName withProperties:properties]; } ``` ##### カスタム属性記録メソッドの作成 {#create-log-custom-attributes-method} SDKは、カスタム属性として多数のタイプをログに記録できます。設定可能な値タイプごとにヘルパーメソッドを作成する必要はありません。代わりに、適切な値に絞り込むことができる1つのメソッドのみを公開します。 ``` - (BOOL)setCustomAttributeWithKey:(NSString *)key andBOOLValue:(BOOL)value; - (BOOL)setCustomAttributeWithKey:(NSString *)key andIntegerValue:(NSIntenger)value; - (BOOL)setCustomAttributeWithKey:(NSString *)key andDoubleValue:(double)value; - (BOOL)setCustomAttributeWithKey:(NSString *)key andStringValue:(NSString *)value; - (BOOL)setCustomAttributeWithKey:(NSString *)key andDateValue:(NSDate *)value; ``` カスタム属性は、`ABKUser` オブジェクトからログに記録されます。 属性に設定可能なすべてのタイプを包含できる**1つのメソッド**を作成します。分析エクステンションの `BrazeManager.swift` ファイルにこのメソッドを追加します。これは、有効なカスタム属性タイプをフィルタリングして、一致するタイプに関連付けられたメソッドを呼び出すことによって行うことができます。 - パラメータ `value` は、`Equatable` プロトコルに準拠するジェネリック型です。これは明示的に行われるため、タイプがBraze iOS SDKの期待するものでない場合、コンパイル時エラーが発生します。 - パラメータ `key` および `value` はオプションのパラメータで、メソッド内で条件付きでアンラップされます。これは、nil以外の値がBraze iOS SDKに渡されるようにする1つの方法です。 ```swift func setCustomAttributeWithKey(_ key: String?, andValue value: T?) { guard let key = key, let value = value else { return } switch value.self { case let value as Date: user?.setCustomAttributeWithKey(key, andDateValue: value) case let value as Bool: user?.setCustomAttributeWithKey(key, andBOOLValue: value) case let value as String: user?.setCustomAttributeWithKey(key, andStringValue: value) case let value as Double: user?.setCustomAttributeWithKey(key, andDoubleValue: value) case let value as Int: user?.setCustomAttributeWithKey(key, andIntegerValue: value) default: return } } ``` ```objc - (void)setCustomAttributeWith:(NSString *)key andValue:(id)value { if ([value isKindOfClass:[NSDate class]]) { [[self user] setCustomAttributeWithKey:key andDateValue:value]; } else if ([value isKindOfClass:[NSString class]]) { [[self user] setCustomAttributeWithKey:key andStringValue:value]; } else if ([value isKindOfClass:[NSNumber class]]) { if (strcmp([value objCType], @encode(double)) == 0) { [[self user] setCustomAttributeWithKey:key andDoubleValue:[value doubleValue]]; } else if (strcmp([value objCType], @encode(int)) == 0) { [[self user] setCustomAttributeWithKey:key andIntegerValue:[value integerValue]]; } else if ([value boolValue]) { [[self user] setCustomAttributeWithKey:key andBOOLValue:[value boolValue]]; } } } ``` ##### 購入記録メソッドの作成 {#create-log-purchase-method} 次に、以下のBraze SDKの `logPurchase` メソッドに基づいて、一致するメソッドを作成します。 **Braze `logPurchase` 参照メソッド**
Braze iOS SDKのメソッドに直接アクセスできるのは `BrazeManager.swift` ファイルだけなので、これは仕様です。したがって、一致するメソッドを作成することで、結果は同じになり、プロダクションコード内でBraze iOS SDKに直接依存する必要がなくなります。 ``` open func logPurchase(_ productIdentifier: String, inCurrency currency: String, atPrice price: NSDecimalNumber, withoutQuantity quantity: UInt) ``` **一致するメソッド**
`Appboy` オブジェクトからの購入をBrazeに記録します。SDKには購入を記録するための複数のメソッドがあり、これは1つの例にすぎません。このメソッドは、`NSDecimal` および `UInt` オブジェクトの作成も処理します。その部分をどのように処理するかはあなた次第ですが、以下はほんの一例です。 ```swift func logPurchase(_ productIdentifier: String, inCurrency currency: String, atPrice price: String, withQuantity quantity: Int) { Appboy.sharedInstance()?.logPurchase(productIdentifier, inCurrency: currency, atPrice: NSDecimalNumber(string: price), withQuantity: UInt(quantity)) } ``` ```objc - (void)logPurchase:(NSString *)productIdentifier inCurrency:(nonnull NSString *)currencyCode atPrice:(nonnull NSDecimalNumber *)price withQuantity:(NSUInteger)quantity { [[Appboy sharedInstance] logPurchase:productIdentifier inCurrency:currencyCode atPrice:price withQuantity:quantity]; } ``` **Checkpoint:** コードをコンパイルしてアプリケーションを実行してください。

カスタムイベントを記録してみてください。

ダッシュボードで、カスタムイベントがログに記録されていることを確認してから先に進んでください。 ### アプリ内メッセージ {#in-app-messages} **Important:** アプリケーションでこのチャネルを使用する予定がない場合、以下のアプリ内メッセージセクションは統合に必要ありません。 #### ABKInAppMessageUIDelegateに準拠する {#conform-to-abkinappmessageuidelegate} 次に、`BrazeManager.swift` ファイルのコードを `ABKInAppMessageUIDelegate` に準拠させ、関連付けられたメソッドを直接処理できるようにします。 デリゲートに準拠するコードは、`BrazeManager.swift` ファイルの `didFinishLaunching...` メソッドに追加されます。初期化コードは最終的に次のようになります。 ```swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { Appboy.start(withApiKey: apiKey, in: application, withLaunchOptions: launchOptions, withAppboyOptions: appboyOptions) let options: UNAuthorizationOptions = [.alert, .sound, .badge] UNUserNotificationCenter.current().requestAuthorization(options: options) { (granted, error) in Appboy.sharedInstance()?.pushAuthorization(fromUserNotificationCenter: granted) } UIApplication.shared.registerForRemoteNotifications() Appboy.sharedInstance()?.inAppMessageController.inAppMessageUIController?.setInAppMessageUIDelegate?(self) } ``` ```objc - (void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Appboy startWithApiKey:[self apiKey] inApplication:application withLaunchOptions:launchOptions withAppboyOptions:[self appboyOptions]]; UNAuthorizationOptions options = (UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge); [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) { [[Appboy sharedInstance] pushAuthorizationFromUserNotificationCenter:granted]; }]; [[UIApplication sharedApplication] registerForRemoteNotifications]; [[Appboy sharedInstance].inAppMessageController.inAppMessageUIController setInAppMessageUIDelegate:self]; } ``` ##### デリゲートメソッドの追加 {#add-delegate-methods} 次に、`ABKInAppMessageUIDelegate` に準拠するエクステンションを作成します。 次のスニペットを分析セクションに追加します。`BrazeManager.swift` オブジェクトがデリゲートとして設定されていることに注意してください。これは、`BrazeManager.swift` ファイルがすべての `ABKInAppMessageUIDelegate` メソッドを処理する場所です。 **Important:** `ABKInAppMessageUIDelegate` には必須メソッドはありませんが、以下は1つの例です。 ```swift // MARK: - ABKInAppMessage UI Delegate extension AppboyManager: ABKInAppMessageUIDelegate{ func inAppMessageViewControllerWith(_ inAppMessage: ABKInAppMessage) -> ABKInAppMessageViewController { switch inAppMessage { case is ABKInAppMessageSlideup: return ABKInAppMessageSlideupViewController(inAppMessage: inAppMessage) case is ABKInAppMessageModal: return ABKInAppMessageModalViewController(inAppMessage: inAppMessage) case is ABKInAppMessageFull: return ABKInAppMessageFullViewController(inAppMessage: inAppMessage) case is ABKInAppMessageHTML: return ABKInAppMessageHTMLViewController(inAppMessage: inAppMessage) default: return ABKInAppMessageViewController(inAppMessage: inAppMessage) } ``` ```objc // MARK: - ABKInAppMessage UI Delegate - (ABKInAppMessageViewController *)inAppMessageViewControllerWithInAppMessage:(ABKInAppMessage *)inAppMessage { if ([inAppMessage isKindOfClass:[ABKInAppMessageSlideup class]]) { return [[ABKInAppMessageSlideupViewController alloc] initWithInAppMessage:inAppMessage]; } else if ([inAppMessage isKindOfClass:[ABKInAppMessageModal class]]) { return [[ABKInAppMessageModalViewController alloc] initWithInAppMessage:inAppMessage]; } else if ([inAppMessage isKindOfClass:[ABKInAppMessageFull class]]) { return [[ABKInAppMessageFullViewController alloc] initWithInAppMessage:inAppMessage]; } else if ([inAppMessage isKindOfClass:[ABKInAppMessageHTML class]]) { return [[ABKInAppMessageHTMLViewController alloc] initWithInAppMessage:inAppMessage]; } return nil; } ``` **Checkpoint:** コードをコンパイルしてアプリケーションを実行してください。

アプリ内メッセージを送信してみてください。

`BrazeManager.swift` ファイルで、`ABKInAppMessageUIDelegate` メソッドの例のエントリにブレークポイントを設定します。アプリ内メッセージを送信し、ブレークポイントに到達したことを確認してから、さらに進んでください。 ### Content Cards {#content-cards} **Important:** アプリケーションでこのチャネルを使用する予定がない場合、以下のContent Cardsセクションは統合に必要ありません。 #### Content Cardsの変数とメソッドの作成 {#create-content-card-variables-and-methods} 不要な `import AppboyUI` ステートメントなしで、Content Cardsビューコントローラーを表示できるようにプロダクションコードを有効にします。 `BrazeManager.swift` ファイルにContent Cardsコードのエクステンションを作成し、ヘルパーファイルでどのような目的が果たされているかをより整理された形で読み取れるようにします。以下に例を示します。 1. `ABKContentCardsTableViewController` を表示します。オプションの `navigationController` は、ビューコントローラーを表示またはプッシュするために必要な唯一のパラメータです。 2. `ABKContentCardsTableViewController` オブジェクトを初期化し、オプションでタイトルを変更します。初期化されたビューコントローラーをナビゲーションスタックに追加する必要もあります。 ```swift // MARK: - Content Cards extension BrazeManager { // 1 func displayContentCards(navigationController: UINavigationController?) { // 2 let contentCardsVc = ABKContentCardsTableViewController() contentCardsVc.title = "Content Cards" navigationController?.pushViewController(contentCardsVc, animated: true) } } ``` ```objc // MARK: - Content Cards // 1 - (void)displayContentCards:(UINavigationController *)navigationController { // 2 ABKContentCardsTableViewController *contentCardsVc = [[ABKContentCardsTableViewController alloc] init]; contentCardsVc.title = @"Content Cards"; [navigationController pushViewController:contentCardsVc animated:YES]; } ``` **Checkpoint:** コードをコンパイルしてアプリケーションを実行してください。

アプリケーションで `ABKContentCardsTableViewController` を表示してみてから先に進んでください。 ## 次のステップ {#next-steps} おめでとうございます!このベストプラクティス統合ガイドを完了しました!`BrazeManager` ヘルパーファイルの例は、[GitHub](https://github.com/braze-inc/braze-growth-shares-ios-demo-app/blob/master/Braze-Demo/BrazeManager.swift)にあります。 これで、Braze iOS SDKへの依存関係をプロダクションコードの残りの部分から切り離すことができたので、オプションの高度な実装ガイドをいくつかご覧ください。 - [高度なプッシュ通知実装ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/implementation_guide) - [高度なアプリ内メッセージ実装ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/implementation_guide) - [高度なContent Cards実装ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/implementation_guide) # iOS 向けのプッシュ統合 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # プッシュ統合 {#push-integration} ## ステップ 1:APNsトークンをアップロードする {#step-1-upload-your-apns-token} Before you can send an iOS push notification using Braze, you need to upload your `.p8` push notification file, as described in [Apple's developer documentation](https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns): 1. In your Apple developer account, go to [**Certificates, Identifiers & Profiles**](https://developer.apple.com/account/ios/certificate). 2. Under **Keys**, select **All** and click the add button (+) in the upper-right corner. 3. Under **Key Description**, enter a unique name for the signing key. 4. Under **Key Services**, select the **Apple Push Notification service (APNs)** checkbox, then click **Continue**. Click **Confirm**. 5. Note the key ID. Click **Download** to generate and download the key. Make sure to save the downloaded file in a secure place, as you cannot download this more than once. 6. In Braze, go to **Settings** > **App Settings** and upload the `.p8` file under **Apple Push Certificate**. You can upload either your development or production push certificate. To test push notifications after your app is live in the App Store, its recommended to set up a separate workspace for the development version of your app. 7. When prompted, enter your app's [bundle ID](https://developer.apple.com/documentation/foundation/nsbundle/1418023-bundleidentifier), [key ID](https://developer.apple.com/help/account/manage-keys/get-a-key-identifier/), and [team ID](https://developer.apple.com/help/account/manage-your-team/locate-your-team-id). You'll also need to specify whether to send notifications to your app's development or production environment, which is defined by its provisioning profile. 8. When you're finished, select **Save**. ## ステップ 2:プッシュ機能を有効にする {#step-2-enable-push-capabilities} プロジェクト設定で、**Capabilities** タブの **Push Notifications** 機能がオンになっていることを確認します。 ![プロジェクト設定で、Capabilities タブの Push Notifications 機能がオンになっていることを確認します。](https://www.braze.com/docs/ja/ja/assets/img_archive/Enable_push_capabilities.png?8a3957eea917ba442294b7dbbe60732f) 開発用と本番用のプッシュ証明書が別々にある場合は、**General** タブの **Automatically manage signing** チェックボックスをオフにしてください。これにより、Xcodeの自動コード署名機能は開発署名のみを行うため、ビルド構成ごとに異なるプロビジョニングプロファイルを選択できるようになります。 ![「General」タブが表示されている Xcode プロジェクトの設定。このタブでは、「Automatically manage signing」オプションがオフになっています。](https://www.braze.com/docs/ja/ja/assets/img_archive/xcode8_auto_signing.png?b00c3b1c9fb39c8f9977bc42343af466) ## ステップ 3:プッシュ通知に登録する {#step-3-register-for-push-notifications} ユーザーのデバイスをAPNsに登録するには、アプリの `application:didFinishLaunchingWithOptions:` デリゲートメソッド内に適切なコードサンプルを含める必要があります。アプリケーションのメインスレッドですべてのプッシュ統合コードを呼び出すようにしてください。 Brazeには、プッシュアクションボタンをサポートするデフォルトのプッシュカテゴリーも用意されており、プッシュ登録コードに手動で追加する必要があります。その他の統合ステップについては、[プッシュアクションボタン](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/action_buttons)を参照してください。 **Warning:** [プッシュ通知のベストプラクティス](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/troubleshooting)の説明に従ってカスタムプッシュプロンプトを実装している場合は、アプリにプッシュ権限を付与した後、**アプリが実行されるたびに**次のコードを呼び出すようにしてください。**[デバイストークンは任意に変更される可能性がある](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html)ため、アプリはAPNsに再登録する必要があります。** ### UserNotification フレームワークの使用(iOS 10以降) {#using-usernotification-framework-ios-10} iOS 10で導入された `UserNotifications` フレームワーク(推奨)を使用している場合は、アプリデリゲートの `application:didFinishLaunchingWithOptions:` メソッドに以下のコードを追加します。 **Important:** 次のコードサンプルには、仮のプッシュ認証の統合が含まれています(5行目と6行目)。アプリで仮認証を使用する予定がない場合は、`requestAuthorization` オプションに `UNAuthorizationOptionProvisional` を追加するコード行を削除できます。
プッシュ仮認証の詳細については、[iOS 通知オプション](https://www.braze.com/docs/ja/ja/user_guide/channels/push/platform_specific_resources/ios/notification_options)をご覧ください。 ```objc if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max) { UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; UNAuthorizationOptions options = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge; if (@available(iOS 12.0, *)) { options = options | UNAuthorizationOptionProvisional; } [center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) { [[Appboy sharedInstance] pushAuthorizationFromUserNotificationCenter:granted]; }]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } else { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil]; [[UIApplication sharedApplication] registerForRemoteNotifications]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; } ``` ```swift if #available(iOS 10, *) { let center = UNUserNotificationCenter.current() center.delegate = self as? UNUserNotificationCenterDelegate var options: UNAuthorizationOptions = [.alert, .sound, .badge] if #available(iOS 12.0, *) { options = UNAuthorizationOptions(rawValue: options.rawValue | UNAuthorizationOptions.provisional.rawValue) } center.requestAuthorization(options: options) { (granted, error) in Appboy.sharedInstance()?.pushAuthorization(fromUserNotificationCenter: granted) } UIApplication.shared.registerForRemoteNotifications() } else { let types : UIUserNotificationType = [.alert, .badge, .sound] let setting : UIUserNotificationSettings = UIUserNotificationSettings(types:types, categories:nil) UIApplication.shared.registerUserNotificationSettings(setting) UIApplication.shared.registerForRemoteNotifications() } ``` **Warning:** アプリの起動が完了する前に、`center.delegate = self` を使用してデリゲートオブジェクトを同期的に割り当てる必要があります(可能であれば `application:didFinishLaunchingWithOptions:` で)。そうしないと、アプリが受信プッシュ通知を受け取れなくなる可能性があります。詳細については、Appleの [`UNUserNotificationCenterDelegate`](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate) ドキュメントを参照してください。 ### UserNotification フレームワークを使用しない場合 {#without-usernotifications-framework} `UserNotifications` フレームワークを使用していない場合は、アプリデリゲートの `application:didFinishLaunchingWithOptions:` メソッドに次のコードを追加します。 ```objc UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil]; [[UIApplication sharedApplication] registerForRemoteNotifications]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; ``` ```swift let types : UIUserNotificationType = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert var setting : UIUserNotificationSettings = UIUserNotificationSettings(forTypes: types, categories: nil) UIApplication.shared.registerUserNotificationSettings(setting) UIApplication.shared.registerForRemoteNotifications() ``` ## ステップ 4:Brazeにプッシュトークンを登録する {#step-4-register-push-tokens-with-braze} APNsの登録が完了したら、次のメソッドを変更して結果の `deviceToken` をBrazeに渡し、ユーザーがプッシュ通知を受信できるようにする必要があります。 `application:didRegisterForRemoteNotificationsWithDeviceToken:` メソッドに次のコードを追加します。 ```objc [[Appboy sharedInstance] registerDeviceToken:deviceToken]; ``` アプリの `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)` メソッドに次のコードを追加します。 ```swift Appboy.sharedInstance()?.registerDeviceToken(deviceToken) ``` **Important:** `application:didRegisterForRemoteNotificationsWithDeviceToken:` デリゲートメソッドは、`[[UIApplication sharedApplication] registerForRemoteNotifications]` の呼び出し後に毎回呼び出されます。他のプッシュサービスからBrazeに移行する場合、ユーザーのデバイスがすでにAPNsに登録されていれば、このメソッドは次回呼び出されたときに既存の登録からトークンを収集するため、ユーザーがプッシュに再オプトインする必要はありません。 ## ステップ 5:プッシュ処理を有効にする {#step-5-enable-push-handling} 以下のコードは受信したプッシュ通知をBrazeに渡すもので、プッシュ分析とリンク処理のログ記録に必要です。アプリケーションのメインスレッドですべてのプッシュ統合コードを呼び出すようにしてください。 ### iOS 10以降 iOS 10以降に対してビルドする場合は、`UserNotifications` フレームワークを統合し、以下の手順を実行することをお勧めします。 アプリケーションの `application:didReceiveRemoteNotification:fetchCompletionHandler:` メソッドに次のコードを追加します。 ```objc [[Appboy sharedInstance] registerApplication:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; ``` 次に、アプリの `(void)userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:` メソッドに次のコードを追加します。 ```objc [[Appboy sharedInstance] userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; ``` **フォアグラウンドでのプッシュ通知処理** アプリがフォアグラウンドにある間にプッシュ通知を表示するには、`userNotificationCenter:willPresentNotification:withCompletionHandler:` を実装します。 ```objc - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { if (@available(iOS 14.0, *)) { completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner); } else { completionHandler(UNNotificationPresentationOptionAlert); } } ``` フォアグラウンド通知がクリックされると、iOS 10のプッシュデリゲート `userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:` が呼び出され、Brazeはプッシュクリックイベントをログに記録します。 アプリの `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)` メソッドに次のコードを追加します。 ```swift Appboy.sharedInstance()?.register(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler) ``` 次に、アプリの `userNotificationCenter(_:didReceive:withCompletionHandler:)` メソッドに次のコードを追加します。 ```swift Appboy.sharedInstance()?.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) ``` **フォアグラウンドでのプッシュ通知処理** アプリがフォアグラウンドにある間にプッシュ通知を表示するには、`userNotificationCenter(_:willPresent:withCompletionHandler:)` を実装します。 ```swift func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { if #available(iOS 14.0, *) { completionHandler([.list, .banner]); } else { completionHandler([.alert]); } } ``` フォアグラウンド通知がクリックされると、iOS 10のプッシュデリゲート `userNotificationCenter(_:didReceive:withCompletionHandler:)` が呼び出され、Brazeはプッシュクリックイベントをログに記録します。 ### iOS 10より前のバージョン {#pre-ios-10} iOS 10では、プッシュがクリックされたときに `application:didReceiveRemoteNotification:fetchCompletionHandler:` を呼び出さないように動作が更新されました。そのため、iOS 10以降に対応するビルドに更新せず `UserNotifications` フレームワークを使用しない場合、古いスタイルの両方のデリゲートからBrazeを呼び出す必要があり、以前の統合とは異なります。 SDK < iOS 10に対してビルドするアプリについては、以下の手順を使用してください。 プッシュ通知でオープントラッキングを有効にするには、アプリの `application:didReceiveRemoteNotification:fetchCompletionHandler:` メソッドに次のコードを追加します。 ```objc [[Appboy sharedInstance] registerApplication:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; ``` iOS 10でプッシュ分析をサポートするには、アプリの `application:didReceiveRemoteNotification:` デリゲートメソッドに次のコードも追加する必要があります。 ```objc [[Appboy sharedInstance] registerApplication:application didReceiveRemoteNotification:userInfo]; ``` プッシュ通知でオープントラッキングを有効にするには、アプリの `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)` メソッドに次のコードを追加します。 ```swift Appboy.sharedInstance()?.register(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler) ``` iOS 10でプッシュ分析をサポートするには、アプリの `application(_:didReceiveRemoteNotification:)` デリゲートメソッドに次のコードも追加する必要があります。 ```swift Appboy.sharedInstance()?.register(application, didReceiveRemoteNotification: userInfo) ``` ## ステップ 6:ディープリンク {#step-6-deep-linking} プッシュからアプリへのディープリンクは、標準のプッシュ統合ドキュメントを介して自動的に処理されます。アプリ内の特定の場所にディープリンクを追加する方法について詳しくは、[高度なユースケース](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/advanced_use_cases/linking#linking-implementation)を参照してください。 ## ステップ 7:単体テスト(オプション) {#step-7-unit-tests-optional} ここまでの統合手順のテストカバレッジを追加するには、[プッシュ単体テスト](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/unit_tests)を実装します。 # iOS のプッシュカスタマイズ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/index.md

# iOS 用プッシュアクションボタン Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/action_buttons/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # アクションボタン {#push-action-buttons-integration} Braze iOS SDKは、各プッシュアクションボタンのURL処理サポートなど、デフォルトのプッシュカテゴリーをサポートしています。現在、デフォルトカテゴリーには、`Accept`/`Decline`、`Yes`/`No`、`Confirm`/`Cancel`、および`More`の4セットのプッシュアクションボタンがあります。 ![カスタマイズ可能な2つのアクションボタンを表示するためにプルダウンされているプッシュメッセージのGIF。](https://www.braze.com/docs/ja/ja/assets/img_archive/iOS8Action.gif?d3553a68ae1aa0c3a58da9e65174f404) デフォルトのプッシュカテゴリーを登録するには、統合手順に従ってください。 ## ステップ 1:Brazeのデフォルトプッシュカテゴリーの追加 {#step-1-adding-braze-default-push-categories} 以下のコードを使用して、[プッシュ登録](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/push_notifications/integration#step-4-register-push-tokens-with-braze)時にデフォルトのプッシュカテゴリーに登録します。 ```objc // For UserNotification.framework (iOS 10+ only) NSSet *appboyCategories = [ABKPushUtils getAppboyUNNotificationCategorySet]; [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:appboyCategories]; // For UIUserNotificationSettings (before iOS 10) NSSet *appboyCategories = [ABKPushUtils getAppboyUIUserNotificationCategorySet]; UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:appboyCategories]; [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; ``` ```swift // For UserNotification.framework (iOS 10+ only) let appboyCategories = ABKPushUtils.getAppboyUNNotificationCategorySet() UNUserNotificationCenter.current().setNotificationCategories(appboyCategories) // For UIUserNotificationSettings (before iOS 10) let appboyCategories = ABKPushUtils.getAppboyUIUserNotificationCategorySet() let settings = UIUserNotificationSettings.init(types: .badge, categories: appboyCategories) UIApplication.shared.registerUserNotificationSettings(settings) ``` バックグラウンドアクティベーションモードでプッシュアクションボタンをクリックすると、通知が閉じられるだけで、アプリは開きません。ユーザーが次回アプリを開くと、これらのアクションのボタンクリック分析がサーバーにフラッシュされます。 独自のカスタム通知カテゴリーを作成する場合は、[アクションボタンのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/push_notifications/customization/action_buttons#push-category-customization)を参照してください。 ## ステップ 2:インタラクティブなプッシュ処理を有効にする {#step-2-enable-interactive-push-handling} `UNNotification`フレームワークを使用しており、Brazeの[デリゲート](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/push_notifications/integration#step-5-enable-push-handling)を実装している場合は、このメソッドがすでに統合されているはずです。 クリック分析やURLルーティングを含むプッシュアクションボタンの処理を有効にするには、アプリの`(void)userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:`デリゲートメソッドに次のコードを追加します。 ```objc [[Appboy sharedInstance] userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; ``` ```swift Appboy.sharedInstance()?.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) ``` UNNotificationフレームワークを使用していない場合は、プッシュアクションボタンの処理を有効にするために、アプリの`application:handleActionWithIdentifier:forRemoteNotification:completionHandler:`に次のコードを追加する必要があります。 ```objc [[Appboy sharedInstance] getActionWithIdentifier:identifier forRemoteNotification:userInfo completionHandler:completionHandler]; ``` ```swift Appboy.sharedInstance()?.getActionWithIdentifier(identifier, forRemoteNotification: userInfo,, completionHandler: completionHandler) ``` **Important:** `handleActionWithIdentifier`を使用している方は、`UNNotification`フレームワークの使用を開始することを強くお勧めします。[`handleActionWithIdentifier`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623068-application?language=objc)が非推奨になったため、これをお勧めします。 ## プッシュカテゴリーのカスタマイズ {#push-category-customization} Brazeは、[デフォルトのプッシュカテゴリー](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/action_buttons)のセットを提供するだけでなく、カスタムの通知カテゴリーやアクションもサポートしています。アプリケーションにカテゴリーを登録すると、Brazeダッシュボードを使用して通知カテゴリーをユーザーに送信できます。 `UserNotifications`フレームワークを使用していない場合は、[代替カテゴリー](https://developer.apple.com/documentation/usernotifications/unnotificationcategory)のドキュメントを参照してください。 その後、これらのカテゴリーをダッシュボードからプッシュ通知に割り当てて、デザインのアクションボタン構成をトリガーできます。デバイスに表示される`LIKE_CATEGORY`を活用する例を次に示します。 ![「いいねを取り消す」と「いいね」の2つのプッシュアクションボタンを表示するプッシュメッセージ。](https://www.braze.com/docs/ja/ja/assets/img_archive/push_example_category.png?342eb7b8bc6d24142ee32606e22f8eee) # iOS用カスタムプッシュ通知サウンド Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/custom_sounds/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # カスタムサウンド {#custom-sounds} ## ステップ 1:アプリでサウンドをホスティングする {#step-1-hosting-the-sound-in-the-app} カスタムプッシュ通知サウンドは、クライアントアプリケーションのメインバンドル内でローカルにホストする必要があります。以下のオーディオデータ形式が使用できます。 - リニア PCM - MA4 - µLaw - aLaw オーディオデータは AIFF、WAV、または CAF ファイルにパッケージできます。Xcode で、サウンドファイルをアプリケーションバンドルの非ローカライズリソースとしてプロジェクトに追加します。 afconvert ツールを使用してサウンドを変換できます。たとえば、16ビットリニア PCM システムサウンド Submarine.aiff を CAF ファイルの IMA4 オーディオに変換するには、ターミナルで次のコマンドを使用します。 ```bash afconvert /System/Library/Sounds/Submarine.aiff ~/Desktop/sub.caf -d ima4 -f caff -v ``` QuickTime Player でサウンドを開き、**ムービー**メニューから**ムービーインスペクターを表示**を選択すると、サウンドのデータ形式を確認できます。 カスタムサウンドは再生時間が30秒未満である必要があります。カスタムサウンドがこの制限を超えている場合、デフォルトのシステムサウンドが代わりに再生されます。 ## ステップ 2:ダッシュボードにサウンドのプロトコル URL を指定する {#step-2-providing-the-dashboard-with-a-protocol-url-for-the-sound} サウンドはアプリ内でローカルにホストする必要があります。プッシュコンポーザーの**サウンド**フィールドで、アプリ内のサウンドファイルの場所を示すプロトコルURLを指定する必要があります。このフィールドに「default」を指定すると、デバイスのデフォルトの通知音が再生されます。これは、[messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)、または以下のスクリーンショットに示すようにプッシュコンポーザーの**設定**にあるダッシュボードを使用して指定できます。 ![サウンドはアプリ内でローカルにホストする必要があります。プッシュコンポーザーのサウンドフィールドで、アプリ内のサウンドファイルの場所を示すプロトコル URL を指定する必要があります。このフィールドに「default」を指定すると、デバイスのデフォルトの通知音が再生されます。messaging API またはプッシュコンポーザーの設定にあるダッシュボードを使用して指定できます。](https://www.braze.com/docs/ja/ja/assets/img_archive/sound_push_ios.png?c035b34ffb6c0f720f6d2c08ca1ba2b2) 指定したサウンドファイルが存在しない場合、またはキーワード「default」を入力した場合、Brazeはデバイスのデフォルトのアラートサウンドを使用します。ダッシュボードとは別に、[messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)でサウンドを設定することもできます。詳細については、[カスタムアラートサウンドの準備](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/SupportingNotificationsinYourApp.html)に関する Apple 開発者ドキュメントを参照してください。 # iOS のリッチプッシュ通知 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/rich_notifications/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS 10リッチプッシュ通知 iOS 10では、画像、GIF、およびビデオでプッシュ通知を送信する機能が導入されています。この機能を有効にするには、クライアントは`Service Extension` を作成する必要があります。これは、プッシュペイロードが表示される前に変更できる新しいタイプの拡張機能です。 ## サービス拡張の作成 [`Notification Service Extension`](https://developer.apple.com/reference/usernotifications/unnotificationserviceextension) を作成するには、Xcode で **[ファイル] > [新規] > [ターゲット]** に移動し、[**通知サービス拡張**] を選択します。 ![](https://www.braze.com/docs/ja/ja/assets/img_archive/ios10_se_at.png?ad077697c9a4c7c7bc3ca07a6405c05d){: style="max-width:90%"} アプリケーションに拡張機能を埋め込むように [**アプリケーションに埋め込む**] が設定されていることを確認します。 ## サービス拡張の設定 `Notification Service Extension` は、アプリにバンドルされている独自のバイナリです。これは、[Apple Developer Portal](https://developer.apple.com)に独自のアプリIDとプロビジョニングプロファイルで設定する必要があります。 `Notification Service Extension` のバンドル ID は、メインアプリターゲットのバンドル ID とは異なる必要があります。たとえば、アプリのバンドル ID が `com.company.appname` の場合、サービス拡張に `com.company.appname.AppNameServiceExtension` を使用できます。 ### Braze で動作するようにサービス拡張を設定する Braze は、リッチコンテンツの設定、ダウンロード、および表示に使用する `ab` キーの下にある APNs ペイロードの添付ペイロードを送信します。以下に例を示します。 ```json { "ab" : { ... "att" : { "url" : "http://mysite.com/myimage.jpg", "type" : "jpg" } }, "aps" : { ... } } ``` 関連するペイロード値は次のとおりです。 `````````objc // The Braze dictionary key static NSString *const AppboyAPNSDictionaryKey = @"ab"; // The attachment dictionary static NSString *const AppboyAPNSDictionaryAttachmentKey = @"att"; // The attachment URL static NSString *const AppboyAPNSDictionaryAttachmentURLKey = @"url"; // The type of the attachment - a suffix for the file you save static NSString *const AppboyAPNSDictionaryAttachmentTypeKey = @"type"; ``` Braze ペイロードで手動でプッシュ通知を表示するには、`AppboyAPNSDictionaryAttachmentURLKey` の下の値からコンテンツをダウンロードし、`AppboyAPNSDictionaryAttachmentTypeKey` キーの下に格納されているファイルタイプのファイルとして保存し、通知添付ファイルに追加します。 ### サンプルコード サービス拡張は、Objective-C または Swift で記述できます。 Objective-C サンプルコードを使用するには、`Notification Service Extension` ターゲットの自動生成された `NotificationService.m` の内容をAppboy の [`NotificationService.m`](https://github.com/Appboy/appboy-ios-sdk/blob/master/Example/StopwatchNotificationService/NotificationService.m) の内容に置き換えます。 Swift サンプルコードを使用するには、`Notification Service Extension` ターゲットの自動生成された`NotificationService.swift` の内容を Appboy の [`NotificationService.swift`](https://github.com/Appboy/appboy-ios-sdk/blob/master/HelloSwift/HelloSwiftNotificationExtension/NotificationService.swift) の内容に置き換えます。 ## ダッシュボードでリッチプッシュ通知を作成する Braze ダッシュボードでリッチプッシュ通知を作成するには、iOS プッシュを作成するか、イメージまたは GIF を添付するか、画像、GIF、または動画をホストするURL を指定します。アセットはプッシュ通知の受信時にダウンロードされるため、コンテンツをホスティングしている場合は、要求が大規模に同期的に急増することを想定する必要があります。 サポートされているファイルタイプとサイズのリストについては、[`unnotificationattachment`](https://developer.apple.com/reference/usernotifications/unnotificationattachment)を参照してください。 # iOS のプッシュ通知バッジ数 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/badges/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # バッジ Braze ダッシュボードを通じてプッシュ通知を作成するときに、希望のバッジ数を指定できます。アプリケーションの [`applicationIconBadgeNumber`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instp/UIApplication/applicationIconBadgeNumber) プロパティまたは[リモート通知ペイロード](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW1)を使用して、バッジ数を手動で更新することもできます。Braze では、アプリがフォアグラウンドで動作しているときに Braze 通知を受信した場合にもバッジ 数はクリアされます。 通常のアプリ操作の一部として、またはバッジをクリアするプッシュを送信してバッジをクリアする計画がない場合は、次のコードをアプリの `applicationDidBecomeActive:` デリゲートメソッドに追加してアプリがアクティブになったときにバッジをクリアする必要があります。 ```objc // For iOS 16.0+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center setBadgeCount:0 withCompletionHandler:^(NSError * _Nullable error) { if (error != nil) { // Handle errors } }]; // Prior to iOS 16. Deprecated in iOS 17+. [UIApplication sharedApplication].applicationIconBadgeNumber = 0; ``` `````````swift // For iOS 16.0+ let center = UNUserNotificationCenter.current() do { try await center.setBadgeCount(0) } catch { // Handle errors } // Prior to iOS 16. Deprecated in iOS 17+. UIApplication.shared.applicationIconBadgeNumber = 0 ``` バッジ番号を 0 に設定すると、通知センターの通知も消去されることに注意してください。したがって、プッシュペイロードにバッジ番号を設定しない場合でも、バッジ番号を0に設定することで、ユーザーがプッシュをクリックした後に通知センターでプッシュ通知を削除できます。 # iOS向けBraze内部プッシュ通知を無視する Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/ignoring_internal_push/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # Brazeの内部プッシュ通知を無視する Braze は、特定の高度な機能の内部実装にサイレントプッシュ通知を使用します。ほとんどの統合では、アプリに代わって変更を行う必要はありません。ただし、内部プッシュ通知に依存する Braze 機能 (アンインストール追跡やジオフェンスなど) を統合する場合は、内部プッシュ通知を無視するようにアプリを更新することが必要になる場合があります。 アプリで、アプリケーションの起動またはバックグラウンドプッシュで自動アクションが実行される場合は、\\ 内部プッシュ通知によってトリガーされないように、そのアクティビティをゲートすることを検討する必要があります。たとえば、バックグラウンドプッシュまたはアプリケーションの起動のたびに新しいコンテンツを取得するためにサーバーを呼び出すロジックがある場合、不要なネットワーク トラフィックが発生するため、内部プッシュによってそれがトリガーされることは望ましくないでしょう。さらに、Braze は特定の種類の内部プッシュをすべてのユーザーにほぼ同時に送信するため、起動時に内部プッシュからのネットワーク呼び出しをゲートしないと、サーバーに重大な負荷がかかる可能性があります。 ## アプリの自動アクションを確認する 次の場所でアプリケーションの自動アクションを確認し、内部プッシュを無視するようにコードを更新する必要があります。 1. **プッシュレシーバー。**バックグラウンドプッシュ通知により、`UIApplicationDelegate` の `application:didReceiveRemoteNotification:fetchCompletionHandler:` が呼び出されます。 2. **アプリケーションデリゲート。**バックグラウンドプッシュにより、[中断された](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html#//apple_ref/doc/uid/TP40007072-CH2-SW3)アプリがバックグラウンドで起動し、`UIApplicationDelegate` の `application:willFinishLaunchingWithOptions:` および `application:didFinishLaunchingWithOptions:` メソッドがトリガーされます。これらのメソッドの `launchOptions` をチェックして、アプリケーションがバックグラウンドプッシュから起動されたかどうかを判断できます。 ## Braze 内部プッシュユーティリティ メソッドの使用 `ABKPushUtils` のユーティリティーメソッドを使用して、アプリが Braze の内部プッシュを受信したか、または Braze の内部プッシュによって起動されたかを確認できます。`isAppboyInternalRemoteNotification:` はすべての Braze 内部プッシュ通知で `YES` を返し、`isUninstallTrackingRemoteNotification:` と `isGeofencesSyncRemoteNotification:` はそれぞれアンインストール追跡とジオフェンス同期通知で `YES` を返します。メソッド宣言については、[`ABKPushUtils.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKPushUtils.h) を参照してください。 ## 実装例 {#internal-push-implementation-example} ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSDictionary *pushDictionary = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; BOOL launchedFromAppboyInternalPush = pushDictionary && [ABKPushUtils isAppboyInternalRemoteNotification:pushDictionary]; if (!launchedFromAppboyInternalPush) { // ... Gated logic here (such as pinging your server to download content) ... } } ``` `````````objc - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { if (![ABKPushUtils isAppboyInternalRemoteNotification:userInfo]) { // ... Gated logic here (such as pinging server for content) ... } } ``` `````````swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { let pushDictionary = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? NSDictionary as? [AnyHashable : Any] ?? [:] let launchedFromAppboyInternalPush = ABKPushUtils.isAppboyInternalRemoteNotification(pushDictionary) if (!launchedFromAppboyInternalPush) { // ... Gated logic here (such as pinging your server to download content) ... } } ``` `````````swift func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { if (!ABKPushUtils.isAppboyInternalRemoteNotification(userInfo)) { // ... Gated logic here (such as pinging server for content) ... } } ``` # 高度なプッシュ設定 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/advanced_settings/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 高度な設定 {#advanced-settings} プッシュキャンペーンを作成する際、作成ステップで**設定**を選択し、利用可能な高度な設定を表示します。 ![Brazeダッシュボードに表示されたiOSプッシュキャンペーンの高度な設定。](https://www.braze.com/docs/ja/ja/assets/img_archive/ios_advanced_settings.png?16f142abe70d854830708b0cb21d9465) ## プッシュのキーと値のペアからデータを抽出する {#extracting-data-from-push-key-value-pairs} Brazeを使用すると、`extras`として知られるカスタム定義の文字列キーと値のペアを、アプリケーションへプッシュ通知と一緒に送ることができます。エクストラは、ダッシュボードまたはAPIを介して定義でき、プッシュデリゲートの実装に渡される`notification`辞書内のキーと値のペアとして利用できます。 ## アラートオプション {#alert-options} **アラートオプション**チェックボックスをオンにすると、デバイスでの通知の表示方法を調整するためのキーと値のドロップダウンが表示されます。 ## コンテンツ利用可能フラグを追加する {#adding-content-available-flag} 新しいコンテンツをバックグラウンドでダウンロードするようデバイスに指示するには、**コンテンツ利用可能フラグを追加**チェックボックスをオンにします。最も一般的には、[サイレント通知](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/silent_push_notifications)の送信に関心がある場合にチェックできます。 ## mutable-contentフラグを追加する {#adding-mutable-content-flag} **Mutable-Contentフラグを追加**チェックボックスをオンにして、iOS 10以上のデバイスで受信者の高度なカスタマイズを有効にします。このフラグは、このチェックボックスの値に関係なく、[リッチプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/rich_notifications)を作成するときに自動的に送信されます。 ## アプリのバッジ数を更新する {#update-app-badge-count} バッジ数を更新したい数値を入力するか、Liquid構文を使用してカスタム条件を設定します。また、アプリケーションの`applicationIconBadgeNumber`プロパティやプッシュ通知のペイロードを使って、バッジ数を手動で更新することもできます。詳しくは、[バッジ数](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/badges)についての専用の記事を参照してください。 ## サウンド {#sounds} ここでは、アプリバンドル内のサウンドファイルへのパスを入力し、プッシュメッセージ受信時に再生するサウンドを指定できます。指定されたサウンドファイルが存在しない場合、またはキーワード「default」が入力された場合、Brazeはデフォルトのデバイスアラートサウンドを使用します。カスタマイズの詳細については、[カスタムサウンド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/custom_sounds)についての専用の記事を参照してください。 ## 折りたたみID {#collapse-id} 同様の通知をまとめるには、折りたたみIDを指定します。同一の折りたたみIDを使用して複数の通知を送信すると、デバイスには最後に受信した通知のみが表示されます。[統合された通知](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1)については、Appleのドキュメントを参照してください。 ## 有効期限 {#expiry} **有効期限**チェックボックスをオンにすると、メッセージの有効期限を設定できます。ユーザーのデバイスが接続を失った場合、Brazeは指定された時間までメッセージの送信を試行し続けます。設定されていない場合、プラットフォームの有効期限はデフォルトで30日となります。配信前に有効期限切れとなったプッシュ通知は失敗とはみなされず、バウンスとして記録されないことに注意してください。 # iOS 向けのサイレントプッシュ通知 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/silent_push_notifications/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # サイレントプッシュ通知 {#silent-push-notifications} プッシュ通知を使用すると、重要なイベントが発生したときにアプリに通知できます。新しいインスタントメッセージを配信したり、ニュース速報を送信したり、ユーザーのお気に入りのテレビ番組の最新エピソードがオフライン視聴用にダウンロードできるようになったときに、プッシュ通知を送信できます。プッシュ通知は、アラートメッセージやサウンドを含まず、アプリのインターフェイスの更新やバックグラウンド作業のトリガーにのみ使用されるサイレント通知にすることもできます。 プッシュ通知は、バックグラウンドでの取得間の遅延が許容できないような、散発的だが即時に必要なコンテンツに適しています。プッシュ通知は、アプリケーションが必要な場合にのみ起動するため、バックグラウンドでの取得よりもはるかに効率的です。 プッシュ通知にはレート制限があるため、アプリケーションで必要なだけ送信しても構いません。iOSとAPNsサーバーが配信頻度をコントロールするため、送信しすぎても問題が発生することはありません。プッシュ通知がスロットリングされている場合、デバイスが次にキープアライブパケットを送信するか、別の通知を受信するまで遅延する可能性があります。 ## サイレントプッシュ通知の送信 {#sending-silent-push-notifications} サイレントプッシュ通知を送信するには、プッシュ通知ペイロードで `content-available` フラグを `1` に設定します。サイレントプッシュ通知を送信する場合、アプリケーションがイベントを参照できるように、通知ペイロードにデータを含めることもできます。これにより、ネットワークリクエストがいくらか節約され、アプリの応答性が向上する可能性があります。 **Warning:** タイトルと本文の両方を `content-available=1` で付加することは、未定義の動作につながる可能性があるため、推奨されません。通知が本当にサイレントであることを確認するには、`content-available` フラグを `1` に設定するときに、タイトルと本文の両方を除外してください。詳細については、[バックグラウンド更新に関するAppleの公式ドキュメント](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app)を参照してください。 `content-available` フラグは、Brazeダッシュボードおよび[メッセージングAPI](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)の[Appleプッシュオブジェクト](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/apple_object)内で設定できます。 ![プッシュコンポーザーの「設定」タブにある「content-available」チェックボックスを表示するBrazeダッシュボード。](https://www.braze.com/docs/ja/ja/assets/img_archive/remote_notification.png?7c9ef06cb8e9c148d37019f5e01d0ce6 "content available") ## サイレントプッシュ通知を使用してバックグラウンド作業をトリガーする {#use-silent-push-notifications-to-trigger-background-work} サイレントプッシュ通知を使用すると、ユーザーに通知することなく、アプリを「一時停止」または「非実行」状態からウェイクし、コンテンツを更新したり、特定のタスクを実行したりできます。 サイレントプッシュ通知を使用してバックグラウンド作業をトリガーするには、前述の手順に従って、メッセージやサウンドなしで `content-available` フラグを設定します。アプリのバックグラウンドモードを設定して、プロジェクト設定の**Capabilities**タブで `remote notifications` を有効にします。リモート通知は、`content-available` フラグが設定された通常のプッシュ通知です。 ![Xcodeの「capabilities」の下に「remote notifications」モードのチェックボックスが表示されています。](https://www.braze.com/docs/ja/ja/assets/img_archive/background_mode.png?15bb65e9a98f4b01af0c73c3917d6950 "background mode enabled") [アンインストール追跡](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_uninstalls?sdktab=swift)では、リモート通知のバックグラウンドモードを有効にする必要があります。 リモート通知バックグラウンドモードが有効になっている場合でも、ユーザーがアプリケーションを強制終了した場合、システムはアプリをバックグラウンドで起動しません。システムによってアプリがバックグラウンドで自動的に起動される前に、ユーザーはアプリケーションを明示的に起動するか、デバイスを再起動する必要があります。 詳細については、[バックグラウンド更新のプッシュ](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app?language=objc)および [`application:didReceiveRemoteNotification:fetchCompletionHandler:`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:didReceiveRemoteNotification:fetchCompletionHandler:) を参照してください。 ## iOSのサイレント通知の制限事項 {#ios-silent-notifications-limitations} iOSオペレーティングシステムは、一部の機能の通知をゲートする場合があります。これらの機能で問題が発生している場合は、iOSのサイレント通知ゲートが原因である可能性があることに注意してください。 Brazeには、iOSサイレントプッシュ通知に依存するいくつかの機能があります。 | 機能 | ユーザーエクスペリエンス | |---|---| | アンインストール追跡 | ユーザーはサイレントな夜間アンインストール追跡プッシュを受け取ります。| | ジオフェンス | サーバーからデバイスへのジオフェンスのサイレント同期。| {: .reset-td-br-1 .reset-td-br-2 aria-label="iOSのサイレント通知の制限事項" } 詳細については、Appleの[インスタンスメソッド](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application)および[未受信通知](https://developer.apple.com/library/content/technotes/tn2265/_index.html#//apple_ref/doc/uid/DTS40010376-CH1-TNTAG23)のドキュメントを参照してください。 [8]:https://developer.apple.com/library/content/technotes/tn2265/_index.html#//apple_ref/doc/uid/DTS40010376-CH1-TNTAG23 # iOS 用プッシュプライマー Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/push_primer/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # プッシュプライマーの統合 {#push-primer-integration} プッシュプライマーキャンペーンは、アプリのデバイスでプッシュを有効にするようユーザーに促します。ユーザーのデバイスに直接メッセージを送信する許可を得るのは複雑な場合がありますが、当社のガイドが役立ちます。このガイドでは、開発者がプッシュプライミングを統合するために行う必要のあるステップを示します。 ## ステップ 1: AppDelegate.m ファイルにスニペットを追加する {#step-1-add-snippet-in-appdelegatem-file} 標準統合の代わりに、次のコード行を `AppDelegate.m` ファイルに追加します。 ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... if (@available(iOS 10.0, *)) { UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { if (settings.authorizationStatus != UNAuthorizationStatusNotDetermined) { // authorization has already been requested, need to follow usual steps [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) { [[Appboy sharedInstance] pushAuthorizationFromUserNotificationCenter:granted]; }]; center.delegate = self; [center setNotificationCategories:[ABKPushUtils getAppboyUNNotificationCategorySet]]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } }]; } else { UIApplication *sharedApplication = [UIApplication sharedApplication]; UIUserNotificationSettings *notificationSettings = [sharedApplication currentUserNotificationSettings]; if (notificationSettings.types) { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:[ABKPushUtils getAppboyUIUserNotificationCategorySet]]; [sharedApplication registerUserNotificationSettings:settings]; [sharedApplication registerForRemoteNotifications]; } } ``` ```swift if #available(iOS 10, *) { let center = UNUserNotificationCenter.current() center.getNotificationSettings(completionHandler: { (settings) in if settings.authorizationStatus != .notDetermined { // authorization has already been requested, need to follow usual steps center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in Appboy.sharedInstance()?.pushAuthorization(fromUserNotificationCenter: granted) } center.delegate = self as? UNUserNotificationCenterDelegate center.setNotificationCategories(ABKPushUtils.getAppboyUNNotificationCategorySet()) UIApplication.shared.registerForRemoteNotifications() } }) } else { let notificationSettiings = UIApplication.shared.currentUserNotificationSettings if notificationSettiings?.types != nil { let setting = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories:nil) UIApplication.shared.registerUserNotificationSettings(setting) UIApplication.shared.registerForRemoteNotifications() } } ``` ## ステップ 2: カスタムイベントチェッカーを AppDelegate.m ファイルに追加する {#step-2-append-custom-event-checker-to-appdelegatem-file} 次のコードスニペットは、カスタムイベントを発火する必要があるかどうかをチェックします。`AppDelegate.m` に次のコード行を追加します。 ```objc if (@available(iOS 10.0, *)) { UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) { if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) { // ... // fire custom event // ... } }]; } else { UIUserNotificationSettings *notificationSettings = [[UIApplication sharedApplication] currentUserNotificationSettings]; if (!notificationSettings.types) { // … // fire custom event // ... } } ``` ```swift if #available(iOS 10, *) { let center = UNUserNotificationCenter.current() center.getNotificationSettings(completionHandler: { (settings) in if settings.authorizationStatus == .notDetermined { // ... // fire custom event // ... } }) } else { let notificationSettiings = UIApplication.shared.currentUserNotificationSettings if notificationSettiings?.types != nil { // ... // fire custom event // ... } } ``` ## ステップ 3: ディープリンクハンドラーを設定する {#step-3-set-up-a-deep-link-handler} 以下のコードスニペットをディープリンク処理コードの中に配置してください。このディープリンクコードは、プッシュプライマーのアプリ内メッセージに対してのみ実行してください。 ディープリンクについて詳しくは、[リンク処理のカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/advanced_use_cases/linking#linking-handling-customization)を参照してください。 ```objc // ... // check that this deep link relates to the push prompt // ... if (@available(iOS 10.0, *)) { UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) { [[Appboy sharedInstance] pushAuthorizationFromUserNotificationCenter:granted]; }]; center.delegate = self; [center setNotificationCategories:[ABKPushUtils getAppboyUNNotificationCategorySet]]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } else { UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:[ABKPushUtils getAppboyUIUserNotificationCategorySet]]; UIApplication *sharedApplication = [UIApplication sharedApplication]; [sharedApplication registerUserNotificationSettings:settings]; [sharedApplication registerForRemoteNotifications]; } ``` ```swift // ... // check that this deep link relates to the push prompt // ... if #available(iOS 10, *) { let center = UNUserNotificationCenter.current() center.delegate = self as? UNUserNotificationCenterDelegate center.requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in Appboy.sharedInstance()?.pushAuthorization(fromUserNotificationCenter: granted) } UIApplication.shared.registerForRemoteNotifications() } else { let setting = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories:nil) UIApplication.shared.registerUserNotificationSettings(setting) UIApplication.shared.registerForRemoteNotifications() } ``` # iOS版 Push Stories Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/push_story/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # Push Storyのセットアップ {#push-story-setup} Push Story機能を使用するには、`UNNotification` フレームワークとiOS 10が必要です。この機能はiOS SDKバージョン3.2.1以降でのみ利用可能です。 ## ステップ 1:アプリでプッシュを有効にする {#step-1-enable-push-in-your-app} [プッシュ通知統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)に従って、アプリでプッシュを有効にします。 ## ステップ 2:通知コンテンツ拡張ターゲットを追加する {#step-2-adding-the-notification-content-extension-target} アプリプロジェクトで、メニュー **[File] > [New] > [Target...]** を選択し、新しい `Notification Content Extension` ターゲットを追加してアクティブ化します。 ![アプリプロジェクトで、メニューの「File」>「New」>「Target...」を選択し、新しい Notification Content Extension ターゲットを追加してアクティブ化します。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/add_content_extension.png?ad9e5d8cc83d88d9e26dbd2c4c8dba67) Xcodeによって新しいターゲットが生成され、次のようなファイルが自動的に作成されます。 - `NotificationViewController.h` - `NotificationViewController.m` - `MainInterface.storyboard` - `NotificationViewController.swift` - `MainInterface.storyboard` ## ステップ 3:機能を有効にする {#step-3-enable-capabilities} Push Story機能では、メインアプリターゲットの **[Capabilities]** セクションのバックグラウンドモードが必要です。バックグラウンドモードをオンにしたら、**[Background fetch]** と **[Remote notifications]** を選択します。 ![Push Story機能では、メインアプリターゲットの「Capabilities」セクションのバックグラウンドモードが必要です。バックグラウンドモードをオンにしたら、「Background fetch」と「Remote notifications」を選択します。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/enable_background_mode.png?37d0c9c4c59fb04aa930729a5539ed59) ### アプリグループの追加 {#adding-an-app-group} `Capability App Groups` も追加する必要があります。アプリにアプリグループがない場合は、メインアプリターゲットの **[Capability]** に移動し、`App Groups` をオンにして **[+]** ボタンをクリックします。アプリのバンドルIDを使用してアプリグループを作成します。たとえば、アプリのバンドルIDが `com.company.appname` の場合、アプリグループに `group.com.company.appname.xyz` という名前を付けることができます。メインアプリとコンテンツ拡張ターゲットの両方で `App Groups` をオンにする必要があります。 **Important:** この場合の `App Groups` は、Appleの[App Groups Entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups)を指し、Brazeワークスペース(以前のアプリグループ)のIDではありません。 アプリをアプリグループに追加しないと、アプリがプッシュペイロードからの特定のフィールドの入力に失敗し、期待したとおりに完全に動作しない可能性があります。 ## ステップ 4:Push Storyフレームワークをアプリに追加する {#step-4-adding-the-push-story-framework-to-your-app} [Swift Package Managerの統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/installation_methods/swift_package_manager)に従って、`AppboyPushStory` を `Notification Content Extension` に追加します。 ![Xcodeで、フレームワークとライブラリーの下にある「+」アイコンを選択してフレームワークを追加します。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/spm1.png?e0309c244812bf68280a061a2de6f24e) ![Swift Package Managerの統合ガイドに従って、AppboyPushStoryをNotification Content Extensionに追加します。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/spm2.png?b44d800ab07db2b950dd6275937465c0) 次の行をPodfileに追加します。 ```ruby target 'YourContentExtensionTarget' do pod 'Appboy-Push-Story' end ``` Podfileを更新したら、ターミナル内でXcodeアプリプロジェクトのディレクトリーに移動し、`pod install` を実行します。 [GitHubリリースページ](https://github.com/Appboy/appboy-ios-sdk/releases)から最新の `AppboyPushStory.zip` をダウンロードして展開し、以下のファイルをプロジェクトの `Notification Content Extension` に追加します。 - `Resources/ABKPageView.nib` - `AppboyPushStory.xcframework` ![GitHubリリースページから最新のAppboyPushStory.zipをダウンロードして展開し、ファイルをプロジェクトのNotification Content Extensionに追加します。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/manual1.png?fb802f18809806513f0295486afb90dd) **Important:** **Embed** 列の下で、**AppboyPushStory.xcframework** に対して **Do Not Embed** が選択されていることを確認します。 **Build Settings** > **Other Linker Flags** でプロジェクトの `Notification Content Extension` に `-ObjC` フラグを追加します。 ## ステップ 5:通知ビューコントローラーを更新する {#step-5-updating-your-notification-view-controller} `NotificationViewController.h` で、次の行を追加して新しいプロパティを追加し、ヘッダーファイルをインポートします。 ```objc #import ``` ```objc @property (nonatomic) IBOutlet ABKStoriesView *storiesView; @property (nonatomic) ABKStoriesViewDataSource *dataSource; ``` `NotificationViewController.m` では、デフォルトの実装を削除し、次のコードを追加します。 ```objc @implementation NotificationViewController - (void)didReceiveNotification:(UNNotification *)notification { self.dataSource = [[ABKStoriesViewDataSource alloc] initWithNotification:notification storiesView:self.storiesView appGroup:@"YOUR-APP-GROUP-IDENTIFIER"]; } - (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption option))completion { UNNotificationContentExtensionResponseOption option = [self.dataSource didReceiveNotificationResponse:response]; completion(option); } - (void)viewWillDisappear:(BOOL)animated { [self.dataSource viewWillDisappear]; [super viewWillDisappear:animated]; } @end ``` `NotificationViewController.swift` で、次の行を追加してヘッダーファイルをインポートします。 ```swift import AppboyPushStory ``` 次に、デフォルトの実装を削除し、次のコードを追加します。 ```swift class NotificationViewController: UIViewController, UNNotificationContentExtension { @IBOutlet weak var storiesView: ABKStoriesView! var dataSource: ABKStoriesViewDataSource? func didReceive(_ notification: UNNotification) { dataSource = ABKStoriesViewDataSource(notification: notification, storiesView: storiesView, appGroup: "YOUR-APP-GROUP-IDENTIFIER") } func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) { if dataSource != nil { let option: UNNotificationContentExtensionResponseOption = dataSource!.didReceive(response) completion(option) } } override func viewWillDisappear(_ animated: Bool) { dataSource?.viewWillDisappear() super.viewWillDisappear(animated) } } ``` ## ステップ 6:通知コンテンツ拡張ストーリーボードを設定する {#step-6-set-the-notification-content-extension-storyboard} `Notification Content Extension` ストーリーボードを開き、通知ビューコントローラーに新しい `UIView` を配置します。クラスの名前を `ABKStoriesView` に変更します。通知ビューコントローラーのメインビューフレームに合わせて、ビューの幅と高さを自動サイズ変更可能にします。 ![Notification Content Extensionストーリーボードを開き、通知ビューコントローラーに新しいUIViewを配置します。クラスの名前をABKStoriesViewに変更します。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/abkstoriesview_class.png?ee2f2e08fdd56df7e4f5bb7661559767) ![通知ビューコントローラーのメインビューフレームに合わせて、ビューの幅と高さを自動サイズ変更可能にします。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/abkstoriesview_size.png?7edb36e8900896e9ad64bf49ea100715) 次に、追加された `ABKStoriesView` に通知ビューコントローラーの `storiesView` IBOutletをリンクします。 ![ステップ6に関連するスクリーンショット:通知コンテンツ拡張ストーリーボードを設定します。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/abkstoriesview_outlet.png?495dd440247e01d31851cf1b878563f1) ## ステップ 7:通知コンテンツ拡張plistを設定する {#step-7-set-the-notification-content-extension-plist} `Notification Content Extension` の `Info.plist` ファイルを開き、`NSExtension \ NSExtensionAttributes` で以下のキーを追加および変更します。 `UNNotificationExtensionCategory` = `ab_cat_push_story_v2`(`String` タイプ) `UNNotificationExtensionDefaultContentHidden` = `YES`(`Boolean` タイプ) `UNNotificationExtensionInitialContentSizeRatio` = `0.65`(`Number` タイプ) ![ステップ7に関連するスクリーンショット:通知コンテンツ拡張plistを設定します。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/notificationcontentextension_plist.png?6c58d280881fdc3384127cad54a4eb4c) ## ステップ 8:メインアプリでのBraze統合のアップデート {#step-8-updating-the-braze-integration-in-your-main-app} ### オプション 1:ランタイム {#option-1-runtime} Brazeインスタンスの設定に使用する `appboyOptions` 辞書で、`ABKPushStoryAppGroupKey` エントリを追加し、値をワークスペースAPI識別子に設定します。 ```objc NSMutableDictionary *appboyOptions = [NSMutableDictionary dictionary]; appboyOptions[ABKPushStoryAppGroupKey] = @"YOUR-APP-GROUP-IDENTIFIER"; [Appboy startWithApiKey:@"YOUR-API-KEY" inApplication:application withLaunchOptions:launchOptions withAppboyOptions:appboyOptions]; ``` ```swift let appboyOptions: [AnyHashable: Any] = [ ABKPushStoryAppGroupKey : "YOUR-APP-GROUP-IDENTIFIER" ] Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:appboyOptions) ``` #### オプション 2:Info.plist {#option-2-infoplist} または、`Info.plist` ファイルからPush Storyワークスペースを構成するには、`Braze` という名前の辞書を `Info.plist` ファイルに追加します。`Braze` 辞書内で、文字列型の `PushStoryAppGroup` サブエントリを追加し、値をワークスペース識別子に設定します。なお、Braze iOS SDK v4.0.2より前のバージョンでは、`Braze` の代わりに辞書キー `Appboy` を使用する必要があります。 ## 次のステップ {#next-steps} 次に、[アクションボタン](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/action_buttons)を統合する手順を参照してください。これはPush Storiesメッセージにボタンを表示するために必要です。 # iOS 用の高度なプッシュ通知の実装(オプション) Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/implementation_guide/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk).
**Important:** 基本的なプッシュ通知開発者統合ガイドをお探しですか?[iOS プッシュ通知の統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)をご覧ください。 # プッシュ通知実装ガイド {#push-notification-implementation-guide} > このオプションの高度な実装ガイドでは、プッシュ通知コンテンツアプリの拡張機能を活用してプッシュメッセージを最大限に活用する方法について説明します。当社チームが構築した3つのカスタムユースケース、付随するコードスニペット、および分析のロギングに関するガイダンスが含まれています。[こちらから](https://github.com/braze-inc/braze-growth-shares-ios-demo-app) Braze Demo リポジトリにアクセスしてください。この実装ガイドは Swift 実装を中心に扱っていますが、興味のある方のために Objective-C のスニペットも提供されています。 ## 通知コンテンツアプリの拡張機能 {#notification-content-app-extensions} ![2つのプッシュメッセージが並んで表示されている。左側のメッセージは、デフォルトの UI でプッシュがどのように表示されるかを示しています。右側のメッセージは、カスタムプッシュ UI を実装して作成したコーヒーパンチカードプッシュを表示しています。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push1.png?d04035fb11637f7db51f24a1afab9e8f){: style="max-width:65%;border:0;margin-top:10px"} プッシュ通知は、さまざまなプラットフォームで標準的に見えますが、デフォルトの UI に通常実装されているものを超えた膨大なカスタマイズオプションを提供しています。プッシュ通知が展開されると、コンテンツ通知拡張により、展開されたプッシュ通知のカスタムビューが有効になります。 プッシュ通知は、次の3つの方法で展開できます。
- プッシュバナーを長押しする
- プッシュバナーを下にスワイプする
- バナーを左にスワイプし、「表示」を選択する これらのカスタムビューでは、顧客を引き付けるスマートな方法が提供され、インタラクティブな通知、ユーザーデータを含む通知、電話番号やメールなどの情報を取得できるプッシュメッセージなど、さまざまな種類のコンテンツを表示できます。この方法でプッシュを実装することに慣れていない方もいるかもしれませんが、Brazeでよく知られている機能の1つである [Push Stories](https://www.braze.com/docs/ja/ja/user_guide/channels/push/create_a_push_message/push_stories) は、通知コンテンツアプリ拡張機能のカスタムビューがどのように表示されるかを示す良い例です。 ### 要件 {#requirements} ![Xcodeの「新しいターゲットのテンプレートを選択」画面で、Application Extension の下にある「Notification Content Extension」が選択されている。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push15.png?64059ffe5c16313ee6377e0a79405812){: style="float:right;max-width:50%;margin-left:10px; border:0;margin-top:10px"} - [プッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)がアプリに正常に統合されていること - iOS 10以上 - コーディング言語に基づいて Xcode が生成する以下のファイル: Swift
- `NotificationViewController.swift`
- `MainInterface.storyboard`

Objective-C
- `NotificationViewController.h`
- `NotificationViewController.m`
- `MainInterface.storyboard` ### カスタムカテゴリの設定 {#custom-category-configuration} ダッシュボードでカスタムビューを設定するには、通知ボタンを切り替えてカスタムカテゴリを入力する必要があります。指定したあらかじめ登録されたカスタム iOS カテゴリは、通知コンテンツ拡張ターゲットの `.plist` の `UNNotificationExtensionCategory` と照合されます。ここで指定される値は、Brazeダッシュボードで設定されている値と一致する必要があります。 ![プッシュメッセージ作成画面の設定にある通知ボタンオプション。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push16.png?be40aad198215645c3ef4ac2553267f4){: style="max-width:75%;border:0;margin-top:10px"} ![UNNotificationExtensionCategory が「your_custom_category」に設定され、UNNotificationExtensionDefaultContentHidden が 1 に設定され、UNNotificationExtensionInitialContentSizeRatio が 1 に設定された NSExtension を含む plist。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push17.png?42f5ff77b6402aade26b936b5c78dbc7){: style="max-width:75%;border:0;margin-top:10px"} **Tip:** コンテンツ拡張を使用したプッシュは必ずしも明らかではないため、プッシュ通知を展開するようにユーザーに促すための行動喚起を含めることをお勧めします。 ## ユースケースと実装のウォークスルー {#use-case-and-implementation-walkthrough} 3つのプッシュ通知コンテンツアプリ拡張タイプが用意されています。各タイプには、概念のウォークスルー、潜在的なユースケース、およびBrazeダッシュボードでプッシュ通知変数がどのように表示され、どのように使用されるかの考察があります。 - [インタラクティブなプッシュ通知](#interactive-push-notification) - [パーソナライズされたプッシュ通知](#personalized-push-notifications) - [情報キャプチャプッシュ通知](#information-capture-push-notification) ### インタラクティブなプッシュ通知 {#interactive-push-notification} プッシュ通知は、コンテンツ拡張内のユーザーアクションに応答できます。iOS 12以降を使用しているユーザーの場合、これはプッシュメッセージを完全にインタラクティブなプッシュ通知に変換できることを意味します。このインタラクティブな機能により、ユーザーを通知に引き付ける多くの可能性が生まれます。次の例は、ユーザーが展開された通知内でマッチゲームをプレイできるプッシュ通知を示しています。 ![インタラクティブなプッシュ通知のフェーズがどのようなものかを示した図。画像は、インタラクティブなマッチングゲームを表示するプッシュ通知をユーザーが押しているところを示しています。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push12.png?e32579b6de7f5aec62265828724d6657){: style="border:0"} #### ダッシュボードの設定 {#dashboard-configuration} ダッシュボードでカスタムビューを設定するには、通知ボタン設定で表示する特定のカテゴリを入力します。次に、通知コンテンツ拡張の `.plist` で、カスタムカテゴリを `UNNotificationExtensionCategory` 属性に設定する必要があります。ここで指定される値は、Brazeダッシュボードで設定されている値と一致する必要があります。最後に、プッシュ通知でユーザーインタラクションを有効にするには、`UNNotificationExtensionInteractionEnabled` キーを true に設定します。 ![Brazeダッシュボードの通知ボタンセクションで、iOS 通知カテゴリフィールドが「match_game」に設定されている。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push3.png?1b1b1f110b2fd607874b5210e8533620){: style="float:right;max-width:45%;"} ![プッシュメッセージ作成画面の設定にある通知ボタンオプション。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push14.png?0015bbc93063d506eabdce38248f8664){: style="max-width:50%;"} #### その他のユースケース {#other-use-cases} プッシュコンテンツ拡張は、プロモーションやアプリケーションにインタラクティビティを導入するエキサイティングなオプションです。例としては、ユーザーがプレイできるゲーム、割引のためのスピン・トゥ・ウィン・ホイール、リストや曲を保存するための「いいね」ボタンなどがあります。 ##### 分析をログに記録する準備はできましたか? {#ready-to-log-analytics} [以下のセクション](#logging-analytics)を参照して、データのフローがどうあるべきかを理解してください。 ### パーソナライズされたプッシュ通知 {#personalized-push-notifications} ![2台の iPhone が並んで表示されています。最初の iPhone には、プッシュメッセージの展開されていないビューが表示されます。2台目の iPhone には、プッシュメッセージの展開されたバージョンが表示され、コースの進行状況、次のセッション、次のセッションの期限を示す「進捗」ショットが表示されます。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push6.png?438d9acc8285244397d14467a8a63d3a){: style="float:right;max-width:40%;margin-left:15px;border:0"} プッシュ通知では、コンテンツ拡張の内部にユーザー固有の情報を表示できます。右の例では、ユーザーが特定のタスク(Brazeラーニングコース)を完了し、この通知を展開して進捗状況を確認するように求められた後のプッシュ通知を示しています。ここで提供される情報はユーザー固有であり、セッションが完了するか、API トリガーを利用して特定のユーザーアクションが実行されたときに呼び出すことができます。 #### ダッシュボードの設定 ダッシュボードでパーソナライズされたプッシュを設定するには、表示する特定のカテゴリを登録し、標準の Liquid を使用してキーと値のペア内で、メッセージに表示する適切なユーザー属性を設定する必要があります。これらのビューは、特定のユーザープロファイルの特定のユーザー属性に基づいてカスタマイズできます。 ![4組のキーと値のペア。「next_session_name」と「next_session_complete_date」は Liquid を使用して API トリガープロパティとして設定され、「completed_session count」と「total_session_count」は Liquid を使用してカスタムユーザー属性として設定されています。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push5.png?199277e2adf2d1ded48e5dba4c2d7b4a){: style="max-width:60%;"} #### キーと値のペアの処理 {#handling-key-value-pairs} 以下のメソッド `didReceive` は、コンテンツ拡張が通知を受け取ったときに呼び出され、`NotificationViewController` 内にあります。ダッシュボードで提供されるキーと値のペアは、`userInfo` 辞書を使用してコードで表されます。 **プッシュ通知からのキーと値のペアの解析**
``` swift func didReceive(_ notification: UNNotification) { let userInfo = notification.request.content.userInfo guard let value = userInfo["YOUR-KEY-VALUE-PAIR"] as? String, let otherValue = userInfo["YOUR-OTHER-KEY-VALUE-PAIR"] as? String, else { fatalError("Key-Value Pairs are incorrect.")} ... } ``` ```objc - (void)didReceiveNotification:(nonnull UNNotification *)notification { NSDictionary *userInfo = notification.request.content.userInfo; if (userInfo[@"YOUR-KEY-VALUE-PAIR"] && userInfo[@"YOUR-OTHER-KEY-VALUE-PAIR"]) { ... } else { [NSException raise:NSGenericException format:@"Key-Value Pairs are incorrect"]; } } ``` #### その他のユースケース 進捗ベースでユーザーにフォーカスしたプッシュコンテンツ拡張のアイデアは無限にあります。いくつかの例としては、異なるプラットフォーム間で進捗状況を共有するオプションの追加、アンロックされた成果の表現、パンチカード、またはオンボーディングチェックリストなどがあります。 ##### 分析をログに記録する準備はできましたか? [以下のセクション](#logging-analytics)を参照して、データのフローがどうあるべきかを理解してください。 ### 情報キャプチャプッシュ通知 {#information-capture-push-notification} プッシュ通知は、コンテンツ拡張の内部でユーザー情報をキャプチャし、プッシュで可能なことの限界を押し広げることができます。次のフローを調べると、ビューは状態の変化に応答できます。これらの状態変更コンポーネントは、各画像に表示されます。 1. ユーザーはプッシュ通知を受信します。 2. プッシュが開かれ、ユーザーに対して情報の入力を求めます。 3. 情報が提供され、有効な場合は、登録ボタンが表示されます。 3. 確認画面が表示され、プッシュが解除されます。 ここで要求される情報は、SMS 番号のキャプチャなど広範なものである可能性があり、メール固有である必要はないことに注意してください。 #### ダッシュボードの設定 ダッシュボードで情報キャプチャ対応プッシュを設定するには、カスタムカテゴリを登録および設定し、必要なキーと値のペアを指定する必要があります。例にあるように、プッシュに画像を含めることもできます。これを行うには、[リッチプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/rich_notifications)を統合し、キャンペーンの通知スタイルをリッチプッシュ通知に設定し、リッチプッシュ画像を含める必要があります。 ![キーと値のペアが3セットあるプッシュメッセージ。1.「Braze_id」は Braze ID を取得するための Liquid 呼び出しとして設定。2.「cert_title」は「Braze Marketer Certification」として設定。3.「Cert_description」は「Certified Braze marketers drive...」として設定。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push9.png?4f1d1fc129e7f564d006e649dc0ef582) #### ボタンアクションの処理 {#handling-button-actions} 各アクションボタンは一意に識別されます。コードは、応答識別子が `actionIdentifier` と等しいかどうかをチェックし、等しい場合は、ユーザーがアクションボタンをクリックしたことと認識します。 **プッシュ通知アクションボタンの応答の処理**
``` swift func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) { if response.actionIdentifier == "YOUR-REGISTER-IDENTIFIER" { // do something } else { // do something else } } ``` ```objc - (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion { if ([response.actionIdentifier isEqualToString:@"YOUR-REGISTER-IDENTIFIER"]) { completion(UNNotificationContentExtensionResponseOptionDismiss); } else { completion(UNNotificationContentExtensionResponseOptionDoNotDismiss); } } ``` ##### プッシュの解除 {#dismissing-pushes} プッシュ通知は、アクションボタンを押すと自動的に解除できます。推奨される事前構築済みのプッシュ解除オプションは3つあります。 1. `completion(.dismiss)` - 通知を解除します 2. `completion(.doNotDismiss)` - 通知は開いたままです 3. `completion(.dismissAndForward)` - プッシュが解除され、ユーザーがアプリケーションに転送されます。 #### その他のユースケース プッシュ通知を介してユーザー入力を要求することは、多くの企業が利用していない魅力的な機会です。これらのプッシュメッセージでは、名前、メール、または番号などの基本的な情報を要求できるだけでなく、ユーザープロファイルが未完了の場合は完了するようにユーザーに促したり、フィードバックを送信するように促すこともできます。 ##### 分析をログに記録する準備はできましたか? [以下のセクション](#logging-analytics)を参照して、データのフローがどうあるべきかを理解してください。 ## 分析のロギング {#logging-analytics} ### Braze APIを使用したロギング(推奨) {#logging-with-the-braze-api-recommended} 分析のロギングは、顧客のサーバーが[`/users/track` エンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)にアクセスすることで、リアルタイムでのみ実行できます。分析をログに記録するには、`braze_id` 値をキーと値のペアフィールド(次のスクリーンショットを参照)に送信し、更新するユーザープロファイルを識別します。 ![キーと値のペアが3セットあるプッシュメッセージ。1.「Braze_id」は Braze ID を取得するための Liquid 呼び出しとして設定。2.「cert_title」は「Braze Marketer Certification」として設定。3.「Cert_description」は「Certified Braze marketers drive...」として設定。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push18.png?ae37ef2a75d3afb0525cc480263728d7){: style="max-width:80%;"} ### 手動ロギング {#logging-manually} 手動でログを記録するには、まず Xcode 内でアプリグループを設定してから、分析を作成、保存、および取得する必要があります。これには、お客様側でカスタム開発者の作業が必要になります。以下に示すコードスニペットは、これを解決するのに役立ちます。 また、モバイルアプリケーションが後で起動されるまで、分析はBrazeに送信されないことに注意してください。つまり、解除設定に応じて、プッシュ通知が解除されてモバイルアプリが起動し、分析が取得されるまでに不確定な期間が存在することがよくあります。この時間バッファーがすべてのユースケースに影響するとは限りませんが、ユーザーは影響を考慮し、必要に応じて、アプリケーションを開いてこの問題に対処するようにユーザージャーニーを調整する必要があります。 ![Brazeで分析がどのように処理されるかを説明する図。1. 分析データが作成されます。2. 分析データが保存されます。3. プッシュ通知が解除されます。4. プッシュ通知が解除されてからモバイルアプリが起動するまでの不確定な期間。5. モバイルアプリが起動します。6. 分析データを受信します。7. 分析データがBrazeに送信されます。](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push13.png?817f7603e474002aae9a3b25bccd81bb) #### ステップ1:Xcode 内でのアプリグループの設定 {#step-1-configure-app-groups-within-xcode} 機能 `App Groups` を追加します。アプリにアプリグループがない場合は、メインアプリターゲットの機能に移動し、`App Groups` をオンにして、「+」をクリックします。アプリのバンドル ID を使用してアプリグループを作成します。たとえば、アプリのバンドル ID が `com.company.appname` の場合、アプリグループに `group.com.company.appname.xyz` という名前を付けることができます。メインアプリターゲットとコンテンツ拡張ターゲットの両方で `App Groups` がオンになっていることを確認します。 ![Xcodeのアプリグループ設定ダイアログで、「group.」がプリフィルされたテキストフィールドが表示されている。](https://www.braze.com/docs/ja/ja/assets/img/ios/push_story/add_app_groups.png?44e3d92af533e6323db33236364b99e1) #### ステップ2:コードスニペットの統合 {#step-2-integrate-code-snippets} 以下のコードスニペットは、カスタムイベント、カスタム属性、およびユーザー属性を保存および送信する方法についての役立つ参考情報です。このガイドでは UserDefaults の観点から説明しますが、コード表現はヘルパーファイル `RemoteStorage` の形式になります。また、追加のヘルパーファイル `UserAttributes` と `EventName Dictionary` もあり、ユーザー属性の送信と保存に使用されます。ヘルパーファイルはすべて、このガイドの末尾にあります。 ##### カスタムイベントの保存 {#saving-custom-events} カスタムイベントを保存するには、分析を最初から作成する必要があります。これを行うには、辞書を作成し、メタデータを入力し、ヘルパーファイルを使用してデータを保存します。 1. イベントメタデータを使用して辞書を初期化します 2. イベントデータを取得して保存するには、`userDefaults` を初期化します 3. 既存の配列がある場合は、既存の配列に新しいデータを追加して保存します 4. 既存の配列がない場合は、新しい配列を `userDefaults` に保存します ``` swift func saveCustomEvent(with properties: [String: Any]? = nil) { // 1 let customEventDictionary = Dictionary(eventName: "YOUR-EVENT-NAME", properties: properties) // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] { pendingEvents.append(contentsOf: [customEventDictionary]) remoteStorage.store(pendingEvents, forKey: .pendingCustomEvents) } else { // 4 remoteStorage.store([customEventDictionary], forKey: .pendingCustomEvents) } } ``` ```objc - (void)saveCustomEvent:(NSDictionary *)properties { // 1 NSDictionary *customEventDictionary = [[NSDictionary alloc] initWithEventName:@"YOUR-EVENT-NAME" properties:properties]; // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingEvents = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents] mutableCopy]; // 3 if (pendingEvents) { [pendingEvents addObject:customEventDictionary]; [remoteStorage store:pendingEvents forKey:RemoteStorageKeyPendingCustomAttributes]; } else { // 4 [remoteStorage store:@[ customEventDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes]; } } ``` ##### カスタムイベントのBrazeへの送信 {#sending-custom-events-to-braze} SDKの初期化後は、通知コンテンツアプリの拡張機能から保存された分析をログに記録するのに最適なタイミングです。これは、保留中のイベントをループして、「Event Name」キーをチェックし、Brazeで適切な値を設定し、次回この関数が必要になったときに備えてストレージをクリアすることで実行できます。 1. 保留中のイベントの配列をループします 2. `pendingEvents` 辞書の各キーと値のペアをループします 3. 「Event Name」のキーを明示的にチェックし、それに応じて値を設定します 4. 他のすべてのキー値が `properties` 辞書に追加されます 5. 個別のカスタムイベントを記録します 6. すべての保留中のイベントをストレージから削除します ``` swift func logPendingCustomEventsIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] else { return } // 1 for event in pendingEvents { var eventName: String? var properties: [AnyHashable: Any] = [:] // 2 for (key, value) in event { if key == PushNotificationKey.eventName.rawValue { // 3 if let eventNameValue = value as? String { eventName = eventNameValue } else { print("Invalid type for event_name key") } } else { // 4 properties[key] = value } } // 5 if let eventName = eventName { logCustomEvent(eventName, withProperties: properties) } } // 6 remoteStorage.removeObject(forKey: .pendingCustomEvents) } ``` ```objc - (void)logPendingEventsIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingEvents = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents]; // 1 for (NSDictionary *event in pendingEvents) { NSString *eventName = nil; NSMutableDictionary *properties = [NSMutableDictionary dictionary]; // 2 for (NSString* key in event) { if ([key isEqualToString:@"event_name"]) { // 3 if ([[event objectForKey:key] isKindOfClass:[NSString class]]) { eventName = [event objectForKey:key]; } else { NSLog(@"Invalid type for event_name key"); } } else { // 4 properties[key] = event[key]; } } // 5 if (eventName != nil) { [[Appboy sharednstance] logCustomEvent:eventName withProperties:properties]; } } // 6 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomEvents]; } ``` ##### カスタム属性の保存 {#saving-custom-attributes} カスタム属性を保存するには、分析を最初から作成する必要があります。これを行うには、辞書を作成し、メタデータを入力し、ヘルパーファイルを使用してデータを保存します。 1. 属性メタデータを使用してディクショナリを初期化します 2. 属性データを取得して格納するには、`userDefaults` を初期化します 3. 既存の配列がある場合は、既存の配列に新しいデータを追加して保存します 4. 既存の配列がない場合は、新しい配列を `userDefaults` に保存します ``` swift func saveCustomAttribute() { // 1 let customAttributeDictionary: [String: Any] = ["YOUR-CUSTOM-ATTRIBUTE-KEY": "YOUR-CUSTOM-ATTRIBUTE-VALUE"] // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] { pendingAttributes.append(contentsOf: [customAttributeDictionary]) remoteStorage.store(pendingAttributes, forKey: .pendingCustomAttributes) } else { // 4 remoteStorage.store([customAttributeDictionary], forKey: .pendingCustomAttributes) } } ``` ``` objc - (void)saveCustomAttribute { // 1 NSDictionary *customAttributeDictionary = @{ @"YOUR-CUSTOM-ATTRIBUTE-KEY": @"YOUR-CUSTOM-ATTRIBUTE-VALUE" }; // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes] mutableCopy]; // 3 if (pendingAttributes) { [pendingAttributes addObject:customAttributeDictionary]; [remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingCustomAttributes]; } else { // 4 [remoteStorage store:@[ customAttributeDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes]; } } ``` ##### カスタム属性のBrazeへの送信 {#sending-custom-attributes-to-braze} SDKの初期化後は、通知コンテンツアプリの拡張機能から保存された分析をログに記録するのに最適なタイミングです。これは、保留中の属性をループし、Brazeで適切なカスタム属性を設定し、次回この関数が必要になったときに備えてストレージをクリアすることで実行できます。 1. 保留中の属性の配列をループします 2. `pendingAttributes` 辞書の各キーと値のペアをループします 3. 対応するキーと値を持つ個別のカスタム属性を記録します 4. ストレージからすべての保留中の属性を削除します ``` swift func logPendingCustomAttributesIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] else { return } // 1 pendingAttributes.forEach { setCustomAttributesWith(keysAndValues: $0) } // 4 remoteStorage.removeObject(forKey: .pendingCustomAttributes) } func setCustomAttributesWith(keysAndValues: [String: Any]) { // 2 for (key, value) in keysAndValues { // 3 if let value = value as? [String] { setCustomAttributeArrayWithKey(key, andValue: value) } else { setCustomAttributeWithKey(key, andValue: value) } } } ``` ```objc - (void)logPendingCustomAttributesIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes]; // 1 for (NSDictionary *attribute in pendingAttributes) { [self setCustomAttributeWith:attribute]; } // 4 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomAttributes]; } - (void)setCustomAttributeWith:(NSDictionary *)keysAndValues { // 2 for (NSString *key in keysAndValues) { // 3 [self setCustomAttributeWith:key andValue:[keysAndValues objectForKey:key]]; } } ``` ##### ユーザー属性の保存 {#saving-user-attributes} ユーザー属性を保存する場合は、更新されている属性のタイプ(`email`、`first_name`、`phone_number` など)を解読するカスタムオブジェクトを作成することをお勧めします。オブジェクトは、`UserDefaults` からの保管/取得に対応している必要があります。これを行う方法の一例については、`UserAttribute` ヘルパーファイルを参照してください。 1. エンコードされた `UserAttribute` オブジェクトを対応する型で初期化します 2. イベントデータを取得して保存するには、`userDefaults` を初期化します 3. 既存の配列がある場合は、既存の配列に新しいデータを追加して保存します 4. 既存の配列がない場合は、新しい配列を `userDefaults` に保存します ``` swift func saveUserAttribute() { // 1 guard let data = try? PropertyListEncoder().encode(UserAttribute.userAttributeType("USER-ATTRIBUTE-VALUE")) else { return } // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] { pendingAttributes.append(contentsOf: [data]) remoteStorage.store(pendingAttributes, forKey: .pendingUserAttributes) } else { // 4 remoteStorage.store([data], forKey: .pendingUserAttributes) } } ``` ```objc - (void)saveUserAttribute { // 1 UserAttribute *userAttribute = [[UserAttribute alloc] initWithUserField:@"USER-ATTRIBUTE-VALUE" attributeType:UserAttributeTypeEmail]; NSError *error; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:userAttribute requiringSecureCoding:YES error:&error]; if (error != nil) { // log error } // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes] mutableCopy]; // 3 if (pendingAttributes) { [pendingAttributes addObject:data]; [remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingUserAttributes]; } else { // 4 [remoteStorage store:@[data] forKey:RemoteStorageKeyPendingUserAttributes]; } } ``` ##### ユーザー属性のBrazeへの送信 {#sending-user-attributes-to-braze} SDKの初期化後は、通知コンテンツアプリの拡張機能から保存された分析をログに記録するのに最適なタイミングです。これは、保留中の属性をループし、Brazeで適切なカスタム属性を設定し、次回この関数が必要になったときに備えてストレージをクリアすることで実行できます。 1. `pendingAttributes` データの配列をループします 2. 属性データからエンコードされた `UserAttribute` オブジェクトを初期化します 3. ユーザー属性タイプ(メール)に基づいて特定のユーザーフィールドを設定します 4. ストレージからすべての保留中のユーザー属性を削除します ``` swift func logPendingUserAttributesIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] else { return } // 1 for attributeData in pendingAttributes { // 2 guard let userAttribute = try? PropertyListDecoder().decode(UserAttribute.self, from: attributeData) else { continue } // 3 switch userAttribute { case .email(let email): user?.email = email } } // 4 remoteStorage.removeObject(forKey: .pendingUserAttributes) } ``` ```objc - (void)logPendingUserAttributesIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes]; // 1 for (NSData *attributeData in pendingAttributes) { NSError *error; // 2 UserAttribute *userAttribute = [NSKeyedUnarchiver unarchivedObjectOfClass:[UserAttribute class] fromData:attributeData error:&error]; if (error != nil) { // log error } // 3 if (userAttribute) { switch (userAttribute.attributeType) { case UserAttributeTypeEmail: [self user].email = userAttribute.userField; break; } } } // 4 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingUserAttributes]; } ``` ##### ヘルパーファイル {#helper-files} **RemoteStorage ヘルパーファイル** ```swift enum RemoteStorageKey: String, CaseIterable { // MARK: - Notification Content Extension Analytics case pendingCustomEvents = "pending_custom_events" case pendingCustomAttributes = "pending_custom_attributes" case pendingUserAttributes = "pending_user_attributes" } enum RemoteStorageType { case standard case suite } class RemoteStorage: NSObject { private var storageType: RemoteStorageType = .standard private lazy var defaults: UserDefaults = { switch storageType { case .standard: return .standard case .suite: return UserDefaults(suiteName: "YOUR-DOMAIN-IDENTIFIER")! } }() init(storageType: RemoteStorageType = .standard) { self.storageType = storageType } func store(_ value: Any, forKey key: RemoteStorageKey) { defaults.set(value, forKey: key.rawValue) } func retrieve(forKey key: RemoteStorageKey) -> Any? { return defaults.object(forKey: key.rawValue) } func removeObject(forKey key: RemoteStorageKey) { defaults.removeObject(forKey: key.rawValue) } func resetStorageKeys() { for key in RemoteStorageKey.allCases { defaults.removeObject(forKey: key.rawValue) } } } ``` ```objc @interface RemoteStorage () @property (nonatomic) StorageType storageType; @property (nonatomic, strong) NSUserDefaults *defaults; @end @implementation RemoteStorage - (id)initWithStorageType:(StorageType)storageType { if (self = [super init]) { self.storageType = storageType; } return self; } - (void)store:(id)value forKey:(RemoteStorageKey)key { [[self defaults] setValue:value forKey:[self rawValueForKey:key]]; } - (id)retrieveForKey:(RemoteStorageKey)key { return [[self defaults] objectForKey:[self rawValueForKey:key]]; } - (void)removeObjectForKey:(RemoteStorageKey)key { [[self defaults] removeObjectForKey:[self rawValueForKey:key]]; } - (void)resetStorageKeys { [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomEvents]]; [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomAttributes]]; [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingUserAttributes]]; } - (NSUserDefaults *)defaults { if (!self.defaults) { switch (self.storageType) { case StorageTypeStandard: return [NSUserDefaults standardUserDefaults]; break; case StorageTypeSuite: return [[NSUserDefaults alloc] initWithSuiteName:@"YOUR-DOMAIN-IDENTIFIER"]; } } else { return self.defaults; } } - (NSString*)rawValueForKey:(RemoteStorageKey)remoteStorageKey { switch(remoteStorageKey) { case RemoteStorageKeyPendingCustomEvents: return @"pending_custom_events"; case RemoteStorageKeyPendingCustomAttributes: return @"pending_custom_attributes"; case RemoteStorageKeyPendingUserAttributes: return @"pending_user_attributes"; default: [NSException raise:NSGenericException format:@"Unexpected FormatType."]; } } ``` **UserAttribute ヘルパーファイル** ```swift enum UserAttribute: Hashable { case email(String?) } // MARK: - Codable extension UserAttribute: Codable { private enum CodingKeys: String, CodingKey { case email } func encode(to encoder: Encoder) throws { var values = encoder.container(keyedBy: CodingKeys.self) switch self { case .email(let email): try values.encode(email, forKey: .email) } } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) let email = try values.decode(String.self, forKey: .email) self = .email(email) } } ``` ```objc @implementation UserAttribute - (id)initWithUserField:(NSString *)userField attributeType:(UserAttributeType)attributeType { if (self = [super init]) { self.userField = userField; self.attributeType = attributeType; } return self; } - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.userField forKey:@"userField"]; [encoder encodeInteger:self.attributeType forKey:@"attributeType"]; } - (id)initWithCoder:(NSCoder *)decoder { if (self = [super init]) { self.userField = [decoder decodeObjectForKey:@"userField"]; NSInteger attributeRawValue = [decoder decodeIntegerForKey:@"attributeType"]; self.attributeType = (UserAttributeType) attributeRawValue; } return self; } @end ``` **EventName Dictionary ヘルパーファイル** ```swift extension Dictionary where Key == String, Value == Any { init(eventName: String, properties: [String: Any]? = nil) { self.init() self[PushNotificationKey.eventName.rawValue] = eventName if let properties = properties { for (key, value) in properties { self[key] = value } } } } ``` ```objc @implementation NSDictionary (Helper) - (id)initWithEventName:(NSString *)eventName properties:(NSDictionary *)properties { self = [self init]; if (self) { dict[@"event_name"] = eventName; for(id key in properties) { dict[key] = properties[key]; } } return self; } @end ```
# iOS のプッシュ通知テスト Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/testing/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # テスト {#push-testing} コマンドラインからアプリ内通知とプッシュ通知をテストする場合は、CURLと[メッセージングAPI](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)を介してターミナルから単一の通知を送信できます。次のフィールドをテストケースの正しい値に置き換える必要があります。 必須フィールド: - `YOUR-API-KEY-HERE` - **設定** > **APIキー**で利用できます。このキーが`/messages/send` REST APIエンドポイントを介したメッセージ送信を許可されていることを確認してください。 - `EXTERNAL_USER_ID` - **ユーザーを検索**ページで確認できます。 - `REST_API_ENDPOINT_URL` - Brazeの[インスタンス](https://www.braze.com/docs/ja/ja/api/basics#endpoints. Ensure using the endpoint corresponds to the Braze instance your workspace is on. Optional fields: - `YOUR_KEY1` (optional)に記載されています。使用するエンドポイントがワークスペースのBrazeインスタンスに対応していることを確認してください。 オプションフィールド: - `YOUR_KEY1`(オプション) - `YOUR_VALUE1`(オプション) ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer YOUR-API-KEY-HERE" -d '{ "external_user_ids":["EXTERNAL_USER_ID"], "messages": { "apple_push": { "alert":"Test push", "extra": { "YOUR_KEY1":"YOUR_VALUE1" } } } }' https://{REST_API_ENDPOINT_URL}/messages/send ``` # iOS のプッシュ通知単体テスト Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/unit_tests/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 単体テスト {#unit-tests} このオプションガイドでは、アプリデリゲートが[プッシュ統合手順](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)に記載されているステップに正しく従っているかどうかを検証するいくつかの単体テストを実装する方法について説明します。 すべてのテストに合格した場合、通常はプッシュ設定のコードベース部分が正しく機能していることを意味します。テストが失敗した場合は、ステップを誤って実行したか、有効なカスタマイズがデフォルトの手順と正確に一致していないことが原因である可能性があります。 いずれにせよ、これは統合ステップに従っていることを確認し、リグレッションを監視するのに役立つアプローチです。 ## ステップ 1: 単体テストターゲットの作成 {#step-1-creating-a-unit-tests-target} Xcodeのアプリプロジェクトにすでに単体テストバンドルが含まれている場合は、このステップをスキップしてください。 アプリプロジェクトで、メニューの **File > New > Target** に移動し、新しい「Unit Testing Bundle」を追加します。このバンドルではObjective-CまたはSwiftを使用でき、任意の名前を付けることができます。「Target to be Tested」をメインのアプリターゲットに設定します。 ## ステップ 2: Braze SDKを単体テストに追加する {#step-2-add-the-braze-sdk-to-your-unit-tests} 最初に[Braze SDKをインストール](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/overview)するために使用したのと同じ方法を使用して、同じSDKインストールが単体テストのターゲットでも使用できることを確認します。たとえば、CocoaPodsを使用する場合は次のようになります。 ``` target 'YourAppTarget' do pod 'Appboy-iOS-SDK' target 'YourAppTargetTests' do inherit! :search_paths end end ``` ## ステップ 3: OCMockを単体テストに追加する {#step-3-add-ocmock-to-your-unit-tests} CocoaPods、Carthage、またはその静的ライブラリーを介して[OCMock](https://ocmock.org/)をテストターゲットに追加します。たとえば、CocoaPodsを使用する場合は次のようになります。 ``` target 'YourAppTarget' do pod 'Appboy-iOS-SDK' target 'YourAppTargetTests' do inherit! :search_paths pod 'OCMock' end end ``` ## ステップ 4: 追加したライブラリーのインストールを完了する {#step-4-finish-installing-the-added-libraries} Braze SDKとOCMockのインストールを完了します。たとえば、CocoaPodsを使用して、ターミナルでXcodeアプリプロジェクトのディレクトリに移動し、次のコマンドを実行します。 ``` pod install ``` この時点で、CocoaPodsによって作成されたXcodeプロジェクトワークスペースを開くことができるはずです。 ## ステップ 5: プッシュテストの追加 {#step-5-adding-push-tests} 単体テストのターゲットに新しいObjective-Cファイルを作成します。 単体テストのターゲットがSwiftの場合、Xcodeは「Would you like to configure an Objective-C bridging header?」と尋ねることがあります。ブリッジングヘッダーはオプションであるため、**Don't Create** をクリックしてもこれらの単体テストを正常に実行できます。 HelloSwiftサンプルアプリの[`AppboyPushUnitTests.m`](https://github.com/Appboy/appboy-ios-sdk/blob/master/HelloSwift/HelloSwiftTests/AppboyPushUnitTests.m)のコンテンツを新しいファイルに追加します。 ## ステップ 6: テストスイートを実行する {#step-6-run-test-suite} アプリの単体テストを実行します。これは1回限りの検証ステップにすることも、リグレッションを検出するためにテストスイートに無期限に含めることもできます。 # iOSのプッシュ通知のトラブルシューティング Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/troubleshooting/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # トラブルシューティング {#push-troubleshooting} ## Braze/APNsのワークフローについて {#understanding-the-brazeapns-workflow} Apple プッシュ通知サービス(APNs)は、iOSおよびOS Xアプリにプッシュ通知を送信するためのAppleのインフラです。ユーザーのデバイスに対してプッシュ通知を有効にする方法と、Brazeがユーザーにプッシュ通知を送信する方法の簡単な構造を次に示します。 1. プッシュ証明書とプロビジョニングプロファイルを構成します 2. デバイスがAPNsに登録し、Brazeにプッシュトークンを提供します 3. Brazeプッシュキャンペーンを開始します 4. Brazeは無効なトークンを削除します ### ステップ 1:プッシュ証明書とプロビジョニングプロファイルの構成 {#step-1-configuring-the-push-certificate-and-provisioning-profile} アプリの開発では、プッシュ通知を有効にするためにSSL証明書を作成する必要があります。この証明書はアプリのビルドに使用されるプロビジョニングプロファイルに含まれ、Brazeダッシュボードにアップロードする必要もあります。証明書を使用すると、Brazeはあなたに代わってプッシュ通知を送信することが許可されていることをAPNsに伝えることができます。 [プロビジョニングプロファイル](https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingProfiles/MaintainingProfiles.html)と証明書には、開発と配布の2つのタイプがあります。混乱を避けるために、配布プロファイルと証明書だけを使用することをお勧めします。開発と配布で異なるプロファイルと証明書を使用することを選択した場合は、ダッシュボードにアップロードされた証明書が現在使用しているプロビジョニングプロファイルと一致することを確認してください。 **Warning:** プッシュ証明書の環境(開発環境と本番環境)を変更しないでください。プッシュ証明書を間違った環境に変更すると、ユーザーのプッシュトークンが誤って削除され、プッシュで到達できなくなる可能性があります。 #### ステップ 2:デバイスがAPNsに登録し、Brazeにプッシュトークンを提供します {#step-2-devices-register-for-apns-and-provide-braze-with-push-tokens} ユーザーがアプリを開くと、プッシュ通知を受け入れるように求められます。このプロンプトを受け入れると、APNsはその特定のデバイスのプッシュトークンを生成します。iOS SDKは、デフォルトの[自動フラッシュポリシー](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/advanced_use_cases/fine_network_traffic_control#automatic-request-processing)を使用して、アプリのプッシュトークンを直ちに非同期に送信します。ユーザーにプッシュトークンが関連付けられると、ダッシュボードの**エンゲージメント**タブのユーザープロファイルに「プッシュ登録済み」と表示され、Brazeのキャンペーンからプッシュ通知を受け取る資格が得られます。 **Note:** Xcode 14では、iOSシミュレーター上でリモートプッシュ通知をテストできます。 #### ステップ 3:Brazeプッシュキャンペーンの開始 {#step-3-launching-a-braze-push-campaign} プッシュキャンペーンが開始されると、BrazeはAPNsにメッセージの配信リクエストを行います。Brazeは、ダッシュボードにアップロードされたSSLプッシュ証明書を使用して認証を行い、提供されたプッシュトークンへのプッシュ通知の送信が許可されていることを確認します。デバイスがオンラインの場合は、キャンペーンが送信された後すぐに通知が受信されます。なお、Brazeは通知のデフォルトのAPNs[有効期限](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607)を30日に設定しています。 #### ステップ 4:無効なトークンの削除 {#step-4-removing-invalid-tokens} [APNs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1)が、メッセージを送信しようとしていたプッシュトークンのいずれかが無効であることを通知した場合、それらのトークンは関連付けられたユーザープロファイルから削除されます。 ## プッシュエラーログの活用 {#utilizing-the-push-error-logs} Brazeは、**メッセージアクティビティログ**内にプッシュ通知エラーのログを提供します。このエラーログは、キャンペーンが期待どおりに機能していない理由を特定するのに非常に役立つさまざまな警告を提供します。エラーメッセージをクリックすると、特定のインシデントのトラブルシューティングに役立つ関連ドキュメントにリダイレクトされます。 ![エラーが発生した時間、アプリ名、チャネル、エラータイプ、およびエラーメッセージを表示するプッシュエラーログ](https://www.braze.com/docs/ja/ja/assets/img_archive/message_activity_log.png?6577302323ab3f2df3196a973320b8d3) ここでよく見かけるエラーとしては、[「プッシュトークンへの未登録送信を受信」](#received-unregistered-sending)など、ユーザー固有の通知があります。 さらに、Brazeは**エンゲージメント**タブのユーザープロファイルにプッシュ通知の変更ログも提供します。この変更ログは、トークンの無効化、プッシュ登録エラー、トークンの新規ユーザーへの移動などのプッシュ登録動作に関するインサイトを提供します。 ![プッシュ変更ログのアニメーション例](https://www.braze.com/docs/ja/ja/assets/img_archive/push_changelog.gif?36d10186d33121a195e943385dd0d02a){: style="max-width:50%;" } ## プッシュ登録に関する問題 {#push-registration-issues} アプリケーションのプッシュ登録ロジックの検証を追加するには、[プッシュユニットテスト](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/unit_tests)を実装します。 ### プッシュ登録プロンプトが表示されない {#no-push-registration-prompt} アプリケーションでプッシュ通知の登録を求めるメッセージが表示されない場合は、プッシュ登録の統合に問題がある可能性があります。[ドキュメント](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)に従っており、プッシュ登録が正しく統合されていることを確認してください。コードにブレークポイントを設定して、プッシュ登録コードが実行されていることを確認することもできます。 #### ダッシュボードに「プッシュ登録済み」ユーザーが表示されない {#no-push-registered-users-showing-in-the-dashboard} - アプリがプッシュ通知を許可するように求めるメッセージを表示していることを確認します。通常、このプロンプトはアプリを初めて起動したときに表示されますが、他の場所に表示されるようにプログラムすることもできます。表示されるべき場所に表示されない場合は、アプリのプッシュ機能の基本構成に問題がある可能性があります。 - [プッシュ統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)の手順が正常に完了したことを確認します。 - アプリのビルドに使用されたプロビジョニングプロファイルにプッシュの権限が含まれていることを確認します。Apple開発者アカウントから利用可能なプロビジョニングプロファイルをすべてプルダウンしていることを確認してください。これを確認するには、次の手順を実行します。 1. Xcodeで、**Preferences > Accounts**に移動します(または、キーボードショートカットCommand+,を使用します)。 2. 開発者アカウントに使用するApple IDを選択し、**View Details**をクリックします。 3. 次のページで、** Refresh**をクリックし、使用可能なすべてのプロビジョニングプロファイルをプルしていることを確認します。 - アプリで[プッシュ機能が適切に有効化](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/push_notifications/integration#step-2-enable-push-capabilities)されていることを確認します。 - プッシュプロビジョニングプロファイルがテスト環境と一致することを確認します。ユニバーサル証明書は、開発または本番のAPNs環境のいずれかに送信するようにBrazeダッシュボードで構成できます。本番アプリ用の開発証明書または開発アプリ用の本番証明書は動作しません。 - コードにブレークポイントを設定して、`registerPushToken`メソッドを呼び出していることを確認します。 - デバイス上にあり(シミュレーター上ではプッシュは機能しません)、ネットワーク接続が良好であることを確認します。 ## デバイスがプッシュ通知を受信しない {#devices-not-receiving-push-notifications} ### プッシュ通知の送信後にユーザーが「プッシュ登録」されなくなった {#users-no-longer-push-registered-after-sending-a-push-notification} これは、ユーザーが無効なプッシュトークンを持っていたことを示している可能性があります。これにはいくつかの理由が考えられます。 #### ダッシュボードとアプリ証明書が一致していない {#dashboard-and-app-certificate-mismatch} ダッシュボードでアップロードしたプッシュ証明書が、アプリのビルドに使用したプロビジョニングプロファイルのものと異なる場合、APNsはトークンを拒否します。別のテスト通知を試みる前に、正しい証明書をアップロードし、アプリで別のセッションを完了していることを確認します。 ##### アンインストール {#uninstalls} ユーザーがアプリケーションをアンインストールした場合、プッシュトークンは無効となり、次回の送信時に削除されます。 ##### プロビジョニングプロファイルの再生成 {#regenerating-your-provisioning-profile} 最後の手段として、最初からやり直してまったく新しいプロビジョニングプロファイルを作成すると、複数の環境、プロファイル、およびアプリを同時に操作することによって発生する構成エラーを解消できます。iOSアプリのプッシュ通知の設定は「動く部分」が多いので、最初からやり直したほうがいい場合もあります。また、トラブルシューティングを続ける必要がある場合は、問題を切り分けるのに役立ちます。 #### プッシュ通知を送信した後もユーザーが「プッシュ登録」されている {#users-still-push-registered-after-sending-a-push-notification} ##### アプリがフォアグラウンドにある {#app-is-foregrounded} `UserNotifications`フレームワークを介してプッシュを統合していないiOSバージョンでは、プッシュメッセージの受信時にアプリがフォアグラウンドにある場合、そのメッセージは表示されません。テストメッセージを送信する前に、テストデバイスでアプリをバックグラウンドにする必要があります。 ##### テスト通知のスケジュールが正しくない {#test-notification-scheduled-incorrectly} テストメッセージに設定したスケジュールを確認します。ローカルタイムゾーン配信または[インテリジェントタイミング](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence_suite/intelligent_timing)に設定されている場合、メッセージがまだ受信されていない(または受信時にアプリがフォアグラウンドにあった)だけかもしれません。 #### テスト対象のアプリに対してユーザーが「プッシュ登録」されていない {#user-not-push-registered-for-the-app-being-tested} テストメッセージを送信しようとしている相手のユーザープロファイルを確認します。**エンゲージメント**タブの下に「プッシュ可能なアプリ」のリストがあるはずです。テストメッセージを送信しようとしているアプリがこのリストにあることを確認します。ユーザーがワークスペース内の任意のアプリのプッシュトークンを持っている場合は「プッシュ登録済み」と表示されるため、誤検知の可能性があります。 以下は、プッシュ登録に問題があるか、プッシュ後にユーザーのトークンがAPNsによって無効としてBrazeに返されたことを示しています。 ![ユーザーの連絡先設定を表示するユーザープロファイル。ここでは、どのアプリがプッシュ通知に登録されているかを確認できます。](https://www.braze.com/docs/ja/ja/assets/img_archive/registration_problem.png?b01abd4f8f8ddd58425f6ecc82c256ea){: style="max-width:50%"} ## プッシュメッセージが送信されない {#push-messages-not-sending} 送信されないプッシュ通知のトラブルシューティングについては、[プッシュのトラブルシューティング](https://www.braze.com/docs/ja/ja/user_guide/channels/push/troubleshooting)を参照してください。 ## メッセージアクティビティログのエラー {#message-activity-log-errors} ### プッシュトークンへの未登録送信を受信した {#received-unregistered-sending} - メソッド`[[Appboy sharedInstance] registerPushToken:]`からBrazeに送信されているプッシュトークンが有効であることを確認してください。**メッセージアクティビティログ**を見ると、プッシュトークンを確認できます。これは`6e407a9be8d07f0cdeb9e724733a89445f57a89ec890d63867c482a483506fa6`のようになり、文字と数字が混在する長い文字列になります。プッシュトークンが異なるように見える場合は、Brazeにプッシュトークンを送信するための[コード](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/push_notifications/integration#step-4-register-push-tokens-with-braze)を確認してください。 - プッシュプロビジョニングプロファイルがテスト対象の環境と一致することを確認します。ユニバーサル証明書は、開発または本番のAPNs環境のいずれかに送信するようにBrazeダッシュボードで構成できます。本番アプリ用の開発証明書または開発アプリ用の本番証明書は動作しません。 - Brazeにアップロードしたプッシュトークンが、プッシュトークンの送信元のアプリのビルドに使用したプロビジョニングプロファイルと一致することを確認します。 #### デバイストークンがトピック用ではない {#device-token-not-for-topic} このエラーは、アプリのプッシュ証明書とバンドルIDが一致しないことを示しています。Brazeにアップロードしたプッシュ証明書が、プッシュトークンの送信元となるアプリのビルドに使用したプロビジョニングプロファイルと一致することを確認してください。 #### プッシュトークンへのBadDeviceTokenの送信 {#baddevicetoken-sending-to-push-token} `BadDeviceToken`はAPNsのエラーコードであり、Brazeから発信されたものではありません。この応答が返される理由としては、次のようなものが考えられます。 - アプリが、ダッシュボードにアップロードされた認証情報に対して無効なプッシュトークンを受け取った。 - このワークスペースではプッシュが無効になっていた。 - ユーザーがプッシュをオプトアウトした。 - アプリがアンインストールされた。 - Appleがプッシュトークンを更新したため、古いトークンが無効になった。 - アプリは本番環境用にビルドされていますが、Brazeにアップロードされたプッシュ認証情報は開発環境用に設定されています(または逆の場合もあります)。 ## プッシュ配信後の問題 {#issues-after-push-delivery} アプリケーションのプッシュ処理の検証を追加するには、[プッシュユニットテスト](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/unit_tests)を実装します。 ### プッシュクリックが記録されない {#push-clicks-not-logged} - これがiOS 10でのみ発生する場合は、[iOS 10](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/push_notifications/integration#step-5-enable-push-handling)のプッシュ統合手順に従っていることを確認してください。 - Brazeでは、フォアグラウンドでサイレント受信したプッシュ通知(`UserNotifications`フレームワーク以前のデフォルトのフォアグラウンドプッシュ動作など)は処理されません。つまり、リンクは開かれず、プッシュクリックは記録されません。アプリケーションが`UserNotifications`フレームワークをまだ統合していない場合、アプリケーション状態が`UIApplicationStateActive`のときにBrazeはプッシュ通知を処理しません。アプリが[プッシュ処理メソッド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/push_notifications/integration#step-5-enable-push-handling)への呼び出しを遅延しないようにしてください。遅延した場合、iOS SDKはプッシュ通知をサイレントフォアグラウンドプッシュイベントとして扱い、処理しないことがあります。 #### プッシュクリックからのWebリンクが開かない {#web-links-from-push-clicks-not-opening} iOS 9以降では、Webビューで開くにはATS準拠のリンクが必要です。WebリンクがHTTPSを使用していることを確認してください。詳細については、[ATS準拠](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/advanced_use_cases/linking#app-transport-security-ats)の記事を参照してください。 #### プッシュクリックからディープリンクが開かない {#deep-links-from-push-clicks-not-opening} ディープリンクを扱うコードのほとんどはプッシュ通知の開封も扱います。まず、プッシュ通知の開封がログに記録されていることを確認します。記録されていない場合は、[その問題を修正](#push-clicks-not-logged)してください(多くの場合、修正によりリンク処理も修正されます)。 開封が記録されている場合は、ディープリンク全般の問題なのか、ディープリンクのプッシュクリック処理の問題なのかを確認してください。そのためには、アプリ内メッセージクリックからのディープリンクが機能するかテストします。 #### 直接開封がほとんどない、または全くない {#few-or-no-direct-opens} iOSプッシュ通知を開封したユーザーが1人以上いるにもかかわらず、Brazeに*直接開封*のログがほとんど残っていない場合、[SDKの統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/overview)に問題がある可能性があります。テスト送信またはサイレントプッシュ通知については、*直接開封*はログに記録されません。 - メッセージが[サイレントプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/silent_push_notifications#sending-silent-push-notifications)として送信されていないことを確認します。メッセージがサイレントと見なされないようにするには、タイトルまたは本文にテキストを含める必要があります。 - [プッシュ統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)から以下のステップを再確認してください。 - [プッシュを登録する](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration#step-1-register-for-push-notifications-with-apns):アプリを起動するたびに、できれば`application:didFinishLaunchingWithOptions:`内で、ステップ3のコードを実行する必要があります。`UNUserNotificationCenter.current()`のdelegateプロパティは、`UNUserNotificationCenterDelegate`を実装し、`(void)userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:`メソッドを含むオブジェクトに割り当てる必要があります。 - [プッシュ処理を有効にする](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/legacy_sdks/ios/push_notifications/integration#step-5-enable-push-handling):`(void)userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:`メソッドが実装されていることを確認してください。 # iOS 向けアプリ内メッセージの概要 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/overview/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # アプリ内メッセージ {#in-app-messages} [アプリ内メッセージ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages)を使用すると、プッシュ通知でユーザーの日常を邪魔することなく、コンテンツをユーザーに届けることができます。カスタマイズされ調整されたアプリ内メッセージは、ユーザーエクスペリエンスを向上させ、オーディエンスがアプリから最大限の価値を得るのに役立ちます。さまざまなレイアウトやカスタマイズツールから選べるため、アプリ内メッセージはこれまで以上にユーザーを惹きつけます。 アプリ内メッセージの例については、[ケーススタディ](https://www.braze.com/customers)をご覧ください。 ## アプリ内メッセージのタイプ {#in-app-message-types} Brazeは現在、以下のアプリ内メッセージタイプをデフォルトで提供しています。 - `Slideup` - `Modal` - `Full` - `HTML Full` 各アプリ内メッセージタイプは、コンテンツ、画像、アイコン、クリックアクション、分析、表示、配信にわたって高度にカスタマイズできます。 すべてのアプリ内メッセージは `ABKInAppMessage` のサブクラスであり、すべてのアプリ内メッセージの基本動作と特徴を定義しています。アプリ内メッセージのクラス構造は以下のとおりです。 ![ABKInAppMessageクラスがABKInAppMessageSlideup、ABKInAppMessageImmersive、ABKInAppMessageHTMLのルートクラスであることを示す図。ABKInAppMessageには、メッセージ、エクストラ、持続時間、クリックアクション、URI、閉じるアクション、アイコンの向き、テキストの配置などのカスタマイズ可能なプロパティが含まれています。ABKInAppMessageSlideupには、シェブロンやスライドアップアンカーなどのカスタマイズ可能なプロパティが含まれています。ABKInAppMessageImmersiveには、ヘッダー、閉じるボタン、フレーム、アプリ内メッセージボタンなどのカスタマイズ可能なプロパティが含まれています。ABKInAppMessageHTMLを使うと、HTMLアプリ内メッセージボタンのクリックを手動で記録できます。](https://www.braze.com/docs/ja/ja/assets/img_archive/ABKInAppMessage-models.png?b0b1c31bde206c1dc8d5f14a07cc82a0) **Important:** デフォルトでは、アプリ内メッセージは、GIFサポートを含む標準SDK統合を完了した後に有効になります。

iOSアプリ内メッセージまたはContent Cards内の画像を表示するためにBraze UIを使用する場合は、`SDWebImage` の統合が必要です。 ### メッセージタイプ別に予想される動作 {#expected-behaviors-by-message-types} ユーザーがデフォルトのアプリ内メッセージタイプの1つを開くと、次のように表示されます。 [`Slideup`](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_in_app_message_slideup.html) アプリ内メッセージは、画面の上部または下部から「スライドアップ」または「スライドダウン」するため、このような名前が付けられています。画面の一部分だけを覆い、効果的で邪魔にならないメッセージング機能を提供します。 ![携帯電話の画面の下部からスライドして表示されるアプリ内メッセージに「Humans are complicated. Custom engagement shouldn't be.」と表示されています。バックグラウンドには、Webページの下隅に表示される同じアプリ内メッセージが表示されています。](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`Modal`](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_in_app_message_modal.html) アプリ内メッセージは画面中央に表示され、半透明のパネルに囲まれます。より重要なメッセージングに有用で、最大2つのクリックアクションと分析対応ボタンを装備できます。 ![携帯電話の画面中央に表示されるモーダルアプリ内メッセージに「Humans are complicated. Custom engagement shouldn't be.」と表示されています。バックグラウンドには、Webページの中央に表示される同じアプリ内メッセージが表示されています。](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`Full`](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_in_app_message_full.html) アプリ内メッセージは、ユーザーコミュニケーションの内容とインパクトを最大化するのに有効です。`full` アプリ内メッセージの上半分には画像が含まれ、下半分にはテキストと最大2つのクリックアクションおよび分析対応ボタンが表示されます。 ![携帯電話の画面全体に表示されるフルスクリーンアプリ内メッセージに「Humans are complicated. Custom engagement shouldn't be.」と表示されています。バックグラウンドには、Webページの中央に大きく表示される同じアプリ内メッセージが表示されています。](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} [`HTML Full`](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_in_app_message_h_t_m_l_full.html) アプリ内メッセージは、完全にカスタマイズされたユーザーコンテンツを作成するのに便利です。ユーザー定義のHTML Fullアプリ内メッセージコンテンツは `WKWebView` に表示され、必要に応じて画像やフォントなどの他のリッチコンテンツを含めることができます。これにより、メッセージの外観と機能を完全に制御できます。

iOSアプリ内メッセージは、HTML内からBraze Web SDKのメソッドを呼び出すためのJavaScript `brazeBridge` インターフェイスをサポートしています。詳細については、[ベストプラクティス](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/best_practices)を参照してください。 次の例は、ページ分割されたHTML Fullアプリ内メッセージを示しています。 ![コンテンツのカルーセルとインタラクティブボタンを備えたHTMLアプリ内メッセージ。](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) Fullアプリ内メッセージコンテンツは `WKWebView` に表示され、オプションで画像やフォントなどの他のリッチコンテンツを含めることができ、メッセージの外観や機能を完全に制御できます。現在、iOSとAndroidのプラットフォームでは、iFrame内でのカスタムHTMLアプリ内メッセージの表示はサポートしていません。 **Note:** iOS SDKバージョン3.19.0以降、以下のJavaScriptメソッドはHTMLアプリ内メッセージではノーオペレーションとなりました: `alert`、`confirm`、`prompt`。 # iOS アプリ内メッセージのカスタマイズ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/index.md

# iOS向けアプリ内メッセージデリゲートの設定 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/setting_delegates/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # デリゲートの設定 {#set-delegates} アプリ内メッセージの表示と配信のカスタマイズは、オプションのデリゲートを設定することでコードで実行できます。 ## アプリ内メッセージデリゲート {#in-app-message-delegate} [`ABKInAppMessageUIDelegate`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyUI/ABKInAppMessage/ABKInAppMessageUIDelegate.h) デリゲートを使用すると、トリガーされたアプリ内メッセージペイロードを受信してさらに処理したり、表示ライフサイクルイベントを受信したり、表示タイミングを制御したりできます。 以下を呼び出して、Brazeインスタンスに`ABKInAppMessageUIDelegate`デリゲートオブジェクトを設定します。 ```objc [[Appboy sharedInstance].inAppMessageController.inAppMessageUIController setInAppMessageUIDelegate:self]; ``` ```swift Appboy.sharedInstance()?.inAppMessageController.inAppMessageUIController?.setInAppMessageUIDelegate?(self) ``` 実装例については、アプリ内メッセージの[サンプルアプリ](https://github.com/Appboy/appboy-ios-sdk/blob/master/Samples/InAppMessage/BrazeInAppMessageSample/BrazeInAppMessageSample/ViewController.m)を確認してください。Braze UIライブラリーをプロジェクトに含めていない場合(一般的ではありません)、このデリゲートは使用できないことに注意してください。 ## コアアプリ内メッセージデリゲート {#core-in-app-message-delegate} プロジェクトにBraze UIライブラリーを含めず、アプリ内でさらなる処理やカスタム表示のためにトリガーされたアプリ内メッセージペイロードを受信したい場合は、[`ABKInAppMessageControllerDelegate`](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/setting_delegates) プロトコルを実装してください。 以下を呼び出して、Brazeインスタンスに`ABKInAppMessageControllerDelegate`デリゲートオブジェクトを設定します。 ```objc [Appboy sharedInstance].inAppMessageController.delegate = self; ``` ```swift Appboy.sharedInstance()?.inAppMessageController.delegate = self ``` または、キー`ABKInAppMessageControllerDelegateKey`を使用して`appboyOptions`経由で、初期化時にコアのアプリ内メッセージデリゲートを設定することもできます。 ```objc [Appboy startWithApiKey:@"YOUR-API_KEY" inApplication:application withLaunchOptions:options withAppboyOptions:@{ ABKInAppMessageControllerDelegateKey : self }]; ``` ```swift Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:[ ABKInAppMessageControllerDelegateKey : self ]) ``` ## メソッド宣言 {#method-declarations} 詳細については、以下のヘッダーファイルを参照してください。 - [`ABKInAppMessage.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKInAppMessage.h) - [`ABKInAppMessageControllerDelegate.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKInAppMessageControllerDelegate.h) ## 実装サンプル {#implementation-samples} アプリ内メッセージサンプルアプリの[`ViewController.m`](https://github.com/Appboy/appboy-ios-sdk/blob/master/Samples/InAppMessage/BrazeInAppMessageSample/BrazeInAppMessageSample/ViewController.m)を参照してください。 # iOS向けアプリ内メッセージの向きをカスタマイズする Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/customizing_orientation/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 向きをカスタマイズする {#customize-orientation} ## すべてのアプリ内メッセージの向きの設定 {#setting-orientation-for-all-in-app-messages} すべてのアプリ内メッセージの向きを固定するには、`ABKInAppMessageUIController`の`supportedOrientationMask`プロパティを設定します。アプリが`startWithApiKey:inApplication:withLaunchOptions:`を呼び出した後に、次のコードを追加します。 ```objc // Set fixed in-app message orientation to portrait. // Use UIInterfaceOrientationMaskLandscape to display in-app messages in landscape id inAppMessageUIController = [Appboy sharedInstance].inAppMessageController.inAppMessageUIController; ((ABKInAppMessageUIController *)inAppMessageUIController).supportedOrientationMask = UIInterfaceOrientationMaskPortrait; ``` ```swift // Set fixed in-app message orientation to portrait // Use .landscape to display in-app messages in landscape if let controller = Appboy.sharedInstance()?.inAppMessageController.inAppMessageUIController as? ABKInAppMessageUIController { controller.supportedOrientationMask = .portrait } ``` その後、すべてのアプリ内メッセージは、デバイスの向きに関係なく、サポートされている向きで表示されます。メッセージを表示するには、デバイスの向きがアプリ内メッセージの`orientation`プロパティでもサポートされている必要があることに注意してください。 ## アプリ内メッセージごとの向きの設定 {#setting-orientation-per-in-app-message} または、メッセージごとに向きを設定することもできます。これを行うには、[アプリ内メッセージデリゲート](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/setting_delegates)を設定します。次に、`beforeInAppMessageDisplayed:`デリゲートメソッドで、`ABKInAppMessage`の`orientation`プロパティを設定します。 ```objc // Set inAppMessage orientation to portrait inAppMessage.orientation = ABKInAppMessageOrientationPortrait; // Set inAppMessage orientation to landscape inAppMessage.orientation = ABKInAppMessageOrientationLandscape; ``` ```swift // Set inAppMessage orientation to portrait inAppMessage.orientation = ABKInAppMessageOrientation.portrait // Set inAppMessage orientation to landscape inAppMessage.orientation = ABKInAppMessageOrientation.landscape ``` デバイスの向きがアプリ内メッセージの`orientation`プロパティと一致しない場合、アプリ内メッセージは表示されません。 **Note:** iPadの場合、アプリ内メッセージは、実際の画面の向きに関係なく、ユーザーが希望する向きのスタイルで表示されます。 ## メソッド宣言 {#method-declarations} 追加情報については、次のヘッダーファイルを参照してください。 - [`ABKInAppMessage.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKInAppMessage.h) # iOS向けアプリ内メッセージ表示の処理をカスタマイズする Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/handling_in_app_display/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # アプリ内メッセージ表示のカスタム処理 {#custom-handling-in-app-message-display} [`ABKInAppMessageControllerDelegate`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKInAppMessageControllerDelegate.h)を設定すると、アプリ内メッセージが表示される前に次のデリゲートメソッドが呼び出されます。 ```objc - (ABKInAppMessageDisplayChoice) beforeInAppMessageDisplayed:(ABKInAppMessage *)inAppMessage; ``` `````````swift func beforeInAppMessageDisplayed(inAppMessage: ABKInAppMessage!) -> ABKInAppMessageDisplayChoice ``` [`ABKInAppMessageUIDelegate`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyUI/ABKInAppMessage/ABKInAppMessageUIDelegate.h)のみを実装した場合は、代わりに次のUIデリゲートメソッドが呼び出されます。 `````````objc - (ABKInAppMessageDisplayChoice) beforeInAppMessageDisplayed:(ABKInAppMessage *)inAppMessage withKeyboardIsUp:(BOOL)keyboardIsUp; ``` `````````swift func beforeInAppMessageDisplayed(inAppMessage: ABKInAppMessage!, withKeyboardIsUp keyboardIsUp: Bool) -> ABKInAppMessageDisplayChoice ``` このデリゲートメソッドを実装し、`ABKInAppMessageDisplayChoice`に対して次のいずれかの値を返すことで、アプリ内メッセージ処理をカスタマイズできます。 | `ABKInAppMessageDisplayChoice` | 動作 | | -------------------------- | -------- | | Objective-C: `ABKDisplayInAppMessageNow`
Swift: `displayInAppMessageNow` | メッセージはすぐに表示されます。 | | Objective-C: `ABKDisplayInAppMessageLater`
Swift: `displayInAppMessageLater` | メッセージは表示されず、スタックの一番上に戻されます。 | | Objective-C: `ABKDiscardInAppMessage`
Swift: `discardInAppMessage` | メッセージは破棄され、表示されません。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="Custom handling in-app message display" } `beforeInAppMessageDisplayed:`デリゲートメソッドを使用して、アプリ内メッセージの表示ロジックを追加したり、Brazeが表示する前にアプリ内メッセージをカスタマイズしたり、Brazeのアプリ内メッセージ表示ロジックおよびUIを完全にオプトアウトしたりできます。 実装例については、[サンプルアプリケーション](https://github.com/Appboy/appboy-ios-sdk/blob/master/Samples/InAppMessage/BrazeInAppMessageSample/BrazeInAppMessageSample/AppDelegate.m)をご覧ください。 ## 表示前のアプリ内メッセージの上書き {#overriding-in-app-messages-before-display} アプリ内メッセージの表示動作を変更したい場合は、必要な表示ロジックを`beforeInAppMessageDisplayed:`デリゲートメソッドに追加する必要があります。たとえば、キーボードが現在表示されている場合は画面の上部からアプリ内メッセージを表示したり、アプリ内メッセージデータモデルを取得してアプリ内メッセージを自分で表示したりできます。 セッションの開始時にアプリ内メッセージキャンペーンが表示されない場合は、必要な表示ロジックが`beforeInAppMessageDisplayed:`デリゲートメソッドに追加されていることを確認してください。これにより、キーボードが表示されている場合でも、アプリ内メッセージキャンペーンを画面の上部から表示できます。 ## ダークモードを無効にする {#disabling-dark-mode} ユーザーデバイスでダークモードが有効になっているときにアプリ内メッセージがダークモードスタイルを採用しないようにするには、[`ABKInAppMessage.enableDarkTheme`](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_in_app_message.html#ae89df6090bed623099ab0ecc0a74ad5d)プロパティを使用します。`ABKInAppMessageControllerDelegate.beforeInAppMessageDisplayed:`または`ABKInAppMessageUIDelegate.beforeInAppMessageDisplayed:`メソッドのいずれかから、メソッドの`inAppMessage`パラメーターの`enableDarkTheme`プロパティを`NO`に設定します。 `````````objc // ABKInAppMessageControllerDelegate - (ABKInAppMessageDisplayChoice)beforeInAppMessageDisplayed:(ABKInAppMessage *)inAppMessage { ... inAppMessage.enableDarkTheme = NO; ... return ABKDisplayInAppMessageNow; } // ABKInAppMessageUIDelegate - (ABKInAppMessageDisplayChoice)beforeInAppMesssageDisplayed:(ABKInAppMessage *)inAppMessage withKeyboardIsUp:(BOOL)keyboardIsUp { ... inAppMessage.enableDarkTheme = NO; ... return ABKDisplayInAppMessageNow; } ``` `````````swift // ABKInAppMessageControllerDelegate func before(inAppMessageDisplayed inAppMessage: ABKInAppMessage) -> ABKInAppMessageDisplayChoice { ... inAppMessage.enableDarkTheme = false ... return ABKInAppMessageDisplayChoice.displayInAppMessageNow } // ABKInAppMessageUIDelegate func before(inAppMessageDisplayed inAppMessage: ABKInAppMessage, withKeyboardIsUp keyboardIsUp: Bool) -> ABKInAppMessageDisplayChoice { ... inAppMessage.enableDarkTheme = false ... return ABKInAppMessageDisplayChoice.displayInAppMessageNow } ``` ## 表示中にステータスバーを非表示にする {#hiding-the-status-bar-during-display} `Full`および`HTML`のアプリ内メッセージの場合、SDKはデフォルトでメッセージをステータスバーの上に配置しようとします。ただし、場合によっては、ステータスバーがアプリ内メッセージの上に表示されたままになることがあります。iOS SDKのバージョン[3.21.1](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3211)以降では、`startWithApiKey:`に渡された`appboyOptions`内で`ABKInAppMessageHideStatusBarKey`を`YES`に設定することで、`Full`および`HTML`のアプリ内メッセージを表示するときにステータスバーを強制的に非表示にできます。 ## インプレッション数とクリック数を記録する {#logging-impressions-and-clicks} 完全なカスタム処理を実装している場合(たとえば、`beforeInAppMessageDisplayed:`で`ABKDiscardInAppMessage`を返すことでBrazeのアプリ内メッセージ表示を回避する場合)、アプリ内メッセージのインプレッション数とクリック数のログへの記録は自動的には行われません。アプリ内メッセージモデルを使用して独自のUIを実装する場合は、`ABKInAppMessage`クラスで次のメソッドを使用して分析をログに記録する必要があります。 `````````objc // Registers that a user has viewed an in-app message with the Braze server. - (void) logInAppMessageImpression; // Registers that a user has clicked on an in-app message with the Braze server. - (void) logInAppMessageClicked; ``` `````````swift // Registers that a user has viewed an in-app message with the Braze server. func logInAppMessageImpression() // Registers that a user has clicked on an in-app message with the Braze server. func logInAppMessageClicked() ``` さらに、`ABKInAppMessageImmersive`のサブクラス(*つまり*、`Modal`と`Full`のアプリ内メッセージ)のボタンクリック数を記録する必要があります。 `````````objc // Logs button click analytics - (void)logInAppMessageClickedWithButtonID:(NSInteger)buttonID; ``` `````````swift // Logs button click analytics func logInAppMessageClickedWithButtonID(buttonId: NSInteger) ``` ## メソッド宣言 {#method-declarations} 詳細については、次のヘッダーファイルを参照してください。 - [`ABKInAppMessage.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKInAppMessage.h) - [`ABKInAppMessageControllerDelegate.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKInAppMessageControllerDelegate.h) ## 実装サンプル {#implementation-samples} [`AppDelegate.m`](https://github.com/Appboy/appboy-ios-sdk/blob/master/Samples/InAppMessage/BrazeInAppMessageSample/BrazeInAppMessageSample/AppDelegate.m)アプリ内メッセージサンプルアプリを参照してください。 # iOS向けアプリ内メッセージのクリック時の動作をカスタマイズする Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/behavior_on_click/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # アプリ内メッセージのクリック時の動作をカスタマイズする {#customize-in-app-message-behavior-on-click} `ABKInAppMessage`の`inAppMessageClickActionType` プロパティは、アプリ内メッセージがクリックされた後のアクション動作を定義します。このプロパティは読み取り専用です。アプリ内メッセージのクリック動作を変更する場合は、`ABKInAppMessage`で以下の方法を呼び出すことができます。 ```objc [inAppMessage setInAppMessageClickAction:clickActionType withURI:uri]; ``` `````````swift inAppMessage.setInAppMessageClickAction(clickActionType: clickActionType, withURI: uri) ``` `inAppMessageClickActionType` は次のいずれかの値に設定できます。 | `ABKInAppMessageClickActionType` | クリック時動作 | | -------------------------- | -------- | | `ABKInAppMessageRedirectToURI` | メッセージがクリックされたときに指定されたURIが表示され、メッセージは閉じられます。`uri` パラメータをnilにすることはできないことに注意してください。 | | `ABKInAppMessageNoneClickAction` | クリックするとメッセージが閉じられます。`uri` パラメータは無視され、`ABKInAppMessage`の`uri` プロパティはnilに設定されます。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="アプリ内メッセージのクリック時の動作をカスタマイズする" } **Important:** ボタンを含むアプリ内メッセージの場合、ボタンテキストを追加する前にクリックアクションが追加されると、メッセージの`clickAction` も最終ペイロードに含まれます。 ## アプリ内メッセージ本文クリックのカスタマイズ {#customizing-in-app-message-body-clicks} アプリ内メッセージがクリックされると、次の[`ABKInAppMessageUIDelegate`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyUI/ABKInAppMessage/ABKInAppMessageUIDelegate.h) デリゲートメソッドが呼び出されます。 `````````objc - (BOOL) onInAppMessageClicked:(ABKInAppMessage *)inAppMessage; ``` `````````swift func onInAppMessageClicked(inAppMessage: ABKInAppMessage!) -> Bool ``` ## アプリ内メッセージボタンクリックのカスタマイズ {#customizing-in-app-message-button-clicks} アプリ内メッセージボタンやHTMLアプリ内メッセージボタン(リンクなど)のクリックに対して、[`ABKInAppMessageUIDelegate`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyUI/ABKInAppMessage/ABKInAppMessageUIDelegate.h) には次のデリゲートメソッドが含まれています。 `````````objc - (BOOL)onInAppMessageButtonClicked:(ABKInAppMessageImmersive *)inAppMessage button:(ABKInAppMessageButton *)button; - (BOOL)onInAppMessageHTMLButtonClicked:(ABKInAppMessageHTML *)inAppMessage clickedURL:(nullable NSURL *)clickedURL buttonID:(NSString *)buttonID; ``` `````````swift func onInAppMessageButtonClicked(inAppMessage: ABKInAppMessageImmersive!, button: ABKInAppMessageButton) -> Bool func onInAppMessageHTMLButtonClicked(inAppMessage: ABKInAppMessageHTML!, clickedURL: URL, buttonID: String) -> Bool ``` 各メソッドは、Brazeがクリックアクションの実行を続行すべきかどうかを示す `BOOL` 値を返します。 デリゲートメソッドでボタンのクリックアクションタイプにアクセスするには、次のコードを使用できます。 `````````objc if ([inAppMessage isKindOfClass:[ABKInAppMessageImmersive class]]) { ABKInAppMessageImmersive *immersiveIAM = (ABKInAppMessageImmersive *)inAppMessage; NSArray *buttons = immersiveIAM.buttons; for (ABKInAppMessageButton *button in buttons) { // Button action type is accessible via button.buttonClickActionType } } ``` `````````swift if inAppMessage is ABKInAppMessageImmersive { let immersiveIAM = inAppMessage as! ABKInAppMessageImmersive; for button in inAppMessage.buttons as! [ABKInAppMessageButton]{ // Button action type is accessible via button.buttonClickActionType } } ``` アプリ内メッセージにボタンがある場合、実行されるクリックアクションは `ABKInAppMessageButton` モデルのクリックアクションのみです。`ABKInAppMessage` モデルにデフォルトのクリックアクションが割り当てられている場合でも、アプリ内メッセージ本文はクリックできません。 ## メソッドの宣言 {#method-declarations} 詳細については、次のヘッダーファイルを参照してください。 - [`ABKInAppMessage.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKInAppMessage.h) # iOS向けアプリ内メッセージのトリガー設定をカスタマイズする Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/custom_triggering/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # カスタムアプリ内メッセージトリガー {#custom-in-app-message-triggering} デフォルトでは、アプリ内メッセージはSDKによって記録されるイベントタイプによってトリガーされます。サーバー送信イベントによってアプリ内メッセージをトリガーしたい場合にも実現できます。 この機能を有効にするには、サイレントプッシュをデバイスに送信し、デバイスがSDKベースのイベントをログに記録できるようにします。このSDKイベントは、その後、ユーザー向けのアプリ内メッセージをトリガーします。 ## ステップ 1:サイレントプッシュとキーと値のペアを処理する {#step-1-handle-silent-push-and-key-value-pairs} `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)` メソッド内に次のコードを追加します。 ```objc - (void)handleExtrasFromPush:(NSDictionary *)userInfo { NSLog(@"A push was received."); if (userInfo !=nil && userInfo[@"IS_SERVER_EVENT"] !=nil && userInfo[@"CAMPAIGN_NAME"]!=nil) { [[Appboy sharedInstance] logCustomEvent:@"IAM Trigger" withProperties:@{@"campaign_name": userInfo[@"CAMPAIGN_NAME"]}]; } }; ``` ```swift func handleExtras(userInfo: [AnyHashable : Any]) { NSLog("A push was received"); if userInfo != nil && (userInfo["IS_SERVER_EVENT"] as? String) != nil && (userInfo["CAMPAIGN_NAME"] as? String) != nil { Appboy.sharedInstance()?.logCustomEvent("IAM Trigger", withProperties: ["campaign_name": userInfo["CAMPAIGN_NAME"]]) } } ``` サイレントプッシュを受信すると、ユーザープロファイルに対してSDKが記録したイベント「アプリ内メッセージトリガー」がログに記録されます。なお、これらのアプリ内メッセージは、アプリケーションがフォアグラウンドにある間にサイレントプッシュが受信された場合にのみトリガーされます。 ## ステップ 2:プッシュキャンペーンを作成する {#step-2-create-a-push-campaign} サーバー送信イベントを介してトリガーされるサイレントプッシュキャンペーンを作成します。サイレントプッシュキャンペーンの作成の詳細については、[サイレントプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/silent_push_notifications)を参照してください。 ![カスタムイベント「server_event」を実行したユーザーに配信される、アクションベースの配信アプリ内メッセージキャンペーン。](https://www.braze.com/docs/ja/ja/assets/img_archive/iosServerSentPush.png?f2398c5efce1eef517dc7eabe0b5801b) プッシュキャンペーンにはキーと値のペアのエクストラを含める必要があります。これは、このプッシュキャンペーンがSDKカスタムイベントを記録するために送信されることを示します。このイベントはアプリ内メッセージをトリガーするために使用されます。 ![2つのキーと値のペアを持つアクションベースの配信アプリ内メッセージキャンペーン。「CAMPAIGN_NAME」は「In-app message name example」に設定され、「IS_SERVER_EVENT」は「true」に設定されています。](https://www.braze.com/docs/ja/ja/assets/img_archive/iOSServerPush.png?e84dc261f2b58bc43d35748e9c7db7f7) `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)` メソッド内のコードはキー `IS_SERVER_EVENT` をチェックし、存在する場合はSDKカスタムイベントをログに記録します。 プッシュペイロードのキーと値のペアのエクストラ内で目的の値を送信することで、イベント名またはイベントプロパティのいずれかを変更できます。カスタムイベントを記録する場合、これらのエクストラはイベント名のパラメータまたはイベントプロパティとして使用できます。 ## ステップ 3:アプリ内メッセージキャンペーンを作成する {#step-3-create-an-in-app-message-campaign} Brazeダッシュボード内から、ユーザーに表示されるアプリ内メッセージキャンペーンを作成します。このキャンペーンにはアクションベースの配信を設定し、`application(_:didReceiveRemoteNotification:fetchCompletionHandler:)` メソッド内から記録されたカスタムイベントからトリガーされるようにする必要があります。 以下の例では、イベントプロパティを最初のサイレントプッシュの一部として送信することで、トリガーされる特定のアプリ内メッセージが設定されています。 ![カスタムイベント「In-app message trigger」を実行したユーザーに配信される、アクションベースの配信アプリ内メッセージキャンペーン。ここで「campaign_name」は「In-app message name example」に等しい。](https://www.braze.com/docs/ja/ja/assets/img_archive/iosIAMeventTrigger.png?2f425e73fa63c23e0270be6007c72cbe) SDKが記録したカスタムイベントの記録にプッシュメッセージが使用されているため、Brazeはこのソリューションを有効にするために、ユーザーごとにプッシュトークンを保存する必要があります。iOSとAndroidの両方で、BrazeはユーザーがOSのプッシュプロンプトを受け取った時点からのトークンのみを保存します。これ以前では、ユーザーはプッシュを使用して到達できず、上記のソリューションも実行できません。 # iOS 用カスタムビューコントローラーのアプリ内メッセージ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/custom_view_controller/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # カスタムビューコントローラにアプリ内メッセージを表示する アプリ内メッセージは、カスタムビューコントローラー内に表示することもでき、これを Braze に渡します。Braze は、カスタマイズされたアプリ内メッセージの送受信をアニメーション化し、アプリ内メッセージの分析を行います。ビューコントローラーは次の要件を満たしている必要があります。 - `ABKInAppMessageViewController` のサブクラスまたはインスタンスでなければなりません。 - 返されるビューコントローラのビューは、`ABKInAppMessageView` のインスタンスまたはそのサブクラスでなければなりません。 次の UI デリゲートメソッドは、アプリ内メッセージが `ABKInAppMessageViewController` に提供されるたびに呼び出され、アプリがアプリ内メッセージの表示のためにカスタムビューコントローラーを Braze に渡せるようにします。 ```objc - (ABKInAppMessageViewController *)inAppMessageViewControllerWithInAppMessage:(ABKInAppMessage *)inAppMessage; ``` `````````swift func inAppMessageViewControllerWithInAppMessage(inAppMessage: ABKInAppMessage!) -> ABKInAppMessageViewController! ``` [アプリ内メッセージビューコントローラー](https://github.com/Appboy/appboy-ios-sdk/tree/master/AppboyUI/ABKInAppMessage/ViewControllers)はカスタマイズ可能です。サブクラスまたはカテゴリを使用して、アプリ内メッセージの表示や動作をカスタマイズできます。 ## メソッド宣言 詳細については、次のヘッダー ファイルを参照してください。 - [`ABKInAppMessage.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKInAppMessage.h) ## 実装サンプル アプリ内メッセージサンプルアプリの [`ViewController.m`](https://github.com/Appboy/appboy-ios-sdk/blob/master/Samples/InAppMessage/BrazeInAppMessageSample/BrazeInAppMessageSample/ViewController.m) および [`CustomInAppMessageViewController.m`](https://github.com/Appboy/appboy-ios-sdk/blob/master/Samples/InAppMessage/BrazeInAppMessageSample/BrazeInAppMessageSample/) を参照してください。 # iOS のアプリ内メッセージモーダルを閉じる Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/modal_dismissal/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 外側のタップでモーダルを閉じる {#dismiss-modal-on-outside-tap} デフォルト値は `NO` です。ユーザーがアプリ内メッセージの外側をタップしたときに、モーダルタイプのアプリ内メッセージが閉じられるかどうかを決定します。 外側タップによる閉じる操作を有効にするには、`Braze` という名前のディクショナリを `Info.plist` ファイルに追加します。次のコードスニペットに示すように、`Braze` ディクショナリ内にブール値サブエントリ `DismissModalOnOutsideTap` を追加し、値を `YES` に設定します。なお、Braze iOS SDK v4.0.2 より前のバージョンでは、`Braze` の代わりにディクショナリキー `Appboy` を使用する必要があります。 ``` Braze DismissModalOnOutsideTap YES ``` また、`appboyOptions` で `ABKEnableDismissModalOnOutsideTapKey` を `YES` に設定して、実行時に機能を有効にすることもできます。 | `DismissModalOnOutsideTap` | 説明 | |----------|-------------| | `YES` | モーダルアプリ内メッセージは、外側タップで閉じられます。 | | `NO` | デフォルトでは、モーダルアプリ内メッセージは外側タップでは閉じられません。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="外側のタップでモーダルを閉じる" } # iOS のアプリ内メッセージのキーと値のペア Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/customization/key_value_pairs/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # キーと値のペアのエクストラ `ABKInAppMessage` オブジェクトはキーと値のペアを `extras` として保持できます。これらは、キャンペーン作成時にダッシュボードで指定します。キーと値のペアを使用して、アプリ内メッセージとともにデータを送信し、アプリでさらに処理することができます。 # iOS 向けアプリ内メッセージ配信 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/in-app_message_delivery/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # アプリ内メッセージ配信 {#in-app-message-delivery} ## トリガーの種類 {#trigger-types} アプリ内メッセージ製品を使用すると、`Any Purchase`、`Specific Purchase`、`Session Start`、`Custom Event`、`Push Click` など、さまざまなイベントタイプの結果としてアプリ内メッセージの表示をトリガーできます。さらに、`Specific Purchase`と`Custom Event`トリガーには堅牢なプロパティフィルターが含まれています。 **Note:** トリガーされたアプリ内メッセージは、Braze SDKを通じて記録されたカスタムイベントでのみ機能します。アプリ内メッセージは、APIまたはAPIイベント(購入イベントなど)によってトリガーすることはできません。iOSを使用している場合は、[カスタムイベントの追跡](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=swift)に関する記事を参照して詳細を確認してください。 ## 配信セマンティクス {#delivery-semantics} ユーザーが対象になるすべてのアプリ内メッセージは、セッション開始時にユーザーのデバイスに配信されます。1つのイベントによって2つのアプリ内メッセージがトリガーされた場合、優先度の高いアプリ内メッセージが表示されます。SDKのセッション開始セマンティクスの詳細については、[セッションライフサイクル](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/analytics/tracking_sessions#session-lifecycle)に関する記事をお読みください。配信時に、SDKはアセットをプリフェッチしてトリガー時にすぐに利用できるようにし、表示遅延を最小限に抑えます。 トリガーイベントに複数の適格なアプリ内メッセージが関連付けられている場合、最も優先度の高いアプリ内メッセージのみが配信されます。 アセットがプリフェッチされていないため、配信時(セッション開始、プッシュクリック)にすぐに表示されるアプリ内メッセージには多少の遅延が発生する可能性があります。 ## トリガー間の最小時間間隔 {#minimum-time-interval-between-triggers} デフォルトでは、高品質のユーザーエクスペリエンスを促進するため、アプリ内メッセージのレートは30秒に1回に制限されています。 この値は、`startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions:` に渡される `appboyOptions` パラメーター内の `ABKMinimumTriggerTimeIntervalKey` を使用してオーバーライドできます。`ABKMinimumTriggerTimeIntervalKey` を、アプリ内メッセージ間の最小時間(秒)として使用する整数値に設定します。 ```objc // Sets the minimum trigger time interval to 5 seconds [Appboy startWithApiKey:@"YOUR-API-KEY" inApplication:application withLaunchOptions:options withAppboyOptions:@{ ABKMinimumTriggerTimeIntervalKey : @(5) }]; ``` ```swift Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:[ABKMinimumTriggerTimeIntervalKey : 5]) ``` ## 一致するトリガーが見つからない {#failing-to-find-a-matching-trigger} Brazeが特定のイベントに一致するトリガーを検出できない場合、[`ABKInAppMessageControllerDelegate`](https://appboy.github.io/appboy-ios-sdk/docs/protocol_a_b_k_in_app_message_controller_delegate-p.html)の[noMatchingTriggerForEvent:name:](https://appboy.github.io/appboy-ios-sdk/docs/protocol_a_b_k_in_app_message_controller_delegate-p.html#ab4d57b13c51545d487227945a37d4ab8) メソッドを呼び出します。このシナリオを処理するには、デリゲートプロトコルを採用するクラスにこのメソッドを実装してください。 ## ローカルのアプリ内メッセージ配信 {#local-in-app-message-delivery} ### アプリ内メッセージスタック {#the-in-app-message-stack} #### アプリ内メッセージの表示 {#showing-in-app-messages} ユーザーがアプリ内メッセージを受信する資格がある場合、`ABKInAppMessageController` にはアプリ内メッセージスタックから最新のアプリ内メッセージが提供されます。スタックはメモリに保存されたアプリ内メッセージのみを保持し、一時停止モードからのアプリ起動間にクリアされます。 **Important:** キーボードが画面に表示されているときは、レンダリングが未定義のため、アプリ内メッセージを表示しないでください。 #### アプリ内メッセージをスタックに追加する {#adding-in-app-messages-to-the-stack} ユーザーは、次の状況でアプリ内メッセージを受信できます。 - アプリ内メッセージトリガーイベントが発生した - セッション開始イベント - プッシュ通知からアプリを開いた トリガーされたアプリ内メッセージは、トリガーイベントが発生するとスタックに配置されます。複数のアプリ内メッセージがスタック内にあり、表示を待機している場合、Brazeは最後に受信したアプリ内メッセージを最初に表示します(後入れ先出し)。 #### アプリ内メッセージをスタックに返す {#returning-in-app-messages-to-the-stack} トリガーされたアプリ内メッセージは、次の状況でスタックに返されることがあります。 - アプリがバックグラウンドにあるときにアプリ内メッセージがトリガーされた。 - 別のアプリ内メッセージが現在表示されている。 - 非推奨の `beforeInAppMessageDisplayed:withKeyboardIsUp:` [UIデリゲートメソッド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/in-app_messaging/customization/setting_delegates#in-app-message-delegate)が実装されておらず、キーボードが現在表示されている。 - `beforeInAppMessageDisplayed:` [デリゲートメソッド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/in-app_messaging/customization/setting_delegates#core-in-app-message-delegate)または非推奨の `beforeInAppMessageDisplayed:withKeyboardIsUp:` [UIデリゲートメソッド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/in-app_messaging/customization/setting_delegates#in-app-message-delegate)が `ABKDisplayInAppMessageLater` を返した。 #### アプリ内メッセージの破棄 {#discarding-in-app-messages} トリガーされたアプリ内メッセージは、次の状況では破棄されます。 - `beforeInAppMessageDisplayed:` [デリゲートメソッド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/in-app_messaging/customization/setting_delegates#core-in-app-message-delegate)または非推奨の `beforeInAppMessageDisplayed:withKeyboardIsUp:` [UIデリゲートメソッド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/in-app_messaging/customization/setting_delegates#in-app-message-delegate)が `ABKDiscardInAppMessage` を返した。 - アプリ内メッセージのアセット(画像またはZIPファイル)のダウンロードに失敗した。 - アプリ内メッセージを表示する準備ができているが、タイムアウト時間が経過した。 - デバイスの向きが、トリガーされたアプリ内メッセージの向きと一致しない。 - アプリ内メッセージはフルアプリ内メッセージだが、画像がない。 - アプリ内メッセージは画像のみのモーダルアプリ内メッセージだが、画像がない。 #### アプリ内メッセージ表示を手動でキューに入れる {#manually-queue-in-app-message-display} アプリ内で別のタイミングでアプリ内メッセージを表示したい場合は、次のメソッドを呼び出してスタックの最上位のアプリ内メッセージを手動で表示できます。 ```objc [[Appboy sharedInstance].inAppMessageController displayNextInAppMessage]; ``` ```swift Appboy.sharedInstance()!.inAppMessageController.displayNextInAppMessage() ``` ### リアルタイムのアプリ内メッセージの作成と表示 {#real-time-in-app-message-creation-and-display} アプリ内メッセージはアプリ内でローカルに作成し、Braze経由で表示することもできます。これは、アプリ内でリアルタイムにトリガーしたいメッセージを表示する場合に特に便利です。Brazeは、ローカルで作成されたアプリ内メッセージの分析をサポートしていません。 ```objc ABKInAppMessageSlideup *customInAppMessage = [[ABKInAppMessageSlideup alloc] init]; customInAppMessage.message = @"YOUR_CUSTOM_SLIDEUP_MESSAGE"; customInAppMessage.duration = 2.5; customInAppMessage.extras = @{@"key" : @"value"}; [[Appboy sharedInstance].inAppMessageController addInAppMessage:customInAppMessage]; ``` ```swift let customInAppMessage = ABKInAppMessageSlideup.init() customInAppMessage.message = "YOUR_CUSTOM_SLIDEUP_MESSAGE" customInAppMessage.duration = 2.5 customInAppMessage.extras = ["key": "value"] Appboy.sharedInstance()!.inAppMessageController.add(customInAppMessage) ``` # カスタム App Store レビュープロンプト Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/custom_app_store_review_prompt/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # カスタム App Store レビュープロンプト {#custom-app-store-review-prompt} **Note:** このプロンプトを実装すると、Brazeはインプレッションの自動トラッキングを停止するため、独自の[分析](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/in-app_messaging/customization/handing_in_app_display#logging-impressions-and-clicks)を記録する必要があります。 アプリ内メッセージの一般的な用途として、ユーザーにApp Storeでのレビューを依頼するキャンペーンの作成があります。 まず、アプリで[アプリ内メッセージのデリゲート](#in-app-message-controller-delegate)を設定します。次に、以下のデリゲートメソッドを実装して、デフォルトのApp Storeレビューメッセージを無効にします。 ```objc - (ABKInAppMessageDisplayChoice)beforeInAppMessageDisplayed:(ABKInAppMessage *)inAppMessage { if (inAppMessage.extras != nil && inAppMessage.extras[@"Appstore Review"] != nil) { [[UIApplication sharedApplication] openURL:inAppMessage.uri options:@{} completionHandler:nil]; return ABKDiscardInAppMessage; } else { return ABKDisplayInAppMessageNow; } } ``` ```swift func before(inAppMessageDisplayed inAppMessage: ABKInAppMessage) -> ABKInAppMessageDisplayChoice { if inAppMessage.extras?["Appstore Review"] != nil && inAppMessage.uri != nil { UIApplication.shared.open(inAppMessage.uri!, options: [:], completionHandler: nil) return ABKInAppMessageDisplayChoice.discardInAppMessage } else { return ABKInAppMessageDisplayChoice.displayInAppMessageNow } } ``` ディープリンク処理コードで、以下のコードを追加して `{YOUR-APP-SCHEME}:appstore-review` ディープリンクを処理します。`SKStoreReviewController`を使用するには `StoreKit` をインポートする必要があることに注意してください。 ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *urlString = url.absoluteString.stringByRemovingPercentEncoding; if ([urlString isEqualToString:@"{YOUR-APP-SCHEME}:appstore-review"]) { [SKStoreReviewController requestReview]; return YES; } // Other deep link handling code… } ``` ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { let urlString = url.absoluteString.removingPercentEncoding if (urlString == "{YOUR-APP-SCHEME}:appstore-review") { SKStoreReviewController.requestReview() return true; } // Other deep link handling code… } ``` 次に、以下の内容でアプリ内メッセージングキャンペーンを作成します。 - キーと値のペア `"Appstore Review" : "true"` - ディープリンク `{YOUR-APP-SCHEME}:appstore-review` を使用して、クリック時の動作を「アプリにディープリンクする」に設定します。 **Tip:** Appleは、App Storeのレビュープロンプトをユーザーごとに年間最大3回に制限しているため、キャンペーンの[レート制限](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/frequency_capping)をユーザーごとに年間3回に設定する必要があります。

ユーザーはApp Storeのレビュープロンプトをオフにできます。そのため、カスタムレビュープロンプトでは、App Storeのネイティブレビュープロンプトが表示されることを約束したり、直接レビューを求めたりしないでください。 # iOS 用アプリ内メッセージ実装ガイド(オプション) Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/implementation_guide/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk).
**Important:** 基本的なアプリ内メッセージ開発者統合ガイドをお探しですか?[基本的なアプリ内メッセージ開発者統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/overview)をご覧ください。 # アプリ内メッセージング実装ガイド {#in-app-messaging-implementation-guide} > このオプションの高度な実装ガイドでは、アプリ内メッセージコードに関する考慮事項、当社チームが構築した3つのカスタムユースケース、および付随するコードスニペットについて説明します。[こちらから](https://github.com/braze-inc/braze-growth-shares-ios-demo-app) Braze Demo リポジトリにアクセスしてください!この実装ガイドは Swift の実装を中心としていますが、興味のある方のために Objective-C のスニペットも提供されています。HTML の実装をお探しですか?Braze の [HTML テンプレートリポジトリ](https://github.com/braze-inc/in-app-message-templates)をご確認ください! ## コードに関する考慮事項 {#code-considerations} 次のガイドでは、デフォルトのアプリ内メッセージに加えて使用する、オプションのカスタム開発者統合について説明します。各ユースケースにはカスタムビューコントローラーが含まれており、機能を拡張したり、アプリ内メッセージの外観をネイティブにカスタマイズしたりするためのサンプルが用意されています。 ### ABKInAppMessage サブクラス {#abkinappmessage-subclasses} 次のコードスニペットは Braze SDKの UI デリゲートメソッドで、アプリ内メッセージに入力するサブクラスビューを決定します。このガイドでは基本的な実装について説明し、フルサブクラス、スライドアップサブクラス、モーダルサブクラスを魅力的な方法で実装する方法を示します。カスタムビューコントローラーを設定する場合は、他のすべてのアプリ内メッセージサブクラスを設定する必要があることに注意してください。サブクラス化の背後にある概念をしっかりと理解したら、[ユースケース](#sample-use-cases)を確認してアプリ内メッセージングサブクラスの実装を開始してください。 **ABKInAppMessage サブクラス**
```swift extension AppboyManager: ABKInAppMessageUIDelegate { func inAppMessageViewControllerWith(_ inAppMessage: ABKInAppMessage) -> ABKInAppMessageViewController { switch inAppMessage { case is ABKInAppMessageSlideup: return slideupViewController(inAppMessage: inAppMessage) //Custom Method case is ABKInAppMessageModal: return modalViewController(inAppMessage: inAppMessage) //Custom Method case is ABKInAppMessageFull: return fullViewController(inAppMessage: inAppMessage) //Custom Method case is ABKInAppMessageHTML: return ABKInAppMessageHTMLViewController(inAppMessage: inAppMessage) default: return ABKInAppMessageViewController(inAppMessage: inAppMessage) } } } ``` **ABKInAppMessage サブクラス**
```objc - (ABKInAppMessageViewController *)inAppMessageViewControllerWithInAppMessage:(ABKInAppMessage *)inAppMessage { if ([inAppMessage isKindOfClass:[ABKInAppMessageSlideup class]]) { return [self slideupViewControllerWithInAppMessage:inAppMessage]; //Custom Method } else if ([inAppMessage isKindOfClass:[ABKInAppMessageModal class]]) { return [self modalViewControllerWithInAppMessage:inAppMessage]; //Custom Method } else if ([inAppMessage isKindOfClass:[ABKInAppMessageFull class]]) { return [self fullViewControllerWithInAppMessage:inAppMessage]; //Custom Method } else if ([inAppMessage isKindOfClass:[ABKInAppMessageHTML class]]) { return [[ABKInAppMessageHTMLViewController alloc] initWithInAppMessage:inAppMessage]; } else { return [[ABKInAppMessageViewController alloc] initWithInAppMessage:inAppMessage]; } } ``` ## ユースケース {#sample-use-cases} 以下の3つのユースケースを提供しています。それぞれのユースケースには、詳細な説明、関連するコードスニペット、およびアプリ内メッセージが Braze ダッシュボードでどのように表示され、どのように使用されるかが記載されています。 - [カスタムスライドアップアプリ内メッセージ](#custom-slide-up-in-app-message) - [カスタムモーダルアプリ内メッセージ](#custom-modal-in-app-message) - [カスタムフルアプリ内メッセージ](#custom-full-in-app-message) ### カスタムスライドアップアプリ内メッセージ {#custom-slide-up-in-app-message} ![2台の iPhone を並べて表示。最初の iPhone では、スライドアップメッセージが画面の下部に接触しています。2台目の iPhone では、スライドアップメッセージが画面の上方に表示され、アプリのナビゲーションボタンが見えるようになっています。](https://www.braze.com/docs/ja/ja/assets/img/iam_implementation/slideup.png?9e02cf3a30829eac685b141146429fdb){: style="float:right;max-width:45%;margin-left:15px;border:0;"} スライドアップのアプリ内メッセージを作成しているときに、デフォルトの方法ではメッセージの配置を変更できないことに気付くかもしれません。このような変更は、`ABKInAppMessageSlideupViewController` をサブクラス化し、独自のカスタム変数で `offset` 変数をオーバーライドすることによって可能になります。右の画像は、これを使用してスライドアップアプリ内メッセージを調整する方法の例を示しています。 開始するには、[`SlideFromBottomViewController`](https://github.com/braze-inc/braze-growth-shares-ios-demo-app/blob/master/Braze-Demo/ViewController/In-App-Messages/SlideFromBottomViewController.swift) にアクセスしてください。 #### デフォルト UI への動作の追加

{#adding-additional-behavior-to-our-default-ui} **`offset` 変数を更新**
`offset` 変数を更新し、必要に応じて独自のオフセットを設定します。 ```swift func setSlideConstraint() { offset = 0 } ``` ```swift override var offset: CGFloat { get { return super.offset } set { super.offset = newValue + adjustedOffset } } ``` **Version 3.34.0 or earlier** **`slideConstraint` 変数を更新**
`slideConstraint` パブリック変数はスーパークラス `ABKInAppMessageSlideupViewController` から取得されます。 ```swift func setSlideConstraint() { slideConstraint?.constant = bottomSpacing } ``` ```swift private var bottomSpacing: CGFloat { return AppboyManager.shared.activeApplicationViewController.topMostViewController().view.safeAreaInsets.bottom } ``` [`topMostViewController()`](https://github.com/braze-inc/braze-growth-shares-ios-demo-app/blob/master/Braze-Demo/Utils/UIViewController_Util.swift#L17) 関数については、Braze Demo リポジトリにアクセスしてください。 **`offset` 変数を更新**
`offset` 変数を更新し、必要に応じて独自のオフセットを設定します。 ```objc - (void)setOffset { self.offset = 0; } ``` ```objc - (CGFloat)offset { return [super offset]; } - (void)setOffset:(CGFloat)offset { [super setOffset:offset + [self adjustedOffset]]; } ``` **Version 3.34.0 or earlier** **`slideConstraint` 変数を更新**
`slideConstraint` パブリック変数はスーパークラス `ABKInAppMessageSlideupViewController` から取得されます。 ```objc - (void)self.setSlideConstraint:(NSLayoutConstraint *)slideConstraint { slideConstraint.constant = bottomSpacing; } ``` ```objc - (CGFloat)bottomSpacing { return [AppboyManager shared].activeApplicationViewController.topMostViewController.view.safeAreaInsets.bottom; } ``` **カスタム制約のオーバーライドと設定**
`beforeMoveInAppMessageViewOnScreen()` をオーバーライドし、必要に応じて独自のカスタム制約値を設定します。元の値はスーパークラスに設定されます。 ```swift override func beforeMoveInAppMessageViewOnScreen() { super.beforeMoveInAppMessageViewOnScreen() setOffset() } ``` **Version 3.34.0 or earlier** ```swift override func beforeMoveInAppMessageViewOnScreen() { setSlideConstraint() } ``` **カスタム制約のオーバーライドと設定**
`beforeMoveInAppMessageViewOnScreen()` をオーバーライドし、必要に応じて独自のカスタム制約値を設定します。元の値はスーパークラスに設定されます。 ```objc - (void)beforeMoveInAppMessageViewOnScreen { [super beforeMoveInAppMessageViewOnScreen]; [self setOffset]; } ``` **Version 3.34.0 or earlier** ```objc - (void)beforeMoveInAppMessageViewOnScreen { [self setSlideConstraint:self.slideConstraint]; } ``` **デバイスの向きの制約を調整**
サブクラスはレイアウト変更中に制約の同期を維持する責任を負うため、`viewWillTransition()` 内のそれぞれの値を調整します。 ### カスタムモーダルアプリ内メッセージ {#custom-modal-in-app-message} ![スポーツチームの一覧を循環させ、お気に入りのチームを選択できるモーダルアプリ内メッセージが表示された iPhone。このアプリ内メッセージの下部には、大きな青い送信ボタンがあります。](https://www.braze.com/docs/ja/ja/assets/img/iam_implementation/modal.png?519e4b01528bc44cbbe0e83274f32c41){: style="float:right;max-width:23%;margin-left:15px;border:0;"} `ABKInAppMessageModalViewController` をサブクラス化して、貴重なユーザー属性を収集する魅力的な方法を提供する `UIPickerView` を活用できます。カスタムモーダルアプリ内メッセージを使用すると、コネクテッドコンテンツまたは使用可能なリストを使用して、アイテムの動的なリストから属性を表示およびキャプチャできます。 サブクラス化されたアプリ内メッセージに独自のビューを挿入できます。この例では、`UIPickerView` を使用して `ABKModalInAppMessageViewController` の機能を拡張する方法を示しています。 開始するには、[ModalPickerViewController](https://github.com/braze-inc/braze-growth-shares-ios-demo-app/blob/master/Braze-Demo/ViewController/In-App-Messages/ModalPickerViewController/ModalPickerViewController.swift) にアクセスしてください。 #### ダッシュボード設定 {#dashboard-configuration} ダッシュボードでモーダルアプリ内メッセージを設定するには、コンマ区切り文字列としてフォーマットされた項目のリストを指定する必要があります。この例では、コネクテッドコンテンツを使用してチーム名の JSON リストを取得し、それに応じてフォーマットします。 ![アプリ内メッセージ作成画面には、アプリ内メッセージの外観のプレビューが表示されますが、代わりに Braze に指定したアイテムの一覧が表示されます。スマートフォンに送信されない限り、Braze UI にはカスタムアプリ内メッセージ UI が表示されないため、プレビューはメッセージの実際の表示を示すものではありません。送信前にテストすることをお勧めします。](https://www.braze.com/docs/ja/ja/assets/img/iam_implementation/dashboard1.png?7c867625250df852a14d3f201138e219) キーと値のペアに `attribute_key` を入力します。このキーは、ユーザーが選択した値とともに、カスタム属性としてユーザープロファイルに保存されます。カスタムビューロジックは、Braze に送信されたユーザー属性を処理する必要があります。 `ABKInAppMessage` オブジェクト内の `extras` ディクショナリを使用して、表示すべき正しいビューを示す `view_type` キー(存在する場合)をクエリできます。アプリ内メッセージはメッセージごとに設定されるため、カスタムとデフォルトのモーダルビューが調和して機能することに注意してください。 ![メッセージ作成画面で検出された2つのキーと値のペア。最初のキーと値のペアは「attribute_key」が「Favorite Team」に設定され、2番目は「view_type」が「picker」に設定されています。](https://www.braze.com/docs/ja/ja/assets/img/iam_implementation/dashboard2.png?f6f9998e902ef22d05a1c3571c0872f7){: style="max-width:65%;"} **UI 表示動作に `view_type` を使用**
`view_type` に対して `extras` ディクショナリを照会して、目的のサブクラス化されたビューコントローラーをロードします。 ```swift func modalViewController(inAppMessage: ABKInAppMessage) -> ABKInAppMessageModalViewController { switch inAppMessage.extras?[InAppMessageKey.viewType.rawValue] as? String { case InAppMessageViewType.picker.rawValue: return ModalPickerViewController(inAppMessage: inAppMessage) default: return ABKInAppMessageModalViewController(inAppMessage: inAppMessage) } } ``` **UI 表示動作に `view_type` を使用**
`view_type` に対して `extras` ディクショナリを照会して、目的のサブクラス化されたビューコントローラーをロードします。 ```objc - (ABKInAppMessageModalViewController *)modalViewControllerWithInAppMessage:(ABKInAppMessage *)inAppMessage { InAppMessageData *inAppMessageData = [[InAppMessageData alloc] init]; NSString *key = [inAppMessageData rawValueForInAppMessageKey:InAppMessageKeyViewType]; NSString *viewType = [inAppMessageData rawValueForInAppMessageViewType:InAppMessageViewTypePicker]; if ([inAppMessage.extras objectForKey:key] && [inAppMessage.extras[key] isEqualToString:viewType]) { return [[ModalViewController alloc] initWithInAppMessage:inAppMessage]; } else { return [[ABKInAppMessageModalViewController alloc] initWithInAppMessage:inAppMessage]; } } ``` **オーバーライドしてカスタムビューを提供する**
`loadView()` をオーバーライドし、必要に応じて独自のカスタムビューを設定します。 ```swift override var nibname: String{ return "ModalPickerViewController" } override func loadView() { Bundle.main.loadNibNamed(nibName, owner: self, options: nil) } ``` **オーバーライドしてカスタムビューを提供する**
`loadView()` をオーバーライドし、必要に応じて独自のカスタムビューを設定します。 ```objc - (void)loadView { NSString *nibName = @"ModalPickerViewController"; [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil]; } ``` **動的リストのフォーマット変数**
`UIPickerView` コンポーネントをリロードする前に、`inAppMessage` メッセージ変数は*文字列*として出力されます。正しく表示するには、このメッセージを項目の配列としてフォーマットする必要があります。例として、これは [`components(separatedBy: ", ")`](https://developer.apple.com/documentation/foundation/nsstring/1413214-components) を使用して実現できます。 ```swift override func viewDidLoad() { super.viewDidLoad() items = inAppMessage.message.separatedByCommaSpaceValue pickerView.reloadAllComponents() } ``` **PickerView のフォーマット変数**
`UIPickerView` コンポーネントをリロードする前に、`inAppMessage` メッセージ変数は*文字列*として出力されます。正しく表示するには、このメッセージを項目の配列としてフォーマットする必要があります。たとえば、[`componentsSeparatedByString`](https://developer.apple.com/documentation/foundation/nsstring/1413214-componentsseparatedbystring?language=objc) を使用してこれを実現できます。 ```objc - (void)viewDidLoad { [super viewDidLoad]; self.items = [[NSArray alloc] initWithArray:[self.inAppMessage.message componentsSeparatedByString:@", "]]; [self.pickerView reloadAllComponents]; } ``` **カスタム属性を割り当てる**
サブクラスを使用して、ユーザーが送信を押した後に、属性とそれに対応する選択した値を Braze に渡します。 ```swift @IBAction func primaryButtonTapped(_ sender: Any) { guard let item = selectedItem, !item.isEmpty, let attributeKey = inAppMessage.extras?[InAppMessageKey.attributeKey.rawValue] as? String else { return } AppboyManager.shared.setCustomAttributeWithKey(attributeKey, andStringValue: item) } ``` **カスタム属性を割り当てる**
サブクラスを使用して、ユーザーが送信を押した後に、属性とそれに対応する選択した値を Braze に渡します。 ```objc - (IBAction)primaryButtonTapped:(id)sender { InAppMessageData *inAppMessageData = [[InAppMessageData alloc] init]; NSString *key = [inAppMessageData rawValueForInAppMessageKey:InAppMessageKeyAttributeKey]; if (self.selectedItem.length > 0 && [self.inAppMessage.extras objectForKey:key]) { [[AppboyManager shared] setCustomAttributeWithKey:self.inAppMessage.extras[key] andStringValue:self.selectedItem]; } } ``` **Tip:** カスタムモーダルアプリ内メッセージを活用して、FaceTime で動画を共有することに興味がありますか?SharePlay アプリ内メッセージの[実装ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/implementation_guide/shareplay)をご覧ください。 ### カスタムフルアプリ内メッセージ {#custom-full-in-app-message} ![各オプションの横にトグルがある設定オプションの一覧を表示するアプリ内メッセージ。メッセージの下部には、大きな青い送信ボタンがあります。](https://www.braze.com/docs/ja/ja/assets/img/iam_implementation/fullscreen.png?efd1d7a82e515ea563a083b96ff24d4a){: style="float:right;max-width:23%;margin-left:15px;border:0;"} カスタムのフルアプリ内メッセージを使用して、インタラクティブで使いやすいプロンプトを作成し、貴重な顧客データを収集します。右の例は、通知設定を備えたインタラクティブなプッシュプライマーとして再構成されたカスタムフルアプリ内メッセージの実装を示しています。 開始するには、[`FullListViewController`](https://github.com/braze-inc/braze-growth-shares-ios-demo-app/blob/master/Braze-Demo/ViewController/In-App-Messages/FullListViewController/FullListViewController.swift) にアクセスしてください。 #### ダッシュボード設定 ダッシュボードでカスタムフルアプリ内メッセージを設定するには、コンマ区切り文字列としてフォーマットされたタグのリストを指定する必要があります。 キーと値のペアに `attribute_key` を入力します。このキーは、ユーザーが選択した値とともに、カスタム属性としてユーザープロファイルに保存されます。カスタムビューロジックは、Braze に送信されたユーザー属性を処理する必要があります。 ![メッセージ作成画面で検出された3つのキーと値のペア。最初のキーと値のペアは「attribute_key」が「Push Tags」に設定され、2番目は「subtitle_text」が「Enabling notifications will also...」に設定され、3番目は「view_type」が「table_list」に設定されています。](https://www.braze.com/docs/ja/ja/assets/img/iam_implementation/dashboard3.png?87fc332d5e758f31bf85971ba1f9345f){: style="max-width:65%;"} #### アプリ内メッセージタッチのインターセプト {#intercepting-in-app-message-touches} ![設定とトグルの行を表示する Apple デバイス。カスタムビューはボタンを処理し、ボタンコントロールの外側でのタッチはアプリ内メッセージによって処理され、メッセージが閉じられます。](https://www.braze.com/docs/ja/ja/assets/img/iam_implementation_guide.png?962cfedd9859a5291b9f693d6e402213){: style="float:right;max-width:30%;margin-left:10px;border:0"} カスタムフルアプリ内メッセージボタンを正しく機能させるには、アプリ内メッセージのタッチをインターセプトすることが重要です。デフォルトでは、`ABKInAppMessageImmersive` はメッセージにタップジェスチャ認識機能を追加するので、ユーザーはボタンなしでメッセージを閉じることができます。`UISwitch` またはボタンを `UITableViewCell` ビュー階層に追加すると、タッチはカスタムビューによって処理されるようになります。iOS 6 以降、ジェスチャー認識機能を使用する場合はボタンやその他のコントロールが優先され、カスタムのフルアプリ内メッセージが正常に機能するようになりました。 # SharePlay アプリ内メッセージ実装ガイド Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/implementation_guide/shareplay/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # SharePlay アプリ内メッセージ実装ガイド {#shareplay-in-app-message-implementation-guide} > SharePlayは、iOS 15 FaceTimeユーザーがデバイス間でメディア体験を共有し、リアルタイムでオーディオと動画を同期することを可能にする新たにリリースされた機能です。SharePlayは、ユーザーが友人や家族と一緒にコンテンツを体験できる優れた方法であり、Brazeの顧客に動画コンテンツを利用する新たな手段を提供し、アプリケーションを新しいユーザーに紹介する機会を提供します。 ![SharePlay](https://www.braze.com/docs/ja/ja/assets/img/shareplay/shareplay6.png?0ffbb203ed26aa0f503eb8f83645216a){: style="border:0;margin-top:10px;"} ## 概要 {#overview} iOS 15アップデートの一部としてAppleがリリースした新しい`GroupActivities`フレームワークを使用すると、Brazeアプリ内メッセージを利用してSharePlayをアプリケーションに統合することで、FaceTimeを活用できるようになります。 ![SharePlay](https://www.braze.com/docs/ja/ja/assets/img/shareplay/shareplay3.png?4b2fdfd489a89e3c3778a1cd3b2e4ab0){: style="float:right;max-width:30%;margin-left:15px;margin-top:10px;"} ユーザーがFaceTime通話でSharePlay動画を開始すると、全員の画面の上部に「Open」ボタンが表示されます。開くと、オーディオと動画がすべての互換性のあるデバイス間で同期され、ユーザーはリアルタイムで動画を一緒に視聴できるようになります。アプリをダウンロードしていない人は、App Storeにリダイレクトされます。 **同期メディア再生**
同期メディア再生では、1人がSharePlay動画を一時停止すると、すべてのデバイスで一時停止されます。

![SharePlay](https://www.braze.com/docs/ja/ja/assets/img/shareplay/shareplay7.png?bcd102ca4418004d04bec6dbcec4fc66){: style="border:0"} ## 統合 {#integration} この統合で使用されるアプリ内メッセージは、サブクラス化されたモーダルアプリ内メッセージビューコントローラーです。セットアップのガイドは、iOSアプリ内メッセージの高度なユースケース[実装ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/implementation_guide)に記載されています。統合する前に、Xcodeプロジェクトに`GroupActivities`エンタイトルメントを追加してください。 **Important:** 統合を完了するには、このガイドと並行して[Apple SharePlayドキュメント](https://developer.apple.com/documentation/avfoundation/media_playback_and_selection/supporting_coordinated_media_playback)を開くことをお勧めします。 ### ステップ1:XIBのオーバーライドと読み込み {#step-1-overriding-and-loading-xib} ```swift override var nibName: String { return "ModalVideoViewController" } /// Overriding loadView() from ABKInAppMessageModalViewController to provide our own view for the in-app message override func loadView() { Bundle.main.loadNibNamed(nibName, owner: self, options: nil) } ``` ### ステップ2:アプリ内メッセージ用にAVPlayerを設定する {#step-2-configure-avplayer-for-in-app-messages} アプリ内メッセージでは、開発者の軽微な作業だけで動画をネイティブに再生できます。こうすることで、SharePlayなど、すべての`AVPlayerVideoController`機能にアクセスできるようになります。この例で使用されるアプリ内メッセージは、ネイティブ動画プレーヤーを埋め込むためのカスタムビューを持つサブクラス化された`ABKInAppMessageModalViewController`です。 ```swift func configureVideoPlayer() { guard let urlString = inAppMessage.extras?["video_url"] as? String, let url = URL(string: urlString) else { return } let videoTitle = inAppMessage.extras?["video_title"] as? String mediaItem = MediaItem(title: videoTitle ?? "Video Content", url: url) let asset = AVAsset(url: url) let playerItem = AVPlayerItem(asset: asset) player.replaceCurrentItem(with: playerItem) playerViewController.player = player addChild(playerViewController) videoPlayerContainer.addSubview(playerViewController.view) playerViewController.didMove(toParent: self) } ``` #### ダッシュボードの設定 {#dashboard-configuration} **キーと値のペア**:動画ファイルはアプリ内メッセージのキーと値のペアで設定する必要があり、メディア項目自体に添付することはできません。コンテンツを表示する前に、ガードレールとして`beforeInAppMessageDisplayed`にURLの有効性チェックを追加することもできます。 **トリガー**:アプリ内メッセージは、再適格性が有効になっているすべてのユーザーに対して有効にする必要があります。これは、メッセージを起動するデフォルトのトリガーと、SharePlayから開始されたときにメッセージを起動するもう1つのトリガーの2つのトリガーを設定することで実行できます。iOS 15を使用していないユーザーは、メッセージをローカルでのみ表示できます。 **Important:** セッション開始時にトリガーされる他のアプリ内メッセージが互いに競合する可能性があることに注意してください。 ### ステップ3:グループ視聴アクティビティを作成する {#step-3-create-group-watching-activity} `GroupActivity`プロトコルに準拠したオブジェクトを作成します。このオブジェクトは、SharePlayライフサイクル全体で共有される`GroupSession`のメタデータになります。 ```swift struct MediaItem: Hashable, Codable { let title: String let url: URL } @available(iOS 15, *) struct MediaItemActivity: GroupActivity { static let activityIdentifier = "com.book-demo.GroupWatching" let mediaItem: MediaItem var metadata: GroupActivityMetadata { var metadata = GroupActivityMetadata() metadata.type = .watchTogether metadata.title = mediaItem.title metadata.fallbackURL = mediaItem.url return metadata } } ``` #### 再生の準備をする {#prepare-to-play} メディア項目の再生を準備するとき、各グループアクティビティの`prepareForActivation()`には以下の3つの状態があります。 - `.activationDisabled` - 個別視聴 - `.activationPreferred` - 一緒に視聴 - `.cancelled` - 無視して適切に処理する 状態が`activationPreferred`として返されたら、残りのグループアクティビティのライフサイクルをアクティブにする合図です。 ![SharePlay](https://www.braze.com/docs/ja/ja/assets/img/shareplay/shareplay.png?dcfb560fc9e9e3fc546253ab35042273){: style="border:0;"} ### ステップ4:SharePlay APIからアプリ内メッセージを起動する {#step-4-launch-in-app-message-from-shareplay-api} `GroupActivities` APIは動画が存在するかどうかを判別します。存在する場合は、カスタムイベントをトリガーして、SharePlay対応のアプリ内メッセージを起動する必要があります。`CoordinationManager`は、ユーザーが通話から離れた場合や通話に参加した場合など、SharePlayの状態変更を管理します。 ```swift private var subscriptions = Set() private var selectedMediaItem: MediaItem? { didSet { // Ensure the UI selection always represents the currently playing media. guard let _ = selectedMediaItem else { return } if !BrazeManager.shared.inAppMessageCurrentlyVisible { BrazeManager.shared.logCustomEvent("SharePlay Event") } } } private func launchVideoPlayerIfNecessary() { CoordinationManager.shared.$enqueuedMediaItem .receive(on: DispatchQueue.main) .compactMap { $0 } .assign(to: \.selectedMediaItem, on: self) .store(in: &subscriptions) } ``` ### ステップ5:アプリ内メッセージの終了時にグループセッションを退出する {#step-5-leaving-a-group-session-on-in-app-message-dismissal} アプリ内メッセージが閉じられたときが、SharePlayセッションを退出し、セッションオブジェクトを破棄する適切なタイミングです。 ```swift override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) groupSession?.leave() CoordinationManager.shared.leave() } class CoordinationManager() { ... // Published values that the player, and other UI items, observe. @Published var enqueuedMediaItem: MediaItem? @Published var groupSession: GroupSession? // Clear activity when the user leaves func leave() { groupSession = nil enqueuedMediaItem = nil } ... } ``` ### SharePlayボタンの表示を設定する {#configure-shareplay-button-visibility} SharePlayインジケーターを動的に非表示または表示することがベストプラクティスです。`isEligibleForGroupSession`変数を使用して、ユーザーが現在FaceTime通話中かどうかを確認します。FaceTime通話中の場合は、チャット内の互換性のあるデバイス間で動画を共有するためのボタンが表示されるようにします。ユーザーが初めてSharePlayを開始すると、元のデバイスにオプションを選択するためのプロンプトが表示されます。その後、共有ユーザーのデバイスに、コンテンツに参加するためのプロンプトが表示されます。 ```swift private var isEligibleForSharePlay: Bool = false { didSet { sharePlayButton.isHidden = !isEligibleForSharePlay } } override func viewDidLoad() { super.viewDidLoad() // SharePlay button eligibility groupStateObserver.$isEligibleForGroupSession .receive(on: DispatchQueue.main) .assign(to: \.isEligibleForSharePlay, on: self) .store(in: &subscriptions) } ``` # iOS 向けアプリ内メッセージングのトラブルシューティング Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/in-app_messaging/troubleshooting/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # アプリ内メッセージのトラブルシューティング {#troubleshoot-in-app-messages} ## インプレッション {#impressions} ### インプレッション分析やクリック分析が記録されていない {#impression-or-click-analytics-arent-being-logged} メッセージ表示またはクリックアクションを手動で処理するようにアプリ内メッセージデリゲートを設定している場合は、アプリ内メッセージのクリック数とインプレッション数を手動で記録する必要があります。 #### インプレッションが予想より低い {#impressions-are-lower-than-expected} トリガーはセッション開始時にデバイスへの同期に時間がかかるため、ユーザーがセッション開始直後にイベントや購入を記録すると競合が発生する可能性があります。考えられる回避策の1つは、キャンペーンをセッション開始時にトリガーするよう変更し、目的のイベントまたは購入でセグメント化することです。なお、イベント発生後の次回セッション開始時にアプリ内メッセージが配信されることに注意してください。 ## 予期したアプリ内メッセージが表示されなかった {#expected-in-app-message-did-not-display} ほとんどのアプリ内メッセージの問題は、配信と表示の2つの主要なカテゴリに分けることができます。予期したアプリ内メッセージがデバイスで表示されない原因をトラブルシューティングするには、まず[アプリ内メッセージがデバイスに配信された](#troubleshooting-in-app-message-delivery)ことを確認してから、[メッセージ表示のトラブルシューティング](#troubleshooting-in-app-message-display)を行う必要があります。 ### アプリ内メッセージ配信 {#troubleshooting-in-app-message-delivery} SDKはセッション開始時にBrazeサーバーからアプリ内メッセージをリクエストします。アプリ内メッセージがデバイスに配信されているかどうかを確認するには、アプリ内メッセージがSDKによってリクエストされ、Brazeサーバーによって返されていることを確認する必要があります。 #### メッセージがリクエストされ、返されたかどうかを確認する {#check-if-messages-are-requested-and-returned} 1. ダッシュボードで自分自身を[テストユーザー](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/developer_console/internal_groups_tab/#adding-test-users)として追加します。 2. ユーザーを対象としたアプリ内メッセージキャンペーンを設定します。 3. アプリケーションで新しいセッションが発生することを確認します。 4. [イベントユーザーログ](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/developer_console/event_user_log_tab/#event-user-log-tab)を使用して、セッション開始時にデバイスがアプリ内メッセージをリクエストしていることを確認します。テストユーザーのセッション開始イベントに関連付けられたSDKリクエストを見つけます。 - トリガーされたアプリ内メッセージをリクエストするためのアプリであれば、**Response Data**の**Requested Responses**フィールドに `trigger` が表示されます。 - アプリが元のアプリ内メッセージをリクエストするためのものだった場合、**Response Data**の**Requested Responses**フィールドに `in_app` が表示されます。 5. [イベントユーザーログ](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/developer_console/event_user_log_tab/#event-user-log-tab)を使って、レスポンスデータに正しいアプリ内メッセージが返されているか確認します。
![アプリ内メッセージリクエストのイベントユーザーログエントリ](https://www.braze.com/docs/ja/ja/assets/img_archive/event_user_log_iams.png?fd8f7c0f05a549b6a529b92744f37f96) #### リクエストされていないメッセージのトラブルシューティング {#troubleshoot-messages-not-being-requested} アプリ内メッセージがリクエストされていない場合、アプリ内メッセージはセッション開始時にリフレッシュされるため、アプリがセッションを正しくトラッキングしていない可能性があります。また、アプリのセッションタイムアウトセマンティクスに基づいて、アプリが実際にセッションを開始していることを確認してください。 ![イベントユーザーログに記録されたSDKリクエストは、セッション開始イベントが成功したことを示しています。](https://www.braze.com/docs/ja/ja/assets/img_archive/event_user_log_session_start.png?972201c9c20f018bc85d97167638f04e) ### メッセージが返されない問題のトラブルシューティング {#troubleshoot-messages-not-being-returned} アプリ内メッセージが返されない場合、キャンペーンターゲティングの問題が発生している可能性があります。 - セグメントにユーザーが含まれていない。 - ユーザーの[**エンゲージメント**](https://www.braze.com/docs/ja/ja/user_guide/audience/manage_audience/user_profiles/#engagement-tab)タブを確認し、**セグメント**欄に正しいセグメントが表示されているか確認します。 - ユーザーが以前にアプリ内メッセージを受け取ったことがあり、再度受け取る資格がなかった。 - **キャンペーン Composer**の**配信**ステップにある[キャンペーンの再適格性設定](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/campaigns/building_campaigns/delivery_types/reeligibility/)を確認し、再適格性設定がテスト設定と一致していることを確認します。 - ユーザーがキャンペーンのフリークエンシーキャップに達した。 - キャンペーンの[フリークエンシーキャップ設定](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/campaigns/building_campaigns/rate-limiting/#frequency-capping)を確認し、テスト設定と一致していることを確認します。 - キャンペーンにコントロールグループが存在した場合、ユーザーがコントロールグループに分類された可能性があります。 - キャンペーンバリアントが**コントロール**に設定されている受信キャンペーンバリアントフィルターでセグメントを作成し、ユーザーがそのセグメントに分類されたかどうかを確認することで、これが発生したかどうかを確認できます。 - 統合テスト目的でキャンペーンを作成する場合は、コントロールグループの追加をオプトアウトしてください。 ### アプリ内メッセージ表示 {#troubleshooting-in-app-message-display} アプリがアプリ内メッセージのリクエストと受信に成功しているのに表示されない場合は、デバイス側のロジックによって表示が妨げられている可能性があります。 - トリガーされたアプリ内メッセージは、[トリガー間の最小時間間隔](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/in-app_messaging/in-app_message_delivery#minimum-time-interval-between-triggers)(デフォルトは30秒)に基づいてレート制限されます。 - アプリ内メッセージ処理をカスタマイズするようにデリゲートを設定している場合は、デリゲートがアプリ内メッセージ表示に影響していないことを確認してください。 - 画像のダウンロードに失敗すると、画像付きのアプリ内メッセージが表示されなくなります。`SDWebImage` フレームワークが正しく統合されていない場合、画像のダウンロードは常に失敗します。画像のダウンロードに失敗していないか、デバイスのログを確認してください。 - デバイスの向きがアプリ内メッセージで指定された向きと一致しなかった場合、アプリ内メッセージは表示されません。デバイスの向きが正しいことを確認してください。 # iOS 用コンテンツカードビューコントローラーの統合 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/integration/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # コンテンツカード統合 {#content-card-integration} ## コンテンツカードデータモデル {#content-cards-data-model} コンテンツカードデータモデルはiOS SDKで使用できます。 ### データを取得する {#getting-the-data} コンテンツカードデータモデルにアクセスするには、コンテンツカード更新イベントを購読してください。 ```objc // Subscribe to Content Cards updates // Note: you should remove the observer where appropriate [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentCardsUpdated:) name:ABKContentCardsProcessedNotification object:nil]; ``` `````````objc // Called when Content Cards are refreshed (via `requestContentCardsRefresh`) - (void)contentCardsUpdated:(NSNotification *)notification { BOOL updateIsSuccessful = [notification.userInfo[ABKContentCardsProcessedIsSuccessfulKey] boolValue]; if (updateIsSuccessful) { // get the cards using [[Appboy sharedInstance].contentCardsController getContentCards]; } } ``` `````````swift // Subscribe to content card updates // Note: you should remove the observer where appropriate NotificationCenter.default.addObserver(self, selector: #selector(contentCardsUpdated), name:NSNotification.Name.ABKContentCardsProcessed, object: nil) ``` `````````swift // Called when the Content Cards are refreshed (via `requestContentCardsRefresh`) @objc private func contentCardsUpdated(_ notification: Notification) { if let updateIsSuccessful = notification.userInfo?[ABKContentCardsProcessedIsSuccessfulKey] as? Bool { if (updateIsSuccessful) { // get the cards using Appboy.sharedInstance()?.contentCardsController.contentCards } } } ``` Brazeから送信された後にカードデータを変更したい場合は、カードデータのディープコピーをローカルに保存し、データを更新してから自分で表示することをおすすめします。カードには[`ABKContentCardsController`](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_content_cards_controller.html)経由でアクセスできます。 ## コンテンツカードモデル {#content-card-model} Brazeには、バナー、キャプション付き画像、クラシックの3種類のContent Cardsが用意されています。各タイプはベース`ABKContentCard`クラスから共通のプロパティを継承し、以下の追加プロパティを持ちます。 ### ベースコンテンツカードモデルプロパティ - ABKContentCard {#base-content-card-model-properties-abkcontentcard} | プロパティ | 説明 | |---|---| | `idString` | (読み取り専用) Brazeで設定されたカードのID。 | | `viewed` | このプロパティは、ユーザーがカードを閲覧したかどうかを反映します。| | `created` | (読み取り専用) このプロパティは、Brazeからのカードの作成時刻のUNIXタイムスタンプです。 | | `expiresAt` | (読み取り専用) このプロパティは、カードの有効期限のUNIXタイムスタンプです。| | `dismissible` | このプロパティは、ユーザーがカードを非表示にできるかどうかを反映します。| | `pinned` | このプロパティは、カードがダッシュボードで「ピン留め」されているかどうかを反映します。| | `dismissed` | このプロパティは、ユーザーがカードを非表示にしたかどうかを反映します。| | `url` | カードをクリックした後に開かれるURL。HTTP(S) URLでもプロトコルURLでもかまいません。| | `openURLInWebView` | このプロパティは、URLをアプリ内で開くか、外部Webブラウザーで開くかを決定します。| | `extras`| `NSString`値のオプションの`NSDictionary`。| {: .reset-td-br-1 .reset-td-br-2 aria-label="Base Content Card model properties - ABKContentCard" } ### バナーコンテンツカードのプロパティ - ABKBannerContentCard {#banner-content-card-properties-abkbannercontentcard} | プロパティ | 説明 | |---|---| | `image` | このプロパティはカードの画像のURLです。| | `imageAspectRatio` | このプロパティはカードの画像の縦横比であり、画像の読み込みが完了する前のヒントとして機能します。ただし、場合によってはプロパティが提供されないことがあります。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="Banner Content Card properties - ABKBannerContentCard" } ### キャプション付き画像コンテンツカードのプロパティ - ABKCaptionedImageCard {#captioned-image-content-card-properties-abkcaptionedimagecard} | プロパティ | 説明 | |---|---| | `image` | このプロパティはカードの画像のURLです。| | `imageAspectRatio` | このプロパティはカードの画像の縦横比です。| | `title` | カードのタイトルテキスト。| | `cardDescription` | カードの本文テキスト。| | `domain` | @"blog.braze.com" のようなプロパティURLのリンクテキスト。カードのUIに表示して、カードをクリックしたときのアクション/方向を示すことができます。| {: .reset-td-br-1 .reset-td-br-2 aria-label="Captioned image Content Card properties - ABKCaptionedImageCard" } ### クラシックコンテンツカードのプロパティ - ABKClassicContentCard {#classic-content-card-properties-abkclassiccontentcard} | プロパティ | 説明 | |---|---| | `image` | (オプション) このプロパティはカードの画像のURLです。| | `title` | カードのタイトルテキスト。 | | `cardDescription` | カードの本文テキスト。 | | `domain` | @"blog.braze.com" のようなプロパティURLのリンクテキスト。カードのUIに表示して、カードをクリックしたときのアクションと方向を示すことができます。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="Classic Content Card properties - ABKClassicContentCard" } ## カードメソッド {#card-methods} | メソッド | 説明 | |---|---| | `logContentCardImpression` | 特定のカードのインプレッションを手動でBrazeに記録します。 | | `logContentCardClicked` | 特定のカードのクリックを手動でBrazeに記録します。SDKは、カードに有効な値の`url`プロパティがある場合にのみカードクリックを記録します。 | | `logContentCardDismissed` | 特定のカードの非表示を手動でBrazeに記録します。カードの`dismissed`プロパティがまだ`true`に設定されていない場合にのみ、SDKはカードの非表示を記録します。 | | `isControlCard` | カードがA/Bテストのコントロールカードであるかどうかを判断します。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="Card methods" } 詳細については、[クラスリファレンスドキュメント](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_content_card.html)を参照してください。 ## コンテンツカードビューコントローラーの統合 {#content-cards-view-controller-integration} コンテンツカードは、ナビゲーションまたはモーダルという2つのビューコントローラーコンテキストで統合できます。 ### ナビゲーションコンテキスト {#navigation-context} ナビゲーションコントローラーに`ABKContentCardsTableViewController`インスタンスをプッシュする例: `````````objc ABKContentCardsTableViewController *contentCards = [[ABKContentCardsTableViewController alloc] init]; contentCards.title = @"Content Cards Title"; contentCards.disableUnreadIndicator = YES; [self.navigationController pushViewController:contentCards animated:YES]; ``` `````````swift let contentCards = ABKContentCardsTableViewController() contentCards.title = "Content Cards Title" contentCards.disableUnreadIndicator = true navigationController?.pushViewController(contentCards, animated: true) ``` **Note:** ナビゲーションバーのタイトルをカスタマイズするには、`ABKContentCardsTableViewController`インスタンスの`navigationItem`のタイトルプロパティを設定します。 ### モーダルコンテキスト {#modal-context} このモーダルは、ビューコントローラーをモーダルビューに表示するために使用され、上部にナビゲーションバー、バーの横に**Done**ボタンが表示されます。 `````````objc ABKContentCardsViewController *contentCards = [[ABKContentCardsViewController alloc] init]; contentCards.contentCardsViewController.title = @"Content Cards Title"; contentCards.contentCardsViewController.disableUnreadIndicator = YES; [self.navigationController presentViewController:contentCards animated:YES completion:nil]; ``` `````````swift let contentCards = ABKContentCardsViewController() contentCards.contentCardsViewController.title = "Content Cards Title" contentCards.contentCardsViewController.disableUnreadIndicator = true self.present(contentCards, animated: true, completion: nil) ``` ビューコントローラーの例については、[Content Cardsサンプルアプリ](https://github.com/Appboy/appboy-ios-sdk/tree/master/Samples/ContentCards/BrazeContentCardsSampleApp)をご覧ください。 **Note:** ヘッダーをカスタマイズするには、親`ABKContentCardsViewController`インスタンスに埋め込まれている`ABKContentCardsTableViewController`インスタンスに属する`navigationItem`のタイトルプロパティを設定します。 # iOS コンテンツカードのカスタマイズ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/customization/index.md

# iOS 向けカスタムコンテンツカードスタイル設定 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/customization/custom_styling/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # カスタムスタイル設定 ## デフォルト画像を上書きする **Important:** iOS アプリ内メッセージまたはコンテンツカード内の画像を表示するために Braze UI を使用しようとしている場合は、`SDWebImage` の統合が必要です。 Braze では、クライアントが既存のデフォルト画像を独自のカスタム画像に置き換えることができます。そのためには、カスタム画像で新しい `png` ファイルを作成し、アプリの画像バンドルに追加します。次に、ファイルの名前を画像の名前に変更して、ライブラリー内の既定の画像をオーバーライドします。また、さまざまなスマートフォンのサイズに対応できるよう、`@2x` と `@3x` のバージョンの画像を必ずアップロードしてください。コンテンツカードでオーバーライド可能な画像は以下の通りです。 - プレースホルダ画像: `appboy_cc_noimage_lrg` - 固定されたアイコンの画像: `appboy_cc_icon_pinned` コンテンツカードには、ダッシュボードに入力できるコンテンツ (メッセージテキスト、画像 URL、リンク、すべてのキーと値のペアなど) の最大サイズが 2 KB という制限があるため、送信する前にサイズを確認してください。このサイズを超えるとカードを送信できなくなります。 **Important:** デフォルト画像の上書きは、現在のところ当社の.NET MAUI iOS統合ではサポートされていない。 ## ダークモードを無効にする ユーザーデバイスでダークモードが有効になっている場合に、コンテンツカードの UI でダークテーマスタイルが採用されないようにするには、`ABKContentCardsTableViewController.enableDarkTheme` プロパティを設定します。`enableDarkTheme` プロパティには、`ABKContentCardsTableViewController` インスタンス上で直接アクセスするか、独自の UI に最適な `ABKContentCardsViewController.contentCardsViewController` プロパティ経由でアクセスできます。 ```objc // Accessing enableDarkTheme via ABKContentCardsViewController.contentCardsViewController. - (IBAction)presentModalContentCards:(id)sender { ABKContentCardsViewController *contentCardsVC = [ABKContentCardsViewController new]; contentCardsVC.contentCardsViewController.enableDarkTheme = NO; ... [self.navigationController presentViewController:contentCardsVC animated:YES completion:nil]; } // Accessing enableDarkTheme directly. - (IBAction)presentNavigationContentCards:(id)sender { ABKContentCardsTableViewController *contentCardsTableVC = [[ABKContentCardsTableViewController alloc] init]; contentCardsTableVC.enableDarkTheme = NO; ... [self.navigationController pushViewController:contentCardsTableVC animated:YES]; } ``` `````````swift // Accessing enableDarkTheme via ABKContentCardsViewController.contentCardsViewController. @IBAction func presentModalContentCards(_ sender: Any) { let contentCardsVC = ABKContentCardsViewController() contentCardsVC.contentCardsViewController.enableDarkTheme = false ... self.navigationController?.present(contentCardsVC, animated: true, completion: nil) } // Accessing enableDarkTheme directly. @IBAction func presentNavigationContentCards(_ sender: Any) { let contentCardsTableVC = ABKContentCardsTableViewController() contentCardsTableVC.enableDarkTheme = false ... self.navigationController?.present(contentCardsTableVC, animated: true, completion: nil) } ``` # iOSのContent Cardsフィードをカスタマイズする Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/customization/customizing_feed/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # Content Cardsのフィードをカスタマイズする {#customize-the-content-cards-feed} `ABKContentCardsTableViewController` を拡張してすべてのUI要素とContent Cardsの動作をカスタマイズすることで、独自のContent Cardsインターフェイスを作成できます。Content Cardsセルをサブクラス化してからプログラムで使用することも、新しいクラスを登録するカスタムストーリーボードを導入することによって使用することもできます。完全な例については、Content Cardsの[サンプルアプリ](https://github.com/Appboy/appboy-ios-sdk/tree/master/Samples/ContentCards/BrazeContentCardsSampleApp)をご確認ください。 また、サブクラス化戦略を使用すべきか、完全にカスタムのビューコントローラーを使用して[データ更新を配信登録](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/integration)すべきかを検討することも重要です。たとえば、`ABKContentCardsTableViewController` をサブクラス化する場合は、[`populateContentCards` メソッド](#overriding-populated-content-cards)を使用してカードのフィルター処理と順序付けを行うことができます(推奨)。ただし、ビューコントローラーを完全にカスタマイズすると、カルーセルでの表示やインタラクティブ要素の追加など、カードの動作をより詳細に制御できるようになりますが、順序付けとフィルター処理のロジックを実装するためにオブザーバーに頼らなければなりません。また、インプレッション、却下イベント、クリックを適切に記録するには、それぞれの分析メソッドを実装する必要もあります。 ## UIをカスタマイズする {#customizing-ui} 次のコードスニペットは、SDKが提供するメソッドを使用して、UIのニーズに合わせてContent Cardsのスタイル設定と変更を行う方法を示しています。これらのメソッドによって、カスタムフォント、カスタマイズされたカラーコンポーネント、カスタマイズされたテキストなど、Content Cards UIのあらゆる側面をカスタマイズすることができます。 Content Cards UIをカスタマイズする方法は2通りあります。 - ダイナミックメソッド: カードごとにカードUIを更新する - スタティックメソッド: すべてのカードでUIを更新する ### ダイナミックUI {#dynamic-ui} Content Cardsの `applyCard` メソッドはカードオブジェクトを参照し、UIの更新に使用されるキーと値のペアを渡すことができます。 ```objc - (void)applyCard:(ABKCaptionedImageContentCard *)captionedImageCard { [super applyCard:captionedImageCard]; if ([card.extras objectForKey:ContentCardKeyBackgroundColorValue]) { NSString *backgroundColor = [card.extras objectForKey:ContentCardKeyBackgroundColor]; if ([backgroundColor colorValue]) { self.rootView.backgroundColor = [backgroundColor colorValue]; } else { self.rootView.backgroundColor = [UIColor lightGray]; } } else { self.rootView.backgroundColor = [UIColor lightGray]; } } ``` ```swift override func apply(_ captionedImageCard: ABKCaptionedImageContentCard!) { super.apply(captionedImageCard) if let backgroundColor = card.extras?[ContentCardKey.backgroundColor.rawValue] as? String, let backgroundColorValue = backgroundColor.colorValue() { rootView.backgroundColor = backgroundColorValue } else { rootView.backgroundColor = .lightGray } } ``` ### スタティックUI {#static-ui} `setUpUI` メソッドは、すべてのカードで静的なContent Cardsコンポーネントに値を割り当てることができます。 ```objc #import "CustomClassicContentCardCell.h" @implementation CustomClassicContentCardCell - (void)setUpUI { [super setUpUI]; self.rootView.backgroundColor = [UIColor lightGrayColor]; self.rootView.layer.borderColor = [UIColor purpleColor].CGColor; self.unviewedLineView.backgroundColor = [UIColor redColor]; self.titleLabel.font = [UIFont italicSystemFontOfSize:20]; } ``` ```swift override func setUpUI() { super.setUpUI() rootView.backgroundColor = .lightGray rootView.layer.borderColor = UIColor.purple.cgColor unviewedLineViewColor = .red titleLabel.font = .italicSystemFont(ofSize: 20) } ``` ## カスタムインターフェイスを提供する {#providing-custom-interfaces} カスタムインターフェイスを提供するには、必要なカードタイプごとにカスタムクラスを登録します。 ![バナーContent Card。バナーのContent Cardには、バナーの右側に画像が表示され、「Thanks for downloading Braze Demo!」というテキストが添えられている。](https://www.braze.com/docs/ja/ja/assets/img/interface1.png?c56c164e8146b5c7652ed27f45facea8){: style="max-width:35%;margin-left:15px;"} ![キャプション付き画像Content Card。キャプション付きのContent Cardには、Brazeの画像が表示され、その下部に「Thanks for downloading Braze Demo!」というキャプションが重ねて表示されている。](https://www.braze.com/docs/ja/ja/assets/img/interface2.png?8ee545c80d29aae4ab7413df02ad504a){: style="max-width:25%;margin-left:15px;"} ![クラシックContent Card。クラシックなContent Cardは、カードの中央に画像を表示し、その下に「Thanks for downloading Braze Demo」という文字が表示される。](https://www.braze.com/docs/ja/ja/assets/img/interface3.png?00b31c463a9f17c93e748f489d2c7c87){: style="max-width:18%;margin-left:15px;"} Brazeには、3つのContent Cardsテンプレート(バナー、キャプション付き画像、クラシック)が用意されています。独自のカスタムインターフェイスを提供する場合は、次のコードスニペットを参照してください。 ```objc - (void)registerTableViewCellClasses { [super registerTableViewCellClasses]; // Replace the default class registrations with custom classes for these two types of cards [self.tableView registerClass:[CustomCaptionedImageContentCardCell class] forCellReuseIdentifier:@"ABKCaptionedImageContentCardCell"]; [self.tableView registerClass:[CustomClassicContentCardCell class] forCellReuseIdentifier:@"ABKClassicCardCell"]; } ``` ```swift override func registerTableViewCellClasses() { super.registerTableViewCellClasses() // Replace the default class registrations with custom classes tableView.register(CustomCaptionedImageContentCardCell.self, forCellReuseIdentifier: "ABKCaptionedImageContentCardCell") tableView.register(CustomBannerContentCardCell.self, forCellReuseIdentifier: "ABKBannerContentCardCell") tableView.register(CustomClassicImageContentCardCell.self, forCellReuseIdentifier: "ABKClassicImageCardCell") tableView.register(CustomClassicContentCardCell.self, forCellReuseIdentifier: "ABKClassicCardCell") } ``` ## 値が挿入されたContent Cardsをオーバーライドする {#overriding-populated-content-cards} Content Cardsをプログラムで変更するには、`populateContentCards` メソッドを使用します。 ```objc - (void)populateContentCards { NSMutableArray *cards = [NSMutableArray arrayWithArray:[Appboy.sharedInstance.contentCardsController getContentCards]]; for (ABKContentCard *card in cards) { // Replaces the card description for all Classic Content Cards if ([card isKindOfClass:[ABKClassicContentCard class]]) { ((ABKClassicContentCard *)card).cardDescription = @"Custom Feed Override title [classic cards only]!"; } } super.cards = cards; } ``` ```swift override func populateContentCards() { guard let cards = Appboy.sharedInstance()?.contentCardsController.contentCards else { return } for card in cards { // Replaces the card description for all Classic Content Cards if let classicCard = card as? ABKClassicContentCard { classicCard.cardDescription = "Custom Feed Override title [classic cards only]!" } } super.cards = (cards as NSArray).mutableCopy() as? NSMutableArray } ``` # iOSではコンテンツカードクリックを手動で処理する Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/customization/handling_clicks_manually/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # クリックを手動で処理する コンテンツカードのクリックを手動で処理するには、[`ABKContentCardsTableViewControllerDelegate`](https://appboy.github.io/appboy-ios-sdk/docs/protocol_a_b_k_content_cards_table_view_controller_delegate-p.html) プロトコルを実装し、`ABKContentCardsTableViewController` の `delegate` プロパティとしてデリゲートオブジェクトを設定します。例については、[コンテンツカードのサンプルアプリ](https://github.com/Appboy/appboy-ios-sdk/tree/master/Samples/ContentCards/BrazeContentCardsSampleApp)を参照してください。 ```objc contentCardsTableViewController.delegate = delegate; // Methods to implement in delegate - (BOOL)contentCardTableViewController:(ABKContentCardsTableViewController *)viewController shouldHandleCardClick:(NSURL *)url { if ([[url.host lowercaseString] isEqualToString:@"my-domain.com"]) { // Custom handle link here NSLog(@"Manually handling Content Card click with URL %@", url.absoluteString); return NO; } // Let the Braze SDK handle the click action return YES; } - (void)contentCardTableViewController:(ABKContentCardsTableViewController *)viewController didHandleCardClick:(NSURL *)url { NSLog(@"Braze SDK handled Content Card click with URL %@", url.absoluteString); } ``` `````````swift contentCardsTableViewController.delegate = delegate // Methods to implement in delegate func contentCardTableViewController(_ viewController: ABKContentCardsTableViewController!, shouldHandleCardClick url: URL!) -> Bool { if (url.host?.lowercased() == "my-domain.com") { // Custom handle link here NSLog("Manually handling Content Card click with URL %@", url.absoluteString) return false } // Let the Braze SDK handle the click action return true } func contentCardTableViewController(_ viewController: ABKContentCardsTableViewController!, didHandleCardClick url: URL!) { NSLog("Braze SDK handled Content Card click with URL %@", url.absoluteString) } ``` **Important:** `ABKContentCardsTableViewController` で `handleCardClick:` メソッドをオーバーライドすると、これらのデリゲートメソッドが呼び出されない場合があります。 # iOS 用コンテンツカード既読 / 未読インジケーター Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/customization/read_unread_indicators/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 既読 / 未読インジケーター ## 未閲覧インジケーターを無効にする ![2つのコンテンツカードが並んで表示されています。左側のカードの下部に青い線が表示されており、まだ閲覧されていないことを示しています。右側のカードには青い線がなく、すでに閲覧済みであることを示しています。](https://www.braze.com/docs/ja/ja/assets/img/braze-content-cards-seen-unseen-behavior.png?00ecd6c2252753cde9662110012ab680){: style="max-width:80%"} カードが閲覧されたかどうかを示すカード下部の青い線を無効にするには、`ABKContentCardsTableViewController` の `disableUnviewedIndicator` プロパティを `YES` に設定します。 ## 未閲覧インジケーターをカスタマイズする 未閲覧インジケーターには、`ABKBaseContentCardCell` クラスの `unviewedLineView` プロパティを使用してアクセスできます。`UITableViewCell` の実装を使用する場合は、セルが描画される前にプロパティにアクセスする必要があります。 たとえば、未閲覧インジケーターの色を赤に設定するには、次のようにします。 ```objc ((ABKBaseContentCardCell *)cell).unviewedLineView.backgroundColor = [UIColor redColor]; ``` `````````swift (card as? ABKBaseContentCardCell).unviewedLineView.backgroundColor = UIColor.red ``` # iOS 向けコンテンツカードバッジ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/customization/badges/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # バッジ ## 未読コンテンツカードの数をリクエストする ユーザーの未読コンテンツカードの数を表示するには、カード数をリクエストし、それをバッジで表示することをお勧めします。バッジは、コンテンツカードに新着コンテンツがあることをユーザーに知らせる優れた方法です。コンテンツカードにバッジを追加する必要がある場合、Braze SDK には以下のクエリを実行するメソッドが用意されています。 - 現在のユーザーの未閲覧コンテンツカードの数 - 現在のユーザーの閲覧可能なコンテンツカードの総数 [`ABKContentCardsController`](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_content_cards_controller.html) の次のメソッド宣言はこれについて詳しく説明したものです。 ```objc - (NSInteger)unviewedContentCardCount; /* This method returns the number of currently active Content Cards that have not been viewed. A "view" happens when a card becomes visible in the Content Cards view. This differentiates between cards that are off-screen in the scrolling view and those which are on-screen; when a card scrolls onto the screen, it's counted as viewed. Cards are counted as viewed only once -- if a card scrolls off the screen and back on, it's not re-counted. Cards are counted only once, even if they appear in multiple Content Cards views or across multiple devices. */ - (NSInteger)contentCardCount; /* This method returns the total number of currently active Content Cards. Cards are counted only once even if they appear in multiple Content Cards views. */ ``` ## アプリのバッジカウントに未閲覧コンテンツカードの数を表示する バッジは、アプリのプッシュ通知リマインダーとして機能するだけでなく、ユーザーのコンテンツカードフィード内の未閲覧項目を示すために利用することもできます。未閲覧コンテンツカード数の最新情報に基づいてバッジカウントを更新すると、ユーザーをアプリに引き戻し、セッション数を増やすのに役立ちます。 このメソッドは、アプリが閉じられ、ユーザーのセッションが終了した後にバッジカウントを記録します。 `````````objc (void)applicationDidEnterBackground:(UIApplication *)application ``` このメソッド内で、次のコードを実装します。これにより、ユーザーが特定のセッション中にカードを閲覧している間にバッジカウントがアクティブに更新されます。 `````````objc [UIApplication sharedApplication].applicationIconBadgeNumber = [[Appboy sharedInstance].contentCardsController unviewedContentCardCount]; ``` `````````swift func applicationDidEnterBackground(_ application: UIApplication) ``` このメソッド内で、次のコードを実装します。これにより、ユーザーが特定のセッション中にカードを閲覧している間にバッジカウントがアクティブに更新されます。 `````````swift UIApplication.shared.applicationIconBadgeNumber = Appboy.sharedInstance()?.contentCardsController.unviewedContentCardCount() ?? 0 ``` 詳細については、`Appboy.h` の[ヘッダーファイル](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/Appboy.h)を参照してください。 # iOS 向けコンテンツカードカルーセルビュー Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/customization/use_cases/carousel_view/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # ユースケース: カルーセルビュー {#use-case-carousel-view} ![記事内でContent Cardsがカルーセル表示されるニュースアプリのサンプル。](https://www.braze.com/docs/ja/ja/assets/img_archive/cc_politer_carousel.png?69a1741df6c7abe2ac58322d309fe6ad){: style="max-width:35%;float:right;margin-left:15px;border:none;"} このセクションでは、ユーザーが水平方向にスワイプして追加の注目カードを表示できるマルチカードカルーセルフィードの実装方法を説明します。カルーセルビューを統合するには、完全にカスタマイズされたContent Cardsの実装を使用する必要があります。これは[クロール、ウォーク、ランアプローチ](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/content_cards/customize#customization-approaches)の「ラン」フェーズに該当します。 このアプローチでは、Brazeのビューとデフォルトロジックを使用せず、代わりにBrazeモデルからのデータが取り込まれた独自のビューを使用して、完全にカスタマイズされた方法でContent Cardsを表示します。 開発労力のレベルという点では、基本的な実装とカルーセル実装の主な違いは次のとおりです。 - 独自のビューを構築する - Content Cardsの分析を記録する - カルーセルにどのカードを何枚表示するかを指示する追加のクライアント側ロジックを導入する ## 実装 {#implementation} ### ステップ1: カスタムビューコントローラーを作成する {#step-1-create-a-custom-view-controller} Content Cardsのカルーセルを作成するには、独自のカスタムビューコントローラー(`UICollectionViewController` など)を作成して、[データ更新を配信登録](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/legacy_sdks/ios/content_cards/integration#getting-the-data)します。デフォルトの `ABKContentCardTableViewController` はデフォルトのContent Cardsタイプしか扱えないため、拡張したりサブクラス化したりすることはできません。 ### ステップ2: 分析を実装する {#step-2-implement-analytics} 完全にカスタマイズされたビューコントローラーを作成する場合、Content Cardsのインプレッション数、クリック数、却下数は自動的に記録されません。インプレッション数、却下イベント、クリック数がBrazeダッシュボードの分析に適切に記録されるようにするには、それぞれの分析メソッドを実装する必要があります。 分析メソッドについては、[カードメソッド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/legacy_sdks/ios/content_cards/integration#card-methods)を参照してください。 **Note:** 同じページには、汎用Content Cardsモデルクラスから継承されたさまざまなプロパティの詳細も記載されています。この情報は、ビューの実装時に役立つ可能性があります。 ### ステップ3: Content Cardsオブザーバーを作成する {#step-3-create-a-content-card-observer} Content Cardsの到着を処理する[Content Cardsオブザーバー](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/content_cards/multiple_feeds#step-2-set-up-a-content-card-listener)を作成し、一度に特定の数のカードをカルーセルに表示する条件付きロジックを実装します。デフォルトでは、Content Cardsは作成日順(新しい順)にソートされ、対象となるすべてのカードがユーザーに表示されます。 ただし、追加の表示ロジックを適用して、さまざまな方法でソートすることもできます。たとえば、配列から最初の5つのContent Cardsオブジェクトを選択したり、キーと値のペア(データモデルの `extras` プロパティ)を導入して条件付きロジックを構築したりできます。 セカンダリContent Cardsフィードとしてカルーセルを実装する場合は、[複数のContent Cardsフィードを使用する](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/multiple_feeds)を参照して、キーと値のペアに基づいてカードが正しいフィードにソートされるようにしてください。 **Important:** マーケターがBrazeダッシュボードに入力するキーと値のペアは、開発者がアプリのロジックに組み込むキーと値のペアと正確に一致しなければならないため、マーケティングチームと開発チームが、どのキーと値のペアを使用するか(たとえば `feed_type = brand_homepage`)について確実に調整することが重要です。 Content Cardsクラス、メソッド、属性に関するiOS固有の開発者向けドキュメントについては、iOS [`ABKContentCard` クラスリファレンス](https://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_content_card.html)を参照してください。 ## 考慮事項 {#considerations} - 完全にカスタマイズされたビューを使用すると、`ABKContentCardsController` で使用されるメソッドを拡張したりサブクラス化したりすることはできなくなります。その代わりに、データモデルのメソッドとプロパティを自分で統合する必要があります。 - カルーセルビューのロジックと実装は、BrazeのContent Cardsのデフォルトタイプではないため、ユースケースを実現するためのロジックは開発チームが提供し、サポートする必要があります。 - カルーセルに一度に特定の数のカードを表示するには、クライアント側ロジックを実装する必要があります。 # iOS向けコンテンツカードフィードを更新する Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/refreshing_the_feed/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # フィードを更新する ## コンテンツカードの更新 `Appboy` インターフェースの `requestContentCardsRefresh:` メソッドを使用して、ユーザーのコンテンツカードを更新するように Braze に手動でリクエストできます。 ```objc [[Appboy sharedInstance] requestContentCardsRefresh]; ``` `````````swift Appboy.sharedInstance()?.requestContentCardsRefresh() ``` 詳細については、`Appboy.h` の[ヘッダーファイル](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/Appboy.h)を参照してください。 # iOS向けに複数のコンテンツカードフィードを使用する Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/multiple_feeds/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 複数のコンテンツカードフィードを使用する コンテンツカードは、アプリ上で特定のカードだけを表示するようにフィルタリングすることができ、異なるユースケース (トランザクション用フィードとマーケティング用フィードを使用する場合のように) に対して複数のコンテンツカードフィードを持つことが可能となります。 以下のドキュメントは、特定の統合に合わせて変更可能な実装例を示しています。 ## ステップ1:カードにキーと値のペアを設定する コンテンツカードキャンペーンを作成する際、各カードにキーと値のペアのデータを設定できます。フィルタリングロジックは、このキーと値のペアデータを使ってカードを分類します。 この例では、どのコンテンツカードフィードにカードを表示するかを指定する `feed_type` キーでキーと値のペアを設定します。この値は、`Transactional`、`Marketing` などのように、カスタムフィードの値になります。 ## ステップ2:コンテンツカードのリスナーを設定する 次のコードスニペットを使って、コンテンツカードの更新をリッスンするオブザーバーを追加します。 ```objc [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentCardsUpdatedNotificationReceived:) name:ABKContentCardsProcessedNotification object:nil]; ``` `````````swift NotificationCenter.default.addObserver(self, selector: #selector(contentCardsUpdated), name:NSNotification.Name.ABKContentCardsProcessed, object: nil) ``` オブザーバーからの更新に応答し、返されたカードをタイプ別にフィルターするために、以下のメソッドを追加します。 最初のメソッド `contentCardsUpdatedNotificationReceived:` は、オブザーバーからの更新を処理します。2番目のメソッド `getCardsForFeedType:` を希望するフィードタイプ (この場合、`Transactional`) で呼び出します。 `````````objc - (void)contentCardsUpdatedNotificationReceived:(NSNotification *)notification { BOOL updateIsSuccessful = [notification.userInfo[ABKContentCardsProcessedIsSuccessfulKey] boolValue]; if (updateIsSuccessful) { // Get an array containing only cards that have the "Transactional" feed type set in their extras. NSArray *filteredArray = [self getCardsForFeedType:@"Transactional"]; NSLog(@"Got filtered array of length: %lu", [filteredArray count]); // Pass filteredArray to your UI layer for display. } } - (NSArray *)getCardsForFeedType:(NSString *)type { NSArray *cards = [Appboy.sharedInstance.contentCardsController getContentCards]; NSArray *filteredArray = [cards filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(ABKContentCard * card, NSDictionary *bindings) { NSDictionary *extras = [card extras]; if (extras != nil && [extras objectForKey:@"feed_type"] != nil && [[extras objectForKey:@"feed_type"] isEqualToString:type]) { NSLog(@"Got card: %@ ", card.idString); return YES; } return NO; }]]; return filteredArray; } ``` `````````swift @objc private func contentCardsUpdatedNotificationReceived(notification: NSNotification) { guard let updateSuccessful = notification.userInfo?[ABKContentCardsProcessedIsSuccessfulKey] as? Bool else { return } if updateSuccessful { // Get an array containing only cards that have the "Transactional" feed type set in their extras. let filteredArray = getCards(forFeedType: "Transactional") NSLog("Got filtered array of length: %@",filteredArray?.count ?? 0) // Pass filteredArray to your UI layer for display. } } func getCards(forFeedType type: String) -> [ABKContentCard]? { guard let allCards = Appboy.sharedInstance()?.contentCardsController.contentCards as? [ABKContentCard] else { return nil } // return filtered cards return allCards.filter { if $0.extras?["feed_type"] as? String == type { NSLog("%@","Got card: \($0.idString)") return true } else { return false } } } ``` # iOS 用コンテンツカード実装ガイド(オプション) Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/implementation_guide/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk).
**Important:** 基本的なコンテンツカード開発者統合ガイドをお探しですか?[基本的なコンテンツカード開発者統合ガイド](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/content_cards/integration)をご覧ください。 # コンテンツカード実装ガイド {#content-card-implementation-guide} > このオプションの高度な実装ガイドでは、コンテンツカードのコードに関する考慮事項、当社チームが構築した3つのカスタムユースケース、付随するコードスニペット、およびインプレッション、クリック、却下のロギングに関するガイダンスについて説明します。[こちらから Braze Demo リポジトリ](https://github.com/braze-inc/braze-growth-shares-ios-demo-app)にアクセスしてください!この実装ガイドは Swift の実装を中心としていますが、興味のある方のために Objective-C のスニペットも提供されています。 ## コードに関する考慮事項 {#code-considerations} ### カスタムオブジェクトとしてのContent Cards {#content-cards-as-custom-objects} ブースターを追加するロケット船のように、独自のカスタムオブジェクトを拡張してContent Cardsとして機能させることができます。このような限定された API サーフェスは、異なるデータバックエンドとの互換性を保つ柔軟性を提供します。これは、`ContentCardable` プロトコルに準拠し、(次のコードスニペットに示すように)イニシャライザを実装することで実行できます。また、`ContentCardData` 構造体を使用することで、`ABKContentCard` データにアクセスできます。`ABKContentCard` ペイロードは、すべてプロトコルに付属のイニシャライザを使用して `Dictionary` 型から `ContentCardData` 構造体とカスタムオブジェクト自体を初期化するために使用されます。 イニシャライザには `ContentCardClassType` enum も含まれます。この enum は、初期化するオブジェクトを決定するために使用されます。Braze ダッシュボード内のキーと値のペアを使用して、初期化するオブジェクトを決定するために使用する明示的な `class_type` キーを設定できます。Content Cardsのこれらのキーと値のペアは、`ABKContentCard` の `extras` 変数に格納されます。イニシャライザのもう1つのコアコンポーネントは、`metaData` ディクショナリパラメータです。`metaData` には解析された `ABKContentCard` から一連のキーと値までのすべてが含まれます。関連するカードが解析され、カスタムオブジェクトに変換された後、アプリは JSON またはその他のソースからインスタンス化されたかのように、それらのカードで作業を開始する準備ができています。 これらのコードに関する考慮事項をしっかりと理解したら、[ユースケース](#sample-use-cases)をチェックして、カスタムオブジェクトの実装を開始してください。 **ContentCardable プロトコル**
`ABKContentCard` データと `ContentCardClassType` enumを表す `ContentCardData` オブジェクトです。`ABKContentCard` メタデータを使用してカスタムオブジェクトをインスタンス化するために使用されるイニシャライザです。 ```swift protocol ContentCardable { var contentCardData: ContentCardData? { get } init?(metaData: [ContentCardKey: Any], classType contentCardClassType: ContentCardClassType) } extension ContentCardable { var isContentCard: Bool { return contentCardData != nil } func logContentCardClicked() { BrazeManager.shared.logContentCardClicked(idString: contentCardData?.contentCardId) } func logContentCardDismissed() { BrazeManager.shared.logContentCardDismissed(idString: contentCardData?.contentCardId) } func logContentCardImpression() { BrazeManager.shared.logContentCardImpression(idString: contentCardData?.contentCardId) } } ``` **コンテンツカードデータ構造体**
`ContentCardData` は、`ABKContentCard` の解析された値を表します。 ```swift struct ContentCardData: Hashable { let contentCardId: String let contentCardClassType: ContentCardClassType let createdAt: Double let isDismissable: Bool ... // other Content Card properties such as expiresAt, pinned, etc. } extension ContentCardData: Equatable { static func ==(lhs: ContentCardData, rhs: ContentCardData) -> Bool { return lhs.contentCardId == rhs.contentCardId } } ``` **ContentCardable プロトコル**
`ABKContentCard` データを `ContentCardClassType` enumと共に表す `ContentCardData` オブジェクトです。`ABKContentCard` メタデータを使用してカスタムオブジェクトをインスタンス化するために使用されるイニシャライザです。 ```objc @protocol ContentCardable @property (nonatomic, strong) ContentCardData *contentCardData; - (instancetype __nullable)initWithMetaData:(NSDictionary *)metaData classType:(enum ContentCardClassType)classType; - (BOOL)isContentCard; - (void)logContentCardImpression; - (void)logContentCardClicked; - (void)logContentCardDismissed; @end ``` **コンテンツカードデータ構造体**
`ContentCardData` は、`ABKContentCard` の解析された値を表します。 ```objc @interface ContentCardData : NSObject + (ContentCardClassType)contentCardClassTypeForString:(NSString *)rawValue; - (instancetype)initWithIdString:(NSString *)idString classType:(ContentCardClassType)classType createdAt:(double)createdAt isDismissible:(BOOL)isDismissible; @property (nonatomic, readonly) NSString *contentCardId; @property (nonatomic) ContentCardClassType classType; @property (nonatomic, readonly) double *createdAt; @property (nonatomic, readonly) BOOL isDismissible; ... // other Content Card properties such as expiresAt, pinned, etc. @end ``` **カスタムオブジェクトイニシャライザ**
`ABKContentCard` からのメタデータは、オブジェクトの変数を設定するために使用されます。Braze ダッシュボードで設定されたキーと値のペアは、「extras」ディクショナリに格納されます。 ```swift extension CustomObject: ContentCardable { init?(metaData: [ContentCardKey: Any], classType contentCardClassType: ContentCardClassType) { guard let idString = metaData[.idString] as? String, let createdAt = metaData[.created] as? Double, let isDismissable = metaData[.dismissable] as? Bool, let extras = metaData[.extras] as? [AnyHashable: Any], else { return nil } let contentCardData = ContentCardData(contentCardId: idString, contentCardClassType: contentCardClassType, createdAt: createdAt, isDismissable: isDismissable) let customObjectProperty = extras["YOUR-CUSTOM-OBJECT-PROPERTY"] as? String self.init(contentCardData: contentCardData, property: customObjectProperty) } } ``` **タイプの識別**
`ContentCardClassType` enumは、Braze ダッシュボードの `class_type` 値を表します。この値は、Content Cardsを異なる場所に表示するためのフィルター識別子としても使用されます。 ```swift enum ContentCardClassType: Hashable { case yourValue case yourOtherValue ... case none init(rawType: String?) { switch rawType?.lowercased() { case "your_value": // these values much match the value set in the Braze dashboard self = .yourValue case "your_other_value": // these values much match the value set in the Braze dashboard self = .yourOtherValue ... default: self = .none } } } ``` **カスタムオブジェクトイニシャライザ**
`ABKContentCard` からのメタデータは、オブジェクトの変数を設定するために使用されます。Braze ダッシュボードで設定されたキーと値のペアは、「extras」ディクショナリに格納されます。 ```objc - (id _Nullable)initWithMetaData:(nonnull NSDictionary *)metaData classType:(enum ContentCardClassType)classType { self = [super init]; if (self) { if ([metaData objectForKey:ContentCardKeyIdString] && [metaData objectForKey:ContentCardKeyCreated] && [metaData objectForKey:ContentCardKeyDismissible] && [metaData objectForKey:ContentCardKeyExtras]) { NSDictionary *extras = metaData[ContentCardKeyExtras]; NSString *idString = metaData[ContentCardKeyIdString]; double createdAt = [metaData[ContentCardKeyCreated] doubleValue]; BOOL isDismissible = metaData[ContentCardKeyDismissible]; if ([extras objectForKey: @"YOUR-CUSTOM-PROPERTY") _customObjectProperty = extras[@"YOUR-CUSTOM-OBJECT-PROPERTY"]; self.contentCardData = [[ContentCardData alloc] initWithIdString:idString classType:classType createdAt:createdAt isDismissible:isDismissible]; return self; } } return nil; } ``` **タイプの識別**
`ContentCardClassType` enumは、Braze ダッシュボードの `class_type` 値を表します。この値は、Content Cardsを異なる場所に表示するためのフィルター識別子としても使用されます。 ```objc typedef NS_ENUM(NSInteger, ContentCardClassType) { ContentCardClassTypeNone = 0, ContentCardClassTypeYourValue, ContentCardClassTypeYourOtherValue, ... }; + (NSArray *)contentCardClassTypeArray { return @[ @"", @"your_value", @"your_other_value" ]; } + (ContentCardClassType)contentCardClassTypeForString:(NSString*)rawValue { if ([[self contentCardClassTypeArray] indexOfObject:rawValue] == NSNotFound) { return ContentCardClassTypeNone; } else { NSInteger value = [[self contentCardClassTypeArray] indexOfObject:rawValue]; return (ContentCardClassType) value; } } ``` **Content Cardsのリクエスト**
オブザーバがまだメモリ内に保持されている限り、Braze SDKからの通知コールバックが期待できます。 ```swift func loadContentCards() { BrazeManager.shared.addObserverForContentCards(observer: self, selector: #selector(contentCardsUpdated)) BrazeManager.shared.requestContentCardsRefresh() } ``` **Content Cards SDKコールバックの処理**
通知コールバックをヘルパーファイルに転送して、カスタムオブジェクトのペイロードデータを解析します。 ```swift @objc func contentCardsUpdated(_ notification: Notification) { guard let contentCards = BrazeManager.shared.handleContentCardsUpdated(notification, for: [.yourValue]) as? [CustomObject],!contentCards.isEmpty else { return } // do something with your array of custom objects } ``` **Content Cardsの操作**
`class_type` はフィルターとして渡され、一致する `class_type` を持つContent Cardsのみを返します。 ```swift func handleContentCardsUpdated(_ notification: Notification, for classTypes: [ContentCardClassType]) -> [ContentCardable] { guard let updateIsSuccessful = notification.userInfo?[ABKContentCardsProcessedIsSuccessfulKey] as? Bool, updateIsSuccessful, let cards = contentCards else { return [] } return convertContentCards(cards, for: classTypes) } ``` **Content Cardsのリクエスト**
オブザーバがまだメモリ内に保持されている限り、Braze SDKからの通知コールバックが期待できます。 ```objc - (void)loadContentCards { [[BrazeManager shared] addObserverForContentCards:self selector:@selector(contentCardsUpdated:)]; [[BrazeManager shared] requestContentCardsRefresh]; } ``` **Content Cards SDKコールバックの処理**
通知コールバックをヘルパーファイルに転送して、カスタムオブジェクトのペイロードデータを解析します。 ```objc - (void)contentCardsUpdated:(NSNotification *)notification { NSArray *classTypes = @[@(ContentCardClassTypeYourValue)]; NSArray *contentCards = [[BrazeManager shared] handleContentCardsUpdated:notification forClassTypes:classTypes]; // do something with your array of custom objects } ``` **Content Cardsの操作**
`class_type` はフィルターとして渡され、一致する `class_type` を持つContent Cardsのみを返します。 ```objc - (NSArray *)handleContentCardsUpdated:(NSNotification *)notification forClassType:(ContentCardClassType)classType { BOOL updateIsSuccessful = [notification.userInfo[ABKContentCardsProcessedIsSuccessfulKey] boolValue]; if (updateIsSuccessful) { return [self convertContentCards:self.contentCards forClassType:classType]; } else { return @[]; } } ``` **ペイロードデータの操作**
Content Cardsの配列をループし、一致する `class_type` を持つカードのみを解析します。ABKContentCard からのペイロードは `Dictionary` に解析されます。 ```swift func convertContentCards(_ cards: [ABKContentCard], for classTypes: [ContentCardClassType]) -> [ContentCardable] { var contentCardables: [ContentCardable] = [] for card in cards { let classTypeString = card.extras?[ContentCardKey.classType.rawValue] as? String let classType = ContentCardClassType(rawType: classTypeString) guard classTypes.contains(classType) else { continue } var metaData: [ContentCardKey: Any] = [:] switch card { case let banner as ABKBannerContentCard: metaData[.image] = banner.image case let captioned as ABKCaptionedImageContentCard: metaData[.title] = captioned.title metaData[.cardDescription] = captioned.cardDescription metaData[.image] = captioned.image case let classic as ABKClassicContentCard: metaData[.title] = classic.title metaData[.cardDescription] = classic.cardDescription default: break } metaData[.idString] = card.idString metaData[.created] = card.created metaData[.dismissible] = card.dismissible metaData[.urlString] = card.urlString metaData[.extras] = card.extras ... // other Content Card properties such as expiresAt, pinned, etc. if let contentCardable = contentCardable(with: metaData, for: classType) { contentCardables.append(contentCardable) } } return contentCardables } ``` **Content Cardsペイロードデータからのカスタムオブジェクトの初期化**
`class_type` は、ペイロードデータから初期化されるカスタムオブジェクトを決定するために使用されます。 ```swift func contentCardable(with metaData: [ContentCardKey: Any], for classType: ContentCardClassType) -> ContentCardable? { switch classType { case .yourValue: return CustomObject(metaData: metaData, classType: classType) case .yourOtherValue: return OtherCustomObject(metaData: metaData, classType: classType) ... default: return nil } } ``` **ペイロードデータの操作**
Content Cardsの配列をループし、一致する `class_type` を持つカードのみを解析します。ABKContentCard からのペイロードは `Dictionary` に解析されます。 ```objc - (NSArray *)convertContentCards:(NSArray *)cards forClassType:(ContentCardClassType)classType { NSMutableArray *contentCardables = [[NSMutableArray alloc] init]; for (ABKContentCard *card in cards) { NSString *classTypeString = [card.extras objectForKey:ContentCardKeyClassType]; ContentCardClassType cardClassType = [ContentCardData contentCardClassTypeForString: classTypeString]; if (cardClassType != classType) { continue; } NSMutableDictionary *metaData = [[NSMutableDictionary alloc] init]; if ([card isKindOfClass:[ABKBannerContentCard class]]) { ABKBannerContentCard *banner = (ABKBannerContentCard *)card; metaData[ContentCardKeyImage] = banner.image; } else if ([card isKindOfClass:[ABKCaptionedImageContentCard class]]) { ABKCaptionedImageContentCard *captioned = (ABKCaptionedImageContentCard *)card; metaData[ContentCardKeyTitle] = captioned.title; metaData[ContentCardKeyCardDescription] = captioned.cardDescription; metaData[ContentCardKeyImage] = captioned.image; } else if ([card isKindOfClass:[ABKClassicContentCard class]]) { ABKClassicContentCard *classic = (ABKClassicContentCard *)card; metaData[ContentCardKeyCardDescription] = classic.title; metaData[ContentCardKeyImage] = classic.image; } metaData[ContentCardKeyIdString] = card.idString; metaData[ContentCardKeyCreated] = [NSNumber numberWithDouble:card.created]; metaData[ContentCardKeyDismissible] = [NSNumber numberWithBool:card.dismissible]; metaData[ContentCardKeyUrlString] = card.urlString; metaData[ContentCardKeyExtras] = card.extras; ... // other Content Card properties such as expiresAt, pinned, etc. id contentCardable = [self contentCardableWithMetaData:metaData forClassType:classType]; if (contentCardable) { [contentCardables addObject:contentCardable]; } } return contentCardables; } ``` **Content Cardsペイロードデータからのカスタムオブジェクトの初期化**
`class_type` は、ペイロードデータから初期化されるカスタムオブジェクトを決定するために使用されます。 ```obj-c - (id)contentCardableWithMetaData:(NSDictionary *)metaData forClassType:(ContentCardClassType)classType { switch (classType) { case ContentCardClassTypeYourValue: return [[CustomObject alloc] initWithMetaData:metaData classType:classType]; case ContentCardClassTypeYourOtherValue: return nil; ... default: return nil; } } ``` ## ユースケース {#sample-use-cases} 以下に3つのユースケースを紹介します。各ユースケースでは、詳細な説明、関連するコードスニペット、およびContent Cardsの変数がBrazeダッシュボードでどのように表示され、どのように使用されるかを確認できます。 - [補足コンテンツとしてのContent Cards](#content-cards-as-supplemental-content) - [メッセージセンターのContent Cards](#content-cards-in-a-message-center) - [インタラクティブContent Cards](#interactive-content-cards) ### 補足コンテンツとしてのContent Cards {#content-cards-as-supplemental-content} ![ローカルデータとBraze Content Cardsを組み合わせたハイブリッドリストを含むフィード。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/supplementary.png?04f6645c99fe71ac7abb4cba8a46ccbd){: style="float:right;max-width:25%;margin-left:15px;border:0;"} Content Cardsを既存のフィードにシームレスにブレンドし、複数のフィードからのデータを同時に読み込むことができます。これにより、Braze Content Cardsと既存のフィードコンテンツとの一体感のある、調和のとれた体験が生まれます。 右の例は、ローカルデータとBrazeを使用したContent Cardsによって設定された項目のハイブリッドリストを含む `UICollectionView` を示しています。これにより、既存のコンテンツとContent Cardsを区別できなくなります。 #### ダッシュボード設定 {#dashboard-configuration} このContent Cardsは、APIトリガーのキーと値のペアを持つAPIトリガーキャンペーンによって提供されます。これは、カードの値が外部要因に依存して、ユーザーに表示するコンテンツを決定するキャンペーンに最適です。なお、`class_type` はセットアップ時に把握しておく必要があります。 ![補足コンテンツカードのユースケースのキーと値のペア。この例では、カードの各要素(「tile_id」、「tile_deeplink」、「tile_title」など)がLiquidを使って設定されています。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/supplementary_content.png?1b9481939960e31dc1b1e5ef57d51b68){: style="max-width:60%;"} ##### 分析をログに記録する準備はできましたか? {#ready-to-log-analytics} データフローの外観について理解を深めるには、[以下のセクション](#logging-impressions-clicks-and-dismissals)を参照してください。 ### メッセージセンターのContent Cards {#content-cards-in-a-message-center}
Content Cardsは、各メッセージが独自のカードであるメッセージセンター形式で使用できます。メッセージセンター内の各メッセージは、Content Cardsペイロードを介して設定され、各カードには、クリック時のUI/UXを起動する追加のキーと値のペアが含まれています。次の例では、1つのメッセージによって任意のカスタムビューが表示され、別のメッセージによってカスタムHTMLを表示するWebビューが開きます。 ![個別のメッセージカードを含むContent Cardsメッセージセンター。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/message_center.png?ec1fb31a68a7f9918c609dac71b1408d){: style="border:0;"}{: style="max-width:80%;border:0"} #### ダッシュボード設定 次のメッセージタイプでは、キーと値のペア `class_type` をダッシュボード設定に追加する必要があります。ここで割り当てる値は任意ですが、クラス型を区別できるようにする必要があります。これらのキーと値のペアは、ユーザーが簡略化された受信トレイメッセージをクリックした際に行き先を決定するときにアプリケーションが参照するキー識別子です。 このユースケースのキーと値のペアは、次のとおりです。 - `message_header` を `Full Page` に設定 - `class_type` を `message_full_page` に設定 ![フルページのContent Cardsメッセージの例。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/full_page.png?a9d79abfd4496252706f34aec0a33d17){: style="max-width:60%;"} このユースケースのキーと値のペアは、次のとおりです。 - `message_header` を `HTML` に設定 - `class_type` を `message_webview` に設定 - `message_title` このメッセージはHTMLキーと値のペアも検索しますが、Webドメインで作業している場合は、URLキーと値のペアも有効です。 ![キーと値のペアからHTML Webビューを開くContent Card。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/html_webview.png?1264dbf1823a4a6168d88108139f1221){: style="max-width:60%;"} #### 詳細説明 {#further-explanation} メッセージセンターのロジックは、Brazeのキーと値のペアによって提供される `contentCardClassType` によって駆動されます。`addContentCardToView` メソッドを使用すると、これらのクラス型をフィルタリングして識別することができます。 **クリック時の動作に `class_type` を使用する**
メッセージをクリックすると、`ContentCardClassType` が次の画面の表示方法を制御します。 ```swift func addContentCardToView(with message: Message) { switch message.contentCardData?.contentCardClassType { case .message(.fullPage): loadContentCardFullPageView(with: message as! FullPageMessage) case .message(.webView): loadContentCardWebView(with: message as! WebViewMessage) default: break } } ``` **クリック時の動作に `class_type` を使用する**
メッセージをクリックすると、`ContentCardClassType` が次の画面の表示方法を制御します。 ```objc - (void)addContentCardToView:(Message *)message { switch (message.contentCardData.classType) { case ContentCardClassTypeMessageFullPage: [self loadContentCardFullPageView:(FullPageMessage *)message]; break; case ContentCardClassTypeMessageWebview: [self loadContentCardWebView:(WebViewMessage *)message]; break; default: break; } } ``` ##### 分析をログに記録する準備はできましたか? データフローの外観について理解を深めるには、[以下のセクション](#logging-impressions-clicks-and-dismissals)を参照してください。 ![画面左下に50%のプロモーションを示すインタラクティブなContent Cardが表示されている。クリックすると、カートにプロモーションが適用されます。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/discount2.png?28bacc3995ff935635bb24b7bb547e1b){: style="border:0;"}{: style="float:right;max-width:45%;border:0;margin-left:15px;"} ### インタラクティブContent Cards {#interactive-content-cards}
Content Cardsを活用して、ユーザーのためのダイナミックでインタラクティブな体験を作成できます。右の例では、Content Cardsのポップアップがチェックアウト時に表示され、ユーザーに最新のプロモーションを提供しています。 このように適切に配置されたカードは、ユーザーが特定のアクションを実行するように「後押し」する優れた方法です。


#### ダッシュボード設定 インタラクティブContent Cardsのダッシュボード設定は簡単です。このユースケースのキーと値のペアには、希望する割引額として設定された `discount_percentage` と、`coupon_code` として設定された `class_type` があります。これらのキーと値のペアは、タイプ固有のContent Cardsがどのようにフィルタリングされ、チェックアウト画面に表示されるかを決定します。 ![チェックアウトプロモーションを表示するインタラクティブContent Card。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/discount.png?0f629adf0e5b56e0d2dc52b0b9f3e087){: style="max-width:70%;"} ##### 分析をログに記録する準備はできましたか? データフローの外観について理解を深めるには、[以下のセクション](#logging-impressions-clicks-and-dismissals)を参照してください。 ## ダークモードのカスタマイズ {#dark-mode-customization} デフォルトでは、Content Cardsビューは、テーマカラーのセットでデバイスのダークモードの変更に自動的に応答します。 この動作は、[カスタムスタイルガイド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/content_cards/customization/custom_styling#disabling-dark-mode)で詳細に説明されているようにオーバーライドできます。 ## インプレッション、クリック、却下のロギング {#logging-impressions-clicks-and-dismissals} カスタムオブジェクトをContent Cardsとして機能するように拡張した後は、インプレッション、クリック、却下などの貴重な指標のロギングを迅速に行えます。これは、`ContentCardable` プロトコルを使用して実行できます。このプロトコルは、Braze SDKによってロギングされるヘルパーファイルを参照し、データを提供します。 ### 実装コンポーネント

{#implementation-components} **分析のロギング**
ロギングメソッドは、`ContentCardable` プロトコルに準拠するオブジェクトから直接呼び出すことができます。 ```swift customObject.logContentCardImpression() customObject.logContentCardClicked() customObject.logContentCardDismissed() ``` **`ABKContentCard` の取得**
カスタムオブジェクトから渡された `idString` は、関連付けられたContent Cardを識別して分析をログに記録するために使用されます。 ```swift extension BrazeManager { func logContentCardImpression(idString: String?) { guard let contentCard = getContentCard(forString: idString) else { return } contentCard.logContentCardImpression() } private func getContentCard(forString idString: String?) -> ABKContentCard? { return contentCards?.first(where: { $0.idString == idString }) } } ``` **分析のロギング**
ロギングメソッドは、`ContentCardable` プロトコルに準拠するオブジェクトから直接呼び出すことができます。 ```objc [customObject logContentCardImpression]; [customObject logContentCardClicked]; [customObject logContentCardDismissed]; ``` **`ABKContentCard` の取得**
カスタムオブジェクトから渡された `idString` は、関連付けられたContent Cardを識別して分析をログに記録するために使用されます。 ```objc - (void)logContentCardImpression:(NSString *)idString { ABKContentCard *contentCard = [self getContentCard:idString]; [contentCard logContentCardImpression]; } - (ABKContentCard *)getContentCard:(NSString *)idString { NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self.idString == %@", idString]; NSArray *filteredArray = [self.contentCards filteredArrayUsingPredicate:predicate]; return filteredArray.firstObject; } ``` **Important:** コントロールバリアントのContent Cardの場合、カスタムオブジェクトは引き続きインスタンス化し、UIロジックでオブジェクトの対応するビューを非表示に設定する必要があります。その後、オブジェクトはインプレッションをログに記録して、ユーザーがいつコントロールカードを表示したかを分析に知らせることができます。 ## ヘルパーファイル {#helper-files} **ContentCardKey ヘルパーファイル** ```swift enum ContentCardKey: String { case idString case created case classType = "class_type" case dismissible case extras ... } ``` ```objc static NSString *const ContentCardKeyIdString = @"idString"; static NSString *const ContentCardKeyCreated = @"created"; static NSString *const ContentCardKeyClassType = @"class_type"; static NSString *const ContentCardKeyDismissible = @"dismissible"; static NSString *const ContentCardKeyExtras = @"extras"; ... ``` # iOS用トラックセッション Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/analytics/tracking_sessions/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS のセッショントラッキング Braze SDK では、ユーザーエンゲージメントなど、ユーザーについて理解するうえで不可欠な分析情報を計算するために Braze ダッシュボードで使用されるセッションデータがレポートされます。SDK では、以下のセッションセマンティクスに基づいて、Braze ダッシュボード内で表示可能なセッションの長さとセッション数を考慮した「セッション開始」と「セッション終了」のデータポイントが生成されます。 ## セッションライフサイクル `[[Appboy sharedInstance]` `startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions]` を呼び出すとセッションが開始されます。その後はデフォルトで、`UIApplicationWillEnterForegroundNotification` 通知が発行されると (アプリがフォアグラウンドに入ったときなど) セッションが開始され、アプリがフォアグラウンドを離れると (`UIApplicationDidEnterBackgroundNotification` 通知が発行されたときや、アプリが終了したときなど) セッションが終了します。 **Note:** 新しいセッションを強制する必要がある場合、ユーザーを変更することで強制が可能になります。 ## セッションタイムアウトのカスタマイズ Braze iOS SDK v3.14.1から、Info.plist ファイルを使用してセッションタイムアウトを設定できるようになった。`Braze` ディクショナリを `Info.plist` ファイルに追加します。`Braze` ディクショナリ内に `SessionTimeout` 番号サブエントリを追加し、値をカスタムセッションタイムアウトに設定します。なお、Braze iOS SDK v4.0.2 より前のバージョンでは、`Braze` の代わりにディクショナリキー `Appboy` を使用する必要があります。 または、[`startWithApiKey`](https://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#afd911d60dfe7e5361afbfb364f5d20f9) に渡される `appboyOptions` オブジェクト内の `ABKSessionTimeoutKey` キーを目的の整数値に設定することもできます。 ```objc // Sets the session timeout to 60 seconds [Appboy startWithApiKey:@"YOUR-API_KEY" inApplication:application withLaunchOptions:options withAppboyOptions:@{ ABKSessionTimeoutKey : @(60) }]; ``` `````````swift // Sets the session timeout to 60 seconds Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:[ ABKSessionTimeoutKey : 60 ]) ``` セッションタイムアウトを設定した場合、セッションセマンティクスの長さはすべてそのカスタマイズされたタイムアウトになります。 **Note:** `sessionTimeoutInSeconds` の最小値は 1 秒です。デフォルト値は 10 秒です。 ## セッショントラッキングをテストする ユーザーを介してセッションを検出するには、ダッシュボードでユーザーを見つけ、ユーザープロファイルの [**アプリの利用状況**] に移動します。「セッション」指標が想定どおりに増加していることを確認することで、セッショントラッキングが機能していることを確認できます。 ![ユーザープロファイルのアプリ利用状況セクションには、セッション数、最終利用日、初回利用日が表示される。](https://www.braze.com/docs/ja/ja/assets/img_archive/test_session.png?0428888ea3bd01a486d8c674fb973747) # iOSのユーザー ID を設定する Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/analytics/setting_user_ids/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOSのユーザー ID を設定する User IDs should be set for each of your users. These should be unchanging and accessible when a user opens the app. Naming your user IDs correctly from the start is one of the most **crucial** steps when setting up user IDs. We strongly suggest using the Braze standard of UUIDs and GUIDs (detailed below). We also strongly recommend providing this identifier as it will allow you to: - Track your users across devices and platforms, improving the quality of your behavioral and demographic data. - Import data about your users using our [user data API](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data/#user-data). - Target specific users with our [messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/) for both general and transactional messages. **Note:** If such an identifier is not available, Braze will assign a unique identifier to your users, but you will lack the capabilities listed for user IDs. You should avoid setting user IDs for users for whom you lack a unique identifier that is tied to them as an individual. Passing a device identifier offers no benefit versus the automatic anonymous user tracking Braze offers by default. **Warning:** If you want to include an identifiable value as your user ID, for additional security, we **strongly recommend** adding our [SDK authentication](https://www.braze.com/docs/ja/ja/developer_guide/authentication/) feature to prevent user impersonation. ## 推奨されるユーザー ID の命名規則 At Braze, we **strongly recommend** naming user IDs, also referred to as external IDs, in a [UUIDs and GUIDs](https://en.wikipedia.org/wiki/Universally_unique_identifier) format. UUIDs and GUIDs are universally unique identifiers that consist of a 128-bit number used to identify information in computer systems. This means that these UUIDs are long, random and well distributed. If you choose a different method in which to name your user IDs, they must also be long, random and well distributed. It is also important to note, that user IDs are **case sensitive**. For example, "Abcdef" is a different user from "abcdef". If you find your user IDs include names, email addresses, timestamps, or incrementors, we suggest using a new naming method that is more secure so that your user IDs are not as easy to guess or impersonate. If you choose to include this in your user IDs, we **strongly recommend** adding our [SDK authentication](https://www.braze.com/docs/ja/ja/developer_guide/authentication/) feature to prevent user impersonation. Providing this information to others may allow people outside your organization to glean information on how your user IDs are structured, opening up your organization to potentially malicious updates or removal of information. Choosing the correct naming convention from the start is one of the most important steps in setting up user IDs. However, a migration is possible using our [external ID migration endpoint](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/external_id_migration/). | User ID Naming | | Recommended | Not Recommended | | ------------ | ----------- | | 123e4567-e89b-12d3-a456-836199333115 | JonDoe829525552 | | 8c0b3728-7fa7-4c68-a32e-12de1d3ed2d5 | Anna@email.com | | f0a9b506-3c5b-4d86-b16a-94fc4fc3f7b0 | CompanyName-1-2-19 | | 2d9e96a1-8f15-4eaf-bf7b-eb8c34e25962 | jon-doe-1-2-19 | {: .reset-td-br-1 .reset-td-br-2 aria-label="Table" } ## ユーザー ID の割り当て ユーザーが識別されたらすぐに (通常はログイン後)、次の呼び出しを行ってユーザー ID を設定する必要があります。 ```objc [[Appboy sharedInstance] changeUser:@"YOUR_USER_ID_STRING"]; ``` `````````swift Appboy.sharedInstance()?.changeUser("YOUR_USER_ID") ``` **Warning:** **ユーザーがログアウトするときに `changeUser()` を呼び出さないでください。`changeUser()` の呼び出しは、ユーザーがアプリケーションにログインするときにのみ行う必要があります。**[`changeUser()`](https://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#ac8b369b40e15860b0ec18c0f4b46ac69%20%22changeuser%22) を静的なデフォルト値に設定すると、ユーザーが再度ログインするまで、すべてのユーザーアクティビティがそのデフォルト「ユーザー」に関連付けられます。 このメソッドはアプリケーションのメインスレッドで呼び出してください。メソッドを非同期的に呼び出すと、定義されていない動作が生じる可能性があります。 また、ユーザーがログアウトするときにユーザー ID を変更しないでください。変更すると、以前にログインしたユーザーを再エンゲージメントキャンペーンでターゲットにできなくなるためです。同じデバイスに複数のユーザーが存在することが予想されるものの、アプリがログアウト状態の間にそのうちの 1 ユーザーのみをターゲットにする場合は、ログアウト中にターゲットにするユーザー ID を個別に追跡し、アプリのログアウトプロセスの中でそのユーザー ID に戻すことをお勧めします。 ## ユーザー ID 統合のベストプラクティスとメモ ### Automatic preservation of anonymous user history | Identification Context | Preservation Behavior | | ---------------------- | -------------------------- | | User **has not** been previously identified | Anonymous history **is merged** with user profile upon identification. | | User **has been** previously identified in-app or via API | Anonymous history **is not merged** with user profile upon identification. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Automatic preservation of anonymous user history" } Refer to [Identified user profiles](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/user_data_collection/user_profile_lifecycle/#identified-user-profiles) for more information on what occurs when you identify anonymous users. ### Additional notes and best practices Note the following: - If your app is used by multiple people, you can assign each user a unique identifier to track them. - After a user ID has been set, you cannot revert that user to an anonymous profile. - Do not change the user ID when a user logs out as this can separate the device from the user profile. - As a result, you won't be able to target the previously logged out user with re-engagement messages. If you anticipate multiple users on the same device, but only want to target one of them when your app is in a logged-out state, we recommend separately keeping track of the user ID you want to target while logged out and switching back to that user ID as part of your app's logout process. By default, only the last user that was logged in will receive push notifications from your app. - Switching from one identified user to another is a relatively costly operation. - When you request the user switch, the current session for the previous user is automatically closed and a new session is started. Braze will automatically make a data refresh request for in-app messages and other Braze resources for the new user. **Tip:** If you opt to use a hash of a unique identifier as your user ID, be sure that you're normalizing the input to your hashing function. For example, if you're going to use a hash of an email address, confirm that you're stripping leading and trailing whitespace from the input, and taking localization into account. ## ユーザーのエイリアシング A [user alias](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/user_data_collection/user_profile_lifecycle/#user-aliases) serves as an alternative unique user identifier. You can use aliases to identify users along different dimensions than your core user ID: * Set a consistent identifier for analytics that will follow a given user both before and after they have logged in to a mobile app or website. * Add the identifiers used by a third-party vendor to your company users in order to more easily reconcile your data externally. Each alias consists of two parts: a name for the identifier itself, and a label indicating the type of alias. Users can have multiple aliases with different labels, but only one name per label. For more information on setting user aliases against a user profile, refer to [User aliases](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/user_data_collection/user_profile_lifecycle/#user-aliases). # iOS向けカスタムイベントのトラッキング Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/analytics/tracking_custom_events/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS向けカスタムイベントのトラッキング {#track-custom-events-for-ios} Brazeでカスタムイベントを記録することで、アプリの使用パターンに関する詳細を把握し、ダッシュボードでのアクションによってユーザーをセグメント化できます。 実装前に、[ベストプラクティス](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/analytics_overview#user-data-collection)のカスタムイベント、カスタム属性、および購入イベントによって提供されるセグメンテーションオプションの例と、[イベント命名規則](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/event_naming_conventions)に関するメモを必ず確認してください。 ## カスタムイベントの追加 {#adding-a-custom-event} ```objc [[Appboy sharedInstance] logCustomEvent:@"YOUR_EVENT_NAME"]; ``` ```swift Appboy.sharedInstance()?.logCustomEvent("YOUR_EVENT_NAME") ``` ### プロパティの追加 {#adding-properties} `NSNumber`、`NSString`、または `NSDate` の値が入力された `NSDictionary` を渡すことで、カスタムイベントに関するメタデータを追加できます。 ```objc [[Appboy sharedInstance] logCustomEvent:@"YOUR-EVENT-NAME" withProperties:@{ @"you": @"can", @"pass": @(NO), @"orNumbers": @42, @"orDates": [NSDate date], @"or": @[@"any", @"array", @"here"], @"andEven": @{ @"deeply": @[@"nested", @"json"] } }]; ``` ```swift Appboy.sharedInstance()?.logCustomEvent( "YOUR-EVENT-NAME", withProperties: [ "you": "can", "pass": false, "orNumbers": 42, "orDates": Date(), "or": ["any", "array", "here"], "andEven": [ "deeply": ["nested", "json"] ] ] ) ``` 詳細については、[クラスに関するドキュメント](http://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#a4f0051d73d85cb37f63c232248124c79)を参照してください。 ### 予約済みのキー {#event-reserved-keys} 以下のキーは予約されているため、カスタムイベントプロパティとして使用できません。 - `time` - `event_name` ## その他のリソース {#additional-resources} - `Appboy.h` [ファイル](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/Appboy.h)内のメソッド宣言を参照してください。 - 詳細については、[`logCustomEvent`のドキュメント](http://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#ad80c39e8c96482a77562a5b1a1d387aa)を参照してください。 # iOS向けにカスタム属性を設定する Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/analytics/setting_custom_attributes/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS向けにカスタム属性を設定する {#set-custom-attributes-for-ios} Brazeには、ユーザーに属性を割り当てるメソッドが用意されています。ダッシュボード上でこれらの属性に基づいて、ユーザーのフィルター処理やセグメント化を行うことができます。 実装前に、[ベストプラクティス](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/analytics_overview#user-data-collection)のカスタムイベント、カスタム属性、および購入イベントによって提供されるセグメンテーションオプションの例と、[イベント命名規則](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/event_naming_conventions)に関する注意事項を必ず確認してください。 ## デフォルトユーザー属性の割り当て {#assigning-default-user-attributes} ユーザー属性を割り当てるには、共有`ABKUser`オブジェクトで適切なフィールドを設定する必要があります。 以下は名属性の設定例です。 ```objc [Appboy sharedInstance].user.firstName = @"first_name"; ``` ```swift Appboy.sharedInstance()?.user.firstName = "first_name" ``` `ABKUser`オブジェクトでは、以下の属性を設定する必要があります。 - `firstName` - `lastName` - `email` - `dateOfBirth` - `country` - `language` - `homeCity` - `phone` - `userID` - `gender` ## カスタムユーザー属性の割り当て {#assigning-custom-user-attributes} Brazeでは、デフォルトユーザー属性以外にも、複数の異なるデータタイプを使用してカスタム属性を定義できます。これらの各属性で提供されるセグメンテーションオプションの詳細については、[ユーザーデータ収集](https://www.braze.com/docs/ja/ja/developer_guide/analytics)を参照してください。 ### 文字列値のカスタム属性 {#custom-attribute-with-a-string-value} ```objc [[Appboy sharedInstance].user setCustomAttributeWithKey:@"your_attribute_key" andStringValue:"your_attribute_value"]; ``` ```swift Appboy.sharedInstance()?.user.setCustomAttributeWithKey("your_attribute_key", andStringValue: "your_attribute_value") ``` ### 整数値のカスタム属性 {#custom-attribute-with-an-integer-value} ```objc [[Appboy sharedInstance].user setCustomAttributeWithKey:@"your_attribute_key" andIntegerValue:yourIntegerValue]; ``` ```swift Appboy.sharedInstance()?.user.setCustomAttributeWithKey("your_attribute_key", andIntegerValue: yourIntegerValue) ``` ### double値のカスタム属性 {#custom-attribute-with-a-double-value} Brazeでは、データベース内での`float`値と`double`値の扱いが同じです。 ```objc [[Appboy sharedInstance].user setCustomAttributeWithKey:@"your_attribute_key" andDoubleValue:yourDoubleValue]; ``` ```swift Appboy.sharedInstance()?.user.setCustomAttributeWithKey("your_attribute_key", andDoubleValue: yourDoubleValue) ``` ### ブール値のカスタム属性 {#custom-attribute-with-a-boolean-value} ```objc [[Appboy sharedInstance].user setCustomAttributeWithKey:@"your_attribute_key" andBOOLValue:yourBOOLValue]; ``` ```swift Appboy.sharedInstance()?.user.setCustomAttributeWithKey("your_attribute_key", andBOOLValue: yourBoolValue) ``` ### 日付値のカスタム属性 {#custom-attribute-with-a-date-value} このメソッドでBrazeに渡される日付は、[ISO 8601](http://en.wikipedia.org/wiki/ISO_8601)形式(例: `2013-07-16T19:20:30+01:00`)または`yyyy-MM-dd'T'HH:mm:ss:SSSZ`形式(`2016-12-14T13:32:31.601-0800`)でなければなりません。 ```objc [[Appboy sharedInstance].user setCustomAttributeWithKey:@"your_attribute_key" andDateValue:yourDateValue]; ``` ```swift Appboy.sharedInstance()?.user.setCustomAttributeWithKey("your_attribute_key", andDateValue:yourDateValue) ``` ### 配列値のカスタム属性 {#custom-attribute-with-an-array-value} 配列内の要素のデフォルトおよび最大数は500です。最大配列数は、Brazeダッシュボードの**データ設定** > **カスタム属性**で更新できます。要素数が最大値を超える配列は、最大要素数に切り捨てられます。 ```objc // Setting a custom attribute with an array value [[Appboy sharedInstance].user setCustomAttributeArrayWithKey:@"array_name" array:@[@"value1", @"value2"]]; // Adding to a custom attribute with an array value [[Appboy sharedInstance].user addToCustomAttributeArrayWithKey:@"array_name" value:@"value3"]; // Removing a value from an array type custom attribute [[Appboy sharedInstance].user removeFromCustomAttributeArrayWithKey:@"array_name" value:@"value2"]; // Removing an entire array and key [[Appboy sharedInstance].user setCustomAttributeArrayWithKey:@"array_name" array:nil]; ``` ```swift // Setting a custom attribute with an array value Appboy.sharedInstance()?.user.setCustomAttributeArrayWithKey("array_name", array: ["value1", "value2"]) // Adding to a custom attribute with an array value Appboy.sharedInstance()?.user.addToCustomAttributeArrayWithKey("array_name", value: "value3") // Removing a value from an array type custom attribute Appboy.sharedInstance()?.user.removeFromCustomAttributeArrayWithKey("array_name", value: "value2") ``` ### カスタム属性の設定解除 {#unsetting-a-custom-attribute} カスタム属性は、次のメソッドを使用して設定を解除することもできます。 ```objc [[Appboy sharedInstance].user unsetCustomAttributeWithKey:@"your_attribute_key"]; ``` ```swift Appboy.sharedInstance()?.user.unsetCustomAttributeWithKey("your_attribute_key") ``` ### カスタム属性のインクリメント/デクリメント {#incrementingdecrementing-custom-attributes} このコードは、カスタム属性のインクリメントの例です。カスタム属性の値は、正または負の整数値やlong値でインクリメントできます。 ```objc [[Appboy sharedInstance].user incrementCustomUserAttribute:@"your_attribute_key" by:incrementIntegerValue]; ``` ```swift Appboy.sharedInstance()?.user.incrementCustomUserAttribute("your_attribute_key", by: incrementIntegerValue) ``` ### REST APIによるカスタム属性の設定 {#setting-a-custom-attribute-via-the-rest-api} REST APIを使用してユーザー属性を設定することもできます。詳細については、[ユーザーAPIのドキュメント](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data#user-data)を参照してください。 ### カスタム属性値の制限 {#custom-attribute-value-limits} カスタム属性値の最大長は255文字です。これより長い値は切り捨てられます。 #### 追加情報 {#additional-information} - 詳細は[`ABKUser.h`ファイル](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/Appboy.h)を参照してください。 - 詳細については、[`ABKUser`のドキュメント](http://appboy.github.io/appboy-ios-sdk/docs/interface_a_b_k_user.html)を参照してください。 ## ユーザーサブスクリプションの設定 {#setting-up-user-subscriptions} ユーザーのサブスクリプション(メールまたはプッシュ)を設定するには、それぞれ関数`setEmailNotificationSubscriptionType`または`setPushNotificationSubscriptionType`を呼び出します。これらの関数では、いずれも引数として列挙型`ABKNotificationSubscriptionType`を使用します。この型には、次の3つの状態があります。 | サブスクリプションのステータス | 定義 | | ------------------- | ---------- | | `ABKOptedin` | 配信登録済み、かつ明示的にオプトイン済み | | `ABKSubscribed` | 購読中、ただし明示的にオプトインされていない | | `ABKUnsubscribed` | 配信停止済みまたは明示的にオプトアウト済み、あるいはその両方 | {: .reset-td-br-1 .reset-td-br-2 role="presentation" aria-label="ユーザーサブスクリプションの設定" } アプリにプッシュ通知の送信を許可するユーザーは、iOSでは明示的なオプトインが必要であるため、デフォルトでステータスが`ABKOptedin`に設定されます。 ユーザーは、有効なメールアドレスを受信すると自動的に`ABKSubscribed`に設定されます。ただし、明示的なオプトインのプロセスを確立し、ユーザーから明示的な同意を得た時点でこの値を`OptedIn`に設定することをお勧めします。詳細については、「[ユーザーサブスクリプションの管理](https://www.braze.com/docs/ja/ja/user_guide/channels/email/subscriptions)」を参照してください。 ### メールサブスクリプションの設定 {#setting-email-subscriptions} ```objc [[Appboy sharedInstance].user setEmailNotificationSubscriptionType: ABKNotificationSubscriptionType] ``` ```swift Appboy.sharedInstance()?.user.setEmailNotificationSubscriptionType(ABKNotificationSubscriptionType) ``` ### プッシュ通知サブスクリプションの設定 {#setting-push-notification-subscriptions} ```objc [[Appboy sharedInstance].user setPushNotificationSubscriptionType: ABKNotificationSubscriptionType] ``` ```swift Appboy.sharedInstance()?.user.setPushNotificationSubscriptionType(ABKNotificationSubscriptionType) ``` 詳細については、「[ユーザーサブスクリプションの管理](https://www.braze.com/docs/ja/ja/user_guide/channels/email/subscriptions)」を参照してください。 # iOS向け購入記録 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/analytics/logging_purchases/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS向けの購入記録 {#log-purchases-for-ios} アプリ内での購入を記録して、売上を経時的にトラッキングしたり、売上源を横断してトラッキングしたりできます。また、ユーザーを生涯価値でセグメント化することもできます。 Brazeは複数の通貨での購入に対応しています。米ドル以外の通貨でレポートする購入は、レポートされた日付の為替レートに基づいて米ドル単位でダッシュボードに表示されます。 実装前に、[ベストプラクティス](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/analytics_overview#user-data-collection)のカスタムイベント、カスタム属性、および購入イベントによって提供されるセグメンテーションオプションの例と、[イベント命名規則](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/event_naming_conventions)に関する注意事項を必ず確認しておいてください。 ## 購入と売上のトラッキング {#tracking-purchases-and-revenue} この機能を使用するには、アプリ内購入が正常に完了した後でこのメソッド呼び出しを追加します。 ```objc [[Appboy sharedInstance] logPurchase:@"your product ID" inCurrency:@"USD" atPrice:[[[NSDecimalNumber alloc] initWithString:@"0.99"] autorelease]]; ``` ```swift Appboy.sharedInstance()?.logPurchase("your product ID", inCurrency: "USD", atPrice: NSDecimalNumber(string: "0.99")) ``` - サポートされている通貨コードはUSD、CAD、EUR、GBP、JPY、AUD、CHF、NOK、MXN、NZD、CNY、RUB、TRY、INR、IDR、ILS、SAR、ZAR、AED、SEK、HKD、SPD、DKKなどです。 - これ以外の通貨コードを指定すると警告が記録され、SDKでその他のアクションは実行されません。 - 商品IDは最大255文字です。 - 製品IDが空の場合、購入はBrazeに記録されないことに注意してください。 ### プロパティの追加 {#properties-purchases} 購入に関するメタデータを追加するには、[イベントプロパティ配列](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/custom_data/custom_events#nested-objects)を渡すか、`NSNumber`、`NSString`、または`NSDate`の値が挿入された`NSDictionary`を渡します。 詳細については、[iOSクラスのドキュメント](http://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#aaca4b885a8f61ac9fad3936b091448cc)を参照してください。 ### 数量の追加 {#adding-quantity} 顧客が1回のチェックアウト手続きで同じ購入を複数回行う場合は、購入に数量を追加できます。これを行うには、数量として`NSUInteger`を渡します。 * SDKで購入を記録するには、数量入力が [0, 100] の範囲内である必要があります。 * 数量入力のないメソッドは、デフォルトの数量値が1になります。 * 数量入力のあるメソッドにはデフォルト値がないため、SDKで購入を記録するには数量入力を受け取る**必要があります**。 詳細については、[iOSクラスのドキュメント](http://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#ab50403068be47c0acba9943583e259fa)を参照してください。 ```objc [[Appboy sharedInstance] logPurchase:@"your product ID" inCurrency:@"USD" atPrice:[[[NSDecimalNumber alloc] initWithString:@"0.99"] autorelease] withProperties:@{@"key1":"value1"}]; ``` ```swift Appboy.sharedInstance()?.logPurchase("your product ID", inCurrency: "USD", atPrice: NSDecimalNumber(string: "0.99"), withProperties: ["key1":"value1"]) ``` **Tip:** 10米ドルという値と数量3を渡すと、10ドルの購入3件、合計30ドルとしてユーザーのプロファイルに記録されます。 ### 注文レベルでの購入記録 {#log-purchases-at-the-order-level} 商品レベルではなく、注文レベルで購入を記録したい場合、注文名または注文カテゴリを`product_id`として使用できます。詳細については、[購入オブジェクトの仕様](https://www.braze.com/docs/ja/ja/api/objects_filters/purchase_object#product-id-naming-conventions)を参照してください。 ### 予約済みのキー {#reserved-keys} 以下のキーは予約されているため、購入プロパティとして使用できません。 - `time` - `product_id` - `quantity` - `event_name` - `price` - `currency` ### REST API REST APIを使用して購入を記録することもできます。詳細については、[ユーザーAPIのドキュメント](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data#user-data)を参照してください。 # iOS の位置情報の追跡 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/analytics/location_tracking/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS の位置情報の追跡 デフォルトでは、Braze で位置情報の追跡は無効になっています。位置情報の追跡は、ホストアプリケーションで位置情報の追跡がオプトインされ、ユーザーから許可を得た後に有効になります。ユーザーが位置情報の追跡をオプトインしている場合、Braze ではセッション開始時に各ユーザーの単一の位置情報がロギングされます。 **Important:** おおよその位置情報をユーザーが許可している場合に iOS 14 で位置情報の追跡を確実に機能させるには、SDK バージョンを少なくとも `3.26.1` にアップデートする必要があります。 ## 位置情報の自動追跡を有効にする Braze iOS SDK `v3.17.0` 以降、位置情報の追跡はデフォルトで無効になっています。位置情報の自動追跡を有効にするには、`Info.plist` ファイルを使用します。`Braze` ディクショナリを `Info.plist` ファイルに追加します。`Braze` ディクショナリ内にブール値の `EnableAutomaticLocationCollection` サブエントリを追加し、値を `YES` に設定します。なお、Braze iOS SDK v4.0.2 より前のバージョンでは、`Braze` の代わりにディクショナリキー `Appboy` を使用する必要があります。 [`startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions`](https://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#aa9f1bd9e4a5c082133dd9cc344108b24) メソッドを使用して、アプリの起動時に位置情報の自動追跡を有効にすることもできます。`appboyOptions` ディクショナリで、`ABKEnableAutomaticLocationCollectionKey` を `YES` に設定します。以下に例を示します。 ```objc [Appboy startWithApiKey:@"YOUR-API_KEY" inApplication:application withLaunchOptions:options withAppboyOptions:@{ ABKEnableAutomaticLocationCollectionKey : @(YES) }]; ``` `````````swift Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:[ ABKEnableAutomaticLocationCollectionKey : true ]) ``` ### 位置データを Braze に渡す 以下の 2 つのメソッドは、ユーザーの既知の最終位置情報を手動で設定するために使用できます。 `````````objc [[Appboy sharedInstance].user setLastKnownLocationWithLatitude:latitude longitude:longitude horizontalAccuracy:horizontalAccuracy]; ``` `````````objc [[Appboy sharedInstance].user setLastKnownLocationWithLatitude:latitude longitude:longitude horizontalAccuracy:horizontalAccuracy altitude:altitude verticalAccuracy:verticalAccuracy]; ``` `````````swift Appboy.sharedInstance()?.user.setLastKnownLocationWithLatitude(latitude: latitude, longitude: longitude, horizontalAccuracy: horizontalAccuracy) ``` `````````swift Appboy.sharedInstance()?.user.setLastKnownLocationWithLatitude(latitude: latitude, longitude: longitude, horizontalAccuracy: horizontalAccuracy, altitude: altitude, verticalAccuracy: verticalAccuracy) ``` 詳細については、[`ABKUser.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKUser.h) を参照してください。 # iOS のアンインストール追跡 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/analytics/uninstall_tracking/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOSのアンインストール追跡 {#uninstall-tracking-for-ios} > この記事では、iOSアプリケーションのアンインストール追跡を構成する方法と、Brazeのアンインストール追跡プッシュの受信時にアプリで不要な自動アクションが実行されないことを確認するためのテスト方法について説明します。 アンインストール追跡では、ペイロードにBrazeフラグを含むバックグラウンドプッシュ通知を利用します。詳細については、ユーザーガイドの[アンインストール追跡](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/tracking/uninstall_tracking#uninstall-tracking)を参照してください。 ## ステップ 1:バックグラウンドプッシュを有効にする {#step-1-enabling-background-push} Xcodeプロジェクトの**Capabilities**タブの**Background Modes**セクションで、**Remote notifications**オプションが有効になっていることを確認します。詳細については、[サイレントプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/silent_push_notifications)のドキュメントを参照してください。 ## ステップ 2:Brazeバックグラウンドプッシュを確認する {#step-2-checking-for-braze-background-push} Brazeでは、バックグラウンドプッシュ通知を使用してアンインストール追跡分析を収集します。アンインストール追跡通知の受信時に、アプリケーションで[不要なアクションが実行されない](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/ignoring_internal_push)ようにしてください。 ## ステップ 3:ダッシュボードからテストする {#step-3-test-from-the-dashboard} 次に、ダッシュボードからテストプッシュを自分に送信します。このテストプッシュでは、ユーザープロファイルは更新されません。 1. **キャンペーン**ページで、プッシュ通知キャンペーンを作成し、プラットフォームとして**iOS push**を選択します。

2. **設定**ページで、キー`appboy_uninstall_tracking`および対応する値`true`を追加し、**Add Content-Available Flag**チェックボックスをオンにします。

3. **プレビュー**ページを使用して、テストアンインストール追跡プッシュを自分に送信します。

4. プッシュの受信時に、アプリで不要な自動アクションが実行されないことを確認してください。 **Important:** これらのテストステップは、Brazeからアンインストール追跡プッシュを送信する代わりとなるものです。バッジ数を有効にしている場合は、テストプッシュとともにバッジ番号が送信されますが、Brazeのアンインストール追跡プッシュによってアプリケーションでバッジ番号が設定されることはありません。 ## ステップ 4:アンインストール追跡を有効にする {#step-4-enable-uninstall-tracking} [アンインストール追跡を有効にする](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/tracking/uninstall_tracking#uninstall-tracking)手順に従ってください。 # iOS向けSDKトラッキングを無効化する Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/analytics/disabling_tracking/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOSでのデータ収集を無効にする {#disable-data-collection-for-ios} データプライバシー規制に準拠するために、iOS SDKのデータトラッキングアクティビティは[`disableSDK`](http://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#a8d3b78a98420713d8590ed63c9172733)メソッドを使用して完全に停止できます。このメソッドによってすべてのネットワーク接続がキャンセルされ、Braze SDKはBrazeサーバーにデータを渡しません。後でデータ収集を再開する場合は、[`requestEnableSDKOnNextAppRun`](http://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#a781078a40a3db0de64ac82dcae3b595b)メソッドを使用してデータ収集を再開できます。 また、[`wipeDataAndDisableForAppRun`](http://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#ac8d580f60ec0608cd91240a8a3aa23a3)メソッドを使用して、デバイスに保存されているすべてのクライアント側データを完全に消去できます。 特定のデバイス上で、同じベンダーのすべてのアプリをユーザーがアンインストールしない限り、`wipeDataAndDisableForAppRun()`を呼び出した後のBraze SDKおよびアプリの次回実行時に、サーバーはそのユーザーをデバイス識別子(IDFV)によって再識別します。すべてのユーザーデータを完全に削除するには、`wipeDataAndDisableForAppRun`の呼び出しと、Braze [REST API](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data#user-delete-endpoint)を介したサーバー上のデータ削除リクエストを組み合わせる必要があります。 ## iOS SDK v5.7.0以降 {#ios-sdk-v570} iOS SDK v5.7.0以降を使用しているデバイスの場合、[IDFVの収集を無効にする](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/legacy_sdks/ios/initial_sdk_setup/other_sdk_customizations#optional-idfv-collection---swift)ときに[`wipeData`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/wipedata())を呼び出しても、サーバーがデバイス識別子(IDFV)を介してそのユーザーを再識別することはありません。 # iOS のディープリンク Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/advanced_use_cases/linking/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS のディープリンク {#deep-linking-for-ios} ディープリンクの基本情報については、[ユーザーガイドの記事](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize/actions_and_media_urls#what-is-deep-linking)を参照してください。Braze アプリにディープリンクを初めて実装する場合は、以下の手順で開始できます。 ## ステップ 1:スキームを登録する {#step-1-register-a-scheme} `Info.plist` ファイルでカスタムスキームを記述する必要があります。ナビゲーション構造はディクショナリの配列によって定義されます。これらの各ディクショナリには、文字列の配列が含まれています。 Xcode を使用して `Info.plist` ファイルを編集します。 1. 新しいキー `URL types` を追加します。Xcode では、これが自動的に `Item 0` というディクショナリを含む配列になります。 2. `Item 0` 内に、キー `URL identifier` を追加します。カスタムスキームに値を設定します。 3. `Item 0` 内に、キー `URL Schemes` を追加します。これは、自動的に `Item 0` 文字列を含む配列になります。 4. `URL Schemes` >> `Item 0` をカスタムスキームに設定します。 また、`Info.plist` ファイルを直接編集する場合は、次の仕様に従うこともできます。 ```html CFBundleURLTypes CFBundleURLName {YOUR.SCHEME} CFBundleURLSchemes {YOUR.SCHEME} ``` ## ステップ 2:カスタムスキームを許可リストに登録する (iOS 9 以降) {#step-2-allowlist-the-custom-scheme-ios-9} iOS 9 以降では、アプリが開くことを許可されているカスタムスキームの許可リストが必要です。このリストに含まれないスキームを呼び出そうとすると、デバイスのログにエラーが記録され、ディープリンクは開かれません。以下はこのエラーの例です。 ``` : -canOpenURL: failed for URL: "yourapp://deeplink" – error: "This app is not allowed to query for scheme yourapp" ``` たとえば、アプリ内メッセージをタップしたときに Facebook アプリが開かれるようにするには、アプリの許可リストに Facebook カスタムスキーム (`fb`) が含まれている必要があります。含まれていないと、システムがディープリンクを拒否します。自分のアプリ内のページやビューに誘導するディープリンクでも、アプリのカスタムスキームがアプリの `Info.plist` に含まれている必要があります。 アプリがディープリンクする必要があるすべてのスキームを、キー `LSApplicationQueriesSchemes` を使用してアプリの `Info.plist` の許可リストに追加する必要があります。以下に例を示します。 ```html LSApplicationQueriesSchemes myapp facebook twitter ``` 詳細については、`LSApplicationQueriesSchemes` キーに関する [Apple のドキュメント](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/TP40009250-SW14)を参照してください。 ## ステップ 3:ハンドラを実装する {#step-3-implement-a-handler} アプリをアクティブにすると、iOS でメソッド [`application:openURL:options:`](https://developer.apple.com/reference/uikit/uiapplicationdelegate/1623112-application?language=objc) が呼び出されます。重要な引数は [NSURL](https://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSURL) オブジェクトです。 ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *path = [url path]; NSString *query = [url query]; // Here you should insert code to take some action based upon the path and query. return YES; } ``` ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let path = url.path let query = url.query // Here you should insert code to take some action based upon the path and query. return true } ``` ![Brazeダッシュボードでのディープリンク設定の例。](https://www.braze.com/docs/ja/ja/assets/img_archive/deep_link.png?30080909d43633ac9ca7ac8d115a686a) # ユニバーサルリンク {#universal-links} ユニバーサルリンクを使用するには、登録済みのドメインがアプリの機能に追加され、`apple-app-site-association` ファイルがアップロードされていることを確認してください。その後で、メソッド `application:continueUserActivity:restorationHandler:` を `AppDelegate` に実装します。以下に例を示します。 ```objc - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { NSURL *url = userActivity.webpageURL; // Handle url } return YES; } ``` ```swift func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { if (userActivity.activityType == NSUserActivityTypeBrowsingWeb) { let url = userActivity.webpageURL // Handle url } return true } ``` 詳細については、[Apple](https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html) を参照してください。 **Note:** デフォルトのユニバーサルリンク統合は、Brazeプッシュ通知やアプリ内メッセージとは互換性がありません。アプリケーション内のユニバーサルリンクを処理するには、[リンクのカスタマイズ](#linking-handling-customization)を参照してください。または、プッシュ通知やアプリ内メッセージでは[スキームベースのディープリンク](#step-1-registering-a-scheme)を使用することをお勧めします。 ## アプリトランスポートセキュリティ (ATS) {#app-transport-security-ats} iOS 9 では、アプリ内メッセージやプッシュ通知に埋め込まれた Web URL に影響を与える破壊的変更が導入されました。 ### ATSの要件 {#ats-requirements} [Apple のドキュメント](https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html#//apple_ref/doc/uid/TP40016198-SW14)から:「アプリトランスポートセキュリティは、アプリと Web サービス間の接続のセキュリティを向上させる機能です。この機能は、安全な接続のベストプラクティスに準拠したデフォルトの接続要件で構成されています。アプリでこのデフォルトの動作をオーバーライドして、トランスポートセキュリティを無効にできます。」 ATS は iOS 9 以降にデフォルトで適用されます。すべての接続が HTTPS を使用し、前方秘匿性を備えた TLS 1.2 で暗号化される必要があります。詳細については、[ATS を使用して接続するための要件](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35)を参照してください。Brazeによりエンドデバイスに提供されるすべての画像は、TLS 1.2 をサポートし、ATS と互換性のあるコンテンツ配信ネットワーク (「CDN」) によって処理されます。 アプリケーションの `Info.plist` で例外として指定されていない限り、これらの要件に従わない接続は次のようなエラーにより失敗します。 ``` CFNetwork SSLHandshake failed (-9801) Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred, and a secure connection to the server cannot be made." ``` ``` NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802) ``` ATS コンプライアンスは、モバイルアプリ内で開かれたリンク (クリックされたリンクのデフォルト処理) に適用され、Web ブラウザーから外部で開かれたサイトには適用されません。 ### ATS 要件の処理 {#handling-ats-requirements} ATS は、次の 3 つの方法のいずれかで処理できます。 #### すべてのリンクが ATS に準拠していることを確認する (推奨) {#confirm-all-links-are-ats-compliant-recommended} (アプリ内メッセージやプッシュキャンペーンから) ユーザーを誘導する既存のリンクが ATS の要件を満たすようにすることで、Braze 統合が ATS 要件を満たすことができます。ATS の制限を回避する方法はありますが、リンクされたすべての URL が ATS に準拠するようにすることをお勧めします。Apple がアプリケーションのセキュリティをこれまで以上に重視していることを考えると、ATS の例外を許可する以下のアプローチが Apple によってサポートされる保証はありません。 SSL ツールにより、Web サーバーのセキュリティの問題を正確に特定できます。この Qualys, Inc. の [SSL サーバーテスト](https://www.ssllabs.com/ssltest/index.html)は、Apple ATS 9 および iOS 9 への準拠に特化した項目を提供します。 #### ATS を一部無効にする {#partially-disable-ats} 特定のドメインやスキームのリンクのサブセットを ATS ルールの例外として処理することを許可できます。Braze メッセージングチャネルで使用するすべてのリンクが ATS に準拠しているか、例外として処理されている場合、Braze 統合は ATS 要件を満たします。 ATS の例外としてドメインを追加するには、アプリの `Info.plist` ファイルに以下を追加します。 ```html NSAppTransportSecurity NSAllowsArbitraryLoads NSExceptionDomains example.com NSExceptionAllowsInsecureHTTPLoads NSIncludesSubdomains ``` 詳細については、[アプリトランスポートセキュリティのキー](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33)に関する Apple の記事を参照してください。 #### ATS を完全に無効にする {#disable-ats-entirely} ATS を完全に無効にできます。ただし、セキュリティ保護が失われることと、将来の iOS との互換性の両方を考慮して、この方法は推奨されないことに注意してください。ATS を無効にするには、アプリの `Info.plist` ファイルに以下を挿入します。 ```html NSAppTransportSecurity NSAllowsArbitraryLoads ``` ATS エラーをデバッグする方法の詳細については、[Shipping an App With App Transport Security](http://timekl.com/blog/2015/08/21/shipping-an-app-with-app-transport-security/?utm_campaign=iOS+Dev+Weekly&utm_medium=email&utm_source=iOS_Dev_Weekly_Issue_213) を参照してください。 ## URL エンコーディング {#url-encoding} Braze iOS SDK v2.21.0 以降、SDKはリンクをパーセントエンコードして有効な `NSURL` を作成します。適切な形式の URL で使用できないリンク文字 (Unicode 文字など) は、すべてパーセントエスケープされます。 エンコードされたリンクをデコードするには、`NSString` メソッド [`stringByRemovingPercentEncoding`](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/index.html#//apple_ref/occ/instm/NSString/stringByRemovingPercentEncoding) を使用します。また、`ABKURLDelegate` で `YES` を返す必要があり、アプリによる URL の処理をトリガーするには、CTA が必要です。以下に例を示します。 ```objc - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { NSString *urlString = url.absoluteString.stringByRemovingPercentEncoding; // Handle urlString return YES; } ``` ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let urlString = url.absoluteString.removingPercentEncoding // Handle urlString return true } ``` ## カスタマイズ {#linking-customization} ### デフォルト WebView のカスタマイズ {#default-webview-customization} カスタマイズ可能な `ABKModalWebViewController` クラスは、通常 Web ディープリンクに対して「アプリ内で Web URL を開く」が選択されている場合に、SDKによって開かれる Web URL を表示します。 `ABKModalWebViewController` クラスのカテゴリを宣言するか、直接変更して、Web ビューにカスタマイズを適用できます。詳細については、このクラスの [.h ファイル](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKModalWebViewController.h)と [.m ファイル](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/ABKModalWebViewController.m)をご確認ください。 ### リンク処理のカスタマイズ {#linking-handling-customization} `ABKURLDelegate` プロトコルを使用して、ディープリンク、Web URL、ユニバーサルリンクなどの URL の処理をカスタマイズできます。Brazeの初期化中にデリゲートを設定するには、[`startWithApiKey:inApplication:withAppboyOptions:`](https://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#aa9f1bd9e4a5c082133dd9cc344108b24) の `appboyOptions` の `ABKURLDelegateKey` にデリゲートオブジェクトを渡します。その後、Brazeは URI を処理する前にデリゲートの `handleAppboyURL:fromChannel:withExtras:` 実装を呼び出します。 #### 統合の例:ABKURLDelegate {#integration-example-abkurldelegate} ```objc - (BOOL)handleAppboyURL:(NSURL *)url fromChannel:(ABKChannel)channel withExtras:(NSDictionary *)extras { if ([[url.host lowercaseString] isEqualToString:@"MY-DOMAIN.com"]) { // Custom handle link here return YES; } // Let Braze handle links otherwise return NO; } ``` ```swift func handleAppboyURL(_ url: URL?, from channel: ABKChannel, withExtras extras: [AnyHashable : Any]?) -> Bool { if (url.host == "MY-DOMAIN.com") { // Custom handle link here return true; } // Let Braze handle links otherwise return false; } ``` **Important:** `handleAppboyURL:fromChannel:withExtras:` が `YES` を返すと、Brazeはアプリが URL を処理していると見なし、URL を開きません。ユニバーサルリンクを処理している場合は、`application:continueUserActivity:restorationHandler:` を自分で呼び出すなどして、URL をアプリのユニバーサルリンクハンドラに明示的にルーティングする必要があります。URL を処理せずに `YES` を返すと、アプリ内メッセージまたはコンテンツカードが目に見えるアクションなしに閉じられます。 Brazeにデフォルトの動作で URL を処理させたい場合は、`NO` を返してください。 詳細については、[`ABKURLDelegate.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/ABKURLDelegate.h) を参照してください。 ## よくあるユースケース {#frequent-use-cases} ### アプリ設定へのディープリンク {#deep-linking-to-app-settings} iOS は、アプリから iOS 設定アプリケーションのページにユーザーを誘導できます。`UIApplicationOpenSettingsURLString` を利用して、プッシュ通知やアプリ内メッセージから設定にユーザーをディープリンクできます。 1. まず、アプリケーションが[スキームベースのディープリンク](#deep-links)または[ユニバーサルリンク](#universal-links)用に設定されていることを確認します。 2. **設定**ページへのディープリンクの URI (`myapp://settings` や `https://www.braze.com/settings` など) を決定します。 3. カスタムスキームベースのディープリンクを使用している場合は、`application:openURL:options:` メソッドに次のコードを追加します。 ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *path = [url path]; if ([path isEqualToString:@"settings"]) { NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; [[UIApplication sharedApplication] openURL:settingsURL]; } return YES; } ``` ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { let path = url.path if (path == "settings") { UIApplication.shared.openURL(URL(string:UIApplicationOpenSettingsURLString)!) } return true } ``` # iOS 向けのきめ細かなネットワークトラフィック制御 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/advanced_use_cases/fine_network_traffic_control/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # きめ細かなネットワークトラフィック制御 ## リクエスト処理ポリシー Braze では、ユーザーに対し、以下のプロトコルを使用してネットワーク トラフィックを制御するオプションが提供されます。 ### 自動リクエスト処理 ***`ABKRequestProcessingPolicy` 列挙値: `ABKAutomaticRequestProcessing`*** - これが**デフォルトのリクエストポリシー**値です。 - Braze SDK では、以下を含むすべてのサーバー通信が自動的に処理されます。 - カスタムイベントと属性データの Braze サーバーへのフラッシュ - コンテンツカードとジオフェンスの更新 - 新しいアプリ内メッセージのリクエスト - アプリ内メッセージなどの Braze 機能にユーザー向けデータが必要である場合に、即時サーバーリクエストが実行されます。 - サーバーの負荷を最小限に抑えるため、Braze では新規ユーザーデータの定期フラッシュが数秒ごとに実行されます。 データは、次の方法を使用して、いつでも手動で Braze サーバーにフラッシュできます。 ```objc [[Appboy sharedInstance] flushDataAndProcessRequestQueue]; ``` `````````swift Appboy.sharedInstance()?.flushDataAndProcessRequestQueue() ``` ### 手動リクエスト処理 ***`ABKRequestProcessingPolicy` 列挙値: `ABKManualRequestProcessing`*** - このプロトコルは、次の点を除いて自動リクエスト処理と同じです。 - カスタム属性とカスタムイベントデータが、ユーザーセッションを通じてサーバーに自動でフラッシュされません。 - Braze で、アプリ内メッセージのリクエスト、アプリ内メッセージの Liquid テンプレート、ジオフェンス、位置情報の追跡などの内部機能に対する自動ネットワークリクエストが実行されます。詳細については、[`Appboy.h`](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/Appboy.h) で `ABKRequestProcessingPolicy` の宣言を参照してください。これらの内部リクエストが実行されると、リクエストのタイプによっては、ローカルに保存されたカスタム属性とカスタムイベントデータが Braze サーバーにフラッシュされる場合があります。 データは、次の方法を使用して、いつでも手動で Braze サーバーにフラッシュできます。 `````````objc [[Appboy sharedInstance] flushDataAndProcessRequestQueue]; ``` `````````swift Appboy.sharedInstance()?.flushDataAndProcessRequestQueue() ``` ## リクエスト処理ポリシーの設定 ### 起動時のリクエストポリシーの設定 これらのポリシーは、アプリの起動時に [`startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions`](https://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#aa9f1bd9e4a5c082133dd9cc344108b24) メソッドから設定できます。`appboyOptions` ディクショナリで、次のコードスニペットに示すように `ABKRequestProcessingPolicyOptionKey` を設定します。 `````````objc NSDictionary *appboyOptions = @{ // Other entries ABKRequestProcessingPolicyOptionKey : @(ABKAutomaticRequestProcessing) }; ``` `````````swift let appboyOptions: [AnyHashable: Any] = [ // Other entries ABKRequestProcessingPolicyOptionKey: ABKRequestProcessingPolicy.automaticRequestProcessing.rawValue ] ``` ### 実行時のリクエストポリシーの設定 リクエスト処理ポリシーは、`requestProcessingPolicy` プロパティを `Appboy` で使用することで実行時に設定することもできます。 `````````objc // Sets the request processing policy to automatic (the default value) [Appboy sharedInstance].requestProcessingPolicy = ABKAutomaticRequestProcessing; ``` `````````swift // Sets the request processing policy to automatic (the default value) Appboy.sharedInstance()?.requestProcessingPolicy = ABKRequestProcessingPolicy.automaticRequestProcessing ``` ## 実行中のサーバー通信の手動シャットダウン 「実行中」のサーバー通信を停止する必要がある場合は、次のメソッドを呼び出す必要があります。 `````````objc [[Appboy sharedInstance] shutdownServerCommunication]; ``` `````````swift Appboy.sharedInstance()?.shutdownServerCommunication(); ``` このメソッドを呼び出した後、リクエスト処理モードを自動にリセットする必要があります。そのため、OS がバックグラウンドタスクなどの停止を強制している場合にのみ、これを呼び出すことをお勧めします。 # iOS のローカライゼーション Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/advanced_use_cases/localization/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # ローカライゼーション {#localization} ローカライゼーションはBraze iOS SDK内でサポートされています。Brazeは英語に加えて、組み込みSDKメッセージ用にいくつかの言語をサポートしています。これらは、接続に問題がある場合など、Brazeと統合されたアプリケーションに表示されるデフォルトのメッセージに関連します(例:「ネットワーク接続を確立できません。後でもう一度やり直してください。」)。スマートフォンの言語がサポートされている言語のいずれかに設定されている場合、統合アプリケーション内でトリガーされたBrazeのデフォルト文字列は、自動的にその言語で表示されます。 ユーザーがプロファイルで選択できるサポート言語の完全なリストをお探しの場合は、[ユーザー言語リスト](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/language_codes)を参照してください。 ## サポートされている言語 {#languages-supported} - アラビア語 - ビルマ語 - カタルーニャ語 - 中国語 - チェコ語 - デンマーク語 - オランダ語 - 英語 - エスペラント語 - エストニア語 - エウェ語 - フィリピン語 - フィンランド語 - フランス語 - ジョージア語 - ドイツ語 - ギリシア語 - ヘブライ語 - ヒンディー語 - ハンガリー語 - インドネシア語 - アイルランド語 - イタリア語 - 日本語 - 韓国語 - マレー語 - ノルウェー語 - 新ノルウェー語 - ポーランド語 - ポルトガル語 - ロシア語 - スペイン語 - スウェーデン語 - タイ語 - ウクライナ語 - ベトナム語 詳細については、[Appleのローカライゼーション](https://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFLocaleRef/)に関する記事と[LOC標準言語リスト](http://www.loc.gov/standards/iso639-2/php/English_list.php)を参照してください。 # iOS 向けビーコン統合 Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/advanced_use_cases/beacon_integration/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # ビーコンの統合 {#beacon-integration} ここでは、特定の種類のビーコンをBrazeと統合して、セグメンテーションとメッセージングを可能にする方法について説明します。 ## Infillion ビーコン {#infillion-beacons} Infillion ビーコンを設定してアプリに統合すると、カスタムイベント(アクセスの開始または終了、ビーコンの検知など)をログに記録できます。これらのイベントのプロパティ(場所の名前、滞在時間など)をログに記録することもできます。 ユーザーが場所に入ったときにカスタムイベントをログに記録するには、次のコードを `didBeginVisit` メソッドに入力します。 ```objc [[Appboy sharedInstance] logCustomEvent:@"Entered %@", visit.place.name]; [[Appboy sharedInstance] flushDataAndProcessRequestQueue]; ``` `````````swift Appboy.sharedInstance()?.logCustomEvent("Entered %@", visit.place.name) Appboy.sharedInstance()?.flushDataAndProcessRequestQueue() ``` `flushDataAndProcessRequestQueue` は、アプリがバックグラウンドで実行されている場合でもイベントが必ずログに記録されることを確認します。これと同じプロセスを、ロケーションから離れる行動についても実装できます。これにより、ユーザーが新しい場所に入るたびにユニークなカスタムイベントが作成され、インクリメントされることに注意してください。50か所を超える場所を作成する予定の場合は、汎用的な「Place Entered」カスタムイベントを1つ作成し、イベントプロパティとして場所名を含めることをお勧めします。 # iOSの位置情報とジオフェンス Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/advanced_use_cases/locations_and_geofences/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # 位置情報とジオフェンス {#locations-and-geofences} iOSのジオフェンスをサポートするには: 1. 統合がバックグラウンドプッシュ通知に対応している必要があります。 2. Brazeジオフェンスを、SDKを通じて有効にする必要があります。位置情報の収集を有効にする(暗黙的)か、ジオフェンスの収集を明示的に[有効にする](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/analytics/location_tracking#enabling-automatic-location-tracking)ことで設定できます。デフォルトでは有効になっていません。 **Important:** iOS 14の時点では、おおよその位置情報の提供許可を選択しているユーザーの場合、ジオフェンスが確実に機能しないことがあります。 ## ステップ 1:バックグラウンドプッシュを有効にする {#step-1-enable-background-push} ジオフェンス同期戦略を完全に使用するには、標準のプッシュ統合に加えて、[バックグラウンドプッシュ](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/ios/push_notifications/silent_push_notifications#use-silent-remote-notifications-to-trigger-background-work)を有効にする必要があります。 ## ステップ 2:ジオフェンスを有効にする {#step-2-enable-geofences} デフォルトでは、ジオフェンスは位置情報の自動収集が有効かどうかに基づいて有効になります。ジオフェンスを有効にするには、`Info.plist` ファイルを使用します。`Braze` ディクショナリを `Info.plist` ファイルに追加します。`Braze` ディクショナリ内にブール値の `EnableGeofences` サブエントリを追加し、値を `YES` に設定します。なお、Braze iOS SDK v4.0.2より前のバージョンでは、`Braze` の代わりにディクショナリキー `Appboy` を使用する必要があります。 また、[`startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions`](https://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#aa9f1bd9e4a5c082133dd9cc344108b24) メソッドを使用して、アプリの起動時にジオフェンスを有効にすることもできます。`appboyOptions` ディクショナリで、`ABKEnableGeofencesKey` を `YES` に設定します。以下に例を示します。 ```objc [Appboy startWithApiKey:@"YOUR-API_KEY" inApplication:application withLaunchOptions:options withAppboyOptions:@{ ABKEnableGeofencesKey : @(YES) }]; ``` ```swift Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:[ ABKEnableGeofencesKey : true ]) ``` ## ステップ 3:Brazeのバックグラウンドプッシュを確認する {#step-3-check-for-braze-background-push} Brazeでは、バックグラウンドプッシュ通知を使用してジオフェンスがデバイスと同期されます。[iOSのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/customization/ignoring_internal_push)に関する記事に従って、Brazeのジオフェンス同期通知を受信したときにアプリケーションで不要なアクションが実行されないようにしてください。 ## ステップ 4:NSLocationAlwaysUsageDescriptionをInfo.plistに追加する {#step-4-add-nslocationalwaysusagedescription-to-your-infoplist} アプリケーションで位置情報を追跡する必要がある理由の説明を含んだ `String` 値を使用して、キー `NSLocationAlwaysUsageDescription` および `NSLocationAlwaysAndWhenInUseUsageDescription` を `info.plist` に追加します。iOS 11以降では両方のキーが必要です。 この説明は、システムの位置情報プロンプトで許可がリクエストされるときに表示されるため、ユーザーに位置情報の追跡の利点を明確に説明する必要があります。 ## ステップ 5:ユーザーに許可をリクエストする {#step-5-request-authorization-from-the-user} ジオフェンス機能は、位置情報に対する許可 `Always` が付与されている場合にのみ機能します。 位置情報許可 `Always` をリクエストするには、次のコードを使用します。 ```objc CLLocationManager *locationManager = [[CLLocationManager alloc] init]; [locationManager requestAlwaysAuthorization]; ``` ```swift var locationManager = CLLocationManager() locationManager.requestAlwaysAuthorization() ``` ## ステップ 6:ダッシュボードでジオフェンスを有効にする {#step-6-enable-geofences-on-the-dashboard} iOSでは、1つのアプリに保存できるジオフェンスは20個までとなっています。位置情報を使用すると、これら20個の使用可能なジオフェンススロットの一部が使用されます。アプリ内の他のジオフェンス関連機能への偶発的または不要な中断を防ぐため、位置情報ジオフェンスはダッシュボード上で個々のアプリに対して有効にする必要があります。 位置情報が正しく動作するには、アプリが利用可能なジオフェンススポットをすべて使用していないことも確認する必要があります。 ### ロケーションページからジオフェンスを有効にする {#enable-geofences-from-the-locations-page} ![Brazeのロケーションページにあるジオフェンスのオプション。](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-locations-page.png?4bf8451a2e59f1723b529fa8ff43b7f7) ### 設定ページからジオフェンスを有効にする {#enable-geofences-from-the-settings-page} ![Brazeの設定ページにあるジオフェンスのチェックボックス。](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-app-settings-page.png?702b6b77bb33116e03d8ba576f4e62f9) ## 自動ジオフェンスリクエストを無効にする {#disabling-automatic-geofence-requests} iOS SDKバージョン3.21.3以降では、ジオフェンスが自動的にリクエストされないようにすることができます。これを行うには、`Info.plist` ファイルを使用します。`Braze` ディクショナリを `Info.plist` ファイルに追加します。`Braze` ディクショナリ内にブール値の `DisableAutomaticGeofenceRequests` サブエントリを追加し、値を `YES` に設定します。 [`startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions`](https://appboy.github.io/appboy-ios-sdk/docs/interface_appboy.html#aa9f1bd9e4a5c082133dd9cc344108b24) メソッドを使用して、アプリの起動時に自動ジオフェンスリクエストを無効にすることもできます。`appboyOptions` ディクショナリで、`ABKDisableAutomaticGeofenceRequestsKey` を `YES` に設定します。以下に例を示します。 ```objc [Appboy startWithApiKey:@"YOUR-API_KEY" inApplication:application withLaunchOptions:options withAppboyOptions:@{ ABKDisableAutomaticGeofenceRequestsKey : @(YES) }]; ``` ```swift Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:[ ABKDisableAutomaticGeofenceRequestsKey : true ]) ``` このオプションの使用を選択した場合、機能が動作するよう、ジオフェンスを手動でリクエストする必要があります。 ## ジオフェンスの手動リクエスト {#manually-requesting-geofences} Braze SDKがバックエンドに対して監視対象のジオフェンスをリクエストすると、ユーザーの現在の位置情報がレポートされ、レポートされた位置情報に基づいて最も関連性が高いと判断されたジオフェンスが受信されます。ジオフェンスの更新には、各セッションで1回というレート制限があります。 SDKでレポートされる位置情報をコントロールして、最も関連性の高いジオフェンスを受信できるようにするため、iOS SDKバージョン3.21.3以降では、位置の緯度と経度を指定することでジオフェンスを手動でリクエストできるようになっています。この方法を使用する場合は、自動ジオフェンスリクエストを無効にすることをお勧めします。そのためには、次のコードを使用します。 ```objc [[Appboy sharedInstance] requestGeofencesWithLongitude:longitude latitude:latitude]; ``` ```swift Appboy.sharedInstance()?.requestGeofences(withLongitude: longitude, latitude: latitude) ``` # Google Tag Manager for iOS Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/advanced_use_cases/google_tag_manager/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # Google Tag Manager for iOS {#google-tag-manager-for-ios} ## SDKの初期化 {#initializing-ios-google-tag-provider} Braze iOS SDKは、[Google Tag Manager](https://tagmanager.google.com/)で設定されたタグによって初期化および制御することができます。 Google Tag Managerを使用する前に、まず[SDKの初期設定](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/initial_sdk_setup/overview)を行ってください。 ## Google Tag Managerの設定 {#configuring-ios-google-tag-manager} この例では、ユーザーが曲を聴いている間に別のイベントをロギングする必要がある音楽ストリーミングアプリを想定しています。Google Tag Manager for iOSを使用して、どのサードパーティベンダーがこのイベントを受信するかをコントロールし、Braze固有のタグを作成できます。 ### カスタムイベント {#custom-events} カスタムイベントは、`logEvent` に設定した `actionType` によってログに記録されます。この例のBrazeカスタムタグプロバイダーは、`eventName` を使用してカスタムイベント名を設定することを想定しています。 最初に、`played song` である「イベント名」を検索するトリガーを作成します。 ![「eventName」が「played song」である場合に一部のイベントに対してトリガーするよう設定されたGoogle Tag Managerのカスタムトリガー。](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_trigger.png?ce7d5cd1e1ab6a285076d8429ac796bd) 次に、新しいタグ(「Function Call」とも呼ばれます)を作成し、この記事で後述する[カスタムタグプロバイダー](#adding-ios-google-tag-provider)のクラスパスを入力します。 このタグは、先ほど作成した `played song` イベントをロギングするとトリガーされます。 サンプルタグのカスタムパラメーター(キーと値のペア)では、`eventName` を `played song` に設定しました。これが、Brazeにロギングされるカスタムイベント名になります。 **Important:** カスタムイベントの送信時に、`actionType` を `logEvent` に設定し、次の例のように `eventName` の値を設定します。 この例のカスタムタグプロバイダーは、これらのキーを使用して、Google Tag Managerからデータを受信した際に実行するアクションとBrazeに送信するイベント名を決定します。 ![classpathフィールドと、キーと値のペアフィールドを含むGoogle Tag Managerのタグ。このタグは、以前に作成された「再生された曲」トリガーでトリガーされるように設定されています。](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_function_call_tag.png?40fad5b2a61b7d2183f635a10e290252) また、追加のキーと値のペア引数をタグに含めることもできます。この引数は、カスタムイベントプロパティとしてBrazeに送信されます。`eventName` および `actionType` は、カスタムイベントプロパティでは無視されません。次のサンプルタグでは、`genre` を渡します。これは、Google Tag Managerでタグ変数を使用して定義されており、アプリでロギングしたカスタムイベントから取得されます。 `genre` イベントプロパティは、「Firebase - Event Parameter」変数としてGoogle Tag Managerに送信されます。Google Tag Manager for iOSでは、Firebaseがデータレイヤーとして使用されるためです。 ![「genre」が「Braze - Played Song Event」タグのイベントパラメーターとして追加されるGoogle Tag Managerの変数。](https://www.braze.com/docs/ja/ja/assets/img/android_google_tag_manager/gtm_android_eventname_variable.png?abff82f38b65ae64ad0ae3842d2ea439) 最後に、ユーザーがアプリで曲を再生すると、タグのトリガー名 `played song` と一致するFirebase分析イベント名を使用し、FirebaseとGoogle Tag Managerを介してイベントがロギングされます。 ```obj-c NSDictionary *parameters = @{@"genre" : @"pop", @"number of times listened" : @42}; [FIRAnalytics logEventWithName:@"played song" parameters:parameters]; ``` ### カスタム属性のロギング {#logging-custom-attributes} カスタム属性は、`customAttribute` に設定された `actionType` を介して設定されます。Brazeカスタムタグプロバイダーは、カスタム属性のキーと値が `customAttributeKey` および `customAttributeValue` を介して設定されることを想定しています。 ```obj-c NSDictionary *parameters = @{@"customAttributeKey" : @"favorite song", @"customAttributeValue" : @"Private Eyes"}; [FIRAnalytics logEventWithName:@"customAttribute" parameters:parameters]; ``` ### changeUserの呼び出し {#calling-changeuser} `changeUser()` の呼び出しは、`changeUser` に設定された `actionType` を介して行われます。Brazeカスタムタグプロバイダーは、BrazeユーザーIDがタグ内のキーと値のペア `externalUserId` を介して設定されることを想定しています。 ```obj-c NSDictionary *parameters = @{@"externalUserId" : userId}; [FIRAnalytics logEventWithName:@"changeUser" parameters:parameters]; ``` ## Braze SDKカスタムタグプロバイダー {#adding-ios-google-tag-provider} タグとトリガーが設定されたら、iOSアプリにGoogle Tag Managerを実装する必要もあります。これについては、Googleの[ドキュメント](https://developers.google.com/tag-manager/ios/v5/)に記載されています。 Google Tag Managerがアプリにインストールされたら、カスタムタグプロバイダーを追加し、Google Tag Manager内で設定したタグに基づいてBraze SDKメソッドを呼び出します。 ファイルへの「Class Path」を必ず書き留めておいてください。[Google Tag Manager](https://tagmanager.google.com/)コンソールでタグを設定するときに入力する内容です。 この例は、カスタムタグプロバイダーを構築する多くの方法の1つを示しています。ここでは、GTMタグから送信されたキーと値のペア `actionType` に基づいて、呼び出すBraze SDKメソッドを決定します。 この例でサポートされている `actionType` は `logEvent`、`customAttribute`、`changeUser` ですが、タグプロバイダーによるGoogle Tag Managerからのデータの処理方法を変更することもできます。 以下のコードを `BrazeGTMTagManager.h` ファイルに追加します。 ```obj-c @import Firebase; @import GoogleTagManager; @interface BrazeGTMTagManager : NSObject @end ``` 以下のコードを `BrazeGTMTagManager.m` ファイルに追加します。 ```obj-c #import #import "BrazeGTMTagManager.h" #import "Appboy-iOS-SDK/AppboyKit.h" static NSString *const ActionTypeKey = @"actionType"; // Custom Events static NSString *const LogEventActionType = @"logEvent"; static NSString *const LogEventEventName = @"eventName"; // Custom Attributes static NSString *const CustomAttributeActionType = @"customAttribute"; static NSString *const CustomAttributeKey = @"customAttributeKey"; static NSString *const CustomAttributeValueKey = @"customAttributeValue"; // Change User static NSString *const ChangeUserActionType = @"changeUser"; static NSString *const ChangeUserExternalUserId = @"externalUserId"; @implementation BrazeGTMTagManager - (NSObject *)executeWithParameters:(NSDictionary *)parameters { NSMutableDictionary *mutableParameters = [parameters mutableCopy]; NSString *actionType = mutableParameters[ActionTypeKey]; if (!actionType) { NSLog(@"There is no Braze action type key in this call. Doing nothing.", nil); return nil; } [mutableParameters removeObjectForKey:ActionTypeKey]; if ([actionType isEqualToString:LogEventActionType]) { [self logEvent:mutableParameters]; } else if ([actionType isEqualToString:CustomAttributeActionType]) { [self logCustomAttribute:mutableParameters]; } else if ([actionType isEqualToString:ChangeUserActionType]) { [self changeUser:mutableParameters]; } else { NSLog(@"Invalid action type. Doing nothing."); } return nil; } - (void)logEvent:(NSMutableDictionary *)parameters { NSString *eventName = parameters[LogEventEventName]; [parameters removeObjectForKey:LogEventEventName]; [[Appboy sharedInstance] logCustomEvent:eventName withProperties:parameters]; } - (void)logCustomAttribute:(NSMutableDictionary *)parameters { NSString *customAttributeKey = parameters[CustomAttributeKey]; id customAttributeValue = parameters[CustomAttributeValueKey]; if ([customAttributeValue isKindOfClass:[NSString class]]) { [[Appboy sharedInstance].user setCustomAttributeWithKey:customAttributeKey andStringValue:customAttributeValue]; } else if ([customAttributeValue isKindOfClass:[NSDate class]]) { [[Appboy sharedInstance].user setCustomAttributeWithKey:customAttributeKey andDateValue:customAttributeValue]; } else if ([customAttributeValue isKindOfClass:[NSNumber class]]) { if (strcmp([customAttributeValue objCType], [@(YES) objCType]) == 0) { [[Appboy sharedInstance].user setCustomAttributeWithKey:customAttributeKey andBOOLValue:[(NSNumber *)customAttributeValue boolValue]]; } else if (strcmp([customAttributeValue objCType], @encode(short)) == 0 || strcmp([customAttributeValue objCType], @encode(int)) == 0 || strcmp([customAttributeValue objCType], @encode(long)) == 0) { [[Appboy sharedInstance].user setCustomAttributeWithKey:customAttributeKey andIntegerValue:[(NSNumber *)customAttributeValue integerValue]]; } else if (strcmp([customAttributeValue objCType], @encode(float)) == 0 || strcmp([customAttributeValue objCType], @encode(double)) == 0) { [[Appboy sharedInstance].user setCustomAttributeWithKey:customAttributeKey andDoubleValue:[(NSNumber *)customAttributeValue doubleValue]]; } else { NSLog(@"Could not map NSNumber value to Appboy custom attribute:%@", customAttributeValue); } } else if ([customAttributeValue isKindOfClass:[NSArray class]]) { [[Appboy sharedInstance].user setCustomAttributeArrayWithKey:customAttributeKey array:customAttributeValue]; } } - (void)changeUser:(NSMutableDictionary *)parameters { NSString *userId = parameters[ChangeUserExternalUserId]; [[Appboy sharedInstance] changeUser:userId]; } @end ``` # iOS 用ストレージ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/storage/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # ストレージ {#storage} この記事では、Braze iOS SDKを使用する際にキャプチャされるさまざまなデバイスレベルのプロパティについて説明します。 ## デバイスのプロパティ {#device-properties} デフォルトでは、Brazeは以下の[デバイスレベルプロパティ](https://github.com/Appboy/appboy-ios-sdk/blob/16e893f2677af7de905b927505d4101c6fb2091d/AppboyKit/headers/AppboyKitLibrary/Appboy.h#L181)を収集し、デバイス、言語、タイムゾーンベースのメッセージのパーソナライゼーションを可能にします。 * デバイスの解像度 * デバイスの通信事業者 * デバイスのロケール * デバイスモデル * デバイスOSのバージョン * IDFV([iOS SDK v5.7.0以上](https://github.com/braze-inc/braze-swift-sdk)ではオプション) * プッシュ有効 * デバイスのタイムゾーン * プッシュ許可ステータス * 広告のトラッキングが有効 **Note:** Braze SDKはIDFAを自動的に収集しません。アプリはオプションで、`ABKIDFADelegate` プロトコルを実装することでIDFAをBrazeに渡すことができます。アプリはIDFAをBrazeに渡す前に、App Tracking Transparencyフレームワークを通じてエンドユーザーによるトラッキングへの明示的なオプトインを取得する必要があります。 設定可能なデバイスフィールドは、[`ABKDeviceOptions`](https://github.com/Appboy/appboy-ios-sdk/blob/4390e9eac8401bccdb81b053fa54eb87b1f6fcaa/Appboy-tvOS-SDK/AppboyTVOSKit.framework/Headers/Appboy.h#L179) 列挙型で定義されます。許可リストに登録したいデバイスフィールドを無効化または指定するには、`startWithApiKey:inApplication:withAppboyOptions:` の `appboyOptions` で目的のフィールドのビット単位の `OR` を [`ABKDeviceAllowlistKey`](https://github.com/Appboy/appboy-ios-sdk/blob/fed071000722673754da288cace15c1ff8aca432/AppboyKit/include/Appboy.h#L148) に割り当てます。 たとえば、許可リストに登録するタイムゾーンとロケールの収集を指定するには、次のように設定します。 ``` appboyOptions[ABKDeviceAllowlistKey] = @(ABKDeviceOptionTimezone | ABKDeviceOptionLocale); ``` デフォルトでは、すべてのフィールドが有効になっています。いくつかのプロパティがないと一部の機能が正しく機能しないことがあるので注意してください。たとえば、ローカルタイムゾーンの配信はタイムゾーンなしでは機能しません。 自動的に収集されるデバイスプロパティの詳細については、[SDKデータ収集](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/sdk_data_collection)をご覧ください。 # iOS 用サンプルアプリ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/sample_apps/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # サンプルアプリ {#sample-apps} Braze SDKにはそれぞれ、利便性を高めるためにリポジトリ内にサンプルアプリケーションが付属しています。これらのアプリはそれぞれ完全にビルド可能であるため、独自のアプリケーション内で実装すると同時に、Brazeの機能をテストできます。ご自身のアプリケーション内での動作のテストと、サンプルアプリケーション内での予期される動作やコードパスとの比較は、問題が発生した場合にデバッグするための優れた方法です。 ## テストアプリケーションのビルド {#building-test-applications} [iOS SDK GitHub リポジトリ](https://github.com/appboy/appboy-ios-sdk)では、いくつかのテストアプリケーションを使用できます。以下の手順に従って、テストアプリケーションをビルドして実行します。 1. 新しい[ワークスペース](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/app_group_configuration#creating-your-app-group-in-my-apps)を作成し、アプリ識別子APIキーを書き留めます。 2. APIキーを `AppDelegate.m` ファイルの適切なフィールドに配置します。 iOSテストアプリケーションのプッシュ通知には、追加の設定が必要です。詳細については、[iOSプッシュ統合](https://www.braze.com/docs/ja/ja/developer_guide/platforms/legacy_sdks/ios/push_notifications/integration)を参照してください。 # iOS Swift SDK の変更ログ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/changelog/swift_changelog/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS Swift SDK 変更ログ

17.0.0

Breaking
  • Braze.init and changeUser(userId:) no longer block the calling thread.
  • The following properties now block the calling thread until the SDK has settled, ensuring they reflect the latest user state immediately after changeUser or Braze.init:
    • braze.user.id
    • braze.deviceId
    • braze.contentCards.cards
    • braze.contentCards.unviewedCards
    • braze.contentCards.lastUpdate
    • braze.featureFlags.featureFlags
    • braze.featureFlags.featureFlag(id:)
    • For UI and other latency-sensitive code paths, prefer the asynchronous getters (getCachedContentCards(_:), getUnviewedCards(_:), getLastUpdate(_:), getAllFeatureFlags(_:)).
  • braze.user.id now returns nil after calling wipeData().
    • Previously, braze.user.id continued to return the last user ID after wipeData().
    • This matches the Swift SDK’s behavior with that of the Android SDK.
  • changeUser now notifies Braze.ContentCards.subscribeToUpdates(_:) subscribers after a user switch, matching the existing Android SDK behavior.
    • Previously, subscribers were not notified until the next Content Cards sync.
  • Removes the deprecated push-to-start token update API on Braze.LiveActivities.
    • Removes the deprecated Braze.LiveActivities.PushToStartTokenUpdate enum and the pushToStartTokenUpdatesStream property.
    • Use subscribeToStateUpdates(_:) instead, which delivers the push-to-start token lifecycle events (UpdateEvent.ActivityType.pushToStartTokenRead, .pushToStartTokenFlushed, .pushToStartOptedOut, .pushToStartOptOutFlushed) as part of the complete Live Activities lifecycle in a single subscription.
Added
  • Adds non-blocking asynchronous accessors for user and device identifiers:
    • Braze.User.getId(_:) and Braze.User.getId() async — deliver on the main thread.
    • Braze.getDeviceId(_:) and Braze.getDeviceId() async — deliver on the main thread.
    • ObjC bridges: getIdWithCompletion: and getDeviceIdWithCompletion:.
    • Prefer these over the synchronous properties on the main thread or in @MainActor contexts.
  • Adds an sdkDisabled error on Braze.ContentCards.requestRefresh(_:), Braze.FeatureFlags.requestRefresh(_:), and Braze.Banners.requestBannersRefresh(_:). When the SDK is disabled, these now invoke their completion handler with .sdkDisabled instead of leaving it uncalled.

16.0.0

Breaking
  • Updates to Content Cards behavior and reliability
    • braze.contentCards.cards is now immediately updated after a card is marked as viewed, dismissed, or clicked via its context.
      • Previously, these mutations were only visible in braze.contentCards.cards after the next server sync.
    • Disabling Content Cards via Braze.Configuration now immediately clears braze.contentCards.cards and notifies subscribeToUpdates subscribers with an empty list.
      • Previously, braze.contentCards.cards retained its last value and subscribers were not notified.
Added
  • Adds Braze.FeatureFlags.getAllFeatureFlags(_:) — an asynchronous, callback-based getter that delivers cached feature flags on the main thread without blocking the calling thread.

15.2.0

Added
  • Adds optional subtotalValue, tax, and shipping fields to Braze.Ecommerce.OrderPlacedEvent, all Braze.Ecommerce.CartUpdated variants (Replace / Add / Remove), and Braze.Ecommerce.CheckoutStartedEvent.
    • Available in Objective-C on BRZEcommerceOrderPlacedEvent, BRZEcommerceCartUpdatedEvent, and BRZEcommerceCheckoutStartedEvent.
Fixed
  • Fixes a video player configuration error for embedded YouTube videos in HTML in-app messages.

15.1.0

Added
  • Adds dismiss() to Braze.Banner.Context and dismiss(using:) to Braze.Banner to dismiss a banner when using a custom UI.
    • Recommended to use Braze.Banner.Context.dismiss.
    • Both methods must be called from the main thread.
    • Calling either method fires the onDismiss callback on any registered BrazeBannerPlacement for that placement ID.
    • Available in Objective-C as -[BRZBannerContext dismiss] and -[BRZBanner dismissUsing:].
  • Adds example implementations for building a custom UI with banners.
  • Adds Braze.ContentCards.getCachedContentCards(_:), Braze.ContentCards.getUnviewedCards(_:), and Braze.ContentCards.getLastUpdate(_:) — asynchronous, callback-based getters that deliver on the main thread.
Fixed
  • Fixes a bug in the default Content Cards UI that would prevent image loading if multiple cards contained the same remote image URL. (#176)
    • If multiple cards contained the same image URL, only the first card to finish loading would display the image, whereas all others would indefinitely display the loading spinner.

15.0.1

Fixed
  • Improves the stability of the SDK’s internal state management, resolving a crash that would occur under low memory conditions.
  • getBanner now returns the cached banner immediately even when the SDK is rate limited.

15.0.0

Breaking
  • Banners: onDismiss now receives Braze/BannerDismissalEvent instead of Braze/Banner.
  • Raises the Xcode version to 26.0 (17A324).
  • Raises the minimum Mac Catalyst deployment target from iOS 13 (macOS 10.15 Catalina) to iOS 16 (macOS 13 Ventura).
    • Mac Catalyst users on macOS 12 Monterey or earlier are no longer supported.
  • Removes the ability to control whether the SDK prevents showing in-app messages to different users in certain edge cases.
    • Removes the option to configure through Braze.Configuration.preventInAppMessageDisplayForDifferentUser.
    • The SDK will now always behave as if this configuration option were set to true.
  • Updates the Braze.WebViewBridge.ScriptMessageHandler and Braze.WebViewBridge.SchemeHandler init to have non-optional channel parameter.
Added
  • Logs configuration validation messages when Braze.Configuration.devicePropertyAllowList omits pushEnabled or pushAuthStatus.
    • Both are required for push token registration and for push notifications to behave correctly.
  • Adds support for logging Braze eCommerce recommended events.
    • Creates the following new event types:
      • Braze.Ecommerce.ProductViewedEvent
      • Braze.Ecommerce.CartUpdated.Replace — full cart snapshot
      • Braze.Ecommerce.CartUpdated.Add — incremental add
      • Braze.Ecommerce.CartUpdated.Remove — incremental remove
      • Braze.Ecommerce.CheckoutStartedEvent
      • Braze.Ecommerce.OrderPlacedEvent
    • Adds the following API: Braze.logEcommerceEvent(_:)
    • Adds Objective-C compatible APIs:
      • -[Braze logEcommerceProductViewed:]
      • -[Braze logEcommerceCartUpdated:]
      • -[Braze logEcommerceCheckoutStarted:]
      • -[Braze logEcommerceOrderPlaced:]
Fixed
  • Fixes a rare race condition where the app would become unresponsive when calling changeUser or wipeData while an HTML in-app message or banner was in the middle of displaying.

14.2.1

Fixed
  • Improves the reliability of resuming the SDK’s tracking of Live Activities when there are multiple active activity types.
    • This improves the tracking of Live Activities when relaunching the app after it has been terminated.
  • Fixes a compilation issue introduced in 14.2.0 on Mac Catalyst targets caused by ActivityKit imports.

14.2.0

Added
  • Adds methods to observe all key events and errors in the ActivityKit API, enabling observation of real-time state and error events from the SDK’s Live Activity lifecycle.
Deprecated
  • Deprecates the push-to-start token update API on Braze.LiveActivities in favor of the new subscribeToStateUpdates(_:) API.
    • Deprecates the Braze.LiveActivities.PushToStartTokenUpdate enum and the pushToStartTokenUpdatesStream property.
    • Use subscribeToStateUpdates(_:) instead, which delivers the push-to-start token lifecycle events (UpdateEvent.ActivityType.pushToStartTokenRead, .pushToStartTokenFlushed, .pushToStartOptedOut, .pushToStartOptOutFlushed) as part of the complete Live Activities lifecycle in a single subscription, covering the same information as the deprecated PushToStartTokenUpdate cases without the need to maintain a separate subscription.
Fixed
  • Improves reliability of Live Activity push token updates during app background and foreground transitions, including cold start scenarios where push-to-start activities may not have received token updates.
  • Content cards now filter out invalid cards so users can still view remaining valid cards.
    • Previously, if any of the cards were invalid in the content card sync, the entire sync would be dropped and no cards would be added.
    • This update brings parity with the behavior on Android and Web.

14.1.0

Added
  • Adds support for Banner dismissal events.
  • Improves the robustness of the SDK’s internal state management.
    • This release includes an internal refactor intended to make SDK behavior more consistent. No external API changes.
  • Adds error logging for Banners operations, providing actionable diagnostics for persistence failures and invalid banner states.
Fixed
  • Improves robustness around push notification and deep link handling during delayed SDK initialization.
  • Fixes an issue where Braze.FeatureFlags.subscribeToUpdates would not trigger the update closure upon all refresh completions.
    • All refresh completions, regardless of a success or error result, will now trigger the update closure. This change brings parity with the Android and Web SDKs.
    • Previously, the update closure would not always trigger upon the completion of a refresh request, depending on whether the cached data had previously been reported.

14.0.4

Fixed
  • Fixes an issue where the configuration of push notification automation would be dropped upon every other re-initialization of the Braze instance.

14.0.3

Fixed
  • Push Stories now filter out invalid pages so users can still navigate through remaining valid pages.

14.0.2

Fixed
  • Fixes the SwiftUI implementation of BannerView to update Banner contents in-place whenever a refresh has succeeded.
  • Re-exposes the public initializer of BrazeInAppMessageUI.HtmlView as a designated init instead of a convenience init, which was introduced in version 14.0.0
    • This allows subclasses of HtmlView to access the public initializer.
  • Improves robustness of internal SDK logic around dictionary access to prevent potential crashes.

14.0.1

Fixed
  • Resolves an issue where the handling of universal links defaulted to the UIApplicationDelegate implementation instead of the UISceneDelegate implementation when the app was not in foreground.
    • This would occur even if there was no UIApplicationDelegate implementation, resulting in dropped universal link handling under such scenarios.
  • Fixes a memory leak where base64-encoded tracking IDs in in-app messages would accumulate on background threads.
  • Resolves an issue where in-app messages were not dismissed when the user is changed, resulting in the user seeing incorrect content.
    • This change also adds changeUser dismissal reason for in-app messages.

14.0.0

Breaking
  • Removes News Feed.
    • This fully removes all UI elements, data models, and actions associated with News Feed.
Added
  • Remote configuration now automatically refetches after SDK upgrades, keeping server defaults in sync and improving reliability after version changes.
Fixed
  • Resolves an issue where long text in in-app message buttons would wrap to multiple lines.
    • These messages will now match the dashboard preview behavior of truncating long text.
  • Push Stories now fail gracefully when receiving null/empty deeplink values.
    • Previously, an invalid deeplink would cause the Push Story’s content to appear blank.
    • StoryPage safely trims and percent-encodes deeplink strings, dropping invalid values instead of throwing an error.
    • StoryView only scrolls when pages exist, preventing the “Next” action from crashing when the carousel is empty.
  • HTML in-app messages now reuse cached payloads to mitigate app hangs that occur in rare situations during presentation.
  • Templated in-app messages with delayed presentation will now request templated values only after completion of the delay.
    • This ensures that templated values are most up-to-date with the display of the message.
    • Previously, the request for templated values would occur at trigger time, prior to the delay.

13.3.0

Added
  • Improves reliability when sending the push token and push authorization status to the backend.
    • This change ensures that push authorization status changes will be flushed immediately as soon as they are read.

13.2.1

Fixed
  • Resolves an issue where an accumulation of Banners pending requests could cause the host application to hang at app startup.
    • This fix performs additional cleanup to any existing requests that were accumulated from previous versions, so you do not need to do any manual cleanup.

13.2.0

Added
  • Adds support for compilation with Xcode 26.0 and its corresponding operating system runtimes on all platforms supported by the Braze Swift SDK.

13.1.0

Added
  • Adds support for Banner properties via new public methods on Braze.Banner instances.
    • banner.stringProperty(key:) for accessing String properties.
    • banner.numberProperty(key:) for accessing Double properties.
    • banner.timestampProperty(key:) for accessing Int Unix millisecond timestamp properties.
    • banner.booleanProperty(key:) for accessing Bool properties.
    • banner.imageProperty(key:) for accessing image URL properties as Strings.
    • banner.jsonProperty(key:) for accessing JSON properties as [String:Any] dictionaries.
    • banner.jsonProperty<T: Decodable>(key:type:decoder:) for accessing JSON properties as values of any custom Decodable type.
  • The default client-side rate limiting values for Banners refresh has been increased. For more information on SDK rate limiting, please refer to the Braze Developer Guide
Fixed
  • Improves the behavior of VoiceOver for assets that are missing an imageAltText for Content Card and In-App Message campaigns created via the Traditional editor.
    • These assets will no longer be selectable or narrated by VoiceOver. Previously, the asset would be selectable and VoiceOver would read gibberish.
    • Drag-and-drop campaigns are not affected by this issue.
    • Campaigns created using the Traditional editor should always have the Alt text field populated for accessible users.

13.0.0

Breaking
  • Extends the functionality of BrazeSDKAuthDelegate.braze(_:sdkAuthenticationFailedWithError:) to be triggered for “Optional” authentication errors.
    • The delegate method BrazeSDKAuthDelegate.braze(_:sdkAuthenticationFailedWithError:) will now be triggered for both “Required” and “Optional” authentication errors.
    • If you want to only handle “Required” SDK authentication errors, add a check ensuring that BrazeSDKAuthError.optional is false inside your implementation of this delegate method.
  • Fixes the usage of Braze.Configuration.sdkAuthentication to take effect when enabled.
    • Previously, the value of this configuration was not consumed by the SDK and the token was always attached to requests if it was present.
    • Now, the SDK will only attach the SDK authentication token to outgoing network requests when this configuration is enabled.
  • The setters for all properties of Braze.FeatureFlag and all properties of Braze.Banner have been made private. The properties of these classes are now read-only.
  • Removes the banner.id property, which was deprecated in version 11.4.0.
    • Instead, use banner.trackingId to read a banner’s campaign tracking ID.
Added
  • Adds the boolean field optional to BrazeSDKAuthError to indicate if it is an optional authentication error.

12.1.0

Added
  • Adds optional imageAltText and language fields to UI classes and structs associated with Content Card and In-App Message campaigns for improved accessibility.
    • The imageAltText field contains the image accessibility alt text (if any) for the image or icon in a given campaign. The SDK’s default UI will use this field to inform how VoiceOver narrates the image portion of a campaign
    • The optional language field is a BCP 47 tag. If it is present, VoiceOver will use the corresponding language narrator when reading the campaign. Otherwise, the user system default settings will be used.
    • These are the classes and structs with imageAltText and language:
      • Braze.ContentCard.ClassicImage
      • Braze.ContentCard.ImageOnly
      • Braze.ContentCard.CaptionedImage
      • Braze.ContentCardRaw (BRZContentCardRaw in Objective-C)
      • Braze.InAppMessage.Slideup
      • Braze.InAppMessage.Modal
      • Braze.InAppMessage.ModalImage
      • Braze.InAppMessage.Full
      • Braze.InAppMessage.FullImage
      • Braze.InAppMessageRaw (BRZInAppMessageRaw in Objective-C)
      • Braze.ContentCard.Classic has the language field only
  • Adds provisional support for Xcode 26 Beta via the braze-inc/braze-swift-sdk-xcode-26-preview repository.
    • Full support will be added to the main repository closer to the public release of Xcode 26.
    • For any compatibility issues discovered while using the Xcode 26 Beta, submit a GitHub issue on the main repository.

12.0.3

Fixed
  • Fixes the Banner rendering incompatibility with iOS 18.5+ while maintaining the correct URL redirect behavior.
    • Banners can now successfully render on iOS 18.5+ without compromising click action functionality.
    • See the changelog entries for versions 12.0.1 and 12.0.2 for further details.

12.0.2

⚠️ Important: This version has a known issue preventing Banners from rendering on iOS 18.5+.

Fixed
  • Reverts Banners to the behavior found in versions 12.0.0 and prior.
    • Banners remain unusable on iOS 18.5+. A future release will address this issue.

12.0.1

⚠️ Important: This version has a known issue in Drag-and-Drop in-app messages and Banners, preventing certain URLs from redirecting properly. Update to a newer version if you are using this feature.

Fixed
  • Fixes an issue where setting configuration.forwardUniversalLinks = true would not properly forward universal links to the system APIs in some cases.
    • The SDK now verifies that the system APIs are implemented (either in your UIApplicationDelegate or SceneDelegate) before forwarding the universal link.
    • When multiple implementations are found, the SDK favors the SceneDelegate implementation over the UIApplicationDelegate implementation.
  • Fixes an issue when configuring Braze.Configuration.Push.Automation.authorizationOptions with the .provisional option.
    • Previously, the .provisional option was also applied for push primer in-app messages. This resulted in no push notification permission prompt being shown to the user.
    • With this change, push primer in-app messages will request push notification permissions using only the .alert, .badge, and .sound options, ensuring that the system prompt is presented to the user.
  • Fixes an incompatibility with iOS 18.5 where Banners would not render.
    • Previously, the Banner view would be added to the view hierarchy with a height of 0 but never successfully load the HTML content.
    • Banner views will no longer trigger superfluous about:blank URLs upon initial load.

12.0.0

Breaking
  • The distributed static XCFrameworks now include their resources directly instead of relying on external resources bundles.
    • When manually integrating the static XCFrameworks, you must select the Embed & Sign option for each XCFramework in the Frameworks, Libraries, and Embedded Content section of your target’s General settings.
    • No changes are required for Swift Package Manager or CocoaPods integrations.
Fixed
  • Fixes an App Store validation issue where Braze’s libraries privacy manifests would fail to be detected when integrating the SDK as static XCFrameworks.
  • Fixes BrazeKitCompat ABKContentCard.expiresAt to return the correct expiration date.
    • Previously, ABKContentCard.expiresAt would always return 0.
  • Fixes an issue where the Braze.FeatureFlags.subscribeToUpdates(_:) update closure was being called immediately after calling changeUser(userId:) instead of waiting for the next feature flags sync result.
  • Fixes an issue where Braze.ContentCards.subscribeToUpdates(_:) would not call the update closure whenever a sync occurred without any changes in the Content Cards data.
    • Previously, the update closure would only be called when the sync resulted in a change.
  • Fixes the Braze.User.set(dateOfBirth:) method to report dates using the Gregorian calendar instead of the device’s current calendar setting.
    • Previously, the SDK would override input dates and formats if the device’s calendar settings were non-Gregorian.
    • With this change, you will still need to ensure that dates provided to set(dateOfBirth:) are generated with the Gregorian calendar, but the Braze SDK will no longer override their formats inadvertently.
  • Enhances the ⁠braze.wipeData() function to send a final update to all registered channel subscribers, notifying them of the data wipe.
    • This update ensures that any UI components utilizing the channel’s data are properly dismissed and cleaned up.
    • For instance, if an in-app message is currently displaying as braze.wipeData() is called, the message will be removed from display.
  • Fixes braze.user.id not resetting to nil after calling braze.wipeData().
    • Internally, the user identifier was properly reset, but the public braze.user.id property was not updated to reflect this change.
Added
  • Adds the BrazeInAppMessagePresenter.dismiss(reason:) optional protocol method.
    • This method enables the SDK to inform the in-app message presenter when an in-app message should be dismissed due to an internal SDK state change.
    • Currently, this method is triggered only by calling ⁠braze.wipeData().
    • BrazeInAppMessageUI implements this optional method and dismisses the in-app message when triggered.

11.9.0

Added
Fixed
  • The SDK Debugger tool will now capture logs even when Braze.configuration.logger.level is .disabled and no SDK logging occurs locally.
    • This aligns the Braze Swift SDK Debugger Tool behavior with that of the Debugger Tool on the Braze Android SDK.
  • Sets the default background of BannerUIView to be transparent.
  • Renames the VisibilityTracker.displayLinkTick method to VisibilityTracker.brazeDisplayLinkTick in BrazeUI to avoid potential naming conflicts with private system methods.

11.8.0

Added
  • Network requests made by the SDK to the Braze Live Activities /push_token_tag endpoint will now be retried in the case of a request failure.
  • Expands customizability options of custom endpoints passed when initializing a Braze instance.
    • You can now specify a base path to be used for SDK network requests (i.e. “example.com/mockServer”).
    • http schemes are now supported for use by custom endpoints (i.e. http://example.com). Previously, only https schemes were supported.
Fixed
  • Fixes an issue where in-app messages would not always be triggered when sending Braze requests to the tracking endpoint. This occurred when both of the following conditions are true:
    • The Braze.Configuration.Api.trackingPropertyAllowList did not include the .everything type.
    • All other Braze.Configuration.TrackingProperty types were manually listed in the trackingPropertyAllowList.
  • Improves the rendering behavior of Banner Cards embedded in a scroll view on hybrid development frameworks.
  • Fixes the Banner Card view to prevent drag gestures from exposing the background of the HTML content.
  • Fixes an issue on the Braze web view bridge where numeric values of 1 or 0 would be incorrectly reported as true or false, respectively.

11.7.0

Added
  • Adds the ability for a banner container to resize when the banner content changes height.

11.6.1

Fixed
  • Improves the reliability of collecting Live Activity push-to-start tokens on calling registerPushToStart:
    • Push-to-start tokens will now flush to the server immediately as soon as they are retrieved.
    • Push-to-start tokens will now be read immediately from the pushToStartToken property as soon as registerPushToStart is called, in addition to the existing behavior where an observable is set up to monitor new tokens.
  • Resolves issues with the SDK’s internal state for devices that were previously affected after restoring from another device’s iCloud or iTunes backup.
    • Previously, these devices would incorrectly inherit the device ID from the original device.
    • With this update, the SDK now generates a unique device ID for each restored device, ensuring proper identification and functionality.
    • This update follows up on the 11.6.0 fix, which prevented the issue from occurring on future backups.

11.6.0

Fixed
  • Fixes the behavior in the Braze-provided UI for Banner Cards where content would not automatically be cleared from the UI when changing to a user that was not eligible for that campaign.
  • Changes the behavior of Braze.Banners.subscribeToUpdates(_:) to match behavior of the corresponding API on the Braze Android SDK.
    • Upon calling Braze.Banners.subscribeToUpdates(_:), the update handler closure will only be called if a banners sync has succeeded during the current user session.
      • Previously, calling Braze.Banners.subscribeToUpdates(_:) would always result in the update handler being called one time immediately.
    • Upon successfully completing a banners sync, Braze.Banners.subscribeToUpdates(_:) will call its registered update handler even if the sync result is identical to the last successful sync.
  • Changes the behavior of Braze.Banners.bannersStream to match behavior of the corresponding API on the Braze Android SDK.
    • Braze.Banners.bannersStream will now only emit an update immediately upon access if a banners sync has succeeded during the current user session.
      • Previously, accessing Braze.Banners.bannersStream would always emit one update immediately.
    • Upon successfully completing a banners sync, Braze.Banners.bannersStream will emit an update even if the sync result is identical to the last successful sync.
  • JavaScript bridge methods expecting number arguments now also accept string representations of numbers.
    • This change aligns the behavior of the Swift SDK with the behavior of the Web SDK.
Added
  • Adds an optional method removeBannerContent to the BrazeBannerPlacement protocol.
  • Locally persisted Braze SDK data will no longer transfer during OS backups. This resolves an issue introduced in 6.2.0.

11.5.0

Fixed
  • Braze.banners.getBanner(for:_:) now successfully returns a cached Banner object for the requested placement ID as long as a Banner Cards sync has ever succeeded for the current user.
    • Previously, it would log a warning and pass nil to the completion handler if a Banner Cards sync had not been completed for the current user during the current session specifically.
    • This change aligns behavior with the Android SDK.
  • Fixes an issue where images with the "JPEG" image type would sometimes not display in Push Stories.
  • Fixes an issue where an in-app message in a Braze-provided UI can be displayed for an ineligible user under rare conditions.
    • This may occur if the in-app message was in the process of being displayed in the UI at the same time that the user was changed to a different user.
Added
  • Adds Braze.User.id to access the current user identifier synchronously.
    • Deprecates Braze.User.id() async and Braze.User.id(queue:completion:) in favor of Braze.User.id.
      • These methods will be removed fully in a future update.
  • Adds the optional parameter userIDMatchBehavior to the initializers of Braze.InAppMessageRaw.Context. This determines the behavior in the UI when the current identified user is different from the one that triggered the in-app message.
    • The default for Braze-provided UIs (.enforce) will enforce that the user ID matches the user ID that triggered the in-app message. If there is a mismatch, the in-app message will not be displayed.
    • For custom UIs, the default is .ignore and a mismatch will still display the in-app message.

11.4.0

Fixed
  • Fixes an issue where the SDK could hang during initialization if previous sessions generated a large number of geofence refreshes. This hang could sometimes lead to a crash by blocking the main thread for an extended period.
  • Fixes an issue where the triggering of in-app messages could be delayed in cases where requests for updated in-app message triggers are also delayed due to rate limiting.
  • Adds additional safeguards to ensure that ongoing network requests are dropped when changing users mid-flight.
Added
  • When Content Cards, Feature Flags, or Banner Cards go from enabled to disabled, the stored data is removed from cache.
  • Adds banner.trackingId to distinguish between banner objects.
    • Deprecates banner.id in favor of banner.trackingId.

11.3.0

Fixed
  • Fixes a behavior where calling the logClick bridge method in HTML in-app messages with "" as the button ID would log an error.
    • Instead, this would log an in-app message body click to match other platforms.
Added
  • Adds support for the Braze Banner Cards product.
    • For usage details, refer to our tutorial here.

11.2.0

Fixed
  • Fixes the Objective-C Braze.delegate declaration to be weak like the Swift variant.
Added
  • Braze.prepareForDelayedInitialization now takes an optional parameter analyticsBehavior: PushEnqueueBehavior.
    • Braze uses this value to determine whether any Braze push payloads received before initialization should be processed once initialization is complete.
    • PushEnqueueBehavior.queue will enqueue received push payloads to be processed upon initialization. This option is selected by default.
    • PushEnqueueBehavior.drop will drop received push payloads, ignoring them.
  • Adds configuration properties to customize the lineSpacing, maxLineHeight, minLineHeight, and lineHeightMultiple for the header and message texts in full and modal in-app messages.
  • Updates BrazeContentCardUI.ViewController.Attributes.defaults to be a var to allow directly editing the property for convenience.

11.1.1

Fixed
  • Fixes an issue introduced in 11.0.0 where the push subscription status would be sent to the backend with an inaccurate value at startup, causing an unexpected subscription state. The SDK now sends up the accurate subscription status at each startup.

11.1.0

⚠️ Important: This version has a known issue related to push subscription status. Upgrade to version 11.1.1 instead.

Fixed
  • Fixes an issue introduced in 11.0.0 where the push token status would not always be reported in all circumstances.
  • Fixes a display bug where an in-app message would appear truncated after certain keyboard dismissal scenarios.
  • Fixes a reference cycle in Braze.NewsFeedCard.Context that could prevent the card from being deallocated.
Added
  • Adds a public initializer for Braze.Notifications.Payload.

11.0.1

Fixed
  • Fixes an issue introduced in 11.0.0 where the push subscription status would be sent to the backend with an inaccurate value at startup, causing an unexpected subscription state. The SDK now sends up the accurate subscription status at each startup.

11.0.0

⚠️ Important: This version has a known issue related to push subscription status. Upgrade to version 11.1.1 instead.

Breaking
  • Adds support for Swift 6 strict concurrency checking.
    • Relevant public Braze classes and data types now conform to the Sendable protocol and can be safely used across concurrency contexts.
    • Main thread-only APIs are now marked with the @MainActor attribute.
    • We recommend using Xcode 16.0 or later to take advantage of these features while minimizing the number of warnings generated by the compiler. Previous versions of Xcode may still be used, but some features may generate warnings.
  • When integrating push notification support manually, you may need to update the UNUserNotificationCenterDelegate conformance to use the @preconcurrency attribute to prevent warnings.
    • Applying the @preconcurrency attribute on protocol conformance is only available in Xcode 16.0 or later. Reference our sample integration code here.
    • As of Xcode 16.0, Apple has not yet audited the UNUserNotificationCenterDelegate protocol for Swift concurrency.
      1
      2
      3
      
      extension AppDelegate: @preconcurrency UNUserNotificationCenterDelegate {
      // Your existing implementation
      }
      
  • Updates the SDWebImage dependency in BrazeUICompat and sample apps to 5.19.7+ to support Swift 6 strict concurrency checking.

Fixed

  • Fixes the push authorization status reporting to display the proper push token status on the Dashboard when a user has not explicitly accepted or declined push permissions.

10.3.1

Fixed
  • Improves the reliability of sending updates to Live Activities that were launched via a push-to-start notification to an app in the terminated state.

10.3.0

Fixed
  • Fixes the in-app message orientation validation logic, which prevented certain device classes from displaying messages under certain orientation configurations.
  • Fixes the default behavior on full-screen in-app messages to display as modals only on tablet screen sizes.
    • Previously, full-screen messages would erroneously default to modal presentations on some larger phones.
  • Fixes a crash when dismissing a slideup in-app message before it has finished presenting.
  • Fixes an issue on iOS 18.0+ where the in-app message UI would persist on the screen when attempting to dismiss the message before it has finished presenting.
  • Updates custom attribute value, custom event, and purchase string validation to use a 255 character maximum instead of a 255 byte maximum.
Added

10.2.0

Fixed
  • Updates the content card image background color to be clear.
Added
  • Adds support for an upcoming Braze SDK Debugging tool.

10.1.0

Fixed
  • Fixes an issue affecting the Objective-C variants of BrazeDelegate, BrazeContentCardUIViewControllerDelegate and BrazeInAppMessageUIDelegate.
    • When setting these delegates in Objective-C a second time, the delegate would end up being set to nil.
    • This issue has been resolved and the delegates can now be set multiple times without issue.
Added

10.0.0

Breaking
  • The following changes have been made when subscribing to Push events with Braze.Notifications.subscribeToUpdates(payloadTypes:_:):
    • The update closure will now be triggered by both “Push Opened” and “Push Received” events by default. Previously, it would only be triggered by “Push Opened” events.
      • To continue subscribing only to “Push Opened” events, pass in [.opened] for the parameter payloadTypes. Alternatively, implement your update closure to check that the type from the Braze.Notifications.Payload is .opened.
    • When receiving a push notification with content-available: true, the Braze.Notifications.Payload.type will now be .received instead of .opened.
  • Marks the following deprecated APIs as unavailable:
    • Braze.Configuration.Api.Flavor
    • Braze.Configuration.Api.flavor
    • Braze.Configuration.Api.SdkMetadata
    • Braze.Configuration.Api.addSdkMetadata(_:)
    • Braze.ContentCard.ClickAction.uri(_:useWebview:)
    • Braze.ContentCard.ClickAction.uri
    • Braze.InAppMessage.ClickAction.uri(_:useWebview:)
    • Braze.InAppMessage.ClickAction.uri
    • Braze.InAppMessage.ModalImage.imageUri
    • Braze.InAppMessage.Full.imageUri
    • Braze.InAppMessage.FullImage.imageUri
    • Braze.InAppMessage.Themes.default
    • Braze.deviceId(queue:completion:)
    • Braze._objc_deviceId(completion:)
    • Braze.deviceId()
    • Braze.User.setCustomAttributeArray(key:array:fileID:line:)
    • Braze.User.addToCustomAttributeArray(key:value:fileID:line:)
    • Braze.User.removeFromCustomAttributeArray(key:value:fileID:line:)
    • Braze.User._objc_addToCustomAttributeArray(key:value:)
    • Braze.User._objc_removeFromCustomAttributeArray(key:value:)
    • gifViewProvider
    • GifViewProvider.default
  • Removes the deprecated APIs:
    • Braze.Configuration.DeviceProperty.pushDisplayOptions
    • Braze.InAppMessageRaw.Context.Error.extraProcessClickAction
  • Removes the deprecated BrazeLocation class in favor of BrazeLocationProvider.
Fixed
  • Fixes a crash when handling a scheme-based deep link containing a registered applink domain (e.g. applinks:example.com with a deep link to app://example.com/path).
Added
  • Adds support to subscribe to “Push Received” events via Braze.Notifications.subscribeToUpdates(payloadTypes:_:).
    • The following notifications will trigger this subscription:
      • Notifications received in the foreground
      • Notifications with the field content-available: true received in the foreground or background
    • The following notifications will not trigger this subscription:
      • Notifications received while terminated
      • Notifications received in the background without the field content-available: true
    • The new parameter payloadTypes will allow you to subscribe to “Push Opened” events, “Push Received” events, or both. If the parameter is omitted, it will subscribe to both by default.
    • If you are using manual push integration, you will need to first implement UNUserNotificationCenter.userNotificationCenter(_:willPresent:withCompletionHandler:), and make sure to call Braze.Notifications.handleForegroundNotification(notification:) within your implementation. Then, use subscribeToUpdates as noted above. See our guide on push notification integration for more info.
  • Adds the public property Braze.Notifications.Payload.type.
  • Adds the Braze.WebViewBridge.ScriptMessageHandler.init(braze:) initializer enabling a simpler way to initialize the ScriptMessageHandler for adding it to user-provided web views.

9.3.1

Fixed
  • Fixes an issue where the Braze.FeatureFlag.subscribeToUpdates(_:) callback was not triggered at app launch when the cached feature flags matched the remote feature flags.
  • Fixes an issue in Objective-C projects where the return value of Braze.FeatureFlag.jsonProperty(key:) would incorrectly encode any entry value equal to null under certain conditions.
    • [String: Any] dictionaries returned by the Swift API will now drop null values.
    • NSDictionary objects returned by the Objective-C API will now encode null values as NSNull.

9.3.0

Added
  • Adds Objective-C support for the BrazeInAppMessageUIDelegate.inAppMessage(_:prepareWith:) method.
    • Customization of ViewAttributes via the attributes property is not available in the Objective-C version of PresentationContextRaw.
  • Adds Braze.FeatureFlag.jsonProperty(key:type:decoder:) to decode jsonobject type Feature Flag properties into custom Decodable types.
  • Deprecates the existing Feature Flag APIs, to be removed in a future version:
    • Braze.FeatureFlag.jsonStringProperty(key:) has been deprecated.
    • Braze.FeatureFlag.jsonObjectProperty(key:) has been deprecated in favor of Braze.FeatureFlag.jsonProperty(key:).
Fixed
  • Fixes an issue where the preferredOrientation on the presentation context of an in-app message would not be respected.

9.2.0

Added
  • Adds the openNewWindowLinksInBrowser configuration (default: false) to Braze.ModalContext.
    • Set this value in the braze(_:willPresentModalWithContext:) method of your BrazeDelegate to specify whether to launch the device browser to open web view hyperlinks that normally open a new tab or window.
Fixed
  • Fixes an issue with the automatic push integration feature that could cause the SDK not to send the device token to Braze.
  • Fixes an issue that prevented external links, which open in a new tab, from being activated in presented web views.

9.1.0

Added
  • Adds support for 3 new Feature Flag property types and various APIs for accessing them:
    • Braze.FeatureFlag.timestampProperty(key:) for accessing Int Unix millisecond timestamps.
    • Braze.FeatureFlag.imageProperty(key:) for accessing image URLs as Strings.
    • Braze.FeatureFlag.jsonObjectProperty(key:) for accessing JSONs as [String:Any] dictionaries.
    • Braze.FeatureFlag.jsonStringProperty(key:) for accessing JSONs as Strings.
  • Adds safeguards when reading the device model.
Fixed
  • Fixes the duplicate symbols compilation errors and runtime warnings that may occur under specific conditions when integrating BrazeKit and either BrazeNotificationService or BrazePushStory via CocoaPods.

9.0.0

Breaking
  • Removes the default privacy tracking domains from the BrazeKit privacy manifest.
    • If you are using the Braze data tracking features, you will need to manually add your tracking endpoint to your app-level privacy manifest.
    • Refer to the updated tutorial for integration guidance.
  • Removes the deprecated BrazeDelegate.braze(_:sdkAuthenticationFailedWithError) method in favor of BrazeSDKAuthDelegate.braze(_:sdkAuthenticationFailedWithError).
    • This method was originally deprecated in release 5.14.0.
    • Failing to switch to the new delegate method will not trigger a compiler error; instead, the BrazeDelegate.braze(_:sdkAuthenticationFailedWithError) method you define will simply not be called.
Fixed
  • Adds the missing NSPrivacyCollectedDataTypes key to the BrazePushStory privacy manifest.

8.4.0

Added
  • Expands Geofences behavior in the background while “When In Use” authorization is selected:
    • Adds the Braze.Location.Configuration.allowBackgroundGeofenceUpdates property to toggle whether geofences should be updated in the background.
      • When using this setting, verify that you have enabled the Location updates background mode.
    • Adds the Braze.Location.Configuration.distanceFilter property to configure the minimum distance sensitivity for triggering a location update.
  • Adds support for the message_extras Liquid tag for in-app messages.

8.3.0

Added
  • Adds early access for a third alternative repository which provides all Braze modules as mergeable XCFrameworks. For instructions on how to leverage it, refer to the repository README:
Fixed
  • Adds a missing privacy manifest for BrazePushStory.
  • Fixes an invalid privacy manifest warning in BrazeLocation when submitting to the App Store as a dynamic XCFramework.
  • Fixes an issue where already enqueued in-app messages would not be removed from the stack after subsequent .reenqueue and .discard display actions.
  • Fixes an issue preventing retried requests from using an updated SDK authentication token until a new request was scheduled for processing.
  • Purchases, custom events, and nested custom user attributes can now include properties with values of any type conforming to BinaryInteger (Int64, UInt16, etc).
    • All values will be cast to Int before being logged.
    • This resolves an issue with a bugfix in 7.6.0.

8.2.1

Fixed
  • Fixes App Store validation issues when archiving with Xcode 15.3.

8.2.0

Added
  • Adds support for remotely starting Live Activities via push notifications.
  • Adds return values for existing liveActivities methods:
    • launchActivity(pushTokenTag:activity:) now returns a discardable Task<Void, Never>?.
  • Adds pushToStartTokens as a new tracking property type.

8.1.0

Added
  • Adds the is_test_send boolean value in the in-app message JSON representation.
  • Adds the Braze.subscribeToSessionUpdates(_:) method and Braze.sessionUpdatesStream property to subscribe to the session updates events generated by the SDK.
  • Adds public APIs to access BrazeKit, BrazeLocation and BrazeUI resources bundles:
    • Braze.Resources.bundle
    • BrazeLocationResources.bundle
    • BrazeUIResources.bundle
  • BrazeKit.overrideResourceBundle and BrazeUI.overrideResourceBundle have been deprecated in favor of BrazeKit.overrideResourcesBundle and BrazeUI.overrideResourcesBundle.
  • Re-enables visionOS sample apps requiring SDWebImage in Examples-CocoaPods.xcworkspace. SDWebImage for visionOS is now supported when using CocoaPods.
  • Updated SDWebImage dependency in BrazeUICompat to 5.19.0+.
Fixed
  • Fixes multiple issues on visionOS:

8.0.1

Fixed
  • Fixes the reported SDK version, see 8.0.0.
  • Removes crash data from the BrazeKit privacy manifest. This data type is not collected by Braze.

8.0.0

⚠️ Warning
  • This release reports the SDK version as 7.7.0 instead of 8.0.0.
Breaking
  • Compiles the SDK using Xcode version 15.2 (15C500b).
    • This also raises the minimum deployment targets to iOS 12.0 and tvOS 12.0.
  • The BrazeLocation class is now marked as unavailable. It was previously deprecated in favor of BrazeLocationProvider in 5.8.1.
Added
  • Adds support for visionOS 1.0.
    • ⚠️ Rich push notifications and Push Stories may not display as expected on visionOS 1.0. We are monitoring the latest versions for potential fixes.
    • ⚠️ CocoaPods is not yet supported by SDWebImage for visionOS. visionOS sample apps requiring SDWebImage have been disabled in the Examples-CocoaPods.xcworkspace. Refer to the SwiftPM or manual integration Xcode project instead.

7.7.0

Added
  • Updates the prebuilt release assets to include the privacy manifest for manual integrations of SDWebImage.
  • Enhances support for language localizations.
    • Introduces a localization for Azerbaijani strings.
    • Updates Ukrainian localization strings for accuracy.
Fixed
  • Fixes the default button placement for full in-app message views.
  • Fixes an issue where setting Braze.Configuration.Api.endpoint to a URL with invalid characters could cause a crash.
    • If the SDK is given an invalid endpoint, it will no longer attempt to make network requests and will instead log an error.
  • Fixes an issue preventing BrazeLocation from working correctly when using the dynamic XCFrameworks.

7.6.0

Added
  • Adds the Braze.InAppMessage.Data.isTestSend property, which indicates whether an in-app message was triggered as part of a test send.
  • Adds logic to separate Braze data into tracking and non-tracking requests.
    • Adds the following methods to set and edit the allow list for properties that will be used for tracking:
      • Braze.Configuration.Api.trackingPropertyAllowList: Set the initial allow list before initializing Braze.
      • Braze.updateTrackingAllowList(adding:removing:): Update the existing allow list during runtime.
    • For full usage details on these configurations, refer to our tutorial here.
Fixed
  • Adds safeguards to prevent a rare race condition occuring in the SDK network layer.
  • Prevents in-app message test sends from attempting re-display after being discarded by a custom in-app message UI delegate.
  • Fixes an issue in the default Braze in-app message UI where some messages were not being removed from the stack after display.
  • Fixes the compilation of BrazeKitCompat and BrazeUICompat in Objective-C++ projects.
  • Fixes an issue in BrazeUICompat where the header text in Full or Modal in-app messages would be duplicated in place of the body text under certain conditions.
  • Fixes the encoding of values of types Float, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32 and UInt64. Those types were previously not supported in custom events and purchase properties.
  • Fixes an issue preventing purchase events from being logged when the product identifier has a leading dollar sign.
  • Fixes an issue preventing custom attributes from being logged when the attribute key has a leading dollar sign.

7.5.0

Added
  • Adds privacy manifests for BrazeKit and BrazeLocation to describe Braze’s data collection policies. For more details, refer to Apple’s documentation on privacy manifests.
    • More fine-tuned configurations to manage your data collection practices will be made available in a future release.
  • Adds the optInWhenPushAuthorized configuration property to specify whether a user’s notification subscription state should automatically be set to optedIn when updating push permissions to authorized.
  • The WebKit Inspector developer tool is now enabled by default for all instances of BrazeInAppMessagesUI.HtmlView. It can be disabled by setting BrazeInAppMessagesUI.HtmlView.Attributes.allowInspector to false.
Fixed
  • Fixes an issue with the code signatures of XCFrameworks introduced in 7.1.0.
  • Fixes a crash on tvOS devices running versions below 16.0, caused by the absence of the UIApplication.openNotificationSettingsURLString symbol in those OS versions.
  • Fixes an issue where a content card would not display if the value under “Redirect to Web URL” was an empty string.
  • Fixes incorrect behavior in BrazeUI where tapping the body of a Full or Modal in-app message with buttons and an “Image Only” layout would dismiss that message and process the button’s click action.
    • Tapping the body will now be a no-op, bringing parity with other platforms.

7.4.0

Added
  • Adds two alternative repositories to support specialized integration options. For instructions on how to leverage them, refer to their respective READMEs:
  • In-App Message assets from URLs containing the query parameter cache=false will not be prefetched.
Fixed
  • Fixes XCFrameworks headers to use the #import syntax instead of @import for compatibility with Objective-C++ contexts.
  • Fixes the push token tag validation during Live Activity registration, accepting strings up to 256 bytes instead of 255 bytes.
  • Braze.ContentCards.unviewedCards no longer includes Control cards to bring parity with Android and Web.
  • Fixes an Objective-C metaclass crash that occurs when initializing a custom subclass of certain BrazeUI views.

7.3.0

Added
  • Adds support for Expo Notifications event listeners when using the automatic push integration.
Fixed
  • Fixes a rare concurrency issue that might result in duplicated events when logging large amount of events.
  • Fixes an issue where user.set(dateOfBirth:) was not setting the date of birth accurately due to variations in the device’s timezone.

7.2.0

Added
  • Exposes the BrazePushStory.NotificationViewController.didReceive methods for custom handling of push story notification events.
Fixed
  • Resolves an issue for in-app messages with buttons where tapping on the body would incorrectly execute the button’s click action.
    • Now, when you tap on the body of an in-app message with buttons, no event should occur.
  • Resolves a potential deadlock under rare circumstances in BrazeUI’s In-App messages presentation.
  • Fixes the default implementation for the Objective-C representation of BrazeInAppMessageUIDelegate.inAppMessage(_:shouldProcess:url:buttonId:message:view:) to return the proper click action URL.
  • Resolves an issue where the body of the modal in-app message may be displayed stretched on some device models.
  • Resolves an issue where BrazeInAppMessageUI could fail to detect the correct application window for presenting its post-click webview.
    • BrazeInAppMessageUI now prefers using the current key UIWindow instead of the first one in the application’s window stack.
Removed
  • Braze.Configuration.DeviceProperty.pushDisplayOptions has been deprecated. Providing this value no longer has an effect.

7.1.0

Fixed
  • Resolves an issue preventing templated in-app messages from triggering if a previous attempt to display the message failed within the same session.
  • Fixes an issue that prevented custom events and nested custom attributes from logging if had a property with a value that was prefixed with a $.
  • Fixes a bug in the Content Cards feed UI where the empty feed message would not display when the user only had control cards in their feed.
  • Adds additional safeguards when reading the device model.
Added
  • Adds a code signature to all XCFrameworks in the Braze Swift SDK, signed by Braze, Inc..
  • BrazeInAppMessageUI.DisplayChoice.later has been deprecated in favor of BrazeInAppMessageUI.DisplayChoice.reenqueue.

7.0.0

Breaking
  • The useUUIDAsDeviceId configuration is now enabled by default.
  • The Banner Content Card type and corresponding UI elements have been renamed to ImageOnly. All member methods and properties remain the same.
    • Braze.ContentCard.BannerBraze.ContentCard.ImageOnly
    • BrazeContentCardUI.BannerCellBrazeContentCardUI.ImageOnlyCell
  • Refactors some text layout logic in BrazeUI into a new Braze.ModalTextView class.
  • Updates the behavior for Feature Flags methods.
    • FeatureFlags.featureFlag(id:) now returns nil for an ID that does not exist.
    • FeatureFlags.subscribeToUpdates(:) will trigger the callback when any refresh request completes with a success or failure.
      • The callback will also trigger immediately upon initial subscription if previously cached data exists from the current session.
Fixed
  • Fixes compiler warnings about Swift 6 when compiling BrazeUI while using Xcode 15.
  • Exposes public imports for ABKClassicImageContentCardCell.h and ABKControlTableViewCell.h for use in the BrazeUICompat layer.
  • Adds additional safeguards around invalid constraint values for BrazeInAppMessageUI.SlideupView.
  • Resolves a Content Cards feed UI issue displaying a placeholder image in Classic cards without an attached image.
Added
  • Adds the enableDarkTheme property to BrazeContentCardUI.ViewController.Attributes.
    • Set this field to false to prevent the Content Cards feed UI from adopting dark theme styling when the device is in dark mode.
    • This field is true by default.

6.6.2

Fixed
  • Fixes an issue preventing purchase events from being logged when the product identifier has a leading dollar sign ($).
  • Fixes an issue preventing custom attributes from being logged when the attribute key has a leading dollar sign ($).

6.6.1

Fixed
  • Fixes a crash in the geofences feature that could occur when the number of monitored regions exceeded the maximum count.
  • Fixes an issue introduced in 6.3.1 that would always update a user’s push subscription status to optedIn on app launch if push permissions were authorized on the device settings.
    • The SDK now will only send the subscription status at app launch if the device notification settings goes from denied to authorized.
  • Braze.ContentCard.logClick(using braze: Braze) will now log a click regardless of whether the ContentCard has a ClickAction.
    • This behavior differs from the default API Braze.ContentCard.Context.logClick(), which has the safeguard of requiring a ClickAction to log a click.

6.6.0

Fixed
  • Fixes an issue in HTML in-app messages where custom event and purchase properties would always convert values for 1 and 0 to become true and false, respectively.
    • These property values will now respect their original form in the HTML.
  • Prevents the default Braze UI from displaying in-app messages underneath the keyboard when Stage Manager is in use.
Added

6.5.0

Fixed
  • Content card impressions can now be logged any number of times on a single card, bringing parity with Android and Web.
    • This removes the limit introduced in 6.3.1 where a card impression could only be logged once per session.
    • In the Braze-provided Content Cards feed UI, impressions will be logged once per feed instance.
Added
  • Adds a simplified method for integrating push notification support into your application:
    • Automatic push integration can be enabled by setting configuration.push.automation = true on your configuration object.
      • This eliminates the need for the manual push integration outlined in the Implement the push notification handlers manually tutorial section.
      • When enabled, the SDK will automatically implement the necessary system delegate methods for handling push notifications.
      • Compatibility with other push providers, whether first or third party, is maintained. The SDK will automatically handle only Braze push notifications, while original system delegate methods will be executed for all other push notifications.
    • Each automation step can be independently enabled or disabled. For example, configuration.push.automation.requestAuthorizationAtLaunch = false can be used to prevent the automatic request for push permissions at launch.
    • Resources:
  • Adds the Braze.Configuration.forwardUniversalLinks configuration. When enabled, the SDK will redirect universal links from Braze campaigns to the appropriate system methods.
  • Adds the Braze.Notifications.subscribeToUpdates(_:) method to subscribe to the push notifications handled by the SDK.
  • Adds the Braze.Notifications.deviceToken property to access the most recent notification device token received by the SDK.

6.4.0

Fixed
  • Fixes an issue preventing text fields from being selected in HTML IAMs for iOS 15.
  • Fixes an issue where the device model was inaccurately reported as iPad on macOS (Mac Catalyst and Designed for iPad configurations).
  • Fixes an issue where custom event and purchase properties would not accept an entry if its value was an empty string.
  • Fixes a crash that occurred in the default UI for Content Cards when encountering a zero-value aspect ratio.
  • Fixes an issue introduced in 6.0.0 where images in in-app messages would appear smaller than expected when using the compatibility UI (BrazeUICompat).
Added
  • Adds the unviewedCards convenience property to the Braze.ContentCards class to get the unviewed content cards for the current user.

6.3.1

Fixed
  • Fixes an issue where the previous user’s data would not be flushed after calling changeUser(userId:sdkAuthSignature:) when the SDK authentication feature is enabled.
  • A content card impression can now be logged once per session. Previously, the Braze-provided Content Cards UI would limit to a single impression per card at maximum, irrespective of sessions.
  • Fixes an issue that previously caused push notification URLs with percent-encoded characters to fail during decoding.
  • Fixes a behavior to automatically set a user’s push subscription state to optedIn after push permissions have explicitly been authorized via the Settings app.
  • Correctly hides shadows on in-app messages that are configured with a transparent background.
  • Fixes a rare crash occurring when deinitializing the Braze instance.
Added
  • Adds additional logging for network-related decoding errors.

6.3.0

Fixed
  • “Confirm” and “Cancel” notification categories now show the correct titles on the action buttons.
Added

6.2.0

Fixed
  • Fixes a crash introduced in 6.0.0 when displaying an HTML in-app message using the BrazeUICompat module.
  • Removed a system call that is known to be slow on older versions of macOS. This resolves the SDK hanging during initialization on Mac Catalyst when running on affected macOS versions.
Added
  • Adds support for target attributes on anchor tags in HTML in-app messages (e.g. <a href="..." target="_blank"></a>).
    • Adding the target attribute to links will allow them to open in a new webview without dismissing the current in-app message.
    • This behavior can be disabled via the linkTargetSupport property of the BrazeInAppMessageUI.HtmlView.Attributes struct.
    • See our Custom HTML in-app messages documentation page for more details.

6.1.0

Fixed
  • Fixes an issue that led to disproportionately large close buttons on in-app messages when the user has set a large font size in the device settings.
  • Fixes an issue that would lock the screen in a specific orientation after the dismissal of an in-app message customized to be presented in that orientation.
    • This issue only impacted iOS 16.0+ devices.
Added
  • Adds new versions of setCustomAttribute to the User object to support nested custom attributes.
    • Renames User.setCustomAttributeArray(key: String, array: [String]?) to setCustomAttribute(…) to align it with other custom attribute setters, and adds “string” to the addTo and removeFrom attribute array methods to clarify which custom attributes they’re used for.

6.0.0

Breaking
Added

5.14.0

Fixed
  • VoiceOver now correctly focuses on in-app message views when they are presented.
  • Fixes an issue causing in-app messages with re-eligibility disabled to display multiple times under certain conditions.
  • Fixes an issue where modal and full in-app message headers were truncated on devices running iOS versions lower than 16 when displaying non-ASCII characters.
  • The dynamic variant of BrazeUI.framework in the release artifact braze-swift-sdk-prebuilt.zip is now an actual dynamic framework. Previously, this specific framework was mistakenly distributed as a static framework.
Added
  • Adds the BrazeSDKAuthDelegate protocol as a separate protocol from BrazeDelegate, allowing for more flexible integrations.
    • Apps implementing BrazeDelegate.braze(_:sdkAuthenticationFailedWithError:) should migrate to use BrazeSDKAuthDelegate and remove the old implementation. The BrazeDelegate method will be removed in a future major release.

5.13.0

Fixed
  • Fixes an issue where the SDK would automatically track body clicks on non-legacy HTML in-app messages.
Added
  • Adds the synchronous deviceId property on the Braze instance.
    • deviceId(queue:completion:) is now deprecated.
    • deviceId() async is now deprecated.
  • Adds the automaticBodyClicks property to the HTML in-app message view attributes. This property can be used to enable automatic body clicks tracking on non-legacy HTML in-app messages.
    • This property is false by default.
    • This property is ignored for legacy HTML in-app messages.

5.12.0

Starting with this release, this SDK will use Semantic Versioning.

Added
  • Adds json() and decoding(json:) public methods to the Feature Flag model object for JSON encoding/decoding.

5.11.2

Fixed
  • Fixes a crash occurring when the SDK is configured with a flush interval of 0 and network connectivity is poor.

5.11.1

Fixed
  • Fixes an issue preventing the correct calculation of the delay when retrying failed requests. This led to a more aggressive retry schedule than intended.
  • Improves the performance of Live Activity tracking by de-duping push token tag requests.
  • Fixes an issue in logClick(using:) where it would incorrectly open the url field in addition to logging a click for metrics. It now only logs a click for metrics.
    • This applies to the associated APIs for content cards, in-app messages, and news feed cards.
    • It is still recommended to use the associated Context object to log interactions instead of these APIs.
Added

5.11.0

Added
  • Adds support for Live Activities via the liveActivities module on the Braze instance.
    • This feature provides the following new methods for tracking and managing Live Activities with the Braze push server:
      • launchActivity(pushTokenTag:activity:)
      • resumeActivities(ofType:)
    • This feature requires iOS 16.1 and up.
    • To learn how to integrate this feature, refer to the setup tutorial.
  • Adds logic to re-synchronize Content Cards on SDK version changes.
  • Adds provisional support for Xcode 14.3 Beta via the braze-inc/braze-swift-sdk-xcode-14-3-preview repository.

5.10.1

Changed
  • Dynamic versions of the prebuilt xcframeworks are now available in the braze-swift-sdk-prebuilt.zip release artifact.

5.10.0

Fixed
  • Fixes an issue where test content cards were removed before their expiration date.
  • Fixes an issue in BrazeUICompat where the status bar appearance wasn’t restored to its original state after dismissing a full in-app message.
  • Fixes an issue when decoding notification payloads where some valid boolean values weren’t correctly parsed.
Changed
  • In-app modal and full-screen messages are now rendered with UITextView, which better supports large amounts of text and extended UTF code points.

5.9.1

Fixed
  • Fixes an issue preventing local expired content cards from being removed.
  • Fixes a behavior that could lead to background tasks extending beyond the expected time limit with inconsistent network connectivity.
Added
  • Adds logImpression(using:) and logClick(buttonId:using:) to news feed cards.

5.9.0

Breaking
  • Raises the minimum deployment target to iOS 11.0 and tvOS 11.0.
  • Raises the Xcode version to 14.1 (14B47b).
Fixed
  • Fixes an issue where the post-click webview would close automatically in some cases.
  • Fixes a behavior where the current user messaging data would not be directly available after initializing the SDK or calling changeUser(userId:).
  • Fixes an issue preventing News Feed data models from being available offline.
  • Fixes an issue where the release binaries could emit warnings when generating dSYMs.
Changed
  • SwiftPM and CocoaPods now use the same release assets.
Added
  • Adds support for the upcoming Braze Feature Flags product.
  • Adds the braze-swift-sdk-prebuilt.zip archive to the release assets.
    • This archive contains the prebuilt xcframeworks and their associated resource bundles.
    • The content of this archive can be used to manually integrate the SDK.
  • Adds the Examples-Manual.xcodeproj showcasing how to integrate the SDK using the prebuilt release assets.
  • Adds support for Mac Catalyst for example applications, available at Support/Examples/
  • Adds support to convert from Data into an in-app message, content card, or news feed card via decoding(json:).

5.8.1

Fixed
  • Fixes a conflict with the shared instance of ProcessInfo, allowing low power mode notifications to trigger correctly.
Changed
  • Renames the BrazeLocation class to BrazeLocationProvider to avoid shadowing the module of the same name (SR-14195).

5.8.0

To help migrate your app from the Appboy-iOS-SDK to our Swift SDK, this release includes the Appboy-iOS-SDK migration guide:

  • Follow step-by-step instructions to migrate each feature to the new APIs.
  • Includes instructions for a minimal migration scenario via our compatibility libraries.
Added
  • Adds compatibility libraries BrazeKitCompat and BrazeUICompat:
    • Provides all the old APIs from Appboy-iOS-SDK to easily start migrating to the Swift SDK.
    • See the migration guide for more details.
  • Adds support for News Feed data models and analytics.
    • News Feed UI is not supported by the Swift SDK. See the migration guide for instructions on using the compatibility UI.

5.7.0

Fixed
  • Fixes an issue where modal image in-app messages would not respect the aspect ratio of the image when the height of the image is larger than its width.
Changed
  • Changes modal, modal image, full, and full image in-app message view attributes to use the ViewDimension type for their minWidth, maxWidth and maxHeight attributes.
    • The ViewDimension type enables providing different values for regular and large size-classes.
Added
  • Adds a configuration to use a randomly generated UUID instead of IDFV as the device ID: useUUIDAsDeviceId.
    • This configuration defaults to false. To opt in to this feature, set this value to true.
    • Enabling this value will only affect new devices. Existing devices will use the device identifier that was previously registered.

5.6.4

Fixed
  • Fixes an issue preventing the execution of BrazeDelegate methods when setting the delegate using Objective-C.
  • Fixes an issue where triggering an in-app message twice with the same event did not place the message on the in-app message stack under certain conditions.
Added
  • Adds the public id field to Braze.InAppMessage.Data.
  • Adds logImpression(using:) and logClick(buttonId:using:) to both in-app messages and content cards, and adds logDismissed(using:) to content cards.
    • It is recommended to continue using the associated Context to log impressions, clicks, and dismissals for the majority of use cases.
  • Adds Swift concurrency to support async/await versions of the following public methods. These methods can be used as alternatives to their corresponding counterparts that use completion handlers:

5.6.3

Fixed
  • Fixes the InAppMessageRaw to InAppMessage conversion to properly take into account the extras dictionary and the duration.
  • Fixes an issue preventing the execution of the braze(_:sdkAuthenticationFailedWithError:) delegate method in case of an authentication error.
Changed
  • Improves error logging descriptions for HTTP requests and responses.

5.6.2

Changed
  • Corrected the version number from the previous release.

5.6.1

Added
  • Adds the public initializers Braze.ContentCard.Context(card:using:) and Braze.InAppMessage.Context(message:using:).

5.6.0

Fixed
  • The modal webview controller presented after a click now correctly handles non-HTTP(S) URLs (e.g. App Store URLs).
  • Fixes an issue preventing some test HTML in-app messages from displaying images.
Added
  • Learn how to easily customize BrazeUI in-app message and content cards UI components with the following documentation and example code:
  • Adds new attributes to BrazeUI in-app message UI components:
    • cornerCurve to change the cornerCurve
    • buttonsAttributes to change the font, spacing and corner radius of the buttons
    • imageCornerRadius to change the image corner radius for slideups
    • imageCornerCurve to change the image cornerCurve for slideups
    • dismissible to change whether slideups can be interactively dismissed
  • Adds direct accessors to the in-app message view subclass on the BrazeInAppMessageUI.messageView property.
  • Adds direct accessors to the content card title, description and domain when available.
  • Adds Braze.Notifications.isInternalNotification to check if a push notification was sent by Braze for an internal feature.
  • Adds brazeBridge.changeUser() to the HTML in-app messages JavaScript bridge.
Changed
  • The applyAttributes() method for BrazeContentCardUI views now take the attributes explicitly as a parameter.

5.5.1

Fixed
  • Fixes an issue where content cards would not be properly removed when stopping a content card campaign on the dashboard and selecting the option Remove card after the next sync (e.g. session start).

5.5.0

Added
  • Adds support for host apps written in Objective-C.
    • Braze Objective-C types start either with BRZ or Braze, e.g.:
      • Braze
      • BrazeDelegate
      • BRZContentCardRaw
    • See our Objective-C Examples project.
  • Adds BrazeDelegate.braze(_:noMatchingTriggerForEvent:) which is called if no Braze in-app message is triggered for a given event.
Changed
  • In Braze.Configuration.Api:
    • Renamed SdkMetadata to SDKMetadata.
    • Renamed addSdkMetadata(_:) to addSDKMetadata(_:).
  • In Braze.InAppMessage:
    • Renamed Themes.default to Themes.defaults.
    • Renamed ClickAction.uri to ClickAction.url.
    • Renamed ClickAction.uri(_:useWebView:) to ClickAction.url(_:useWebView:).

5.4.0

Fixed
  • Fixes an issue where brazeBridge.logClick(button_id) would incorrectly accept invalid button_id values like "", [], or {}.
Added
  • Adds support for Braze Action Deeplink Click Actions.

5.3.2

Fixed
  • Fixes an issue preventing compilation when importing BrazeUI via SwiftPM in specific cases.
  • Lowers BrazeUI minimum deployment target to iOS 10.0.

5.3.1

Fixed
  • Fixes an HTML in-app message issue where clicking a link in an iFrame would launch a separate webview and close the message, instead of redirecting within the iFrame.
  • Fixes the rounding of In-App Message modal view top corners.
  • Fixes the display of modals and full screen in-app messages on iPads in landscape mode.
Added

5.3.0

Added
  • Adds support for tvOS.
    • See the schemes Analytics-tvOS and Location-tvOS in the Examples project.

5.2.0

Added
Changed
  • Raises BrazeUI minimum deployment target to iOS 11.0 to allow providing SwiftUI compatible Views.

5.1.0

Fixed
  • Fixes an issue where the SDK would be unable to present a webview when the application was already presenting a modal view controller.
  • Fixes an issue preventing a full device data update after changing the identified user.
  • Fixes an issue preventing events and user attributes from being flushed automatically under certain conditions.
  • Fixes an issue delaying updates to push notifications settings.
Added

5.0.1

Fixed
  • Fixes a race condition when retrieving the user’s notification settings.
  • Fixes an issue where duplicate data could be recorded after force quitting the application.

5.0.0 (Early Access)

We are excited to announce the initial release of the Braze Swift SDK!

The Braze Swift SDK is set to replace the current Braze iOS SDK and provides a more modern API, simpler integration, and better performance.

Current limitations

The following features are not supported yet:

  • Objective-C integration
  • tvOS integration
  • News Feed
  • Content Cards
。 # iOS Objective-C SDK の変更ログ Source: /docs/ja/developer_guide/platforms/legacy_sdks/ios/changelog/objc_changelog/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # iOS Objective-C SDK 変更ログ

⚠️ The New Braze Swift SDK is now available!

4.7.0

Breaking

  • Updates the minimum required version of SDWebImage from 5.8.2 to 5.18.7.

Added

  • Adds the privacy manifest to describe data usage collected by Braze. For more details, refer to the Apple documentation on privacy manifests.
  • Adds code signatures to all XCFrameworks in the Braze iOS SDK, signed by Braze, Inc..
Fixed
  • Fixes an issue in Full or Modal in-app messages where the header text would be duplicated in place of the body text under certain conditions.

4.6.0

This release requires Xcode 14.x.

Breaking

  • Drops support for iOS 9 and iOS 10.
  • Removes support for the outdated .framework assets when importing via Carthage in favor of the modern .xcframework assets.
    • Use the command carthage update --use-xcframeworks to import the appropriate Braze asset.
    • Removes support for appboy_ios_sdk_full.json in favor of using appboy_ios_sdk.json by including these lines in your Cartfile:
      1
      2
      
      binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk.json"
      github "SDWebImage/SDWebImage"
      
Fixed
  • Improves resilience when triggering in-app messages with date property filters.
Added
  • Adds a new option ABKReenqueueInAppMessage to enum ABKInAppMessageDisplayChoice.
    • Return this option in beforeInAppMessageDisplayed: of an ABKInAppMessageControllerDelegate to ensure that an in-app message is not displayed and becomes eligible to trigger again.
    • This option will reset any trigger times and re-eligibility rules as if it was never triggered. It will not add the message to the in-app message stack.

4.5.4

Fixed
  • Improves reliability of custom event property type validation.
  • Fixes an issue where the status bar would not restore to its original state after a full in-app message was dismissed.

4.5.3

Fixed
  • Fixes a crash that occurs when receiving custom event properties of numeric types under certain conditions.
  • Fixes UI responsiveness warnings when requesting location authorization status.

4.5.2

Fixed
  • Improves reliability when validating trigger properties.
  • Improves the NSURLSessionConfiguration disk and memory cache capacities for file downloads. This change enables larger file downloads to be cached if needed.

4.5.1

Fixed
  • Improves eligibility checks around the minimum trigger timeout for in-app messages by now checking at trigger time in addition to display time.
  • Fixes an issue where purchases would not trigger certain templated in-app messages.
Added
  • Adds the delegate method noMatchingTriggerForEvent:name: to ABKInAppMessageControllerDelegate, which is called if no Braze in-app message was triggered for a given event.

4.5.0

Added
  • Adds support for Content Cards to evaluate Retry-After headers.

4.4.4

Fixed
  • Calling appboyBridge.closeMessage() or brazeBridge.closeMessage() from an HTML in-app message now correctly triggers ABKInAppMessageUIDelegate.onInAppMessageDismissed: when implemented.
  • Fixes an issue in 4.4.3 where the tvOS SDK incorrectly referenced an older SDK version.

4.4.3

Fixed
  • Fixes an issue introduced in 4.4.0 which prevented custom events or purchases with an empty dictionary of properties from being logged.
  • Improves handling of ABKInAppMessageWindow’s dismissal to promptly remove it from the view hierarchy.
  • Fixes the position of the pinned indicator for Captioned Image Content Cards when using the default UI.
  • Fixes an issue introduced in 4.3.2 and limited to users of Appboy-tvOS-SDK, which prevented custom events with properties or purchases with properties from being logged.
Added
  • Adds a padding property to ABKCaptionedImageContentCardCell to support modifying the default value.

4.4.2

Fixed
  • Fixes a bug for HTML in-app messages using the HTML Upload with Preview option to improve the reliability of in-app message display.
  • Fixes a bug preventing integration via Swift Package Manager in specific contexts.
  • Fixes an issue in the default Content Cards UI where the empty feed label was truncated if it was too large for the screen, for example due to accessibility or localization.
  • Fixes an issue where Slideup in-app messages would be automatically dismissed after multiple interaction with the app’s main window.
Changed
  • If changeUser:sdkAuthSignature: is called with the current user’s ID, but with a new and valid SDK Authentication signature, the new signature will be used.
  • Improves push tracking accuracy for apps making use of UISceneDelegate (UIKit) or Scene (SwiftUI).

4.4.1

Fixed
  • Fixes an issue in which input elements with type="date" in HTML in-app messages do not respond to some user interactions on iOS 14 and iOS 15.
  • Fixes ABKSdkMetadata availability when using the dynamic variant of the SDK.
  • Fixes an issue in which the default content cards UI’s empty feed label does not wrap properly when the device is using Larger Accessibility Sizes for its text size.
Changed
  • Changed ABKInAppMessageUIDelegate.inAppMessageViewControllerWithInAppMessage: to accept a nil return value.
Added
  • Adds support for the playsinline attribute on HTML <video> elements within webpages that are opened in the app by Braze.
  • Adds XCFramework support for the Core integration via Carthage. Please follow the Carthage migration guide when transitioning to the new artifact.

4.4.0

Breaking
  • Adds XCFramework support to Carthage. This allows projects integrated via Carthage to support Apple Silicon simulators and Mac Catalyst.
    • When migrating from the original .framework to the new .xcframework, follow the official Carthage migration guide.
    • For those using the Full integration, use the following lines in your Cartfile. Note that it references the file appboy_ios_sdk.json:
      1
      2
      
      binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk.json"
      github "SDWebImage/SDWebImage"
      
      • To continue using the original Full .framework file, include the Cartfile lines above but reference appboy_ios_sdk_full.json. Then, run carthage update.
    • For those using the Thin integration, use the same Cartfile above but exclude the line with SDWebImage.
    • The Core integration does not support XCFrameworks, and you can use the original .framework files as before.
Added
  • Adds a new attachment to the release called Appboy_iOS_SDK.xcframework.zip.
    • This artifact has the all-in-one XCFramework containing the full SDK code including all of the assets.
    • When importing this code manually, drag-and-drop the XCFramework into your project and select Embed & Sign. Then, add -ObjC under Build Settings > Other Linker Flags in your app’s target.
  • Adds localization support for the close button’s accessibility label in modal and full in-app messages.
  • Adds the ability to set the SDK’s log level at runtime by setting ABKLogLevelKey to an integer in appboyOptions. Descriptions of the available log levels can be found here.
  • Adds Appboy.addSdkMetadata: to allow self reporting of SDK Metadata fields via the ABKSdkMetadata enum.

4.3.4

This release requires Xcode 13.

Fixed
  • Fixes an issue in which the pinned indicator for a Banner Content Card would not display in the default Content Cards UI.
  • Fixes an issue which prevented custom events and purchases with properties larger than 50 KB to be properly discarded.

4.3.3

Fixed
  • Fixes a race-condition occasionally preventing HTML in-app messages with assets from being displayed from a test push.
  • Fixes an issue which prevented HTML in-app messages from opening sms:, mailto:, tel:, facetime: and facetime-audio: urls.
    • Previously, those urls would fail to open silently.
  • Fixes an issue where ABKContentCardsTableViewController was not displaying the “no update” label after the last card was deleted from the feed.
Added
  • Adds methods addToSubscriptionGroupWithGroupId: and removeFromSubscriptionGroupWithGroupId: to ABKUser to manage SMS/Email Subscription Groups.
    • Also adds appboyBridge.getUser().addToSubscriptionGroup(groupId) and appboyBridge.getUser().removeFromSubscriptionGroup(groupId) to the javascript interface for HTML in-app messages.

4.3.2

Fixed
  • Iframes embedded in an HTML in-app message are now displayed as part of the same in-app message. Previously, iframes would be loaded in a separate webview.
Added
  • Adds support for navigation bar transparency changes introduced in iOS 15. Apps using Braze default UIs for Content Cards, the News Feed, and the modal WebView should upgrade to this version as soon as possible ahead of iOS 15’s release.

4.3.1

Fixed
  • The sdkAuthenticationDelegate now works as expected when setting the property directly.
  • VoiceOver no longer reads content beneath the displayed in-app message.
Changed
  • The number of unviewed Content Cards in ABKContentCardsController’s unviewedContentCardCount now excludes control cards.
  • The default Content Cards UI now allows swipe-to-refresh gestures when empty.
  • Deprecates ABKInAppMessageController’s method displayNextInAppMessageWithDelegate: in favor of displayNextInAppMessage.
Added
  • Custom events and purchases now support nested properties.
    • In addition to integers, floats, booleans, dates, or strings, a JSON object can be provided containing dictionaries of arrays or nested dictionaries. All properties combined can be up to 50 KB in total length.

4.3.0

Breaking
  • Refined Content Cards UI public api changes introduced in 4.2.0.
Fixed
  • Fixes an issue introduced in 4.2.0 that caused Content Card type ABKClassicImageContentCardCell to crash on display when not using Storyboard.

4.2.0

⚠️ Known Issues
  • This release contains a known issue with the Content Cards default UI on iOS, where showing a “Classic” type card with an image causes a crash. If you are using the default Content Cards UI, do not upgrade to this version.
Breaking
  • Content Cards and News Feed are now more extensible!
Fixed
  • Fixes an issue with Dynamic Type support introduced in 3.34.0 to be compatible with iOS 9.
Added
  • Adds support for new SDK Authentication feature.
  • Exposes window.brazeBridge in HTML in-app messages which replaces window.appboyBridge. appboyBridge is deprecated and will be removed in a future version of the SDK.
Changed
  • Makes in-app message window handling more resilient:
    • The in-app message window tries to display up to 10 times when another window competes for visibility. If the in-app message is not guaranteed visibility, it is dismissed and an error is logged.
  • Improves Appboy’s wipeDataAndDisableForAppRun and disableSDK to handle additional use cases.
  • Deprecates flushDataAndProcessRequestQueue in favor of requestImmediateDataFlush.

4.1.0

Breaking
  • ABKURLDelegate method handleAppboyURL:fromChannel:withExtras: is now invoked for all urls.
    • Previously, this delegate method was not invoked for urls opened in a WebView or the default browser when originating from the News Feed or Content Cards.
  • Removes ABKUIURLUtils method openURLWithSystem:fromChannel:. Use openURLWithSystem: as a replacement.
Fixed
  • Fixes a case where the ABKURLDelegate method handleAppboyURL:fromChannel:withExtras: was being called twice when opening a push notification with an url.
Changed
  • Deprecates ABKUnknownChannel.

4.0.2

Fixed
  • Fixes a double redirection bug in Push Stories when the app is in a terminated state and application:didReceiveRemoteNotification:fetchCompletionHandler: is not implemented.
Changed
  • Improves the Swift Package Manager bundle lookup to be more flexible.
Added
  • Adds support to use a dictionary named Braze instead of Appboy when adding customization in the Info.plist. After adding the Braze dictionary, please remove the previous Appboy dictionary.

4.0.1

Fixed
  • Sets CFBundleSupportedPlatforms in .plist files to the correct non-simulator value.
  • Removes the Dynamic Type support warnings.

4.0.0

Breaking
  • AppboyKit is now distributed as an XCFramework when integrating with Cocoapods. Cocoapods 1.10.0+ is required.
Fixed
  • Fixes the Swift Package Manager cleanup script to remove only the necessary files.
Added
  • Adds Mac Catalyst support for apps integrating with Cocoapods.

3.34.0

Breaking
  • Replaces ABKInAppMessageSlideupViewController’s slideConstraint by offset.
Added
  • Adds a new Github repo to optimize import speeds for applications integrating with Swift Package Manager.
    • To use this repo, follow these steps:
      • Remove the existing package in your application that points to the url: https://github.com/Appboy/Appboy-ios-sdk.
      • Add a new package using the new url: https://github.com/braze-inc/braze-ios-sdk.
      • Follow the rest of the setup instructions here.
  • Adds support for Right-to-Left languages in the News Feed.
  • Adds support for scaling fonts automatically with Dynamic Type for in-app messages and the News Feed.
Changed
  • Improves accessibility handling for modal and full in-app messages.
  • Improves Slideup in-app message animations.

3.33.1

Fixed
  • Fixes Swift Package Manager integration.
    • In Xcode, select File ▸ Swift Packages ▸ Update to Latest Package Versions to update.
  • Fixes Push Story integration via CocoaPods for applications that have use_frameworks! in their Podfile.

3.33.0

Breaking
  • Changed Push Story integration to use XCFrameworks for Cocoapods and manual integration. Applications currently integrating Push Stories via Cocoapods or manual integration must follow these steps when updating:
    • In your Notification Content Extension target:
      • Remove AppboyPushStory.framework from Frameworks and Libraries under the General tab.
    • In your application target:
      • Delete the Copy File build phase copying the AppboyPushStory.framework to the Frameworks destination.
      • Delete the Run Script build phase that starts with:
        1
        2
        3
        4
        
        APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
        
        find "$APP_PATH" -name 'AppboyPushStory.framework' -type d | while read -r FRAMEWORK
        ...
        
  • Removed ABKSDWebImageProxy’s prefetchURLs: method.
Fixed
  • Fixes a double redirection bug in Push Stories when the app is in a terminated state and the UNUserNotificationCenter delegate is not the AppDelegate.

3.32.0

Added
  • Adds Mac Catalyst support for apps integrating with Swift Package Manager (SPM).
    • Please follow the instructions here to import the SDK with SPM. The SDK does not currently support Mac Catalyst when integrated through Cocoapods or Carthage.
    • To add Mac Catalyst support, update the Run Script Action described in the 3.31.0 section of the Changelog.
      • Replace the existing script with the following:
        1
        2
        3
        4
        
        # iOS
        bash "$BUILT_PRODUCTS_DIR/Appboy_iOS_SDK_AppboyKit.bundle/Appboy.bundle/appboy-spm-cleanup.sh"
        # macOS
        bash "$BUILT_PRODUCTS_DIR/Appboy_iOS_SDK_AppboyKit.bundle/Contents/Resources/Appboy.bundle/appboy-spm-cleanup.sh"
        

3.31.2

Fixed
  • Fixes the formatting of Full and Slideup in-app messages when displaying on iPhone 12 mini.
Changed
  • Improves Push Story click tracking handling.

3.31.1

Breaking
  • Removes the method getSDWebImageProxyClass from ABKUIUtils.
    • You can access the public class ABKSDWebImageProxy directly by importing ABKSDWebImageProxy.h.
Fixed
  • Fixes a bug in the Cocoapods integration that would lead to SDK localizations being embedded for languages not explicitly supported in the app.
  • Fixes a rare crash that would occur when no windows exist at UIWindowLevelNormal while an in-app message is being displayed and UIKit requests UI updates (orientation change, etc.).
  • Fixes a bug in modal in-app messages where some languages (such as Burmese) may have clipped text.

3.31.0

Breaking
  • For apps that have previously integrated through Swift Package Manager, please perform the following steps:
    • In the Xcode menu, click Product > Scheme > Edit Scheme...
      • Click the expand ▶️ next to Build and select Post-actions. Press + and select New Run Script Action.
      • In the dropdown next to Provide build settings from, select your app’s target.
      • Copy this script into the open field:
        1
        
        bash "$BUILT_PRODUCTS_DIR/Appboy_iOS_SDK_AppboyKit.bundle/Appboy.bundle/appboy-spm-cleanup.sh"
        
    • If you are updating from 3.29.0 or 3.29.1, remove the Run Script Action previously specified in the 3.29.0 section of this changelog.
Added
  • Adds Push Stories support for apps integrating with Swift Package Manager.
    • In your app content extension’s target, under Build Settings > Other Linker Flags, add the -ObjC linker flag.
Changed
  • Updates the email validation on the SDK to be more lenient in favor of more accurate validation by the Braze backend. Valid emails with uncommon patterns or international characters that were previously rejected will now be accepted.
  • Deprecates ABKDeviceWhitelistKey in favor of ABKDeviceAllowlistKey.
Fixed
  • Fixes a bug in HTML in-app messages where some native WebKit UI elements could be unresponsive.

3.30.0

Breaking
  • Body click analytics will no longer automatically be collected for HTML in-app messages created using the HTML Upload with Preview option in the platform.
    • To continue to receive body click analytics, you must log body clicks explicitly from your message via Javascript using appboyBridge.logClick().
Fixed
  • Fixes a bug with Full in-app messages where the button positions did not match the preview on the Braze dashboard.
  • Fixes a bug where in-app messages would be displayed below the application window under specific conditions.
    • Apps that set up their window asynchronously at startup could accidentally hide the in-app message window if one was being displayed (e.g. as a result of clicking on a test in-app message notification).
Added
  • Adds support for custom endpoints with a scheme included (https, http, etc.). For example, http://localhost:3001 will no longer result in https://http://localhost:3001 as the resolved endpoint.

3.29.1

Added

  • Adds improved support for in-app message display on iPhone 12 models.

3.29.0

Added
  • Adds initial support for Swift Package Manager. There are 2 new packages that have been added: AppboyKit for the core SDK and AppboyUI for the full SDK (including UI elements), which correspond to the Appboy-iOS-SDK/Core and Appboy-iOS-SDK pods, respectively.
    • Note that tvOS support is not available via Swift Package Manager for this release. Push Stories is only available through a side-by-side integration with Cocoapods.
    • To add the package to your project follow these steps:
      • Select File > Swift Packages > Add Package Dependency.
        • In the search bar, enter https://github.com/Appboy/Appboy-ios-sdk.
        • Select one of AppboyKit or AppboyUI. Note that AppboyUI includes AppboyKit automatically.
      • In your app’s target, under Build Settings > Other Linker Flags, add the -ObjC linker flag.
      • In the Xcode menu, click Product > Scheme > Edit Scheme...
        • Click the expand ▶️ next to Build and select Post-actions. Press + and select New Run Script Action.
        • In the dropdown next to Provide build settings from, select your app’s target.
        • Copy this script into the open field:
          1
          2
          
          rm -rf "${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Frameworks/libAppboyKitLibrary.a"
          rm -rf "${TARGET_BUILD_DIR}/${PRODUCT_NAME}.app/Plugins/libAppboyKitLibrary.a"
          

3.28.0

Breaking
  • Removes userNotificationWasSentFromAppboy: and pushNotificationWasSentFromAppboy: on Appboy. Use isAppboyUserNotification: and isAppboyRemoteNotification: in ABKPushUtils instead.
  • Updates ABKURLDelegate’s method signature for handleAppboyURL:fromChannel:withExtras: to include nullability annotations required for proper Swift support.
Fixed
  • Fixes a race condition in Appboy method wipeDataAndDisableForAppRun where certain persisted fields would still be available immediately after calling the method. These fields now are removed synchronously.
Changed
  • Updated SDWebImage to use version 5.9.x.

3.27.0

Breaking
  • Adds support for iOS 14. Requires Xcode 12.
  • Removes the ABK_ENABLE_IDFA_COLLECTION preprocessor macro from the SDK.
  • Updates the ABKIDFADelegate protocol by renaming isAdvertisingTrackingEnabled to isAdvertisingTrackingEnabledOrATTAuthorized to reflect the addition of the AppTrackingTransparency framework in iOS 14.
    • If you use the Ad Tracking Enabled segment filter on the Braze dashboard or are implementing AppTrackingTransparency, you must update your integration to use AppTrackingTransparency to read the correct user status. Please see our sample app for implementation details.
    • If you do not use the Ad Tracking Enabled segment filter and are not implementing AppTrackingTransparency yet, your implementation of isAdvertisingTrackingEnabledOrATTAuthorized may temporarily continue to use isAdvertisingTrackingEnabled. However, the returned value will always be NO in iOS 14, regardless of actual IDFA availability.
    • Note that Apple announced that they will delay the enforcement of upcoming IDFA changes until early 2021. Please reference our iOS 14 upgrade guide for more details.
  • Updates the minimum required version of SDWebImage from 5.0 to 5.8.2.
  • Integrators will now be required to exclude the arm64 simulator slice in their entire project.
    • This is done automatically when integrating via Cocoapods.
    • For other cases:
      • If you are using xcconfig files to build your app, please set:
        • For iOS targets: EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64
        • For tvOS targets: EXCLUDED_ARCHS[sdk=appletvsimulator*] = arm64
      • If you are using the Xcode Build Settings panel, enable Build Active Architecture Only for the configuration you use to run your app on the simulator. (ONLY_ACTIVE_ARCH = YES)

3.26.1

Changed
  • Deprecates the compilation macro ABK_ENABLE_IDFA_COLLECTION in favor of the ABKIDFADelegate implementation.
    • ABK_ENABLE_IDFA_COLLECTION will not function properly in iOS 14. To continue collecting IDFA on iOS 14 devices, please upgrade to Xcode 12 and implement App Tracking Transparency and Braze’s ABKIDFADelegate (see the iOS 14 upgrade guide for more information).
Added
  • Adds improved support for iOS 14 Approximate Location tracking.

3.26.0

Breaking
  • Removed readonly property overrideApplicationStatusBarHiddenState in ABKInAppMessageViewController.h.
Fixed
  • Fixes an issue with in-app messages not respecting the application’s status bar style when View controller-based status bar appearance (UIViewControllerBasedStatusBarAppearance) is set to YES in the Info.plist.
  • Fixes an issue which can lead to text being cut off in Content Cards for specific iPhone models.
  • Fixes an issue preventing test Content Cards from displaying under specific conditions.
Changed
  • Added Binary Project Specification file for more efficient Carthage integration of the full SDK.
    • Update your Cartfile to use binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk_full.json"
    • Support for this integration method was added starting with version 3.24.0 of the SDK.
Added
  • Adds support for specifying PushStoryAppGroup in the Appboy dictionary in your app’s Info.plist. This Apple App Group will share the Braze Push Story information such as Campaign IDs between applications from a single Apple Developer account.
  • Adds appboyBridge.getUser().addAlias(alias, label) to the javascript interface for HTML in-app messages.
  • Adds the property overrideUserInterfaceStyle to ABKInAppMessage that allows forcing Light or Dark mode in the same way as Apple’s UIViewController.overrideUserInterfaceStyle.
  • Adds the ability to dismiss modal in-app messages when the user clicks outside of the in-app message.
    • This feature is disabled by default.
    • You can enable the feature by adding the Appboy dictionary to your Info.plist file. Inside the Appboy dictionary, add the DismissModalOnOutsideTap boolean subentry and set the value to YES.
    • You can also enable the feature at runtime by setting ABKEnableDismissModalOnOutsideTapKey to YES in appboyOptions.

3.25.0

Breaking
  • Removes the arm64e architecture when building with Cocoapods.
  • Removes the deprecated property appWindow from ABKInAppMessageWindowController.

3.24.2

Fixed
  • Fixes an issue with post-dismissal view hierarchy restoration for in-app messages under specific conditions.
Changed
  • Deprecates ABKInAppMessageWindowController property appWindow.

3.24.1

Fixed
  • Fixes an issue introduced in 3.24.0 breaking the SDK compatibility with Cocoapods.

3.24.0

Important This release is not compatible with Cocoapods. Do not upgrade to this version and upgrade to 3.24.1 and above instead.

Breaking
  • Renames ABKInAppMessageWindow’s catchClicksOutsideInAppMessage to handleAllTouchEvents.
Fixed
  • Fixes an issue where the unread indicator on a Content Card would persist even after being read.
  • Fixes an issue preventing long texts from displaying correctly in Full in-app messages.
  • Fixes an issue where appboyBridge would not work in an Ajax callback within HTML In-App Messages.
Changed
  • Changes the manual integration steps for versions 3.24.0 and newer. Please follow the updated integration steps here.
Added
  • Adds support for JavaScript functions window.alert(), window.confirm() and window.prompt() in HTML in-app messages.
  • Adds the ABKContentCardsTableViewControllerDelegate protocol to more intricately handle Content Card clicks using the methods contentCardTableViewController:shouldHandleCardClick: and contentCardTableViewController:didHandleCardClick:.

3.23.0

Fixed
  • Fixes an issue with regex based event property triggers not working as expected. Previously on iOS they had to match the entire string, now they will search for matches as expected.
  • Improves resiliency when handling multiple background requests.
Added
  • Adds support for upcoming HTML In-App Message templates.
  • Adds support for applications using scenes (UIWindowSceneDelegate). In-app messages are now properly displayed in that context.

3.22.0

Breaking
  • Removes the key ABKInAppMessageHideStatusBarKey from appboyOptions and the property forceHideStatusBar from ABKInAppMessageController. Full screen in-app messages are now always displayed with the status bar hidden.
  • Adds Dark Mode support to Content Cards. This feature is enabled by default and can be disabled by setting enableDarkTheme property to NO on ABKContentCardsTableViewController before the view controller is presented.
Fixed
  • Fixes an issue in HTML in-app messages where button clicks weren’t correctly being attributed for mailto: and tel: links.
  • Fixes an issue in HTML in-app messages where videos would be displayed underneath the in-app message when full screen playback was enabled. The in-app message UIWindow’s windowLevel is now set to UIWindowLevelNormal instead of being above UIWindowLevelStatusBar.
  • Fixes an issue in Content Cards where ABKURLDelegate was not being respected when opening links.
Added
  • Adds appboyBridge.logClick(id), appboyBridge.logClick() and appboyBridge.getUser().setCustomLocationAttribute(key, latitude, longitude) to the javascript interface for HTML in-app messages.
  • Adds Czech and Ukrainian language support for Braze UI elements.
  • Adds the ability to unset the current user’s email attribute by setting the email property of the current ABKUser instance to nil (e.g. [Appboy sharedInstance].user.email = nil;).
  • Adds Dark Mode support to Push Stories.
  • Adds the ability to set maximum width of Content Cards by using the maxContentCardWidth property of ABKContentCardsTableViewController.

3.21.3

Added
  • Adds an option to disable automatic geofence requests.
    • You can do this in the plist by adding the Appboy dictionary to your Info.plist file. Inside the Appboy dictionary, add the DisableAutomaticGeofenceRequests boolean subentry and set the value to YES.
    • You can also disable automatic geofence requests at runtime by setting ABKDisableAutomaticGeofenceRequestsKey to YES in appboyOptions.
  • Adds the method requestGeofencesWithLongitude:latitude: to Appboy.h. This method can be called whenever you explicitly want Braze to send a request for updated Geofences information. This call is rate limited to once per user session.

3.21.2

Fixed
  • Fixes an issue in HTML in-app messages where, during display, the viewport would shift down if the keyboard was opened but not shift back up when the keyboard was closed.
  • Fixes an issue introduced in 3.17.0 where the SDK would give precedence to the endpoint passed in Info.plist if given both an endpoint from the Info.plist and appboyOptions.
Added
  • Adds the ability to set a custom WKWebViewConfiguration for HTML in-app messages. You can set it using the method setCustomWKWebViewConfiguration in ABKInAppMessageUIDelegate.
Changed
  • Removes calls to deprecated APIs statusBarOrientation and statusBarFrame.
  • Un-deprecates the following push utility methods: isUninstallTrackingUserNotification:, isUninstallTrackingRemoteNotification:, isGeofencesSyncUserNotification:, isGeofencesSyncRemoteNotification:, and isPushStoryRemoteNotification: from ABKPushUtils. These APIs were originally deprecated in 3.16.0.

3.21.1

Fixed
  • Fixes an issue for Modal and Full in-app messages where the opacity value of the close X button was not being respected.
Changed
  • ABKContentCard.m will now log a click event when logContentCardClicked is called and no URL field is populated.
Added
  • Adds the ability to force the status bar to hide when a Full or HTML in-app message is being actively displayed. To opt in to this feature, set ABKInAppMessageHideStatusBarKey to YES in appboyOptions.

3.21.0

Breaking
  • Requires XCode 11.
Fixed
  • Fixes an issue in the animate-in behavior of HTML in-app messages that could cause a brief flicker before the message displayed on older devices and simulators.
  • Fixes an issue with Slideup in-app messages where they would cover part of the status bar when animating from the top on non-notched devices.
  • Fixes an issue introduced in 3.14.1 where boolean-typed event properties would be improperly cast to numbers.
Changed
  • Updates the logging format for debug, warn, and error ABKLogger messages to now print their log level.
Added
  • Adds support for the upcoming feature, in-app messages with Dark Mode support.
    • Dark Mode enabled messages must be created from the dashboard. Braze does not dynamically theme in-app messages for Dark Mode.
    • This feature is enabled by default for all new ABKInAppMessage instances. To prevent Braze from automatically applying a Dark Theme when the fields are available on Braze’s servers, set the enableDarkTheme flag on ABKInAppMessage to NO in the beforeInAppMessageDisplayed: method of your ABKInAppMessageControllerDelegate delegate implementation.
  • Adds the ability to reference the Braze iOS SDK API from Swift when using the Appboy-tvOS-SDK pod. Adding import AppboyTVOSKit to the top of your Swift file while using the Appboy-tvOS-SDK pod will give you equivalent behavior to adding import Appboy_iOS_SDK while using the Appboy-iOS-SDK pod.
  • Adds the populateContentCards: method and the cards property to ABKContentCardsTableViewController’s public interface. By setting the cards property from within populateContentCards:, you may manipulate ABKContentCard field data and/or control which ABKContentCard instances are displayed from the context of a custom ABKContentCardsTableViewController subclass.

3.20.4

Fixed
  • Fixed an issue with Content Cards where the header and description text fields would appear to be missing in Dark Mode.
Added
  • Adds a TEALIUM SDK flavor option.

3.20.3

Added
  • If Automatic Braze location collection is enabled, the SDK now submits a session start location request if location hasn’t already been sent up for the session after any affirmative location permission prompt. This also applies to the new “Allow Once” option in iOS 13.

3.20.2

Important If you are on Braze iOS SDK 3.19.0 or below, we recommend upgrading to this version immediately to ensure uninterrupted collection of new push tokens as users upgrade to iOS 13.

  • In application:didRegisterForRemoteNotificationsWithDeviceToken:, replace
    1
    2
    
    [[Appboy sharedInstance] registerPushToken:
                  [NSString stringWithFormat:@"%@", deviceToken]];
    

    with

    1
    
    [[Appboy sharedInstance] registerDeviceToken:deviceToken];
    
  • If you are on Braze iOS SDK 3.19.0 or below and unable to upgrade, you must ensure your [Appboy registerPushToken] implementation does not rely on stringWithFormat or description for parsing the deviceToken passed in from application:didRegisterForRemoteNotificationsWithDeviceToken:. Please reach out to your Customer Success Manager for more information.

  • Important In Braze iOS SDK 3.19.0, we updated our HTML in-app message container from UIWebview to WKWebView, however, the initial releases have known issues displaying HTML in-app messages. If you are currently using 3.19.0, 3.20.0, or 3.20.1, you are strongly encouraged to upgrade if you make use of HTML in-app messages. Please see the following for more important information about the transition to WKWebView:
    • If you are utilizing customization for HTML in-app messages (such as customizing ABKInAppMessageHTMLFullViewController or ABKInAppMessageHTMLViewController), we strongly recommend testing to ensure your in-app messages continue to display correctly and interactions function as intended.
    • The following javascript methods are now no-ops: alert, confirm, prompt.
    • Deep links without schemes are no longer supported. Ensure that your in-app message deep links contain schemes.
Fixed
  • Fixes an issue introduced in 3.19.0 where HTML in-app messages would not register user clicks when the .xib failed to load.
  • Fixes an issue introduced in 3.19.0 where HTML in-app messages with select special characters and an assets zip would cause display irregularities.
Changed
  • Updates the WKWebView which displays HTML in-app messages with the following attributes:
    • suppressesIncrementalRendering is set to true
    • mediaTypesRequiringUserActionForPlayback is set to WKAudiovisualMediaTypeAll
  • Updates the background color of the WKWebView which displays HTML in-app messages from [[UIColor blackColor] colorWithAlphaComponent:.3] to [UIColor clearColor].

3.20.1

Important This release has known issues displaying HTML in-app messages. Do not upgrade to this version and upgrade to 3.20.2 and above instead. If you are using this version, you are strongly encouraged to upgrade to 3.20.2 or above if you make use of HTML in-app messages.

Fixed
  • Fixes an issue introduced in 3.19.0 which changed the background of HTML in-app messages to a non-transparent color.
  • Improves the robustness of push token collection code for iOS 13 introduced in 3.20.0.

3.20.0

Important This release has known issues displaying HTML in-app messages and a known issue with push token collection. Do not upgrade to this version and upgrade to 3.20.2 and above instead. If you are using this version, you are strongly encouraged to upgrade to 3.20.2 or above if you make use of HTML in-app messages.

Breaking
  • Introduced a signature change for push token collection methods:
    1
    2
    
    [[Appboy sharedInstance] registerPushToken:
                  [NSString stringWithFormat:@"%@", deviceToken]];
    

    with

    1
    
    [[Appboy sharedInstance] registerDeviceToken:deviceToken];
    

3.19.0

Important This release has known issues displaying HTML in-app messages. Do not upgrade to this version and upgrade to 3.20.2 and above instead. If you are using this version, you are strongly encouraged to upgrade to 3.20.2 or above if you make use of HTML in-app messages.

Breaking
  • Replaces UIWebView with WKWebView for HTML in-app messages.
    • If you are utilizing customization for HTML in-app messages (such as customizing ABKInAppMessageHTMLFullViewController or ABKInAppMessageHTMLViewController), you must test to ensure your in-app messages continue to display correctly and interactions function as intended.
    • The following javascript methods are now no-ops: alert, confirm, prompt.
    • Deep links without schemes are no longer supported. Please ensure that your in-app message deep links contain schemes.

3.18.0

Breaking
  • Automatic Braze location collection is now disabled by default. If you choose to use our location collection, you must explicitly enable location collection.
    • You can do this in the plist by adding the Appboy dictionary to your Info.plist file. Inside the Appboy dictionary, add the EnableAutomaticLocationCollection boolean subentry and set the value to YES.
    • You can also enable location at runtime by setting ABKEnableAutomaticLocationCollectionKey to YES in appboyOptions.
  • Removes the Feedback feature from the SDK. The Feedback subspec and all Feedback methods on the SDK, including [[Appboy sharedInstance] submitFeedback] and [[Appboy sharedInstance] logFeedbackDisplayed], are removed.
Changed
  • Improves support for in-app messages on “notched” devices (for example, iPhone X, Pixel 3XL). Full-screen messages now expand to fill the entire screen of any phone, while covering the status bar.
Added
  • Adds the ability to enable Braze Geofences without enabling Braze location collection. You can set this in the plist by adding the Appboy dictionary to your Info.plist file. Inside the Appboy dictionary, add the EnableGeofences boolean subentry and set the value to YES to enable Braze Geofences. You can also enable geofences at runtime by setting ABKEnableGeofencesKey to YES in appboyOptions.
    • If this key is not set, it will default to the status of automatic location collection (see breaking change above).
    • Note that Braze Geofences will continue to work on existing integrations if location collection is enabled and this new configuration is not present. This new configuration is intended for integrations that want Braze Geofences, but not location collection enabled as well.

3.17.0

Breaking
  • Removes ABKAppboyEndpointDelegate.
    • You can now set the endpoint at runtime by setting the value of ABKEndpointKey in appboyOptions to your custom endpoint (ex. sdk.api.braze.eu) at initialization.

3.16.0

  • Important: If you are using ABKAppboyEndpointDelegate, you will need to replace dev.appboy.com with sdk.iad-01.braze.com in the getApiEndpoint method.
Breaking
  • Removes the methods: allowRequestWhenInUseLocationPermission and allowRequestAlwaysPermission from ABKLocationManager.
    • To request when in use location permission, use the following code:
      1
      2
      
      CLLocationManager *locationManager = [[CLLocationManager alloc] init];
      [locationManager requestWhenInUseAuthorization];
      
    • To request always location permission, use the following code:
      1
      2
      
      CLLocationManager *locationManager = [[CLLocationManager alloc] init];
      [locationManager requestAlwaysAuthorization];
      
    • The preprocessor macro ABK_DISABLE_LOCATION_SERVICES is no longer needed.
    • Important: Configuring geofences to request always location permissions remotely from the Braze dashboard is no longer supported. If you are using Geofences, you will need to ensure that your app requests always location permission from your users manually.
  • ABKAutomaticRequestProcessingExceptForDataFlush is deprecated. Users using ABKAutomaticRequestProcessingExceptForDataFlush should switch to ABKManualRequestProcessing, as the new behavior of ABKManualRequestProcessing is identical to the previous behavior of ABKAutomaticRequestProcessingExceptForDataFlush
Changed
  • Deprecates the push utility methods: isUninstallTrackingUserNotification:, isUninstallTrackingRemoteNotification:, isGeofencesSyncUserNotification:, isGeofencesSyncRemoteNotification:, and isPushStoryRemoteNotification: from ABKPushUtils. Please use the function isAppboyInternalRemoteNotification:.
  • Minor changes to the logic of ABKManualRequestProcessing. The original ABKManualRequestProcessing had specific exceptions and behaved more like ABKAutomaticRequestProcessingExceptForDataFlush in practice. As a result, the two policies have been merged into ABKManualRequestProcessing. Note that the new definition of ABKManualRequestProcessing is that periodic automatic data flushes are disabled. Other requests important to basic Braze functionality will still occur.

3.15.0

  • Important: If you are using ABKAppboyEndpointDelegate, you will need to replace dev.appboy.com with sdk.iad-01.braze.com in the getApiEndpoint method.
Breaking
  • Adds support for SDWebImage version 5.0.
    • Note that upgrading to SDWebImage 5.0 also removed the FLAnimatedImage transitive dependency from the SDK.

3.14.1

  • Important: If you are using ABKAppboyEndpointDelegate, you will need to replace dev.appboy.com with sdk.iad-01.braze.com in the getApiEndpoint method.
Changed
  • Changed in-app message trigger behavior to not perform trigger events until after any pending trigger sync requests to the server have finished.
Fixed
  • Fixed a serialization issue that could cause improper type conversions for certain decimal values.
  • Fixed a behavior introduced in 3.12.0 which caused in-app messages to not be considered triggered locally if ABKDiscardInAppMessage was returned by the host app in beforeInAppMessageDisplayed:.
Added
  • Added the ability to set the session timeout via the Info.plist.
    • Add the Appboy dictionary to your Info.plist file. Inside the Appboy Dictionary, add the SessionTimeout Number subentry and set the value to your session timeout.
  • Added the ability to disable location tracking via the Info.plist.
    • Add the Appboy dictionary to your Info.plist file. Inside the Appboy Dictionary, add the DisableAutomaticLocation Boolean subentry and set the value to YES.
  • Added dynamic cell resizing for Content Cards cells with templated images in our default Content Cards UI.
  • Added validation to the local filename’s canonical path during zip file extraction.

3.14.0

  • Important: If you are using ABKAppboyEndpointDelegate and plan to upgrade to 3.14.1, you will need to replace dev.appboy.com with sdk.iad-01.braze.com in the getApiEndpoint method.
Added
  • Improves the look and feel of In-App Messages to adhere to the latest UX and UI best practices. Changes affect font sizes, padding, and responsiveness across all message types. Now supports button border styling.

3.13.0

Breaking
  • Upgrades the delivery mechanism of Push Stories to allow delivery even after a user’s app has been force closed..
    • Required: Please change your integration to use ab_cat_push_story_v2 instead of ab_cat_push_story for the UNNotificationExtensionCategory in your content extension. See documentation for more details.
Changed
  • Improves in-app message triggering logic to fall back to lower priority messages when the Braze server aborts templating (e.g. from a Connected Content abort in the message body, or because the user is no longer in the correct Segment for the message).
  • Updates German translations to improve formatting.

3.12.0

Breaking
  • Drops support for iOS 8.
  • Adds support for the arm64e architecture when building with Cocoapods. Requires Xcode 10.1.
Fixed
  • Fixes bitcode support for the Push Story framework when using Xcode 10.
  • Improves triggered in-app message re-eligibility logic to better handle templating failures.
Changed
  • Changes the behavior of News Feed so that only one impression is logged for each card per News Feed open.
Added
  • Adds HTML IAM appboyBridge ready event to know precisely when the appboyBridge has finished loading.
    • Example below:
      1
      2
      3
      4
      5
      6
      
       <script type="text/javascript">
         function logMyCustomEvent() {
           appboyBridge.logCustomEvent('My Custom Event');
         }
         window.addEventListener('ab.BridgeReady', logMyCustomEvent, false);
       </script>
      
Removed
  • Removes Cross-Promotion cards from the News Feed.
    • Cross-Promotion cards have also been removed as a card model and will thus no longer be returned.

3.11.0

Added
  • Adds the ability to set or remove custom location attributes for a specific user from within HTML IAMs.
  • Updates the SDK to report users who disable banner notifications but are still opted-in to push notifications as push enabled. Note this change does not affect provisionally authorized users on iOS 12, who were considered push enabled before this release regardless of their banner notification settings.
  • Adds Carthage Core support which allows for integration with the core Braze SDK without any UI components. To implement the core SDK, add binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk_core.json" to your Cartfile.
Changed
  • Deprecates the Feedback feature.
Fixed
  • Fixes an issue with the JS bridge when trying to set a custom attribute with the character ‘&’.

3.10.0

Added
  • Adds the ability to specify a whitelist for device fields that are collected by the Braze SDK.
    • Configurable device fields are defined in the ABKDeviceOptions enum.
    • To specify whitelisted device fields, assign the bitwise OR of desired fields to ABKDeviceWhitelistKey in the appboyOptions of startWithApiKey:inApplication:withAppboyOptions:.
      • For example, to specify timezone and locale collection to be whitelisted, set appboyOptions[ABKDeviceWhitelistKey] = @(ABKDeviceOptionTimezone | ABKDeviceOptionLocale);.
    • To turn off all fields, set appboyOptions[ABKDeviceWhitelistKey] = @(ABKDeviceOptionNone);.
    • By default, all fields are enabled.
  • Added the clicked property to ABKContentCard. Clicks made through [ABKContentCard logContentCardClicked] are now saved locally on the device.
Breaking
  • Removes ABKSignificantChangeCollectionEnabledOptionKey, ABKSignificantChangeCollectionDistanceFilterOptionKey, and ABKSignificantChangeCollectionTimeFilterOptionKey from the Appboy interface.
Removed
  • Removes the ability to optionally track locations in the background.
Fixed
  • Fixes an issue where Slideup and Full In-App Message content could be obscured by the notch on iPhone XR and iPhone XS Max.

3.9.0

Breaking
  • Adds support for iOS 12. Requires Xcode 10.
Fixed
  • Fixes minor issues with subclassing ABKInAppMessageModalViewController and News Feed request timeouts.
    • Thanks @datkinnguyen for your contribution.

3.8.4

Fixed
  • Fixes a regression introduced in version 3.8.3 that caused background tasks to extend beyond execution time.

3.8.3

Fixed
  • Fixes an issue where ABKContentCardsController unviewedContentCardCount would always return 0.
Changed
  • Updates the Content Cards UI with minor layout improvements.

3.8.2

Fixed
  • Fixes an issue with possible build failure when using Content Cards related to duplicate image names in Content Cards and News Feed pods. Please use this version if integrating Content Cards.
Changed
  • Updates the Content Cards UI with minor layout improvements.

3.8.1

Fixed
  • Important: Fixes an issue with Content Cards syncing. Note: As additional fixes were added in later versions, please use Braze iOS SDK version 3.8.2 or above if integrating Content Cards.

3.8.0

Added
  • In ABKUser class, addLocationCustomAttributeWithKey:latitude:longitude: and removeLocationCustomAttributeWithKey: methods are added to manage location custom attributes.
  • Introduces support for the upcoming Content Cards feature, which will eventually replace the existing News Feed feature and adds significant capability. This feature is currently in closed beta testing; if you’re interested in joining the beta, please reach out to your Customer Success Manager or Account Manager.
Changed
  • Status bar is not obscured when displaying a full screen in-app message.

3.7.1

Changed
  • Improves data handling immediately following a user change to bring behavioral parity with the Android and Web SDKs.

3.7.0

Breaking
  • In ABKInAppMessageUIControlling protocol, getCurrentDisplayChoiceForControlInAppMessage method is added to define whether the control in-app message impression should be logged now, later or discarded.
  • In ABKInAppMessageControllerDelegate protocol, beforeControlMessageImpressionLogged method is added to define whether the control in-app message impression should be logged now, later or discarded.
Added
  • CLLocationManager authorization requests can now be prevented from compiling by setting a Preprocessor flag ABK_DISABLE_LOCATION_SERVICES.
Fixed
  • Fixes an issue where in-app messages triggered on session start could potentially be templated with the old user’s attributes.

3.6.0

Breaking
  • In ABKSDWebImageProxy.h, renames removeImageForKey to removeSDWebImageForKey and clearCache to clearSDWebImageCache to avoid conflicts with internal Apple API. Important: We have received reports of sporadic App Store rejection stemming from Apple’s static checks mistaking our APIs for an invalid usage of the internal Apple API. We recommend new App Store submissions integrating the Braze iOS SDK ship with this version or above to decrease the likelihood of rejection.
Added
  • Exposes handleCardClick on ABKNewsFeedTableViewController.h to enable custom handling via subclassing.
  • Improves News Feed image handling on iPad.

3.5.1

Fixed
  • Fixes an issue with integrating the NewsFeed subspec in Swift projects via Cocoapods.

3.5.0

Breaking
  • Open sources the News Feed UI code and moves it into a new subspec named “NewsFeed”.
    • Manual integrators must now add the AppboyUI folder of this repository to their projects as a group, in addition to AppboyKit.
    • The “NewsFeed” subspec contains the Braze News Feed UI and the Core SDK. It does not include the Feedback or In-App Message UI.
    • The “UI” subspec contains all Braze UI and the Core SDK subpsec.
    • ABKFeedViewControllerDelegate was removed.
    • To integrate a navigation context News Feed, use the following code:
      1
      2
      
      ABKNewsFeedTableViewController *newsFeed = [ABKNewsFeedTableViewController getNavigationFeedViewController];
      [self.navigationController pushViewController:newsFeed animated:YES];
      
    • To integrate a modal context News Feed, use the following code:
      1
      2
      
      ABKNewsFeedViewController *newsFeed = [[ABKNewsFeedViewController alloc] init];
      [self.navigationController presentViewController:newsFeed animated:YES completion:nil];
      
    • See our News Feed Sample app for sample implementations and customizations.
  • Removes NUI support for Feedback, In-App Messages, and the News Feed.
    • All customization can now be done by using categories or by extending our open sourced view controllers.
  • Removes deprecated ABKPushURIDelegate from the SDK. Use ABKURLDelegate instead.

3.4.0

Breaking
  • Adds preferredOrientation to ABKInAppMessageUIController and ABKInAppMessageWindowController.
  • Removes supportedOrientations from ABKInAppMessageUIController and ABKInAppMessageWindowController.
  • Renames supportedOrientationMasks to supportedOrientationMask in ABKInAppMessageUIController and ABKInAppMessageWindowController.
Fixed
  • Fixes an issue that caused GIFs to not animate on SDWebImage versions above or equal to 4.3.0

3.3.4

Added
  • Adds the ability to view verbose logs from the SDK for debugging.
    • To enable verbose logging, add a dictionary named Appboy to your Info.plist file. Inside the Appboy Dictionary, add the LogLevel String subentry and set the value to “0”.

3.3.3

Added
  • Adds wipeDataAndDisableForAppRun: on the Appboy interface to support wiping all customer data created by the Braze SDK.
  • Adds disableSDK: and requestEnableSDKOnNextAppRun: to the Appboy interface to disable and re-enable the Braze SDK.
Fixed
  • Fixes an issue where events setting custom attribute arrays to nil would persist on the SDK beyond their useful life.

3.3.2

Changed
  • Updates the SDK with internal, non-functional improvements.

3.3.1

Added
  • Adds Other, Unknown, Not Applicable, and Prefer not to Say options for user gender.
  • Adds umbrella header files AppboyFeedback.h and AppboyInAppMessage.h for the Feedback and InAppMessage subspecs.
Fixed
  • Fixes an issue where the method beforeInAppMessageDisplayed: in class ABKInAppMessageControllerDelegate is not called when the host app is using the Core subspec.

3.3.0

Breaking
  • Open sources the In-App Message UI code and moves it into a new subspec named “InAppMessage”.
    • Manual integrators must now add the AppboyUI folder of this repository to their projects as a group, in addition to AppboyKit.
    • The “InAppMessage” subspec contains the Braze In-App Message UI and the Core SDK. It does not include Feedback or the News Feed UI.
    • The “UI” subspec contains all Braze UI and the Core SDK subpsec.
    • The open-sourced In-App Message view controllers offer backward compatible NUI support, although we recommend using categories or subclassing the In-App Message view controllers for customization as the NUI library isn’t actively maintained any more. Support for NUI customization will be removed in a future release.
    • Most delegate customization methods are moved from ABKInAppMessageControllerDelegate to ABKInAppMessageUIDelegate.
    • See our In-App Message Sample app for sample implementations and customizations.
  • Removes support for original in-app messages. Moving forward, triggered in-app messages must be used.
  • Removes requestInAppMessageRefresh method from Appboy.
Changed
  • Removes the current behavior of displaying an in-app message from the stack on app open, if the stack is non-empty
Fixed
  • Adds Macros for methods which are only available from iOS 10.
    • Addresses https://github.com/Appboy/appboy-ios-sdk/issues/128.
  • Stops using deprecated openURL: method when in iOS 10 and above.
    • Addresses https://github.com/Appboy/appboy-ios-sdk/issues/132.

3.2.3

Fixed
  • Fixes an issue introduced in version 3.0.0 which caused detailed device model information to not be collected by the SDK.
  • Fixes an issue where Braze’s Carthage framework did not support simulators.

3.2.2

Fixed
  • Fixes an issue where Slideup and Full In-App Message content could be obscured by the notch on iPhone X.

3.2.1

Fixed
  • Fixes an issue where Push Story Framework did not support bitcode.

3.2.0

Added
  • Adds Push Stories, a new push type that uses UNNotificationContentExtension to display multiple images in a single notification.
    • This feature requires iOS 10 and above.
Fixed
  • Fixes an issue where tvOS SDK did not support bitcode.

3.1.1

Added
  • Adds a new property language to ABKUser to allow explicit control over the user’s language in the Braze dashboard. Note that this is separate and independent from the language settings on the user’s device.
  • Adds an Objective-C sample app for the Core subspec of the SDK. See Samples/Core/ObjCSample.
Fixed
  • Fixes a bug introduced in version 2.30 where crashes could occur if the SDK was directed to handle a custom scheme deep link inside a WebView.
    • Addresses https://github.com/Appboy/appboy-ios-sdk/issues/122.
  • Fixes a bug introduced in version 3.0 where new custom attributes were not being flushed if custom attributes had been previously flushed in the same foregrounded session.
  • Fixes a bug introduced in version 3.0 where previously flushed custom attributes were being re-sent.
  • Fixes an issue where slow image fetching blocked image-only modal in-app messages from displaying.
    • Addresses https://github.com/Appboy/appboy-ios-sdk/issues/118.

3.1.0

Breaking
  • Adds support for iOS 11. Requires Xcode 9.

3.0.2

Added
  • Adds the ability to set a custom API endpoint via the Info.plist.
    • Add the Appboy dictionary to your Info.plist file. Inside the Appboy Dictionary, add the Endpoint String subentry and set the value to your custom endpoint (e.g., sdk.api.braze.eu).
Fixed
  • Fixes an issue where changing the IDFA settings through a third party wrapper could cause a crash.

3.0.1

Fixed
  • Fixes an issue where calling incrementCustomUserAttribute: on ABKUser could cause a crash.

3.0.0

Breaking
  • Removes the deprecated foursquareAccessToken property from ABKUser. To associate a Foursquare access token with a user profile, use setCustomAttributeWithKey:andStringValue: instead.
  • Note: Braze iOS SDK version 3.0.0 will only support downgrading to iOS SDK version 2.31.0. Downgrading to versions prior to 2.31.0 may result in app crashes.
Added
  • Adds a major performance upgrade that reduces CPU usage, memory footprint, and network traffic.

2.31.0

Breaking
  • Open sources the Feedback view controllers and moves them into a new subspec “Feedback”.
    • The “Feedback” subspec has the Braze Feedback UI and the Core SDK. It will not include in-app messages or News Feed UI.
    • Removes the popover context for Feedback due to the deprecation of UIPopoverViewController in iOS.
    • Renames the ABKFeedbackViewControllerModalContext and ABKFeedbackViewControllerNavigationContext class to ABKModalFeedbackViewController and ABKNavigationFeedbackViewController.
    • The open-sourced Feedback view controllers offer backward compatible NUI support, although we recommend using categories or subclassing the Feedback view controllers for customization as NUI library isn’t actively maintained any more. See here for customization details.
    • See our Feedback Sample app for sample implementations and customizations.
Added
  • Adds user aliasing capability. Aliases can be used in the API and dashboard to identify users in addition to their ID. See the addAlias:withLabel: method on ABKUser for more information.
Changed
  • Updates the AppboyKit.h to include all the public header files in the SDK.

2.30.0

Breaking
  • Open sources the ABKModalWebViewController class, which is used to display the web URLs from push or in-app message clicks.
    • Drops NUI customization support for the navigation bar and navigation bar button item on ABKModalWebViewController. To customize the UI, create an ABKModalWebViewController category and override the corresponding method(s) exposed.
  • Open sources the ABKNoConnectionLocalization class, which provides Braze’s default localized string for “No Connection” error.
    • You can customize the localization by adding Appboy.no-connection.message as the key in your Localizable.strings files.
  • Removes the Appboy.bundle from the Core subspec of the SDK.
    • If you use the Core subspec, the in-app messages will not display, and trying to display Braze’s News Feed and Feedback UI will lead to unpredictable behavior.

2.29.1

Added
  • Adds a new property buttonTextFont to ABKInAppMessageButton. It allows clients to set customized fonts on in-app message buttons before the in-app message is displayed.
Fixed
  • Makes class ABKInAppMessageWindowController.h public.
    • Addresses https://github.com/Appboy/appboy-ios-sdk/issues/105.
  • Fixes an issue where device information was not flushed for a new user when server requests were queued for two or more users.
Changed
  • Removes the warnings in ABKSDWebImageProxy.

2.29.0

Breaking
  • Drops support for iOS 7.
  • Removes the shouldOpenURIExternally field from ABKInAppMessage.
  • Requires XCode 8.3.
  • Changes the behavior of the onCardClicked:feedViewController: method in ABKFeedViewControllerDelegate to let Braze handle the card click action if the delegate method returns NO.
    • Previously, Braze would handle the card click action if onCardClicked:feedViewController: returned YES.
    • This change standardizes delegate behavior with ABKInAppMessageControllerDelegate and ABKURLDelegate.
Added
  • Adds the property openUrlInWebView to ABKInAppMessage, ABKInAppMessageButton and ABKCard. This property determines if the URL associated with the object will be opened in a UIWebView.
  • Adds a Javascript interface to HTML in-app messages with ability to log custom events, log purchases, set user attributes, navigate users, and close the message.
  • Adds an abDeepLink query field to HTML in-app messages, which defaults to false. To prevent the SDK from opening deep links in a UIWebView, specify abDeepLink=true in your link (e.g., https://www.braze.com?abDeepLink=true).
  • Adds the ABKURLDelegate protocol for customizing URL handling across channels. Set the ABKURLDelegate by passing a delegate object to the ABKURLDelegateKey in the appboyOptions of startWithApiKey:inApplication:withAppboyOptions:. See our Stopwatch sample application for a Universal Link implementation sample.
  • Adds the following utility methods to ABKPushUtils for detecting if a push notification was sent by Braze for internal feature purposes:
    • + (BOOL)isAppboyInternalUserNotification:(UNNotificationResponse *)response;
    • + (BOOL)isAppboyInternalRemoteNotification:(NSDictionary *)userInfo;
    • + (BOOL)isUninstallTrackingUserNotification:(UNNotificationResponse *)response;
    • + (BOOL)isGeofencesSyncUserNotification:(UNNotificationResponse *)response;
    • + (BOOL)isGeofencesSyncRemoteNotification:(NSDictionary *)userInfo;
    • These methods can be used to ensure that your app does not take any undesired or unnecessary actions upon receiving Braze’s internal content-available notifications (e.g., pinging your server for content).
Changed
  • Deprecates ABKPushURIDelegate. If you were previously using ABKPushURIDelegate, use ABKURLDelegate instead.
  • Deprecates userNotificationWasSentFromAppboy: and pushNotificationWasSentFromAppboy: on Appboy. Use isAppboyUserNotification: and isAppboyRemoteNotification: on ABKPushUtils instead.
  • Deprecates shouldFetchTestTriggersFlagContainedInPayload: on ABKPushUtils.

2.28.0

Breaking:
  • Removes support for watchOS 1, including Braze WatchKit SDK and all public APIs for watchOS in Braze iOS SDK.
Added
  • Adds ABKSDWebImageProxy to access the SDWebImage framework. This will prevent the Core subspec of the SDK from calling any SDWebImage methods directly.

2.27.0

Breaking
  • Removes the following deprecated items: the bio field of ABKUser, the setIsSubscribedToEmails: method of ABKUser, and the getResourceEndpoint: method of the ABKAppboyEndpointDelegate protocol.
Added
  • Adds support for registering geofences and messaging on geofence events. Please reach out to success@braze.com for more information about this feature.
  • Adds Braze default push categories which can be fetched from ABKPushUtils.
    • To use the Braze default push categories, you need to manually add the Braze categories when you register for push. You can get the Braze categories from [ABKPushUtils getAppboyUNNotificationCategorySet] or [ABKPushUtils getAppboyUIUserNotificationCategorySet].
    • In this version, we add four sets of push action buttons: accept/decline, yes/no, confirm/cancel, more. These will be available as button sets on the dashboard when creating an iOS push campaign.
    • All Braze push action buttons support localization.
  • Adds support for web link and deep link handling of push action buttons.
Fixed
  • Fixes the issue where the combination of the Core subspec of the SDK and a non-supported version of SDWebImage framework can cause apps to crash.
    • Addresses https://github.com/Appboy/appboy-ios-sdk/issues/104.
Changed
  • HTML in-app messages now log body click analytics on all links that are not appboy://customEvent and do not include the abButtonId query field. Previously, no body click analytics were logged.
Removed
  • Removes deprecated method - (NSString *)getResourceEndpoint:(NSString *)appboyResourceEndpoint from ABKAppboyEndpointDelegate.
  • Removes deprecated property bio and deprecated method - (BOOL)setIsSubscribedToEmails:(BOOL)subscribed from ABKUser.

2.26.0

Breaking
  • Adds support for SDWebImage version 4.0.0 with GIF support. SDWebImage version 3.x will not be supported from this version on. Please make sure you are using the correct version of SDWebImage.framework. Note: SDWebImage 4.0.0 relies on FLAnimatedImage - users integrating in ways besides CocoaPods should ensure they link the FLAnimatedImage framework if they want GIF support.
  • Removes the url property from subclasses of ABKCard. This property has been renamed to urlString and moved onto the ABKCard superclass.
Added
  • Adds Cocoapods subspecs “Core” and “UI”.
    • The “UI” subspsec has the full feature set of the current SDK. This is the default subspec when no subspec is specified in the Podfile.
    • The “Core” subspec removes the SDWebImage framework dependency. This is for apps who do not use any Braze UI that leverages images (News Feed, in-app messages). If you use the “Core” subspec, in-app messages with images will not display, and the News Feed will render with plain white images.
  • Makes ABKThemableFeedNavigationBar.h and ABKNavigationBar.h public.
    • Addresses https://github.com/Appboy/appboy-ios-sdk/issues/68
  • Adds an unsafeInstance method that returns a nonoptional Appboy instance. If used before calling startWithApiKey: an exception will be thrown.
    • Addresses https://github.com/Appboy/appboy-ios-sdk/issues/45.
  • Adds ABKIDFADelegate protocol that can be used to create a delegate to pass Braze the IDFA in startWithApiKey: in the appboyOptions dictionary under the ABKIDFADelegateKey key. Alternative to existing ABKIdentifierForAdvertisingProvider compile flag solution.
Changed
  • Disables the -webkit-touch-callout property on HTML in-app messages. Long presses and 3D Touch on links will no longer display pop-ups with additional link information.

2.25.0

Added
  • Adds the ability to set the ABKInAppMessageControllerDelegate when the SDK starts by passing a delegate object to the ABKInAppMessageControllerDelegateKey in the appboyOptions of startWithApiKey:inApplication:withAppboyOptions:.
    • This is the recommended way to set the ABKInAppMessageControllerDelegate and circumvents a potential race condition where in-app messages can be shown before the delegate has been set.
  • Exposes the ABKFeedback object and adds a new method - (void)submitFeedback:(ABKFeedback *)feedback withCompletionHandler:(nullable void (^)(ABKFeedbackSentResult feedbackSentResult))completionHandler; in Appboy. The new method accepts a completion handler which receives an ABKFeedbackSentResult enum as feedback sending result.
    • The possible feedback sending results are: invalid feedback object(ABKInvalidFeedback), fail to send feedback(ABKNetworkIssue), and feedback sent successfully(ABKFeedbackSentSuccessfully).
  • Adds the utility method - (BOOL)userNotificationWasSentFromAppboy:(UNNotificationResponse *)response; to Appboy. This method is compatible with the UserNotifications framework and returns whether a push notification was sent from Braze’s server.
    • Those using - (BOOL)pushNotificationWasSentFromAppboy:(NSDictionary *)options; who have integrated the UserNotifications framework should use this method instead.
Fixed
  • Changes the ABKInAppMessageButton from a UIButton object to a pure data model class in NSObject.
    • This resolves the issue https://github.com/Appboy/appboy-ios-sdk/issues/97.
Changed
  • Adds more protection around triggered in-app message display.

2.24.5

Fixed
  • Fixes an issue where in-app messages triggered off of push clicks wouldn’t fire when the push click happened before the in-app message configuration was synced to the device.
Changed
  • Updates push registration to flush the token to the server immediately.
  • Improves the accessibility of in-app messages and news feed cards.
    • When in voiceOver mode, the SDK auto-focuses on in-app messages when they appear and resets focus on dismissal.
    • VoiceOver no longer reads Braze internal labels.
    • News feed cards are enhanced to be more accessible.

2.24.4

Added
  • Adds protection around in-app message UI code to avoid displaying in-app messages with corrupted images.
Fixed
  • Fixes the iOS version number in the deprecation warnings in Appboy.h.

2.24.3

Breaking
  • Update REQUIRED for apps using Braze SDK 2.24.0, 2.24.1 or 2.24.2 with UserNotifications.framework
Fixed
  • Fixes an issue where a user’s foreground push enabled status could erroneously be marked as disabled.
    • This issue can occur when opening the app from suspended mode. At that time, the foreground push enabled status was defaulted to disabled until the UserNotifications.framework returned the user’s push authorization status. If the user closed the app within a few seconds, the SDK would not flush the updated push status and the user would mistakenly be marked as “push disabled”.
    • This issue only affected apps using UserNotifications.framework to register for push notifications.
    • The updated code stores the push authorization status on disk to fix the issue.
  • Fixes an issue where triggered in-app messages with event property templating did not respect re-eligibility settings.
Changed
  • Updates the Podspecs for iOS and tvOS SDK.
  • Updates deprecation warnings to specify iOS version.
  • Updates the ABKFeedController with more generic nullability.
  • Disables all data detectors on HTML in-app messages. Phone numbers, web URLs, addresses and calendar events will no longer be automatically converted.
  • Disables scrolling bounces on HTML in-app messages.

2.24.2

Fixed
  • Fixes an issue where HTML in-app messages loaded JavaScript more than once.
  • Fixes the Appboy.inAppMessage.webview.done-button.title string in the French localization file, which was named incorrectly and wasn’t being found.

2.24.1

Added
  • Adds nullability annotation for the completionHandler in userNotificationCenter :didReceiveNotificationResponse:withCompletionHandler.

2.24.0

Breaking
  • Updates the SDK to require XCode 8.
  • iOS 10 changes behavior of application:didReceiveRemoteNotification:fetchCompletionHandler and subsequently breaks open tracking and deep link handling on most existing Braze iOS integrations. If you don’t currently implement application:didReceiveRemoteNotification: you need to modify your integration, and we recommend that all users update.
Added
  • Updates the iOS and tvOS SDKs to support iOS 10.
  • Adds a new method - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler. This method supports the new delegate method for push notification handling in UserNotification framework.
Changed
  • Deprecates two push delegate methods: - (void)registerApplication:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification and - (void)getActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(nullable void (^)())completionHandler.

2.23.0

Added
  • Adds support for upgraded in-app messages including image-only messages, improved image sizing/cropping, text scrolling, text alignment, configurable orientation, and configurable frame color.
  • Adds support for in-app messages triggered on custom event properties, purchase properties, and in-app message clicks.
  • Adds support for templating event properties within in-app messages.
Removed
  • Removes the deprecated method logSocialShare from Appboy class.

2.22.1

Changed
  • Updates tvOS bitcode support, patching an error introduced by an Xcode bug.

2.22.0

Added
  • Adds tvOS support for logging analytics; adds sample applications for tvOS and TVML.
  • Adds Hebrew localization support.

2.21.0

Breaking
  • Drops support for iOS 6.
Added
  • Adds support for deep links with non-URL-encoded characters. The SDK will encode unencoded url strings to create valid deep link NSURLs.
Fixed
  • Fixes a bug where the background of a slideup in-app message remained transparent when configured with 100% opacity.
Changed
  • Updates the podspec SDWebImage dependency to fetch the latest version.
  • Replaces SDK usage of NSURLConnection with NSURLSession.
  • Updates the SDK to always call canOpenURL: before opening a deep link. After this change, the SDK will only direct deep links whose schemes are whitelisted.
  • Updates push registration to immediately, asynchronously send up the push token.

2.20.1

Fixed
  • Fixes an issue where in certain conditions NSUserDefault blocking would cause custom events logged in the main thread to result in UI freezing.
Changed
  • Implements an optimization in push handling to not prefetch the News Feed when a push arrives and the app is in the background.

2.20.0

Added
  • Adds Carthage support.
Fixed
  • Fixes a multithreading issue where logging custom events from different threads would sporadically cause errors.
  • Fixes the issue where a close button’s color on modal and full in-app messages didn’t respect the opacity value.
  • Fixes an issue where failure to download HTML in-app message assets mid-download resulted in display without assets.
Changed
  • Now the onInAppMessageHTMLButtonClicked:clickedURL:buttonID: delegate method will be called every time a URL is clicked. The method used to be only called when there was a button ID in the URL link.
  • Updates the feedback element to reject messages that contain only whitespace.
  • Updates remote push handling to call the completion handler passed in every time (a code path previously existed that would return without calling it).
Removed
  • Removes the delegate method onInAppMessageHTMLButtonClicked:buttonID: from ABKInAppMessageControllerDelegate protocol.

2.19.3

Added
  • Adds a new feature allowing manual control of deep link handling in push notications. To use this, add a ABKPushURIDelegate value for the ABKPushURIDelegate key in the appboyOptions dictionary of startWithApiKey:inApplication:inApplication:withAppboyOptions:. Also updates the ABKPushURIDelegate integration to be initialized through that integration point.
  • Adds guarding against a possible crash caused by a user’s offline state being corrupted and not including an active session when a network request occurred.
Fixed
  • Fixes an issue where duplicate data could be recorded when a force quit or crash occurs after a network request completed successfully, but before any other activity (such as leaving the app, putting it to sleep, updating an attribute or firing some other event or purchase) occurred.

2.19.2

Added
  • Adds warning when messaging doesn’t succeed because SDWebImage is not integrated.
Fixed
  • Fixes a bug where users who went from being eligible for triggered messages to not being eligible for any triggered messages didn’t see their local triggers configuration get updated. This has already been fixed with a server-side update for affected versions; this update fixes the issue client-side.
Changed
  • Updates headers to be compatible with Swift 2.2.

2.19.1

Added
  • Adds sample code for a universal link in Stopwatch.
Fixed
  • Fixes the benign issue that caused the log message *** -[NSKeyedUnarchiver initForReadingWithData:]: data is NULL.
  • Fixes an issue where NULL campaign IDs in push messages (e.g. from a REST API push message without a specified campaign id) resulted in push-clicked triggers for triggered in-app messages not firing.
  • Fixes an issue where calling changeUser between identified users caused the read/unread state of the news feed cards of the old user to be set as the new user’s read/unread states.
  • Fixes an issue where a user attribute value that had been set to multiple different values created a state that would not let you set the original value again. The bug was introduced in version 2.17.1.
Changed
  • Analytics are now logged for in-app messages and in-app message buttons with ‘ABKInAppMessageNoneClickAction’ click actions. ABKInAppMessageNoneClickAction is set when an in-app message on the dashboard has a click action that only closes the in-app message; formerly this did not count as a click.

2.19.0

Added
  • Adds support for action-based, locally triggered in-app messages. In-app messages are now sent to the device at session start with associated trigger events. The SDK will display in-app messages in near real-time when the trigger event associated with a message occurs. Trigger events can be app opens, push opens, purchases, and custom events.
Changed
  • Deprecates the old system of requesting in-app message display, now collectively known as ‘original’ in-app messaging, where messages were limited to displaying at app start.

2.18.4

Fixed
  • Fixes a Cocoapods issue that emerged during the release of 2.8.13.

2.18.3

Changed
  • Makes an internal update to provide functionality for SDKs that embed this library.

2.18.2

Added
  • Adds warning logging if [Appboy sharedInstance] is called while in an uninitialized state.
Changed
  • Deprecates the delegate method getResourceEndpoint: in ABKAppboyEndpointDelegate. The SDK will no longer call this delegate method.

2.18.1

Fixed
  • Fixes the nullability annotation warnings in the public header files.
Changed
  • Updates HelloSwift sample app to adopt swift 2.0.

2.18

Added
  • Adds nullability annotations to all Braze public APIs.
  • Adds a new delegate method to support custom push URI handle. For more detail, please see ABKPushURIDelegate.h;
Changed
  • Updates to auto-dismiss the Braze web view when a user returns to the app after following a link out of the app from an Braze web view.
Removed
  • Removes the deprecated method requestSlideupRefresh from Braze class.

2.17.1

Fixed
  • Fixes a bug where in certain conditions the SDK would resend user attributes that had already synced with the server.

2.17

Added
  • Adds a new button clicked delegate method for HTML in-app message. The new delegate method also passes the URL of the clicked button.
Fixed
  • Fixes the crash caused by inserting a nil object into an NSDictionary when parsing an event object.
Changed
  • Makes the WebView background for HTML in-app messages transparent. Ensure HTML in-app messages you send to the device are created expecting a transparent background.
  • Applies the Braze endpoint delegate methods to in-app messages’ resource(zip and image) fetching.
Removed
  • Removes the Facebook button from Feedback page.

2.16.1

Added
  • Adds the ability to log a custom event from an HTML in-app message. To log a custom event from an HTML in-app message, navigate a user to a url of the form appboy://customEvent?name=customEventName&p1=v2, where the name URL parameter is the name of the event, and the remaining parameters are logged as String properties on the event.
  • Adds the support for customization of the background color of modal in-app messages.
Fixed
  • Fixes an issue where daylight savings changes were not reflected in the user profile timezone.
Changed
  • Enables users to input text into HTML in-app messages by allowing HTML in-app messages to be displayed with a keyboard on screen. For all other in-app messages, the in-app message will be dismissed when a keyboard is displayed.

2.16

Added
  • Adds HTML In-App Message types.
    • HTML In-App Messages consist of HTML and a url of a zipped archive of assets (e.g. images, css) to download locally which the HTML can reference. See InAppMessageUIViewController in our Stopwatch sample app for an example for the callbacks on the actions inside the WebView hosting the HTML In-App Message.
Changed
  • Deprecates the method - (void) logSocialShare:(ABKSocialNetwork)socialNetwork and enum ABKSocialNetwork in the Appboy class. If you use logSocialShare: to track user’s social account sharing, you can use logCustomEvent: instead.
  • Deprecates the property bio in the ABKUser class.

2.15.1

Fixed
  • Fixes the warning “full bitcode bundle could not be generated because XXX was built only with bitcode marker”.

2.15

Changed
  • Updates the SDK to support iOS 9. In iOS9, previous versions of the SDK: 1) did not have bitcode support, 2) had a minor UI issue in in-app messages where the slideup messages were not docked on the bottom of the screen if they had one line of text, 3) failed to localize for zh-HK and zh-TW.

2.14

Breaking
  • Migrates the SDK to ARC. If you are using our Apple Watch Extension and not using ARC, you must apply -fobjc-arc to the extension files.
Added
  • Adds configurable session timeout feature.
  • Adds feedbackViewControllerBeforeFeedbackSent method to the feedback delegate protocols, which can be used to modify the feedback message before it’s sent to Braze.
  • Adds a setAttributionData method to ABKUser that sets an ABKAttributionData object for the user. To be used with attribution provider SDKs when attribution events are fired.

2.13.2

Changed
  • Increases the number of supported currency codes from 22 to 171. All common currency codes are now supported. The full list of supported codes is available at Appboy.h.

2.13.1

Changed
  • Updates the isUninstallTrackingNotification method in ABKPushUtils to return the correct value.

2.13

Added
  • Adds an open-source Watch SDK to support data analytics on watchKit apps. You can use the Appboy-WatchKit SDK by downloading and adding the “Appboy-WatchKit” folder in your watchKit extension target. For more detail, please refer to ABWKUser.h and AppboyWatchKit.h.
  • Adds an opt-in location service that logs background location events; adds ABKLocationManager with methods for allowing Braze to request location permission on your behalf and logging the current location. More information on the background location capabilities will be made available when dashboard support is released.
  • Adds client side blocking of blacklisted attributes and events.
  • Adds ABKPushUtils with method + (BOOL) isUninstallTrackingNotification:(NSDictionary *)userInfo; that can be used to detect if a content-available push is from Braze uninstall tracking (and shouldn’t be acted upon).
  • Adds a new property expiresAt in class ABKCard. The property is the unix timestamp of the card’s expiration time. For more detail, please refer to ABKCard.h.
Changed
  • Stops collecting user’s Twitter data automatically. You can pass a user’s Twitter information to Braze by initialzing a ABKTwitterUser object with the twitter data, and setting it to [Appboy sharedInstance].user.twitterUser. For more information, please refer to ABKUser.h and ABKTwitterUser.h.
  • Stops logging foreground push as a push open as it is not delivered by the system.
Removed
  • Removes the feature of prompting a user to connect his/her social account. You can refer to the method promptUserToConnectTwitterAccountOnDeviceAndFetchAccountData in TwitterViewController.m to continue prompting the user to connect the Twitter account.

2.12.2

Fixed
  • Fixes the slideup in-app message display issue. When the host app sets the launch screen file, slideup in-app message from bottom sometimes didn’t dock at the bottom of the screen on iPhone 6 and iPhone 6 Plus.

2.12.1

Added
  • Adds font and font size customization to all in-app message’s header and message text through NUI. You can customize in-app message’s font by adding ABKInAppMessageSlideupMessageLabel, ABKInAppMessageeModalHeaderLabel,ABKInAppMessageModalMessageLabel, ABKInAppMessageFullHeaderLabel, ABKInAppMessageFullMessageLabel to your NUI nss style sheet.
Fixed
  • Fixes news feed issue where no news feed cards resulted in the loading spinner remaining on screen.
Changed
  • Cleans up the console logging in Class ABKIdentifierForAdvertisingProvider.

2.12.0

Fixed
  • Fixes the incorrect path runtime error for users who integrate our pod as a dynamic framework. For SDK versions before 2.12, when you integrate Braze with use_frameworks! in the Podfile, the library is integrated as a dynamic framework and the Appboy.bundle is stored in a different path.
Changed
  • Changes HelloSwift sample app to integrate Braze SDK as a dynamic framework.
Removed
  • Removes the subspecs from the podspec. This fixes the duplicate symbol error https://github.com/Appboy/appboy-ios-sdk/issues/24. If you are still using subspec like pod 'Appboy-iOS-SDK/AppboyKit' in your podfile, please make sure to change it to pod 'Appboy-iOS-SDK'.

2.11.3

Added
  • Adds the ability to send and retrieve extra key-value pairs via a News Feed card.
  • Adds the ability to define custom key-value properties on a custom event or purchase. Property keys are strings and values may be NSString, NSDate, or NSNumber objects.
  • Added the fix for an edge case when there are extra UIWindows at the time in-app message is going to display, the in-app message would have issue during dismissing.

2.11.2

Changed
  • Updates the serialize and deserialize methods for in-app message classes. This is for use by wrappers such as Braze’s Unity SDK for iOS.

2.11.1

Fixed
  • Fixes a UI issue in modal in-app messages displayed on iPads running iOS 6/7.

2.11

Added
  • Adds support for modal and full screen style in-app messages. Also adds support for including fontawesome icons and images with in-app messages, changing colors on in-app message UI elements, expanded customization options, and message resizing for tablets. Please visit our documentation for more information.
Changed
  • Updates the completionHandler signature in getActionWithIdentifier:forRemoteNotification:completionHandler: to match the comletionHandler passed by the system in method - (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler.

2.10.2

Added
  • Adds the fix for an edge case when there are extra UIWindows at the time in-app message is going to display, the in-app message would have issue during dismissing.

2.10.1

Fixed
  • Fixes a bug which would cause the host app to crash when a deep link was launched from a push notification. In versions 2.10.0 and 2.9.4, if the host app used [[Appboy sharedInstance] registerApplication: didReceiveRemoteNotification:]; instead of [[Appboy sharedInstance] registerApplication: didReceiveRemoteNotification: fetchCompletionHandler:];, opening a push with a deep link would crash the host app in some circumstances.

2.10.0

Changed
  • Updates the minimum deployment targets of Braze iOS SDK to iOS 6.0. For apps supporting lower iOS versions, please continue to use 2.9.+ versions of the Braze SDK.
  • Stops collecting user’s Facebook data automatically. You can pass a user’s Facebook information to Braze by initializing a ABKFacebookUser object with the facebook data, and set it to [Appboy sharedInstance].user.facebookUser. For more information, please refer to ABKUser.h and ABKFacebookUser.h.
Removed
  • Removes Facebook SDK dependent builds. Now there is a single library - AppboyKit - and a single Pod without functional subspecs - Appboy-iOS-SDK (note we now have both the subspecs pointing at the same library). Please update your Podfile to pod 'Appboy-iOS-SDK if you are integrating Braze with Cocoapods.
  • Removes the feature of prompting a user to connect his/her Facebook account. You can refer to the method promptUserToConnectFacebookAccountOnDeviceAndFetchAccountData in FacebookViewController.m to continue prompting the user to connect the Facebook account.

2.9.6

Added
  • Adds the fix for an edge case when there are extra UIWindows at the time in-app message is going to display, the in-app message would have issue during dismissing.

2.9.5

Fixed
  • Fixes a bug which would cause the host app to crash when a deep link was launched from a push notification. In versions 2.9.4, if the host app used [[Appboy sharedInstance] registerApplication: didReceiveRemoteNotification:]; instead of [[Appboy sharedInstance] registerApplication: didReceiveRemoteNotification: fetchCompletionHandler:];, opening a push with a deep link would crash the host app in some circumstances.

2.9.4

Added
  • Adds a major performance upgrade that reduces CPU usage, memory footprint, and network traffic.
  • Adds 26 additional languages to localization support for Braze UI elements.
  • Adds support for deep linking from APNS push notification clicks.
  • Adds ability to customize the font of Feedback text using NUI with NUI class name ABKFeedbackTextView.
Fixed
  • Fixes the feedback page UI issues in iOS 8: when the device’s orientation is UIInterfaceOrientationPortraitUpsideDown, the contact info bar was off.
  • Fixes in-app messages to display correctly in landscape mode in iOS 8.
Changed
  • Updates the SDK to adopt the latest SDWebImage protocol methods.
Removed
  • Removes the “required” labels on the feedback page.

2.9.3

Added
  • Adds a new method - (void) registerApplication:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)notification fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler to support push with background fetch. This method should be called in - (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler. For more details, please refer to Appboy.h.
  • Adds a HelloSwift sample app to demo how to use Braze in a swift app.
  • Adds a new NSString property “displayPrice” in ABKCrossPromotionCard to enable server side price localization.
Fixed
  • Fixes a bug of when sessions were being created when the app opened in the background.
  • Fixes a bug where requesting the news feed with a news feed open led to card impressions not updating until the next feed refresh.

2.9.2

Added
  • Adds the ability to turn off Braze’s automatic location collection by setting the ABKDisableAutomaticLocationCollectionKey boolean in AppboyOptions in startWithApiKey:inApplication:inApplication:withAppboyOptions:.
  • Adds the ability to send location tracking events to Braze manually using setLastKnownLocationWithLatitude:longitude:horizontalAccuracy: and setLastKnownLocationWithLatitude:longitude:horizontalAccuracy:altitude:verticalAccuracy: on the ABKUser. this is intended to be used with ABKDisableAutomaticLocationCollectionKey set to true in the AppboyOptions so that locations are only being recorded from a single source.
Fixed
  • Fixes a news feed bug: sometimes the spinner keeps spinning on the screen even after the news feed card image is displayed.
Changed
  • Updates sample app core location fetching code based on the changes in iOS 8.

2.9.1

Fixed
  • Fixes a news feed bug: When a user refreshed the news feed by swiping down, if the total number of cards in the feed was going to be reduced by the refresh, the app would crash.

2.9.0

Fixed
  • Fixes an App Store validation error introduced when the App Store started accepting submissions for iOS8. This was done by changing the packaging of the Braze framework to include a universal binary and a resource bundle (instead of combining them both together in a universal framework). Due to this change, Cocoapod integration is even more highly recommended than before to fully automate integration.

2.8.1

Added
  • Adds a new method - (void) getActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo to collect analytics data for push actions in iOS 8. It should be called in the UIApplication delegate method - (void) application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler. For more details, please refer to Appboy.h.
  • New Custom Attribute Data Type (Array): Braze now supports custom attributes which contain an array of string elements. In addition, we also provide methods for adding or removing an string element from an array type custom attribute. For more information, please refer to ABKUser.h.
  • Users can now pull down on the Braze Newsfeed to refresh the content on iOS version 6.0 or later.
Changed
  • Restricts product identifier string to 255 characters for method - (void) logPurchase:(NSString *)productIdentifier inCurrency:(NSString *)currencyCode atPrice:(NSDecimalNumber *)price and - (void) logPurchase:(NSString *)productIdentifier inCurrency:(NSString *)currencyCode atPrice:(NSDecimalNumber *)price withQuantity:(NSUInteger)quantity.
  • News feed card now can update the card height and display a full image based on the image ratio. Card image ratio used to be a fix number and images were aspect stretched to fit in the views.
  • The right and left margins in the news feed are now touchable areas for scrolling.
  • Card titles have been improved and will now truncate with “…” when they are more than 2 lines.

2.8

Breaking
  • Renames the class names of news feed cards to match the names on dashboard:
v2.8 v2.7
ABKBannerCard ABKCardBanner
ABKCaptionedImageCard ABKCardCaptionedMessage
ABKCrossPromotionCard ABKCardCrossPromotionSmall
ABKClassicCard ABKCardNews
ABKTextAnnouncementCard ABKCardTextAnnouncement
Added
  • Adds email and push notification subscription types for a user. Subscription types are explicitly opted in, subscribed, and unsubscribed. The previous email boolean subscribe method has been deprecated.
  • Adds custom slideup orientation support. You can now ask the slideup to only support certain orientations. For more details on slideup custom orientation support, please refer to ABKSlideupController.h.
  • Adds quantity parameter as an option when logging purchase. The quanlity should be an unsigned interger greater than 0 and no larger than 100. For more information, please refer to Appboy.h.
  • Adds a class method in ABKCard to deserialize a given dictionary to a card. This is for use by wrappers such as Braze’s Unity SDK for iOS. Please refer to ABKCard.h for more information.

2.7

News Feed Update

  • Exposes raw card data in ABKFeedController
    • Developers can use the raw card data to creat custom user interfaces for the news feed. For more details on the card data, please refer to ABKFeedController.h.
  • Addes support for categories on cards and news feed view controllers.
    • Categories include Announcement, Advertising, Social, News and No Category. You can get cards of certain categories from ABKFeedController, or you can make ABKFeedViewController only display certain categories of cards.
  • Uses SDWebImage to handle images downloading and caching in the news feed, display a spinner while downloading images and show a default image when no image available.
    • Adds support for asynchronous image downloading in the news feed, asynchronous memory and disk image caching with automatic cache expiration handling.
  • Adds news feed view controller delegate to support custom handling of card clicks on news feed.
    • The app can customize click actions from the feed and display any card link in their own user interface.

Slideup Changes

  • Updates ABKSlideupControllerDelegate method onSlideupClicked to return a BOOL value to indicate if Braze should continue to execute the click action.
  • Stops logging slideup click when the slideup click action is ABKSlideupNoneClickAction.

Feedback Changes

  • Updates the ABKFeedbackViewControllerPopoverContext so now it should be used in all cases where the feedback page displayed in a popover, including the case that the feedback is push on a navigation controller in a popover.
  • Fixes the ABKFeedbackVIewControllerModalContext cancel button delegate issue.
  • Fixes the form sheet style ABKFeedbackViewControllerModalContext layout issue.

Other Changes

  • Adds API to request feed and slideup refresh.
  • Adds API to log news feed displayed and feedback displayed.
    • Allows updating analytics data even using customized news feed or feedback user interfaces.
  • Updates badge count policy to only update when app is foreground.
  • Adds clearTwitterDataWhenNoDataOfTwitterIdentifier to ABKUser, allowing developer to clear user data when a user disconnectes their twitter accounts.
  • Updates custom key and string value for custom attributes to automatically trim.

2.6.3

Changed
  • Updates the SDK to authenticate with the Twitter API using SSL.

2.6.2

Fixed
  • Fixes a news feed card click tracking issue.
Changed
  • Updates data flush time interval.

2.6.1

Fixed
  • Fixes a minor display problem that affected news items with no image or link for version 2.6.

2.6

Breaking
  • Braze iOS SDK now supports 64 bit as well. The minimum deployment targets that Braze iOS SDK supports is iOS 5.1.1.
    • The Braze iOS SDK will now allow function with 64-bit apps. This version of the SDK only supports iOS 5.1.1+. Legacy iOS apps should continue to use version 2.5 of the SDK.
    • You can install legacy versions of our SDK via CocoaPods by following changing the podfile to include something like the following example pod 'Appboy-iOS-SDK/AppboyKit', '~> 2.5'.

2.5.1

Fixed
  • Fixes a minor display problem that affected news items with no image or link for version 2.5.

2.5

Localization

Localization is now supported in version 2.5 of the Braze SDK. We have provided .string files for English, Simplified Chinese and Traditional Chinese. You can also optionally override our Braze’s default LocalizedAppboyUIString.strings right within your app’s Localizable.Strings file in much the same way you would do an override in CSS. To do so, copy the key and string pair into your Localizable.Strings file and edit the string as you so desire.

For your convenience our CocoaPod integrates the LocalizedAppboyUIString.strings files for the three aforementioned languages. If you do not wish to use one or more of these languages, you can feel free to delete these files from your project.

Slideup Upgrade

Braze version 2.5 provides a substantial upgrade to the slideup code and reorganization for better flexibility moving forward, but at the expense of a number of breaking changes. We’ve detailed the changes in this changelog and hope that you’ll love the added power, increased flexibility, and improved UI that the new Braze slideup provides. If you have any trouble with these changes, feel free to reach out to success@braze.com for help, but most migrations to the new code structure should be relatively painless.

New Slideup Controller

  • The property slideupController has been added to the Braze object. Please see ABKSlideupController.h for details.
    • The delegate property allows you to specify a delegate for the slideup.
      • This replaces slideupDelegate which has been removed.
    • The displayNextSlideupWithDelegate: method displays the next available slideup with the specified delegate.
      • This replaces provideSlideupToDelegate: which has been removed from Braze.
    • The slideupsRemainingOnStack method returns the number of slideups that are waiting locally to be displayed.
    • The addSlideup: method allows you to display a slideup object with custom content. This is useful in testing or if you want to use the Braze slideup’s UI/UX with another notification system that you are using.
      • Clicks and impressions of slideups added by this method will not be collected by Braze.
    • hideCurrentSlideup: method will remove any slideup currently on screen, with or without animation.

New Slideup Properties and Methods in ABKSlideup.h

The following properties and methods all belong to the ABKSlideup object. Please see ABKSlideup.h for more information.

New Properties
  • The extras property carries additional data within key value pairs that have been defined on the dashboard, just like a push notification. Braze does nothing with the extras property, any additional behavior is at your discretion.
  • The slideupAnchor property defines whether the slideup originates from the top or the bottom of the screen.
  • The slideupDismissType property controls whether the slideup will dismiss automatically after a period of time has lapsed, or if it will wait for interaction with the user before disappearing.
    • The slideup will be dismissed automatically after the number of seconds defined by the newly added duration property if the slideup’s slideupDismissType is ABKSlideupDismissAutomatically.
  • The slideupClickActionType property defines the action behavior after the slideup is clicked: displaying a news feed, redirect to a uri, or nothing but dismissing the slideup. This property is read only. If you want to change the slideup’s click behavior, you can call one of the following method: setSlideupClickActionToNewsFeed, setSlideupClickActionToUri: or setSlideupClickActionToNone.
  • The uri property defines the uri string that the slide up will open when the slideupClickActionType is ABKSlideupRedirectToURI. This is a read only property, you can call setSlideupClickActionToUri: to change it’s value.
New Methods
  • logSlideupImpression and logSlideupClicked have been added to allow you to report user interactions with the slideup in the case that you’ve fully customized the slideup experience and Braze is not handling the interactions.
  • setSlideupClickActionToNewsFeed, setSlideupClickActionToUri: and setSlideupClickActionToNone have been added to allow you to change the slideup’s click action behavior. setSlideupClickActionToUri: accepts a uri string as parameter and required the given uri string is valid.

Delegate Method Changes

All former Braze slideup delegate methods have been depreciated and removed. In their place Braze has added new slideup delegate methods within ABKSlideupControllerDelegate.h.

  • onSlideupReceived: is called when slideup objects are received from the Braze server.
  • beforeSlideupDisplayed:withKeyboardIsUp: is called before slideup objects are displayed, the return value determines whether the slideup will be displayed, queued or discarded.
  • slideupViewControllerWithSlideup: This delegate method allows you to specify custom view controllers in which your slideups will be displayed.
    • The custom view controller should be a subclass of ABKSlideupViewController.
      • Alternatively, it can also be an instance of ABKSlideupViewController.
    • The view of the returned view controller should be an instance of ABKSlideupView or its subclass.
    • For integration examples of a custom slideup view controller, see the CustomSlideupViewController class in Braze’s sample app Stopwatch.
  • onSlideupClicked: is called when a user clicks on a slideup. We recommend that you specify behavior on click via the dashboard, but you can additionally specify behavior on click by defining this delegate method.
  • onSlideupDismissed: is called whenever the slideup is dismissed regardless of whether the dismissal occurs automatically or via swipe. This method is not called if the user clicks on the slideup. If the user clicks or taps on the slideup, onSlideupClicked is called instead.

New Options on the Dashboard

  • Slideup behavior on click can now be set within the dashboard to open a modal news feed, open a URI within a modal, or do nothing.
  • The following properties can be set remotely from the Braze Dashboard:
    • extras
    • slideupAnchor
    • slideupDismissType
    • slideupClickActionType
    • uri

News Feed Changes

  • News feed items are now cached in offline storage, allowing the news feed to render even when no internet connectivity is available. Braze will still automatically try to pull down a new news feed when a session opens, even if an offline feed is available.
  • Each card now has a maximum height of no more than 2009 points to avoid any performance issues as recommended by iOS developer guidelines.
  • The entirety of captioned image cards are now clickable. Formerly, only the link itself was clickable.
  • When the news feed is brought to the foreground, it will now automatically check for new content if the cached version of the feed was received more than 60 seconds ago. — The width of news feed cards as well as the minimum margin between any card and the left & right edges of the view controller can now be customized. These values can be set separately for both iPad and iPhone. This allows for a larger news feed to render on larger screen sizes. All card images will scale proportionally. Please see ABKFeedViewControllerContext.h and ABKFeedViewController.h for more information.

Other Changes

  • Various internal and news feed display optimizations.

2.4

  • IDFA Collection is now optional.
    • By default, IDFA collection is now disabled by the Braze SDK.
      • There will be no loss of continuity on user profiles or loss of functionality whatsoever as a result of this change.
      • If you’re using advertising elsewhere in the app or through our in-app news feed, we recommend continuing to collect the IDFA through Braze. You should be able to do so safely without fear of rejection from the iOS App Store.
      • The future availability of IDFAs will enable functionality like integrating with other third-party systems, including your own servers, and enabling re-targeting of existing users outside of Braze. If you continue to record them we will store IDFAs free of charge so you can take advantage of these options immediately when they are released without additional development work.
    • Necessary Project Changes
      • ABKIdentifierForAdvertisingProvider.m and ABKIdentifierForAdvertisingProvider.h must be added to your project regardless of whether or not you enable collection. This occurs automatically if you integrate/update via the CocoaPod.
    • Enabling Braze IDFA Collection
      • IDFA collection can be enabled via adding the following PreProcessor Macro to the Build Settings of your app:
        • ABK_ENABLE_IDFA_COLLECTION

2.3.1

  • The Braze SDK for iOS now has two versions, one for use with apps which incorporate the official Facebook SDK and one for those which do not. In November of 2013, the App Store Validation Process started generating warnings about the usage of isOpen and setActiveSession in the Braze SDK. These selectors were being sent to instances of classes in the Facebook SDK and are generally able to be used without generating warnings. However because of the way that the classes were initialized in Braze (a result of building a single Braze binary to fully support apps with and without the Facebook SDK), the App Store Validation Process started generating warnings the Facebook SDK methods share a name with private selectors elsewhere in iOS. Although none of our customers have been denied App Store approval yet, to protect against potential validation policy changes by Apple, Braze now provides two versions of its SDK, neither of which generate warnings. Going forward, the appboy-ios-sdk repository will provide both versions of the SDK in the folders ‘AppboySDK’ (as before) and ‘AppboySDKWithoutFacebookSupport’. The ‘AppboySDKWithoutFacebookSupport’ does not require the host app to include the Facebook SDK, but as a result does not include all of the Braze features for Facebook data fetching. More information is available here within the Braze documentation.
  • Fixed a bug that repeatedly updated the push token of some users unnecessarily.
  • The “Reporting an Issue?” box within the UI layout of the Feedback Page has been moved to the left side of the label away from the “Send” button. This change was made to reduce the number of misclicks of the “Send” button. The “Reporting an Issue?” label is now clickable as well.
  • Cross Promotion Cards for apps with long titles will now render appropriately in iOS5. Before the title would render abnormally large on these devices.
  • Fixed a bug where view recycling would cause incorrect card images to appear for newly rendered cards (until the image for that card finished downloading). Card images for newly rendered cards will now remain empty until the correct image is downloaded.
  • Internal changes to enable future support for a 64 bit library release.
  • Improvements to the Braze Sample App.
  • Internal code structure and performance improvements including the move of more offline caching to background tasks.

2.3

  • BREAKING CHANGE: The ABKSlideupControllerDelegate interface has been changed to work with ABKSlideup objects instead of simply the slideup message. This provides you with more control over the click actions and display of slideups and is also being made in anticipation of the augmentation of the ABKSlideup object with more data properties in future releases. To access the message previously sent to shouldDisplaySlideup, simply access the message property on the provided ABKSlideup argument.
  • displayNextAvailableSlideup has been deprecated and will be removed in the next minor release, it has been replaced by provideSlideupToDelegate, see Appboy.h documentation for more information.
  • provideSlideupToDelegate has been added to Braze to allow for more fine grained control over slideup display.
  • Fixes a bug where the slideupDelegate property getter on Braze would always return nil.
  • Changes the slideupDelegate property on Braze to be retained, instead of assigned.

2.2.1

  • Adds a startup option to appboyOptions to control the automatic capture of social network data. See the documentation on ABKSocialAccountAcquisitionPolicy in Appboy.h for more information.
  • Changes a table cell’s default background color to clear, from the white value that became default in iOS7.
  • Adds support for developer to send up image_url for user avatars, allowing for custom images to be included in user profiles on the dashboard.

2.2

  • Adds support for new banner and captioned image card types.
  • Adds support for submitting feedback programmatically through an Appboy.h method without using Braze feedback form. This allows you to create your own feedback form.
  • Fixes an issue where the the news feed’s web view would display “Connection Error” when a user came back into the app after a card had directed him or her to a protocol URL. Now when users come back from a redirected protocol URL, the feed is properly displayed.
  • Fixes an issue where the SDK might have incorrectly sent both read and write Facebook permissions at the same time, instead preferring to request only those read permissions that Braze is interested in and have already been requested by the incorporating app.
  • Fixes a corner case where card impressions could be miscounted when the feed view controller is the master view controller of a split view.
  • Makes cards truncate properly at two lines.

2.1.1

  • URGENT BUGFIX: This fixes an issue which exists in all previous versions of the v2 SDK which is causing crashes on the just release iPhone 5c and iPhone 5s. All users of v2 are recommended to upgrade the Braze SDK to 2.1.1 immediately and re-submit to the app store.

2.1.0

  • Adds support for iOS 7. You will need to use Xcode 5 to use this and future versions of the Braze iOS SDK.
  • Updates internal usage of NUI. If you’re using NUI, please ensure that you are at least using version 0.3.3 (the most up to date as of this writing is 0.3.4).
  • Removes support for iOS 4.3.
  • Optimizes news feed rendering for faster start up times and smoother scrolling of long feeds.
  • Removes the deprecated - (void) logPurchase:(NSString *)productId priceInCents:(NSUInteger)price method in favor of the new multi-currency tracking method. Conversion of old method calls is straightforward. [[Appboy sharedInstance] logPurchase:@"powerups" priceInCents:99]; should turn into [[Appboy sharedInstance] logPurchase:@"powerups" inCurrency:@"USD" atPrice:[[[NSDecimalNumber alloc] initWithFloat:.99f] autorelease]];
  • Any references to the delegate property of ABKFeedbackViewControllerModalContext should be updated to the new property name feedbackDelegate.
  • Following the removal of support for 4.3, removes SBJson parsing and uses built-in parsing added in iOS5 to improve performance and lower the SDK footprint.

2.0.4

  • Adds support for reporting purchases in multiple currencies. Also, changes the price reporting object type to NSDecimalNumber for consistency with StoreKit.
  • Adds additional space savings optimizations to image assets.
  • Minor fix to orientation change handling in the example app code.

2.0.3

  • Adds the ability to assign a Foursquare access token for each user. Doing so will cause the Braze backend to make Foursquare data available in user profiles on the dasbhard.
  • Adds more fine grained control options for Braze’s network activity. See Appboy.h for more information.

2.0.2

  • Fixes a bug where Braze might reopen a Facebook read session when a publish session already exists

2.0.1

  • UI Improvements
    • Fixed a bug when using the nav context feedback in a popover window that would cause the email bar to disappear
    • Updated news feed’s close button when opened from a slide up
    • Added a loading spinner on the feedback page when fetching email address from Facebook
    • Fixed the bug where the modal context feed page’s navigation bar would not adhere to NUI theming
    • Improved the look of the popover content feedback page
    • Enabled resizable webpages when clicking on to a web URL through a card
  • API updates
    • Updated custom user attribute setting methods to return a boolean value indicating if the setting is successful
    • Added methods for incrementing custom user attributes
    • Added support for device push tokens as NSData when registering the token to Braze
    • More detailed error messages logged in console
    • Removed the enable/disable Braze methods from Appboy.h

2.0

  • Initial release
。 # MacOS 用の SDKの初期設定 Source: /docs/ja/developer_guide/platforms/legacy_sdks/macOS/initial_sdk_setup/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # SDKの初期設定 {#initial-sdk-setup} > この参照記事では、MacOS用のBraze SDKのインストール方法について説明します。 バージョン [3.32.0](https://github.com/Appboy/appboy-ios-sdk/releases/tag/3.32.0) 以降、Braze SDKはSwift Package Managerを介して統合する場合、[Mac Catalyst](https://developer.apple.com/mac-catalyst/) を使用するアプリのmacOSをサポートしています。現在、SDKはCocoaPodsまたはCarthageを使用する場合、Mac Catalystをサポートしていません。 **Note:** Mac Catalystでアプリを構築するには、Appleのドキュメント を参照してください。 アプリでCatalystがサポートされたら、[次の手順に従ってSwift Package Managerを使用して](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/sdk_integration?tab=swift%20package%20manager/)Braze SDKをアプリにインポートします。 ## サポートされている機能 {#supported-features} Brazeは、Mac Catalyst上で実行している場合、[プッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications?sdktab=swift)、[Content Cards](https://www.braze.com/docs/ja/ja/developer_guide/platforms/swift/content_cards#content-cards-data-model)、[アプリ内メッセージ](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_location?sdktab=swift)、および[自動ロケーション収集](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_location?sdktab=swift)をサポートしています。 Push Stories、リッチプッシュ、ジオフェンスはmacOSではサポートされていません。 [1]:https://github.com/Appboy/appboy-ios-sdk/releases/tag/3.32.0 [2]:https://developer.apple.com/mac-catalyst/ # tvOS の初期 SDK セットアップ Source: /docs/ja/developer_guide/platforms/legacy_sdks/tvos/initial_sdk_setup/index.md
**Warning:** [AppboyKit](https://github.com/Appboy/appboy-ios-sdk) (also known as the Objective-C SDK) is no longer supported and has been replaced by the [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). It will no longer receive new features, bug fixes, security updates, or technical support—however, messaging and analytics will continue to function as normal. To learn more, see [Introducing the New Braze Swift SDK](https://www.braze.com/resources/articles/introducing-the-new-braze-swift-sdk). # SDKの初期セットアップ {#initial-sdk-setup} > この参照記事では、tvOS 用 Braze SDKをインストールする方法について説明します。Braze SDKをインストールすると、基本的な分析機能が提供されます。 **Note:** 当社の tvOS SDKは現在、分析機能をサポートしています。ダッシュボードに tvOS アプリを追加するには、[サポートチケット](https://www.braze.com/docs/ja/ja/braze_support)を開いてください。 tvOS Braze SDKは、Objective-C および Swift プロジェクトの依存関係マネージャーである [CocoaPods](http://cocoapods.org/) を使用してインストールまたは更新する必要があります。CocoaPods を使用すると、統合と更新がさらに簡単になります。 ## tvOS SDK CocoaPods の統合 {#tvos-sdk-cocoapods-integration} ### ステップ1:CocoaPods をインストールする {#step-1-install-cocoapods} tvOS [CocoaPods](http://cocoapods.org/) を介してSDKをインストールすると、インストールプロセスの大部分が自動化されます。このプロセスを開始する前に、[Ruby バージョン 2.0.0](https://www.ruby-lang.org/en/installation/) 以降を使用していることを確認してください。 開始するには、次のコマンドを実行します。 ```bash $ sudo gem install cocoapods ``` - `rake` 実行可能ファイルを上書きするプロンプトが表示された場合、詳細については CocoaPods.org の [Getting started](http://guides.cocoapods.org/using/getting-started.html) を参照してください。 - CocoaPods に関する問題がある場合は、[CocoaPods トラブルシューティングガイド](http://guides.cocoapods.org/using/troubleshooting.html)を参照してください。 ### ステップ2:Podfile の構築 {#step-2-constructing-the-podfile} CocoaPods Ruby Gem をインストールしたら、Xcode プロジェクトディレクトリに `Podfile` という名前のファイルを作成する必要があります。 次の行を Podfile に追加します。 ``` target 'YourAppTarget' do pod 'Appboy-tvOS-SDK' end ``` ポッドの更新がマイナーバージョンの更新よりも小さいものを自動的に取得するように、Braze をバージョン管理することをお勧めします。これは `pod 'Appboy-tvOS-SDK' ~> Major.Minor.Build` のようになります。メジャーな変更があっても最新の Braze SDK バージョンを自動的に統合する場合は、Podfile で `pod 'Appboy-tvOS-SDK'` を使用できます。 ### ステップ3:Braze SDKのインストール {#step-3-installing-the-braze-sdk} Braze SDK CocoaPods をインストールするには、ターミナル内で Xcode アプリプロジェクトのディレクトリに移動し、次のコマンドを実行します。 ``` pod install ``` この時点で、CocoaPods によって作成された新しい Xcode プロジェクトワークスペースを開くことができるはずです。Xcode プロジェクトの代わりに、必ずこの Xcode ワークスペースを使用してください。 ![CocoaPods によって作成された新しい Xcode プロジェクトワークスペース。Xcode プロジェクトの代わりに、必ずこの Xcode ワークスペースを使用してください。](https://www.braze.com/docs/ja/ja/assets/img_archive/podsworkspace.png?96819fcb60bb61e9a9b991e15b4ef6d6) ### ステップ4:アプリデリゲートの更新 {#step-4-updating-your-app-delegate} 次のコード行を `AppDelegate.m` ファイルに追加します。 ```objc #import ``` `AppDelegate.m` ファイル内で、`application:didFinishLaunchingWithOptions` メソッド内に次のスニペットを追加します。 ```objc [Appboy startWithApiKey:@"YOUR-API-KEY" inApplication:application withLaunchOptions:launchOptions]; ``` 最後に、**設定の管理**ページの正しい値で `YOUR-API-KEY` を更新します。 Braze SDKを CocoaPods または Carthage と統合する場合は、次のコード行を `AppDelegate.swift` ファイルに追加します。 ```swift import AppboyTVOSKit ``` Swift プロジェクトでの Objective-C コードの使用方法について詳しくは、[Apple 開発者ガイド](https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html)を参照してください。 `AppDelegate.swift` で、次のスニペットを `application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool` に追加します。 ```swift Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions) ``` 次に、**設定の管理**ページの正しい値で `YOUR-API-KEY` を更新します。 `sharedInstance` シングルトンは、Braze 機能を使用するための前提条件である `startWithApiKey:` が呼び出される前は nil になります。 **Warning:** 必ずアプリケーションのメインスレッドで Braze を初期化してください。非同期で初期化すると、機能が破損する可能性があります。 ### ステップ5:カスタムエンドポイントまたはデータクラスターを指定する {#step-5-specify-your-custom-endpoint-or-data-cluster} **Note:** 2019年12月をもって、カスタムエンドポイントは提供されなくなりました。既存のカスタムエンドポイントがある場合は、それを引き続き使用できます。詳細については、利用可能なエンドポイントのリスト を参照してください。 Braze 担当者から、[正しいエンドポイント](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/sdk_endpoints/)についてすでに案内があったはずです。 #### コンパイル時のエンドポイント構成(推奨) {#compile-time-endpoint-configuration-recommended} 既存のカスタムエンドポイントが指定されている場合: - Braze iOS SDK v3.0.2 以降では、`Info.plist` ファイルを使用してカスタムエンドポイントを設定できます。`Appboy` ディクショナリを Info.plist ファイルに追加します。`Appboy` ディクショナリ内で、`Endpoint` 文字列サブエントリを追加し、値をカスタムエンドポイント URL のオーソリティに設定します(例: `https://sdk.iad-01.braze.com` ではなく `sdk.iad-01.braze.com`)。 #### ランタイムエンドポイント構成 {#runtime-endpoint-configuration} 既存のカスタムエンドポイントが指定されている場合: - Braze iOS SDK v3.17.0 以降では、`startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions:` に渡される `appboyOptions` パラメーター内の `ABKEndpointKey` を使用してエンドポイントの設定をオーバーライドできます。値をカスタムエンドポイント URL のオーソリティに設定します(例: `https://sdk.iad-01.braze.com` ではなく `sdk.iad-01.braze.com`)。 **Note:** `ABKAppboyEndpointDelegate` を使用した実行時のエンドポイント設定サポートは、Braze iOS SDK v3.17.0 で削除されました。すでに `ABKAppboyEndpointDelegate` を使用している場合は、Braze iOS SDK バージョン v3.14.1 から v3.16.0 では、`getApiEndpoint()` メソッドの `dev.appboy.com` への参照を `sdk.iad-01.braze.com` への参照に置き換える必要があります。 ### SDKの統合が完了 {#sdk-integration-complete} これで、Braze はアプリケーションからデータを収集しており、基本的な統合は完了しているはずです。tvOS アプリおよびその他のサードパーティライブラリをコンパイルするときは、Bitcode を有効にする必要があることに注意してください。 ### CocoaPods 経由で Braze SDKを更新する {#updating-the-braze-sdk-via-cocoapods} CocoaPod を更新するには、プロジェクトディレクトリ内で次のコマンドを実行するだけです。 ``` pod update ``` ## 起動時の Braze のカスタマイズ {#customizing-braze-on-startup} 起動時に Braze をカスタマイズする場合は、代わりに Braze 初期化メソッド `startWithApiKey:inApplication:withLaunchOptions:withAppboyOptions` を使用し、オプションの Braze 起動キーの `NSDictionary` を渡すことができます。 `AppDelegate.m` ファイルの `application:didFinishLaunchingWithOptions` メソッド内に、次の Braze メソッドを追加します。 ```objc [Appboy startWithApiKey:@"YOUR-API-KEY" inApplication:application withLaunchOptions:launchOptions withAppboyOptions:appboyOptions]; ``` `AppDelegate.swift` の `application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool` メソッド内に、次の Braze メソッドを追加します。 ```swift Appboy.start(withApiKey: "YOUR-API-KEY", in:application, withLaunchOptions:launchOptions, withAppboyOptions:appboyOptions) ``` ここで、`appboyOptions` はスタートアップ構成値の `Dictionary` です。 このメソッドは `startWithApiKey:inApplication:withLaunchOptions:` 初期化メソッドを置き換え、次のパラメーターで呼び出されます。 - `YOUR-API-KEY`: アプリケーションの API キーは、Braze ダッシュボードの**設定の管理**にあります。 - `application`: 現在のアプリ。 - `launchOptions`: `application:didFinishLaunchingWithOptions:` から取得するオプション `NSDictionary`。 - `appboyOptions`: Braze のスタートアップ構成値を持つオプションの `NSDictionary`。 Braze 起動キーの一覧については、[Appboy.h](https://github.com/Appboy/appboy-ios-sdk/blob/master/AppboyKit/include/Appboy.h) を参照してください。 ## Appboy.sharedInstance() および Swift の nullability {#appboysharedinstance-and-swift-nullability} 一般的な慣例とは多少異なりますが、`Appboy.sharedInstance()` シングルトンはオプションです。これは、`startWithApiKey:` が呼び出される前は `sharedInstance` が `nil` であり、遅延初期化を使用できる非標準だが無効ではない実装がいくつかあるためです。 Appboy の `sharedInstance`(標準実装)にアクセスする前に `didFinishLaunchingWithOptions:` デリゲートで `startWithApiKey:` を呼び出すと、`Appboy.sharedInstance()?.changeUser("testUser")` のようなオプショナルチェーンを使用して、煩雑なチェックを回避できます。これは、非 null の `sharedInstance` を想定した Objective-C 実装と同等になります。 ## 手動統合オプション {#manual-integration-options} tvOS SDKを手動で統合することもできます。[パブリックリポジトリ](https://github.com/appboy/appboy-ios-sdk)からフレームワークを取得し、前のセクションで説明したように Braze を初期化するだけです。 ## ユーザーの特定と分析レポート {#identifying-users-and-reporting-analytics} ユーザー ID の設定、カスタムイベントのログ記録、ユーザー属性の設定については、[iOS ドキュメント](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_ids?tab=swift)を参照してください。また、[イベントの命名規則](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/event_naming_conventions)についてもよく理解しておくことをお勧めします。 # バナーついて Source: /docs/ja/developer_guide/banners/index.md # Banners > With Banners, you can create personalized messaging for your users, all while extending the reach of your other channels, such as email or push notifications. You can embed Banners directly in your app or website, which lets you engage with users through an experience that feels natural. ## Prerequisites Banners availability depends on your Braze package. Contact your account manager or customer success manager to get started. Before you start, make sure you have [Banner placements](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements/) created in your app or website. ![An example Banner rendered on a device.](https://www.braze.com/docs/ja/ja/assets/img/banners/sample_banner.png?c7f37292fa4f239707f73a88139a4685) ## Why use Banners? Banners allow marketing and product teams to personalize app or website content dynamically, reflecting real-time user eligibility and behavior. They persistently display messages inline, providing non-intrusive, contextually relevant experiences that can be refreshed at the start of a session or mid-session when your app or website explicitly requests it. After Banners are integrated into an app or website, marketers can design and launch Banners using a simple drag-and-drop editor, eliminating the need for ongoing developer assistance, reducing complexity, and improving efficiency. | Use case | Explanation | | --- | --- | | Announcements | Keep announcements like upcoming events or policy changes at the forefront of your app experience. | | Personalizing offers | Show personalized promotions and incentives based on each user’s browsing history, cart content, subscription tier, and loyalty status. | | Targeting new user engagement | Guide new users through onboarding flows and account setup. | | Sales and promotions | Highlight featured content, trending products, and ongoing brand campaigns persistently and directly on your homepage without disrupting the user experience. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Why use Banners?" } ## Features Features for Banners include: - **Easy content building:** Create and preview your Banner using a visual, drag-and-drop editor with support for images, text, buttons, email capture forms, custom code, and more. - **Flexible placements:** Define multiple locations within your application or website where Banners can appear, enabling precise targeting to specific contexts or user experiences. - **Dynamic personalization:** Banners can only be refreshed at the start of a new session or mid-session if you explicitly request the refresh. Banners don't update automatically on a new session. If you don't request the refresh, the Banner won't update. - **Native prioritization:** Set the display priority for when multiple Banners target the same placement, ensuring the right message reaches users at the right time. - **Custom Code editor block:** Use the Custom Code editor block to add custom HTML for advanced customization or seamless integration with your existing web styles. ## About Banners {#about-banners} ### Placement IDs {#placement-id} Banner placements are specific locations in your app or website [you create with the Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements/) that designate where Banners can appear. Common locations include the top of your homepage, product detail pages, and checkout flows. After placements are created, Banners can be [assigned in your Banner campaign](https://www.braze.com/docs/ja/ja/user_guide/channels/banners/create_a_banner/). There is no fixed limit on the number of placements you can create per workspace, and you can create as many placement IDs as your experience requires. Each placement must be unique within a workspace. A single placement ID can be referenced by up to 25 active messages at the same time. **Important:** Avoid modifying placement IDs after launching a Banner campaign. ### Banner priority {#priority} When multiple Banner messages reference the same placement ID, Banners are displayed in order of priority: high, medium, or low. By default, Banners are set to medium, but you can [manually set the priority](https://www.braze.com/docs/ja/ja/user_guide/channels/banners/create_a_banner/#set-banner-priority-optional) when you create or edit your Banner campaign. If multiple Banners are set to the same priority, the newest Banner that the user is eligible for is displayed first. ### Placement requests {#requests} When you [create placements in your app or website](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements/#requestBannersRefresh), your app sends a request to Braze to fetch Banner messages for each placement. - You can request up to **10 placements per refresh request**. - For each placement, Braze returns the **highest-priority Banner** the user is eligible to receive. - If more than 10 placements are requested in a refresh, only the first 10 are returned; the rest are dropped. For example, an app might request three placements in a refresh request: `homepage_promo`, `cart_abandonment`, and `seasonal_offer`. Each request returns the most relevant Banner for that placement. #### Rate limiting for refresh requests If you're on older SDK versions (before Swift 13.1.0, Android 38.0.0, Web 6.1.0, React Native 17.0.0, and Flutter 15.0.0), only one refresh request is permitted per user session. If you're on newer minimum SDK versions (Swift 13.1.0+, Android 38.0.0+, Web 6.1.0+, React Native 17.0.0+, and Flutter 15.0.0+), refresh requests are controlled by a token bucket algorithm to prevent excessive polling: - Each user session begins with five refresh tokens. - Tokens refill at a rate of one token every 180 seconds (3 minutes). Each explicit call to `requestBannersRefresh` consumes one token. The automatic refresh that occurs at the start of a new session or when `changeUser` is called does not consume a token, as this refresh is a publishing of the last cached Banner for that user. If you attempt a refresh when no tokens are available, the SDK doesn't make the request and logs an error until a token refills. This is important for mid-session and event-triggered updates. To implement dynamic updates (for example, after a user completes an action on the same page), call the refresh method after the custom event is logged, but note the necessary delay for Braze to ingest and process the event before the user qualifies for a different Banner campaign. ### Message delivery Banner messages are delivered to your app or website as HTML content, typically rendered inside an iframe. This ensures that your Banners render consistently across devices, and helps you keep their styles and scripts separate from the rest of your code. Iframes allow for dynamic and personalized content updates that don't require changes to your codebase. Each iframe retrieves and displays the HTML for each user session using campaign targeting and personalization logic. ### Dimensions and sizing Here's what you need to know about Banner dimensions and sizing: - While the composer allows you to preview Banners in different dimensions, that information isn't saved or sent to the SDK. - The HTML takes up the full width of the container it's rendered in. - We recommend making a fixed dimension element and testing those dimensions in composer. ## Limitations Each workspace can support up to 200 active Banner campaigns. If this limit is reached, you'll need to [archive or deactivate](https://www.braze.com/docs/ja/ja/user_guide/messaging/governance/statuses/#changing-the-status) an existing campaign before creating a new one. Additionally, Banner messages do not support the following features: - API-triggered and action-based campaigns - Connected Content - Promotional codes - `catalog_items` using the [`:rerender` tag](https://www.braze.com/docs/ja/ja/user_guide/data/activation/catalogs/using_catalogs/#using-liquid) ## Next steps - [Create Banner placements in your app or website](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements/) - [Create a Banner campaign in Braze](https://www.braze.com/docs/ja/ja/user_guide/channels/banners/create_a_banner/) - [Tutorial: Displaying a Banner by Placement ID](https://www.braze.com/docs/ja/ja/developer_guide/banners/tutorial_displaying_banners) **Tip:** Want to help prioritize what's next? Contact [banners-feedback@braze.com](mailto:banners-feedback@braze.com). # Braze SDKのバナー配置を管理する Source: /docs/ja/developer_guide/banners/placements/index.md # バナー配置を管理する {#manage-banner-placements} > Braze SDKでバナー配置の作成と管理方法を学びます。配置固有のプロパティへのアクセスやインプレッションの記録についても説明します。一般的な情報については、[バナーについて](https://www.braze.com/docs/ja/ja/developer_guide/banners)を参照してください。 ## 配置リクエストについて {#requests} When you [create placements in your app or website](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements/#requestBannersRefresh), your app sends a request to Braze to fetch Banner messages for each placement. - You can request up to **10 placements per refresh request**. - For each placement, Braze returns the **highest-priority Banner** the user is eligible to receive. - If more than 10 placements are requested in a refresh, only the first 10 are returned; the rest are dropped. For example, an app might request three placements in a refresh request: `homepage_promo`, `cart_abandonment`, and `seasonal_offer`. Each request returns the most relevant Banner for that placement. #### Rate limiting for refresh requests If you're on older SDK versions (before Swift 13.1.0, Android 38.0.0, Web 6.1.0, React Native 17.0.0, and Flutter 15.0.0), only one refresh request is permitted per user session. If you're on newer minimum SDK versions (Swift 13.1.0+, Android 38.0.0+, Web 6.1.0+, React Native 17.0.0+, and Flutter 15.0.0+), refresh requests are controlled by a token bucket algorithm to prevent excessive polling: - Each user session begins with five refresh tokens. - Tokens refill at a rate of one token every 180 seconds (3 minutes). Each explicit call to `requestBannersRefresh` consumes one token. The automatic refresh that occurs at the start of a new session or when `changeUser` is called does not consume a token, as this refresh is a publishing of the last cached Banner for that user. If you attempt a refresh when no tokens are available, the SDK doesn't make the request and logs an error until a token refills. This is important for mid-session and event-triggered updates. To implement dynamic updates (for example, after a user completes an action on the same page), call the refresh method after the custom event is logged, but note the necessary delay for Braze to ingest and process the event before the user qualifies for a different Banner campaign. ## 配置を作成する {#create-a-placement} ### 前提条件 {#prerequisites} バナー配置を作成するために必要な最小SDKバージョンは以下の通りです。 ### Step 1: Create placements in Braze If you haven't already, you'll need to create Banner placements in Braze that are used to define the locations in your app or site can display Banners. To create a placement, go to **Settings** > **Banners Placements**, then select **Create Placement**. ![Banner Placements section to create placement IDs.](https://www.braze.com/docs/ja/ja/assets/img/banners/create_placement.png?98a42014b57988954fcac2c2d94f82da) Give your placement a name and assign a **Placement ID**. Be sure you consult other teams before assigning an ID, as it'll be used throughout the card's lifecycle and shouldn't be changed later. For more information, see [Placement IDs]. ![Placement details that designate a Banner will display in the left sidebar for spring sale promotion campaigns.](https://www.braze.com/docs/ja/ja/assets/img/banners/placement_details_example.png?e94e5b7365737e3a8d7ae38e01121c6c) ### ステップ2:アプリの配置を更新する {#requestBannersRefresh} 配置を更新するには、SDKの更新メソッドを呼び出します。`subscribeToBannersUpdates`がアクティブな場合、SDKは新しいセッションの開始時および`changeUser`を呼び出したときに、キャッシュされた配置IDを自動的に再パブリッシュします。この自動更新はレート制限トークンを消費しません。 **Tip:** バナーのダウンロードや表示の遅延を避けるため、できるだけ早く配置を更新してください。 ```javascript import * as braze from "@braze/web-sdk"; braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]); ``` ```swift AppDelegate.braze?.banners.requestRefresh(placementIds: ["global_banner", "navigation_square_banner"]) ``` ```java ArrayList listOfBanners = new ArrayList<>(); listOfBanners.add("global_banner"); listOfBanners.add("navigation_square_banner"); Braze.getInstance(context).requestBannersRefresh(listOfBanners); ``` ```kotlin Braze.getInstance(context).requestBannersRefresh(listOf("global_banner", "navigation_square_banner")) ``` ```javascript Braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]); ``` ```csharp This feature is not currently supported on Unity. ``` ```javascript This feature is not currently supported on Cordova. ``` ```dart braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]); ``` ```brightscript This feature is not currently supported on Roku. ``` ### ステップ3:更新をリッスンする {#subscribeToBannersUpdates} **Tip:** このガイドのSDKメソッドを使ってバナーを挿入する場合、すべての分析イベント(インプレッションやクリックなど)は自動的に処理され、インプレッションはバナーが表示されているときのみ記録されます。 Web Braze SDKでvanilla JavaScriptを使用している場合、[`subscribeToBannersUpdates`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#subscribetobannersupdates)を使って配置の更新をリッスンし、[`requestBannersRefresh`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#requestbannersrefresh)を呼び出してフェッチします。 ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToBannersUpdates((banners) => { console.log("Banners were updated"); }); // always refresh after your subscriber function has been registered braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]); ``` Web Braze SDKでReactを使用している場合、`useEffect`フック内で[`subscribeToBannersUpdates`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#subscribetobannersupdates)を設定し、リスナーを登録した後に[`requestBannersRefresh`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#requestbannersrefresh)を呼び出します。 ```typescript import * as braze from "@braze/web-sdk"; useEffect(() => { const subscriptionId = braze.subscribeToBannersUpdates((banners) => { console.log("Banners were updated"); }); // always refresh after your subscriber function has been registered braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]); // cleanup listeners return () => { braze.removeSubscription(subscriptionId); } }, []); ``` **Note:** バナー更新リスナーは、SDKのインメモリバナー状態を反映します。1回の更新には、最新の`requestRefresh`呼び出しの配置IDだけでなく、すでにキャッシュされている配置(たとえば、以前の更新、別の画面、またはSDKの自動処理によるもの)も含まれる場合があります。特定の配置のみに関心がある場合は、リスナー内で各バナーの配置IDを確認し、それ以外はスキップしてください。リスナーを登録したら、Brazeから同期したい配置に対して`requestRefresh`を呼び出します。 ```swift let placementIds = ["global_banner", "navigation_square_banner"] let cancellable = brazeClient.braze()?.banners.subscribeToUpdates { banners in banners.forEach { placementId, banner in print("Received banner: \(banner) with placement ID: \(placementId)") } } // Always refresh after your subscriber is registered brazeClient.braze()?.banners.requestRefresh(placementIds: placementIds) ``` **Note:** バナー更新リスナーは、SDKのインメモリバナー状態を反映します。1回の更新には、最新の`requestBannersRefresh`呼び出しの配置IDだけでなく、すでにキャッシュされている配置(たとえば、以前の更新、別の画面、またはSDKの自動処理によるもの)も含まれる場合があります。特定の配置のみに関心がある場合は、リスナー内で各バナーの配置IDを確認し、それ以外はスキップしてください。リスナーを登録したら、Brazeから同期したい配置に対して`requestBannersRefresh`を呼び出します。 ```java ArrayList placementIds = new ArrayList<>(); placementIds.add("global_banner"); placementIds.add("navigation_square_banner"); Braze.getInstance(context).subscribeToBannersUpdates(banners -> { for (Banner banner : banners.getBanners()) { Log.d(TAG, "Received banner: " + banner.getPlacementId()); } }); // Always refresh after your subscriber is registered Braze.getInstance(context).requestBannersRefresh(placementIds); ``` ```kotlin val placementIds = listOf("global_banner", "navigation_square_banner") Braze.getInstance(context).subscribeToBannersUpdates { update -> for (banner in update.banners) { Log.d(TAG, "Received banner: " + banner.placementId) } } // Always refresh after your subscriber is registered Braze.getInstance(context).requestBannersRefresh(placementIds) ``` ```javascript const bannerCardsSubscription = Braze.addListener( Braze.Events.BANNER_CARDS_UPDATED, (data) => { const banners = data.banners; console.log( `Received ${banners.length} Banner Cards with placement IDs:`, banners.map((banner) => banner.placementId) ); } ); ``` ```csharp This feature is not currently supported on Unity. ``` ```javascript This feature is not currently supported on Cordova. ``` ```dart StreamSubscription bannerStreamSubscription = braze.subscribeToBanners((List banners) { for (final banner in banners) { print("Received banner: " + banner.toString()); } }); ``` ```brightscript This feature is not currently supported on Roku. ``` ### ステップ4:配置IDを使って挿入する {#insertBanner} **Tip:** 完全なステップバイステップのチュートリアルについては、[配置IDによるバナーの表示](https://www.braze.com/docs/ja/ja/developer_guide/banners/tutorial_displaying_banners)を参照してください。 バナーのコンテナ要素を作成します。幅と高さを必ず設定してください。 ```html
``` Web Braze SDKでvanilla JavaScriptを使用している場合、[`insertBanner`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#insertbanner)メソッドを呼び出してコンテナ要素の内部HTMLを置き換えます。 ```javascript import * as braze from "@braze/web-sdk"; braze.initialize("sdk-api-key", { baseUrl: "sdk-base-url", allowUserSuppliedJavascript: true, // banners require you to opt-in to user-supplied javascript }); braze.subscribeToBannersUpdates((banners) => { // get this placement's banner. If it's `null` the user did not qualify for one. const globalBanner = braze.getBanner("global_banner"); if (!globalBanner) { return; } // choose where in the DOM you want to insert the banner HTML const container = document.getElementById("global-banner-container"); // Insert the banner which replaces the innerHTML of that container braze.insertBanner(globalBanner, container); // Special handling if the user is part of a Control Variant if (globalBanner.isControl) { // hide or collapse the container container.style.display = "none"; } }); braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]); ``` Web Braze SDKでReactを使用している場合、[`insertBanner`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#insertbanner)メソッドを`ref`と共に呼び出してコンテナ要素の内部HTMLを置き換えます。 ```tsx import { useRef } from 'react'; import * as braze from "@braze/web-sdk"; export default function App() { const bannerRef = useRef(null); useEffect(() => { const globalBanner = braze.getBanner("global_banner"); if (!globalBanner || globalBanner.isControl) { // hide the container } else { // insert the banner to the container node braze.insertBanner(globalBanner, bannerRef.current); } }, []); return
} ``` **Tip:** インプレッションをトラッキングするには、`isControl`の場合でも必ず`insertBanner`を呼び出してください。その後、コンテナを非表示にしたり折りたたんだりできます。 ```swift // To get access to the Banner model object: let globalBanner: Braze.Banner? AppDelegate.braze?.banners.getBanner(for: "global_banner", { banner in self.globalBanner = banner }) // UIKit implementation: // If you simply want the Banner view, initialize a `UIView` with the placement ID: if let braze = AppDelegate.braze { let bannerUIView = BrazeBannerUI.BannerUIView( placementId: "global_banner", braze: braze, // iOS does not perform automatic resizing or visibility changes. // Use the `processContentUpdates` parameter to adjust the size and visibility of your Banner according to your use case. processContentUpdates: { result in switch result { case .success(let updates): if let height = updates.height { // Adjust the visibility and/or height. } case .failure(let error): // Handle the error. } } ) } // SwiftUI implementation: // Similarly, if you want a Banner view in SwiftUI, use the corresponding `BannerView` initializer: if let braze = AppDelegate.braze { let bannerView = BrazeBannerUI.BannerView( placementId: "global_banner", braze: braze, // iOS does not perform automatic resizing or visibility changes. // Use the `processContentUpdates` parameter to adjust the size and visibility of your Banner according to your use case. processContentUpdates: { result in switch result { case .success(let updates): if let height = updates.height { // Adjust the visibility and/or height according to your parent controller. } case .failure(let error): // Handle the error. } } ) } ``` Javaコードでバナーを取得するには、以下を使用します。 ```java Banner globalBanner = Braze.getInstance(context).getBanner("global_banner"); ``` 次のXMLを含めることで、Androidビューレイアウトでバナーを作成できます。 ```xml ``` Android Viewsを使用している場合は、次のXMLを使用します。 ```xml ``` Jetpack Composeを使用するには、アプリモジュールに`com.braze:android-sdk-jetpack-compose`アーティファクトを追加します。他のBraze Android SDK依存関係と同じバージョンを使用してください。このモジュールは`android-sdk-ui`とは別で、`com.braze.jetpackcompose.banners`配下の[`Banner`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.banners/-banner.html)コンポーザブルを提供します。 **Note:** 一部のCompose UIライブラリは独自の`Banner`コンポーザブルを定義しています。BrazeのAPIを呼び出すには、`com.braze.jetpackcompose.banners.Banner`を明示的にインポートしてください。 ```kotlin import com.braze.jetpackcompose.banners.Banner @Composable fun myBannerSlot() { Banner(placementId = "global_banner") } ``` オプションで`heightCallback`を渡すと、バナーサイズが変更されたときにレンダリングされた高さ(dp単位)を受け取ることができます。詳細については、[`Banner`のKDoc](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.banners/-banner.html)を参照してください。 Jetpack Composeモジュールを追加しない場合は、[`BannerView`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.banners/-banner-view/index.html)を[`AndroidView`](https://developer.android.com/reference/kotlin/androidx/compose/ui/viewinterop/AndroidView)でラップします。 ```kotlin import android.view.ViewGroup import androidx.compose.runtime.Composable import androidx.compose.ui.viewinterop.AndroidView import com.braze.ui.banners.BannerView @Composable fun myBannerSlot() { AndroidView( factory = { context -> BannerView(context, "global_banner").apply { layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ) } }, update = { it.placementId = "global_banner" } ) } ``` Kotlinでバナーを取得するには、以下を使用します。 ```kotlin val banner = Braze.getInstance(context).getBanner("global_banner") ``` [React Nativeの新しいアーキテクチャ](https://reactnative.dev/architecture/landing-page)を使用している場合は、`BrazeBannerView`をFabricコンポーネントとして`AppDelegate.mm`に登録する必要があります。 ```swift #ifdef RCT_NEW_ARCH_ENABLED /// Register the `BrazeBannerView` for use as a Fabric component. - (NSDictionary> *)thirdPartyFabricComponents { NSMutableDictionary * dictionary = [super thirdPartyFabricComponents].mutableCopy; dictionary[@"BrazeBannerView"] = [BrazeBannerView class]; return dictionary; } #endif ``` 最もシンプルな統合方法として、以下のJavaScript XML(JSX)スニペットをビュー階層に追加し、配置IDだけを指定します。 ```javascript ``` React Nativeでバナーのデータモデルを取得したり、ユーザーのキャッシュにその配置が存在するかどうかを確認するには、以下を使用します。 ```javascript const banner = await Braze.getBanner("global_banner"); ``` ```csharp This feature is not currently supported on Unity. ``` ```javascript This feature is not currently supported on Cordova. ``` 最もシンプルな統合方法として、以下のウィジェットをビュー階層に追加し、配置IDだけを指定します。 ```dart BrazeBannerView( placementId: "global_banner", ), To get the Banner's data model in Flutter, use: ``` `getBanner`メソッドを使って、ユーザーのキャッシュにその配置が存在するかどうかを確認できます。 ```dart braze.getBanner("global_banner").then((banner) { if (banner == null) { // Handle null cases. } else { print(banner.toString()); } }); ``` ```brightscript This feature is not currently supported on Roku. ``` ### ステップ5:テストバナーを送信する(オプション) {#handling-test-cards} バナーキャンペーンを開始する前に、[テストバナーを送信](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/sending_test_messages?tab=banners)して統合を確認できます。テストバナーは別のインメモリキャッシュに保存され、アプリの再起動後は保持されません。追加のセットアップは不要ですが、テストを表示できるようにテストデバイスがフォアグラウンドのプッシュ通知を受信できる必要があります。 **Note:** テストバナーは他のバナーと同じですが、次のアプリセッションで削除される点が異なります。 ## インプレッションを記録する {#log-impressions} Brazeは、SDKメソッドを使ってバナーを挿入する際に、表示されているバナーのインプレッションを自動的に記録します—そのため、インプレッションを手動でトラッキングする必要はありません。 ## クリックを記録する {#logging-clicks} バナーのクリックを記録するために使用するメソッドは、バナーのレンダリング方法とクリックハンドラーの配置場所によって異なります。 ### 標準バナーコンテンツ(自動) {#standard-banner-content-automatic} デフォルトの標準SDKメソッドを使ってバナーを挿入しており、バナーが標準のエディターコンポーネント(画像、ボタン、テキスト)を使用している場合、クリックは自動的にトラッキングされます。SDKがこれらの要素にクリックリスナーをアタッチするため、追加のコードは不要です。 ### カスタムコードブロック {#custom-code-blocks} バナーがBrazeダッシュボードの**カスタムコード**エディターブロックを使用している場合、そのカスタムHTML内からクリックを記録するには`brazeBridge.logClick()`を使用する必要があります。これは、SDKメソッドを使ってバナーをレンダリングする場合でも同様です。SDKはカスタムコード内の要素にリスナーを自動的にアタッチできないためです。 ```html ``` 完全なリファレンスについては、[バナー用のカスタムコードとJavaScriptブリッジ](https://www.braze.com/docs/ja/ja/user_guide/channels/banners/create_a_banner#custom-code)を参照してください。`brazeBridge`は、バナーの内部HTMLと親Braze SDKの間の通信レイヤーを提供します。 ### カスタムUI実装(ヘッドレス) {#custom-ui-implementations-headless} バナーのHTMLをレンダリングする代わりに、バナーの[カスタムプロパティ](#custom-properties)を使って完全にカスタムのUIを構築する場合、アプリケーションコードからクリックとインプレッションを手動で記録する必要があります。SDKがバナーをレンダリングしていないため、カスタムUI要素とのインタラクションを自動的にトラッキングする方法がありません。 メソッドシグネチャと詳細については、[Braze SDKリファレンスドキュメント](https://www.braze.com/docs/ja/ja/developer_guide/references)を参照してください。 #### インプレッションを記録する {#logging-impressions} カスタムUIがバナーを「閲覧済み」と見なしたときに、プラットフォームのバナーインプレッションメソッドを呼び出します。重複イベントを避けるために、インプレッションとしてカウントする条件について堅牢なロジックを構築してください。たとえば、バナーがビューポートに入ったとき(または同等のタイミング)にのみ記録し、同じバナーがスクロールで再び表示されたときやコンポーネントが新しいビューイベントなしに再レンダリングされたときには再度記録しないようにします。 ```javascript import * as braze from "@braze/web-sdk"; // Log impression when your custom UI considers the banner viewed (for example, once when it enters viewport) const banner = braze.getBanner("placement_id_homepage_top"); if (banner) { braze.logBannerImpressions([banner]); } ``` [Web SDKリファレンス](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logbannerimpressions) ```kotlin // Log impression when your custom UI considers the banner viewed (for example, once when it enters viewport) Braze.getInstance(context).logBannerImpression("placement_id_homepage_top") ``` ```java // Log impression when your custom UI considers the banner viewed (for example, once when it enters viewport) Braze.getInstance(context).logBannerImpression("placement_id_homepage_top"); ``` [Android SDKリファレンス](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/log-banner-impression.html) ```swift // Retrieve a banner and log an impression on it (for example, once when it enters viewport) braze.banners.getBanner(for: "placement_id_homepage_top") { banner in banner?.context.logImpression() } ``` [Swift SDKリファレンス](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/banner/context-swift.class/logimpression()) ```javascript // Log impression when your custom UI considers the banner viewed (for example, once when it enters viewport) Braze.logBannerImpression("placement_id_homepage_top"); ``` 最新のメソッドシグネチャについては、[React Native SDKリポジトリ](https://github.com/braze-inc/braze-react-native-sdk)を参照してください。 ```dart // Log impression when your custom UI considers the banner viewed (for example, once when it enters viewport) braze.logBannerImpression("placement_id_homepage_top"); ``` [Flutter SDKリファレンス](https://pub.dev/documentation/braze_plugin/latest/braze_plugin/BrazePlugin/logBannerImpression.html) #### クリックを記録する ユーザーがカスタムバナー(または特定のボタン)をタップしたときに、プラットフォームのバナークリックメソッドを呼び出します。クリックが特定のボタンに対するものである場合は、オプションの`buttonId`を渡して、分析がクリックを正しく帰属できるようにします。 ```javascript import * as braze from "@braze/web-sdk"; // Log click braze.logBannerClick("placement_id_homepage_top", buttonId); // buttonID is optional ``` [Web SDKリファレンス](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logbannerclick) ```kotlin // Log click Braze.getInstance(context).logBannerClick("placement_id_homepage_top", buttonId) // buttonID parameter can be null ``` ```java // Log click Braze.getInstance(context).logBannerClick("placement_id_homepage_top", buttonId); // buttonID parameter can be null ``` [Android SDKリファレンス](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/log-banner-click.html) ```swift // Retrieve a banner and log a click on it braze.banners.getBanner(for: "placement_id_homepage_top") { banner in banner?.context.logClick(buttonId: buttonId) // buttonID is optional } ``` [Swift SDKリファレンス](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/banner/context-swift.class/logclick(buttonid:)) ```javascript // Log click Braze.logBannerClick("placement_id_homepage_top", buttonId); // buttonID is optional ``` 最新のメソッドシグネチャについては、[React Native SDKリポジトリ](https://github.com/braze-inc/braze-react-native-sdk)を参照してください。 ```dart // Log click braze.logBannerClicked("placement_id_homepage_top", buttonId); // buttonID parameter can be null ``` [Flutter SDKリファレンス](https://pub.dev/documentation/braze_plugin/latest/braze_plugin/BrazePlugin/logBannerClicked.html) ## 非表示を記録する {#log-dismissals} バナーの非表示は、ユーザーが能動的にバナーを閉じたときに、プログラムで配置からバナーを削除します。非表示にすると、そのユーザーに対してバナーは抑制されます。次に配置リストが更新されたとき、ユーザーが対象であれば新しいバナーが返されます。 ### 前提条件 バナーの非表示を記録するために必要な最小SDKバージョンは以下の通りです。 ### 統合 {#integrations} #### 標準バナー統合(ドラッグ&ドロップエディター) {#standard-banner-integrations-drag-and-drop-editor} バナーがドラッグ&ドロップエディターを使用しており、非表示ボタンコンポーネントが含まれている場合、追加のコードは不要です。ユーザーが非表示ボタンをクリックすると、メッセージが非表示になり、非表示がトリガーされ、分析用の非表示イベントが記録されます。 #### カスタムコードブロック バナーが**カスタムコード**エディターブロックを使用している場合、バナーのHTML内から`brazeBridge.closeMessage()`を使って直接非表示をトリガーできます。 ```html ``` #### プログラムでバナーを非表示にする {#dismiss-a-banner-programmatically} ドラッグ&ドロップエディターで作成した非表示ボタンを含む標準の`BrazeBannerView`を使用している場合、追加のコードは不要です。非表示は自動的に処理されます。 カスタムUI統合の場合、Brazeインスタンスのdismissメソッドを直接呼び出して、プログラムでバナーを非表示にし、非表示イベントを記録できます。dismissメソッドは複数回呼び出しても安全です。SDKは同じバナーに対する重複呼び出しを無視します。 プログラムでバナーを非表示にするために必要な最小SDKバージョンは以下の通りです。 `Banner`オブジェクトを`braze.dismissBanner()`に渡します。`Banner`オブジェクトは`braze.getAllBanners()`または`subscribeToBannersUpdates`コールバックから取得できます。 ```javascript import * as braze from "@braze/web-sdk"; const banners = braze.getAllBanners(); const banner = banners["global_banner"]; if (banner) { braze.dismissBanner(banner); } ``` ```typescript import * as braze from "@braze/web-sdk"; const banners = braze.getAllBanners(); const banner = banners["global_banner"]; if (banner) { braze.dismissBanner(banner); } ``` ```java Braze.getInstance(context).dismissBanner("your-placement-id"); ``` ```kotlin Braze.getInstance(context).dismissBanner("your-placement-id") ``` バナーのcontextが利用可能な場合は、`dismiss()`を使用します。このメソッドは冪等で、`onDismiss`コールバックを自動的に発火します。contextが利用できない場合は、バナーに対して直接`dismiss(using:)`を呼び出します。どちらのメソッドもメインスレッドから呼び出す必要があります。 ```swift // Preferred: dismiss via context. banner.context?.dismiss() // Fallback: if context is unavailable. banner.dismiss(using: braze) ``` Objective-Cでは、`[banner.context dismiss]`および`[banner dismissUsing:braze]`として利用できます。 ```javascript Braze.dismissBanner("your-placement-id"); ``` ```dart braze.dismissBanner("your-placement-id"); ``` ### バナー非表示時にカスタム分析を記録する {#log-custom-analytics-on-banner-dismissal} バナーの非表示時にカスタムロジック(分析の記録など)を実行するには、SDKの非表示コールバックを使用します。コールバックは、バナーの`placementId`、`stableKey`、`trackingId`を含むイベントオブジェクトを受け取ります。 [`Banner.subscribeToDismissedEvent()`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.banner.html#subscribetodismissedevent)を使って、特定のバナーが非表示にされたときにカスタムロジックを実行します。バナーを表示する前にイベントをサブスクライブしてください。 **Note:** `Banner.subscribeToDismissedEvent()`にはWeb SDK 6.9.0以降が必要です。それ以前のバージョンでは、`braze.subscribeToBannersUpdates()`を使用し、更新されたバナーマップにバナーが存在しなくなったかどうかを確認することで非表示を検出してください。 ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToBannersUpdates((banners) => { const banner = banners["global_banner"]; if (banner) { banner.subscribeToDismissedEvent(() => { // Run any custom logic here, such as logging custom analytics console.log("Banner was dismissed"); }); } }); braze.requestBannersRefresh(["global_banner"]); ``` ```typescript import { useEffect } from "react"; import * as braze from "@braze/web-sdk"; useEffect(() => { const subscriptionId = braze.subscribeToBannersUpdates((banners) => { const banner = banners["global_banner"]; if (banner) { banner.subscribeToDismissedEvent(() => { // Run any custom logic here, such as logging custom analytics console.log("Banner was dismissed"); }); } }); braze.requestBannersRefresh(["global_banner"]); return () => { braze.removeSubscription(subscriptionId); }; }, []); ``` [`BannerView`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.banners/-banner-view/index.html)のオプションの[`onDismissCallback`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.banners/-banner-view/on-dismiss-callback.html)プロパティを設定します。 ```java import android.util.Log; import com.braze.ui.banners.BannerView; import kotlin.Unit; // After obtaining your BannerView instance (for example from XML via findViewById, or `new BannerView(context, "global_banner")`) bannerView.setOnDismissCallback((snapshot) -> { Log.d(TAG, "placementId: " + snapshot.getPlacementId() + ", stableKey: " + snapshot.getStableKey() + ", trackingId: " + snapshot.getTrackingId()); // Run any custom logic here, such as logging custom analytics return Unit.INSTANCE; }); ``` ```kotlin import android.util.Log import com.braze.ui.banners.BannerView // After obtaining your BannerView instance (for example via findViewById or `BannerView(context, "global_banner")`) bannerView.onDismissCallback = { snapshot -> Log.d(TAG, "placementId: ${snapshot.placementId}, stableKey: ${snapshot.stableKey}, trackingId: ${snapshot.trackingId}") // Run any custom logic here, such as logging custom analytics } ``` ```swift // After initializing your banner view instance using UIKit or SwiftUI bannerView.onDismiss = { event in print("Banner dismissed — placementId: \(event.placementId ?? "unknown")") print(" stableKey: \(event.stableKey ?? "unknown")") print(" trackingId: \(event.trackingId ?? "unknown")") // Run any custom logic here, such as logging custom analytics } ``` `Braze.BrazeBannerView`の`onDismiss`プロパティを設定して、バナーが非表示にされたときにカスタムロジックを実行します。 ```javascript import Braze from "@braze/react-native-sdk"; { console.log("placementId:", event.placementId, "stableKey:", event.stableKey, "trackingId:", event.trackingId); // Run any custom logic here, such as logging custom analytics }} /> ``` `BrazeBannerView`の`onDismiss`パラメーターを設定して、バナーが非表示にされたときにカスタムロジックを実行します。 ```dart BrazeBannerView( placementId: 'global_banner', onDismiss: (BrazeBannerDismissEvent event) { print('placementId: ${event.placementId}, stableKey: ${event.stableKey}, trackingId: ${event.trackingId}'); // Run any custom logic here, such as logging custom analytics }, ) ``` ### 保留中の非表示のストレージ上限 {#pending-dismissal-storage-cap} 非表示イベントは、次の`requestBannersRefresh`呼び出し時にBrazeサーバーに同期されるまで、保留中のエントリとしてローカルに保存されます。 **Warning:** まれに、同期が成功しないまま大量の非表示が蓄積された場合、古い保留中の非表示が削除されることがあります。この場合、以前に非表示にしたバナーが次の同期が成功するまで再表示される可能性があります。このリスクを最小限に抑えるには、アプリがネットワーク接続を回復するたびに`requestBannersRefresh`を呼び出してください。 ## サイズと寸法 {#dimensions-and-sizing} バナーのサイズと寸法について知っておくべきことは以下の通りです。 - コンポーザーではさまざまなサイズでバナーをプレビューできますが、その情報は保存されず、SDKに送信されません。 - HTMLは、レンダリングされるコンテナの全幅を使用します。 - 固定サイズの要素を作成し、そのサイズをコンポーザーでテストすることをお勧めします。 ## カスタムプロパティ {#custom-properties} バナーキャンペーンのカスタムプロパティを使って、SDKを通じてキーと値のデータを取得し、アプリの動作や外観を変更できます。たとえば、以下のようなことが可能です。 - サードパーティの分析ツールや統合サービス向けにメタデータを送信する。 - `timestamp`やJSONオブジェクトなどのメタデータを使って条件分岐ロジックをトリガーする。 - `ratio`や`format`などのメタデータに基づいてバナーの動作をコントロールする。 ### 前提条件 バナーキャンペーンに[カスタムプロパティを追加](https://www.braze.com/docs/ja/ja/user_guide/channels/banners/create_a_banner#custom-properties)する必要があります。さらに、カスタムプロパティにアクセスするために必要な最小SDKバージョンは以下の通りです。 ### カスタムプロパティにアクセスする {#access-custom-properties} バナーのカスタムプロパティにアクセスするには、ダッシュボードで定義されたプロパティの型に基づいて、以下のいずれかのメソッドを使用します。キーがその型のプロパティと一致しない場合、またはキーが存在しない場合、メソッドは`null`を返します。 ```javascript // Returns the Banner instance const banner = braze.getBanner("placement_id_homepage_top"); // banner may be undefined or null if (banner) { // Returns the string property const stringProperty = banner.getStringProperty("color"); // Returns the boolean property const booleanProperty = banner.getBooleanProperty("expanded"); // Returns the number property const numberProperty = banner.getNumberProperty("height"); // Returns the timestamp property (as a number) const timestampProperty = banner.getTimestampProperty("account_start"); // Returns the image URL property as a string of the URL const imageProperty = banner.getImageProperty("homepage_icon"); // Returns the JSON object property const jsonObjectProperty = banner.getJsonProperty("footer_settings"); } ``` ```swift // Passes the specified banner to the completion handler AppDelegate.braze?.banners.getBanner(for: "placement_id_homepage_top") { banner in // Returns the string property let stringProperty: String? = banner.stringProperty(key: "color") // Returns the boolean property let booleanProperty: Bool? = banner.boolProperty(key: "expanded") // Returns the number property as a double let numberProperty: Double? = banner.numberProperty(key: "height") // Returns the Unix UTC millisecond timestamp property as an integer let timestampProperty: Int? = banner.timestampProperty(key: "account_start") // Returns the image property as a String of the image URL let imageProperty: String? = banner.imageProperty(key: "homepage_icon") // Returns the JSON object property as a [String: Any] dictionary let jsonObjectProperty: [String: Any]? = banner.jsonObjectProperty(key: "footer_settings") } ``` ```java // Returns the Banner instance Banner banner = Braze.getInstance(context).getBanner("placement_id_homepage_top"); // banner may be undefined or null if (banner != null) { // Returns the string property String stringProperty = banner.getStringProperty("color"); // Returns the boolean property Boolean booleanProperty = banner.getBooleanProperty("expanded"); // Returns the number property Number numberProperty = banner.getNumberProperty("height"); // Returns the timestamp property (as a Long) Long timestampProperty = banner.getTimestampProperty("account_start"); // Returns the image URL property as a String of the URL String imageProperty = banner.getImageProperty("homepage_icon"); // Returns the JSON object property as a JSONObject JSONObject jsonObjectProperty = banner.getJSONProperty("footer_settings"); } ``` ```kotlin // Returns the Banner instance val banner: Banner = Braze.getInstance(context).getBanner("placement_id_homepage_top") ?: return // Returns the string property val stringProperty: String? = banner.getStringProperty("color") // Returns the boolean property val booleanProperty: Boolean? = banner.getBooleanProperty("expanded") // Returns the number property val numberProperty: Number? = banner.getNumberProperty("height") // Returns the timestamp property (as a Long) val timestampProperty: Long? = banner.getTimestampProperty("account_start") // Returns the image URL property as a String of the URL val imageProperty: String? = banner.getImageProperty("homepage_icon") // Returns the JSON object property as a JSONObject val jsonObjectProperty: JSONObject? = banner.getJSONProperty("footer_settings") ``` ```javascript // Get the Banner instance const banner = await Braze.getBanner('placement_id_homepage_top'); if (!banner) return; // Get the string property const stringProperty = banner.getStringProperty('color'); // Get the boolean property const booleanProperty = banner.getBooleanProperty('expanded'); // Get the number property const numberProperty = banner.getNumberProperty('height'); // Get the timestamp property (as a number) const timestampProperty = banner.getTimestampProperty('account_start'); // Get the image URL property as a string const imageProperty = banner.getImageProperty('homepage_icon'); // Get the JSON object property const jsonObjectProperty = banner.getJSONProperty('footer_settings'); ``` ```dart // Fetch the banner asynchronously _braze.getBanner(placementId).then(('placement_id_homepage_top') { // Get the string property final String? stringProperty = banner?.getStringProperty('color'); // Get the boolean property final bool? booleanProperty = banner?.getBooleanProperty('expanded'); // Get the number property final num? numberProperty = banner?.getNumberProperty('height'); // Get the timestamp property final int? timestampProperty = banner?.getTimestampProperty('account_start'); // Get the image URL property final String? imageProperty = banner?.getImageProperty('homepage_icon'); // Get the JSON object property final Map? jsonObjectProperty = banner?.getJSONProperty('footer_settings'); // Use these properties as needed in your UI or logic }); ``` # テストバナー Source: /docs/ja/developer_guide/banners/testing/index.md # テストバナー {#test-banners} > すべてのメディア、コピー、パーソナライゼーション、カスタム属性が正しくレンダリングされるようにするために、キャンペーンを起動する前にバナーメッセージをテストする方法について説明します。一般的な情報については、[バナーについて](https://www.braze.com/docs/ja/ja/developer_guide/banners)を参照してください。 ## 前提条件 {#prerequisites} Brazeでバナーメッセージをテストする前に、[Brazeでバナーキャンペーンを作成する](https://www.braze.com/docs/ja/ja/user_guide/channels/banners/create_a_banner)必要があります。さらに、テストしたいプレースメントがすでに[アプリやWebサイトに配置されている](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements)ことを確認してください。 テストを[コンテンツテストグループ](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/developer_console/internal_groups_tab#content-test-groups)または個々のユーザーに送信するには、送信前にテストデバイスでプッシュが有効になっており、テストユーザーの有効なプッシュトークンが登録されている必要があります。 ## バナーをテストする {#test-a-banner} **Preview** to you preview your Banner or send a test message. ![Preview tab of the Banner composer.](https://www.braze.com/docs/ja/ja/assets/img/banners/select_preview.png?898229d959020b86215b0604a136dfae){: style="max-width:50%;"} Keep in mind, your preview may not be identical to the final render on a user's device due to differences across hardware. To send a test message, add either a content test group or one or more individual users as **Test Recipients**, then select **Send Test**. You'll be able to view your test message on the device for up to 5 minutes. You can then select **Copy preview link** to generate and copy a shareable preview link that shows what the banner will look like for a random user. The link will last for seven days before it needs to be regenerated. ![Preview tab of the Banner composer.](https://www.braze.com/docs/ja/ja/assets/img/banners/preview_banner.png?d8aab458e372815d934bd3cd9c3f3f43) While reviewing your test Banner, verify the following: - Is your Banner campaign assigned to a placement? - Do the images and media show up and act as expected on your targeted device types and screen sizes? - Do your links and buttons direct the user to where they should go? - Does the Liquid function as expected? Have you accounted for a default attribute value in the event that the Liquid returns no information? - Is your copy clear, concise, and correct? For more information, see [Send test messages](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/sending_test_messages/). # バナー分析 Source: /docs/ja/developer_guide/banners/analytics/index.md # バナー分析 > キャンペーンの詳細、メッセージパフォーマンス、過去のパフォーマンスなど、バナーの分析方法を学習する。一般的な情報については、[バナーについて](https://www.braze.com/docs/ja/ja/developer_guide/banners)を参照してください。 ## Viewing analytics Once you've launched your campaign, you can return to the details page for that campaign to view key metrics. Navigate to the **Campaigns** page and select your campaign to open the details page. For sent in Canvas, refer to [Canvas analytics](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/canvas/testing_canvases/measuring_and_testing_with_canvas_analytics/). **Tip:** Looking for definitions for the terms and metrics listed in your report? Refer to our From the **Campaign Analytics** tab, you can view your reports in a series of panels. You may see more or less than those listed in the following sections, but each has its own useful purpose. ### Time range By default, the time range for **Campaign Analytics** will display the last 90 days from the current time. This means that if the campaign was launched more than 90 days ago, the analytics will display as "0" for the given time range. To view all analytics for older campaigns, adjust the reporting time range. ### Campaign details The **Campaign Details** panel shows a high-level overview of the entire performance for your Review this panel to see overall metrics such as the number of messages sent to the number of recipients, the primary conversion rate, and the total revenue generated by this message. You can also review delivery, audience, and conversion settings from this page. **Note:** Analytics numbers in the dashboard and Snowflake may differ slightly. Braze measures numbers in the dashboard and records rows to Snowflake separately. Snowflake is the more precise data source, so if you see discrepancies between these sources, we recommend referring to Snowflake data. #### Estimated Audience and Current Audience Depending on how large your workspace is, the **Campaign Details** panel may label audience statistics **Estimated Audience** or **Current Audience**. The following table summarizes what each label means. | Footer label | When it is used | | --- | --- | | **Estimated Audience** | Braze does not run a full-database count by default. Audience size is estimated from a sample and extrapolated, similar to the **Reachable users** range in the segment builder. Margins of error are expected, especially for large workspaces or small segments as a share of the workspace. | | **Current Audience** | Braze can compute the default statistic with a full scan of workspace profiles, so the displayed audience size is a current, unsampled count (still subject to channel reachability, subscription rules, and other targeting options). | {: .reset-td-br-1 .reset-td-br-2 aria-label="Estimated Audience and Current Audience" } For details on sampling behavior, **Calculate exact statistics**, and segmenting **Reachable users**, see [Measure segment size](https://www.braze.com/docs/ja/ja/user_guide/audience/segments/measuring_segment_size/). #### Changes Since Last Viewed The number of updates to the campaign from other members of your team is tracked by the *Changes Since Last Viewed* metric on the campaign overview page. Select **Changes Since Last Viewed** to view a changelog of updates to the campaign's name, schedule, tags, message, audience, approval status, or team access configuration. For each update, you can see who performed the update and when. You can use this changelog to audit changes to your campaign. If you want to simplify your view, click **Add/Remove Columns** and clear any metrics as desired. By default, all metrics are displayed. ### Historical performance The **Historical Performance** panel allows you to view the metrics from the **Message Performance** panel as a graph over time. Use the filters at the top of the panel to modify the stats and channels shown in the graph. The time range of this graph will always mirror the time range specified at the top of the page. To get a day-by-day breakdown, click the hamburger menu and select **Download CSV** to receive a CSV export of the report. ![A graph of the Historical Performance panel with example statistics for an email from February 2021 to May 2022.](https://www.braze.com/docs/ja/ja/assets/img/cc-historical-performance.png?03e5e9b53261a881b6f96b5e65e70222) ### Conversion event details The **Conversion Event Details** panel shows you the performance of your conversion events for your campaign. For more information, refer to [Conversion Events](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/campaigns/building_campaigns/conversion_events/#step-3-view-results). ![The Conversion Event Details panel.](https://www.braze.com/docs/ja/ja/assets/img/cc-conversion.png?39e3903bd0948f87cac25bf481eb0ba5) ### Conversion correlation The **Conversion Correlation** panel gives you insight into what user attributes and behaviors help or hurt the outcomes you set for campaigns. For more information, refer to [Conversion correlation](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/testing/conversion_correlation/). ![The Conversion Correlation panel with an analysis on user attributes and behavior from the Primary Conversion Event - A.](https://www.braze.com/docs/ja/ja/assets/img/convcorr.png?9322bf2817e7a5fbecd4ceb3b850875f) ## Retention report Retention reports show you the rates at which your users have performed a selected retention event over time periods in a specific campaign or Canvas. For more information, refer to [Retention reports](https://www.braze.com/docs/ja/ja/user_guide/analytics/reporting/retention_reports/). ## Funnel report Funnel reporting offers a visual report that allows you to analyze the journeys your customers take after receiving a campaign or Canvas. If your campaign or Canvas uses a control group or multiple variants, you will be able to understand how the different variants have impacted the conversion funnel at a more granular level and optimize based on this data. For more information, refer to [Funnel reports](https://www.braze.com/docs/ja/ja/user_guide/analytics/reporting/funnel_reports/). # Content Cardsからバナーへ移行する Source: /docs/ja/developer_guide/banners/migrating_from_content_cards/index.md # Content Cardsからバナーへ移行する {#migrate-from-content-cards-to-banners} > このガイドは、バナー形式のメッセージングユースケースにおいて、Content Cardsからバナーへの移行を支援するものです。バナーは、アプリケーション内の特定の配置に表示される、インラインで持続的なアプリ内メッセージおよびWebメッセージに最適です。 ## なぜバナーに移行するのか? {#why-migrate-to-banners} - エンジニアリングチームがカスタムContent Cardsを構築または保守している場合、バナーへの移行によりその継続的な投資を削減できます。バナーはマーケターがUIを直接コントロールできるようにし、開発者を他の作業に解放します。 - 新しいホームページメッセージやオンボーディングフロー、常時表示の告知を立ち上げる場合は、Content Cardsで構築するよりバナーから始めましょう。リアルタイムのパーソナライゼーション、30日間の有効期限なし、サイズ制限なし、そしてネイティブな優先順位付けを導入初日から活用できます。 - 30日間の有効期限制限を回避する必要がある場合、複雑な再適格性ロジックを管理している場合、あるいは陳腐化したパーソナライゼーションに悩まされている場合、バナーはこれらの問題をネイティブに解決します。 バナーは、バナー形式のメッセージングにおいてContent Cardsよりもいくつかの利点があります: ### 制作の加速 {#accelerated-production} - **継続的なエンジニアリングサポートの必要性が減少**:マーケターは、カスタマイズに開発者の支援を必要とせずに、ドラッグ&ドロップエディターとカスタムHTMLを使用して独自のメッセージを作成できます。 - **柔軟なカスタマイズオプション**:エディター内で直接デザインするか、HTMLを使用するか、カスタムプロパティで既存のデータモデルを活用できます。 ### より良いユーザー体験 {#better-ux} - **ダイナミックなコンテンツの更新**:バナーはリフレッシュのたびにLiquidロジックと適格性を更新するため、ユーザーは常に最も関連性の高いコンテンツを閲覧できます。 - **ネイティブ配置サポート**:メッセージはフィードではなく特定のコンテキストで表示されるため、文脈に応じた関連性が高くなります。 - **ネイティブ優先順位付け**:カスタムロジックなしで表示順序をコントロールできるため、メッセージの階層構造を管理しやすくなります。 ### 永続性 {#persistence} - **有効期限なし**:バナーキャンペーンにはContent Cardsのような30日間の有効期限がないため、メッセージを真に永続的に表示できます。 ## 移行するタイミング {#when-to-migrate} 以下の目的でContent Cardsを使用している場合は、バナーへの移行を検討してください: - ホームページのヒーロー広告、商品ページのプロモーション、チェックアウト時のオファー - 常時表示のナビゲーション告知やサイドバーメッセージ - 30日以上継続する常時表示メッセージ - リアルタイムでのパーソナライゼーションと適格性を求めるメッセージ ## Content Cardsを維持すべきケース {#when-to-keep-content-cards} 以下が必要な場合は、Content Cardsを引き続き使用してください: - **フィード体験:** 複数のスクロール可能なメッセージやカード形式の「受信トレイ」を伴うあらゆるユースケース。 - **特定の機能:** コネクテッドコンテンツやプロモーションコードを必要とするメッセージ。バナーはこれらをネイティブでサポートしていません。 - **トリガー配信:** APIトリガーまたはアクションベースの配信を厳密に必要とするユースケース。バナーはAPIトリガー型やアクションベースの配信をサポートしていませんが、リアルタイム適格性評価により、ユーザーは各リフレッシュ時にセグメントの所属に基づいて即座に適格か不適格かが判定されます。 ## 移行ガイド {#migration-guide} ### 前提条件 {#prerequisites} 移行前に、Braze SDKが最低バージョン要件を満たしていることを確認してください: 解除と再適格性には、以下の最小SDKバージョンが必要です: ### 更新をサブスクライブする {#subscribe-to-updates} #### Content Cards方式 {#content-cards-approach} ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToContentCardsUpdates((cards) => { // Handle array of cards cards.forEach(card => { console.log("Card:", card.id); }); }); ``` ```kotlin Braze.getInstance(context).subscribeToContentCardsUpdates { cards -> // Handle array of cards cards.forEach { card -> Log.d(TAG, "Card: ${card.id}") } } ``` ```swift braze.contentCards.subscribeToUpdates { cards in // Handle array of cards for card in cards { print("Card: \(card.id)") } } ``` ```javascript Braze.addListener(Braze.Events.CONTENT_CARDS_UPDATED, (update) => { const cards = update.cards; // Handle array of cards cards.forEach(card => { console.log("Card:", card.id); }); }); ``` ```dart StreamSubscription contentCardsStreamSubscription = braze.subscribeToContentCards((List contentCards) { // Handle array of cards for (final card in contentCards) { print("Card: ${card.id}"); } }); ``` #### バナー方式 {#banners-approach} ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToBannersUpdates((banners) => { // Get banner for specific placement const banner = braze.getBanner("sample_placement_id"); if (banner) { console.log("Banner received for placement:", banner.placementId); } }); ``` ```kotlin Braze.getInstance(context).subscribeToBannersUpdates { update -> // Get banner for specific placement val banner = Braze.getInstance(context).getBanner("sample_placement_id") if (banner != null) { Log.d(TAG, "Banner received for placement: ${banner.placementId}") } } ``` ```swift braze.banners.subscribeToUpdates { banners in // Get banner for specific placement braze.banners.getBanner(for: "sample_placement_id") { banner in guard let banner = banner else { return } print("Banner received for placement: \(banner.placementId)") } } ``` ```javascript Braze.addListener(Braze.Events.BANNER_CARDS_UPDATED, (data) => { const banners = data.banners; // Get banner for specific placement Braze.getBanner("sample_placement_id").then(banner => { if (banner) { console.log("Banner received for placement:", banner.placementId); } }); }); ``` ```dart StreamSubscription bannerStreamSubscription = braze.subscribeToBanners((List banners) { // Get banner for specific placement braze.getBanner("sample_placement_id").then((banner) { if (banner != null) { print("Banner received for placement: ${banner.placementId}"); } }); }); ``` ### コンテンツを表示する {#display-content} **Note:** Content Cardsはカスタムのロジックで手動レンダリングできますが、バナーは標準のSDKメソッドでのみレンダリングできます。 #### Content Cards方式 ```javascript // Show default feed UI braze.showContentCards(document.getElementById("feed")); // Or manually render cards const cards = braze.getCachedContentCards(); cards.forEach(card => { // Custom rendering logic if (card instanceof braze.ClassicCard) { // Render classic card } }); ``` ```kotlin // Using default fragment val fragment = ContentCardsFragment() supportFragmentManager.beginTransaction() .replace(R.id.content_cards_container, fragment) .commit() // Or manually render cards val cards = Braze.getInstance(context).getCachedContentCards() cards.forEach { card -> when (card) { is ClassicCard -> { // Render classic card } } } ``` ```swift // Using default view controller let contentCardsController = BrazeContentCardUI.ViewController(braze: braze) navigationController?.pushViewController(contentCardsController, animated: true) // Or manually render cards let cards = braze.contentCards.cards for card in cards { switch card { case let card as Braze.ContentCard.Classic: // Render classic card default: break } } ``` ```javascript // Launch default feed Braze.launchContentCards(); // Or manually render cards const cards = await Braze.getContentCards(); cards.forEach(card => { if (card.type === 'CLASSIC') { // Render classic card } }); ``` ```dart // Launch default feed braze.launchContentCards(); // Or manually render cards final cards = await braze.getContentCards(); for (final card in cards) { if (card.type == 'CLASSIC') { // Render classic card } } ``` #### バナー方式 ```javascript braze.subscribeToBannersUpdates((banners) => { const banner = braze.getBanner("sample_placement_id"); if (!banner) { return; } const container = document.getElementById("global-banner-container"); braze.insertBanner(banner, container); if (banner.isControl) { container.style.display = "none"; } }); braze.requestBannersRefresh(["sample_placement_id"]); ``` ```kotlin // Using BannerView in XML // // Or programmatically val bannerView = BannerView(context).apply { placementId = "sample_placement_id" } container.addView(bannerView) Braze.getInstance(context).requestBannersRefresh(listOf("sample_placement_id")) ``` ```swift // Using BannerUIView let bannerView = BrazeBannerUI.BannerUIView( placementId: "sample_placement_id", braze: braze, processContentUpdates: { result in switch result { case .success(let updates): if let height = updates.height { // Update height constraint } case .failure: break } } ) view.addSubview(bannerView) braze.banners.requestBannersRefresh(placementIds: ["sample_placement_id"]) ``` ```javascript // Using BrazeBannerView component // Or get banner data const banner = await Braze.getBanner("sample_placement_id"); if (banner) { // Render custom banner UI } Braze.requestBannersRefresh(["sample_placement_id"]); ``` ```dart // Using BrazeBannerView widget BrazeBannerView( placementId: "sample_placement_id", ) // Or get banner data final banner = await braze.getBanner("sample_placement_id"); if (banner != null) { // Render custom banner UI } braze.requestBannersRefresh(["sample_placement_id"]); ``` ### 分析のログ記録(カスタム実装) {#log-analytics-custom-implementations} **Note:** Content Cardsとバナーは、デフォルトのUIコンポーネントを使用する場合、自動的に分析データをトラッキングします。以下の例は、独自のUIを構築するカスタム実装向けです。 #### Content Cards方式 ```javascript // Manual impression logging required for custom implementations cards.forEach(card => { braze.logContentCardImpressions([card]); }); // Manual click logging required for custom implementations card.logClick(); ``` ```kotlin // Manual impression logging required for custom implementations cards.forEach { card -> card.logImpression() } // Manual click logging required for custom implementations card.logClick() ``` ```swift // Manual impression logging required for custom implementations for card in cards { card.context?.logImpression() } // Manual click logging required for custom implementations card.context?.logClick() ``` ```javascript // Manual impression logging required for custom implementations cards.forEach(card => { Braze.logContentCardImpression(card.id); }); // Manual click logging required for custom implementations Braze.logContentCardClicked(card.id); ``` ```dart // Manual impression logging required for custom implementations for (final card in cards) { braze.logContentCardImpression(card); } // Manual click logging required for custom implementations braze.logContentCardClicked(card); ``` #### バナー方式 **Important:** `insertBanner()`を使用すると、分析は自動的にトラッキングされます。`insertBanner()`を使用している場合は、手動でのログ記録は使用しないでください。 ```javascript // Analytics are automatically tracked when using insertBanner() // Manual logging should not be used when using insertBanner() // For custom implementations, use manual logging methods: // Log impression braze.logBannerImpressions([banner]); // Log click (with optional buttonId) braze.logBannerClick("sample_placement_id", buttonId); ``` **Important:** BannerViewを使用すると、分析データは自動的にトラッキングされます。BannerViewを使用する際は、手動でのログ記録は使用しないでください。 ```kotlin // Analytics are automatically tracked when using BannerView // Manual logging should not be used for default BannerView // For custom implementations, use manual logging methods: // Log impression Braze.getInstance(context).logBannerImpression("sample_placement_id"); // Log click (with optional buttonId) Braze.getInstance(context).logBannerClick("sample_placement_id", buttonId); ``` **Important:** BannerUIViewを使用すると、分析は自動的にトラッキングされます。デフォルトのBannerUIViewでは手動でのログ記録は使用しないでください。 ```swift // Analytics are automatically tracked when using BannerUIView // Manual logging should not be used for default BannerUIView // For custom implementations, use manual logging methods: // Get banner for specific placement braze.banners.getBanner(for: "sample_placement_id") { banner in guard let banner = banner else { return } // Log impression banner.context?.logImpression() // Log click (with optional buttonId) banner.context?.logClick(buttonId: buttonId) } // Control groups are automatically handled by BannerUIView ``` **Important:** BrazeBannerViewを使用すると、分析は自動的にトラッキングされます。手動でのログ記録は不要です。 ```javascript // Analytics are automatically tracked when using BrazeBannerView // No manual logging required // Note: Manual logging methods for Banners are not yet supported in React Native // Control groups are automatically handled by BrazeBannerView ``` **Important:** BrazeBannerViewを使用すると、分析は自動的にトラッキングされます。手動でのログ記録は不要です。 ```dart // Analytics are automatically tracked when using BrazeBannerView // No manual logging required // Note: Manual logging methods for Banners are not yet supported in Flutter // Control groups are automatically handled by BrazeBannerView ``` ### プロパティの取得 {#getting-properties} #### Content Cards方式 ```javascript cards.forEach(card => { console.log("Card id:", card.id, "Extras:", card.extras); }); ``` ```kotlin cards.forEach { card -> Log.d(TAG, "Card id: ${card.id} Extras: ${card.extras}") } ``` ```swift for card in cards { print("Card id: \(card.id) Extras: \(card.extras)") } ``` ```javascript cards.forEach(card => { console.log("Card id:", card.id, "Extras:", card.extras); }); ``` ```dart for (final card in cards) { print("Card id: ${card.id} Extras: ${card.extras}"); } ``` #### バナー方式 ```javascript const banner = braze.getBanner("sample_placement_id"); if (!banner) { return; } console.log("Banner placement:", banner.placementId, "Properties:", banner.properties); ``` ```kotlin val banner = Braze.getInstance(context).getBanner("sample_placement_id") if (banner != null) { Log.d(TAG, "Banner placement: ${banner.placementId} Properties: ${banner.properties}") } ``` ```swift braze.banners.getBanner(for: "sample_placement_id") { banner in guard let banner = banner else { return } print("Banner placement: \(banner.placementId) Properties: \(banner.properties)") } ``` ```javascript const banner = await Braze.getBanner("sample_placement_id"); if (banner) { console.log("Banner placement:", banner.placementId, "Properties:", banner.properties); } ``` ```dart final banner = await braze.getBanner("sample_placement_id"); if (banner != null) { print("Banner placement: ${banner.placementId} Properties: ${banner.properties}"); } ``` ### コントロールグループの処理 {#handling-control-groups} #### Content Cards方式 ```javascript cards.forEach(card => { if (card.isControl) { // Logic for control cards ie. don't display but log analytics } else { // Logic for cards ie. render card } }); ``` ```kotlin cards.forEach { card -> if (card.isControl) { // Logic for control cards ie. don't display but log analytics } else { // Logic for cards ie. render card } } ``` ```swift for card in cards { if card.isControl { // Logic for control cards ie. don't display but log analytics } else { // Logic for cards ie. render card } } ``` ```javascript cards.forEach(card => { if (card.isControl) { // Logic for control cards ie. don't display but log analytics } else { // Logic for cards ie. render card } }); ``` ```dart for (final card in cards) { if (card.isControl) { // Logic for control cards ie. don't display but log analytics } else { // Logic for cards ie. render card } } ``` #### バナー方式 ```javascript braze.subscribeToBannersUpdates((banners) => { const banner = braze.getBanner("sample_placement_id"); if (!banner) { return; } const container = document.getElementById("global-banner-container"); // Always call insertBanner to track impression (including control) braze.insertBanner(banner, container); // Hide if control group if (banner.isControl) { container.style.display = "none"; } }); ``` ```kotlin // BannerView automatically handles control groups // No additional code needed val bannerView = BannerView(context).apply { placementId = "sample_placement_id" } ``` ```swift // BannerUIView automatically handles control groups // No additional code needed let bannerView = BrazeBannerUI.BannerUIView( placementId: "sample_placement_id", braze: braze ) ``` ```javascript // BrazeBannerView automatically handles control groups // No additional code needed ``` ```dart // BrazeBannerView automatically handles control groups // No additional code needed BrazeBannerView( placementId: "sample_placement_id", ) ``` ## 制限事項 {#limitations} Content Cardsからバナーへ移行する際は、以下の制限事項に注意してください: ### トリガーメッセージの移行 {#migrating-triggered-messages} バナーはスケジュールされた配信キャンペーンのみをサポートしています。以前APIトリガーまたはアクションベースで送信されていたメッセージを移行するには、セグメントベースのターゲティングに変換してください: - **例:** APIで「プロファイルを完了」カードをトリガーする代わりに、過去7日以内に登録したがプロファイルを完了していないユーザー向けのセグメントを作成します。 - **リアルタイム適格性:** ユーザーは、各リフレッシュ時にセグメントの所属に基づいて、バナーの表示対象となるか否かが即座に判定されます。 ### 機能の違い {#feature-differences} | 機能 | Content Cards | バナー | |---------|--------------|---------| | **コンテンツ構造** | | フィード内の複数カード | ✅ サポートされています | ✅ 複数の配置を作成でき、カルーセルのような実装を実現できます。各配置につき、バナーは1つだけ返されます。 | | 複数の配置 | N/A | ✅ 複数配置に対応しています | | カードの種類(クラシック、キャプション付き、画像のみ) | ✅ 複数の事前定義済みタイプ | ✅ 単一のHTMLベースのバナー(より柔軟性があります) | | **コンテンツ管理** | | ドラッグ&ドロップエディター | ❌ カスタマイズには開発者が必要です | ✅ マーケターはエンジニアリングなしで作成・更新できます | | カスタムHTML/CSS | ❌ カード構造に限定されます | ✅ HTML/CSSの完全サポート | | カスタマイズ用のキーと値のペア | ✅ 高度なカスタマイズに必要です | ✅ 高度なカスタマイズのための「プロパティ」と呼ばれる強い型付けのキーと値のペア | | **永続性と有効期限** | | カードの有効期限 | ✅ サポート対象(30日間制限あり) | ✅ サポート対象(有効期限なし) | | 真の永続性 | ❌ 最大30日間 | ✅ 無制限の永続性 | | **表示とターゲティング** | | フィードUI | ✅ デフォルトのフィードが利用可能です | ❌ 配置ベースのみ | | 状況に即した配置 | ❌ フィードベース | ✅ ネイティブ配置サポート | | 優先順位付け | ❌ カスタムロジックが必要です | ✅ ネイティブ優先順位付け | | **ユーザーインタラクション** | | 手動での解除 | ✅ サポートされています | ✅ サポートされています | | 解除後の再適格性 | ❌ カスタムフィルターまたはキャンペーンロジックが必要です | ✅ デフォルトの待機期間 | | 固定されたカード | ✅ サポートされています | N/A | | **分析** | | 自動分析(デフォルトUI) | ✅ サポートされています | ✅ サポートされています | | 優先順位ソート | ❌ サポートされていません | ✅ サポートされています | | **コンテンツの更新** | | Liquidテンプレート更新 | ❌ カードごとに送信時/起動時に1回のみ | ✅ リフレッシュのたびに更新されます | | 適格性の更新 | ❌ カードごとに送信時/起動時に1回のみ | ✅ セッションごとに更新されます | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="機能の違い" } ### 製品の制限事項 {#product-limitations} - 1つの配置につき最大25件のアクティブなメッセージです。 - リフレッシュリクエストごとに最大10個の配置IDまでです。これを超えるリクエストは切り捨てられます。 ### SDKの制限事項 {#sdk-limitations} - バナーは現在、.NET MAUI(Xamarin)、Cordova、Unity、Vega、TVプラットフォームではサポートされていません。 - 前提条件に記載されている最小SDKバージョンを使用していることを確認してください。 ## 関連記事 {#related-articles} - [バナーの配置](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements) - [チュートリアル:配置IDによるバナーの表示](https://www.braze.com/docs/ja/ja/developer_guide/banners/tutorial_displaying_banners) - [バナー分析](https://www.braze.com/docs/ja/ja/developer_guide/banners/analytics) - [バナーに関するよくある質問](https://www.braze.com/docs/ja/ja/developer_guide/banners/faq) # チュートリアル: プレースメントIDによるバナーの表示 Source: /docs/ja/developer_guide/banners/tutorial_displaying_banners/index.md # チュートリアル: プレースメントIDによるバナーの表示 {#tutorial-displaying-a-banner-by-placement-id} > このチュートリアルのサンプルコードに沿って、プレースメントIDを使用してバナーを表示します。詳細については、[バナー](https://www.braze.com/docs/ja/ja/developer_guide/banners)を参照してください。 ## Prerequisites Before you can start this tutorial, verify that your Braze SDK meets the minimum version requirements: ## Displaying banners for the Web SDK **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```js file=index.js import * as braze from "@braze/web-sdk"; braze.initialize("YOUR-API-KEY", { baseUrl: "YOUR-ENDPOINT", enableLogging: true, }); braze.subscribeToBannersUpdates((banners) => { // Get this placement's banner. If it's `null`, the user did not qualify for any banners. const globalBanner = braze.getBanner("global_banner"); if (!globalBanner) { return; } const container = document.getElementById("global-banner-container"); braze.insertBanner(globalBanner, container); if (globalBanner.isControl) { // Hide or collapse the container container.style.display = "none"; } }); braze.requestBannersRefresh(["global_banner", "navigation_square_banner"]); ``` ```html file=main.html
``` !!step lines-index.js=5 #### 1. Enable debugging (optional) To make troubleshooting easier while developing, consider enabling debugging. !!step lines-index.js=8-23 #### 2. Subscribe to Banner updates Use `subscribeToBannersUpdates()` to register a handler that runs whenever a Banner is updated. Inside the handler, call `braze.getBanner("global_banner")` to get the latest placement. !!step lines-index.js=15-22 #### 3. Insert the Banner and handle control groups Use `braze.insertBanner(banner, container)` to insert a Banner when it's returned. To ensure keep your layout clean, hide or collapse Banners that are apart of a control group (for example, when `isControl` is `true`). !!step lines-index.js=25 #### 4. Refresh your Banners After initializing the SDK, call `requestBannersRefresh(["global_banner", ...])` to ensure that Banners are refreshed at the start of each session. You can also call this function at any time to refresh Banner placements later. !!step lines-main.html=3 #### 5. Add a container for your Banner In your HTML, add a new `
` element and give it a short, Banner-related `id`, such as `global-banner-container`. Braze will use this `
` to insert your Banner into the page. ## Prerequisites Before you can start this tutorial, verify that your Braze SDK meets the minimum version requirements: ## Displaying banners for the Android SDK **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```kotlin file=MainApplication.kt import android.app.Application import android.util.Log import com.braze.Braze import com.braze.configuration.BrazeConfig import com.braze.support.BrazeLogger public class MainApplication : Application() { override fun onCreate() { super.onCreate() // Turn on verbose Braze logging BrazeLogger.logLevel = Log.VERBOSE // Configure Braze with your SDK key and endpoint val config = BrazeConfig.Builder() .setApiKey("YOUR-API-KEY") .setCustomEndpoint("YOUR-ENDPOINT") .build() Braze.configure(this, config) // Subscribe to Banner updates Braze.getInstance(this) .subscribeToBannersUpdates { update -> for (banner in update.banners) { Log.d("brazeBanners", "Received banner for placement: ${banner.placementId}") // Add any custom banner logic you'd like } } } } ``` ```kotlin file=MainActivity.kt import android.os.Bundle import androidx.activity.ComponentActivity class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Inflate the XML layout setContentView(R.layout.banners) // Refresh placements Braze.getInstance(this) .requestBannersRefresh( listOf("top-1") ) } } ``` ```xml file=banners.xml ``` !!step lines-MainApplication.kt=12 #### 1. Enable debugging (optional) To make troubleshooting easier while developing, consider enabling debugging. !!step lines-MainApplication.kt=21-28 #### 2. Subscribe to Banner updates Use `subscribeToBannersUpdates()` to register a handler that runs whenever a Banner is updated. !!step lines-MainActivity.kt=10-14 #### 3. Refresh your placements After initializing the Braze SDK, call `requestBannersRefresh(["PLACEMENT_ID"])` to fetch the latest Banner content for that placement. !!step lines-banners.xml=15-19 #### 4. Define `BannerView` in your `banners.xml` In `banners.xml`, declare a `` element with `app:placementId="PLACEMENT_ID"`. Braze will use this element to insert your Banner into your UI. ## Prerequisites Before you can start this tutorial, verify that your Braze SDK meets the minimum version requirements: ## Displaying banners for the Swift SDK **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```swift file=AppDelegate.swift import UIKit import BrazeKit import BrazeUI class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Braze configuration with your SDK API key and endpoint let configuration = Braze.Configuration(apiKey: "YOUR-API-TOKEN", endpoint: "YOUR-ENDPOINT") configuration.logger.level = .debug // Initialize Braze SDK instance AppDelegate.braze = Braze(configuration: configuration) // Request a banners refresh AppDelegate.braze?.banners.requestBannersRefresh(placementIds: ["top-1"]) return true } } ``` ```swift file=SampleApp.swift import SwiftUI @main struct SampleApp: App { // Bind the AppDelegate into the SwiftUI lifecycle @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { ContentView() } } } ``` ```swift file=BannerViewController.swift import UIKit import BrazeKit import BrazeUI final class BannerViewController: UIViewController { static let bannerPlacementID = "top-1" var bannerHeightConstraints: NSLayoutConstraint? lazy var contentView: UILabel = { let contentView = UILabel() contentView.text = "Your Content Here" contentView.textAlignment = .center contentView.translatesAutoresizingMaskIntoConstraints = false return contentView }() lazy var bannerView: BrazeBannerUI.BannerUIView = { var bannerView = BrazeBannerUI.BannerUIView( placementId: BannerViewController.bannerPlacementID, braze: AppDelegate.braze!, processContentUpdates: { [weak self] result in // Update layout properties when banner content has finished loading. DispatchQueue.main.async { guard let self else { return } switch result { case .success(let updates): if let height = updates.height { self.bannerView.isHidden = false self.bannerHeightConstraint?.constant = min(height, 80) } case .failure(let error): return } } } ) bannerView.translatesAutoresizingMaskIntoConstraints = false bannerView.isHidden = true return bannerView }() override func viewDidLoad() { super.viewDidLoad() self.view.addSubview(contentView) self.view.addSubview(bannerView) bannerHeightConstraint = bannerView.heightAnchor.constraint(equalToConstant: 0) NSLayoutConstraint.activate([ contentView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor), contentView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor), bannerView.topAnchor.constraint(equalTo: self.contentView.bottomAnchor), bannerView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor), bannerView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor), bannerView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), bannerHeightConstraint!, ]) } } ``` !!step lines-AppDelegate.swift=14 #### 1. Enable debugging (optional) To make troubleshooting easier while developing, consider enabling debugging. !!step lines-AppDelegate.swift=20 #### 2. Refresh your placements After initializing the Braze SDK, `call requestBannersRefresh(placementIds: ["PLACEMENT_ID"])` to refresh Banner content at the start of each session. !!step lines-BannerViewController.swift=19-37 #### 3. Initialize the Banner and provide a callback Create a `BrazeBannerUI.BannerUIView` instance with your Braze object and placement ID, and provide a `processContentUpdates` callback to unhide the Banner and update its height constraint based on the provided content height. !!step lines-BannerViewController.swift=38-40 #### 4. Enable Auto Layout constraints Hide the Banner view by default, then disable autoresizing mask translation to enable Auto Layout constraints. !!step lines-BannerViewController.swift=43-58 #### 5. Anchor content and set height constraints Anchor your main content to the top using Auto Layout, and place the Banner view directly below it. Pin the Banner’s leading, trailing, and bottom edges to the safe area, and set an initial height constraint of `0` that will be updated when content loads. ```swift file=AppDelegate.swift import BrazeKit import BrazeUI class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Braze configuration with your SDK API key and endpoint let configuration = Braze.Configuration(apiKey: "YOUR-API-TOKEN", endpoint: "YOUR-ENDPOINT") configuration.logger.level = .debug // Initialize Braze SDK instance AppDelegate.braze = Braze(configuration: configuration) // Request a banners refresh AppDelegate.braze?.banners.requestBannersRefresh(placementIds: ["top-1"]) return true } } ``` ```swift file=SampleApp.swift import SwiftUI @main struct SampleApp: App { // Bind the AppDelegate into the SwiftUI lifecycle @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { BannerSwiftUIView() } } } ``` ```swift file=BannerSwiftUIView.swift import BrazeKit import BrazeUI import SwiftUI @available(iOS 13.0, *) struct BannerSwiftUIView: View { static let bannerPlacementID = "top-1" @State var hasBannerForPlacement: Bool = false @State var contentHeight: CGFloat = 0 var body: some View { VStack { Text("Your Content Here") .frame(maxWidth: .infinity, maxHeight: .infinity) if let braze = AppDelegate.braze, hasBannerForPlacement { BrazeBannerUI.BannerView( placementId: BannerSwiftUIView.bannerPlacementID, braze: braze, processContentUpdates: { result in switch result { case .success(let updates): if let height = updates.height { self.contentHeight = height } case .failure: return } } ) .frame(height: min(contentHeight, 80)) } }.onAppear { AppDelegate.braze?.banners.getBanner( for: BannerSwiftUIView.bannerPlacementID, { banner in hasBannerForPlacement = banner != nil } ) } } } ``` !!step lines-AppDelegate.swift=13 #### 1. Enable debugging (optional) To make troubleshooting easier while developing, consider enabling debugging. !!step lines-AppDelegate.swift=19 #### 2. Refresh your placements After initializing the Braze SDK, call `requestBannersRefresh(placementIds: ["PLACEMENT_ID"])` to refresh Banner content at the start of each session. !!step lines-BannerSwiftUIView.swift=1-46 #### 3. Create a view component Create a reusable SwiftUI view component that displays available Banners and contains your main app content if needed. !!step lines-BannerSwiftUIView.swift=36-43 #### 4. Only display available Banners Only attempt to show `BrazeBannerUI.BannerView` if the SDK is initialized and Banner content exists for that user. In `.onAppear`, call `getBanner(for:placementID)` to set the state of `hasBannerForPlacement`. !!step lines-BannerSwiftUIView.swift=17-32 #### 5. Only show `BannerView` after it loads To avoid blank space in your UI, only show `BrazeBannerUI.BannerView` if a Banner is present and the SDK is initialized. !!step lines-BannerSwiftUIView.swift=23-32 #### 6. Dynamically update Banner height Use the `processContentUpdates` callback to fetch the Banner’s content height as soon as it loads. Update your SwiftUI state (`contentHeight`) and apply a `.frame(height:)` constraint using the provided height. !!step lines-BannerSwiftUIView.swift=34 #### 7. Limit the Banner height To ensure your Banner never exceeds the maximum height, apply a `.frame(height: min(contentHeight, 80))` modifier. This will keep your UI visually balanced regardless of the Banner's content. # バナー:よくある質問 Source: /docs/ja/developer_guide/banners/faq/index.md # Frequently asked questions > These are answers to frequently asked questions about Banners in Braze. For more general information, see [About Banners](). ## When do Banner updates appear for users? Banners are refreshed with their latest data whenever you call the refresh method—there's no need to resend or update your Banner campaign. ## How many placements can I request in a session? In a single refresh request, you can request a maximum of 10 placements. For each one you request, Braze will return the highest-priority Banner a user is eligible for. Additional requests will return an error. For more information, see [Placement requests](). ## How many Banner campaigns can be active simultaneously? Each workspace can support up to 200 active Banner campaigns. If this limit is reached, you'll need to [archive or deactivate](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/messaging_fundamentals/about_statuses/#changing-the-status) an existing campaign before creating a new one. ## For campaigns sharing a placement, which Banner is displayed first? If a user qualifies for multiple Banner campaigns that share the same placement, the Banner with the highest priority will be displayed. For more information, see [Banner priority](). ## Can I use Banners in my existing Content Card feed? Banners are different from Content Cards, meaning you can’t use Banners and Content Cards in the same feed. To replace existing Content Card feeds with Banners, you’ll need to [create placements in your app or website](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements/). ## Can Banners include video? The standard Banner composer supports images, text, and buttons. To include a video in a Banner, you could use a **Custom Code** block and render a video or embedded player in your app or website. ## Can I trigger a banner based on user actions? While Banners do not support [action-based delivery](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/campaigns/building_campaigns/delivery_types/triggered_delivery), you can target users based on their past actions using segmentation and priority. For example, to show a special Banner only to users who have completed a `purchase` event: 1. **Targeting:** In your campaign, target a segment of users who have performed the custom event `purchase` at least once. 2. **Priority:** If you have a general Banner for all users and this specific Banner for purchasers targeting the same placement, set the specific Banner's priority to **High** and the general Banner to **Medium** or **Low**. When the user starts a new session or refreshes Banners after performing the action, Braze evaluates their eligibility. If they match the "Purchase" segment, the high-priority Banner will be displayed. ## Can users dismiss a Banner? Yes. You can allow users to manually dismiss a Banner by turning on dismissal behavior in the Banner composer. See [Configure dismissal behavior](https://www.braze.com/docs/ja/ja/user_guide/channels/banners/create_a_banner/#dismiss-behavior) for details on turning on dismissal and customizing the dismiss button. Users can manually dismiss Banners only if dismissal behavior is enabled. If dismissal isn't enabled, you can control Banner visibility by managing user segment eligibility. When a user no longer meets the targeting criteria for a Banner campaign, they won't see it again on their next session. When a user dismisses a Banner, they're ineligible for that campaign by default. To let dismissed users see the Banner again, [configure re-eligibility](https://www.braze.com/docs/ja/ja/user_guide/channels/banners/create_a_banner/#re-eligibility) in the campaign's **Delivery Controls** step. Canvas Banner steps use Canvas re-entry settings to control re-eligibility instead. For example, if you display a promotional Banner until a user makes a purchase, logging an event such as `purchase_completed` can remove that user from the targeted segment, effectively hiding the Banner in subsequent sessions. ## Can I export Banners campaign analytics using the Braze API? Yes. You can use the [`/campaigns/data_series` endpoint](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaign_analytics/) to get data on how many Banner campaigns were viewed, clicked, or converted. ## When are users segmented? Users are segmented at the beginning of the session. If a campaign's targeted segments depend on custom attributes, custom events, or other targeting attributes, they must be present on the user at the beginning of the session. ## How can I compose Banners to ensure the lowest latency? The simpler the messaging in your Banner, the faster it will render. It’s best to test your Banner campaign against the expected latency for your use case. For example, be sure to test Liquid attributes like `catalog_items`. ## Are all Liquid tags supported? No. However, most Liquid tags are supported for Banner messages, except for `catalog_items` that are re-rendered using the [`:rerender` tag](https://www.braze.com/docs/ja/ja/user_guide/data/activation/catalogs/using_catalogs/#using-liquid). ## Can I capture click events? Yes. How click events are captured depends on how your Banner is rendered: - **Standard editor components:** If your Banner uses standard editor components (images, buttons, text), clicks are tracked automatically when using the SDK's insertion methods. - **Custom Code Blocks:** If you want to track clicks for elements within a Custom Code editor block, you must call `brazeBridge.logClick()` from within your custom HTML to track clicks. This applies even when using the SDK methods to insert and render the Banner. For the full reference, see [Custom code and JavaScript bridge for Banners](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/banners/custom_code/#javascript-bridge). - **Custom UI (headless):** If you're building a fully custom UI using the Banner's custom properties instead of rendering the Banner HTML, call `logClick()` on the Banner object from your application code. For more information, see [Logging clicks](https://www.braze.com/docs/ja/ja/developer_guide/banners/placements/#logging-clicks). # Braze SDKのコンテンツカード Source: /docs/ja/developer_guide/content_cards/index.md # コンテンツカードによって促進された > アプリケーションで使用できるさまざまなデータモデルやカード固有のプロパティなど、Braze SDK のコンテンツカードについて説明します。 **Tip:** Using Content Cards for banner-style messages? Try out [Banners](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/banners/)— perfect for inline, persistent in-app and web messages. **Note:** This guide uses code samples from the Braze Web SDK 4.0.0+. To upgrade to the latest Web SDK version, see [SDK Upgrade Guide](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md). ## Prerequisites Before you can use Content Cards, you'll need to [integrate the Braze Web SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web) into your app. However, no additional setup is required. To build your own UI instead, see [Content Card Customization Guide](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/). **Note:** Some ad blockers and browser privacy extensions can block the Braze Web SDK script or related network requests, which can prevent Content Cards from loading. If you're using the CDN integration method, consider switching to the [NPM integration method](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?subtab=package%20manager&sdktab=web), which stores SDK libraries locally on your website and can avoid some ad-blocker-related issues. ## Standard feed UI To use the included Content Cards UI, you'll need to specify where to show the feed on your website. In this example, we have a `
` in which we want to place the Content Cards feed. We'll use three buttons to hide, show, or toggle (hide or show based on its current state) the feed. ```html ``` When using the `toggleContentCards(parentNode, filterFunction)` and `showContentCards(parentNode, filterFunction)` methods, if no arguments are provided, all Content Cards will be shown in a fixed-position sidebar on the right-hand side of the page. Otherwise, the feed will be placed in the specified `parentNode` option. |Parameters | Description | |---|---| |`parentNode` | The HTML node to render the Content Cards into. If the parent node already has a Braze Content Cards view as a direct descendant, the existing Content Cards will be replaced. For example, you should pass in `document.querySelector(".my-container")`.| |`filterFunction` | A filter or sort function for cards displayed in this view. Invoked with the array of `Card` objects, sorted by `{pinned, date}`. Expected to return an array of sorted `Card` objects to render for this user. If omitted, all cards will be displayed. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Standard feed UI" } [See the SDK reference docs](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#togglecontentcards) for more information on Content Card toggling. ## Testing Content Cards on the web You can test your Content Cards integration using your browser's developer tools. 1. Create a Content Card campaign and target your test user. 2. Log in to the website that has your Web SDK integration. 3. Open your browser console. For Chrome, right-click the page, select **Inspect**, then select the **Console** tab. 4. Run these commands in the console: - `window.braze.getCachedContentCards()` - `window.braze.toggleContentCards()` ## Card types and properties The Content Cards data model is available in the Web SDK and offers the following Content Card types: [ImageOnly](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.imageonly.html), [CaptionedImage](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.captionedimage.html), and [ClassicCard](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.classiccard.html). Each type inherits common properties from a base model [Card](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.card.html) and has the following additional properties. **Tip:** To log Content Card data, see [Logging analytics](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/logging_analytics/). ### Base card model All Content Cards have these shared properties: |Property|Description| |---|---| | `expiresAt` | The UNIX timestamp of the card's expiration time.| | `extras`| (Optional) Key-value pair data formatted as a string object with a value string. | | `id` | (Optional) The id of the card. This will be reported back to Braze with events for analytics purposes. | | `pinned` | This property reflects if the card was set up as "pinned" in the dashboard.| | `updated` | The UNIX timestamp of when this card was last modified. | | `viewed` | This property reflects whether the user viewed the card or not.| | `isControl` | This property is `true` when a card is a "control" group within an A/B test.| {: .reset-td-br-1 .reset-td-br-2 aria-label="Base card model" } ### Image only [ImageOnly](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.imageonly.html) cards are clickable full-sized images. |Property|Description| |---|---| | `aspectRatio` | The aspect ratio of the card's image and serves as a hint before image loading completes. Note that the property may not be supplied in certain circumstances. | | `categories` | This property is purely for organization in your custom implementation; these categories can be set in the dashboard composer. | | `clicked` | This property indicates whether this card has ever been clicked on this device. | | `created` | The UNIX timestamp of the card's creation time from Braze. | | `dismissed` | This property indicates if this card has been dismissed. | | `dismissible` | This property reflects if the user can dismiss the card, removing it from view. | | `imageUrl` | The URL of the card's image.| | `linkText` | The display text for the URL. | | `url` | The URL that will be opened after the card is clicked on. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Image only" } ### Captioned image [CaptionedImage](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.captionedimage.html) cards are clickable, full-sized images with accompanying descriptive text. |Property|Description| |---|---| | `aspectRatio` | The aspect ratio of the card's image and serves as a hint before image loading completes. Note that the property may not be supplied in certain circumstances. | | `categories` | This property is purely for organization in your custom implementation; these categories can be set in the dashboard composer. | | `clicked` | This property indicates whether this card has ever been clicked on this device. | | `created` | The UNIX timestamp of the card's creation time from Braze. | | `dismissed` | This property indicates if this card has been dismissed. | | `dismissible` | This property reflects if the user can dismiss the card, removing it from view. | | `imageUrl` | The URL of the card's image.| | `linkText` | The display text for the URL. | | `title` | The title text for this card. | | `url` | The URL that will be opened after the card is clicked on. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Captioned image" } ### Classic The [ClassicCard](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.classiccard.html) model can contain an image with no text or a text with image. |Property|Description| |---|---| | `aspectRatio` | The aspect ratio of the card's image and serves as a hint before image loading completes. Note that the property may not be supplied in certain circumstances. | | `categories` | This property is purely for organization in your custom implementation; these categories can be set in the dashboard composer. | | `clicked` | This property indicates whether this card has ever been clicked on this device. | | `created` | The UNIX timestamp of the card's creation time from Braze. | | `description` | The body text for this card. | | `dismissed` | This property indicates if this card has been dismissed. | | `dismissible` | This property reflects if the user can dismiss the card, removing it from view. | | `imageUrl` | The URL of the card's image.| | `linkText` | The display text for the URL. | | `title` | The title text for this card. | | `url` | The URL that will be opened after the card is clicked on. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Classic" } ## Control group If you use the default Content Cards feed, impressions and clicks will be automatically tracked. If you use a custom integration for Content Cards, you need need [log impressions](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/logging_analytics/) when a Control Card would have been seen. As part of this effort, make sure to handle Control cards when logging impressions in an A/B test. These cards are blank, and while they aren’t seen by users, you should still log impressions in order to compare how they perform against non-Control cards. To determine if a Content Card is in the Control group for an A/B test, check the `card.isControl` property (Web SDK v4.5.0+) or check if the card is a `ControlCard` instance (`card instanceof braze.ControlCard`). ## Card methods ### Default feed methods Use these methods when displaying Content Cards using the Braze default feed UI: |Method | Description | |---|---| |[`showContentCards`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#showcontentcards)| Displays the default Content Cards feed. Renders cards into a provided `parentNode` HTML element, or as a fixed-position sidebar on the right side of the page if no element is given. Accepts an optional `filterFunction` to sort or filter cards before display. | |[`hideContentCards`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#hidecontentcards)| Hides the default Content Cards feed if it is currently showing. | |[`toggleContentCards`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#togglecontentcards)| Shows the default Content Cards feed if it is hidden, or hides it if it is visible. If you need to display multiple Content Card feeds simultaneously, use `showContentCards` and `hideContentCards` instead. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Default feed methods" } ### Custom feed methods Use these methods when building your own Content Card UI: |Method | Description | |---|---| |[`subscribeToContentCardsUpdates`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#subscribetocontentcardsupdates)| Registers a callback function that is invoked whenever Content Cards are updated for the current user, such as on session start. Use this as the primary way to receive card data for your custom feed. Must be called before `openSession()` to receive updates on the initial session. | |[`getCachedContentCards`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#getcachedcontentcards)| Returns all currently available cards from the most recent Content Cards refresh. Use this to immediately display cards on page load without waiting for a new server request, such as when the user returns to a page during an active session. | |[`requestContentCardsRefresh`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#requestcontentcardsrefresh)| Requests an immediate refresh of Content Cards from Braze servers. By default, cards refresh on session start and when the default feed is reopened. Use this to force a refresh at other times, such as after a specific user action. Be aware of [rate limits](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/customizing_cards/feed/#rate-limit). | |[`logContentCardImpressions`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logcontentcardimpressions)| Logs impression events for an array of cards. Call this when cards are rendered and visible to the user. Required for accurate campaign reporting when using a custom UI, as impressions are not tracked automatically outside the default feed. | |[`logContentCardClick`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logcontentcardclick)| Logs a click event for a single card. Call this when a user interacts with a card in your custom UI. Required for accurate campaign reporting, as clicks are not tracked automatically outside the default feed. | |[`handleBrazeAction`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#handlebrazeaction)| Processes a card's URL and executes the configured on-click action, including Braze actions (`brazeActions://` URLs) and standard URL navigation. Call this in your card click handler to ensure on-click behaviors configured in the Braze dashboard are executed. | |[`dismissCard`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.card.html#dismisscard)| Programmatically dismisses a card, removing it from the user's feed. Use this to allow users to dismiss cards in your custom UI. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Custom feed methods" } For more details, refer to the [SDK reference documentation](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html). ## Best practices ### Call methods in the correct order For custom feeds, Content Cards refresh only on session start if `subscribeToContentCardsUpdates()` is called before `openSession()`. Call your Braze methods in this order: ```javascript import * as braze from "@braze/web-sdk"; // Step 1: Initialize the SDK braze.initialize("YOUR-API-KEY", { baseUrl: "YOUR-SDK-ENDPOINT" }); // Step 2: Subscribe to card updates braze.subscribeToContentCardsUpdates((updates) => { const cards = updates.cards; renderCards(cards); }); // Step 3: Identify the user braze.changeUser("USER_ID"); // Step 4: Start the session braze.openSession(); ``` ### Use cached cards to persist content across page loads Because `subscribeToContentCardsUpdates()` invokes only its callback when there are new updates (such as on session start), cards can disappear from your custom feed if a user refreshes the page mid-session. To prevent this, use `getCachedContentCards()` to immediately render cards from the local cache, alongside your subscription for new updates: ```javascript import * as braze from "@braze/web-sdk"; function renderCards(cards) { const container = document.getElementById("content-cards"); container.textContent = ""; const displayedCards = []; cards.forEach(card => { if (card instanceof braze.ClassicCard || card instanceof braze.CaptionedImage) { const cardElement = document.createElement("div"); const h3 = document.createElement("h3"); h3.textContent = card.title || ""; cardElement.appendChild(h3); const p = document.createElement("p"); p.textContent = card.description || ""; cardElement.appendChild(p); if (card.imageUrl) { const img = document.createElement("img"); img.src = card.imageUrl; img.alt = card.title || ""; cardElement.appendChild(img); } if (card.url) { cardElement.addEventListener("click", () => { braze.logContentCardClick(card); braze.handleBrazeAction(card.url); }); } container.appendChild(cardElement); displayedCards.push(card); } }); if (displayedCards.length > 0) { braze.logContentCardImpressions(displayedCards); } } // Display cached cards immediately const cached = braze.getCachedContentCards(); if (cached && cached.cards.length > 0) { renderCards(cached.cards); } // Subscribe to future updates braze.subscribeToContentCardsUpdates((updates) => { renderCards(updates.cards); }); ``` ### Log analytics for custom feeds When using a custom UI, impressions, clicks, and dismissals are not tracked automatically. You must log each event manually: - **Impressions:** Call `logContentCardImpressions([card1, card2, ...])` with an array of card objects when cards become visible to the user. - **Clicks:** Call `logContentCardClick(card)` when a user interacts with a card. - **On-click behavior:** Call `handleBrazeAction(card.url)` to execute the card's configured on-click action (such as navigating to a URL or logging a custom event). **Warning:** The argument passed to `logContentCardClick()` must be an original Braze `Card` object. If you transform or reconstruct the card data (for example, by serializing and deserializing), clicks are not logged and you see the error: "card must be a Card object." ## Using Google Tag Manager Google Tag Manager works by injecting the [Braze CDN](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/initial_sdk_setup#install-cdn) (a version of our Web SDK) directly into your website code, which means that all SDK methods are available just as if you had integrated the SDK without Google Tag Manager, except when implementing Content Cards. ### Setting up Content Cards For a standard integration of the Content Card feed, you can use a **Custom HTML** tag in Google Tag Manager. Add the following to your Custom HTML tag, which will activate the standard Content Card feed: ```html ``` ![Tag Configuration in Google Tag Manager of a Custom HTML tag that shows the Content Card feed.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm_content_cards.png?0568575182a8f9fbe2e5acfd37f9a3c4) For more freedom over customizing the appearance of Content Cards and their feed, you can directly integrate Content Cards into your native website. There are two approaches you can take with this: using the standard feed UI or creating a custom feed UI. When implementing the [standard feed UI](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/content_cards/integration/#standard-feed-ui), Braze methods must have `window.` added to the start of the method. For example, `braze.showContentCards` should instead be `window.braze.showContentCards`. For [custom feed](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/creating_cards/) styling, the steps are the same as if you had integrated the SDK without GTM. For example, if you want to customize the width of the Content Card feed, you can paste the following into your CSS file: ```css body .ab-feed { width: 800px; } ``` ### Upgrading templates {#upgrading} To upgrade to the latest version of the Braze Web SDK, take the following three steps in your Google Tag Manager dashboard: 1. **Update tag template**
Go to the **Templates** page within your workspace. Here you should see an icon indicating an update is available.

![Templates page showing an update is available](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-update-available.png?f36c891c9e7be7f37f873e17517a827b)

Click that icon and after reviewing the change, click to **Accept Update**.

![A screen comparing the old and new tag templates with a button to "Accept Update"](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-accept-update.png?417cfc6f52f25fc1953509c10e637ed1)

2. **Update version number**
Once your tag template has been updated, edit the Braze Initialization Tag, and update the SDK version to the most recent `major.minor` version. For example, if the latest version is `4.1.2`, enter `4.1`. You can view a list of SDK versions in our [changelog](https://github.com/braze-inc/braze-web-sdk/blob/master/CHANGELOG.md).

![Braze Initialization Template with an input field to change the SDK Version](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-version-number.png?9487bc3d9318863f2899478c0265715f)

3. **QA and publish**
Verify the new SDK version is working using Google Tag Manager's [debugging tool](https://support.google.com/tagmanager/answer/6107056?hl=en) prior to publishing an update to your tag container. ### Troubleshooting {#troubleshooting} #### Enable tag debugging {#debugging} Each Braze tag template has an optional **GTM Tag Debugging** checkbox which can be used to log debug messages to your web page's JavaScript console. ![Google Tag Manager's Debug tool](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-tag-debugging.png?7389da92ab6dd818760e71b6f48dfbab) #### Enter debug mode Another way to help debug your Google Tag Manager integration is using Google's [Preview mode](https://support.google.com/tagmanager/answer/6107056) feature. This will help identify what values are being sent from your web page's data layer to each triggered Braze tag and will also explain which tags were or were not triggered. ![The Braze Initialization Tag summary page provides an overview of the tag, including information on which tags were triggered.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-debug-mode.png?f7a1f3c237c28bc521087754a40561f3) #### Verify tag sequencing for custom events {#tag-sequencing} If custom events or other actions aren't logging in Braze, a common cause is a race condition where an action tag (such as **Custom Event** or **Purchase**) fires before the **Braze Initialization** tag has completed. To fix this, configure [tag sequencing](https://support.google.com/tagmanager/answer/6238868) in GTM: 1. Open the action tag that isn't logging correctly. 2. Under **Advanced Settings** > **Tag Sequencing**, select **A tag that fires before \[this tag\]**. 3. Choose your **Braze Initialization** tag as the setup tag. This ensures the SDK is fully initialized before any action tags attempt to send data to Braze. #### Enable verbose logging To capture detailed logs for troubleshooting, you can enable verbose logging on your Google Tag Manager integration. These logs will appear in the **Console** tab of your browser's [developer tools](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools). In your Google Tag Manager integration, navigate to your Braze Initialization Tag and select **Enable Web SDK Logging**. ![The Braze Initialization Tag summary page with the option to Enable Web SDK Logging turned on.](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm_verbose_logging.png?c5d9946843f312420b2b6e00ea669647) [changelog]: https://github.com/braze-inc/braze-web-sdk/blob/master/CHANGELOG.md ## Prerequisites Before you can use Braze Content Cards, you'll need to integrate the [Braze Android SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android) into your app. However, no additional setup is required. ## Google fragments In Android, the Content Cards feed is implemented as a [fragment](https://developer.android.com/guide/components/fragments.html) available in the Braze Android UI project. The [`ContentCardsFragment`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards/-content-cards-fragment/index.html) class will automatically refresh and display the contents of the Content Cards and log usage analytics. The cards that can appear in a user's `ContentCards` are created on the Braze dashboard. To learn how to add a fragment to an activity, see [Google's fragments documentation](https://developer.android.com/guide/fragments#Adding). ## Card types and properties The Content Cards data model is available in the Android SDK and offers the following unique Content Card types. Each type shares a base model, which allows them to inherit common properties from the base model, in addition to having their own unique properties. For full reference documentation, see [`com.braze.models.cards`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/index.html). ### Base card model {#base-card-for-android} The [base card](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/index.html) model provides foundational behavior for all cards. |Property | Description | |---|---| |`getId()` | Returns the card's ID set by Braze.| |`getViewed()` | Returns a boolean reflects if the card is read or unread by the user.| |`getExtras()` | Returns a map of key-value extras for this card.| |`getCreated()` | Returns the unix timestamp of the card's creation time from Braze.| |`isPinned` | Returns a boolean that reflects whether the card is pinned.| |`getOpenUriInWebView()` | Returns a boolean that reflects whether Uris for this card should be opened
in the Braze WebView or not.| |`getExpiredAt()` | Gets the expiration date of the card.| |`isRemoved()` | Returns a boolean that reflects whether the end user has dismissed this card.| |`isDismissibleByUser()` | Returns a boolean that reflects whether the card is dismissible by the user.| |`isClicked()` | Returns a boolean that reflects the clicked state of this card.| |`isDismissed` | Returns a boolean that reflects whether the card has been dismissed. Set to `true` to mark the card as dismissed. If a card is already marked as dismissed, it cannot be marked as dismissed again.| |`isControl()` | Returns a boolean if this card is a control card and should not be rendered.| {: .reset-td-br-1 .reset-td-br-2 aria-label="Base card model #base-card-for-android" } ### Image only {#banner-image-card-for-android} [Image only cards](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-image-only-card/index.html) are clickable full-sized images. |Property | Description | |---|---| |`getImageUrl()` | Returns the URL of the card's image.| |`getUrl()` | Returns the URL that will be opened after the card is clicked. It can be a HTTP(s) URL or a protocol URL.| |`getDomain()` | Returns link text for the property URL.| {: .reset-td-br-1 .reset-td-br-2 aria-label="Image only #banner-image-card-for-android" } ### Captioned image {#captioned-image-card-for-android} [Captioned image cards](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-captioned-image-card/index.html) are clickable, full-sized images with accompanying descriptive text. |Property | Description | |---|---| |`getImageUrl()` | Returns the URL of the card's image.| |`getTitle()` | Returns the title text for the card.| |`getDescription()` | Returns the body text for the card.| |`getUrl()` | Returns the URL that will be opened after the card is clicked. It can be a HTTP(s) URL or a protocol URL.| |`getDomain()` | Returns the link text for the property URL. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Captioned image #captioned-image-card-for-android" } ### Classic {#text-Announcement-card-for-android} A classic card without an image included will result in a [text announcement card](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-text-announcement-card/index.html). If an image is included, you will receive a [short news card](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-short-news-card/index.html). |Property | Description | |---|---| |`getTitle()` | Returns the title text for the card. | |`getDescription()` | Returns the body text for the card. | |`getUrl()` | Returns the URL that will be opened after the card is clicked. It can be a HTTP(s) URL or a protocol URL. | |`getDomain()` | Returns the link text for the property URL. | |`getImageUrl()` | Returns the URL of the card's image, applies only to the classic Short News Card. | |`isDismissed` | Returns a boolean that reflects whether the card has been dismissed. Set to `true` to mark the card as dismissed. If a card is already marked as dismissed, it cannot be marked as dismissed again. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Classic #text-Announcement-card-for-android" } ## Card methods All [`Card`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/index.html) data model objects offer the following analytics methods for logging user events to Braze servers. |Method | Description | |---|---| |`logImpression()` | Manually log an impression to Braze for a particular card. | |`logClick()` | Manually log a click to Braze for a particular card. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Card methods" } ## Prerequisites Before you can use Content Cards, you'll need to integrate the [Braze Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift) into your app. However, no additional setup is required. ## View controller contexts The default Content Cards UI can be integrated from the `BrazeUI` library of the Braze SDK. Create the Content Cards view controller using the `braze` instance. If you wish to intercept and react to the Content Card UI lifecycle, implement [`BrazeContentCardUIViewControllerDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcarduiviewcontrollerdelegate) as the delegate for your `BrazeContentCardUI.ViewController`. **Note:** For more information about iOS view controller options, refer to the [Apple developer documentation](https://developer.apple.com/documentation/uikit/view_controllers/showing_and_hiding_view_controllers). The `BrazeUI` library of the Swift SDK provides two default view controller contexts: [navigation](#swift_navigation) or [modal](#swift_modal). This means you can integrate Content Cards in these contexts by adding a few lines of code to your app or site. Both views offer customization and styling options as described in the [customization guide](https://www.braze.com/docs/ja/ja/developer_guide/customization_guides/content_cards/customizing_styles/?tab=ios). You can also create a custom Content Card view controller instead of using the standard Braze one for even more customization options—refer to the [Content Cards UI tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/c2-contentcardsui/) for an example. **Important:** To handle control variant Content Cards in your custom UI, pass in your [`Braze.ContentCard.Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/control(_:)) object, then call the `logImpression` method as you would with any other Content Card type. The object will implicitly log a control impression to inform our analytics of when a user would have seen the control card. ### Navigation A navigation controller is a view controller that manages one or more child view controllers in a navigation interface. Here is an example of pushing a `BrazeContentCardUI.ViewController` instance into a navigation controller: ```swift func pushViewController() { guard let braze = AppDelegate.braze else { return } let contentCardsController = BrazeContentCardUI.ViewController(braze: braze) // Implement and set `BrazeContentCardUIViewControllerDelegate` if you wish to intercept click actions. contentCardsController.delegate = self self.navigationController?.pushViewController(contentCardsController, animated: true) } ``` ```objc - (void)pushViewController { BRZContentCardUIViewController *contentCardsController = [[BRZContentCardUIViewController alloc] initWithBraze:self.braze]; // Implement and set `BrazeContentCardUIViewControllerDelegate` if you wish to intercept click actions. [contentCardsController setDelegate:self]; [self.navigationController pushViewController:contentCardsController animated:YES]; } ``` ### Modal Use modal presentations to create temporary interruptions in your app’s workflow, such as prompting the user for important information. This model view has a navigation bar on top and a **Done** button on the side of the bar. Here is an example of pushing a `BrazeContentCard.ViewController` instance into a modal controller: ```swift func presentModalViewController() { guard let braze = AppDelegate.braze else { return } let contentCardsModal = BrazeContentCardUI.ModalViewController(braze: braze) // Implement and set `BrazeContentCardUIViewControllerDelegate` if you wish to intercept click actions. contentCardsModal.viewController.delegate = self self.navigationController?.present(contentCardsModal, animated: true, completion: nil) } ``` ```objc - (void)presentModalViewController { BRZContentCardUIModalViewController *contentCardsModal = [[BRZContentCardUIModalViewController alloc] initWithBraze:AppDelegate.braze]; // Implement and set `BrazeContentCardUIViewControllerDelegate` if you wish to intercept click actions. [contentCardsModal.viewController setDelegate:self]; [self.navigationController presentViewController:contentCardsModal animated:YES completion:nil]; } ``` For example usage of `BrazeUI` view controllers, check out the corresponding Content Cards UI samples in our [Examples app](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples). ## Base card model The Content Cards data model is available in the `BrazeKit` module of the Braze Swift SDK. This module contains the following Content Card types, which are an implementation of the `Braze.ContentCard` type. For a full list of Content Card properties and their usage, see [`ContentCard` class](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard). - Image only - Captioned image - Classic - Classic image - Control To access the Content Cards data model, call `contentCards.cards` on your `braze` instance. See [Logging analytics](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/logging_analytics/) for more information on subscribing to card data. **Note:** Keep in mind, `BrazeKit` offers an alternative [`ContentCardRaw`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcardraw) class for Objective-C compatibility. ## Card methods Each card is initialized with a `Context` object, which contains various methods for managing your card's state. Call these methods when you want to modify the corresponding state property on a particular card object. | Method | Description | |--------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------| | `card.context?.logImpression()` | Log the content card impression event. | | `card.context?.logClick()` | Log the content card click event. | | `card.context?.processClickAction()` | Process a given [`ClickAction`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/clickaction) input. | | `card.context?.logDismissed()` | Log the content card dismissed event. | | `card.context?.logError()` | Log an error related to the content card. | | `card.context?.loadImage()` | Load a given content card image from a URL. This method can be nil when the content card does not have an image. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Card methods" } For more details, refer to the [`Context` class documentation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcardraw/context-swift.class) ## Prerequisites Before you can use this feature, you'll need to [integrate the Cordova Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=cordova). ## Card Feeds The Braze SDK includes a default card feed. To show the default card feed, you can use the `launchContentCards()` method. This method handles all analytics tracking, dismissals, and rendering for a user's Content Cards. ## Content Cards You can use these additional methods to build a custom Content Cards Feed within your app: |Method | Description | |---|---| |`requestContentCardsRefresh()`|Sends a background request to request the latest Content Cards from the Braze SDK server.| |`getContentCardsFromServer(successCallback, errorCallback)`|Retrieves Content Cards from the Braze SDK. This will request the latest Content Cards from the server and return the list of cards upon completion.| |`getContentCardsFromCache(successCallback, errorCallback)`|Retrieves Content Cards from the Braze SDK. This will return the latest list of cards from the local cache, which was updated at the last refresh.| |`logContentCardClicked(cardId)`|Logs a click for the given Content Card ID.| |`logContentCardImpression(cardId)`|Logs an impression for the given Content Card ID.| |`logContentCardDismissed(cardId)`|Logs a dismissal for the given Content Card ID.| {: .reset-td-br-1 .reset-td-br-2 aria-label="Content Cards" } ## About Flutter Content Cards The Braze SDK includes a default card feed to get you started with Content Cards. To show the card feed, you can use the `braze.launchContentCards()` method. The default card feed included with the Braze SDK will handle all analytics tracking, dismissals, and rendering for a user's Content Cards. ## Prerequisites Before you can use this feature, you'll need to [integrate the Flutter Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=flutter). ## Card methods You can use these additional methods to build a custom Content Cards Feed within your app by using the following methods available on the [plugin public interface](https://github.com/braze-inc/braze-flutter-sdk/blob/master/lib/braze_plugin.dart): | Method | Description | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | `braze.requestContentCardsRefresh()` | Requests the latest Content Cards from the Braze SDK server. | | `braze.logContentCardClicked(contentCard)` | Logs a click for the given Content Card object. | | `braze.logContentCardImpression(contentCard)` | Logs an impression for the given Content Card object. | | `braze.logContentCardDismissed(contentCard)` | Logs a dismissal for the given Content Card object. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Card methods" } ## Receiving Content Card data To receive Content Card data in your Flutter app, the `BrazePlugin` supports sending Content Card data by using [Dart Streams](https://dart.dev/tutorials/language/streams). The `BrazeContentCard` [object](https://pub.dev/documentation/braze_plugin/latest/braze_plugin/BrazeContentCard-class.html) supports a subset of fields available in the native model objects, including `description`, `title`, `image`, `url`, `extras`, and more. ### Listen for Content Card data in the Dart layer To receive Content Card data in the Dart layer, use the code below to create a `StreamSubscription` and call `braze.subscribeToContentCards()`. Remember to `cancel()` the stream subscription when it is no longer needed. ```dart // Create stream subscription StreamSubscription contentCardsStreamSubscription; contentCardsStreamSubscription = braze.subscribeToContentCards((List contentCards) { // Handle Content Cards } // Cancel stream subscription contentCardsStreamSubscription.cancel(); ``` For an example, see [main.dart](https://github.com/braze-inc/braze-flutter-sdk/blob/master/example/lib/main.dart) in the Braze Flutter SDK sample application. ### Forward Content Card data from the native iOS layer Content Card data is automatically forwarded from both the Android and iOS native layers. No additional setup is required. If you're using Flutter SDK 17.1.0 or earlier, Content Card data forwarding from the iOS native layer requires manual setup. Your application likely contains a `contentCards.subscribeToUpdates` callback that calls `BrazePlugin.processContentCards(contentCards)`. To migrate to Flutter SDK 18.0.0, remove the `BrazePlugin.processContentCards(_:)` call—data forwarding is now handled automatically. For an example, see [AppDelegate.swift](https://github.com/braze-inc/braze-flutter-sdk/blob/master/example/ios/Runner/AppDelegate.swift) in the Braze Flutter SDK sample application. #### Replaying the callback for Content Cards To store any Content Cards triggered before the callback is available and replay them after it is set, add the following entry to the `customConfigs` map when initializing the `BrazePlugin`: ```dart BrazePlugin braze = new BrazePlugin(customConfigs: {replayCallbacksConfigKey: true}); ``` ## About React Native Content Cards The Braze SDKs include a default card feed to get you started with Content Cards. To show the card feed, you can use the `Braze.launchContentCards()` method. The default card feed included with the Braze SDK will handle all analytics tracking, dismissals, and rendering for a user's Content Cards. ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Cards methods To build your own UI, you can get a list of available cards, and listen for updates to cards: ```javascript // Set initial cards const [cards, setCards] = useState([]); // Listen for updates as a result of card refreshes, such as: // a new session, a manual refresh with `requestContentCardsRefresh()`, or after the timeout period Braze.addListener(Braze.Events.CONTENT_CARDS_UPDATED, async (update) => { setCards(update.cards); }); // Manually trigger a refresh of cards Braze.requestContentCardsRefresh(); ``` **Important:** If you choose to build your own UI to display cards, you must call `logContentCardImpression` in order to receive analytics for those cards. This includes `control` cards, which must be tracked even though they are not displayed to the user. You can use these additional methods to build a custom Content Cards Feed within your app: | Method | Description | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------ | | `launchContentCards()` | Launches the Content Cards UI element. | | `requestContentCardsRefresh()` | Requests the latest Content Cards from the Braze SDK server. The resulting list of cards is passed to each of the previously registered [content card event listeners](#reactnative_cards-methods). | | `getContentCards()` | Retrieves Content Cards from the Braze SDK. This returns a promise that resolves with the latest list of cards from the server. | | `getCachedContentCards()` | Returns the most recent Content Cards array from the cache. | | `logContentCardClicked(cardId)` | Logs a click for the given Content Card ID. This method is used only for analytics. To execute the click action, call `processContentCardClickAction(cardId)` in addition. | | `logContentCardImpression(cardId)` | Logs an impression for the given Content Card ID. | | `logContentCardDismissed(cardId)` | Logs a dismissal for the given Content Card ID. | | `processContentCardClickAction(cardId)` | Perform the action of a particular card. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Cards methods" } ## Card types and properties The Content Cards data model is available in the React Native SDK and offers the following Content Cards card types: [Image Only](#image-only), [Captioned Image](#captioned-image), and [Classic](#classic). There's also a special [Control](#control) card type, which is returned to users that are in the control group for a given card. Each type inherits common properties from a base model in addition to its own unique properties. **Tip:** For a full reference of the Content Card data model, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard) documentation. ### Base card model The base card model provides foundational behavior for all cards. |Property | Description | |--------------|------------------------------------------------------------------------------------------------------------------------| |`id` | The card's ID set by Braze. | |`created` | The UNIX timestamp of the card's creation time from Braze. | |`expiresAt` | The UNIX timestamp of the card's expiration time. When the value is less than 0, it means the card never expires. | |`viewed` | Whether the card is read or unread by the user. This does not log analytics. | |`clicked` | Whether the card has been clicked by the user. | |`pinned` | Whether the card is pinned. | |`dismissed` | Whether the user has dismissed this card. Marking a card as dismissed that has already been dismissed will be a no-op. | |`dismissible` | Whether the card is dismissible by the user. | |`url` | (Optional) The URL string associated with the card click action. | |`openURLInWebView` | Whether URLs for this card should be opened in the Braze WebView or not. | |`isControl` | Whether this card is a control card. Control cards should not be displayed to the user. | |`extras` | The map of key-value extras for this card. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Base card model" } For a full reference of the base card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/data-swift.struct) documentation. ### Image only Image only cards are clickable, full-sized images. |Property | Description | |-------------------|-------------------------------------------------------------------------------------------------------------------| |`type` | The Content Card type, `IMAGE_ONLY`. | |`image` | The URL of the card's image. | |`imageAspectRatio` | The aspect ratio of the card's image. It is meant to serve as a hint before image loading completes. Note that the property may not be supplied in certain circumstances. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Image only" } For a full reference of the image only card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-image-only-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/imageonly-swift.struct) documentation. ### Captioned image Captioned image cards are clickable, full-sized images with accompanying descriptive text. |Property | Description | |-------------------|-------------------------------------------------------------------------------------------------------------------| |`type` | The Content Card type, `CAPTIONED`. | |`image` | The URL of the card's image. | |`imageAspectRatio` | The aspect ratio of the card's image. It is meant to serve as a hint before image loading completes. Note that the property may not be supplied in certain circumstances. | |`title` | The title text for the card. | |`cardDescription` | The description text for the card. | |`domain` | (Optional) The link text for the property URL, for example, `"braze.com/resources/"`. It can be displayed on the card's UI to indicate the action/direction of clicking on the card. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Captioned image" } For a full reference of the captioned image card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-captioned-image-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/captionedimage-swift.struct) documentation. ### Classic Classic cards have a title, description, and an optional image on the left of the text. |Property | Description | |-------------------|-------------------------------------------------------------------------------------------------------------------| |`type` | The Content Card type, `CLASSIC`. | |`image` | (Optional) The URL of the card's image. | |`title` | The title text for the card. | |`cardDescription` | The description text for the card. | |`domain` | (Optional) The link text for the property URL, for example, `"braze.com/resources/"`. It can be displayed on the card's UI to indicate the action/direction of clicking on the card. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Classic" } For a full reference of the classic (text announcement) Content Card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-text-announcement-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/classic-swift.struct) documentation. For the classic image (short news) card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-short-news-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/classicimage-swift.struct) documentation. ### Control Control cards include all of the base properties, with a few important differences. Most importantly: - The `isControl` property is guaranteed to be `true`. - The `extras` property is guaranteed to be empty. For a full reference of the control card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-control-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/control-swift.struct) documentation. ## Prerequisites Before you can use Content Cards, you'll need to integrate the [Braze Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift) into your app. Then you'll need to complete the steps for setting up your tvOS app. **Important:** Keep in mind, you'll need to implement your own custom UI since Content Cards are supported via headless UI using the Swift SDK—which does not include any default UI or views for tvOS. ## Setting up your tvOS app ### Step 1: Create a new iOS app In Braze, select **Settings** > **App Settings**, then select **Add App**. Enter a name for your tvOS app, select **iOS**—_not tvOS_—then select **Add App**. ![ALT_TEXT.](https://www.braze.com/docs/ja/ja/assets/img/tvos.png?d1c5036d5b83f425591adb03556ca684){: style="width:70%"} **Warning:** If you select the **tvOS** checkbox, you will not be able to customize Content Cards for tvOS. ### Step 2: Get your app's API key In your app settings, select your new tvOS app then take note of your app's API key. You'll use this key to configure your app in Xcode. ![ALT_TEXT](https://www.braze.com/docs/ja/ja/assets/img/tvos1.png?9851deb799c1c88a248f97bd284c91cb){: style="width:70%"} ### Step 3: Integrate BrazeKit Use your app's API key to integrate the [Braze Swift SDK](https://github.com/braze-inc/braze-swift-sdk) into your tvOS project in Xcode. You only need to integrate BrazeKit from the Braze Swift SDK. ### Step 4: Create your custom UI Because Braze doesn't provide a default UI for content cards on tvOS, you'll need to customize it yourself. For a full walkthrough, see our step-by-step tutorial: [Customizing content cards for tvOS](https://braze-inc.github.io/braze-swift-sdk/documentation/braze/content-cards-customization/). For a sample project, see [Braze Swift SDK samples](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples#contentcards-custom-ui). ## Prerequisites Before you can use this feature, you'll need to [integrate the Unity Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=unity). ## Displaying Content Cards natively {#unity-content-cards-native-ui} You can display the default UI for Content Cards using the following call: ```csharp Appboy.AppboyBinding.DisplayContentCards(); ``` ## Receiving Content Card data in Unity You may register Unity game objects to be notified of incoming Content Cards. We recommend setting game object listeners from the Braze configuration editor. If you need to configure your game object listener at runtime, use `AppboyBinding.ConfigureListener()` and specify `BrazeUnityMessageType.CONTENT_CARDS_UPDATED`. Note, you will additionally need to make a call to `AppboyBinding.RequestContentCardsRefresh()` to start receiving data in your game object listener on iOS. ## Parsing Content Cards Incoming `string` messages received in your Content Cards game object callback can be parsed into our pre-supplied [`ContentCard`](https://github.com/braze-inc/braze-unity-sdk/blob/master/Assets/Plugins/Appboy/Models/Cards/ContentCard.cs) model object for convenience. Parsing Content Cards requires JSON parsing, see the following example for details: ##### Example Content Cards callback ```csharp void ExampleCallback(string message) { try { JSONClass json = (JSONClass)JSON.Parse(message); // Content Card data is contained in the `mContentCards` field of the top level object. if (json["mContentCards"] != null) { JSONArray jsonArray = (JSONArray)JSON.Parse(json["mContentCards"].ToString()); Debug.Log(String.Format("Parsed content cards array with {0} cards", jsonArray.Count)); // Iterate over the card array to parse individual cards. for (int i = 0; i < jsonArray.Count; i++) { JSONClass cardJson = jsonArray[i].AsObject; try { ContentCard card = new ContentCard(cardJson); Debug.Log(String.Format("Created card object for card: {0}", card)); // Example of logging Content Card analytics on the ContentCard object card.LogImpression(); card.LogClick(); } catch { Debug.Log(String.Format("Unable to create and log analytics for card {0}", cardJson)); } } } } catch { throw new ArgumentException("Could not parse content card JSON message."); } } ``` ## Refreshing Content Cards To refresh Content Cards from Braze, call either of the following methods: ```csharp // results in a network request to Braze AppboyBinding.RequestContentCardsRefresh() AppboyBinding.RequestContentCardsRefreshFromCache() ``` ## Analytics Clicks and impressions must be manually logged for Content Cards not displayed directly by Braze. Use `LogClick()` and `LogImpression()` on [ContentCard](https://github.com/braze-inc/braze-unity-sdk/blob/master/Assets/Plugins/Appboy/Models/Cards/ContentCard.cs) to log clicks and impressions for specific cards. ## About .NET MAUI Content Cards The Braze .NET MAUI (formerly Xamarin) SDK includes a default card feed to get you started with Content Cards. The default card feed included with the Braze SDK will handle all analytics tracking, dismissals, and rendering for a user’s Content Cards. ## Prerequisites Before you can use this feature, you'll need to [integrate the .NET MAUI Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=.net%20maui%20(xamarin)). ## Card types and properties The Braze .NET MAUI SDK has three unique Content Cards card types that share a base model: [Banner](#xamarin_banner), [Captioned Image](#xamarin_captioned-image), and [Classic](#xamarin_classic). Each type inherits common properties from a base model and has the following additional properties. ### Base card model |Property | Description | |-------------------|------------------------------------------------------------------------------------------------------------------------| |`idString` | The card's ID set by Braze. | |`created` | The UNIX timestamp of the card's creation time from Braze. | |`expiresAt` | The UNIX timestamp of the card's expiration time. When the value is less than 0, it means the card never expires. | |`viewed` | Whether the card is read or unread by the user. This does not log analytics. | |`clicked` | Whether the card has been clicked by the user. | |`pinned` | Whether the card is pinned. | |`dismissed` | Whether the user has dismissed this card. Marking a card as dismissed that has already been dismissed will be a no-op. | |`dismissible` | Whether the card is dismissible by the user. | |`urlString` | (Optional) The URL string associated with the card click action. | |`openUrlInWebView` | Whether URLs for this card should be opened in the Braze WebView or not. | |`isControlCard` | Whether this card is a control card. Control cards should not be displayed to the user. | |`extras` | The map of key-value extras for this card. | |`isTest` | Whether this card is a test card. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Base card model" } For a full reference of the base card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/data-swift.struct) documentation. ### Banner Banner cards are clickable, full-sized images. |Property | Description | |-------------------|-------------------------------------------------------------------------------------------------------------------| |`image` | The URL of the card's image. | |`imageAspectRatio` | The aspect ratio of the card's image. It is meant to serve as a hint before image loading completes. Note that the property may not be supplied in certain circumstances. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Banner" } For a full reference of the banner card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-image-only-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/imageonly-swift.struct) documentation (now renamed to image only). ### Captioned image Captioned image cards are clickable, full-sized images with accompanying descriptive text. |Property | Description | |-------------------|-------------------------------------------------------------------------------------------------------------------| |`image` | The URL of the card's image. | |`imageAspectRatio` | The aspect ratio of the card's image. It is meant to serve as a hint before image loading completes. Note that the property may not be supplied in certain circumstances. | |`title` | The title text for the card. | |`cardDescription` | The description text for the card. | |`domain` | (Optional) The link text for the property URL, for example, `"braze.com/resources/"`. It can be displayed on the card's UI to indicate the action/direction of clicking on the card. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Captioned image" } For a full reference of the captioned image card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-captioned-image-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/captionedimage-swift.struct) documentation. ### Classic Classic cards have a title, description, and an optional image on the left of the text. |Property | Description | |-------------------|-------------------------------------------------------------------------------------------------------------------| |`image` | (Optional) The URL of the card's image. | |`title` | The title text for the card. | |`cardDescription` | The description text for the card. | |`domain` | (Optional) The link text for the property URL, for example, `"braze.com/resources/"`. It can be displayed on the card's UI to indicate the action/direction of clicking on the card. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Classic" } For a full reference of the classic (text announcement) Content Card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-text-announcement-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/classic-swift.struct) documentation. For a full reference of the classic image (short news) card, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-short-news-card/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/classicimage-swift.struct) documentation. ## Card methods You can use these additional methods to build a custom Content Cards Feed within your app: | Method | Description | | ---------------------------------------- | ------------------------------------------------------------------------------------------------------ | | `requestContentCardsRefresh()` | Requests the latest Content Cards from the Braze SDK server. | | `getContentCards()` | Retrieves Content Cards from the Braze SDK. This will return the latest list of cards from the server. | | `logContentCardClicked(cardId)` | Logs a click for the given Content Card ID. This method is used only for analytics. | | `logContentCardImpression(cardId)` | Logs an impression for the given Content Card ID. | | `logContentCardDismissed(cardId)` | Logs a dismissal for the given Content Card ID. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Card methods" } # コンテンツカードを作成する Source: /docs/ja/developer_guide/content_cards/creating_cards/index.md # コンテンツカードを作成する {#create-content-cards} > この記事では、カスタムコンテンツカードを実装するときに使用する基本的なアプローチと、3つの一般的なユースケースについて説明します。Content Cardsカスタマイズガイドの他の記事をすでに読んで、デフォルトでできることとカスタムコードが必要なことを理解していることを前提としています。特に、カスタムコンテンツカードの[分析を記録](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/logging_analytics)する方法を理解しておくと役立ちます。 **Tip:** Using Content Cards for banner-style messages? Try out [Banners](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/banners/)— perfect for inline, persistent in-app and web messages. ## カードを作成する {#creating-a-card} ### ステップ 1:カスタム UI を作成する {#step-1-create-a-custom-ui} まず、カードのレンダリングに使用するカスタム HTML コンポーネントを作成します。 まず、独自のカスタムフラグメントを作成します。デフォルトの [`ContentCardsFragment`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards/-content-cards-fragment/index.html) は、デフォルトのコンテンツカードタイプのみに対応するよう設計されていますが、良い出発点になります。 まず、独自のカスタムビューコントローラーコンポーネントを作成します。デフォルトの [`BrazeContentCardUI.ViewController`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller) は、デフォルトのコンテンツカードタイプのみに対応するよう設計されていますが、良い出発点になります。 ### ステップ 2:カードの更新を購読する {#step-2-subscribe-to-card-updates} カードが更新されたときにデータ更新を受け取るためのコールバック関数を登録します。コンテンツカードオブジェクトを解析し、`title`、`cardDescription`、`imageUrl` などのペイロードデータを抽出して、結果のモデルデータを使用してカスタム UI を表示できます。 コンテンツカードのデータモデルを取得するには、コンテンツカードの更新を購読します。特に以下のプロパティに注意してください。 * **`id`:** コンテンツカードの ID 文字列を表します。カスタムコンテンツカードから分析を記録するために使用される一意の識別子です。 * **`extras`:** Brazeダッシュボードからのすべてのキーと値のペアを含みます。 `id` と `extras` 以外のすべてのプロパティは、カスタムコンテンツカードでは解析がオプションです。データモデルの詳細については、各プラットフォームの統合記事を参照してください: [Android](https://www.braze.com/docs/ja/ja/developer_guide/content_cards?sdktab=android)、[iOS](https://www.braze.com/docs/ja/ja/developer_guide/content_cards?sdktab=swift)、[Web](https://www.braze.com/docs/ja/ja/developer_guide/content_cards?sdktab=web)。 ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToContentCardsUpdates((updates) => { const cards = updates.cards; // For example: cards.forEach(card => { if (card.isControl) { // Do not display the control card, but remember to call `logContentCardImpressions([card])` } else if (card instanceof braze.ClassicCard || card instanceof braze.CaptionedImage) { // Use `card.title`, `card.imageUrl`, etc. } else if (card instanceof braze.ImageOnly) { // Use `card.imageUrl`, etc. } }) }); braze.openSession(); ``` **Note:** Content Cardsは、`openSession()` の前に `subscribeToContentCardsUpdates()` が呼び出された場合にのみ、セッション開始時に更新されます。いつでも[フィードを手動で更新](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/customizing_cards/feed)することもできます。 #### ステップ 2a:プライベートサブスクライバー変数を作成する {#step-2a-create-a-private-subscriber-variable} カードの更新を購読するには、まずカスタムクラスでサブスクライバーを保持するプライベート変数を宣言します。 ```java // subscriber variable private IEventSubscriber mContentCardsUpdatedSubscriber; ``` #### ステップ 2b:更新を購読する {#step-2b-subscribe-to-updates} 以下のコードを追加して、Brazeからのコンテンツカードの更新を購読します。通常、カスタムコンテンツカードアクティビティの `Activity.onCreate()` 内に配置します。 ```java // Remove the previous subscriber before rebuilding a new one with our new activity. Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class); mContentCardsUpdatedSubscriber = new IEventSubscriber() { @Override public void trigger(ContentCardsUpdatedEvent event) { // List of all Content Cards List allCards = event.getAllCards(); // Your logic below } }; Braze.getInstance(context).subscribeToContentCardsUpdates(mContentCardsUpdatedSubscriber); Braze.getInstance(context).requestContentCardsRefresh(); ``` #### ステップ 2c:購読を解除する {#step-2c-unsubscribe} カスタムアクティビティが画面外に移動したときに購読を解除します。以下のコードをアクティビティの `onDestroy()` ライフサイクルメソッドに追加します。 ```java Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class); ``` #### ステップ 2a:プライベートサブスクライバー変数を作成する カードの更新を購読するには、まずカスタムクラスでサブスクライバーを保持するプライベート変数を宣言します。 ```kotlin private var contentCardsUpdatedSubscriber: IEventSubscriber? = null ``` #### ステップ 2b:更新を購読する 以下のコードを追加して、Brazeからのコンテンツカードの更新を購読します。通常、カスタムコンテンツカードアクティビティの `Activity.onCreate()` 内に配置します。 ```kotlin // Remove the previous subscriber before rebuilding a new one with our new activity. Braze.getInstance(context).subscribeToContentCardsUpdates(contentCardsUpdatedSubscriber) Braze.getInstance(context).requestContentCardsRefresh() // List of all Content Cards val allCards = event.allCards // Your logic below } Braze.getInstance(context).subscribeToContentCardsUpdates(mContentCardsUpdatedSubscriber) Braze.getInstance(context).requestContentCardsRefresh(true) ``` #### ステップ 2c:購読を解除する カスタムアクティビティが画面外に移動したときに購読を解除します。以下のコードをアクティビティの `onDestroy()` ライフサイクルメソッドに追加します。 ```kotlin Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java) ``` コンテンツカードのデータモデルにアクセスするには、`braze` インスタンスで [`contentCards.cards`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class/cards) を呼び出します。 ```swift let cards: [Braze.ContentCard] = AppDelegate.braze?.contentCards.cards ``` さらに、コンテンツカードの変更を監視するサブスクリプションを維持できます。以下の2つの方法があります。 1. キャンセル可能オブジェクトを維持する方法 2. `AsyncStream` を維持する方法 ##### キャンセル可能オブジェクト {#cancellable} ```swift // This subscription is maintained through a Braze cancellable, which will observe for changes until the subscription is cancelled. // You must keep a strong reference to the cancellable to keep the subscription active. // The subscription is canceled either when the cancellable is deinitialized or when you call its `.cancel()` method. let cancellable = AppDelegate.braze?.contentCards.subscribeToUpdates { [weak self] contentCards in // Implement your completion handler to respond to updates in `contentCards`. } ``` ##### AsyncStream ```swift let stream: AsyncStream<[Braze.ContentCard]> = AppDelegate.braze?.contentCards.cardsStream ``` ```objc NSArray *contentCards = AppDelegate.braze.contentCards.cards; ``` さらに、コンテンツカードのサブスクリプションを維持したい場合は、[`subscribeToUpdates`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class/subscribetoupdates(_:)) を呼び出すことができます。 ```objc // This subscription is maintained through Braze cancellable, which will continue to observe for changes until the subscription is cancelled. BRZCancellable *cancellable = [self.braze.contentCards subscribeToUpdates:^(NSArray *contentCards) { // Implement your completion handler to respond to updates in `contentCards`. }]; ``` ### ステップ 3:分析を実装する {#step-3-implement-analytics} コンテンツカードのインプレッション、クリック、却下は、カスタムビューでは自動的に記録されません。すべての指標がBrazeダッシュボードの分析に適切に記録されるように、[それぞれのメソッドを実装](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/logging_analytics)する必要があります。 ### ステップ 4:カードをテストする(オプション) {#step-4-test-your-card-optional} コンテンツカードをテストするには: 1. [`changeUser()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#changeuser) メソッドを呼び出して、アプリケーションでアクティブユーザーを設定します。 2. Brazeで**キャンペーン**に移動し、[新しいContent Cardsキャンペーンを作成します](https://www.braze.com/docs/ja/ja/user_guide/channels/content_cards/create_a_content_card)。 3. キャンペーンで**Test**を選択し、テストユーザーの `user-id` を入力します。準備ができたら、**Send Test**を選択します。すぐにデバイスでコンテンツカードを起動できます。 ![BrazeのContent Cardsキャンペーンでは、自分のユーザー IDをテスト受信者として追加し、コンテンツカードをテストすることができます。](https://www.braze.com/docs/ja/ja/assets/img/react-native/content-card-test.png?f0066f72bf53ec72ed55c34856064ac6 "Content Card キャンペーン Test") ## コンテンツカードの配置 {#content-card-placements} Content Cardsはさまざまな方法で使用できます。3つの一般的な実装は、メッセージセンター、ダイナミックな画像広告、または画像カルーセルとして使用することです。これらの配置ごとに、[キーと値のペア](https://www.braze.com/docs/ja/ja/developer_guide/customization_guides/content_cards/customizing_behavior#key-value-pairs)(データモデルの `extras` プロパティ)をContent Cardsに割り当て、その値に基づいて、ランタイム時にカードの動作、外観、または機能をダイナミックに調整します。 ![3つのContent Cards配置例(メッセージ受信トレイ、ダイナミック画像広告、画像カルーセル)を示す図。](https://www.braze.com/docs/ja/ja/assets/img_archive/cc_placements.png?1d164a98534752857c2faae74733bb03){: style="border:0px;"} ### メッセージ受信トレイ {#message-inbox} Content Cardsを使用してメッセージセンターをシミュレーションできます。この形式では、各メッセージはクリック時のイベントを動作させる[キーと値のペア](https://www.braze.com/docs/ja/ja/developer_guide/customization_guides/content_cards/customizing_behavior#key-value-pairs)を含む独自のカードです。これらのキーと値のペアは、ユーザーが受信トレイのメッセージをクリックしたときに、アプリケーションが遷移先を決定する際に参照する重要な識別子です。キーと値のペアの値は任意です。 #### 例 {#example} たとえば、ユーザーにおすすめの読書の有効化を促すコールトゥアクションと、新しいサブスクライバーセグメントに付与されるクーポンコードという2つのメッセージカードを作成できます。 `body`、`title`、`buttonText` などのキーは、マーケターが設定できるシンプルな文字列値を持つ場合があります。`terms` のようなキーは、法務部門が承認したフレーズの小さなコレクションを提供する値を持つ場合があります。`style` や `class_type` などのキーには、アプリやサイトでのカードのレンダリング方法を決定するために設定できる文字列値があります。 おすすめの読書カードのキーと値のペア: | キー | 値 | |------------|----------------------------------------------------------------------| | `body` | Politer Weeklyのプロファイルに興味のある内容を追加して、パーソナルなおすすめを受け取りましょう。 | | `style` | info | | `class_type` | notification_center | | `card_priority` | 1 | {: .reset-td-br-1 .reset-td-br-2 aria-label="例" } 新しいサブスクライバークーポンのキーと値のペア: | キー | 値 | |------------|------------------------------------------------------------------| | `title` | 無制限のゲームに登録する | | `body` | 夏の終わりスペシャル - Politerゲームが10%オフ | | `buttonText` | 今すぐ購読する | | `style` | promo | | `class_type` | notification_center | | `card_priority` | 2 | | `terms` | new_subscribers_only | {: .reset-td-br-1 .reset-td-br-2 aria-label="例" } **Androidの追加情報** AndroidとFireOS SDKでは、メッセージセンターのロジックはBrazeのキーと値のペアが提供する `class_type` 値によって駆動されます。[`createContentCardable`](https://www.braze.com/docs/ja/ja/developer_guide/content_cards) メソッドを使用すると、これらのクラスタイプをフィルタリングして識別できます。 **クリック時の動作に `class_type` を使用する**
コンテンツカードのデータをカスタムクラスにインフレートするときに、データの `ContentCardClass` プロパティを使用して、データの格納に使用する具象サブクラスを決定します。 ```kotlin private fun createContentCardable(metadata: Map, type: ContentCardClass?): ContentCardable?{ return when(type){ ContentCardClass.AD -> Ad(metadata) ContentCardClass.MESSAGE_WEB_VIEW -> WebViewMessage(metadata) ContentCardClass.NOTIFICATION_CENTER -> FullPageMessage(metadata) ContentCardClass.ITEM_GROUP -> Group(metadata) ContentCardClass.ITEM_TILE -> Tile(metadata) ContentCardClass.COUPON -> Coupon(metadata) else -> null } } ``` 次に、メッセージリストに対するユーザーの操作を処理するときに、メッセージのタイプを使用して、ユーザーに表示するビューを決定できます。 ```kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //... listView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id -> when (val card = dataProvider[position]){ is WebViewMessage -> { val intent = Intent(this, WebViewActivity::class.java) val bundle = Bundle() bundle.putString(WebViewActivity.INTENT_PAYLOAD, card.contentString) intent.putExtras(bundle) startActivity(intent) } is FullPageMessage -> { val intent = Intent(this, FullPageContentCard::class.java) val bundle = Bundle() bundle.putString(FullPageContentCard.CONTENT_CARD_IMAGE, card.icon) bundle.putString(FullPageContentCard.CONTENT_CARD_TITLE, card.messageTitle) bundle.putString(FullPageContentCard.CONTENT_CARD_DESCRIPTION, card.cardDescription) intent.putExtras(bundle) startActivity(intent) } } } } ``` **クリック時の動作に `class_type` を使用する**
コンテンツカードのデータをカスタムクラスにインフレートするときに、データの `ContentCardClass` プロパティを使用して、データの格納に使用する具象サブクラスを決定します。 ```java private ContentCardable createContentCardable(Map metadata, ContentCardClass type){ switch(type){ case ContentCardClass.AD:{ return new Ad(metadata); } case ContentCardClass.MESSAGE_WEB_VIEW:{ return new WebViewMessage(metadata); } case ContentCardClass.NOTIFICATION_CENTER:{ return new FullPageMessage(metadata); } case ContentCardClass.ITEM_GROUP:{ return new Group(metadata); } case ContentCardClass.ITEM_TILE:{ return new Tile(metadata); } case ContentCardClass.COUPON:{ return new Coupon(metadata); } default:{ return null; } } } ``` 次に、メッセージリストに対するユーザーの操作を処理するときに、メッセージのタイプを使用して、ユーザーに表示するビューを決定できます。 ```java @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState) //... listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id){ ContentCardable card = dataProvider.get(position); if (card instanceof WebViewMessage){ Bundle intent = new Intent(this, WebViewActivity.class); Bundle bundle = new Bundle(); bundle.putString(WebViewActivity.INTENT_PAYLOAD, card.getContentString()); intent.putExtras(bundle); startActivity(intent); } else if (card instanceof FullPageMessage){ Intent intent = new Intent(this, FullPageContentCard.class); Bundle bundle = Bundle(); bundle.putString(FullPageContentCard.CONTENT_CARD_IMAGE, card.getIcon()); bundle.putString(FullPageContentCard.CONTENT_CARD_TITLE, card.getMessageTitle()); bundle.putString(FullPageContentCard.CONTENT_CARD_DESCRIPTION, card.getCardDescription()); intent.putExtras(bundle) startActivity(intent) } } }); } ``` ### カルーセル {#carousel} フルカスタムのカルーセルフィードにContent Cardsを設定して、ユーザーがスワイプして追加の注目カードを表示できるようにすることができます。デフォルトでは、Content Cardsは作成日順(最新のものが先頭)でソートされ、ユーザーには対象となるすべてのカードが表示されます。 Content Cardsカルーセルを実装するには: 1. [Content Cardsの変更](https://www.braze.com/docs/ja/ja/developer_guide/customization_guides/content_cards/customizing_feed#refreshing-the-feed)を監視し、Content Cardsの到着を処理するカスタムロジックを作成します。 2. カスタムのクライアント側ロジックを作成して、カルーセルに一度に表示するカードの数を指定します。たとえば、配列から最初の5つのContent Cardsオブジェクトを選択したり、キーと値のペアを導入して条件付きロジックを構築したりできます。 **Tip:** カルーセルをセカンダリContent Cardsフィードとして実装する場合は、[キーと値のペアを使用してカードを正しいフィードにソート](https://www.braze.com/docs/ja/ja/developer_guide/customization_guides/content_cards/customizing_feed#multiple-feeds)してください。 ### 画像のみ {#image-only} Content Cardsは「カード」のように見せる必要はありません。たとえば、Content Cardsは、ホームページや指定されたページの上部に永続的に表示されるダイナミックな画像として表示できます。 これを実現するには、マーケターが**Image Only**タイプのContent Cardsでキャンペーンまたはキャンバスステップを作成します。次に、[Content Cardsを補足コンテンツとして](https://www.braze.com/docs/ja/ja/developer_guide/customization_guides/content_cards/customizing_behavior#content-cards-as-supplemental-content)使用するのに適したキーと値のペアを設定します。 # カードをカスタマイズする Source: /docs/ja/developer_guide/content_cards/customizing_cards/index.md **Tip:** Using Content Cards for banner-style messages? Try out [Banners](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/banners/)— perfect for inline, persistent in-app and web messages. # Content Cardsのスタイルをカスタマイズする Source: /docs/ja/developer_guide/content_cards/customizing_cards/style/index.md # Content Cardsのスタイルをカスタマイズする {#customize-the-style-of-content-cards} > Braze Content Cardsには、デフォルトのルックアンドフィールが含まれています。この記事では、ブランドアイデンティティに合わせるためのContent Cardsのスタイルオプションについて説明します。コンテンツカードタイプの完全なリストについては、[Content Cardsについて](https://www.braze.com/docs/ja/ja/developer_guide/content_cards)を参照してください。 ## カスタムスタイルの作成 {#creating-a-custom-style} デフォルトのContent Cards UIは、Braze SDKのUIレイヤーからインポートされます。そこから、カードのスタイルの特定の部分、カードが表示される順序、フィードがユーザーに表示される方法を調整できます。 ![2枚のコンテンツカード。1枚はデフォルトのフォントで角が四角いもの、もう1枚は角が丸くカーリーフォントのもの](https://www.braze.com/docs/ja/ja/assets/img/content_cards/content-card-customization-attributes.png?7b3bf29220daf2c82bb590aa371309d1) **Note:** Content Cardsのプロパティ(`title`、`cardDescription`、`imageUrl` など)は、[ダッシュボード](https://www.braze.com/docs/ja/ja/user_guide/channels/content_cards/creative_details)から直接編集できます。これは、詳細を変更するための推奨される方法です。 Brazeのデフォルトスタイルは、Braze SDK内のCSSで定義されています。アプリケーションで選択したスタイルをオーバーライドすることで、標準フィードを独自の背景画像、フォントファミリー、スタイル、サイズ、アニメーションなどでカスタマイズできます。例えば、以下のオーバーライドはContent Cardsを幅800ピクセルで表示させる例です。 ``` css body .ab-feed { width: 800px; } ``` 変更可能なプロパティの完全な一覧については、[BrazeのSDK設定オプション](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html)を参照してください。 デフォルトでは、AndroidおよびFireOS SDKのContent Cardsは標準のAndroid UIガイドラインに準拠し、シームレスなエクスペリエンスを提供します。これらのデフォルトのスタイルは、Braze SDKディストリビューション内の[`res/values/styles.xml`](https://github.com/braze-inc/braze-android-sdk/blob/master/android-sdk-ui/src/main/res/values/styles.xml)ファイルで確認できます。 ```xml ``` Content Cardsのスタイルをカスタマイズするには、このデフォルトのスタイルをオーバーライドします。スタイルをオーバーライドするには、スタイル全体をプロジェクトの`styles.xml`ファイルにコピーし、変更を加えます。すべての属性が正しく設定されるようにするには、スタイル全体をローカルの`styles.xml`ファイルにコピーする必要があります。 ```xml ``` ```xml ``` デフォルトでは、AndroidおよびFireOS SDKのContent Cardsは標準のAndroid UIガイドラインに準拠し、シームレスなエクスペリエンスを提供します。 2つの方法のいずれかでスタイルを適用できます。1つ目は、以下の例のように、[`ContentCardListStyling`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-list-styling/index.html)および[`ContentCardStyling`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-styling/index.html)を[`ContentCardsList`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards/-content-cards-list.html)に渡す方法です。 ```kotlin ContentCardsList( style = ContentCardListStyling(listBackgroundColor = Color.Red), cardStyle = ContentCardStyling( titleTextStyle = TextStyle( fontFamily = fontFamily, fontSize = 25.sp ), shadowRadius = 10.dp, shortNewsContentCardStyle = BrazeShortNewsContentCardStyling( shadowRadius = 15.dp ) ) ) ``` 2つ目は、以下の例のように、[`BrazeStyle`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose/-braze-style.html)を使用してBrazeコンポーネントのグローバルスタイルを作成する方法です。 ```kotlin BrazeStyle( contentCardStyle = ContentCardStyling( textAnnouncementContentCardStyle = BrazeTextAnnouncementContentCardStyling( cardBackgroundColor = Color.Red, descriptionTextStyle = TextStyle( fontFamily = fontFamily, fontSize = 25.sp, ) ), titleTextColor = Color.Magenta ) ) { // Your app here, including any ContentCardsList() in it } ``` Content Cardsビューコントローラーを使用すると、[`BrazeContentCardUI.ViewController.Attributes`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/attributes-swift.struct)構造体を介してすべてのセルの外観と動作をカスタマイズできます。`Attributes`を使用したContent Cardsの設定は簡単なオプションであり、最小限のセットアップでContent Cards UIを起動できます。 **Important:** `Attributes`によるカスタマイズは、Swiftでのみ利用可能です。 **`Attributes.default`の変更** 静的[`Attributes.defaults`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/attributes-swift.struct/defaults)変数を直接変更して、Braze Content Cards UIビューコントローラーのすべてのインスタンスのルックアンドフィールをカスタマイズします。 たとえば、すべてのセルのデフォルトの画像サイズと角の半径を変更するには、次のようにします。 ```swift BrazeContentCardUI.ViewController.Attributes.defaults.cellAttributes.cornerRadius = 20 BrazeContentCardUI.ViewController.Attributes.defaults.cellAttributes.classicImageSize = CGSize(width: 65, height: 65) ``` **Attributesを使用してビューコントローラーを初期化する** Braze Content Cards UIビューコントローラーの特定のインスタンスのみを変更する場合は、[`init(braze:attributes:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/init(braze:attributes:)/)イニシャライザーを使用してカスタムの`Attributes`構造体をビューコントローラーに渡します。 たとえば、ビューコントローラーの特定のインスタンスの画像サイズと角の半径を変更できます。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.cellAttributes.cornerRadius = 20 attributes.cellAttributes.classicImageSize = CGSize(width: 65, height: 65) let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes) ``` **サブクラス化によるセルのカスタマイズ** また、必要なカードタイプごとにカスタムクラスを登録して、カスタムインターフェイスを作成することもできます。デフォルトのセルの代わりにサブクラスを使用するには、`Attributes`構造体の[`cells`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/attributes-swift.struct/cells)プロパティを変更します。以下に例を示します。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults // Register your own custom cell attributes.cells[BrazeContentCardUI.ClassicImageCell.identifier] = CustomClassicImageCell.self let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes) ``` **プログラムによるContent Cardsの変更** `Attributes`構造体に[`transform`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/attributes-swift.struct/transform)クロージャを割り当てることで、プログラムでContent Cardsを変更できます。以下の例では、互換性のあるカードの`title`と`description`を変更しています。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.transform = { cards in cards.map { card in var card = card if let title = card.title { card.title = "[modified] \(title)" } if let description = card.description { card.description = "[modified] \(description)" } return card } } let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes) ``` 完全な例については、[Examplesサンプルアプリ](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples/Swift)を確認してください。 `Attributes`によるContent Cardsのカスタマイズは、Objective-Cではサポートされていません。 ## カスタマイズの例 {#customization-examples} ### カスタムフォント {#custom-font} Content Cardsで使用されるフォントをカスタマイズすると、ブランドアイデンティティを維持し、ユーザーにとって視覚的に魅力的なエクスペリエンスを作成できます。以下のレシピを使用して、すべてのContent Cardsのフォントをプログラムで設定します。 他のWeb要素と同様に、CSSを使用してContent Cardsの外観を簡単にカスタマイズできます。CSSファイルまたはインラインスタイルで、`font-family`プロパティを使用して、希望のフォント名またはフォントスタックを指定します。 ```css /* CSS selector targeting the Content Card element */ .card-element { font-family: "Helvetica Neue", Arial, sans-serif; } ``` デフォルトのフォントをプログラムで変更するには、カードのスタイルを設定し、`fontFamily`属性を使用して、カスタムフォントファミリーを使用するようにBrazeに指示します。 たとえば、キャプション付き画像カードのすべてのタイトルのフォントを更新するには、`Braze.ContentCards.CaptionedImage.Title`スタイルをオーバーライドし、カスタムフォントファミリーを参照します。属性値は、`res/font`ディレクトリのフォントファミリーを指す必要があります。 以下は、最後の行でカスタムフォントファミリー`my_custom_font_family`を参照している省略されたコード例です。 ```xml ``` Android SDKでのフォントのカスタマイズの詳細については、[フォントファミリーガイド](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/advanced_use_cases/font_customization#font-customization)を参照してください。 デフォルトのフォントをプログラムで変更するには、`ContentCardStyling`の[`titleTextStyle`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-styling/index.html#715371549%2FProperties%2F-1725759721)を設定します。 また、[`BrazeShortNewsContentCardStyling`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-braze-short-news-content-card-styling/index.html)に設定し、`ContentCardStyling`の[`shortNewsContentCardStyle`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-styling/index.html#8580250%2FProperties%2F-1725759721)に渡すことで、特定のカードタイプに`titleTextStyle`を設定することもできます。 ```kotlin val fontFamily = FontFamily( Font(R.font.sailec_bold) ) ContentCardStyling( titleTextStyle = TextStyle( fontFamily = fontFamily ) ) ``` [`cellAttributes`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/attributes-swift.struct/cellattributes/)インスタンスプロパティの`Attributes`をカスタマイズして、フォントをカスタマイズします。以下に例を示します。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.cellAttributes.titleFont = .preferredFont(textStyle: .callout, weight: .bold) attributes.cellAttributes.descriptionFont = .preferredFont(textStyle: .footnote, weight: .regular) attributes.cellAttributes.domainFont = .preferredFont(textStyle: .footnote, weight: .medium) let viewController = BrazeContentCardUI.ViewController.init(braze: braze, attributes: attributes) ``` `Attributes`によるフォントのカスタマイズは、Objective-Cではサポートされていません。 カスタムフォントを使用して独自のUIを構築する例については、[Examplesサンプルアプリ](https://github.com/braze-inc/braze-swift-sdk/blob/main/Examples/ObjC/Sources/ContentCards-Custom-UI/CardsInfoViewController.m#L97)を確認してください。 ### カスタムの固定アイコン {#custom-pinned-icons} Content Cardsの作成時、マーケターはカードを固定するオプションを選択できます。固定されたカードはユーザーのフィードの上部に表示され、ユーザーはそれを閉じることができません。カードスタイルをカスタマイズする際に、固定アイコンの見た目を変更できます。 ![Brazeのモバイルおよび Web向けContent Cardsプレビューを、「このカードをフィードの先頭にピン留めする」オプションを選択した状態で並べて表示](https://www.braze.com/docs/ja/ja/assets/img/cc_pin_to_top.png?a48fd827da3c7adb662f8aece660f43f){:style="border:none"} Content Cardsの固定アイコンの構造は次のとおりです。 ```css
``` 別のFontAwesomeアイコンを使用したい場合は、`i`要素のクラス名を目的のアイコンのクラス名に置き換えます。 アイコンを完全に切り替えたい場合は、`i`要素を削除し、カスタムアイコンを`ab-pinned-indicator`の子要素として追加します。アイコンを変更する方法はいくつかありますが、簡単な方法の一つは、`ab-pinned-indicator`要素に`replaceChildren()`を使用することです。 以下に例を示します。 ```javascript // Get the parent element const pinnedIndicator = document.querySelector('.ab-pinned-indicator'); // Create a new custom icon element const customIcon = document.createElement('span'); customIcon.classList.add('customIcon'); // Replace the existing icon with the custom icon pinnedIndicator.replaceChildren(customIcon); ``` カスタムの固定アイコンを設定するには、`Braze.ContentCards.PinnedIcon`スタイルをオーバーライドします。カスタム画像アセットは、`android:src`要素で宣言する必要があります。以下に例を示します。 ```xml ``` デフォルトの固定アイコンを変更するには、`ContentCardStyling`の[`pinnedResourceId`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-styling/index.html#794044424%2FProperties%2F-1725759721)を設定します。以下に例を示します。 ```kotlin ContentCardStyling( pinnedResourceId = R.drawable.pushpin, pinnedImageAlignment = Alignment.TopCenter ) ``` `ContentCardStyling`の[`pinnedComposable`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-styling/index.html#1460938052%2FProperties%2F-1725759721)にComposableを指定することもできます。`pinnedComposable`が指定された場合、`pinnedResourceId`の値がオーバーライドされます。 ```kotlin ContentCardStyling( pinnedComposable = { Box(Modifier.fillMaxWidth()) { Text( modifier = Modifier .align(Alignment.Center) .width(50.dp), text = "This message is not read. Please read it." ) } } ) ``` 固定アイコンをカスタマイズするには、[`cellAttributes`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/attributes-swift.struct/cellattributes/)インスタンスプロパティの`pinIndicatorColor`と`pinIndicatorImage`のプロパティを変更します。以下に例を示します。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.cellAttributes.pinIndicatorColor = .red attributes.cellAttributes.pinIndicatorImage = UIImage(named: "my-image") let viewController = BrazeContentCardUI.ViewController.init(braze: braze, attributes: attributes) ``` サブクラス化を使用して、ピンインジケーターを含む`BrazeContentCardUI.Cell`のカスタムバージョンを独自に作成することもできます。以下に例を示します。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.cells[BrazeContentCardUI.ClassicImageCell.identifier] = CustomClassicImageCell.self let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes) ``` `Attributes`によるピンインジケーターのカスタマイズは、Objective-Cではサポートされていません。 ### 未読インジケーターの色の変更 {#changing-the-unread-indicator-color} Content Cardsの下部には、カードが閲覧されたかどうかを示す青い線が表示されます。 ![2枚のContent Cardsが並んで表示されている。最初のカードの下部には青い線があり、まだ閲覧されていないことを示している。2番目のカードには青い線がなく、すでに閲覧されたことを示している。](https://www.braze.com/docs/ja/ja/assets/img/braze-content-cards-seen-unseen-behavior.png?00ecd6c2252753cde9662110012ab680) カードの未読インジケーターの色を変更するには、WebページにカスタムCSSを追加します。たとえば、未閲覧インジケーターの色を緑に設定するには、次のようにします。 ```css .ab-unread-indicator { background-color: green; } ``` 未読インジケーターバーの色を変更するには、`colors.xml`ファイルの`com_braze_content_cards_unread_bar_color`の値を変更します。 ```xml #1676d0 ``` 未読インジケーターバーの色を変更するには、`ContentCardStyling`の[`unreadIndicatorColor`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-styling/index.html#-1669590042%2FProperties%2F-1725759721)の値を変更します。 ```kotlin ContentCardStyling( unreadIndicatorColor = Color.Red ) ``` 未読インジケーターバーの色を変更するには、`BrazeContentCardUI.ViewController`インスタンスのティントカラーに値を割り当てます。 ```swift let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze) viewController.view.tintColor = .systemGreen ``` ただし、未閲覧インジケーターのみを変更したい場合は、`BrazeContentCardUI.ViewController.Attributes`構造体の`unviewedIndicatorColor`プロパティにアクセスします。Brazeの`UITableViewCell`実装を使用する場合、セルが描画される前にプロパティにアクセスしてください。 たとえば、未閲覧インジケーターの色を赤に設定するには、次のようにします。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.cellAttributes.unviewedIndicatorColor = .red let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes) ``` 完全な例については、[Examplesサンプルアプリ](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples/Swift)を確認してください。 未読インジケーターバーの色を変更するには、`BRZContentCardUIViewController`のティントカラーに値を割り当てます。 ```objc BRZContentCardUIViewController *viewController = [[BRZContentCardUIViewController alloc] initWithBraze:AppDelegate.braze]; [viewController.view setTintColor:[UIColor systemGreenColor]]; ``` `Attributes`による未閲覧インジケーターのみのカスタマイズは、Objective-Cではサポートされていません。 ### ダークモード {#dark-mode} デバイスのダークモードまたはライトモードに基づいて異なる画像やスタイルを表示するには、Content Cardsメッセージで[キーと値のペア](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/content_cards/creative_details#key-value-pairs)を使用します。たとえば、`dark_mode_image`というキーと値のペアにダークモード画像アセットのURLを追加します。次に、アプリにカスタムロジックを追加して、デバイスの現在の外観モードを確認し、適切な画像を表示します。 ```swift if let darkImageUrl = card.extras["dark_mode_image"], view.traitCollection.userInterfaceStyle == .dark { // Use darkImageUrl for the image } ``` ```kotlin val darkModeImage = card.extras["dark_mode_image"] val isDarkMode = (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES if (isDarkMode && darkModeImage != null) { // Use darkModeImage for the image } ``` ```javascript const darkModeImage = card.extras?.dark_mode_image; const isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches; if (isDarkMode && darkModeImage) { // Use darkModeImage for the image } ``` このパターンは、テキスト、色、レイアウトなど、外観に依存するあらゆるコンテンツに使用できます。ダークモードの画像アセットを[メディアライブラリ](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/media_library/image_specifications)にアップロードし、キーと値のペアで参照します。 ### 未読インジケーターを無効にする {#disabling-unread-indicator} 未読インジケーターバーを非表示にするには、`css`に次のスタイルを追加します。 ```css .ab-unread-indicator { display: none; } ``` 未読インジケーターバーを非表示にするには、`ContentCardViewHolder`の[`setUnreadBarVisible`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.view/-content-card-view-holder/set-unread-bar-visible.html?query=fun%20setUnreadBarVisible(isVisible:%20Boolean))を`false`に設定します。 未読インジケーターの無効化は、Jetpack Composeではサポートされていません。 未読インジケーターバーを非表示にするには、`Attributes`構造体の`attributes.cellAttributes.unviewedIndicatorColor`プロパティを`.clear`に設定します。 `Attributes`による未閲覧インジケーターのみのカスタマイズは、Objective-Cではサポートされていません。 # Content Cardsの動作をカスタマイズする Source: /docs/ja/developer_guide/content_cards/customizing_cards/behavior/index.md # Content Cardsの動作をカスタマイズする {#customize-the-behavior-of-content-cards} > この実装ガイドでは、Content Cardsの動作の変更、ペイロードへのキーと値のペアなどの追加、一般的なカスタマイズのレシピについて説明します。コンテンツカードタイプの完全なリストについては、[Content Cardsについて](https://www.braze.com/docs/ja/ja/developer_guide/content_cards)を参照してください。 ## キーと値のペア {#key-value-pairs} Brazeでは、キーと値のペアを使用して、Content Cardsを介して追加のデータペイロードをユーザーデバイスに送信できます。これらは、内部指標の追跡、アプリコンテンツの更新、プロパティのカスタマイズに役立ちます。[ダッシュボードを使用してキーと値のペアを追加します](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/content_cards/create#step-4-configure-additional-settings-optional)。 **Note:** ネストされたJSON値をキーと値のペアとして送信することは推奨しません。代わりに、送信する前にJSONを平坦化してください。 キーと値のペアは、`extras`として`card` オブジェクトに格納されます。これらは、カードと一緒にデータを送信し、アプリケーションでさらに処理するために使用できます。`card.extras`を呼び出して、これらの値にアクセスします。 キーと値のペアは、`extras`として`card` オブジェクトに格納されます。これらは、カードと一緒にデータを送信し、アプリケーションでさらに処理するために使用できます。`card.extras` を呼び出して、これらの値にアクセスします。 キーと値のペアは、`extras`として`card` オブジェクトに格納されます。これらは、カードと一緒にデータを送信し、アプリケーションでさらに処理するために使用できます。`card.extras` を呼び出して、これらの値にアクセスします。 **Tip:** マーケターがBrazeダッシュボードに入力するキーと値のペアは、開発者がアプリのロジックに組み込むキーと値のペアと正確に一致する必要があるため、マーケティングチームと開発チームが使用するキーと値のペア(たとえば`feed_type = brand_homepage`)について確実に調整することが重要です。 ## 補足コンテンツとしてのContent Cards {#content-cards-as-supplemental-content} ![ローカルデータとBraze Content Cardsを組み合わせたハイブリッドリストを持つフィード。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/supplementary.png?04f6645c99fe71ac7abb4cba8a46ccbd){: style="float:right;max-width:25%;margin-left:15px;border:0;"} Content Cardsを既存のフィードにシームレスにブレンドし、複数のフィードからのデータを同時に読み込むことができます。これにより、Braze Content Cardsと既存のフィードコンテンツとの一貫性のある、調和のとれたエクスペリエンスが生まれます。 右の例は、ローカルデータとBrazeを活用したContent Cardsによるハイブリッドなアイテムリストを持つフィードを示しています。これにより、Content Cardsは既存のコンテンツと区別がつかなくなります。 ### APIトリガーのキーと値のペア {#api-triggered-key-value-pairs} [APIトリガーキャンペーン](https://www.braze.com/docs/ja/ja/user_guide/messaging/campaigns/schedule_your_campaign/api_triggered_delivery)は、カードの値が外部要因に依存してユーザーに表示するコンテンツを決定する場合に使用するのに適した戦略です。たとえば、補足的なコンテンツを表示するには、Liquidを使用してキーと値のペアを設定します。なお、`class_type`はセットアップ時に把握しておく必要があります。 ![補足Content Cardsのユースケースのキーと値のペア。この例では、「tile_id」、「tile_deeplink」、「tile_title」などカードのさまざまな要素がLiquidを使って設定されています。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/supplementary_content.png?1b9481939960e31dc1b1e5ef57d51b68){: style="max-width:60%;"} ## インタラクティブコンテンツとしてのContent Cards {#content-cards-as-interactive-content} ![画面左下に50%のプロモーションを示すインタラクティブなContent Cardが表示されている。クリックすると、カートにプロモーションが適用されます。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/discount2.png?28bacc3995ff935635bb24b7bb547e1b){: style="border:0;"}{: style="float:right;max-width:45%;border:0;margin-left:15px;"} Content Cardsを活用して、ユーザーのためのダイナミックでインタラクティブな体験を作成できます。右の例では、Content Cardのポップアップがチェックアウト時に表示され、ユーザーに最新のプロモーションを提供しています。このようなカードをうまく配置することで、ユーザーを特定のアクションに「後押し」することができます。 このユースケースのキーと値のペアには、希望する割引額として設定された`discount_percentage`と、`coupon_code`として設定された`class_type`が含まれます。これらのキーと値のペアによって、チェックアウト画面でタイプ別のContent Cardsをフィルタリングして表示できます。キーと値のペアを使用して複数のフィードを管理する方法の詳細については、[デフォルトのContent Cardsフィードのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/customization_guides/content_cards/customizing_feed#multiple-feeds)を参照してください。

![チェックアウトプロモーションを表示するインタラクティブなContent Card。](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/discount.png?0f629adf0e5b56e0d2dc52b0b9f3e087){: style="max-width:80%;"} ## Content Cardsバッジ {#content-card-badges} ![Brazeのサンプルアプリ「Swifty」が表示されたiPhoneのホーム画面に、赤いバッジで数字の7が表示されている](https://www.braze.com/docs/ja/ja/assets/img/cc_implementation/ios-unread-badge.png?f8538f586f860532f0f670933ea72054){: style="max-width:35%;float:right;margin-left:15px;border:none;"} バッジは小さなアイコンで、ユーザーの注意を引くのに最適です。バッジを使って新しいContent Cardsの内容をユーザーに知らせることで、ユーザーをアプリに呼び戻し、セッションを増やすことができます。 ### Content Cardsの未読数をバッジで表示する {#displaying-the-number-of-unread-content-cards-as-a-badge} Content Cardsの未読数をバッジとしてアプリのアイコンに表示できます。 未読カードの数は、以下を呼び出していつでもリクエストできます。 ```javascript braze.getCachedContentCards().getUnviewedCardCount(); ``` この情報を使って、未読Content Cardsの数を示すバッジを表示できます。詳細については、SDKリファレンスドキュメント を参照してください。 未読カードの数は、以下を呼び出していつでもリクエストできます。 ```java Braze.getInstance(context).getContentCardUnviewedCount(); ``` ```kotlin Braze.getInstance(context).contentCardUnviewedCount ``` この情報を使って、未読Content Cardsの数を示すバッジを表示できます。詳細については、SDKリファレンスドキュメント を参照してください。 次のサンプルでは、`braze.contentCards`を使用して未読Content Cardsの数をリクエストして表示しています。アプリが閉じられ、ユーザーのセッションが終了した後、このコードはカードカウントをリクエストし、`viewed`プロパティに基づいてカードの数をフィルタリングします。 ```swift func applicationDidEnterBackground(_ application: UIApplication) ``` このメソッド内で、次のコードを実装します。これにより、ユーザーが特定のセッション中にカードを閲覧している間にバッジカウントがアクティブに更新されます。 ```swift let unreadCards = AppDelegate.braze?.contentCards.cards.filter { $0.viewed == false } UIApplication.shared.applicationIconBadgeNumber = unreadCards?.count ?? 0 ``` ```objc (void)applicationDidEnterBackground:(UIApplication *)application ``` このメソッド内で、次のコードを実装します。これにより、ユーザーが特定のセッション中にカードを閲覧している間にバッジカウントがアクティブに更新されます。 ```objc NSInteger unreadCardCount = 0; for (BRZContentCardRaw *card in AppDelegate.braze.contentCards.cards) { if (card.viewed == NO) { unreadCardCount += 1; } } [UIApplication sharedApplication].applicationIconBadgeNumber = unreadCardCount; ``` # Content Cards用のフィードをカスタマイズする Source: /docs/ja/developer_guide/content_cards/customizing_cards/feed/index.md # Content Cards用のフィードをカスタマイズする {#customize-the-feed-for-content-cards} > Content Cardsフィードは、モバイルまたはWebアプリケーションにおける一連のContent Cardsです。この記事では、フィードの更新タイミングの設定、カードの順序、複数フィードの管理、「空のフィード」エラーメッセージについて説明します。コンテンツカードタイプの完全なリストについては、[Content Cardsについて](https://www.braze.com/docs/ja/ja/developer_guide/content_cards)を参照してください。 ## About the session lifecycle A session refers to the period of time the Braze SDK tracks user activity in your app after it's launched. You can also force a new session by [calling the `changeUser()` method](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_ids/#setting-a-user-id). By default, a session starts when you first call `braze.openSession()`. The session will remain active for up to `30` minutes of inactivity (unless you [change the default session timeout](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions/?tab=web#change-session-timeout) or the user closes the app. **Note:** If you've set up the [activity lifecycle callback](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/initial_sdk_setup/android_sdk_integration/#step-4-tracking-user-sessions-in-android) for Android, Braze will automatically call [`openSession()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/open-session.html) and [`closeSession()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/close-session.html) for each activity in your app. By default, a session starts when `openSession()` is first called. If your app goes to the background and then returns to the foreground, the SDK will check if more than 10 seconds have passed since the session started (unless you [change the default session timeout](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions/?tab=android#change-session-timeout)). If so, a new session will begin. Keep in mind that if the user closes your app while it's in the background, session data may not be sent to Braze until they reopen the app. Calling `closeSession()` will not immediately end the session. Instead, it will end the session after 10 seconds if `openSession()` isn't called again by the user starting another activity. By default, a session starts when you call `Braze.init(configuration:)`. This occurs when the `UIApplicationWillEnterForegroundNotification` notification is triggered, meaning the app has entered the foreground. If your app goes to the background, `UIApplicationDidEnterBackgroundNotification` is triggered. The app does not remain in an active session while in the background. When your app returns to the foreground, the SDK compares the time elapsed since the session started against the session timeout (unless you [change the default session timeout](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions/?tab=swift#change-session-timeout)). If the time since the session started exceeds the timeout period, a new session begins. ## フィードの更新 {#refreshing-the-feed} ### 自動リフレッシュ {#automatic-refresh} デフォルトでは、次の場合にContent Cardsフィードが自動的に更新されます。 - 新しいセッションが開始された場合 - デフォルトのContent Cardsフィードが閉じられ、最後の更新から60秒以上経過した後に再度開かれた場合 **Tip:** 手動で更新せずに最新のContent Cardsをダイナミックに表示するには、カード作成時に**最初のインプレッション発生時**を選択します。これらのカードは、利用可能になると更新されます。 ### 手動更新 {#manual-refresh} 特定のタイミングでフィードを手動で更新するには: Web SDKから[`requestContentCardsRefresh()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#requestcontentcardsrefresh)を呼び出して、いつでも手動でBraze Content Cardsのリフレッシュをリクエストできます。 また、[`getCachedContentCards`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#getcachedcontentcards)を呼び出して、最新のContent Cards更新から現在利用可能なすべてのカードを取得することもできます。 ```javascript import * as braze from "@braze/web-sdk"; function refresh() { braze.requestContentCardsRefresh(); } ``` Content Cardsのリンクを同じタブではなく新しいブラウザタブで開くには、Web SDKの初期化オプションで`openCardsInNewTab: true`を設定します。初期化オプションの詳細については、[Web SDKリポジトリガイド](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/web)を参照してください。 Android SDKから[`requestContentCardsRefresh`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/request-content-cards-refresh.html)を呼び出すことで、いつでも手動でBraze Content Cardsの更新をリクエストできます。 ```java Braze.getInstance(context).requestContentCardsRefresh(); ``` ```kotlin Braze.getInstance(context).requestContentCardsRefresh() ``` [`Braze.ContentCards`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class)クラスの[`requestRefresh`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class/requestrefresh(_:))メソッドを呼び出すことで、いつでもSwift SDKからBraze Content Cardsの手動更新をリクエストできます。 Swiftでは、オプションの完了ハンドラまたはネイティブのSwift concurrency APIを使用した非同期リターンにより、Content Cardsを更新できます。 #### 完了ハンドラ {#completion-handler} ```swift AppDelegate.braze?.contentCards.requestRefresh { result in // Implement completion handler } ``` #### Async/Await ```swift let contentCards = await AppDelegate.braze?.contentCards.requestRefresh() ``` ```objc [AppDelegate.braze.contentCards requestRefreshWithCompletion:^(NSArray * contentCards, NSError * error) { // Implement completion handler }]; ``` ### フル同期とパーシャル同期 {#full-sync-vs-partial-sync} Braze SDKは、サーバーからContent Cardsを取得する際に2種類の同期を使用します。 - **フル同期:** ユーザーが対象となるすべてのContent Cardsを取得します。フル同期は7日ごとに自動的に実行されるか、`changeUser()`が呼び出されたときに実行されます。 - **パーシャル同期:** 前回のリクエスト以降の新しいContent Cardsのみを取得します。ユーザーが新しいカードの対象でない場合、レスポンスはゼロカードを返します。パーシャル同期は`requestContentCardsRefresh()`が呼び出されるたびに実行されます(前回のフル同期から7日が経過している場合は、代わりにフル同期がトリガーされます)。 パーシャル同期により、サーバー負荷とデバイスのバッテリー使用量が削減されます。すでに受信されたContent CardsはSDKにローカルで保存されるため、パーシャル同期がゼロの新しいカードを返した場合でも、ユーザーは利用可能なカードを引き続き表示できます。 ### レート制限 {#rate-limit} Brazeはトークンバケットアルゴリズムを使用して、次のレート制限を適用します。 - デバイスあたり最大5回の更新呼び出し(ユーザー間および`openSession()`への呼び出しと共有) - 制限に達すると、180秒(3分)ごとに新しい呼び出しが1回利用可能になります - システムは、いつでも使用できるように最大5回分の呼び出しを保持します - `subscribeToContentCards()`はレート制限中でもキャッシュされたカードを返します **Important:** Braze SDKは、パフォーマンスと信頼性のためにレート制限も適用します。自動テストの実行時や手動QAの実施時には、この点にご注意ください。詳細については、[Braze SDKのレート制限](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/rate_limits)を参照してください。 ## 表示されるカードの順序をカスタマイズする {#customizing-displayed-card-order} Content Cardsの表示順序を変更できます。これにより、時間的制約のあるプロモーションなど、特定のタイプのコンテンツに優先順位を付けることで、ユーザーエクスペリエンスを微調整できます。 `showContentCards():`の[`filterFunction`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#showcontentcards)パラメーターを使用して、フィード内のContent Cardsの表示順序をカスタマイズします。以下に例を示します。 ```javascript braze.showContentCards(null, (cards) => { return sortBrazeCards(cards); // Where sortBrazeCards is your sorting function that returns the sorted card array }); ``` [`ContentCardsFragment`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards/-content-cards-fragment/index.html)は、[`IContentCardsUpdateHandler`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/extras.html)に依存して、フィードに表示される前にContent Cardsのソートまたは変更を処理します。カスタム更新ハンドラは、`ContentCardsFragment`の[`setContentCardUpdateHandler`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards/-content-cards-fragment/set-content-card-update-handler.html)で設定できます。 以下はデフォルトの`IContentCardsUpdateHandler`であり、カスタマイズの出発点として使用できます。 **Javaの例を表示** ```java public class DefaultContentCardsUpdateHandler implements IContentCardsUpdateHandler { // Interface that must be implemented and provided as a public CREATOR // field that generates instances of your Parcelable class from a Parcel. public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public DefaultContentCardsUpdateHandler createFromParcel(Parcel in) { return new DefaultContentCardsUpdateHandler(); } public DefaultContentCardsUpdateHandler[] newArray(int size) { return new DefaultContentCardsUpdateHandler[size]; } }; @Override public List handleCardUpdate(ContentCardsUpdatedEvent event) { List sortedCards = event.getAllCards(); // Sort by pinned, then by the 'updated' timestamp descending // Pinned before non-pinned Collections.sort(sortedCards, new Comparator() { @Override public int compare(Card cardA, Card cardB) { // A displays above B if (cardA.getIsPinned() && !cardB.getIsPinned()) { return -1; } // B displays above A if (!cardA.getIsPinned() && cardB.getIsPinned()) { return 1; } // At this point, both A & B are pinned or both A & B are non-pinned // A displays above B since A is newer if (cardA.getUpdated() > cardB.getUpdated()) { return -1; } // B displays above A since A is newer if (cardA.getUpdated() < cardB.getUpdated()) { return 1; } // At this point, every sortable field matches so keep the natural ordering return 0; } }); return sortedCards; } // Parcelable interface method @Override public int describeContents() { return 0; } // Parcelable interface method @Override public void writeToParcel(Parcel dest, int flags) { // No state is kept in this class so the parcel is left unmodified } } ``` **Kotlinの例を表示** ```kotlin class DefaultContentCardsUpdateHandler : IContentCardsUpdateHandler { override fun handleCardUpdate(event: ContentCardsUpdatedEvent): List { val sortedCards = event.allCards // Sort by pinned, then by the 'updated' timestamp descending // Pinned before non-pinned sortedCards.sortWith(Comparator sort@{ cardA: Card, cardB: Card -> // A displays above B if (cardA.isPinned && !cardB.isPinned) { return@sort -1 } // B displays above A if (!cardA.isPinned && cardB.isPinned) { return@sort 1 } // At this point, both A & B are pinned or both A & B are non-pinned // A displays above B since A is newer if (cardA.updated > cardB.updated) { return@sort -1 } // B displays above A since A is newer if (cardA.updated < cardB.updated) { return@sort 1 } 0 }) return sortedCards } // Parcelable interface method override fun describeContents(): Int { return 0 } // Parcelable interface method override fun writeToParcel(dest: Parcel, flags: Int) { // No state is kept in this class so the parcel is left unmodified } companion object { // Interface that must be implemented and provided as a public CREATOR // field that generates instances of your Parcelable class from a Parcel. val CREATOR: Parcelable.Creator = object : Parcelable.Creator { override fun createFromParcel(`in`: Parcel): DefaultContentCardsUpdateHandler? { return DefaultContentCardsUpdateHandler() } override fun newArray(size: Int): Array { return arrayOfNulls(size) } } } } ``` **Tip:** `ContentCardsFragment`のソースは[GitHub](https://github.com/braze-inc/braze-android-sdk/blob/master/android-sdk-ui/src/main/java/com/braze/ui/contentcards/ContentCardsFragment.kt)で確認できます。 Jetpack ComposeでContent Cardsをフィルタリングおよびソートするには、`cardUpdateHandler`パラメータを設定します。以下に例を示します。 ```kotlin ContentCardsList( cardUpdateHandler = { it.sortedWith { cardA, cardB -> // A displays above B if (cardA.isPinned && !cardB.isPinned) { return@sortedWith -1 } // B displays above A if (!cardA.isPinned && cardB.isPinned) { return@sortedWith 1 } // At this point, both A & B are pinned or both A & B are non-pinned // A displays above B since A is newer if (cardA.updated > cardB.updated) { return@sortedWith -1 } // B displays above A since A is newer if (cardA.updated < cardB.updated) { return@sortedWith 1 } 0 } } ) ``` 静的な[`Attributes.defaults`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/attributes-swift.struct/defaults)変数を直接変更して、カードフィードの順序をカスタマイズします。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.transform = { cards in cards.sorted { if $0.pinned && !$1.pinned { return true } else if !$0.pinned && $1.pinned { return false } else { return $0.createdAt > $1.createdAt } } } let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes) ``` `BrazeContentCardUI.ViewController.Attributes`によるカスタマイズはObjective-Cでは使用できません。 ## 「空のフィード」メッセージのカスタマイズ {#customizing-empty-feed-message} ユーザーがどのContent Cardsにも該当しない場合、SDKは「更新はありません。後で再度確認してください。」という「空のフィード」エラーメッセージを表示します。この「空のフィード」エラーメッセージは、次のようにカスタマイズできます。 ![「これはカスタムの空状態のメッセージです。」と表示される空のフィードエラーメッセージ](https://www.braze.com/docs/ja/ja/assets/img/content_cards/content-card-customization-empty.png?f309ee8967ad09179432d3212ff8e073) Web SDKでは、「空のフィード」の文言をプログラムで置き換えることはサポートされていません。フィードが表示されるたびに置き換えることもできますが、フィードの更新に時間がかかる場合があり、空のフィードテキストがすぐに表示されないため、この方法はお勧めしません。 [`ContentCardsFragment`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards/-content-cards-fragment/index.html)がユーザーにContent Cardsの対象がないと判断した場合、空のフィードエラーメッセージが表示されます。 特殊なアダプタ[`EmptyContentCardsAdapter`](https://github.com/braze-inc/braze-android-sdk/blob/master/android-sdk-ui/src/main/java/com/braze/ui/contentcards/adapters/EmptyContentCardsAdapter.kt)が標準の[`ContentCardAdapter`](https://github.com/braze-inc/braze-android-sdk/blob/master/android-sdk-ui/src/main/java/com/braze/ui/contentcards/adapters/ContentCardAdapter.kt)を置き換えてこのエラーメッセージを表示します。カスタムメッセージ自体を設定するには、文字列リソース`com_braze_feed_empty`をオーバーライドします。 このメッセージの表示に使用されるスタイルは[`Braze.ContentCardsDisplay.Empty`](https://github.com/braze-inc/braze-android-sdk/blob/2e386dfa59a87bfc24ef7cb6ff5adf6b16f44d24/android-sdk-ui/src/main/res/values/styles.xml#L522-L530)で確認でき、次のコードスニペットに示されています。 ```xml ``` Content Cardsのスタイル要素のカスタマイズについて詳しくは、[スタイルのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/customizing_cards/style)を参照してください。 Jetpack Composeで「空のフィード」エラーメッセージをカスタマイズするには、`emptyString`を[`ContentCardsList`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards/-content-cards-list.html)に渡します。また、[`emptyTextStyle`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-list-styling/index.html#1193499348%2FProperties%2F-1725759721)を`ContentCardListStyling`に渡して、このメッセージをさらにカスタマイズすることもできます。 ```kotlin ContentCardsList( emptyString = "No messages today", style = ContentCardListStyling( emptyTextStyle = TextStyle(...) ) ) ``` 代わりに表示したいComposableがある場合は、`emptyComposable`を[`ContentCardsList`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards/-content-cards-list.html)に渡します。`emptyComposable`を指定した場合、`emptyString`は使用されません。 ```kotlin ContentCardsList( emptyComposable = { Image( painter = painterResource(id = R.drawable.noMessages), contentDescription = "No messages" ) } ) ``` 関連する[`Attributes`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcardui/viewcontroller/attributes-swift.struct/defaults)を設定して、ビューコントローラーの空の状態をカスタマイズします。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.emptyStateMessage = "This is a custom empty state message" attributes.emptyStateMessageFont = .preferredFont(forTextStyle: .title1) attributes.emptyStateMessageColor = .secondaryLabel ``` 空のContent Cardsフィードに自動的に表示される文言を変更するには、アプリの[`ContentCardsLocalizable.strings`](https://github.com/braze-inc/braze-swift-sdk/tree/main/Sources/BrazeUI/Resources/Localization/en.lproj)ファイルでローカライズ可能なContent Cards文字列を再定義します。 **Note:** 別のロケール言語でこのメッセージを更新する場合は、[リソースフォルダ構造](https://github.com/braze-inc/braze-swift-sdk/tree/main/Sources/BrazeUI/Resources/Localization)で対応する言語の`ContentCardsLocalizable.strings`を探してください。 ## 複数フィードの実装 {#implementing-multiple-feeds} Content Cardsはアプリ内でフィルタリングして特定のカードのみを表示できるため、さまざまなユースケースに対応する複数のContent Cardsフィードを持つことができます。たとえば、トランザクションフィードとマーケティングフィードの両方を維持できます。これを実現するには、Brazeダッシュボードでキーと値のペアを設定して、Content Cardsのさまざまなカテゴリーを作成します。次に、これらのタイプのContent Cardsを異なる方法で処理し、一部のタイプをフィルタリングして他のタイプを表示するフィードをアプリまたはサイトに作成します。 ### ステップ1:カードにキーと値のペアを設定する {#step-1-set-key-value-pairs-on-cards} Content Cards キャンペーンを作成する際に、各カードに[キーと値のペアデータ](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/customizing_cards/behavior)を設定します。このキーと値のペアを使用してカードを分類します。キーと値のペアは、カードのデータモデルの`extras`プロパティに保存されます。 この例では、カードが表示されるContent Cardsフィードを指定するキー`feed_type`を使用してキーと値のペアを設定します。値は、`home_screen`や`marketing`など、カスタムフィードに応じた任意の値になります。 ### ステップ2:Content Cardsをフィルタリングする {#step-2-filter-content-cards} キーと値のペアを割り当てたら、表示したいカードを表示し、他のタイプのカードをフィルタリングするロジックを含むフィードを作成します。この例では、`feed_type: "Transactional"`のキーと値のペアが一致するカードのみを表示します。 次の例では、`Transactional`タイプのカードのContent Cardsフィードを表示します。 ```javascript /** * @param {String} feed_type - value of the "feed_type" KVP to filter */ function showCardsByFeedType(feed_type) { braze.showContentCards(null, function(cards) { return cards.filter((card) => card.extras["feed_type"] === feed_type); }); } ``` 次に、カスタムフィードのトグルを設定できます。 ```javascript // show the "Transactional" feed when this button is clicked document.getElementById("show-transactional-feed").onclick = function() { showCardsByFeedType("Transactional"); }; ``` 詳細については、[SDKメソッドのドキュメント](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#showcontentcards)を参照してください。 デフォルトでは、Content Cardsフィードは[`ContentCardsFragment`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards/-content-cards-fragment/index.html)に表示され、[`IContentCardsUpdateHandler`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.handlers/-i-content-cards-update-handler/index.html)はBraze SDKから[`ContentCardsUpdatedEvent`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.events/-content-cards-updated-event/index.html)を受け取った後に表示するカードのリストを返します。ただし、カードのソートのみを行い、フィルタリングは直接処理しません。 #### ステップ2.1:カスタムハンドラを作成する {#step-21-create-a-custom-handler} ダッシュボードで[`Card.getExtras()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.handlers/-i-content-cards-update-handler/index.html)によって設定されたキーと値のペアを使用してカスタム[`IContentCardsUpdateHandler`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.handlers/-i-content-cards-update-handler/index.html)を実装し、先ほど設定した`feed_type`の値と一致しないカードをリストから削除するように変更することで、Content Cardsをフィルタリングできます。 **Javaの例を表示** ```java private IContentCardsUpdateHandler getUpdateHandlerForFeedType(final String desiredFeedType) { return new IContentCardsUpdateHandler() { @Override public List handleCardUpdate(ContentCardsUpdatedEvent event) { // Use the default card update handler for a first // pass at sorting the cards. This is not required // but is done for convenience. final List cards = new DefaultContentCardsUpdateHandler().handleCardUpdate(event); final Iterator cardIterator = cards.iterator(); while (cardIterator.hasNext()) { final Card card = cardIterator.next(); // Make sure the card has our custom KVP // from the dashboard with the key "feed_type" if (card.getExtras().containsKey("feed_type")) { final String feedType = card.getExtras().get("feed_type"); if (!desiredFeedType.equals(feedType)) { // The card has a feed type, but it doesn't match // our desired feed type, remove it. cardIterator.remove(); } } else { // The card doesn't have a feed // type at all, remove it cardIterator.remove(); } } // At this point, all of the cards in this list have // a feed type that explicitly matches the value we put // in the dashboard. return cards; } }; } ``` **Kotlinの例を表示** ```kotlin private fun getUpdateHandlerForFeedType(desiredFeedType: String): IContentCardsUpdateHandler { return IContentCardsUpdateHandler { event -> // Use the default card update handler for a first // pass at sorting the cards. This is not required // but is done for convenience. val cards = DefaultContentCardsUpdateHandler().handleCardUpdate(event) val cardIterator = cards.iterator() while (cardIterator.hasNext()) { val card = cardIterator.next() // Make sure the card has our custom KVP // from the dashboard with the key "feed_type" if (card.extras.containsKey("feed_type")) { val feedType = card.extras["feed_type"] if (desiredFeedType != feedType) { // The card has a feed type, but it doesn't match // our desired feed type, remove it. cardIterator.remove() } } else { // The card doesn't have a feed // type at all, remove it cardIterator.remove() } } // At this point, all of the cards in this list have // a feed type that explicitly matches the value we put // in the dashboard. cards } } ``` #### ステップ2.2:フラグメントに追加する {#step-22-add-it-to-a-fragment} [`IContentCardsUpdateHandler`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.handlers/-i-content-cards-update-handler/index.html)を作成したら、それを使用する[`ContentCardsFragment`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards/-content-cards-fragment/index.html)を作成します。このカスタムフィードは、他の`ContentCardsFragment`と同様に使用できます。アプリのさまざまな部分で、ダッシュボードで設定したキーに基づいて、異なるContent Cardsフィードを表示します。各`ContentCardsFragment`フィードには、各フラグメントのカスタム`IContentCardsUpdateHandler`により、固有のカードセットが表示されます。 **Javaの例を表示** ```java // We want a Content Cards feed that only shows "Transactional" cards. ContentCardsFragment customContentCardsFragment = new ContentCardsFragment(); customContentCardsFragment.setContentCardUpdateHandler(getUpdateHandlerForFeedType("Transactional")); ``` **Kotlinの例を表示** ```kotlin // We want a Content Cards feed that only shows "Transactional" cards. val customContentCardsFragment = ContentCardsFragment() customContentCardsFragment.contentCardUpdateHandler = getUpdateHandlerForFeedType("Transactional") ``` このフィードに表示されるContent Cardsをフィルタリングするには、`cardUpdateHandler`を使用します。以下に例を示します。 ```kotlin ContentCardsList( cardUpdateHandler = { it.filter { card -> card.extras["feed_type"] == "Transactional" } } ) ``` The following example will show the Content Cards feed for `Transactional` type cards: ```swift // Filter cards by the `Transactional` feed type based on your key-value pair. let transactionalCards = cards.filter { $0.extras["feed_type"] as? String == "Transactional" } ``` さらに一歩進めて、ビューコントローラーに表示されるカードは、`Attributes`構造体の`transform`プロパティを設定して、条件でフィルタリングされたカードのみを表示するようにフィルタリングできます。 ```swift var attributes = BrazeContentCardUI.ViewController.Attributes.defaults attributes.transform = { cards in cards.filter { $0.extras["feed_type"] as? String == "Transactional" } } // Pass your attributes containing the transformed cards to the Content Card UI. let viewController = BrazeContentCardUI.ViewController(braze: AppDelegate.braze, attributes: attributes) ``` ```objc // Filter cards by the `Transactional` feed type based on your key-value pair. NSMutableArray *transactionalCards = [[NSMutableArray alloc] init]; for (BRZContentCardRaw *card in AppDelegate.braze.contentCards.cards) { if ([card.extras[@"feed_type"] isEqualToString:@"Transactional"]) { [transactionalCards addObject:card]; } } ``` # 分析の記録 Source: /docs/ja/developer_guide/content_cards/logging_analytics/index.md # 分析の記録 {#log-analytics} > When building a custom UI for Content Cards, you must manually log analytics like impressions, clicks, and dismissals, as this is only handled automatically for default card models. Logging these events is a standard part of a Content Card integration and is essential for accurate campaign reporting and billing. To do this, populate your custom UI with data from the Braze data models and then manually log the events. Once you understand how to log analytics, you can see common ways Braze customers [create custom Content Cards](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/creating_cards/). ## Logging analytics When implementing your custom Content Cards, you can parse the Content Card objects and extract their payload data such as `title`, `cardDescription`, and `imageUrl`. Then, you can use the resulting model data to populate your custom UI. To obtain the Content Card data models, subscribe to Content Card updates. There are two properties to pay particular attention to: * **`id`**: Represents the Content Card ID string. This is the unique identifier used to log analytics from custom Content Cards. * **`extras`**: Encompasses all the key-value pairs from the Braze dashboard. All properties outside of `id` and `extras` are optional to parse for custom Content Cards. For more information on the data model, see each platform's integration article: [Android](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/?sdktab=android), [iOS](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/?sdktab=swift), [Web](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/?sdktab=web). Register a callback function to subscribe for updates when cards are refreshed. ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToContentCardsUpdates((updates) => { const cards = updates.cards; // For example: cards.forEach(card => { if (card.isControl) { // Do not display the control card, but remember to call `logContentCardImpressions([card])` } else if (card instanceof braze.ClassicCard || card instanceof braze.CaptionedImage) { // Use `card.title`, `card.imageUrl`, etc. } else if (card instanceof braze.ImageOnly) { // Use `card.imageUrl`, etc. } }) }); braze.openSession(); ``` **Note:** Content Cards will only refresh on session start if a subscribe request is called before `openSession()`. You can always choose to [manually refresh the feed](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/customizing_cards/feed/) as well. ### Step 1: Create a private subscriber variable To subscribe to card updates, first declare a private variable in your custom class to hold your subscriber: ```java // subscriber variable private IEventSubscriber mContentCardsUpdatedSubscriber; ``` ### Step 2: Subscribe to updates Next, add the following code to subscribe to Content Card updates from Braze, typically inside of your custom Content Cards activity's `Activity.onCreate()`: ```java // Remove the previous subscriber before rebuilding a new one with our new activity. Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class); mContentCardsUpdatedSubscriber = new IEventSubscriber() { @Override public void trigger(ContentCardsUpdatedEvent event) { // List of all Content Cards List allCards = event.getAllCards(); // Your logic below } }; Braze.getInstance(context).subscribeToContentCardsUpdates(mContentCardsUpdatedSubscriber); Braze.getInstance(context).requestContentCardsRefresh(); ``` ### Step 3: Unsubscribe We also recommend unsubscribing when your custom activity moves out of view. Add the following code to your activity's `onDestroy()` lifecycle method: ```java Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class); ``` ### Step 1: Create a private subscriber variable To subscribe to card updates, first declare a private variable in your custom class to hold your subscriber: ```kotlin private var contentCardsUpdatedSubscriber: IEventSubscriber? = null ``` ### Step 2: Subscribe to updates Next, add the following code to subscribe to Content Card updates from Braze, typically inside of your custom Content Cards activity's `Activity.onCreate()`: ```kotlin // Remove the previous subscriber before rebuilding a new one with our new activity. Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java) contentCardsUpdatedSubscriber = IEventSubscriber { event -> // List of all Content Cards val allCards = event.allCards // Your logic below } Braze.getInstance(context).subscribeToContentCardsUpdates(contentCardsUpdatedSubscriber) Braze.getInstance(context).requestContentCardsRefresh(true) ``` ### Step 3: Unsubscribe We also recommend unsubscribing when your custom activity moves out of view. Add the following code to your activity's `onDestroy()` lifecycle method: ```kotlin Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java) ``` To access the Content Cards data model, call [`contentCards.cards`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class/cards) on your `braze` instance. ```swift let cards: [Braze.ContentCard] = AppDelegate.braze?.contentCards.cards ``` Additionally, you can also maintain a subscription to observe for changes in your Content Cards. You can do so in one of two ways: 1. Maintaining a cancellable; or 2. Maintaining an `AsyncStream`. ### Cancellable ```swift // This subscription is maintained through a Braze cancellable, which will observe for changes until the subscription is cancelled. // You must keep a strong reference to the cancellable to keep the subscription active. // The subscription is canceled either when the cancellable is deinitialized or when you call its `.cancel()` method. let cancellable = AppDelegate.braze?.contentCards.subscribeToUpdates { [weak self] contentCards in // Implement your completion handler to respond to updates in `contentCards`. } ``` ### AsyncStream ```swift let stream: AsyncStream<[Braze.ContentCard]> = AppDelegate.braze?.contentCards.cardsStream ``` ```objc NSArray *contentCards = AppDelegate.braze.contentCards.cards; ``` Additionally, if you wish to maintain a subscription to your content cards, you can call [`subscribeToUpdates`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class/subscribetoupdates(_:)): ```objc // This subscription is maintained through Braze cancellable, which will continue to observe for changes until the subscription is cancelled. BRZCancellable *cancellable = [self.braze.contentCards subscribeToUpdates:^(NSArray *contentCards) { // Implement your completion handler to respond to updates in `contentCards`. }]; ``` To get the Content Card data, use the `getContentCards` method: ```javascript import Braze from "@braze/react-native-sdk"; const cards = await Braze.getContentCards(); ``` To listen for updates, subscribe to Content Card update events: ```javascript const subscription = Braze.addListener(Braze.Events.CONTENT_CARDS_UPDATED, (update) => { const cards = update.cards; cards.forEach(card => { if (card.isControl) { // Do not display the control card, but remember to log an impression } else { // Use card.title, card.cardDescription, card.image, etc. } }); }); ``` To request a manual refresh of Content Cards from Braze servers: ```javascript Braze.requestContentCardsRefresh(); ``` To get cached Content Cards without a network request: ```javascript const cachedCards = await Braze.getCachedContentCards(); ``` ## Logging events Logging valuable metrics like impressions, clicks, and dismissals is quick and simple. Set a custom click listener to manually handle these analytics. Log impression events when cards are viewed by users using [`logContentCardImpressions`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logcontentcardimpressions): ```javascript import * as braze from "@braze/web-sdk"; braze.logContentCardImpressions([card1, card2, card3]); ``` Log card click events when users interact with a card using [`logContentCardClick`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logcontentcardclick): ```javascript import * as braze from "@braze/web-sdk"; braze.logContentCardClick(card); ``` The [`BrazeManager`](https://github.com/braze-inc/braze-growth-shares-android-demo-app/blob/main/app/src/main/java/com/braze/advancedsamples/BrazeManager.kt) can reference Braze SDK dependencies such as the Content Card objects array list to get the [`Card`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/index.html) to call the Braze logging methods. Use the `ContentCardable` base class to easily reference and provide data to the `BrazeManager`. To log an impression or click on a card, call [`Card.logClick()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/log-click.html) or [`Card.logImpression()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/log-impression.html) respectively. You can manually log or set a Content Card as "dismissed" to Braze for a particular card with [`isDismissed`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/is-dismissed.html). If a card is already marked as dismissed, it cannot be marked as dismissed again. To create a custom click listener, create a class that implements [`IContentCardsActionListener`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.listeners/-i-content-cards-action-listener/index.html) and register it with [`BrazeContentCardsManager`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.managers/-braze-content-cards-manager/index.html). Implement the [`onContentCardClicked()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.listeners/-i-content-cards-action-listener/on-content-card-clicked.html) method, which will be called when the user clicks a Content Card. Then, instruct Braze to use your Content Card click listener. For example: ```java BrazeContentCardsManager.getInstance().setContentCardsActionListener(new IContentCardsActionListener() { @Override public boolean onContentCardClicked(Context context, Card card, IAction cardAction) { return false; } @Override public void onContentCardDismissed(Context context, Card card) { } }); ``` For example: ```kotlin BrazeContentCardsManager.getInstance().contentCardsActionListener = object : IContentCardsActionListener { override fun onContentCardClicked(context: Context, card: Card, cardAction: IAction): Boolean { return false } override fun onContentCardDismissed(context: Context, card: Card) { } } ``` **Important:** To handle control variant Content Cards in your custom UI, pass in your [`com.braze.models.cards.Card`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/index.html) object, then call the `logImpression` method as you would with any other Content Card type. The object will implicitly log a control impression to inform our analytics of when a user would have seen the control card. Implement the [`BrazeContentCardUIViewControllerDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcarduiviewcontrollerdelegate) protocol and set your delegate object as the `delegate` property of your `BrazeContentCardUI.ViewController`. This delegate will handle passing the data of your custom object back to Braze to be logged. For an example, see [Content Cards UI tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/c2-contentcardsui/). ```swift // Set the delegate when creating the Content Cards controller contentCardsController.delegate = delegate // Method to implement in delegate func contentCard( _ controller: BrazeContentCardUI.ViewController, shouldProcess clickAction: Braze.ContentCard.ClickAction, card: Braze.ContentCard ) -> Bool { // Intercept the content card click action here. return true } ``` ```objc // Set the delegate when creating the Content Cards controller contentCardsController.delegate = delegate; // Method to implement in delegate - (BOOL)contentCardController:(BRZContentCardUIViewController *)controller shouldProcess:(NSURL *)url card:(BRZContentCardRaw *)card { // Intercept the content card click action here. return YES; } ``` **Important:** To handle control variant Content Cards in your custom UI, pass in your [`Braze.ContentCard.Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/control(_:)) object, then call the `logImpression` method as you would with any other Content Card type. The object will implicitly log a control impression to inform our analytics of when a user would have seen the control card. Log impression events when cards are viewed by users: ```javascript Braze.logContentCardImpression(card.id); ``` Log card click events when users interact with a card: ```javascript Braze.logContentCardClicked(card.id); ``` Log dismissal events when a user dismisses a card: ```javascript Braze.logContentCardDismissed(card.id); ``` ## Handling on-click behavior When a user clicks a Content Card in a custom feed, the on-click behavior (such as navigating to a URL, deep linking, or logging a custom event) is not handled automatically. Use [`handleBrazeAction`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#handlebrazeaction) to process the card's URL and execute the configured on-click action, including Braze actions (`brazeActions://` URLs). ```javascript import * as braze from "@braze/web-sdk"; // In your card click handler function onCardClick(card) { // Log the click braze.logContentCardClick(card); // Handle the on-click behavior if (card.url) { braze.handleBrazeAction(card.url); } } ``` | Parameter | Description | |---|---| | `url` | A valid URL, or a valid Braze action URL with the scheme `brazeActions://`. | | `openLinkInNewTab` | (Optional) Whether the URL should open in a new tab. Defaults to `false`. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Handling on-click behavior" } **Important:** If you don't call `handleBrazeAction()`, on-click behaviors configured in the Braze dashboard (such as "Log Custom Event" or "Navigate to URL") won't execute for cards displayed in a custom feed. On-click behavior is handled automatically by the default Content Cards UI. For custom implementations, use the [`IContentCardsActionListener`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.listeners/-i-content-cards-action-listener/index.html) interface described in the [Logging analytics](#logging-analytics) section above. On-click behavior is handled automatically by the default Content Cards UI. For custom implementations, use the [`BrazeContentCardUIViewControllerDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcarduiviewcontrollerdelegate) protocol described in the [Logging analytics](#logging-analytics) section above. ## ユニーク非表示数がユニークインプレッション数を上回る場合 {#unique-dismissals-higher-than-unique-impressions} *ユニーク非表示数*が*ユニークインプレッション数*を上回っている場合、カスタムContent Cardsの統合で、該当するカードのインプレッションを記録せずに非表示を記録しています。BrazeのデフォルトのContent Cards UIは両方を自動的に記録するため、この不一致はカスタムUIを使用している場合にのみ発生します。 カードを表示するたびにインプレッションを記録し、ユーザーがカードを非表示にしたときに非表示を記録してください。メソッド名と例については、以下のプラットフォームセクションを参照してください。 ## コンテンツカードの分析が欠落している場合 {#missing-content-cards-analytics} コンテンツカードがアプリに正しく表示されているにもかかわらず、分析データ(インプレッション、クリックなど)が一貫して受信されない場合、SDKの統合に問題がある可能性があります。 - **カスタムコンテンツカードビュー(Android、iOS、Web):** デフォルトのBraze UIは、すべてのプラットフォームでインプレッションとクリックを自動的に記録します。カスタムコンテンツカードビューまたは実装を使用している場合は、アプリケーション内で適切なログ記録メソッドを明示的に呼び出す必要があります。お使いのプラットフォームの[分析の記録](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/logging_analytics)を参照してください。特にカスタムWeb実装の場合は、Braze Web SDKが読み込まれていることを確認し、ブラウザーコンソールでエラーを確認し、カードデータが受信されていることを検証してください。 - **SDKの初期化とユーザー識別:** カードを表示する前に、SDKが完全に初期化されていることを確認してください。SDKが未初期化、遅延初期化モード、またはGDPR無効の状態では、イベントはキューに入れられずにサイレントに破棄されます。SDKは匿名ユーザーの分析も記録しますが、「ユニークデイリーインプレッション」などのダッシュボード指標にはユーザーIDの解決が必要です。そのため、可能な限りカードを表示する前に`changeUser`を呼び出してください。 ## コンテンツカードID {#content-card-id} キャンペーンが受信者に送信されるたびに、新しいコンテンツカードIDが生成されます。同じユーザーが後の送信で再度そのキャンペーンを受信した場合、Brazeは新しいIDを割り当てます。カスタム実装でインプレッション、クリック、非表示を記録する際は、カードの`id`を参照してください。 # Content Cardsのディープリンク Source: /docs/ja/developer_guide/content_cards/deep_linking/index.md # Content Cardsのディープリンク {#deep-linking-in-content-cards} > Braze SDKを使用して、Content Cards内でディープリンクを行う方法について説明します。ディープリンクの詳細については、[ディープリンクとは](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize/actions_and_media_urls#what-is-deep-linking)を参照してください。 現時点では、Web Braze SDKではContent Cardsのディープリンクはサポートされていません。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Creating a universal delegate The Android SDK provides the ability to set a single delegate object to custom handle all deep links opened by Braze across Content Cards, in-app messages, and push notifications. Your delegate object should implement the [`IBrazeDeeplinkHandler`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-deeplink-handler/index.html) interface and be set using [`BrazeDeeplinkHandler.setBrazeDeeplinkHandler()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-deeplink-handler/-companion/set-braze-deeplink-handler.html). In most cases, the delegate should be set in your app's `Application.onCreate()`. The following is an example of overriding the default [`UriAction`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.actions/-uri-action/index.html) behavior with custom intent flags and custom behavior for YouTube URLs: ```java public class CustomDeeplinkHandler implements IBrazeDeeplinkHandler { private static final String TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler.class); @Override public void gotoUri(Context context, UriAction uriAction) { String uri = uriAction.getUri().toString(); // Open YouTube URLs in the YouTube app and not our app if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) { uriAction.setUseWebView(false); } CustomUriAction customUriAction = new CustomUriAction(uriAction); customUriAction.execute(context); } public static class CustomUriAction extends UriAction { public CustomUriAction(@NonNull UriAction uriAction) { super(uriAction); } @Override protected void openUriWithActionView(Context context, Uri uri, Bundle extras) { Intent intent = getActionViewIntent(context, uri, extras); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); if (intent.resolveActivity(context.getPackageManager()) != null) { context.startActivity(intent); } else { BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link " + uri + "."); } } } } ``` ```kotlin class CustomDeeplinkHandler : IBrazeDeeplinkHandler { override fun gotoUri(context: Context, uriAction: UriAction) { val uri = uriAction.uri.toString() // Open YouTube URLs in the YouTube app and not our app if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) { uriAction.useWebView = false } val customUriAction = CustomUriAction(uriAction) customUriAction.execute(context) } class CustomUriAction(uriAction: UriAction) : UriAction(uriAction) { override fun openUriWithActionView(context: Context, uri: Uri, extras: Bundle) { val intent = getActionViewIntent(context, uri, extras) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP if (intent.resolveActivity(context.packageManager) != null) { context.startActivity(intent) } else { BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link $uri.") } } } companion object { private val TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler::class.java) } } ``` ## Deep linking to app settings To allow deep links to directly open your app's settings, you'll need a custom `BrazeDeeplinkHandler`. In the following example, the presence of a custom key-value pair called `open_notification_page` will make the deep link open the app's settings page: ```java BrazeDeeplinkHandler.setBrazeDeeplinkHandler(new IBrazeDeeplinkHandler() { @Override public void gotoUri(Context context, UriAction uriAction) { final Bundle extras = uriAction.getExtras(); if (extras.containsKey("open_notification_page")) { Intent intent = new Intent(); intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //for Android 5-7 intent.putExtra("app_package", context.getPackageName()); intent.putExtra("app_uid", context.getApplicationInfo().uid); // for Android 8 and later intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName()); context.startActivity(intent); } } }); ``` ```kotlin BrazeDeeplinkHandler.setBrazeDeeplinkHandler(object : IBrazeDeeplinkHandler { override fun gotoUri(context: Context, uriAction: UriAction) { val extras = uriAction.extras if (extras.containsKey("open_notification_page")) { val intent = Intent() intent.action = "android.settings.APP_NOTIFICATION_SETTINGS" intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK //for Android 5-7 intent.putExtra("app_package", context.packageName) intent.putExtra("app_uid", context.applicationInfo.uid) // for Android 8 and later intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName) context.startActivity(intent) } } }) ``` ## Customizing WebView activity {#Custom_Webview_Activity} When Braze opens website deeplinks inside the app, the deeplinks are handled by [`BrazeWebViewActivity`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-web-view-activity/index.html). **Note:** For custom HTML in-app messages, links configured with `target="_blank"` open in the device's default web browser and are not handled by `BrazeWebViewActivity`. To change this: 1. Create a new Activity that handles the target URL from `Intent.getExtras()` with the key `com.braze.Constants.BRAZE_WEBVIEW_URL_EXTRA`. For an example, see [`BrazeWebViewActivity.kt`](https://github.com/braze-inc/braze-android-sdk/blob/master/android-sdk-ui/src/main/java/com/braze/ui/BrazeWebViewActivity.kt). 2. Add that activity to `AndroidManifest.xml` and set `exported` to `false`. ```xml ``` 3. Set your custom Activity in a `BrazeConfig` [builder object](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-custom-web-view-activity-class.html). Build the builder and pass it to [`Braze.configure()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/configure.html) in your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()). ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setCustomWebViewActivityClass(MyCustomWebViewActivity::class) ... .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setCustomWebViewActivityClass(MyCustomWebViewActivity::class.java) ... .build() Braze.configure(this, brazeConfig) ``` ## Troubleshooting If deep links from push notifications aren't working on Android, try the following steps: 1. **Test the deep link outside of Braze.** Open the deep link URL from another app, such as email or a browser. If it doesn't open your app, the deep link may not be configured correctly in your `AndroidManifest.xml`. For more information, see Android's [Create Deep Links](https://developer.android.com/training/app-links/deep-linking) documentation. 2. **Check that automatic deep link handling is enabled.** Verify that `com_braze_handle_push_deep_links_automatically` is set to `true` in `braze.xml`, or set this option through [runtime configuration](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization/?sdktab=android). Without this setting, Braze doesn't automatically open your app and deep link destination when someone taps a push notification. 3. **Verify your deep link handler delegate.** If you set a custom `IBrazeDeeplinkHandler`, confirm that your `gotoUri` implementation handles the URI and doesn't drop it. 4. **Test across channels.** If the same deep link works in an in-app message but not from push, the issue is likely in your push deep link handling, not in the deep link itself. ## Using Jetpack Compose To handle deeplinks when using Jetpack Compose with NavHost: 1. Ensure that the activity handling your deeplink is registered in the Android Manifest. ```xml ``` 2. In NavHost, specify which deeplinks you want it to handle. ```kotlin composableWithCompositionLocal( route = "YOUR_ROUTE_HERE", deepLinks = listOf(navDeepLink { uriPattern = "myapp://articles/{${MainDestinations.ARTICLE_ID_KEY}}" }), arguments = listOf( navArgument(MainDestinations.ARTICLE_ID_KEY) { type = NavType.LongType } ), ) { backStackEntry -> val arguments = requireNotNull(backStackEntry.arguments) val articleId = arguments.getLong(MainDestinations.ARTICLE_ID_KEY) ArticleDetail( articleId ) } ``` 3. Depending on your app architecture, you may need to handle the new intent that's sent to your current activity as well. ```kotlin DisposableEffect(Unit) { val listener = Consumer { navHostController.handleDeepLink(it) } addOnNewIntentListener(listener) onDispose { removeOnNewIntentListener(listener) } } ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). **Tip:** For help choosing between custom scheme deep links, universal links, and "Open Web URL Inside App," see [iOS deep linking guide](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/ios_deep_linking_guide). For troubleshooting, see [Deep linking troubleshooting](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking_troubleshooting). ## Handling deep links ### Step 1: Register a scheme {#register-a-scheme} To handle deep linking, a custom scheme must be stated in your `Info.plist` file. The navigation structure is defined by an array of dictionaries. Each of those dictionaries contains an array of strings. Use Xcode to edit your `Info.plist` file: 1. Add a new key, `URL types`. Xcode will automatically make this an array containing a dictionary called `Item 0`. 2. Within `Item 0`, add a key `URL identifier`. Set the value to your custom scheme. 3. Within `Item 0`, add a key `URL Schemes`. This will automatically be an array containing a `Item 0` string. 4. Set `URL Schemes` >> `Item 0` to your custom scheme. Alternatively, if you wish to edit your `Info.plist` file directly, you can follow this spec: ```html CFBundleURLTypes CFBundleURLName YOUR.SCHEME CFBundleURLSchemes YOUR.SCHEME ``` ### Step 2: Add a scheme allowlist You must declare the URL schemes you wish to pass to `canOpenURL(_:)` by adding the `LSApplicationQueriesSchemes` key to your app's Info.plist file. Attempting to call schemes outside this allowlist will cause the system to record an error in the device's logs, and the deep link will not open. An example of this error will look like this: ``` : -canOpenURL: failed for URL: "yourapp://deeplink" – error: "This app is not allowed to query for scheme yourapp" ``` For example, if an in-app message should open the Facebook app when tapped, the app has to have the Facebook custom scheme (`fb`) in your allowlist. Otherwise, the system will reject the deep link. Deep links that direct to a page or view inside your own app still require that your app's custom scheme be listed in your app's `Info.plist`. Your example allowlist might look something like: ```html LSApplicationQueriesSchemes myapp fb twitter ``` For more information, refer to [Apple's documentation](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/TP40009250-SW14) on the `LSApplicationQueriesSchemes` key. ### Step 3: Implement a handler After activating your app, iOS will call the method [`application:openURL:options:`](https://developer.apple.com/reference/uikit/uiapplicationdelegate/1623112-application?language=objc). The important argument is the [NSURL](https://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSURL) object. ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let path = url.path let query = url.query // Insert your code here to take some action based upon the path and query. return true } ``` ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *path = [url path]; NSString *query = [url query]; // Insert your code here to take some action based upon the path and query. return YES; } ``` ## App Transport Security (ATS) As defined by [Apple](https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html#//apple_ref/doc/uid/TP40016198-SW14), "App Transport Security is a feature that improves the security of connections between an app and web services. The feature consists of default connection requirements that conform to best practices for secure connections. Apps can override this default behavior and turn off transport security." ATS is applied by default. It requires that all connections use HTTPS and are encrypted using TLS 1.2 with forward secrecy. Refer to [Requirements for Connecting Using ATS](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35) for more information. All images served by Braze to end devices are handled by a content delivery network ("CDN") that supports TLS 1.2 and is compatible with ATS. Unless they are specified as exceptions in your application's `Info.plist`, connections that do not follow these requirements will fail with errors that are similar to the following. **Example Error 1:** ```bash CFNetwork SSLHandshake failed (-9801) Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred, and a secure connection to the server cannot be made." ``` **Example Error 2:** ```bash NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802) ``` ATS compliance is enforced for links opened within the mobile app (our default handling of clicked links) and does not apply to sites opened externally via a web browser. ### Working with ATS You can handle ATS in either of the following ways, but we recommend **complying with ATS requirements**. Your Braze integration can satisfy ATS requirements by ensuring that any existing links you drive users to (for example, though in-app message and push campaigns) satisfy ATS requirements. While there are ways to bypass ATS restrictions, our recommendation is to ensure that all linked URLs are ATS-compliant. Given Apple's increasing emphasis on application security, the following approaches to allowing ATS exceptions are not guaranteed to be supported by Apple. You can allow a subset of links with certain domains or schemes to be treated as exceptions to the ATS rules. Your Braze integration will satisfy ATS requirements if every link you use in a Braze messaging channel is either ATS compliant or handled by an exception. To add a domain as an exception of the ATS, add following to your app's `Info.plist` file: ```html NSAppTransportSecurity NSAllowsArbitraryLoads NSExceptionDomains example.com NSExceptionAllowsInsecureHTTPLoads NSIncludesSubdomains ``` Refer to Apple's article on [app transport security keys](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33) for more information. You can turn off ATS entirely. Note that this is not recommended practice, due to both lost security protections and future iOS compatibility. To disable ATS, insert the following in your app's `Info.plist` file: ```html NSAppTransportSecurity NSAllowsArbitraryLoads ``` ## Decoding URLs The SDK percent-encodes links to create valid `URL`s. All link characters that are not allowed in a properly formed URL, such as Unicode characters, will be percent escaped. To decode an encoded link, use the `String` property [`removingPercentEncoding`](https://developer.apple.com/documentation/swift/stringprotocol/removingpercentencoding). You must also return `true` in the `BrazeDelegate.braze(_:shouldOpenURL:)`. A call to action is required to trigger the handling of the URL by your app. For example: ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let urlString = url.absoluteString.removingPercentEncoding // Handle urlString return true } ``` ```objc - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { NSString *urlString = [url.absoluteString stringByRemovingPercentEncoding]; // Handle urlString return YES; } ``` ## Deep linking to app settings You can take advantage of `UIApplicationOpenSettingsURLString` to deep link users to your app's settings from Braze push notifications and in-app messages. To take users from your app into the iOS settings: 1. First, make sure your application is set up for either [scheme-based deep links](#swift_register-a-scheme) or [universal links](#swift_universal-links). 2. Decide on a URI for deep linking to the **Settings** page (for example, `myapp://settings` or `https://www.braze.com/settings`). 3. If you are using custom scheme-based deep links, add the following code to your `application:openURL:options:` method: ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { let path = url.path if (path == "settings") { UIApplication.shared.openURL(URL(string:UIApplication.openSettingsURLString)!) } return true } ``` ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *path = [url path]; if ([path isEqualToString:@"settings"]) { NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; [[UIApplication sharedApplication] openURL:settingsURL]; } return YES; } ``` ## Customization options {#customization-options} ### Default WebView customization The `Braze.WebViewController` class displays web URLs opened by the SDK, typically when "Open Web URL Inside App" is selected for a web deep link. You can customize the `Braze.WebViewController` via the [`BrazeDelegate.braze(_:willPresentModalWithContext:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazedelegate/braze(_:willpresentmodalwithcontext:)-12sqy/) delegate method. ### Linking handling customization The `BrazeDelegate` protocol can be used to customize the handling of URLs such as deep links, web URLs, and universal links. To set the delegate during Braze initialization, set a delegate object on the `Braze` instance. Braze will then call your delegate's implementation of `shouldOpenURL` before handling any URIs. When a push notification or in-app message uses **Open web URL inside mobile app**, Braze passes `context.useWebView == true` on [`Braze.URLContext`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/urlcontext). When the message opens the URL in the system browser instead, `useWebView` is `false`. Inspect `context.useWebView` in `braze(_:shouldOpenURL:)` to branch your custom handling—for example, to open an in-app `WebViewController` only when the campaign requested in-app display. #### Universal links {#universal-links} Braze supports universal links in push notifications, in-app messages, and Content Cards. To enable universal link support, [`configuration.forwardUniversalLinks`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/forwarduniversallinks) must be set to `true`. When enabled, Braze will forward universal links to your app's `AppDelegate` via the [`application:continueUserActivity:restorationHandler:`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623072-application) method. Your application also needs to be set up to handle universal links. Refer to [Apple's documentation](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) to ensure your application is configured correctly for universal links. **Warning:** Universal link forwarding requires access to the application entitlements. When running the application in a simulator, these entitlements are not directly available and universal links are not forwarded to the system handlers. To add support to simulator builds, you can add the application `.entitlements` file to the _Copy Bundle Resources_ build phase. See [`forwardUniversalLinks`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/forwarduniversallinks) documentation for more details. **Note:** The SDK does not query your domains' `apple-app-site-association` file. It performs the differentiation between universal links and regular URLs by looking at the domain name only. As a result, the SDK does not respect any exclusion rule defined in the `apple-app-site-association` per [Supporting associated domains](https://developer.apple.com/documentation/xcode/supporting-associated-domains). ## Examples ### BrazeDelegate Here's an example using `BrazeDelegate`. For more information, see [Braze Swift SDK reference](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazedelegate). ```swift func braze(_ braze: Braze, shouldOpenURL context: Braze.URLContext) -> Bool { if context.url.host == "MY-DOMAIN.com" { // Custom handle link here return false } // Let Braze handle links otherwise return true } ``` ```objc - (BOOL)braze:(Braze *)braze shouldOpenURL:(BRZURLContext *)context { if ([[context.url.host lowercaseString] isEqualToString:@"MY-DOMAIN.com"]) { // Custom handle link here return NO; } // Let Braze handle links otherwise return YES; } ``` # コンテンツカードにGIFを埋め込む Source: /docs/ja/developer_guide/content_cards/embedding_gifs/index.md # コンテンツカードにGIFを埋め込む > Braze SDK を使用してGIF をコンテンツカードに埋め込む方法について説明します。 **Note:** リストされていないラッパーSDK の場合は、代わりに関連するネイティブAndroid またはSwift メソッドを使用します。Android およびSwift Braze SDK はアニメーションGIF をネイティブにサポートしていないため、代わりにサードパーティツールを使用してコンテンツカードGIF を実装します。 GIF のサポートは、Web SDK 統合にデフォルトで含まれています。 ## About GIFs Braze offers the ability to use a custom image library to display animated GIFs. Although the example below uses [Glide](https://bumptech.github.io/glide/), any image library that supports GIFs is compatible. ## Integrating a custom image library ### Step 1: Creating the image loader delegate The Image Loader delegate must implement the following methods: * [`getInAppMessageBitmapFromUrl()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/get-in-app-message-bitmap-from-url.html) * [`getPushBitmapFromUrl()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/get-push-bitmap-from-url.html) * [`renderUrlIntoCardView()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/render-url-into-card-view.html) * [`renderUrlIntoInAppMessageView()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/render-url-into-in-app-message-view.html) * [`setOffline()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/set-offline.html) The integration example below is taken from the [Glide integration sample app](https://github.com/braze-inc/braze-android-sdk/tree/master/samples/glide-image-integration) included with the Braze Android SDK. ```java import com.braze.support.BrazeLogger; import com.bumptech.glide.load.resource.gif.GifDrawable; import android.graphics.drawable.Drawable; public class GlideBrazeImageLoader implements IBrazeImageLoader { private static final String TAG = GlideBrazeImageLoader.class.getName(); private RequestOptions mRequestOptions = new RequestOptions(); @Override public void renderUrlIntoCardView(Context context, Card card, String imageUrl, ImageView imageView, BrazeViewBounds viewBounds) { renderUrlIntoView(context, imageUrl, imageView); } @Override public void renderUrlIntoInAppMessageView(Context context, IInAppMessage inAppMessage, String imageUrl, ImageView imageView, BrazeViewBounds viewBounds) { renderUrlIntoView(context, imageUrl, imageView); } @Override public Bitmap getPushBitmapFromUrl(Context context, Bundle extras, String imageUrl, BrazeViewBounds viewBounds) { return getBitmapFromUrl(context, imageUrl, viewBounds); } @Override public Bitmap getInAppMessageBitmapFromUrl(Context context, IInAppMessage inAppMessage, String imageUrl, BrazeViewBounds viewBounds) { return getBitmapFromUrl(context, imageUrl, viewBounds); } private void renderUrlIntoView(Context context, String imageUrl, ImageView imageView) { try { final Drawable drawable = Glide.with(context) .load(imageUrl) .apply(mRequestOptions) .submit() .get(); imageView.post(() -> { imageView.setImageDrawable(drawable); if (drawable instanceof GifDrawable) { ((GifDrawable) drawable).start(); } }); } catch (Exception e) { BrazeLogger.e(TAG, "Failed to render URL into view: " + imageUrl, e); } } private Bitmap getBitmapFromUrl(Context context, String imageUrl, BrazeViewBounds viewBounds) { try { return Glide.with(context) .asBitmap() .apply(mRequestOptions) .load(imageUrl).submit().get(); } catch (Exception e) { Log.e(TAG, "Failed to retrieve bitmap at url: " + imageUrl, e); } return null; } @Override public void setOffline(boolean isOffline) { // If the loader is offline, then we should only be retrieving from the cache mRequestOptions = mRequestOptions.onlyRetrieveFromCache(isOffline); } } ``` ```kotlin import com.braze.support.BrazeLogger import com.bumptech.glide.load.resource.gif.GifDrawable class GlideBrazeImageLoader : IBrazeImageLoader { companion object { private val TAG = GlideBrazeImageLoader::class.qualifiedName } private var mRequestOptions = RequestOptions() override fun renderUrlIntoCardView(context: Context, card: Card, imageUrl: String, imageView: ImageView, viewBounds: BrazeViewBounds) { renderUrlIntoView(context, imageUrl, imageView) } override fun renderUrlIntoInAppMessageView(context: Context, inAppMessage: IInAppMessage, imageUrl: String, imageView: ImageView, viewBounds: BrazeViewBounds) { renderUrlIntoView(context, imageUrl, imageView) } override fun getPushBitmapFromUrl(context: Context, extras: Bundle, imageUrl: String, viewBounds: BrazeViewBounds): Bitmap? { return getBitmapFromUrl(context, imageUrl, viewBounds) } override fun getInAppMessageBitmapFromUrl(context: Context, inAppMessage: IInAppMessage, imageUrl: String, viewBounds: BrazeViewBounds): Bitmap? { return getBitmapFromUrl(context, imageUrl, viewBounds) } private fun renderUrlIntoView(context: Context, imageUrl: String, imageView: ImageView) { try { val drawable = Glide.with(context) .load(imageUrl) .apply(mRequestOptions) .submit() .get() imageView.post { imageView.setImageDrawable(drawable) if (drawable is GifDrawable) { drawable.start() } } } catch (e: Exception) { BrazeLogger.e(TAG, "Failed to render URL into view: $imageUrl", e) } } private fun getBitmapFromUrl(context: Context, imageUrl: String, viewBounds: BrazeViewBounds): Bitmap? { try { return Glide.with(context) .asBitmap() .apply(mRequestOptions) .load(imageUrl).submit().get() } catch (e: Exception) { Log.e(TAG, "Failed to retrieve bitmap at url: $imageUrl", e) } return null } override fun setOffline(isOffline: Boolean) { // If the loader is offline, then we should only be retrieving from the cache mRequestOptions = mRequestOptions.onlyRetrieveFromCache(isOffline) } } ``` ### Fixing image loading for Android SDK 36.0.0 and later In Android SDK 36.0.0 and later, `displayInAppMessage()` is a `suspend` function. This means `renderUrlIntoInAppMessageView()` runs on a background thread instead of the main thread. If your custom image loader calls `Glide.into(imageView)` in `renderUrlIntoInAppMessageView()`, your app can fail with "You must call this method on the main thread." To avoid this: 1. Load the image on the background thread with `submit().get()`. 2. Post the UI update to the main thread with `imageView.post { ... }`. 3. If the loaded result is a GIF drawable, start the animation after setting it on the view. This separates image loading from UI rendering, and keeps your custom image loader compatible with Android SDK 36.0.0 and later. This guidance applies to Android custom image loaders. Web in-app messages support GIFs out of the box. The following Kotlin sample uses placeholder values to show this pattern: ```kotlin private const val TAG = "SampleGlideLoader" private const val glideBrazeImageLoaderTag = "sample-loader" private fun renderUrlIntoView( context: Context, imageUrl: String, imageView: ImageView ) { try { val drawable: Drawable = Glide.with(context) .load(imageUrl) .apply(mRequestOptions) .submit() .get() imageView.post { imageView.setImageDrawable(drawable) if (drawable is GifDrawable) { drawable.start() } } } catch (e: Exception) { Log.e(TAG, "$glideBrazeImageLoaderTag renderUrlIntoView failed: url=$imageUrl", e) } } ``` ### Step 2: Setting the image loader delegate The Braze SDK will use any custom image loader set with [`IBrazeImageLoader`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/index.html). We recommend setting the custom image loader in a custom application subclass: ```java public class GlideIntegrationApplication extends Application { @Override public void onCreate() { super.onCreate(); Braze.getInstance(context).setImageLoader(new GlideBrazeImageLoader()); } } ``` ```kotlin class GlideIntegrationApplication : Application() { override fun onCreate() { super.onCreate() Braze.getInstance(context).imageLoader = GlideBrazeImageLoader() } } ``` ## Custom Image Loading with Jetpack Compose To override image loading with Jetpack Compose, you can pass in a value to [`imageComposable`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-styling/index.html#-808910455%2FProperties%2F-1725759721). This function will take a `Card` and render the image and the modifiers needed. Alternatively, you can use `customCardComposer` of `ContentCardsList` to render the entire card. In the following example, Glide's Compose library is used for the cards listed in the `imageComposable` function: ```kotlin ContentCardsList( cardStyle = ContentCardStyling( imageComposable = { card -> when (card.cardType) { CardType.CAPTIONED_IMAGE -> { val captionedImageCard = card as CaptionedImageCard GlideImage( modifier = Modifier .fillMaxWidth() .wrapContentHeight() .run { if (captionedImageCard.aspectRatio > 0) { aspectRatio(captionedImageCard.aspectRatio) } else { this } }, contentScale = ContentScale.Crop, model = captionedImageCard.url, loading = placeholder(R.drawable.pushpin), contentDescription = "" ) } CardType.IMAGE -> { val imageOnlyCard = card as ImageOnlyCard GlideImage( modifier = Modifier .fillMaxWidth() .run { if (imageOnlyCard.aspectRatio > 0) { aspectRatio(imageOnlyCard.aspectRatio) } else { this } }, contentScale = ContentScale.Crop, model = imageOnlyCard.url, loading = placeholder(R.drawable.pushpin), contentDescription = "" ) } CardType.SHORT_NEWS -> { val shortNews = card as ShortNewsCard GlideImage( modifier = Modifier .width(100.dp) .height(100.dp), model = shortNews.url, loading = placeholder(R.drawable.pushpin), contentDescription = "" ) } else -> Unit } } ) ) ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). ## Integrating a custom image library ### Step 1: Integrate SDWebImage Integrate the [SDWebImage repository](https://github.com/SDWebImage/SDWebImage) into your Xcode project. ### Step 2: Create a new Swift file In your Xcode project, create a new file named `SDWebImageGIFViewProvider.swift` and import the following: ```swift import UIKit import BrazeUI import SDWebImage ``` ### Step 3: Add `GIFViewProvider` Next, add our sample SDWebImage [`GIFViewProvider`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/gifviewprovider/). Your file should be similar to the following: ```swift import UIKit import BrazeUI import SDWebImage extension GIFViewProvider { /// A GIF view provider using [SDWebImage](https://github.com/SDWebImage/SDWebImage) as a /// rendering library. public static let sdWebImage = Self( view: { SDAnimatedImageView(image: image(for: $0)) }, updateView: { ($0 as? SDAnimatedImageView)?.image = image(for: $1) } ) private static func image(for url: URL?) -> UIImage? { guard let url else { return nil } return url.pathExtension == "gif" ? SDAnimatedImage(contentsOfFile: url.path) : UIImage(contentsOfFile: url.path) } } ``` ### Step 4: Modify your `AppDelegate.swift` In your project's `AppDelegate.swift`, add GIF support to your `BrazeUI` components using `GIFViewProvider`. Your file should be similar to the following: ```swift import UIKit import BrazeKit import BrazeUI @main class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { /* ... */ GIFViewProvider.shared = .sdWebImage return true } } ``` # チュートリアル: Content Cardsを使った受信トレイの作成 Source: /docs/ja/developer_guide/content_cards/content_card_inbox/index.md # チュートリアル: Content Cardsを使った受信トレイの作成 {#tutorial-making-an-inbox-with-content-cards} > このチュートリアルのサンプルコードに沿って、BrazeのContent Cardsで受信トレイを構築しましょう。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Android(Compose)向けContent Cardsを使った受信トレイの作成 {#making-an-inbox-with-content-cards-for-android-compose} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```kotlin file=MainApplication.kt import android.app.Application import com.braze.Braze import com.braze.support.BrazeLogger import com.braze.configuration.BrazeConfig import android.util.Log class ContentCardsApplication : Application() { override fun onCreate() { super.onCreate() // Turn on verbose Braze logging BrazeLogger.enableVerboseLogging() // Configure Braze with your SDK key & endpoint val config = BrazeConfig.Builder() .setApiKey("YOUR_API_KEY") .setCustomEndpoint("YOUR_API_ENDPOINT") .build() Braze.configure(this, config) } } ``` ```kotlin file=ContentCardsInboxScreen.kt import android.content.Intent import android.net.Uri import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.braze.Braze import com.braze.events.ContentCardsUpdatedEvent import com.braze.events.IEventSubscriber import com.braze.models.cards.* @Composable fun ContentCardInboxScreen() { val context = LocalContext.current var cards by remember { mutableStateOf>(emptyList()) } val loggedImpressions = remember { mutableSetOf() } DisposableEffect(Unit) { val subscriber = IEventSubscriber { event -> cards = event.allCards.filter { !it.isControl } } Braze.getInstance(context).subscribeToContentCardsUpdates(subscriber) Braze.getInstance(context).requestContentCardsRefresh(false) onDispose { Braze.getInstance(context) .removeSingleSubscription(subscriber, ContentCardsUpdatedEvent::class.java) } } Column(modifier = Modifier.fillMaxSize()) { Text( text = "Message Inbox", fontSize = 20.sp, fontWeight = FontWeight.Bold, modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 12.dp, bottom = 8.dp) ) LazyColumn( modifier = Modifier .fillMaxSize() .padding(horizontal = 16.dp) ) { items(cards, key = { it.id }) { card -> ContentCardItem( card = card, onImpression = { if (!loggedImpressions.contains(card.id)) { card.logImpression() loggedImpressions.add(card.id) } }, onClick = { card.logClick() card.url?.let { context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(it))) } } ) } } } } @Composable fun ContentCardItem( card: Card, onImpression: () -> Unit, onClick: () -> Unit ) { // Log impression when the card becomes visible LaunchedEffect(card.id) { onImpression() } val title = when (card) { is CaptionedImageCard -> card.title is ShortNewsCard -> card.title is TextAnnouncementCard -> card.title else -> null } val description = when (card) { is CaptionedImageCard -> card.description is ShortNewsCard -> card.description is TextAnnouncementCard -> card.description else -> null } Card( modifier = Modifier .fillMaxWidth() .padding(vertical = 4.dp) .clickable { onClick() } ) { Column(modifier = Modifier.padding(16.dp)) { title?.let { Text( text = it, fontWeight = FontWeight.Bold, fontSize = 16.sp ) } description?.let { Spacer(modifier = Modifier.height(4.dp)) Text( text = it, fontSize = 14.sp ) } } } } ``` !!step lines-MainApplication.kt=12 ### 1. デバッグを有効にする(オプション) {#1-enable-debugging-optional} 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-ContentCardsInboxScreen.kt=47-69 #### 2. UIビューを構築する {#2-build-a-ui-view} Jetpack Composeでは、[`LazyColumn`]()を使用して、スクロール可能なリストにContent Cardsを表示します。 !!step lines-ContentCardsInboxScreen.kt=25-37 #### 3. Content Cardsの更新をサブスクライブする {#3-subscribe-to-content-card-updates} [`DisposableEffect`]()を使用してサブスクリプションのライフサイクルを管理し、コンポーザブルがコンポジションから離脱する際に適切なクリーンアップを行います。 !!step lines-ContentCardsInboxScreen.kt=84-95 #### 4. カスタム受信トレイUIを構築する {#4-build-a-custom-inbox-ui} Content Cardsの[属性]()(`title`、`description`、`url`など)を使用することで、特定のUI要件に合ったContent Cardsを作成できます。ここでは、Jetpack Composeの`Card`コンポーザブルと`Column`コンポーザブルを使って受信トレイを構築しています。 !!step lines-ContentCardsInboxScreen.kt=57,62 #### 5. インプレッションとクリックをトラッキングする {#5-track-impressions-and-clicks} Content Cards向けに用意されている[`logImpressions`]()メソッドと[`logClick`]()メソッドを使って、インプレッションとクリックを記録できます。 インプレッションは、ユーザーがカードを閲覧した際に一度だけ記録する必要があります。`LaunchedEffect`を使用して、カードが表示されたときにインプレッションを記録します。アプリのビューライフサイクルやユースケースを考慮して、インプレッションが正しく記録されるようにする必要がある点にご注意ください。 ## Android向けContent Cardsを使った受信トレイの作成(RecyclerView) {#making-an-inbox-with-content-cards-for-android-recyclerview} ```kotlin file=MainApplication.kt import android.app.Application import com.braze.Braze import com.braze.support.BrazeLogger import com.braze.configuration.BrazeConfig import android.util.Log class ContentCardsApplication : Application() { override fun onCreate() { super.onCreate() // Turn on verbose Braze logging BrazeLogger.enableVerboseLogging() // Configure Braze with your SDK key & endpoint val config = BrazeConfig.Builder() .setApiKey("YOUR_API_KEY") .setCustomEndpoint("YOUR_API_ENDPOINT") .build() Braze.configure(this, config) } } ``` ```kotlin file=ContentCardInboxActivity.kt import android.content.Intent import android.net.Uri import android.os.Bundle import androidx.activity.ComponentActivity import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import android.view.* import android.widget.TextView import com.braze.Braze import com.braze.events.ContentCardsUpdatedEvent import com.braze.events.IEventSubscriber import com.braze.models.cards.* class ContentCardsActivity : ComponentActivity() { private val cards = mutableListOf() private var subscriber: IEventSubscriber? = null private lateinit var recyclerView: RecyclerView private val adapter = ContentCardAdapter() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.content_card_inbox) recyclerView = findViewById(R.id.contentCardsRecyclerView) recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = adapter // Prepare the subscriber (attach/detach in onStart/onStop) subscriber = IEventSubscriber { event -> runOnUiThread { cards.clear() cards.addAll(event.allCards.filter { !it.isControl }) adapter.notifyDataSetChanged() } } } override fun onStart() { super.onStart() subscriber?.let { Braze.getInstance(this).subscribeToContentCardsUpdates(it) } // Fetch fresh cards Braze.getInstance(this).requestContentCardsRefresh(false) } override fun onStop() { // Avoid leaks by removing the subscription when not visible Braze.getInstance(this) .removeSingleSubscription(subscriber, ContentCardsUpdatedEvent::class.java) super.onStop() } inner class ContentCardAdapter : RecyclerView.Adapter() { inner class CardViewHolder(v: View) : RecyclerView.ViewHolder(v) { val title: TextView = v.findViewById(android.R.id.text1) val description: TextView = v.findViewById(android.R.id.text2) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder { val view = LayoutInflater.from(parent.context) .inflate(android.R.layout.simple_list_item_2, parent, false) return CardViewHolder(view) } override fun getItemCount() = cards.size override fun onBindViewHolder(holder: CardViewHolder, position: Int) { val card = cards[position] val title = when (card) { is CaptionedImageCard -> card.title is ShortNewsCard -> card.title is TextAnnouncementCard -> card.title else -> null } val description = when (card) { is CaptionedImageCard -> card.description is ShortNewsCard -> card.description is TextAnnouncementCard -> card.description else -> null } holder.title.text = title.orEmpty() holder.description.text = description.orEmpty() // Naive impression guard: only log the first time we bind a not-yet-viewed card. if (!card.viewed) card.logImpression() holder.itemView.setOnClickListener { card.logClick() card.url?.let { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(it))) } } } } } ``` ```xml file=content_card_inbox.xml ``` !!step lines-MainApplication.kt=12 ### 1. デバッグを有効にする(オプション) 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-content_card_inbox.xml=1-24 #### 2. UIビューを構築する このチュートリアルでは、Androidの[`RecyclerView`]()を使用してContent Cardsを表示しますが、ユースケースに合ったクラスやコンポーネントでUIを構築することをお勧めします。BrazeはデフォルトでUIを提供しますが、このチュートリアルでは外観と動作をカスタマイズするためのカスタムビューの作成方法を説明します。 !!step lines-ContentCardInboxActivity.kt=29-35,40-42,44 #### 3. Content Cardsの更新をサブスクライブする [`subscribeToContentCardsUpdates`]()を使用して、新しいContent Cardsが利用可能になった際にUIが応答できるようにします。ここでは、サブスクライバーはアクティビティのライフサイクルフック内で登録および削除されます。 !!step lines-ContentCardInboxActivity.kt=73-84 #### 4. カスタム受信トレイUIを構築する Content Cardsの[属性]()(`title`、`description`、`url`など)を使用することで、特定のUI要件に合ったContent Cardsを作成できます。ここでは、Androidのネイティブ`RecyclerView`を使って受信トレイを構築しています。 !!step lines-ContentCardInboxActivity.kt=90,93 #### 5. インプレッションとクリックをトラッキングする Content Cards向けに用意されている[`logImpressions`]()メソッドと[`logClick`]()メソッドを使って、インプレッションとクリックを記録できます。 インプレッションは、ユーザーがカードを閲覧した際に一度だけ記録する必要があります。ここでは、カードごとのフラグを用いて重複ログを防ぐシンプルな仕組みを採用しています。アプリのビューライフサイクルやユースケースを考慮して、インプレッションが正しく記録されるようにする必要がある点にご注意ください。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). また、[Swiftのアプリ内メッセージを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=swift#swift_enabling-in-app-messages)必要もあります。 ## Swift向けContent Cardsを使った受信トレイの作成 {#making-an-inbox-with-content-cards-for-swift} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```swift file=AppDelegate.swift import SwiftUI import BrazeKit import BrazeUI class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze! func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Braze configuration with your SDK API key and endpoint let configuration = Braze.Configuration(apiKey: "YOUR_API_ENDPOINT", endpoint: "YOUR_API_KEY") configuration.logger.level = .debug // Initialize Braze SDK instance AppDelegate.braze = Braze(configuration: configuration) return true } } struct InboxViewControllerRepresentable: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> UINavigationController { let vc = BrazeInboxViewController(style: .plain) return UINavigationController(rootViewController: vc) } func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {} } struct ContentView: View { var body: some View { NavigationView { InboxViewControllerRepresentable() .navigationTitle("Message Inbox") } } } ``` ```swift file=SampleApp.swift import SwiftUI @main struct SampleApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { ContentView() } } } ``` ```swift file=BrazeInboxView.swift import SwiftUI import UIKit import BrazeKit class BrazeInboxViewController: UITableViewController { private var cards: [Braze.ContentCard] = [] private var subscription: Any? private var loggedImpressions = Set() override func viewDidLoad() { super.viewDidLoad() tableView.register(UITableViewCell.self, forCellReuseIdentifier: "CardCell") tableView.rowHeight = 100 subscription = AppDelegate.braze.contentCards.subscribeToUpdates { [weak self] updatedCards in self?.cards = updatedCards self?.tableView.reloadData() } AppDelegate.braze.contentCards.requestRefresh() } override func numberOfSections(in tableView: UITableView) -> Int { 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { cards.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let card = cards[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) // Work with the content card's title and description cell.textLabel?.numberOfLines = 2 cell.textLabel?.text = [card.title, card.description].compactMap { $0 }.joined(separator: "\n") return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let card = cards[indexPath.row] card.logClick(using: AppDelegate.braze) if let url = card.clickAction?.url { UIApplication.shared.open(url, options: [:], completionHandler: nil) } tableView.deselectRow(at: indexPath, animated: true) } override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { let card = cards[indexPath.row] if !loggedImpressions.contains(card.id) { card.logImpression(using: AppDelegate.braze) } } } ``` !!step lines-AppDelegate.swift=15 ### 1. デバッグを有効にする(オプション) 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-BrazeInboxView.swift=5 #### 2. UIビューを構築する このチュートリアルではSwiftの[`UITableViewController`](https://developer.apple.com/documentation/uikit/uitableviewcontroller)を使用しますが、ユースケースに合ったクラスやコンポーネントでUIを構築することをお勧めします。 !!step lines-BrazeInboxView.swift=15-20 #### 3. Content Cardsの更新をサブスクライブする Content Cardsリスナーをサブスクライブして最新の更新を受け取り、`requestRefresh()`を呼び出してそのユーザー向けの最新のContent Cardsをリクエストします。 !!step lines-BrazeInboxView.swift=34-35 #### 4. カスタム受信トレイUIを構築する Content Cardsの[`attributes`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard)(`title`、`description`、`imageUrl`など)を使用することで、特定のUI要件に合ったContent Cardsを作成できます。ここでは、SwiftのネイティブテーブルAPIを使って受信トレイを構築しています。 !!step lines-BrazeInboxView.swift=8,43,49-56 #### 5. インプレッションとクリックをトラッキングする コンテンツカード向けに用意されている[`logClick(using:)`]()メソッドと[`logImpression(using:)`]()メソッドを使って、インプレッションとクリックを記録できます。 さらに、却下の記録には[`logDismissed(using:)`]()も使用できます。 インプレッションは、ユーザーが閲覧した際に一度だけ記録する必要があります。ここでは、`Set`と`willDisplay`を使用したシンプルな仕組みでこれを実現しています。アプリのUIライフサイクルやユースケースを考慮して、インプレッションが正しく記録されるようにする必要がある点にご注意ください。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ただし、追加のセットアップは不要です。 ## Web向けContent Cardsを使った受信トレイの作成 {#making-an-inbox-with-content-cards-for-web} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```js file=main.js import * as braze from "@braze/web-sdk"; // Uncomment this if you'd like to run braze web SDK methods in the console // window.braze = braze; // initialize the Braze SDK braze.initialize("YOUR_API_KEY", { baseUrl: "YOUR_API_ENDPOINT", enableLogging: true, }); braze.openSession(); // --- DOM refs --- const listEl = document.getElementById("cards-list"); // --- State for impression de-duping & lookup --- const loggedImpressions = new Set(); const idToCard = new Map(); let observer = null; // Utility: clean observer between renders function resetObserver() { if (observer) observer.disconnect(); observer = new IntersectionObserver(onIntersect, { threshold: 0.6 }); } // Intersection callback: logs impression once when ≥60% visible function onIntersect(entries) { entries.forEach((entry) => { if (!entry.isIntersecting) return; const id = entry.target.dataset.cardId; if (!id || loggedImpressions.has(id)) return; const card = idToCard.get(id); if (!card) return; // Log a single-card impression and stop observing this element braze.logContentCardImpressions([card]); loggedImpressions.add(id); observer.unobserve(entry.target); }); } // Renders cards into the DOM, sets up click + visibility tracking function renderCards(cards) { // Rebuild lookup and observer each render idToCard.clear(); resetObserver(); listEl.textContent = ""; // clear list cards.forEach((card) => { // Skip control-group cards in UI; (optional) you could log impressions for them elsewhere if (card.isControl) return; idToCard.set(card.id, card); const item = document.createElement("article"); item.className = "card-item"; item.dataset.cardId = card.id; const h3 = document.createElement("h3"); h3.textContent = card.title || ""; const p = document.createElement("p"); p.textContent = card.description || ""; let img = undefined; if (card.imageUrl) { img = document.createElement("img"); img.src = card.imageUrl; item.append(img); } const children = [h3, p]; if (img) { children.push(img); } item.append(...children); // Click tracking + action item.addEventListener("click", (e) => { braze.logContentCardClick(card); if (card.url) { // any url-handling logic for your use case } }); listEl.appendChild(item); observer.observe(item); }); } // Subscribe to updates *then* ask for a refresh braze.subscribeToContentCardsUpdates((updates) => { const cards = updates.cards || []; renderCards(cards); }); braze.requestContentCardsRefresh(); ``` ```html file=index.html

Message Inbox

``` !!step lines-main.js=3-4,9 ### 1. デバッグを有効にする(オプション) 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。オプションとして、コンソールでBraze Web SDKのメソッドを実行することもできます。 !!step lines-index.html=1-44 #### 2. UIを構築する {#2-build-the-ui} 受信トレイページのUIを作成します。ここでは、基本的なHTMLページを作成しています。このページには、`cards-list`というIDを持つ`div`が含まれています。これはContent Cardsをレンダリングするためのターゲットコンテナとして使用されます。 !!step lines-main.js=96-99,101 #### 3. Content Cardsの更新をサブスクライブする Content Cardsリスナーをサブスクライブして最新の更新を受け取り、[`requestContentCardsRefresh()`]()を呼び出してそのユーザー向けの最新のContent Cardsをリクエストします。または、セッション開始時に自動更新を行うために、`openSession()`の前にサブスクライバーを呼び出すこともできます。 !!step lines-main.js=64,67,70-74 #### 4. 受信トレイの要素を作成する {#4-build-the-inbox-elements} Content Cardsの[属性]()(`title`、`description`、`url`など)を使用することで、特定のUI要件に合わせてContent Cardsを表示できます。 !!step lines-main.js=22-25,28-43,84,91 #### 5. インプレッションとクリックをトラッキングする Content Cards向けに用意されている[`logContentCardImpressions`]()メソッドと[`logContentCardClick`]()メソッドを使って、インプレッションとクリックを記録できます。 さらに、却下の記録には[`logCardDismissal`]()も使用できます。 インプレッションは、ユーザーが閲覧した際に一度だけ記録する必要があります。ここでは、`IntersectionObserver`と`card.id`をキーとした`Set`を使用して重複ログを防止しています。アプリのUIライフサイクルやユースケースを考慮して、インプレッションが正しく記録されるようにする必要がある点にご注意ください。 # Braze SDK用アプリ内メッセージ Source: /docs/ja/developer_guide/in_app_messages/index.md # アプリ内メッセージ > アプリ内メッセージとBraze SDKの設定方法について学習する。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). However, no additional setup is required. ## Message types All in-app messages inherit their prototype from [`InAppMessage`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.inappmessage.html), which defines basic behavior and traits for all in-app messages. The prototypical subclasses are [`SlideUpMessage`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.slideupmessage.html), [`ModalMessage`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.modalmessage.html), [`FullScreenMessage`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.fullscreenmessage.html), and [`HtmlMessage`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.htmlmessage.html). Each in-app message type is customizable across content, images, icons, click actions, analytics, display, and delivery. [`SlideUp`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.slideupmessage.html) in-app messages are so-named because traditionally on mobile platforms, they "slide up" or "slide down" from the top or bottom of the screen. In the Braze Web SDK, these messages are displayed as more of a Growl or Toast style notification to align with the web's dominant paradigm. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. ![An in-app message sliding from the bottom of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the bottom corner of a web page.](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`Modal`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.modalmessage.html) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two click action and analytics-enabled buttons. ![A modal in-app message in the center of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`Full`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.fullscreenmessage.html) in-app messages are useful for maximizing the content and impact of your user communication. On narrow browser windows (for example, the mobile web), `full` in-app messages take up the entire browser window. On larger browser windows, `full` in-app messages appear similarly to `modal` in-app messages. The upper half of a `full` in-app message contains an image, and the lower half allows up to eight lines of text as well as up to two click action, and analytics-enabled buttons ![A full screen in-app message shown across an entire phone screen displaying, "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed largely in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} [`HTML`](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.htmlmessage.html) in-app messages are useful for creating fully customized user content. User-defined HTML is displayed in an iFrame and may contain rich content, such as images, fonts, videos, and interactive elements, allowing for full control over message appearance and functionality. These support a JavaScript `brazeBridge` interface to call methods on the Braze Web SDK from within your HTML, see our [best practices](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/best_practices/) for more details. **Important:** To enable HTML in-app messages through the Web SDK, you **must** supply the `allowUserSuppliedJavascript` initialization option to Braze, for example, `braze.initialize('YOUR-API_KEY', {allowUserSuppliedJavascript: true})`. This is for security reasons. HTML in-app messages can execute JavaScript, so we require a site maintainer to enable them. The following example shows a paginated HTML in-app message: ![An HTML in-app message with the a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). You'll also need to enable in-app messages. ## Message types Braze offers several default in-app message types, each customizable with messages, images, [Font Awesome](https://fontawesome.com/icons?d=gallery&p=2) icons, click actions, analytics, color schemes, and more. Their basic behavior and traits are defined by the [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html) interface, in a subclass called [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). `IInAppMessage` also includes a subinterface, [`IInAppMessageImmersive`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-immersive/index.html), which lets you add close, click-action, and analytics [buttons](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-message-button/index.html) to your app. **Important:** Keep in mind, in-app messages containing buttons will include the `clickAction` message in the final payload if the click action is added prior to adding the button text. [`slideup`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-slideup/index.html) in-app messages are so-named because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. The `slideup` in-app message object extends [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). ![An in-app message sliding from the bottom of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the bottom right corner of a web page.](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`modal`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-modal/index.html) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with two click-action and analytics-enabled buttons. This message type is a subclass of [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), an abstract class that implements `IInAppMessageImmersive`, giving you the option to add custom functionality to your locally generated in-app messages. ![A modal in-app message in the center of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`full`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-full/index.html) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `full` in-app message contains an image, and the lower half displays text and up to two click action and analytics-enabled buttons. This message type extends [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), giving you the option to add custom functionality to your locally generated in-app messages. ![A full screen in-app message shown across an entire phone screen displaying, "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed largely in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img_archive/In-App_Full.png?ecd62a88d38438aaebbda4cdcc22aa00) [`HTML`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-html/index.html) in-app messages are useful for creating fully customized user content. User-defined HTML in-app message content is displayed in a `WebView` and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality. This message type implements [`IInAppMessageHtml`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-html/index.html), which is a subclass of [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html). **Note:** On Android, links configured with `target="_blank"` in custom HTML in-app messages open in the device's default web browser. Android in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Android SDK from within your HTML, see our JavaScript bridge page for more details. ![An HTML in-app message with the a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} **Important:** We currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. **Tip:** You can also define custom in-app message views for your app. For a full walkthrough, see [Setting custom factories](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization#android_setting-custom-factories). ## Enabling in-app messages ### Step 1: Register `BrazeInAppMessageManager` In-app message display is managed by the [`BrazeInAppMessageManager`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-braze-in-app-message-manager/index.html) class. Every activity in your app must be registered with the `BrazeInAppMessageManager` to allow it to add in-app message views to the view hierarchy. There are two ways to accomplish this: The [activity lifecycle callback integration](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration#android_step-4-enable-user-session-tracking) handles in-app message registration automatically; no extra integration is required. This is the recommended method for handling in-app message registration. **Warning:** If you're using activity lifecycle callback for automatic registration, do not complete this step. In your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()), call [`ensureSubscribedToInAppMessageEvents()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-braze-in-app-message-manager/ensure-subscribed-to-in-app-message-events.html): ```java BrazeInAppMessageManager.getInstance().ensureSubscribedToInAppMessageEvents(context); ``` ```kotlin BrazeInAppMessageManager.getInstance().ensureSubscribedToInAppMessageEvents(context) ``` In every activity where in-app messages can be shown, call [`registerInAppMessageManager()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-braze-in-app-message-manager/register-in-app-message-manager.html) in that activity's `onResume()`: ```java @Override public void onResume() { super.onResume(); // Registers the BrazeInAppMessageManager for the current Activity. This Activity will now listen for // in-app messages from Braze. BrazeInAppMessageManager.getInstance().registerInAppMessageManager(activity); } ``` ```kotlin public override fun onResume() { super.onResume() // Registers the BrazeInAppMessageManager for the current Activity. This Activity will now listen for // in-app messages from Braze. BrazeInAppMessageManager.getInstance().registerInAppMessageManager(this) } ``` In every activity where [`registerInAppMessageManager()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-braze-in-app-message-manager/register-in-app-message-manager.html) was called, call [`unregisterInAppMessageManager()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-braze-in-app-message-manager/unregister-in-app-message-manager.html) in that activity's `onPause()`: ```java @Override public void onPause() { super.onPause(); // Unregisters the BrazeInAppMessageManager for the current Activity. BrazeInAppMessageManager.getInstance().unregisterInAppMessageManager(activity); } ``` ```kotlin public override fun onPause() { super.onPause() // Unregisters the BrazeInAppMessageManager. BrazeInAppMessageManager.getInstance().unregisterInAppMessageManager(this) } ``` ### Step 2: Update the manager's blocklist (optional) In your integration, you may require that certain activities in your app should not show in-app messages. The [activity lifecycle callback integration](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration#android_step-4-enable-user-session-tracking) provides an easy way to accomplish this. The following sample code adds two activities to the in-app message registration blocklist, `SplashActivity` and `SettingsActivity`: ```java public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Set inAppMessageBlocklist = new HashSet<>(); inAppMessageBlocklist.add(SplashActivity.class); inAppMessageBlocklist.add(SettingsActivity.class); registerActivityLifecycleCallbacks(new BrazeActivityLifecycleCallbackListener(inAppMessageBlocklist)); } } ``` ```kotlin class MyApplication : Application() { override fun onCreate() { super.onCreate() val inAppMessageBlocklist = HashSet>() inAppMessageBlocklist.add(SplashActivity::class.java) inAppMessageBlocklist.add(SettingsActivity::class.java) registerActivityLifecycleCallbacks(BrazeActivityLifecycleCallbackListener(inAppMessageBlocklist)) } } ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). You'll also need to enable in-app messages. ## Message types Each in-app message type is highly customizable across content, images, icons, click actions, analytics, display, and delivery. They are enumerated types of `Braze.InAppMessage`, which defines basic behavior and traits for all in-app messages. For the full list of in-app message properties and usage, see the [`InAppMessage` class](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage). These are the available in-app message types in Braze and how they will look like for end-users. [`Slideup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/slideup-swift.struct) in-app messages are given this name because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. ![A slideup in-app message at the bottom and the top of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/slideup-spec.png?5e0eb3225ef5a9ca264817b8267aad45){: style="max-width:35%;border:none;"} [`Modal`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modal-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-header-text.png?cef10f16ce8c681a237e5352cebf76f9){: style="max-width:35%;border:none;"} [`Modal Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modalimage-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. These messages are similar to the `Modal` type except without header or message text. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal image in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-full-image.png?2cda602759102cab22396c78978d712b){: style="max-width:35%;border:none;"} [`Full`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/full-swift.struct) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `Full` in-app message contains an image, and the lower half displays text and up to two analytics-enabled buttons. ![A fullscreen in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-header-text.png?803a758bf53c33ebc3ff63797676339b){: style="max-width:35%;border:none;"} [`Full Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/fullimage-swift.struct) in-app messages are similar to `Full` in-app messages except without header or message text. This message type is useful for maximizing the content and impact of your user communication. A `Full Image` in-app message contains an image spanning the entire screen, with the option to display up to two analytics-enabled buttons. ![A fullscreen image in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-image.png?b29bfae801d78d57fcc7c9fdcb7cc0cc){: style="max-width:35%;border:none;"} [`HTML`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/html-swift.struct) in-app messages are useful for creating fully customized user content. User-defined HTML Full in-app message content is displayed in a `WKWebView`and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality.

iOS in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Web SDK from within your HTML, see our [best practices](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/best_practices/) for more details. The following example shows a paginated HTML Full in-app message: ![An HTML in-app message with a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) Note that we currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. [`Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/control-swift.struct) in-app messages do not contain a UI component and are used primarily for analytics purposes. This type is used to verify receipt of an in-app message sent to a control group. For further details about Intelligent Selection and control groups, refer to [Intelligent Selection](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence/intelligent_selection/). ## Enabling in-app messages ### Step 1: Create an implementation of `BrazeInAppMessagePresenter` To let Braze display in-app messages, create an implementation of the `BrazeInAppMessagePresenter` protocol and assign it to the optional `inAppMessagePresenter` on your Braze instance. You can also use the default Braze UI presenter by instantiating a `BrazeInAppMessageUI` object. Note that you will need to import the `BrazeUI` library to access the `BrazeInAppMessageUI` class. ```swift AppDelegate.braze?.inAppMessagePresenter = BrazeInAppMessageUI() ``` ```objc AppDelegate.braze.inAppMessagePresenter = [[BrazeInAppMessageUI alloc] init]; ``` ### Step 2: Handle no matching triggers Implement [`BrazeDelegate.(_:noMatchingTriggerForEvent)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazedelegate/braze(_:nomatchingtriggerforevent:)-8rt7y/) within the relevant `BrazeDelegate` class. When Braze fails to find a matching trigger for a particular event, it will call this method automatically. ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## About TV and OTT support The Android Braze SDK natively supports displaying in-app messages on OTT devices like Android TV or Fire Stick. However, there's some key differences between native Android and OTT in-app messages. For OTT devices: - In-app messages that require touch mode, such as slideup, are disabled on OTT. - The currently selected or focused item, such as a button or close button, will be highlighted. - Body clicks on the in-app message itself, such as not on a button, are not supported. ## Prerequisites Before you can use this feature, you'll need to [integrate the Cordova Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=cordova). ## Message types Braze offers several default in-app message types, each customizable with messages, images, [Font Awesome](https://fontawesome.com/icons?d=gallery&p=2) icons, click actions, analytics, color schemes, and more. Their basic behavior and traits are defined by the [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html) interface, in a subclass called [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). `IInAppMessage` also includes a subinterface, [`IInAppMessageImmersive`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-immersive/index.html), which lets you add close, click-action, and analytics [buttons](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-message-button/index.html) to your app. **Important:** Keep in mind, in-app messages containing buttons will include the `clickAction` message in the final payload if the click action is added prior to adding the button text. [`slideup`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-slideup/index.html) in-app messages are so-named because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. The `slideup` in-app message object extends [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). ![An in-app message sliding from the bottom of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the bottom right corner of a web page.](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`modal`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-modal/index.html) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with two click-action and analytics-enabled buttons. This message type is a subclass of [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), an abstract class that implements `IInAppMessageImmersive`, giving you the option to add custom functionality to your locally generated in-app messages. ![A modal in-app message in the center of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`full`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-full/index.html) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `full` in-app message contains an image, and the lower half displays text and up to two click action and analytics-enabled buttons. This message type extends [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), giving you the option to add custom functionality to your locally generated in-app messages. ![A full screen in-app message shown across an entire phone screen displaying, "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed largely in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img_archive/In-App_Full.png?ecd62a88d38438aaebbda4cdcc22aa00) [`HTML`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-html/index.html) in-app messages are useful for creating fully customized user content. User-defined HTML in-app message content is displayed in a `WebView` and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality. This message type implements [`IInAppMessageHtml`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-html/index.html), which is a subclass of [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html). **Note:** On Android, links configured with `target="_blank"` in custom HTML in-app messages open in the device's default web browser. Android in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Android SDK from within your HTML, see our JavaScript bridge page for more details. ![An HTML in-app message with the a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} **Important:** We currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. **Tip:** You can also define custom in-app message views for your app. For a full walkthrough, see [Setting custom factories](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization#android_setting-custom-factories). Each in-app message type is highly customizable across content, images, icons, click actions, analytics, display, and delivery. They are enumerated types of `Braze.InAppMessage`, which defines basic behavior and traits for all in-app messages. For the full list of in-app message properties and usage, see the [`InAppMessage` class](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage). These are the available in-app message types in Braze and how they will look like for end-users. [`Slideup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/slideup-swift.struct) in-app messages are given this name because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. ![A slideup in-app message at the bottom and the top of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/slideup-spec.png?5e0eb3225ef5a9ca264817b8267aad45){: style="max-width:35%;border:none;"} [`Modal`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modal-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-header-text.png?cef10f16ce8c681a237e5352cebf76f9){: style="max-width:35%;border:none;"} [`Modal Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modalimage-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. These messages are similar to the `Modal` type except without header or message text. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal image in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-full-image.png?2cda602759102cab22396c78978d712b){: style="max-width:35%;border:none;"} [`Full`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/full-swift.struct) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `Full` in-app message contains an image, and the lower half displays text and up to two analytics-enabled buttons. ![A fullscreen in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-header-text.png?803a758bf53c33ebc3ff63797676339b){: style="max-width:35%;border:none;"} [`Full Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/fullimage-swift.struct) in-app messages are similar to `Full` in-app messages except without header or message text. This message type is useful for maximizing the content and impact of your user communication. A `Full Image` in-app message contains an image spanning the entire screen, with the option to display up to two analytics-enabled buttons. ![A fullscreen image in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-image.png?b29bfae801d78d57fcc7c9fdcb7cc0cc){: style="max-width:35%;border:none;"} [`HTML`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/html-swift.struct) in-app messages are useful for creating fully customized user content. User-defined HTML Full in-app message content is displayed in a `WKWebView`and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality.

iOS in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Web SDK from within your HTML, see our [best practices](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/best_practices/) for more details. The following example shows a paginated HTML Full in-app message: ![An HTML in-app message with a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) Note that we currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. [`Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/control-swift.struct) in-app messages do not contain a UI component and are used primarily for analytics purposes. This type is used to verify receipt of an in-app message sent to a control group. For further details about Intelligent Selection and control groups, refer to [Intelligent Selection](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence/intelligent_selection/). ## Prerequisites Before you can use this feature, you'll need to [integrate the Flutter Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=flutter). ## Message types Braze offers several default in-app message types, each customizable with messages, images, [Font Awesome](https://fontawesome.com/icons?d=gallery&p=2) icons, click actions, analytics, color schemes, and more. Their basic behavior and traits are defined by the [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html) interface, in a subclass called [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). `IInAppMessage` also includes a subinterface, [`IInAppMessageImmersive`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-immersive/index.html), which lets you add close, click-action, and analytics [buttons](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-message-button/index.html) to your app. **Important:** Keep in mind, in-app messages containing buttons will include the `clickAction` message in the final payload if the click action is added prior to adding the button text. [`slideup`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-slideup/index.html) in-app messages are so-named because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. The `slideup` in-app message object extends [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). ![An in-app message sliding from the bottom of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the bottom right corner of a web page.](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`modal`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-modal/index.html) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with two click-action and analytics-enabled buttons. This message type is a subclass of [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), an abstract class that implements `IInAppMessageImmersive`, giving you the option to add custom functionality to your locally generated in-app messages. ![A modal in-app message in the center of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`full`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-full/index.html) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `full` in-app message contains an image, and the lower half displays text and up to two click action and analytics-enabled buttons. This message type extends [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), giving you the option to add custom functionality to your locally generated in-app messages. ![A full screen in-app message shown across an entire phone screen displaying, "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed largely in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img_archive/In-App_Full.png?ecd62a88d38438aaebbda4cdcc22aa00) [`HTML`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-html/index.html) in-app messages are useful for creating fully customized user content. User-defined HTML in-app message content is displayed in a `WebView` and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality. This message type implements [`IInAppMessageHtml`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-html/index.html), which is a subclass of [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html). **Note:** On Android, links configured with `target="_blank"` in custom HTML in-app messages open in the device's default web browser. Android in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Android SDK from within your HTML, see our JavaScript bridge page for more details. ![An HTML in-app message with the a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} **Important:** We currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. **Tip:** You can also define custom in-app message views for your app. For a full walkthrough, see [Setting custom factories](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization#android_setting-custom-factories). Each in-app message type is highly customizable across content, images, icons, click actions, analytics, display, and delivery. They are enumerated types of `Braze.InAppMessage`, which defines basic behavior and traits for all in-app messages. For the full list of in-app message properties and usage, see the [`InAppMessage` class](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage). These are the available in-app message types in Braze and how they will look like for end-users. [`Slideup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/slideup-swift.struct) in-app messages are given this name because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. ![A slideup in-app message at the bottom and the top of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/slideup-spec.png?5e0eb3225ef5a9ca264817b8267aad45){: style="max-width:35%;border:none;"} [`Modal`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modal-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-header-text.png?cef10f16ce8c681a237e5352cebf76f9){: style="max-width:35%;border:none;"} [`Modal Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modalimage-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. These messages are similar to the `Modal` type except without header or message text. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal image in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-full-image.png?2cda602759102cab22396c78978d712b){: style="max-width:35%;border:none;"} [`Full`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/full-swift.struct) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `Full` in-app message contains an image, and the lower half displays text and up to two analytics-enabled buttons. ![A fullscreen in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-header-text.png?803a758bf53c33ebc3ff63797676339b){: style="max-width:35%;border:none;"} [`Full Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/fullimage-swift.struct) in-app messages are similar to `Full` in-app messages except without header or message text. This message type is useful for maximizing the content and impact of your user communication. A `Full Image` in-app message contains an image spanning the entire screen, with the option to display up to two analytics-enabled buttons. ![A fullscreen image in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-image.png?b29bfae801d78d57fcc7c9fdcb7cc0cc){: style="max-width:35%;border:none;"} [`HTML`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/html-swift.struct) in-app messages are useful for creating fully customized user content. User-defined HTML Full in-app message content is displayed in a `WKWebView`and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality.

iOS in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Web SDK from within your HTML, see our [best practices](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/best_practices/) for more details. The following example shows a paginated HTML Full in-app message: ![An HTML in-app message with a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) Note that we currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. [`Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/control-swift.struct) in-app messages do not contain a UI component and are used primarily for analytics purposes. This type is used to verify receipt of an in-app message sent to a control group. For further details about Intelligent Selection and control groups, refer to [Intelligent Selection](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence/intelligent_selection/). ## Enabling in-app messages The Braze Flutter SDK automatically sets up the default in-app message presenter on both Android and iOS. In-app messages are displayed and forwarded to the Dart layer without additional setup. ### Customizing the in-app message presenter on iOS To override the default in-app message presenter on iOS, use the `postInitialization` closure in `BrazePlugin.configure(_:postInitialization:)`. Your custom presenter must call `BrazePlugin.processInAppMessage(message)` to forward in-app message data to the Dart layer. ```swift import BrazeUI BrazePlugin.configure( { configuration in // Set non-API-key configurations here. }, postInitialization: { braze in let customPresenter = CustomInAppMessagePresenter() braze.inAppMessagePresenter = customPresenter } ) ``` In the custom presenter class, call `BrazePlugin.processInAppMessage(message)` and `super.present(message: message)` to forward data to Dart and display the default UI. ```swift class CustomInAppMessagePresenter: BrazeInAppMessageUI { override func present(message: Braze.InAppMessage) { BrazePlugin.processInAppMessage(message) super.present(message: message) } } ``` **Note:** This step is for iOS only. The default implementation for in-app messages is already set up on Android. To set up the default presenter for in-app messages on iOS, create an implementation of the `BrazeInAppMessagePresenter` protocol and assign it to the optional `inAppMessagePresenter` on your Braze instance. You can also use the default Braze UI presenter by instantiating a `BrazeInAppMessageUI` object. You must import the `BrazeUI` library to access the `BrazeInAppMessageUI` class. ```swift import BrazeUI override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil ) -> Bool { ... let braze = BrazePlugin.initBraze(configuration) braze.inAppMessagePresenter = BrazeInAppMessageUI() AppDelegate.braze = braze return true } ``` ```objc @import BrazeUI; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... Braze *braze = [BrazePlugin initBraze:configuration]; braze.inAppMessagePresenter = [[BrazeInAppMessageUI alloc] init]; AppDelegate.braze = braze; [self.window makeKeyAndVisible]; return YES; } ``` For more information about accessing in-app message data, refer to [Logging in-app message data](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/logging_message_data?sdktab=flutter). ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Message types Braze offers several default in-app message types, each customizable with messages, images, [Font Awesome](https://fontawesome.com/icons?d=gallery&p=2) icons, click actions, analytics, color schemes, and more. Their basic behavior and traits are defined by the [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html) interface, in a subclass called [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). `IInAppMessage` also includes a subinterface, [`IInAppMessageImmersive`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-immersive/index.html), which lets you add close, click-action, and analytics [buttons](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-message-button/index.html) to your app. **Important:** Keep in mind, in-app messages containing buttons will include the `clickAction` message in the final payload if the click action is added prior to adding the button text. [`slideup`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-slideup/index.html) in-app messages are so-named because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. The `slideup` in-app message object extends [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). ![An in-app message sliding from the bottom of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the bottom right corner of a web page.](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`modal`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-modal/index.html) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with two click-action and analytics-enabled buttons. This message type is a subclass of [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), an abstract class that implements `IInAppMessageImmersive`, giving you the option to add custom functionality to your locally generated in-app messages. ![A modal in-app message in the center of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`full`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-full/index.html) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `full` in-app message contains an image, and the lower half displays text and up to two click action and analytics-enabled buttons. This message type extends [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), giving you the option to add custom functionality to your locally generated in-app messages. ![A full screen in-app message shown across an entire phone screen displaying, "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed largely in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img_archive/In-App_Full.png?ecd62a88d38438aaebbda4cdcc22aa00) [`HTML`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-html/index.html) in-app messages are useful for creating fully customized user content. User-defined HTML in-app message content is displayed in a `WebView` and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality. This message type implements [`IInAppMessageHtml`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-html/index.html), which is a subclass of [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html). **Note:** On Android, links configured with `target="_blank"` in custom HTML in-app messages open in the device's default web browser. Android in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Android SDK from within your HTML, see our JavaScript bridge page for more details. ![An HTML in-app message with the a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} **Important:** We currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. **Tip:** You can also define custom in-app message views for your app. For a full walkthrough, see [Setting custom factories](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization#android_setting-custom-factories). Each in-app message type is highly customizable across content, images, icons, click actions, analytics, display, and delivery. They are enumerated types of `Braze.InAppMessage`, which defines basic behavior and traits for all in-app messages. For the full list of in-app message properties and usage, see the [`InAppMessage` class](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage). These are the available in-app message types in Braze and how they will look like for end-users. [`Slideup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/slideup-swift.struct) in-app messages are given this name because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. ![A slideup in-app message at the bottom and the top of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/slideup-spec.png?5e0eb3225ef5a9ca264817b8267aad45){: style="max-width:35%;border:none;"} [`Modal`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modal-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-header-text.png?cef10f16ce8c681a237e5352cebf76f9){: style="max-width:35%;border:none;"} [`Modal Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modalimage-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. These messages are similar to the `Modal` type except without header or message text. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal image in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-full-image.png?2cda602759102cab22396c78978d712b){: style="max-width:35%;border:none;"} [`Full`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/full-swift.struct) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `Full` in-app message contains an image, and the lower half displays text and up to two analytics-enabled buttons. ![A fullscreen in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-header-text.png?803a758bf53c33ebc3ff63797676339b){: style="max-width:35%;border:none;"} [`Full Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/fullimage-swift.struct) in-app messages are similar to `Full` in-app messages except without header or message text. This message type is useful for maximizing the content and impact of your user communication. A `Full Image` in-app message contains an image spanning the entire screen, with the option to display up to two analytics-enabled buttons. ![A fullscreen image in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-image.png?b29bfae801d78d57fcc7c9fdcb7cc0cc){: style="max-width:35%;border:none;"} [`HTML`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/html-swift.struct) in-app messages are useful for creating fully customized user content. User-defined HTML Full in-app message content is displayed in a `WKWebView`and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality.

iOS in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Web SDK from within your HTML, see our [best practices](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/best_practices/) for more details. The following example shows a paginated HTML Full in-app message: ![An HTML in-app message with a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) Note that we currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. [`Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/control-swift.struct) in-app messages do not contain a UI component and are used primarily for analytics purposes. This type is used to verify receipt of an in-app message sent to a control group. For further details about Intelligent Selection and control groups, refer to [Intelligent Selection](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence/intelligent_selection/). ## Data model The in-app message model is available in the React Native SDK. Braze has four in-app message types that share the same data model: **slideup**, **modal**, **full** and **HTML full**. ### Messages The in-app message model provides the base for all in-app messages. |Property | Description | |------------------|------------------------------------------------------------------------------------------------------------------------| |`inAppMessageJsonString` | The message JSON representation. | |`message` | The message text. | |`header` | The message header. | |`uri` | The URI associated with the button click action. | |`imageUrl` | The message image URL. | |`zippedAssetsUrl` | The zipped assets prepared to display HTML content. | |`useWebView` | Indicates whether the button click action should redirect using a web view. | |`duration` | The message display duration. | |`clickAction` | The button click action type. The types are: `URI`, and `NONE`. | |`dismissType` | The message close type. The two types are: `SWIPE` and `AUTO_DISMISS`. | |`messageType` | The in-app message type supported by the SDK. The four types are: `SLIDEUP`, `MODAL`, `FULL` and `HTML_FULL`. | |`extras` | The message extras dictionary. Default value: `[:]`. | |`buttons` | The list of buttons on the in-app message. | |`toString()` | The message as a String representation. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Messages" } For a full reference of the in-app message model, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage) documentation. ### Buttons Buttons can be added to in-app messages to perform actions and log analytics. The button model provides the base for all in-app message buttons. |Property | Description | |------------------|-----------------------------------------------------------------------------------------------------------------------------| |`text` | The text on the button. | |`uri` | The URI associated with the button click action. | |`useWebView` | Indicates whether the button click action should redirect using a web view. | |`clickAction` | The type of click action processed when the user clicks on the button. The types are: `URI`, and `NONE`. | |`id` | The button ID on the message. | |`toString()` | The button as a String representation. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Buttons" } For a full reference of button model, see the [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-message-button/index.html) and [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/button) documentation. ## Prerequisites Before you can use this feature, you'll need to [integrate the Roku Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=roku). Additionally, in-app messages will only be sent to Roku devices running the minimum supported SDK version: ## Message types Braze offers several default in-app message types, each customizable with messages, images, [Font Awesome](https://fontawesome.com/icons?d=gallery&p=2) icons, click actions, analytics, color schemes, and more. Their basic behavior and traits are defined by the [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html) interface, in a subclass called [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). `IInAppMessage` also includes a subinterface, [`IInAppMessageImmersive`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-immersive/index.html), which lets you add close, click-action, and analytics [buttons](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-message-button/index.html) to your app. **Important:** Keep in mind, in-app messages containing buttons will include the `clickAction` message in the final payload if the click action is added prior to adding the button text. [`slideup`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-slideup/index.html) in-app messages are so-named because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. The `slideup` in-app message object extends [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). ![An in-app message sliding from the bottom of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the bottom right corner of a web page.](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`modal`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-modal/index.html) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with two click-action and analytics-enabled buttons. This message type is a subclass of [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), an abstract class that implements `IInAppMessageImmersive`, giving you the option to add custom functionality to your locally generated in-app messages. ![A modal in-app message in the center of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`full`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-full/index.html) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `full` in-app message contains an image, and the lower half displays text and up to two click action and analytics-enabled buttons. This message type extends [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), giving you the option to add custom functionality to your locally generated in-app messages. ![A full screen in-app message shown across an entire phone screen displaying, "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed largely in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img_archive/In-App_Full.png?ecd62a88d38438aaebbda4cdcc22aa00) [`HTML`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-html/index.html) in-app messages are useful for creating fully customized user content. User-defined HTML in-app message content is displayed in a `WebView` and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality. This message type implements [`IInAppMessageHtml`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-html/index.html), which is a subclass of [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html). **Note:** On Android, links configured with `target="_blank"` in custom HTML in-app messages open in the device's default web browser. Android in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Android SDK from within your HTML, see our JavaScript bridge page for more details. ![An HTML in-app message with the a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} **Important:** We currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. **Tip:** You can also define custom in-app message views for your app. For a full walkthrough, see [Setting custom factories](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization#android_setting-custom-factories). Each in-app message type is highly customizable across content, images, icons, click actions, analytics, display, and delivery. They are enumerated types of `Braze.InAppMessage`, which defines basic behavior and traits for all in-app messages. For the full list of in-app message properties and usage, see the [`InAppMessage` class](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage). These are the available in-app message types in Braze and how they will look like for end-users. [`Slideup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/slideup-swift.struct) in-app messages are given this name because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. ![A slideup in-app message at the bottom and the top of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/slideup-spec.png?5e0eb3225ef5a9ca264817b8267aad45){: style="max-width:35%;border:none;"} [`Modal`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modal-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-header-text.png?cef10f16ce8c681a237e5352cebf76f9){: style="max-width:35%;border:none;"} [`Modal Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modalimage-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. These messages are similar to the `Modal` type except without header or message text. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal image in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-full-image.png?2cda602759102cab22396c78978d712b){: style="max-width:35%;border:none;"} [`Full`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/full-swift.struct) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `Full` in-app message contains an image, and the lower half displays text and up to two analytics-enabled buttons. ![A fullscreen in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-header-text.png?803a758bf53c33ebc3ff63797676339b){: style="max-width:35%;border:none;"} [`Full Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/fullimage-swift.struct) in-app messages are similar to `Full` in-app messages except without header or message text. This message type is useful for maximizing the content and impact of your user communication. A `Full Image` in-app message contains an image spanning the entire screen, with the option to display up to two analytics-enabled buttons. ![A fullscreen image in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-image.png?b29bfae801d78d57fcc7c9fdcb7cc0cc){: style="max-width:35%;border:none;"} [`HTML`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/html-swift.struct) in-app messages are useful for creating fully customized user content. User-defined HTML Full in-app message content is displayed in a `WKWebView`and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality.

iOS in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Web SDK from within your HTML, see our [best practices](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/best_practices/) for more details. The following example shows a paginated HTML Full in-app message: ![An HTML in-app message with a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) Note that we currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. [`Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/control-swift.struct) in-app messages do not contain a UI component and are used primarily for analytics purposes. This type is used to verify receipt of an in-app message sent to a control group. For further details about Intelligent Selection and control groups, refer to [Intelligent Selection](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence/intelligent_selection/). ## Enabling in-app messages ### Step 1: Add an observer To process in-app messages, you can add an observer on `BrazeTask.BrazeInAppMessage`: ```brightscript m.BrazeTask.observeField("BrazeInAppMessage", "onInAppMessageReceived") ``` ### Step 2: Access triggered messages Then within your handler, you have access to the highest in-app message that your campaigns have triggered: ```brightscript sub onInAppMessageReceived() in_app_message = m.BrazeTask.BrazeInAppMessage ... end sub ``` ## Message fields ### Handling The following lists the fields you will need to handle your in-app messages: | Fields | Description | | ------ | ----------- | | `buttons` | List of buttons (could be an empty list). | | `click_action` | `"URI"` or `"NONE"`. Use this field to indicate whether the in-app message should open to a URI link or close the message when clicked. When there are no buttons, this should happen when the user clicks "OK" when the in-app message is displayed. | | `dismiss_type` | `"AUTO_DISMISS"` or `"SWIPE"`. Use this field to indicate whether your in-app message will auto dismiss or require a swipe to dismiss. | | `display_delay` | How long (seconds) to wait until displaying the in-app message. | | `duration` | How long (milliseconds) the message should be displayed when `dismiss_type` is set to `"AUTO_DISMISS"`. | | `extras` | Key-value pairs. | | `header` | The header text. | | `id` | The ID used to log impressions or clicks. | | `image_url` | In-app message image URL. | | `message` | Message body text. | | `uri` | Your URI users will be sent to based on your `click_action`. This field must be included when `click_action` is `"URI"`. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Handling" } **Important:** For in-app messages containing buttons, the message `click_action` will also be included in the final payload if the click action is added prior to adding the button text. ### Styling There are also various styling fields that you could choose to use from the dashboard: | Fields | Description | | ------ | ----------- | | `bg_color` | Background color. | | `close_button_color` | Close button color. | | `frame_color` | The color of the background screen overlay. | | `header_text_color` | Header text color. | | `message_text_color` | Message text color. | | `text_align` | "START", "CENTER", or "END". Your selected text alignment. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Styling" } Alternatively, you could implement the in-app message and style it within your Roku application using a standard palette: ### Buttons | Fields | Description | | ------ | ----------- | | `click_action` | `"URI"` or `"NONE"`. Use this field to indicate whether the in-app message should open to a URI link or close the message when clicked. | | `id` | The ID value of the button itself. | | `text` | The text to display on the button. | | `uri` | Your URI users will be sent to based on your `click_action`. This field must be included when `click_action` is `"URI"`. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Buttons" } **Important:** Keep in mind, you'll need to implement your own custom UI since in-app messaging is supported via headless UI using the Swift SDK—which does not include any default UI or views for tvOS. ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). ## Enabling in-app messages ### Step 1: Create a new iOS app In Braze, select **Settings** > **App Settings**, then select **Add App**. Enter a name for your tvOS app, select **iOS**—_not tvOS_—then select **Add App**. ![ALT_TEXT.](https://www.braze.com/docs/ja/ja/assets/img/tvos.png?d1c5036d5b83f425591adb03556ca684){: style="width:70%"} **Warning:** If you select the **tvOS** checkbox, you will not be able to customize in-app messages for tvOS. ### Step 2: Get your app's API key In your app settings, select your new tvOS app then take note of your app's API key. You'll use this key to configure your app in Xcode. ![ALT_TEXT](https://www.braze.com/docs/ja/ja/assets/img/tvos1.png?9851deb799c1c88a248f97bd284c91cb){: style="width:70%"} ### Step 3: Integrate BrazeKit Use your app's API key to integrate the [Braze Swift SDK](https://github.com/braze-inc/braze-swift-sdk) into your tvOS project in Xcode. You only need to integrate BrazeKit from the Braze Swift SDK. ### Step 4: Create your custom UI Because Braze doesn't provide a default UI for in-app messages on tvOS, you'll need to customize it yourself. For a full walkthrough, see our step-by-step tutorial: [Customizing in-app messages for tvOS](https://braze-inc.github.io/braze-swift-sdk/documentation/braze/in-app-message-customization). For a sample project, see [Braze Swift SDK samples](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples#inappmessages-custom-ui). ## Prerequisites Before you can use this feature, you'll need to [integrate the Unity Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=unity). ## Message types Braze offers several default in-app message types, each customizable with messages, images, [Font Awesome](https://fontawesome.com/icons?d=gallery&p=2) icons, click actions, analytics, color schemes, and more. Their basic behavior and traits are defined by the [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html) interface, in a subclass called [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). `IInAppMessage` also includes a subinterface, [`IInAppMessageImmersive`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-immersive/index.html), which lets you add close, click-action, and analytics [buttons](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-message-button/index.html) to your app. **Important:** Keep in mind, in-app messages containing buttons will include the `clickAction` message in the final payload if the click action is added prior to adding the button text. [`slideup`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-slideup/index.html) in-app messages are so-named because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. The `slideup` in-app message object extends [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). ![An in-app message sliding from the bottom of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the bottom right corner of a web page.](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`modal`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-modal/index.html) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with two click-action and analytics-enabled buttons. This message type is a subclass of [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), an abstract class that implements `IInAppMessageImmersive`, giving you the option to add custom functionality to your locally generated in-app messages. ![A modal in-app message in the center of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`full`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-full/index.html) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `full` in-app message contains an image, and the lower half displays text and up to two click action and analytics-enabled buttons. This message type extends [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), giving you the option to add custom functionality to your locally generated in-app messages. ![A full screen in-app message shown across an entire phone screen displaying, "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed largely in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img_archive/In-App_Full.png?ecd62a88d38438aaebbda4cdcc22aa00) [`HTML`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-html/index.html) in-app messages are useful for creating fully customized user content. User-defined HTML in-app message content is displayed in a `WebView` and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality. This message type implements [`IInAppMessageHtml`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-html/index.html), which is a subclass of [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html). **Note:** On Android, links configured with `target="_blank"` in custom HTML in-app messages open in the device's default web browser. Android in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Android SDK from within your HTML, see our JavaScript bridge page for more details. ![An HTML in-app message with the a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} **Important:** We currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. **Tip:** You can also define custom in-app message views for your app. For a full walkthrough, see [Setting custom factories](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization#android_setting-custom-factories). Each in-app message type is highly customizable across content, images, icons, click actions, analytics, display, and delivery. They are enumerated types of `Braze.InAppMessage`, which defines basic behavior and traits for all in-app messages. For the full list of in-app message properties and usage, see the [`InAppMessage` class](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage). These are the available in-app message types in Braze and how they will look like for end-users. [`Slideup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/slideup-swift.struct) in-app messages are given this name because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. ![A slideup in-app message at the bottom and the top of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/slideup-spec.png?5e0eb3225ef5a9ca264817b8267aad45){: style="max-width:35%;border:none;"} [`Modal`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modal-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-header-text.png?cef10f16ce8c681a237e5352cebf76f9){: style="max-width:35%;border:none;"} [`Modal Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modalimage-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. These messages are similar to the `Modal` type except without header or message text. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal image in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-full-image.png?2cda602759102cab22396c78978d712b){: style="max-width:35%;border:none;"} [`Full`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/full-swift.struct) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `Full` in-app message contains an image, and the lower half displays text and up to two analytics-enabled buttons. ![A fullscreen in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-header-text.png?803a758bf53c33ebc3ff63797676339b){: style="max-width:35%;border:none;"} [`Full Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/fullimage-swift.struct) in-app messages are similar to `Full` in-app messages except without header or message text. This message type is useful for maximizing the content and impact of your user communication. A `Full Image` in-app message contains an image spanning the entire screen, with the option to display up to two analytics-enabled buttons. ![A fullscreen image in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-image.png?b29bfae801d78d57fcc7c9fdcb7cc0cc){: style="max-width:35%;border:none;"} [`HTML`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/html-swift.struct) in-app messages are useful for creating fully customized user content. User-defined HTML Full in-app message content is displayed in a `WKWebView`and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality.

iOS in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Web SDK from within your HTML, see our [best practices](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/best_practices/) for more details. The following example shows a paginated HTML Full in-app message: ![An HTML in-app message with a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) Note that we currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. [`Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/control-swift.struct) in-app messages do not contain a UI component and are used primarily for analytics purposes. This type is used to verify receipt of an in-app message sent to a control group. For further details about Intelligent Selection and control groups, refer to [Intelligent Selection](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence/intelligent_selection/). ## Prerequisites Before you can use this feature, you'll need to [integrate the .NET MAUI Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=.net%20maui%20(xamarin)). ## Message types Braze offers several default in-app message types, each customizable with messages, images, [Font Awesome](https://fontawesome.com/icons?d=gallery&p=2) icons, click actions, analytics, color schemes, and more. Their basic behavior and traits are defined by the [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html) interface, in a subclass called [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). `IInAppMessage` also includes a subinterface, [`IInAppMessageImmersive`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-immersive/index.html), which lets you add close, click-action, and analytics [buttons](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-message-button/index.html) to your app. **Important:** Keep in mind, in-app messages containing buttons will include the `clickAction` message in the final payload if the click action is added prior to adding the button text. [`slideup`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-slideup/index.html) in-app messages are so-named because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. The `slideup` in-app message object extends [`InAppMessageBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-base/index.html). ![An in-app message sliding from the bottom of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the bottom right corner of a web page.](https://www.braze.com/docs/ja/ja/assets/img/slideup-behavior.gif?7239589ee8c964f354440e07ca4b9db1){: style="border:0px;"} [`modal`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-modal/index.html) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with two click-action and analytics-enabled buttons. This message type is a subclass of [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), an abstract class that implements `IInAppMessageImmersive`, giving you the option to add custom functionality to your locally generated in-app messages. ![A modal in-app message in the center of a phone screen displaying "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img/modal-behavior.gif?00fa4f83404c611c82cb0816f682e3f3){: style="border:0px;"} [`full`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-full/index.html) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `full` in-app message contains an image, and the lower half displays text and up to two click action and analytics-enabled buttons. This message type extends [`InAppMessageImmersiveBase`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-immersive-base/index.html), giving you the option to add custom functionality to your locally generated in-app messages. ![A full screen in-app message shown across an entire phone screen displaying, "Humans are complicated. Custom engagement shouldn't be." In the background is the same in-app message displayed largely in the center of a web page.](https://www.braze.com/docs/ja/ja/assets/img_archive/In-App_Full.png?ecd62a88d38438aaebbda4cdcc22aa00) [`HTML`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-in-app-message-html/index.html) in-app messages are useful for creating fully customized user content. User-defined HTML in-app message content is displayed in a `WebView` and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality. This message type implements [`IInAppMessageHtml`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-html/index.html), which is a subclass of [`IInAppMessage`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html). **Note:** On Android, links configured with `target="_blank"` in custom HTML in-app messages open in the device's default web browser. Android in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Android SDK from within your HTML, see our JavaScript bridge page for more details. ![An HTML in-app message with the a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-behavior.gif?b47edcbdd910efce932489d1fa592bd0){: style="border:0px;"} **Important:** We currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. **Tip:** You can also define custom in-app message views for your app. For a full walkthrough, see [Setting custom factories](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization#android_setting-custom-factories). Each in-app message type is highly customizable across content, images, icons, click actions, analytics, display, and delivery. They are enumerated types of `Braze.InAppMessage`, which defines basic behavior and traits for all in-app messages. For the full list of in-app message properties and usage, see the [`InAppMessage` class](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage). These are the available in-app message types in Braze and how they will look like for end-users. [`Slideup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/slideup-swift.struct) in-app messages are given this name because they "slide up" or "slide down" from the top or bottom of the screen. They cover a small portion of the screen and provide an effective and non-intrusive messaging capability. ![A slideup in-app message at the bottom and the top of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/slideup-spec.png?5e0eb3225ef5a9ca264817b8267aad45){: style="max-width:35%;border:none;"} [`Modal`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modal-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-header-text.png?cef10f16ce8c681a237e5352cebf76f9){: style="max-width:35%;border:none;"} [`Modal Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/modalimage-swift.struct) in-app messages appear in the center of the screen and are framed by a translucent panel. These messages are similar to the `Modal` type except without header or message text. Useful for more critical messaging, they can be equipped with up to two analytics-enabled buttons. ![A modal image in-app message in the center of a phone screen.](https://www.braze.com/docs/ja/ja/assets/img/modal-full-image.png?2cda602759102cab22396c78978d712b){: style="max-width:35%;border:none;"} [`Full`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/full-swift.struct) in-app messages are useful for maximizing the content and impact of your user communication. The upper half of a `Full` in-app message contains an image, and the lower half displays text and up to two analytics-enabled buttons. ![A fullscreen in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-header-text.png?803a758bf53c33ebc3ff63797676339b){: style="max-width:35%;border:none;"} [`Full Image`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/fullimage-swift.struct) in-app messages are similar to `Full` in-app messages except without header or message text. This message type is useful for maximizing the content and impact of your user communication. A `Full Image` in-app message contains an image spanning the entire screen, with the option to display up to two analytics-enabled buttons. ![A fullscreen image in-app message shown across an entire phone screen.](https://www.braze.com/docs/ja/ja/assets/img/full-screen-image.png?b29bfae801d78d57fcc7c9fdcb7cc0cc){: style="max-width:35%;border:none;"} [`HTML`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/html-swift.struct) in-app messages are useful for creating fully customized user content. User-defined HTML Full in-app message content is displayed in a `WKWebView`and may optionally contain other rich content, such as images and fonts, allowing for full control over message appearance and functionality.

iOS in-app messages support a JavaScript `brazeBridge` interface to call methods on the Braze Web SDK from within your HTML, see our [best practices](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/best_practices/) for more details. The following example shows a paginated HTML Full in-app message: ![An HTML in-app message with a carousel of content and interactive buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-html-full-iam.gif?4c6c9603065d4c430d406677e8cb6045) Note that we currently do not support the display of custom HTML in-app messages in an iFrame on the iOS and Android platforms. [`Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/control-swift.struct) in-app messages do not contain a UI component and are used primarily for analytics purposes. This type is used to verify receipt of an in-app message sent to a control group. For further details about Intelligent Selection and control groups, refer to [Intelligent Selection](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence/intelligent_selection/). ## 次のステップ もっと深く潜る準備はできているか?これらのステップバイステップのチュートリアルを見てみろ: - [トリガーメッセージを遅延させたり復元したり](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/tutorials/deferring_triggered_messages)することで、メッセージ配信のタイミングを微調整する。 - [条件付き表示ルールを設定](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/tutorials/conditionally_displaying_messages)することで、メッセージのターゲティングを精緻化する。 - [キーと値のペアでメッセージのスタイルをカスタマイズし](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/tutorials/customizing_message_styling)、ブランドの見た目に合わせるのだ。 # Braze SDKのアプリ内メッセージをカスタマイズする Source: /docs/ja/developer_guide/in_app_messages/customization/index.md # アプリ内メッセージをカスタマイズする > Braze SDKのアプリ内メッセージをカスタマイズする方法を学習。高度なスタイル設定については、[キーと値のペアを使ってメッセージのスタイルをカスタマイズする](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/tutorials/customizing_message_styling)チュートリアルを参照せよ。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ## Custom styles Braze UI elements come with a default look and feel that create a neutral in-app message experience and aim for consistency with other Braze mobile platforms. The default Braze styles are defined in CSS within the Braze SDK. ### Setting a default style By overriding selected styles in your application, you can customize our standard in-app message types with your own background images, font families, styles, sizes, animations, and more. For instance, the following is an example override that will cause an in-app message's headers to appear italicized: ```css body .ab-in-app-message .ab-message-header { font-style: italic; } ``` See the [JSDocs](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.inappmessage.html) for more information. ### Customizing the z-index By default, in-app messages are displayed using `z-index: 9001`. This is configurable using the `inAppMessageZIndex ` [initialization option](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initializationoptions) in the scenario that your website styles elements with higher values than that. ```javascript braze.initialize("YOUR-API-KEY", { baseUrl: "YOUR-API-ENDPOINT", inAppMessageZIndex: 12000 }); ``` **Important:** This feature is only available for Web Braze SDK v3.3.0 and later. ## Customizing message dismissals By default, when an in-app message is showing, pressing the escape button or a click on the grayed-out background of the page will dismiss the message. Configure the `requireExplicitInAppMessageDismissal` [initialization option](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initializationoptions) to `true` to prevent this behavior and require an explicit button click to dismiss messages. ```javascript import * as braze from "@braze/web-sdk"; braze.initialize("YOUR-API-KEY", { baseUrl: "YOUR-API-ENDPOINT", requireExplicitInAppMessageDismissal: true }); ``` ## Customizing display timing To override the default display timing, remove calls to `braze.automaticallyShowInAppMessages()` and handle messages in `braze.subscribeToInAppMessage()`. Register your callback before `braze.openSession()`, so you can intercept session-start messages and decide whether to display or defer each message. By default, Braze displays in-app messages when they are triggered and eligible to display. If you need different behavior for your app experience, use a custom callback to defer or display messages based on your own logic. The following example shows how to subscribe to triggered in-app messages, defer selected messages, and display deferred messages later: ```javascript import * as braze from "@braze/web-sdk"; braze.initialize("YOUR-API-KEY", { baseUrl: "YOUR-API-ENDPOINT" }); braze.subscribeToInAppMessage(function (message) { // Control-group messages should always be "shown" to log analytics. if (message.isControl || message instanceof braze.ControlMessage) { braze.showInAppMessage(message); return; } const shouldDefer = true; // Replace with your own display logic if (shouldDefer) { braze.deferInAppMessage(message); return; } braze.showInAppMessage(message); }); braze.openSession(); // Later, when your app is ready to display a deferred message: const deferredMessage = braze.getDeferredInAppMessage(); if (deferredMessage) { braze.showInAppMessage(deferredMessage); } ``` For related delivery customization guidance, see: - [Web `deferInAppMessage` reference](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#deferinappmessage) - [Web `subscribeToInAppMessage` reference](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#subscribetoinappmessage) ## Opening links in a new tab To set your in-app message links to open in a new tab, set the `openInAppMessagesInNewTab` option to `true` to force all links from in-app message clicks open in a new tab or window. ```javascript braze.initialize('api-key', { openInAppMessagesInNewTab: true} ); ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). You'll also need to [set up in-app messages](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages). ## Setting custom manager listeners While the `BrazeInAppMessageManager` listener can automatically handle the display and lifecycle of in-app messages, you'll need to implement a custom manager listener if you'd like to fully customize your messages. The Braze SDK has a default `DefaultHtmlInAppMessageActionListener` class that is used if no custom listener is defined and takes appropriate action automatically. If you require more control over how a user interacts with different buttons inside a custom HTML in-app message, implement a custom `IHtmlInAppMessageActionListener` class. This listener applies to __both__ messages built with custom HTML and messages created using the Drag-and-Drop (DnD) editor. It does not apply to traditional IAMs. Traditional IAMs are Braze's built-in, SDK-rendered message types (for example, slideup, modal, and full) created in the original in-app message composer using predefined layouts. Unlike custom HTML and DnD IAMs, they do not run through the HTML action listener flow. If you set a custom `IHtmlInAppMessageActionListener`, its logic will override the default click behavior for _all_ DnD messages. Please ensure your marketing team is aware of this, as it may affect their campaigns in unexpected ways. ### Step 1: Implement the custom manager listener #### Step 1.1: Implement `IInAppMessageManagerListener` Create a class that implements [`IInAppMessageManagerListener`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/index.html). The callbacks in your `IInAppMessageManagerListener` will also be called at various points in the in-app message lifecycle. For example, if you set a custom manager listener when an in-app message is received from Braze, the [`beforeInAppMessageDisplayed()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/before-in-app-message-displayed.html) method will be called. If your implementation of this method returns [`InAppMessageOperation.DISCARD`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-in-app-message-operation/-d-i-s-c-a-r-d/index.html), that signals to Braze that the in-app message will be handled by the host app and should not be displayed by Braze. If [`InAppMessageOperation.DISPLAY_NOW`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-in-app-message-operation/-d-i-s-p-l-a-y_-n-o-w/index.html) is returned, Braze will attempt to display the in-app message. This method should be used if you choose to display the in-app message in a customized manner. `IInAppMessageManagerListener` also includes delegate methods for message clicks and buttons, which can be used in cases like intercepting a message when a button or message is clicked for further processing. #### Step 1.2: Hook into IAM view lifecycle methods (optional) The [`IInAppMessageManagerListener`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/index.html) interface has in-app message view methods called at distinct points in the in-app message view lifecycle. These methods are called in the following order: 1. [`beforeInAppMessageViewOpened`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/before-in-app-message-view-opened.html): Called just before the in-app message is added to the activity's view. The in-app message is not yet visible to the user at this time. 2. [`afterInAppMessageViewOpened`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/after-in-app-message-view-opened.html): Called just after the in-app message is added to the activity's view. The in-app message is now visible to the user at this time. 3. [`beforeInAppMessageViewClosed`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/before-in-app-message-view-closed.html): Called just before the in-app message is removed from the activity's view. The in-app message is still visible to the user at this time. 4. [`afterInAppMessageViewClosed`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/after-in-app-message-view-closed.html): Called just after the in-app message is removed from the activity's view. The in-app message is no longer visible to the user at this time. Note that the time between [`afterInAppMessageViewOpened`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/after-in-app-message-view-opened.html) and [`beforeInAppMessageViewClosed`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/before-in-app-message-view-closed.html) is when the in-app message view is on screen, visible to the user. **Note:** Implementation of these methods is not required. They're only provided to track and inform the in-app message view lifecycle. You can leave these method implementations empty. Create a class that implements [`IHtmlInAppMessageActionListener`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-html-in-app-message-action-listener/index.html). The callbacks in your `IHtmlInAppMessageActionListener` will be called whenever the user initiates any of the following actions inside the HTML in-app message: - Clicks on the close button - Fires a custom event - Clicks on a URL inside HTML in-app message ```java public class CustomHtmlInAppMessageActionListener implements IHtmlInAppMessageActionListener { private final Context mContext; public CustomHtmlInAppMessageActionListener(Context context) { mContext = context; } @Override public void onCloseClicked(IInAppMessage inAppMessage, String url, Bundle queryBundle) { Toast.makeText(mContext, "HTML In App Message closed", Toast.LENGTH_LONG).show(); BrazeInAppMessageManager.getInstance().hideCurrentlyDisplayingInAppMessage(false); } @Override public boolean onCustomEventFired(IInAppMessage inAppMessage, String url, Bundle queryBundle) { Toast.makeText(mContext, "Custom event fired. Ignoring.", Toast.LENGTH_LONG).show(); return true; } @Override public boolean onOtherUrlAction(IInAppMessage inAppMessage, String url, Bundle queryBundle) { Toast.makeText(mContext, "Custom url pressed: " + url + " . Ignoring", Toast.LENGTH_LONG).show(); BrazeInAppMessageManager.getInstance().hideCurrentlyDisplayingInAppMessage(false); return true; } } ``` ```kotlin class CustomHtmlInAppMessageActionListener(private val mContext: Context) : IHtmlInAppMessageActionListener { override fun onCloseClicked(inAppMessage: IInAppMessage, url: String, queryBundle: Bundle) { Toast.makeText(mContext, "HTML In App Message closed", Toast.LENGTH_LONG).show() BrazeInAppMessageManager.getInstance().hideCurrentlyDisplayingInAppMessage(false) } override fun onCustomEventFired(inAppMessage: IInAppMessage, url: String, queryBundle: Bundle): Boolean { Toast.makeText(mContext, "Custom event fired. Ignoring.", Toast.LENGTH_LONG).show() return true } override fun onOtherUrlAction(inAppMessage: IInAppMessage, url: String, queryBundle: Bundle): Boolean { Toast.makeText(mContext, "Custom url pressed: $url . Ignoring", Toast.LENGTH_LONG).show() BrazeInAppMessageManager.getInstance().hideCurrentlyDisplayingInAppMessage(false) return true } } ``` ### Step 2: Instruct Braze to use the custom manager listener After you create `IInAppMessageManagerListener`, call `BrazeInAppMessageManager.getInstance().setCustomInAppMessageManagerListener()` to instruct `BrazeInAppMessageManager` to use your custom `IInAppMessageManagerListener` instead of the default listener. Do this in your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()) before any other calls to Braze, so the custom listener is set before any in-app messages are displayed. #### Altering in-app messages before display When a new in-app message is received, and there is already an in-app message being displayed, the new message will be put onto the top of the stack and can be displayed at a later time. However, if there is no in-app message being displayed, the following delegate method in `IInAppMessageManagerListener` will be called: ```java @Override public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessage) { return InAppMessageOperation.DISPLAY_NOW; } ``` ```kotlin override fun beforeInAppMessageDisplayed(inAppMessage: IInAppMessage): InAppMessageOperation { return InAppMessageOperation.DISPLAY_NOW } ``` The `InAppMessageOperation()` return value can control when the message should be displayed. The suggested usage of this method would be to delay messages in certain parts of the app by returning `DISPLAY_LATER` when in-app messages would be distracting to the user's app experience. | `InAppMessageOperation` return value | Behavior | | -------------------------- | -------- | | `DISPLAY_NOW` | The message will be displayed | | `DISPLAY_LATER` | The message will be returned to the stack and displayed at the next available opportunity | | `DISCARD` | The message will be discarded | | `null` | The message will be ignored. This method should **NOT** return `null` | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Altering in-app messages before display" } See [`InAppMessageOperation`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-in-app-message-operation/index.html) for more details. **Tip:** If you choose to `DISCARD` the in-app message and replace it with your in-app message view, you will need to log in-app message clicks and impressions manually. On Android, this is done by calling `logClick` and `logImpression` on in-app messages and `logButtonClick` on immersive in-app messages. **Tip:** Once an in-app message has been placed on the stack, you can request for it to be retrieved and displayed at any time by calling [`BrazeInAppMessageManager.getInstance().requestDisplayInAppMessage()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-braze-in-app-message-manager/request-display-in-app-message.html). This method requests Braze to display the next available in-app message from the stack. After your `IHtmlInAppMessageActionListener` is created, call `BrazeInAppMessageManager.getInstance().setCustomHtmlInAppMessageActionListener()` to instruct `BrazeInAppMessageManager` to use your custom `IHtmlInAppMessageActionListener` instead of the default action listener. We recommend setting your `IHtmlInAppMessageActionListener` in your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()) before any other calls to Braze. This will set the custom action listener before any in-app message is displayed: ```java BrazeInAppMessageManager.getInstance().setCustomHtmlInAppMessageActionListener(new CustomHtmlInAppMessageActionListener(context)); ``` ```kotlin BrazeInAppMessageManager.getInstance().setCustomHtmlInAppMessageActionListener(CustomHtmlInAppMessageActionListener(context)) ``` ## Setting custom factories You can override a number of defaults through custom factory objects. These can be registered with the Braze SDK as needed to achieve the desired results. However, if you decide to override a factory, you'll likely need to explicitly defer to the default or reimplement the functionality provided by the Braze default. The following code snippet illustrates how to supply custom implementations of the `IInAppMessageViewFactory` and the `IInAppMessageViewWrapperFactory` interfaces. **In-app message types**
```kotlin class BrazeDemoApplication : Application(){ override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(BrazeActivityLifecycleCallbackListener(true, true)) BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewWrapperFactory(CustomInAppMessageViewWrapperFactory()) BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewFactory(CustomInAppMessageViewFactory()) } } ``` **In-app message types**
```java 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()); } } ``` Braze in-app message types are versatile enough to cover most custom use cases. However, if you want to fully define the visual appearance of your in-app messages instead of using a default type, Braze makes this possible by setting a custom view factory. The `BrazeInAppMessageManager` automatically handles placing the in-app message model into the existing activity view hierarchy by default using [`DefaultInAppMessageViewWrapper`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-default-in-app-message-view-wrapper/index.html). If you need to customize how in-app messages are placed into the view hierarchy, you should use a custom [`IInAppMessageViewWrapperFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-wrapper-factory/index.html). In-app messages have preset animation behavior. `Slideup` messages slide into the screen; `full` and `modal` messages fade in and out. If you want to define custom animation behaviors for your in-app messages, Braze makes this possible by setting up a custom animation factory. ### Step 1: Implement the factory Create a class that implements [`IInAppMessageViewFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-factory/index.html): ```java public class CustomInAppMessageViewFactory implements IInAppMessageViewFactory { @Override public View createInAppMessageView(Activity activity, IInAppMessage inAppMessage) { // Uses a custom view for slideups, modals, and full in-app messages. // HTML in-app messages and any other types will use the Braze default in-app message view factories switch (inAppMessage.getMessageType()) { case SLIDEUP: case MODAL: case FULL: // Use a custom view of your choosing return createMyCustomInAppMessageView(); default: // Use the default in-app message factories final IInAppMessageViewFactory defaultInAppMessageViewFactory = BrazeInAppMessageManager.getInstance().getDefaultInAppMessageViewFactory(inAppMessage); return defaultInAppMessageViewFactory.createInAppMessageView(activity, inAppMessage); } } } ``` ```kotlin class CustomInAppMessageViewFactory : IInAppMessageViewFactory { override fun createInAppMessageView(activity: Activity, inAppMessage: IInAppMessage): View { // Uses a custom view for slideups, modals, and full in-app messages. // HTML in-app messages and any other types will use the Braze default in-app message view factories when (inAppMessage.messageType) { MessageType.SLIDEUP, MessageType.MODAL, MessageType.FULL -> // Use a custom view of your choosing return createMyCustomInAppMessageView() else -> { // Use the default in-app message factories val defaultInAppMessageViewFactory = BrazeInAppMessageManager.getInstance().getDefaultInAppMessageViewFactory(inAppMessage) return defaultInAppMessageViewFactory!!.createInAppMessageView(activity, inAppMessage) } } } } ``` Create a class that implements [`IInAppMessageViewWrapperFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-wrapper-factory/index.html) and returns an [`IInAppMessageViewWrapper`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-wrapper/index.html). This factory is called immediately after the in-app message view is created. The easiest way to implement a custom [`IInAppMessageViewWrapper`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-wrapper/index.html) is just to extend the default [`DefaultInAppMessageViewWrapper`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-default-in-app-message-view-wrapper/index.html): ```java public class CustomInAppMessageViewWrapper extends DefaultInAppMessageViewWrapper { public CustomInAppMessageViewWrapper(View inAppMessageView, IInAppMessage inAppMessage, IInAppMessageViewLifecycleListener inAppMessageViewLifecycleListener, BrazeConfigurationProvider brazeConfigurationProvider, Animation openingAnimation, Animation closingAnimation, View clickableInAppMessageView) { super(inAppMessageView, inAppMessage, inAppMessageViewLifecycleListener, brazeConfigurationProvider, openingAnimation, closingAnimation, clickableInAppMessageView); } @Override public void open(@NonNull Activity activity) { super.open(activity); Toast.makeText(activity.getApplicationContext(), "Opened in-app message", Toast.LENGTH_SHORT).show(); } @Override public void close() { super.close(); Toast.makeText(mInAppMessageView.getContext().getApplicationContext(), "Closed in-app message", Toast.LENGTH_SHORT).show(); } } ``` ```kotlin class CustomInAppMessageViewWrapper(inAppMessageView: View, inAppMessage: IInAppMessage, inAppMessageViewLifecycleListener: IInAppMessageViewLifecycleListener, brazeConfigurationProvider: BrazeConfigurationProvider, openingAnimation: Animation, closingAnimation: Animation, clickableInAppMessageView: View) : DefaultInAppMessageViewWrapper(inAppMessageView, inAppMessage, inAppMessageViewLifecycleListener, brazeConfigurationProvider, openingAnimation, closingAnimation, clickableInAppMessageView) { override fun open(activity: Activity) { super.open(activity) Toast.makeText(activity.applicationContext, "Opened in-app message", Toast.LENGTH_SHORT).show() } override fun close() { super.close() Toast.makeText(mInAppMessageView.context.applicationContext, "Closed in-app message", Toast.LENGTH_SHORT).show() } } ``` Create a class that implements [`IInAppMessageAnimationFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-animation-factory/index.html): ```java public class CustomInAppMessageAnimationFactory implements IInAppMessageAnimationFactory { @Override public Animation getOpeningAnimation(IInAppMessage inAppMessage) { Animation animation = new AlphaAnimation(0, 1); animation.setInterpolator(new AccelerateInterpolator()); animation.setDuration(2000L); return animation; } @Override public Animation getClosingAnimation(IInAppMessage inAppMessage) { Animation animation = new AlphaAnimation(1, 0); animation.setInterpolator(new DecelerateInterpolator()); animation.setDuration(2000L); return animation; } } ``` ```kotlin class CustomInAppMessageAnimationFactory : IInAppMessageAnimationFactory { override fun getOpeningAnimation(inAppMessage: IInAppMessage): Animation { val animation: Animation = AlphaAnimation(0, 1) animation.interpolator = AccelerateInterpolator() animation.duration = 2000L return animation } override fun getClosingAnimation(inAppMessage: IInAppMessage): Animation { val animation: Animation = AlphaAnimation(1, 0) animation.interpolator = DecelerateInterpolator() animation.duration = 2000L return animation } } ``` ### Step 2: Instruct Braze to use the factory After your `IInAppMessageViewFactory` is created, call `BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewFactory()` to instruct `BrazeInAppMessageManager` to use your custom `IInAppMessageViewFactory` instead of the default view factory. **Tip:** We recommend setting your `IInAppMessageViewFactory` in your `Application.onCreate()` before any other calls to Braze. This will set the custom view factory before any in-app message is displayed. #### How it works The `slideup` in-app message view implements [`IInAppMessageView`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.views/-i-in-app-message-view/index.html). The `full` and `modal` type message views implement [`IInAppMessageImmersiveView`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.views/-i-in-app-message-immersive-view/index.html). Implementing one of these classes allows Braze to add click listeners to your custom view where appropriate. All Braze view classes extend Android's [`View`](http://developer.android.com/reference/android/view/View.html) class. Implementing `IInAppMessageView` allows you to define a certain portion of your custom view as clickable. Implementing [`IInAppMessageImmersiveView`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.views/-i-in-app-message-immersive-view/index.html) allows you to define message button views and a close button view. After your [`IInAppMessageViewWrapper`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-wrapper/index.html) is created, call [`BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewWrapperFactory()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-in-app-message-manager-base/set-custom-in-app-message-view-factory.html) to instruct `BrazeInAppMessageManager` to use your custom [`IInAppMessageViewWrapperFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-wrapper-factory/index.html) instead of the default view wrapper factory. We recommend setting your [`IInAppMessageViewWrapperFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-wrapper-factory/index.html) in your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()) before any other calls to Braze. This will set the custom view wrapper factory before any in-app message is displayed: ```java BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewWrapperFactory(new CustomInAppMessageViewWrapper()); ``` ```kotlin BrazeInAppMessageManager.getInstance().setCustomInAppMessageViewWrapperFactory(CustomInAppMessageViewWrapper()) ``` Once your `IInAppMessageAnimationFactory` is created, call `BrazeInAppMessageManager.getInstance().setCustomInAppMessageAnimationFactory()` to instruct `BrazeInAppMessageManager` to use your custom `IInAppMessageAnimationFactory` instead of the default animation factory. We recommend setting your `IInAppMessageAnimationFactory` in your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()) before any other calls to Braze. This will set the custom animation factory before any in-app message is displayed. ## Custom styles Braze UI elements come with a default look and feel that matches the Android standard UI guidelines and provides a seamless experience. This reference article covers custom in-app messaging styling for your Android or FireOS application. ### Setting a default style You can see default styles in the Braze SDK's [`styles.xml`](https://github.com/braze-inc/braze-android-sdk/blob/master/android-sdk-ui/src/main/res/values/styles.xml) file: ```xml ``` If you would prefer, you can override these styles to create a look and feel that better suits your app. To override a style, copy it in its entirety to the `styles.xml` file in your project and make modifications. The whole style must be copied over to your local `styles.xml` file for all attributes to be correctly set. Note that these custom styles are for changes to individual UI elements, not wholesale changes to layouts. Layout-level changes need to be handled with custom views. **Note:** You can customize some colors directly in your Braze campaign without modifying the XML. Keep in mind, colors set in the Braze dashboard will override colors you set anywhere else. ### Customizing the font You can set a custom font by locating the typeface in the `res/font` directory. To use it, override the style for message text, headers, and button text and use the `fontFamily` attribute to instruct Braze to use your custom font family. For example, to update the font on your in-app message button text, override the `Braze.InAppMessage.Button` style and reference your custom font family. The attribute value should point to a font family in your `res/font` directory. Here is a truncated example with a custom font family, `my_custom_font_family`, referenced on the last line: ```xml ``` Aside from the `Braze.InAppMessage.Button` style for button text, the style for message text is `Braze.InAppMessage.Message` and the style for message headers is `Braze.InAppMessage.Header`. If you want to use your custom font family across all possible in-app message text, you can set your font family on the `Braze.InAppMessage` style, which is the parent style for all in-app messages. **Important:** As with other custom styles, the entire style must be copied over to your local `styles.xml` file for all attributes to be correctly set. ## Message dismissals ### Swiping to dismiss slideup messages By default, slideup in-app messages can be dismissed with a swipe gesture. The direction of the swipe depends on the slideup position: - **Left or right swipe:** Dismisses the slideup regardless of its position. - **Slideup from the bottom:** Swiping from top to bottom dismisses the message. Swiping from bottom to top does not dismiss it. - **Slideup from the top:** Swiping from bottom to top dismisses the message. Swiping from top to bottom does not dismiss it. This swipe behavior is built into the default [`DefaultInAppMessageViewWrapper`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-default-in-app-message-view-wrapper/index.html) and applies only to slideup in-app messages. Modal and full in-app messages don't support swipe-to-dismiss. To customize this behavior, you can implement a [custom view wrapper factory](#android_setting-custom-factories). **Note:** Tapping outside of a slideup message does not dismiss it by default. This behavior differs from modal messages, which can be configured for outside tap dismissal. For slideups, use the swipe gesture or the close button to dismiss the message. ### Disabling back button dismissals By default, the hardware back button dismisses Braze in-app messages. This behavior can be disabled on a per-message basis via [`BrazeInAppMessageManager.setBackButtonDismissesInAppMessageView()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-in-app-message-manager-base/set-back-button-dismisses-in-app-message-view.html). In the following example, `disable_back_button` is a custom key-value pair set on the in-app message that signifies whether the message should allow for the back button to dismiss the message: ```java BrazeInAppMessageManager.getInstance().setCustomInAppMessageManagerListener(new DefaultInAppMessageManagerListener() { @Override public void beforeInAppMessageViewOpened(View inAppMessageView, IInAppMessage inAppMessage) { super.beforeInAppMessageViewOpened(inAppMessageView, inAppMessage); final Map extras = inAppMessage.getExtras(); if (extras != null && extras.containsKey("disable_back_button")) { BrazeInAppMessageManager.getInstance().setBackButtonDismissesInAppMessageView(false); } } @Override public void afterInAppMessageViewClosed(IInAppMessage inAppMessage) { super.afterInAppMessageViewClosed(inAppMessage); BrazeInAppMessageManager.getInstance().setBackButtonDismissesInAppMessageView(true); } }); ``` ```kotlin BrazeInAppMessageManager.getInstance().setCustomInAppMessageManagerListener(object : DefaultInAppMessageManagerListener() { override fun beforeInAppMessageViewOpened(inAppMessageView: View, inAppMessage: IInAppMessage) { super.beforeInAppMessageViewOpened(inAppMessageView, inAppMessage) val extras = inAppMessage.extras if (extras != null && extras.containsKey("disable_back_button")) { BrazeInAppMessageManager.getInstance().setBackButtonDismissesInAppMessageView(false) } } override fun afterInAppMessageViewClosed(inAppMessage: IInAppMessage) { super.afterInAppMessageViewClosed(inAppMessage) BrazeInAppMessageManager.getInstance().setBackButtonDismissesInAppMessageView(true) } }) ``` **Note:** Note that if this functionality is disabled, the host activity's hardware back button default behavior will be used instead. This may lead to the back button closing the application instead of the displayed in-app message. ### Enabling outside tap dismissals By default, dismissing the modal using an outside tap is set to `false`. Setting this value to `true` will result in the modal in-app message being dismissed when the user taps outside of the in-app message. This behavior can be toggled on by calling: ```java BrazeInAppMessageManager.getInstance().setClickOutsideModalViewDismissInAppMessageView(true) ``` ## Customizing the orientation To set a fixed orientation for an in-app message, first [set a custom in-app message manager listener](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization/?sdktab=android#android_setting-custom-manager-listeners). Then, update the orientation on the `IInAppMessage` object in the `beforeInAppMessageDisplayed()` delegate method: ```java public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessage) { // Set the orientation to portrait inAppMessage.setOrientation(Orientation.PORTRAIT); return InAppMessageOperation.DISPLAY_NOW; } ``` ```kotlin override fun beforeInAppMessageDisplayed(inAppMessage: IInAppMessage): InAppMessageOperation { // Set the orientation to portrait inAppMessage.orientation = Orientation.PORTRAIT return InAppMessageOperation.DISPLAY_NOW } ``` For tablet devices, in-app messages will appear in the user's preferred orientation style regardless of actual screen orientation. ## Disabling dark theme {#android-in-app-message-dark-theme-customization} By default, `IInAppMessageManagerListener`'s `beforeInAppMessageDisplayed()` checks the system settings and conditionally enables dark theme styling on the message with the following code: ```java @Override public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessage) { if (inAppMessage instanceof IInAppMessageThemeable && ViewUtils.isDeviceInNightMode(BrazeInAppMessageManager.getInstance().getApplicationContext())) { ((IInAppMessageThemeable) inAppMessage).enableDarkTheme(); } return InAppMessageOperation.DISPLAY_NOW; } ``` ```kotlin override fun beforeInAppMessageDisplayed(inAppMessage: IInAppMessage): InAppMessageOperation { if (inAppMessage is IInAppMessageThemeable && ViewUtils.isDeviceInNightMode(BrazeInAppMessageManager.getInstance().applicationContext!!)) { (inAppMessage as IInAppMessageThemeable).enableDarkTheme() } return InAppMessageOperation.DISPLAY_NOW } ``` To change this, you can call [`enableDarkTheme`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message-themeable/enable-dark-theme.html) at any step in the pre-display process to implement your own conditional logic. ## Customizing the Google Play review prompt Due to the limitations and restrictions set by Google, custom Google Play review prompts are not currently supported by Braze. While some users have been able to integrate these prompts successfully, others have shown low success rates due to [Google Play quotas](https://developer.android.com/guide/playcore/in-app-review#quotas). Integrate at your own risk. Refer to documentation on [Google Play in-app review prompts](https://developer.android.com/guide/playcore/in-app-review). ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). ## Setting up the UI delegate (required) To customize the presentation of in-app messages and react to various lifecycle events, you'll need to set up [`BrazeInAppMessageUIDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate). This is a delegate protocol used for receiving and processing triggered in-app message payloads, receiving display lifecycle events, and controlling display timing. To use `BrazeInAppMessageUIDelegate`, you must: - Use the default [`BrazeInAppMessageUI`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui) implementation as your `inAppMessagePresenter`. - Include the `BrazeUI` library in your project. ### Step 1: Implement the `BrazeInAppMessageUIDelegate` protocol First, implement the `BrazeInAppMessageUIDelegate` protocol and any corresponding methods you wish. In our example below, we are implementing this protocol in our application's `AppDelegate` class. ```swift extension AppDelegate: BrazeInAppMessageUIDelegate { // Implement your protocol methods here. } ``` ```objc @interface AppDelegate () @end @implementation AppDelegate // Implement your protocol methods here. @end ``` ### Step 2: Assign the `delegate` object Assign the `delegate` object on the `BrazeInAppMessageUI` instance before assigning this in-app message UI as your `inAppMessagePresenter`. ```swift let inAppMessageUI = BrazeInAppMessageUI() inAppMessageUI.delegate = self AppDelegate.braze?.inAppMessagePresenter = inAppMessageUI ``` ```objc BrazeInAppMessageUI *inAppMessageUI = [[BrazeInAppMessageUI alloc] init]; inAppMessageUI.delegate = self; AppDelegate.braze.inAppMessagePresenter = inAppMessageUI; ``` **Important:** Not all delegate methods are available in Objective-C due to the incompatibility of their parameters with the language runtime. **Tip:** For a step-by-step implementation of the in-app message UI delegate, refer to this [tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/c1-inappmessageui). ## On-click behavior Each `Braze.InAppMessage` object contains a corresponding [`ClickAction`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/inappmessage/clickaction), which defines the behavior upon clicking. ### Click action types The `clickAction` property on your `Braze.InAppMessage` defaults to `.none` but can be set to one of the following values: | `ClickAction` | On-Click Behavior | | -------------------------- | -------- | | `.url(URL, useWebView: Bool)` | Opens the given URL in an external browser. If `useWebView` is set to `true`, it will open in a web view. | | `.none` | The message will be dismissed when clicked. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Click action types" } **Important:** For in-app messages containing buttons, the message `clickAction` will also be included in the final payload if the click action is added prior to adding the button text. ### Customizing on-click behavior To customize this behavior, you may modify the `clickAction` property by referring to the following sample: ```swift func inAppMessage( _ ui: BrazeInAppMessageUI, prepareWith context: inout BrazeInAppMessageUI.PresentationContext ) { if let newUrl = URL(string: "{your-url}") { context.message.clickAction = .url(newUrl, useWebView: true) } } ``` The `inAppMessage(_:prepareWith:)` method is not available in Objective-C. ### Handling the custom behavior The following [`BrazeInAppMessageUIDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate) delegate method is called when a user clicks an in-app message. This callback is triggered for user-initiated clicks on in-app message buttons and HTML in-app message buttons (links), and a button ID is provided as an optional parameter for these interactions. This callback is not invoked for programmatic clicks triggered through `brazeBridge.logClick()`. ```swift func inAppMessage( _ ui: BrazeInAppMessageUI, shouldProcess clickAction: Braze.InAppMessage.ClickAction, buttonId: String?, message: Braze.InAppMessage, view: InAppMessageView ) -> Bool ``` ```objc - (BOOL)inAppMessage:(BrazeInAppMessageUI *)ui shouldProcess:(enum BRZInAppMessageRawClickAction)clickAction url:(NSURL *)uri buttonId:(NSString *)buttonId message:(BRZInAppMessageRaw *)message view:(UIView *)view; ``` This method returns a boolean value to indicate if Braze should continue to execute the click action. ```swift func inAppMessage( _ ui: BrazeInAppMessageUI, shouldProcess clickAction: Braze.InAppMessage.ClickAction, buttonId: String?, message: Braze.InAppMessage, view: InAppMessageView ) -> Bool { guard let buttonId, let idInt = Int(buttonId) else { return true } var button: BrazeKit.Braze.InAppMessage.Button? = nil switch message { case .modal(let modal): button = modal.buttons[idInt] case .modalImage(let modalImage): button = modalImage.buttons[idInt] case .full(let full): button = full.buttons[idInt] case .fullImage(let fullImage): button = fullImage.buttons[idInt] default: break } print(button?.id) print(button?.text) print(button?.clickAction) return true } ``` ```objc - (BOOL)inAppMessage:(BrazeInAppMessageUI *)ui shouldProcess:(enum BRZInAppMessageRawClickAction)clickAction url:(NSURL *)uri buttonId:(NSString *)buttonId message:(BRZInAppMessageRaw *)message view:(UIView *)view { NSInteger buttonInt = [buttonId integerValue]; if (message.type == BRZInAppMessageRawTypeFull || message.type == BRZInAppMessageRawTypeModal) { BRZInAppMessageRawButton *button = message.buttons[buttonInt]; NSLog(@"%ld", (long)button.identifier); NSLog(@"%@", button.text); NSLog(@"%ld", (long)button.clickAction); } return YES; } ``` ## Swiping to dismiss slideup messages By default, slideup in-app messages can be dismissed with a swipe gesture. The direction of the swipe depends on the slideup position: - **Left or right swipe:** Dismisses the slideup regardless of its position. - **Slideup from the bottom:** Swiping from top to bottom dismisses the message. Swiping from bottom to top does not dismiss it. - **Slideup from the top:** Swiping from bottom to top dismisses the message. Swiping from top to bottom does not dismiss it. This swipe behavior is built into the default `BrazeInAppMessageUI` [`SlideupView`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/slideupview) and applies only to slideup in-app messages. Modal and full in-app messages don't support swipe-to-dismiss. To further customize the slideup view, including swipe behavior, you can modify the [`SlideupView.Attributes`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/slideupview/attributes-swift.struct) or provide a custom view via subclassing. **Note:** Tapping outside of a slideup message does not dismiss it. For modal or full in-app messages, you can enable outside tap dismissals using the `dismissOnBackgroundTap` attribute described below. ## Customizing modal dismissals To enable outside tap dismissals, you can modify the `dismissOnBackgroundTap` property on the `Attributes` struct of the in-app message type you wish to customize. For example, if you wish to enable this feature for modal image in-app messages, you can configure the following: ```swift BrazeInAppMessageUI.ModalImageView.Attributes.defaults.dismissOnBackgroundTap = true ``` Customization via `Attributes` is not available in Objective-C. The default value is `false`. This determines if the modal in-app message will be dismissed when the user taps outside of the in-app message. | `DismissModalOnOutsideTap` | Description | |----------|-------------| | `true` | Modal in-app messages will be dismissed on outside tap. | | `false` | Default, modal in-app messages will not be dismissed on outside tap. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Customizing modal dismissals" } For more details on in-app message customization, refer to this [article](https://braze-inc.github.io/braze-swift-sdk/documentation/braze/in-app-message-customization). ## Customizing message orientation You can customize the orientation of your in-app messages. You can set a new default orientation for all messages or set a custom orientation for a single message. To choose a default orientation for all in-app messages, use the [`inAppMessage(_:prepareWith:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:preparewith:)-11fog) method to set the `preferredOrientation` property on the `PresentationContext`. For example, to set portrait as the default orientation: ```swift func inAppMessage( _ ui: BrazeInAppMessageUI, prepareWith context: inout BrazeInAppMessageUI.PresentationContext ) { context.preferredOrientation = .portrait } ``` ```objc - (void)inAppMessage:(BrazeInAppMessageUI *)ui prepareWith:(BrazeInAppMessageUIPresentationContextRaw *)context { context.preferredOrientation = BRZInAppMessageRawOrientationPortrait; } ``` To set the orientation for a single message, modify the `orientation` property of `Braze.InAppMessage`: ```swift // Set inAppMessage orientation to support any configuration inAppMessage.orientation = .any // Set inAppMessage orientation to only display in portrait inAppMessage.orientation = .portrait // Set inAppMessage orientation to only display in landscape inAppMessage.orientation = .landscape ``` ```objc // Set inAppMessage orientation to support any configuration inAppMessage.orientation = BRZInAppMessageRawOrientationAny; // Set inAppMessage orientation to only display in portrait inAppMessage.orientation = BRZInAppMessageRawOrientationPortrait; // Set inAppMessage orientation to only display in landscape inAppMessage.orientation = BRZInAppMessageRawOrientationLandscape; ``` After the in-app message is displayed, any device orientation changes while the message is still being displayed will cause the message to rotate with the device (provided it's supported by the message's `orientation` configuration). The device orientation must also be supported by the in-app message's `orientation` property for the message to display. Additionally, the `preferredOrientation` setting will only be respected if it is included in your application's supported interface orientations under the **Deployment Info** section of your target's settings in Xcode. ![Supported orientations in Xcode.](https://www.braze.com/docs/ja/ja/assets/img/supported_interface_orientations_xcode.png?79fd9f5e4c58ef88e3ab26db7e77897c) **Note:** The orientation is applied only for the presentation of the message. After the device changes orientation, the message view adopts one of the orientations it supports. On smaller devices (iPhones, iPod Touch), setting a landscape orientation for a modal or full in-app message may lead to truncated content. ## Customizing display timing You can control if an available in-app message will display during certain points of your user experience. If there are situations where you would not want the in-app message to appear, such as during a fullscreen game or on a loading screen, you can delay or discard pending in-app message messages. To control the timing of in-app message, use the `inAppMessage(_:displayChoiceForMessage:)` [delegate method](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:displaychoiceformessage:)-9w1nb) to set the `BrazeInAppMessageUI.DisplayChoice` property. ```swift func inAppMessage( _ ui: BrazeInAppMessageUI, displayChoiceForMessage message: Braze.InAppMessage ) -> BrazeInAppMessageUI.DisplayChoice ``` ```objc - (enum BRZInAppMessageUIDisplayChoice)inAppMessage:(BrazeInAppMessageUI *)ui displayChoiceForMessage:(BRZInAppMessageRaw *)message ``` Configure `BrazeInAppMessageUI.DisplayChoice` to return one of the following values: | Display Choice | Behavior | | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | `.now` | The message will be displayed immediately. This is the default value. | | `.reenqueue` | The message will be not be displayed and will be placed back on the top of the stack. | | `.later` | The message will be not be displayed and will be placed back on the top of the stack. (Deprecated, please use `.reenqueue`) | | `.discard` | The message will be discarded and will not be displayed. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Customizing display timing" } **Tip:** For a sample of `InAppMessageUI`, check out our [Swift Braze SDK repository](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples/Swift/Sources/InAppMessageUI) and [Objective-C](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples/ObjC/Sources/InAppMessageUI). ## Hiding the status bar For `Full`, `FullImage` and `HTML` in-app messages, the SDK will hide the status bar by default. For other types of in-app messages, the status bar is left untouched. To configure this behavior, use the `inAppMessage(_:prepareWith:)` [delegate method](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:preparewith:)-11fog) to set the `statusBarHideBehavior` property on the `PresentationContext`. This field takes one of the following values: | Status Bar Hide Behavior | Description | | ----------------------------------- | ------------------------------------------------------------------------------------- | | `.auto` | The message view decides the status bar hidden state. | | `.hidden` | Always hide the status bar. | | `.visible` | Always display the status bar. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Hiding the status bar" } ## Disabling dark mode To prevent in-app messages from adopting dark mode styling when the user device has dark mode enabled, implement the `inAppMessage(_:prepareWith:)` [delegate method](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:preparewith:)-11fog) method. The `PresentationContext` passed to the method contains a reference to the `InAppMessage` object to be presented. Each `InAppMessage` has a `themes` property containing a `dark` and `light` mode theme. If you set the `themes.dark` property to `nil`, Braze will automatically present the in-app message using its light theme. In-app message types with buttons have an additional `themes` object on their `buttons` property. To prevent buttons from adopting dark mode styling, you can use [`map(_:)`](https://developer.apple.com/documentation/swift/array/map(_:)-87c4d) to create a new array of buttons with a `light` theme and no `dark` theme. ```swift func inAppMessage( _ ui: BrazeInAppMessageUI, prepareWith context: inout BrazeInAppMessageUI.PresentationContext ) { switch context.message { case .slideup: guard var slideup = context.message.slideup else { return } slideup.themes.dark = nil context.message.slideup = slideup case .modal: guard var modal = context.message.modal else { return } modal.themes.dark = nil modal.buttons = modal.buttons.map { var newButton = $0 newButton.themes = .init(themes: ["light": $0.themes.light]) return newButton } context.message.modal = modal case .modalImage: guard var modalImage = context.message.modalImage else { return } modalImage.themes.dark = nil modalImage.buttons = modalImage.buttons.map { var newButton = $0 newButton.themes = .init(themes: ["light": $0.themes.light]) return newButton } context.message.modalImage = modalImage case .full: guard var full = context.message.full else { return } full.themes.dark = nil full.buttons = full.buttons.map { var newButton = $0 newButton.themes = .init(themes: ["light": $0.themes.light]) return newButton } context.message.full = full case .fullImage: guard var fullImage = context.message.fullImage else { return } fullImage.themes.dark = nil fullImage.buttons = fullImage.buttons.map { var newButton = $0 newButton.themes = .init(themes: ["light": $0.themes.light]) return newButton } context.message.fullImage = fullImage default: break } } ``` ```objc - (void)inAppMessage:(BrazeInAppMessageUI *)ui prepareWith:(BrazeInAppMessageUIPresentationContextRaw *)context { switch (context.message.type) { case BRZInAppMessageRawTypeSlideup: { NSMutableDictionary *updatedThemes = [context.message.themes mutableCopy]; [updatedThemes removeObjectForKey:@"dark"]; context.message.themes = updatedThemes; break; } case BRZInAppMessageRawTypeModal: case BRZInAppMessageRawTypeFull: { NSMutableDictionary *updatedThemes = [context.message.themes mutableCopy]; [updatedThemes removeObjectForKey:@"dark"]; context.message.themes = updatedThemes; NSMutableArray *updatedButtons = [NSMutableArray arrayWithCapacity:context.message.buttons.count]; for (BRZInAppMessageRawButton *button in context.message.buttons) { BRZInAppMessageRawButtonTheme *lightTheme = BRZInAppMessageRawButtonTheme.defaultLight; BRZInAppMessageRawButton *newButton = [button mutableCopy]; newButton.textColor = lightTheme.textColor; newButton.backgroundColor = lightTheme.backgroundColor; newButton.borderColor = lightTheme.borderColor; [updatedButtons addObject:newButton]; } context.message.buttons = updatedButtons; break; } default: break; } } ``` ## Customizing the app store review prompt You can use in-app messages in a campaign to ask users for an App Store review. **Note:** Because this example prompt overrides default behavior of Braze, we cannot automatically track impressions if it is implemented. You must [log your own analytics](https://www.braze.com/docs/ja/ja/developer_guide/analytics/). ### Step 1: Set the in-app message delegate First, set the [`BrazeInAppMessageUIDelegate`](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization/#swift_setting-up-the-ui-delegate-required) in your app. ### Step 2: Disable the default App Store review message Next, implement the `inAppMessage(_:displayChoiceForMessage:)` [delegate method](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:displaychoiceformessage:)-9w1nb) to disable the default App Store review message. ```swift func inAppMessage(_ ui: BrazeInAppMessageUI, displayChoiceForMessage message: Braze.InAppMessage) -> BrazeInAppMessageUI.DisplayChoice { if message.extras["AppStore Review"] != nil, let messageUrl = message.clickAction.url { UIApplication.shared.open(messageUrl, options: [:], completionHandler: nil) return .discard } else { return .now } } ``` ```objc - (enum BRZInAppMessageUIDisplayChoice)inAppMessage:(BrazeInAppMessageUI *)ui displayChoiceForMessage:(BRZInAppMessageRaw *)message { if (message.extras != nil && message.extras[@"AppStore Review"] != nil) { [[UIApplication sharedApplication] openURL:message.url options:@{} completionHandler:nil]; return BRZInAppMessageUIDisplayChoiceDiscard; } else { return BRZInAppMessageUIDisplayChoiceNow; } } ``` ### Step 3: Create a deep link In your deep link handling code, add the following code to process the `{YOUR-APP-SCHEME}:app-store-review` deep link. Note that you will need to import `StoreKit` to use `SKStoreReviewController`: ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { let urlString = url.absoluteString.removingPercentEncoding if (urlString == "{YOUR-APP-SCHEME}:app-store-review") { SKStoreReviewController.requestReview() return true; } // Other deep link handling code… } ``` ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *urlString = url.absoluteString.stringByRemovingPercentEncoding; if ([urlString isEqualToString:@"{YOUR-APP-SCHEME}:app-store-review"]) { [SKStoreReviewController requestReview]; return YES; } // Other deep link handling code… } ``` ### Step 4: Set custom on-click behavior Next, create an in-app messaging campaign with the following: - The key-value pair `"AppStore Review" : "true"` - The on-click behavior set to "Deep Link Into App", using the deep link `{YOUR-APP-SCHEME}:app-store-review`. **Tip:** Apple limits App Store review prompts to a maximum of three times per year for each user, so your campaign should be [rate-limited](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/campaigns/building_campaigns/rate-limiting/) to three times per year per user.

Users may turn off App Store review prompts. As a result, your custom review prompt should not promise that a native App Store review prompt will appear or directly ask for a review. ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Methods for logging You can use these methods by passing your `BrazeInAppMessage` instance to log analytics and perform actions: | Method | Description | | --------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `logInAppMessageClicked(inAppMessage)` | Logs a click for the provided in-app message data. | | `logInAppMessageImpression(inAppMessage)` | Logs an impression for the provided in-app message data. | | `logInAppMessageButtonClicked(inAppMessage, buttonId)` | Logs a button click for the provided in-app message data and button ID. | | `hideCurrentInAppMessage()` | Dismisses the currently displayed in-app message. | | `performInAppMessageAction(inAppMessage)` | Performs the action for an in-app message. | | `performInAppMessageButtonAction(inAppMessage, buttonId)` | Performs the action for an in-app message button. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Methods for logging" } ## Handling message data In most cases, you can use the `Braze.addListener` method to register event listeners to handle data coming from in-app messages. Additionally, you can access the in-app message data in the JavaScript layer by calling the `Braze.subscribeToInAppMessage` method to have the SDKs publish an `inAppMessageReceived` event when an in-app message is triggered. Pass a callback to this method to execute your own code when the in-app message is triggered and received by the listener. To customize how message data is handled, refer to the following implementation examples: To enhance the default behavior, or if you don't have access to customize the native iOS or Android code, we recommend that you disable the default UI while still receiving in-app message events from Braze. To disable the default UI, pass `false` to the `Braze.subscribeToInAppMessage` method and use the in-app message data to construct your own message in JavaScript. Note that you will need to manually log analytics on your messages if you choose to disable the default UI. ```javascript import Braze from "@braze/react-native-sdk"; // Option 1: Listen for the event directly via `Braze.addListener`. // // You may use this method to accomplish the same thing if you don't // wish to make any changes to the default Braze UI. Braze.addListener(Braze.Events.IN_APP_MESSAGE_RECEIVED, (event) => { console.log(event.inAppMessage); }); // Option 2: Call `subscribeToInAppMessage`. // // Pass in `false` to disable the automatic display of in-app messages. Braze.subscribeToInAppMessage(false, (event) => { console.log(event.inAppMessage); // Use `event.inAppMessage` to construct your own custom message UI. }); ``` To include more advanced logic to determine whether or not to show an in-app message using the built-in UI, implement in-app messages through the native layer. **Warning:** Since this is an advanced customization option, note that overriding the default Braze implementation will also nullify the logic to emit in-app message events to your JavaScript listeners. If you wish to still use `Braze.subscribeToInAppMessage` or `Braze.addListener` as described in [Accessing in-app message data](#accessing-in-app-message-data), you will need to handle publishing the events yourself. Implement the `IInAppMessageManagerListener` as described in our Android article on [Custom Manager Listener](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization/?sdktab=android#android_setting-custom-manager-listeners). In your `beforeInAppMessageDisplayed` implementation, you can access the `inAppMessage` data, send it to the JavaScript layer, and decide to show or not show the native message based on the return value. For more on these values, see our [Android documentation](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/). ```java // In-app messaging @Override public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessage) { WritableMap parameters = new WritableNativeMap(); parameters.putString("inAppMessage", inAppMessage.forJsonPut().toString()); getReactNativeHost() .getReactInstanceManager() .getCurrentReactContext() .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("inAppMessageReceived", parameters); // Note: return InAppMessageOperation.DISCARD if you would like // to prevent the Braze SDK from displaying the message natively. return InAppMessageOperation.DISPLAY_NOW; } ``` ### Overriding the default UI delegate By default, [`BrazeInAppMessageUI`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/) is created and assigned when you initialize the `braze` instance. `BrazeInAppMessageUI` is an implementation of the [`BrazeInAppMessagePresenter`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazeinappmessagepresenter) protocol and comes with a `delegate` property that can be used to customize the handling of in-app messages that have been received. 1. Implement the `BrazeInAppMessageUIDelegate` delegate as described in [our iOS article here](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/c1-inappmessageui). 2. In the `inAppMessage(_:displayChoiceForMessage:)` delegate method, you can access the `inAppMessage` data, send it to the JavaScript layer, and decide to show or not show the native message based on the return value. For more details on these values, see our [iOS documentation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/). ```objc - (enum BRZInAppMessageUIDisplayChoice)inAppMessage:(BrazeInAppMessageUI *)ui displayChoiceForMessage:(BRZInAppMessageRaw *)message { // Convert the message to a JavaScript representation. NSData *inAppMessageData = [message json]; NSString *inAppMessageString = [[NSString alloc] initWithData:inAppMessageData encoding:NSUTF8StringEncoding]; NSDictionary *arguments = @{ @"inAppMessage" : inAppMessageString }; // Send to JavaScript. [self sendEventWithName:@"inAppMessageReceived" body:arguments]; // Note: Return `BRZInAppMessageUIDisplayChoiceDiscard` if you would like // to prevent the Braze SDK from displaying the message natively. return BRZInAppMessageUIDisplayChoiceNow; } ``` To use this delegate, assign it to `brazeInAppMessagePresenter.delegate` after initializing the `braze` instance. **Note:** `BrazeUI` can only be imported in Objective-C or Swift. If you are using Objective-C++, you will need to handle this in a separate file. ```objc @import BrazeUI; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:apiKey endpoint:endpoint]; Braze *braze = [BrazeReactBridge initBraze:configuration]; ((BrazeInAppMessageUI *)braze.inAppMessagePresenter).delegate = [[CustomDelegate alloc] init]; AppDelegate.braze = braze; } ``` ### Overriding the default native UI If you wish to fully customize the presentation of your in-app messages at the native iOS layer, conform to the [`BrazeInAppMessagePresenter`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazeinappmessagepresenter) protocol and assign your custom presenter following the sample below: ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:apiKey endpoint:endpoint]; Braze *braze = [BrazeReactBridge initBraze:configuration]; braze.inAppMessagePresenter = [[MyCustomPresenter alloc] init]; AppDelegate.braze = braze; ``` ## Customizing the display behavior You can change the display behavior of in-app messages at runtime via the following: ```csharp // Sets in-app messages to display immediately when triggered. Appboy.AppboyBinding.SetInAppMessageDisplayAction(BrazeUnityInAppMessageDisplayActionType.IAM_DISPLAY_NOW); // Sets in-app messages to display at a later time and be saved in a stack. Appboy.AppboyBinding.SetInAppMessageDisplayAction(BrazeUnityInAppMessageDisplayActionType.IAM_DISPLAY_LATER); // Sets in-app messages to be discarded after being triggered. Appboy.AppboyBinding.SetInAppMessageDisplayAction(BrazeUnityInAppMessageDisplayActionType.IAM_DISCARD); ``` ## Setting a custom listener If you require more control over how a user interacts with in-app messages, use a `BrazeInAppMessageListener` and assign it to `Appboy.AppboyBinding.inAppMessageListener`. For any delegates you don't want to use, you can simply leave them as `null`. ```csharp BrazeInAppMessageListener listener = new BrazeInAppMessageListener() { BeforeInAppMessageDisplayed = BeforeInAppMessageDisplayed, OnInAppMessageButtonClicked = OnInAppMessageButtonClicked, OnInAppMessageClicked = OnInAppMessageClicked, OnInAppMessageHTMLClicked = OnInAppMessageHTMLClicked, OnInAppMessageDismissed = OnInAppMessageDismissed, }; Appboy.AppboyBinding.inAppMessageListener = listener; public void BeforeInAppMessageDisplayed(IInAppMessage inAppMessage) { // Executed before an in-app message is displayed. } public void OnInAppMessageButtonClicked(IInAppMessage inAppMessage, InAppMessageButton inAppMessageButton) { // Executed whenever an in-app message button is clicked. } public void OnInAppMessageClicked(IInAppMessage inAppMessage) { // Executed whenever an in-app message is clicked. } public void OnInAppMessageHTMLClicked(IInAppMessage inAppMessage, Uri uri) { // Executed whenever an HTML in-app message is clicked. } public void OnInAppMessageDismissed(IInAppMessage inAppMessage) { // Executed whenever an in-app message is dismissed without a click. } ``` # Braze SDKを通じてアプリ内メッセージをトリガーする Source: /docs/ja/developer_guide/in_app_messages/triggering_messages/index.md # アプリ内メッセージをトリガーする {#trigger-in-app-messages} > Braze SDKを通じてアプリ内メッセージをトリガーする方法を説明します。 ## メッセージのトリガーと配信 {#message-triggers-and-delivery} アプリ内メッセージは、SDKが以下のカスタムイベントタイプのいずれかをログに記録したときにトリガーされます: `Session Start`、`Push Click`、`Any Purchase`、`Specific Purchase`、`Custom Event`(最後の2つは堅牢なプロパティフィルターを含みます)。 ユーザーのセッション開始時に、Brazeは対象となるすべてのアプリ内メッセージをユーザーのデバイスに配信し、同時にアセットをプリフェッチして表示レイテンシーを最小化します。トリガーイベントに複数の適格なアプリ内メッセージがある場合、最も優先度の高いメッセージのみが配信されます。詳しくは[セッションライフサイクル](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions#about-the-session-lifecycle)を参照してください。 **Note:** アプリ内メッセージは、APIまたはAPIイベントによってトリガーすることはできません—SDKによってログに記録されるカスタムイベントによってのみトリガーされます。ロギングの詳細については、[カスタムイベントのログ記録](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events)を参照してください。 ## アプリ内メッセージのタイプ {#types-of-in-app-messages} Brazeは、セッション開始時にユーザーのデバイスに以下のタイプのアプリ内メッセージを送信します: `inapp`と`templated_iam`。ダッシュボードユーザーとしては異なるタイプを目にすることはありませんが、Brazeはセットアップとコンテンツに応じてそれらを異なる方法で処理します。 ### `inapp`(標準) {#inapp-standard} `inapp`(または「[標準](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages#standard-message-types)」)アプリ内メッセージは、Brazeがすでに把握しているカスタム属性などの必要な情報がすでにテンプレート化されています。一般的に、アプリ内メッセージがデバイスにダウンロードされると、デバイスがオフラインまたは機内モードであっても、トリガーイベントによってSDKが`inapp`アプリ内メッセージを表示します。 ### `templated_iam`(テンプレート化) {#templated_iam-templated} `templated_iam`(または「テンプレート化」)アプリ内メッセージは、まだ必要な情報がテンプレート化されていません。メッセージが表示される前に、Brazeは情報を取得するために別のリクエストを行う必要があります。 In-app messages are delivered as templated in-app messages when **Re-evaluate campaign eligibility before displaying** is selected or if any of the following Liquid tags exist in the message: - `canvas_entry_properties` - `connected_content` - SMS variables such as `{sms.${*}}` - `catalog_items` - `catalog_selection_items` - `event_properties` This means that during session start, the device will receive the trigger of that in-app message instead of the entire message. When the user triggers the in-app message, the user's device will make a network request to fetch the actual message. **Note:** The message will not be delivered if the device doesn't have access to the internet. The message might not be delivered if the Liquid logic takes too long to resolve. ## キーと値のペア {#key-value-pairs} Brazeでキャンペーンを作成する際、キーと値のペアを`extras`として設定できます。アプリ内メッセージングオブジェクトはこれを使用してアプリにデータを送信できます。 ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToInAppMessage(function(inAppMessage) { // control group messages should always be "shown" // this will log an impression and not show a visible message if (inAppMessage instanceof braze.ControlMessage) { return braze.showInAppMessage(inAppMessage); } if (inAppMessage instanceof braze.InAppMessage) { const extras = inAppMessage.extras; if (extras) { for (const key in extras) { console.log("key: " + key + ", value: " + extras[key]); } } } braze.showInAppMessage(inAppMessage); }); ``` ```java Map getExtras() ``` ```kotlin extras: Map ``` **Tip:** 詳細については、[KDoc](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.inappmessage/-i-in-app-message/index.html#1498425856%2FProperties%2F-1725759721)を参照してください。 次の例では、カスタムロジックを使用して、`extras`のキーと値のペアに基づいてアプリ内メッセージの表示を設定します。完全なカスタマイズ例については、[サンプルアプリ](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples)を参照してください。 ```swift let customization = message.extras["custom-display"] as? String if customization == "colorful-slideup" { // Perform your custom logic. } ``` ```objc if ([message.extras[@"custom-display"] isKindOfClass:[NSString class]]) { NSString *customization = message.extras[@"custom-display"]; if ([customization isEqualToString:@"colorful-slideup"]) { // Perform your custom logic. } } ``` ## 自動トリガーを無効にする {#disabling-automatic-triggers} デフォルトでは、アプリ内メッセージは自動的にトリガーされます。これを無効にするには: 読み込みスニペット内の`braze.automaticallyShowInAppMessages()`への呼び出しを削除し、アプリ内メッセージの表示/非表示を処理するカスタムロジックを作成します。 ```javascript braze.subscribeToInAppMessage(function(inAppMessage) { // control group messages should always be "shown" // this will log an impression and not show a visible message if (inAppMessage.isControl) { // v4.5.0+, otherwise use `inAppMessage instanceof braze.ControlMessage` return braze.showInAppMessage(inAppMessage); } // Display the in-app message. You could defer display here by pushing this message to code within your own application. // If you don't want to use the display capabilities in Braze, you could alternatively pass the in-app message to your own display code here. if ( should_show_the_message_according_to_your_custom_logic ) { braze.showInAppMessage(inAppMessage); } else { // do nothing } }); ``` **Important:** `braze.automaticallyShowInAppMessages()`を削除せずに`braze.showInAppMessage`を呼び出すと、メッセージが2回表示される場合があります。 メッセージのタイミングをより高度にコントロールする方法(トリガーメッセージの遅延や復元を含む)については、[チュートリアル: トリガーメッセージの遅延と復元](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/tutorials/deferring_triggered_messages)を参照してください。 1. カスタムリスナーを設定するために[`IInAppMessageManagerListener`](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization?sdktab=android&tab=global%20listener#android_step-1-implement-the-custom-manager-listener)を実装します。 2. [`beforeInAppMessageDisplayed()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.listeners/-i-in-app-message-manager-listener/before-in-app-message-displayed.html)メソッドを更新して、[`InAppMessageOperation.DISCARD`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-in-app-message-operation/-d-i-s-c-a-r-d/index.html)を返すようにします。 メッセージのタイミングをより高度にコントロールする方法(後から表示や再キューイングを含む)については、[メッセージのカスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization?tab=global%20listener&subtab=kotlin#android_step-2-instruct-braze-to-use-the-custom-manager-listener)ページを参照してください。 1. アプリに`BrazeInAppMessageUIDelegate`デリゲートを実装します。完全な手順については、[チュートリアル: アプリ内メッセージUI](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/c1-inappmessageui)を参照してください。 2. `inAppMessage(_:displayChoiceForMessage:)`デリゲートメソッドを更新して`.discard`を返すようにします。 メッセージのタイミングをより高度にコントロールする方法(トリガーメッセージの遅延や復元を含む)については、[チュートリアル: トリガーメッセージの遅延と復元](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/tutorials/deferring_triggered_messages)を参照してください。 1. 自動統合初期化機能を使用していることを確認してください。この機能は、バージョン`2.2.0`以降でデフォルトで有効になっています。 2. 次の行を`braze.xml`ファイルに追加することで、アプリ内メッセージ操作のデフォルトを`DISCARD`に設定します。 ```xml DISCARD ``` Androidの場合、Braze設定エディターで**Automatically Display In-App Messages**の選択を解除します。または、Unityプロジェクトの`braze.xml`で`com_braze_inapp_show_inapp_messages_automatically`を`false`に設定できます。 アプリ内メッセージの初期表示動作は、Braze設定の「In App Message Manager Initial Display Operation」で設定できます。 iOSの場合、Braze設定エディターでゲームオブジェクトリスナーを設定し、**Braze Displays In-App Messages**が選択されていないことを確認します。 アプリ内メッセージの初期表示動作は、Braze設定の「In App Message Manager Initial Display Operation」で設定できます。 ## 1つのセッションで2つのアプリ内メッセージを連鎖させる {#chaining-two-in-app-messages-in-one-session} セッション開始時にアプリ内メッセージをトリガーし、最初のメッセージでボタンが押された後に2番目のアプリ内メッセージをトリガーできます。これを行うには、2番目のメッセージをトリガーするボタンクリックのカスタムイベントをログに記録します。2番目のメッセージのトリガーはすでにデバイス上にある必要があり(ユーザーはすでに2番目のメッセージの対象である必要があります)、デバイス側で発生する必要があります(Braze SDKはBrazeサーバーで発生するカスタム属性の変更を取得しません)。複数のアプリ内メッセージを素早く連続して表示するには、アプリ内メッセージトリガー間のデフォルトの30秒クールダウンを変更する必要があります。プラットフォーム固有の設定については、[デフォルトのレート制限をオーバーライドする](#overriding-the-default-rate-limit)を参照してください。 ## デフォルトのレート制限をオーバーライドする {#overriding-the-default-rate-limit} デフォルトでは、SDKはトリガーされたアプリ内メッセージを30秒に1回にレート制限しています。これをオーバーライドするには、Brazeインスタンスが初期化される前に、以下のプロパティを設定ファイルに追加します。この値は、新しいレート制限(秒単位)として使用されます。 本番アプリでは、ユーザーが連続するアプリ内メッセージに圧倒されないよう、この値を10秒未満に設定しないでください。テストやサンプルアプリのフローでは、5秒が一般的な設定です。 テスト用にこの間隔を`0`に設定できます。ただし、`0`秒の間隔は複数のアプリ内メッセージを同時に表示させるものではありません。1つのアプリ内メッセージがすでに表示されている場合、現在のメッセージが閉じられるまで、別のトリガーされたメッセージは表示されません。 ```javascript // Sets the minimum time interval between triggered in-app messages to 5 seconds instead of the default 30 braze.initialize('YOUR-API-KEY', { minimumIntervalBetweenTriggerActionsInSeconds: 5 }) ``` ```xml 5 ``` ```swift let configuration = Braze.Configuration( apiKey: "YOUR-APP-IDENTIFIER-API-KEY", endpoint: "YOUR-BRAZE-ENDPOINT" ) // Sets the minimum trigger time interval to 5 seconds configuration.triggerMinimumTimeInterval = 5 let braze = Braze(configuration: configuration) AppDelegate.braze = braze ``` ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:@"" endpoint:@""]; // Sets the minimum trigger time interval to 5 seconds configuration.triggerMinimumTimeInterval = 5; Braze *braze = [BrazePlugin initBraze:configuration]; AppDelegate.braze = braze; ``` ## 手動でメッセージをトリガーする {#manually-triggering-messages} デフォルトでは、アプリ内メッセージはSDKがカスタムイベントを記録したときに自動的にトリガーされます。しかし、これに加えて、以下の方法を使って手動でメッセージをトリガーすることもできます。 ### サーバー側のイベントを使用する {#using-a-server-side-event} 現時点では、Web Braze SDKはサーバー側のイベントを使用して手動でメッセージをトリガーすることをサポートしていません。 サーバー送信イベントを使用してアプリ内メッセージをトリガーするには、サイレントプッシュ通知をデバイスに送信し、カスタムプッシュコールバックがSDKベースのイベントをログに記録できるようにします。このイベントは、その後ユーザー向けのアプリ内メッセージをトリガーします。 #### ステップ1: サイレントプッシュを受信するプッシュコールバックを作成する {#step-1-create-a-push-callback-to-receive-the-silent-push} 特定のサイレントプッシュ通知をリッスンするには、カスタムプッシュコールバックを登録します。詳細については、[プッシュ通知の設定](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications#android_setting-up-push-notifications)を参照してください。 アプリ内メッセージが配信されるために2つのイベントが記録されます。1つはサーバーによって記録され、もう1つはカスタムプッシュコールバック内から記録されます。同じイベントが重複しないようにするには、プッシュコールバック内からログに記録されるイベントは、サーバー送信イベントと同じ名前ではなく、「アプリ内メッセージトリガーイベント」などの一般的な命名規則に従う必要があります。そうしないと、単一のユーザーアクションについてログに記録される重複イベントによって、セグメンテーションとユーザーデータが影響を受ける可能性があります。 ```java Braze.getInstance(context).subscribeToPushNotificationEvents(event -> { final Bundle kvps = event.getNotificationPayload().getBrazeExtras(); if (kvps.containsKey("IS_SERVER_EVENT")) { BrazeProperties eventProperties = new BrazeProperties(); // The campaign name is a string extra that clients can include in the push String campaignName = kvps.getString("CAMPAIGN_NAME"); eventProperties.addProperty("campaign_name", campaignName); Braze.getInstance(context).logCustomEvent("IAM Trigger", eventProperties); } }); ``` ```kotlin Braze.getInstance(applicationContext).subscribeToPushNotificationEvents { event -> val kvps = event.notificationPayload.brazeExtras if (kvps.containsKey("IS_SERVER_EVENT")) { val eventProperties = BrazeProperties() // The campaign name is a string extra that clients can include in the push val campaignName = kvps.getString("CAMPAIGN_NAME") eventProperties.addProperty("campaign_name", campaignName) Braze.getInstance(applicationContext).logCustomEvent("IAM Trigger", eventProperties) } } ``` #### ステップ2: プッシュキャンペーンを作成する {#step-2-create-a-push-campaign} サーバー送信イベントを介してトリガーされる[サイレントプッシュキャンペーン](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent?sdktab=android)を作成します。 ![アクションベースの配信で設定されたサイレントプッシュキャンペーンの配信ステップ。server_eventカスタムイベントトリガーが設定されている。](https://www.braze.com/docs/ja/ja/assets/img_archive/serverSentPush.png?ba3ed6cdbb6033f36d1e824f9ac5c350) プッシュキャンペーンにはキーと値のペアエクストラを含める必要があります。これは、このプッシュキャンペーンがSDKカスタムイベントを記録するために送信されることを示します。このイベントはアプリ内メッセージをトリガーするために使用されます。 ![2組のキーと値のペア: IS_SERVER_EVENTが「true」に設定され、CAMPAIGN_NAMEが「example campaign name」に設定されている。](https://www.braze.com/docs/ja/ja/assets/img_archive/kvpConfiguration.png?2bd106b4fee497321c428fe8b8a6ccbe){: style="max-width:70%;" } 前出のプッシュコールバックサンプルコードは、キーと値のペアを認識して、適切なSDKカスタムイベントをログに記録します。 「アプリ内メッセージトリガー」イベントに添付するイベントプロパティを含めるには、プッシュペイロードのキーと値のペアでプロパティを渡します。この例では、後続のアプリ内メッセージのキャンペーン名が含められています。カスタムプッシュコールバックは、カスタムイベントをログに記録するときに、イベントプロパティのパラメーターとして値を渡すことができます。 #### ステップ3: アプリ内メッセージキャンペーンを作成する {#step-3-create-an-in-app-message-campaign} Brazeダッシュボードで、ユーザーに表示されるアプリ内メッセージキャンペーンを作成します。このキャンペーンにはアクションベースの配信が必要であり、カスタムプッシュコールバック内から記録されたカスタムイベントからトリガーされる必要があります。 以下の例では、イベントプロパティを最初のサイレントプッシュの一部として送信することで、トリガーされる特定のアプリ内メッセージが設定されています。 ![アクションベースの配信キャンペーンで、「campaign_name」が「IAM campaign name example」と等しい場合にアプリ内メッセージがトリガーされる。](https://www.braze.com/docs/ja/ja/assets/img_archive/iam_event_trigger.png?131d09d4b7d8389dca24630f1e3ad054) アプリがフォアグラウンドにないときにサーバー送信イベントがログに記録されると、イベントはログに記録されますが、アプリ内メッセージは表示されません。アプリケーションがフォアグラウンドになるまでイベントを遅延させたい場合は、カスタムプッシュレシーバーにチェックを含めて、アプリがフォアグラウンドになるまでイベントを無視または遅延させる必要があります。 #### ステップ1: サイレントプッシュとキーと値のペアを処理する {#step-1-handle-silent-push-and-key-value-pairs} 次の関数を実装し、[`application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`メソッド](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application/)内で呼び出します。 ```swift func handleExtras(userInfo: [AnyHashable : Any]) { print("A push was received") if userInfo != nil && (userInfo["IS_SERVER_EVENT"] as? String) != nil && (userInfo["CAMPAIGN_NAME"] as? String) != nil { AppDelegate.braze?.logCustomEvent("IAM Trigger", properties: ["campaign_name": userInfo["CAMPAIGN_NAME"]]) } } ``` ```objc - (void)handleExtrasFromPush:(NSDictionary *)userInfo { NSLog(@"A push was received."); if (userInfo !=nil && userInfo[@"IS_SERVER_EVENT"] !=nil && userInfo[@"CAMPAIGN_NAME"]!=nil) { [AppDelegate.braze logCustomEvent:@"IAM Trigger" properties:@{@"campaign_name": userInfo[@"CAMPAIGN_NAME"]}]; } }; ``` サイレントプッシュを受信すると、ユーザープロファイルに対してSDKが記録したイベント「アプリ内メッセージトリガー」がログに記録されます。 **Important:** SDKのログに記録されたカスタムイベントの記録にプッシュメッセージが使用されているため、Brazeはこのソリューションを有効にするために、ユーザーごとにプッシュトークンを格納する必要があります。iOSユーザーの場合、BrazeではユーザーがOSのプッシュプロンプトを受け取った時点からのトークンのみが保存されます。これ以前では、ユーザーはプッシュを使用して到達できず、先行ソリューションも実行できません。 #### ステップ2: サイレントプッシュキャンペーンを作成する {#step-2-create-a-silent-push-campaign} サーバー送信イベントを介してトリガーされる[サイレントプッシュキャンペーン](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent?sdktab=swift)を作成します。 ![カスタムイベント「server_event」をユーザープロファイルに持つユーザーに配信される、アクションベースのアプリ内メッセージキャンペーン。](https://www.braze.com/docs/ja/ja/assets/img_archive/iosServerSentPush.png?f2398c5efce1eef517dc7eabe0b5801b) プッシュキャンペーンにはキーと値のペアエクストラを含める必要があります。これは、このプッシュキャンペーンがSDKカスタムイベントを記録するために送信されることを示します。このイベントはアプリ内メッセージをトリガーするために使用されます。 ![アクションベースの配信アプリ内メッセージキャンペーンには、2つのキーと値のペアがある。「CAMPAIGN_NAME」が「In-app message name example」に設定され、「IS_SERVER_EVENT」が「true」に設定されている。](https://www.braze.com/docs/ja/ja/assets/img_archive/iOSServerPush.png?e84dc261f2b58bc43d35748e9c7db7f7) `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`メソッド内のコードはキー`IS_SERVER_EVENT`をチェックし、存在する場合はSDKカスタムイベントをログに記録します。 プッシュペイロードのキーと値のペアエクストラ内で目的の値を送信することで、イベント名またはイベントプロパティのいずれかを変更できます。カスタムイベントを記録する場合、これらのエクストラはイベント名のパラメーターまたはイベントプロパティとして使用できます。 #### ステップ3: アプリ内メッセージキャンペーンを作成する Brazeダッシュボードで、ユーザーに表示されるアプリ内メッセージキャンペーンを作成します。このキャンペーンにはアクションベースの配信があり、`application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`メソッド内から記録されたカスタムイベントからトリガーされる必要があります。 以下の例では、イベントプロパティを最初のサイレントプッシュの一部として送信することで、トリガーされる特定のアプリ内メッセージが設定されています。 ![カスタムイベント「In-app message trigger」を実行したユーザーに配信される、アクションベースのアプリ内メッセージキャンペーン。「campaign_name」が「IAM キャンペーン Name Example」と等しい。](https://www.braze.com/docs/ja/ja/assets/img_archive/iosIAMeventTrigger.png?2f425e73fa63c23e0270be6007c72cbe) **Note:** これらのアプリ内メッセージは、アプリケーションがフォアグラウンドにある間にサイレントプッシュが受信された場合にのみトリガーされます。 ### 事前定義されたメッセージを表示する {#displaying-a-pre-defined-message} 事前定義したアプリ内メッセージを手動で表示するには、以下の方法を使用します。 Web SDKでは、`braze.showInAppMessage(inAppMessage)`を使用してアプリ内メッセージを表示します。詳細と例については、[リアルタイムでメッセージを表示する](#displaying-a-message-in-real-time)を参照してください。 ```java BrazeInAppMessageManager.getInstance().addInAppMessage(inAppMessage); ``` ```kotlin BrazeInAppMessageManager.getInstance().addInAppMessage(inAppMessage) ``` ```swift if let inAppMessage = AppDelegate.braze?.inAppMessagePresenter?.nextAvailableMessage() { AppDelegate.braze?.inAppMessagePresenter?.present(message: inAppMessage) } ``` ### リアルタイムでメッセージを表示する {#displaying-a-message-in-real-time} ダッシュボードで利用できるのと同じカスタマイズオプションを使って、ローカルのアプリ内メッセージをリアルタイムで作成・表示することもできます。そのためには: ```javascript // Displays a slideup type in-app message. var message = new braze.SlideUpMessage("Welcome to Braze! This is an in-app message."); message.slideFrom = braze.InAppMessage.SlideFrom.TOP; braze.showInAppMessage(message); ``` ```java // Initializes a new slideup type in-app message and specifies its message. InAppMessageSlideup inAppMessage = new InAppMessageSlideup(); inAppMessage.setMessage("Welcome to Braze! This is a slideup in-app message."); ``` ```kotlin // Initializes a new slideup type in-app message and specifies its message. val inAppMessage = InAppMessageSlideup() inAppMessage.message = "Welcome to Braze! This is a slideup in-app message." ``` **Important:** ソフトキーボードが画面に表示されているときは、レンダリングが定義されていないため、アプリ内メッセージを表示しないでください。 `inAppMessagePresenter`で[`present(message:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazeinappmessagepresenter/present(message:))メソッドを手動で呼び出します。以下に例を示します。 ```swift let customInAppMessage = Braze.InAppMessage.slideup( .init(message: "YOUR_CUSTOM_SLIDEUP_MESSAGE", slideFrom: .bottom, themes: .defaults) ) AppDelegate.braze?.inAppMessagePresenter?.present(message: customInAppMessage) ``` ```objc BRZInAppMessageRaw *customInAppMessage = [[BRZInAppMessageRaw alloc] init]; customInAppMessage.type = BRZInAppMessageRawTypeSlideup; customInAppMessage.message = @"YOUR_CUSTOM_SLIDEUP_MESSAGE"; customInAppMessage.slideFrom = BRZInAppMessageRawSlideFromBottom; customInAppMessage.themes = @{ @"light": BRZInAppMessageRawTheme.defaultLight, @"dark": BRZInAppMessageRawTheme.defaultDark }; [AppDelegate.braze.inAppMessagePresenter presentMessage:customInAppMessage]; ``` **Note:** 独自のアプリ内メッセージを作成する場合、分析トラッキングをオプトアウトし、`message.context`を使用してクリックとインプレッションのロギングを手動で処理する必要があります。 スタックの次のメッセージを表示するには、`DisplayNextInAppMessage()`メソッドを使用します。`DISPLAY_LATER`または`BrazeUnityInAppMessageDisplayActionType.IAM_DISPLAY_LATER`がアプリ内メッセージ表示アクションとして選択されている場合、メッセージはこのスタックに保存されます。 ```csharp Appboy.AppboyBinding.DisplayNextInAppMessage(); ``` ## アプリ内メッセージの遅延の原因 {#causes-of-in-app-message-delays} セッション開始後数秒でアプリ内メッセージキャンペーンを受信した場合、遅延は以下の原因で発生した可能性があります: - キャンペーントリガーの遅延 - カスタマイズ - トリガーイベントの記録が予想より遅かった場合(`templated_iam`の場合など) ## Web用Exit-intentメッセージ {#exit-intent-messages-for-web} Exit-intentメッセージは、訪問者がWebサイトを離れる前に重要な情報を伝えるために使用される、中断のないアプリ内メッセージです。 Web SDKでこれらのメッセージタイプのトリガーを設定するには、Webサイトにexit-intentライブラリ([ouibounceのオープンソースライブラリ](https://github.com/carlsednaoui/ouibounce)など)を実装し、次のコードを使ってBrazeのカスタムイベントとして`'exit intent'`をログに記録します。これで、今後のアプリ内メッセージキャンペーンでは、このメッセージタイプをカスタムイベントトリガーとして使用できます。 ```javascript var _ouibounce = ouibounce(false, { callback: function() { braze.logCustomEvent('exit intent'); } }); ``` # HTMLアプリ内メッセージ Source: /docs/ja/developer_guide/in_app_messages/html_messages/index.md # HTMLアプリ内メッセージ {#html-in-app-messages} > アプリにBraze JavaScriptインターフェイスを追加して、Braze APIを使用してカスタムWebViewで[HTMLアプリ内メッセージ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/message_types/custom_html)を作成する方法を説明します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## About HTML messages With the Braze JavaScript interface, you can leverage Braze inside the custom WebViews within your app. The [`InAppMessageJavascriptInterface`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage.jsinterface/-in-app-message-javascript-interface/index.html) is responsible for: 1. Injecting the Braze JavaScript bridge into your WebView, as outlined in [User Guide: HTML in-app messages](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/customize/#custom-html-messages). 2. Passing the bridge methods received from your WebView to the [Braze Android SDK](https://github.com/braze-inc/braze-android-sdk). ## Adding the interface to a WebView Using Braze functionality from a WebView in your app can be done by adding the Braze JavaScript interface to your WebView. After the interface has been added, the same API available for [User Guide: HTML in-app messages](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/customize/#custom-html-messages) will be available within your custom WebView. ```java String javascriptString = BrazeFileUtils.getAssetFileStringContents(context.getAssets(), "braze-html-bridge.js"); myWebView.loadUrl("javascript:" + javascriptString); final InAppMessageJavascriptInterface javascriptInterface = new InAppMessageJavascriptInterface(context, inAppMessage); myWebView.addJavascriptInterface(javascriptInterface, "brazeInternalBridge"); ``` ```kotlin val javascriptString = context.assets.getAssetFileStringContents("braze-html-bridge.js") myWebView.loadUrl("javascript:" + javascriptString!!) val javascriptInterface = InAppMessageJavascriptInterface(context, inAppMessage) myWebView.addJavascriptInterface(javascriptInterface, "brazeInternalBridge") ``` ## Embedding YouTube content YouTube and other HTML5 content can play in HTML in-app messages. This requires hardware acceleration to be enabled in the activity where the in-app message is being displayed; see the [Android developer guide](https://developer.android.com/guide/topics/graphics/hardware-accel.html#controlling) for more details. Hardware acceleration is only available on Android API versions 11 and later. The following is an example of an embedded YouTube video in an HTML snippet: ```html
X
``` ## Using deep links When using deep links or external links in Android HTML in-app messages, **do not** call `brazeBridge.closeMessage()` in your JavaScript. The SDK's internal logic automatically closes the in-app message when it redirects to a link. Calling `brazeBridge.closeMessage()` interferes with this process and may cause the message to become unresponsive when users return to your app. The following is an example of a deep link in a code snippet: ```javascript ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). ## About HTML messages With the Braze JavaScript interface, you can leverage Braze inside the custom WebViews within your app. The interface's [`ScriptMessageHandler`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/webviewbridge/scriptmessagehandler) is responsible for: 1. Injecting the Braze JavaScript bridge into your WebView, as outlined in [User Guide: HTML in-app messages](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/in-app_messages/customize/#custom-html-messages). 2. Passing the bridge methods received from your WebView to the [Braze Swift SDK](https://github.com/braze-inc/braze-swift-sdk). ## Adding the interface to a WebView First, add the [`ScriptMessageHandler`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/webviewbridge/scriptmessagehandler) from `WebViewBridge` to your app. ```swift let scriptMessageHandler = Braze.WebViewBridge.ScriptMessageHandler(braze: braze) ``` Add the initialized `scriptMessageHandler` to a WkWebView's `userContentController`. ```swift configuration.userContentController.add( scriptMessageHandler, name: Braze.WebViewBridge.ScriptMessageHandler.name ) ``` Then create the WebView using your configuration. ```swift let webView = WKWebView(frame: .zero, configuration: configuration) ``` When you're finished, your code should be similar to the following: ```swift // Create the script message handler using your initialized Braze instance. let scriptMessageHandler = Braze.WebViewBridge.ScriptMessageHandler(braze: braze) // Create a web view configuration and setup the script message handler. let configuration = WKWebViewConfiguration() configuration.userContentController.addUserScript( Braze.WebViewBridge.ScriptMessageHandler.script ) configuration.userContentController.add( scriptMessageHandler, name: Braze.WebViewBridge.ScriptMessageHandler.name ) // Create the webview using the configuration let webView = WKWebView(frame: .zero, configuration: configuration) ``` ## Example: Logging a custom event In the following example, `BrazeBridge` logs a custom event from existing web content to the Braze Swift SDK. ```javascript Logging data via BrazeBridge Example ``` # Braze SDKのアプリ内メッセージのディープリンク Source: /docs/ja/developer_guide/in_app_messages/deep_linking/index.md # アプリ内メッセージのディープリンク {#in-app-message-deep-linking} > Braze SDKのアプリ内メッセージ内でディープリンクを行う方法について説明します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Creating a universal delegate The Android SDK provides the ability to set a single delegate object to custom handle all deep links opened by Braze across Content Cards, in-app messages, and push notifications. Your delegate object should implement the [`IBrazeDeeplinkHandler`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-deeplink-handler/index.html) interface and be set using [`BrazeDeeplinkHandler.setBrazeDeeplinkHandler()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-deeplink-handler/-companion/set-braze-deeplink-handler.html). In most cases, the delegate should be set in your app's `Application.onCreate()`. The following is an example of overriding the default [`UriAction`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.actions/-uri-action/index.html) behavior with custom intent flags and custom behavior for YouTube URLs: ```java public class CustomDeeplinkHandler implements IBrazeDeeplinkHandler { private static final String TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler.class); @Override public void gotoUri(Context context, UriAction uriAction) { String uri = uriAction.getUri().toString(); // Open YouTube URLs in the YouTube app and not our app if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) { uriAction.setUseWebView(false); } CustomUriAction customUriAction = new CustomUriAction(uriAction); customUriAction.execute(context); } public static class CustomUriAction extends UriAction { public CustomUriAction(@NonNull UriAction uriAction) { super(uriAction); } @Override protected void openUriWithActionView(Context context, Uri uri, Bundle extras) { Intent intent = getActionViewIntent(context, uri, extras); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); if (intent.resolveActivity(context.getPackageManager()) != null) { context.startActivity(intent); } else { BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link " + uri + "."); } } } } ``` ```kotlin class CustomDeeplinkHandler : IBrazeDeeplinkHandler { override fun gotoUri(context: Context, uriAction: UriAction) { val uri = uriAction.uri.toString() // Open YouTube URLs in the YouTube app and not our app if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) { uriAction.useWebView = false } val customUriAction = CustomUriAction(uriAction) customUriAction.execute(context) } class CustomUriAction(uriAction: UriAction) : UriAction(uriAction) { override fun openUriWithActionView(context: Context, uri: Uri, extras: Bundle) { val intent = getActionViewIntent(context, uri, extras) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP if (intent.resolveActivity(context.packageManager) != null) { context.startActivity(intent) } else { BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link $uri.") } } } companion object { private val TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler::class.java) } } ``` ## Deep linking to app settings To allow deep links to directly open your app's settings, you'll need a custom `BrazeDeeplinkHandler`. In the following example, the presence of a custom key-value pair called `open_notification_page` will make the deep link open the app's settings page: ```java BrazeDeeplinkHandler.setBrazeDeeplinkHandler(new IBrazeDeeplinkHandler() { @Override public void gotoUri(Context context, UriAction uriAction) { final Bundle extras = uriAction.getExtras(); if (extras.containsKey("open_notification_page")) { Intent intent = new Intent(); intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //for Android 5-7 intent.putExtra("app_package", context.getPackageName()); intent.putExtra("app_uid", context.getApplicationInfo().uid); // for Android 8 and later intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName()); context.startActivity(intent); } } }); ``` ```kotlin BrazeDeeplinkHandler.setBrazeDeeplinkHandler(object : IBrazeDeeplinkHandler { override fun gotoUri(context: Context, uriAction: UriAction) { val extras = uriAction.extras if (extras.containsKey("open_notification_page")) { val intent = Intent() intent.action = "android.settings.APP_NOTIFICATION_SETTINGS" intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK //for Android 5-7 intent.putExtra("app_package", context.packageName) intent.putExtra("app_uid", context.applicationInfo.uid) // for Android 8 and later intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName) context.startActivity(intent) } } }) ``` ## Customizing WebView activity {#Custom_Webview_Activity} When Braze opens website deeplinks inside the app, the deeplinks are handled by [`BrazeWebViewActivity`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-web-view-activity/index.html). **Note:** For custom HTML in-app messages, links configured with `target="_blank"` open in the device's default web browser and are not handled by `BrazeWebViewActivity`. To change this: 1. Create a new Activity that handles the target URL from `Intent.getExtras()` with the key `com.braze.Constants.BRAZE_WEBVIEW_URL_EXTRA`. For an example, see [`BrazeWebViewActivity.kt`](https://github.com/braze-inc/braze-android-sdk/blob/master/android-sdk-ui/src/main/java/com/braze/ui/BrazeWebViewActivity.kt). 2. Add that activity to `AndroidManifest.xml` and set `exported` to `false`. ```xml ``` 3. Set your custom Activity in a `BrazeConfig` [builder object](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-custom-web-view-activity-class.html). Build the builder and pass it to [`Braze.configure()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/configure.html) in your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()). ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setCustomWebViewActivityClass(MyCustomWebViewActivity::class) ... .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setCustomWebViewActivityClass(MyCustomWebViewActivity::class.java) ... .build() Braze.configure(this, brazeConfig) ``` ## Troubleshooting If deep links from push notifications aren't working on Android, try the following steps: 1. **Test the deep link outside of Braze.** Open the deep link URL from another app, such as email or a browser. If it doesn't open your app, the deep link may not be configured correctly in your `AndroidManifest.xml`. For more information, see Android's [Create Deep Links](https://developer.android.com/training/app-links/deep-linking) documentation. 2. **Check that automatic deep link handling is enabled.** Verify that `com_braze_handle_push_deep_links_automatically` is set to `true` in `braze.xml`, or set this option through [runtime configuration](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization/?sdktab=android). Without this setting, Braze doesn't automatically open your app and deep link destination when someone taps a push notification. 3. **Verify your deep link handler delegate.** If you set a custom `IBrazeDeeplinkHandler`, confirm that your `gotoUri` implementation handles the URI and doesn't drop it. 4. **Test across channels.** If the same deep link works in an in-app message but not from push, the issue is likely in your push deep link handling, not in the deep link itself. ## Using Jetpack Compose To handle deeplinks when using Jetpack Compose with NavHost: 1. Ensure that the activity handling your deeplink is registered in the Android Manifest. ```xml ``` 2. In NavHost, specify which deeplinks you want it to handle. ```kotlin composableWithCompositionLocal( route = "YOUR_ROUTE_HERE", deepLinks = listOf(navDeepLink { uriPattern = "myapp://articles/{${MainDestinations.ARTICLE_ID_KEY}}" }), arguments = listOf( navArgument(MainDestinations.ARTICLE_ID_KEY) { type = NavType.LongType } ), ) { backStackEntry -> val arguments = requireNotNull(backStackEntry.arguments) val articleId = arguments.getLong(MainDestinations.ARTICLE_ID_KEY) ArticleDetail( articleId ) } ``` 3. Depending on your app architecture, you may need to handle the new intent that's sent to your current activity as well. ```kotlin DisposableEffect(Unit) { val listener = Consumer { navHostController.handleDeepLink(it) } addOnNewIntentListener(listener) onDispose { removeOnNewIntentListener(listener) } } ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). **Tip:** For help choosing between custom scheme deep links, universal links, and "Open Web URL Inside App," see [iOS deep linking guide](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/ios_deep_linking_guide). For troubleshooting, see [Deep linking troubleshooting](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking_troubleshooting). ## Handling deep links ### Step 1: Register a scheme {#register-a-scheme} To handle deep linking, a custom scheme must be stated in your `Info.plist` file. The navigation structure is defined by an array of dictionaries. Each of those dictionaries contains an array of strings. Use Xcode to edit your `Info.plist` file: 1. Add a new key, `URL types`. Xcode will automatically make this an array containing a dictionary called `Item 0`. 2. Within `Item 0`, add a key `URL identifier`. Set the value to your custom scheme. 3. Within `Item 0`, add a key `URL Schemes`. This will automatically be an array containing a `Item 0` string. 4. Set `URL Schemes` >> `Item 0` to your custom scheme. Alternatively, if you wish to edit your `Info.plist` file directly, you can follow this spec: ```html CFBundleURLTypes CFBundleURLName YOUR.SCHEME CFBundleURLSchemes YOUR.SCHEME ``` ### Step 2: Add a scheme allowlist You must declare the URL schemes you wish to pass to `canOpenURL(_:)` by adding the `LSApplicationQueriesSchemes` key to your app's Info.plist file. Attempting to call schemes outside this allowlist will cause the system to record an error in the device's logs, and the deep link will not open. An example of this error will look like this: ``` : -canOpenURL: failed for URL: "yourapp://deeplink" – error: "This app is not allowed to query for scheme yourapp" ``` For example, if an in-app message should open the Facebook app when tapped, the app has to have the Facebook custom scheme (`fb`) in your allowlist. Otherwise, the system will reject the deep link. Deep links that direct to a page or view inside your own app still require that your app's custom scheme be listed in your app's `Info.plist`. Your example allowlist might look something like: ```html LSApplicationQueriesSchemes myapp fb twitter ``` For more information, refer to [Apple's documentation](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/TP40009250-SW14) on the `LSApplicationQueriesSchemes` key. ### Step 3: Implement a handler After activating your app, iOS will call the method [`application:openURL:options:`](https://developer.apple.com/reference/uikit/uiapplicationdelegate/1623112-application?language=objc). The important argument is the [NSURL](https://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSURL) object. ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let path = url.path let query = url.query // Insert your code here to take some action based upon the path and query. return true } ``` ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *path = [url path]; NSString *query = [url query]; // Insert your code here to take some action based upon the path and query. return YES; } ``` ## App Transport Security (ATS) As defined by [Apple](https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html#//apple_ref/doc/uid/TP40016198-SW14), "App Transport Security is a feature that improves the security of connections between an app and web services. The feature consists of default connection requirements that conform to best practices for secure connections. Apps can override this default behavior and turn off transport security." ATS is applied by default. It requires that all connections use HTTPS and are encrypted using TLS 1.2 with forward secrecy. Refer to [Requirements for Connecting Using ATS](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35) for more information. All images served by Braze to end devices are handled by a content delivery network ("CDN") that supports TLS 1.2 and is compatible with ATS. Unless they are specified as exceptions in your application's `Info.plist`, connections that do not follow these requirements will fail with errors that are similar to the following. **Example Error 1:** ```bash CFNetwork SSLHandshake failed (-9801) Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred, and a secure connection to the server cannot be made." ``` **Example Error 2:** ```bash NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802) ``` ATS compliance is enforced for links opened within the mobile app (our default handling of clicked links) and does not apply to sites opened externally via a web browser. ### Working with ATS You can handle ATS in either of the following ways, but we recommend **complying with ATS requirements**. Your Braze integration can satisfy ATS requirements by ensuring that any existing links you drive users to (for example, though in-app message and push campaigns) satisfy ATS requirements. While there are ways to bypass ATS restrictions, our recommendation is to ensure that all linked URLs are ATS-compliant. Given Apple's increasing emphasis on application security, the following approaches to allowing ATS exceptions are not guaranteed to be supported by Apple. You can allow a subset of links with certain domains or schemes to be treated as exceptions to the ATS rules. Your Braze integration will satisfy ATS requirements if every link you use in a Braze messaging channel is either ATS compliant or handled by an exception. To add a domain as an exception of the ATS, add following to your app's `Info.plist` file: ```html NSAppTransportSecurity NSAllowsArbitraryLoads NSExceptionDomains example.com NSExceptionAllowsInsecureHTTPLoads NSIncludesSubdomains ``` Refer to Apple's article on [app transport security keys](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33) for more information. You can turn off ATS entirely. Note that this is not recommended practice, due to both lost security protections and future iOS compatibility. To disable ATS, insert the following in your app's `Info.plist` file: ```html NSAppTransportSecurity NSAllowsArbitraryLoads ``` ## Decoding URLs The SDK percent-encodes links to create valid `URL`s. All link characters that are not allowed in a properly formed URL, such as Unicode characters, will be percent escaped. To decode an encoded link, use the `String` property [`removingPercentEncoding`](https://developer.apple.com/documentation/swift/stringprotocol/removingpercentencoding). You must also return `true` in the `BrazeDelegate.braze(_:shouldOpenURL:)`. A call to action is required to trigger the handling of the URL by your app. For example: ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let urlString = url.absoluteString.removingPercentEncoding // Handle urlString return true } ``` ```objc - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { NSString *urlString = [url.absoluteString stringByRemovingPercentEncoding]; // Handle urlString return YES; } ``` ## Deep linking to app settings You can take advantage of `UIApplicationOpenSettingsURLString` to deep link users to your app's settings from Braze push notifications and in-app messages. To take users from your app into the iOS settings: 1. First, make sure your application is set up for either [scheme-based deep links](#swift_register-a-scheme) or [universal links](#swift_universal-links). 2. Decide on a URI for deep linking to the **Settings** page (for example, `myapp://settings` or `https://www.braze.com/settings`). 3. If you are using custom scheme-based deep links, add the following code to your `application:openURL:options:` method: ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { let path = url.path if (path == "settings") { UIApplication.shared.openURL(URL(string:UIApplication.openSettingsURLString)!) } return true } ``` ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *path = [url path]; if ([path isEqualToString:@"settings"]) { NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; [[UIApplication sharedApplication] openURL:settingsURL]; } return YES; } ``` ## Customization options {#customization-options} ### Default WebView customization The `Braze.WebViewController` class displays web URLs opened by the SDK, typically when "Open Web URL Inside App" is selected for a web deep link. You can customize the `Braze.WebViewController` via the [`BrazeDelegate.braze(_:willPresentModalWithContext:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazedelegate/braze(_:willpresentmodalwithcontext:)-12sqy/) delegate method. ### Linking handling customization The `BrazeDelegate` protocol can be used to customize the handling of URLs such as deep links, web URLs, and universal links. To set the delegate during Braze initialization, set a delegate object on the `Braze` instance. Braze will then call your delegate's implementation of `shouldOpenURL` before handling any URIs. When a push notification or in-app message uses **Open web URL inside mobile app**, Braze passes `context.useWebView == true` on [`Braze.URLContext`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/urlcontext). When the message opens the URL in the system browser instead, `useWebView` is `false`. Inspect `context.useWebView` in `braze(_:shouldOpenURL:)` to branch your custom handling—for example, to open an in-app `WebViewController` only when the campaign requested in-app display. #### Universal links {#universal-links} Braze supports universal links in push notifications, in-app messages, and Content Cards. To enable universal link support, [`configuration.forwardUniversalLinks`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/forwarduniversallinks) must be set to `true`. When enabled, Braze will forward universal links to your app's `AppDelegate` via the [`application:continueUserActivity:restorationHandler:`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623072-application) method. Your application also needs to be set up to handle universal links. Refer to [Apple's documentation](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) to ensure your application is configured correctly for universal links. **Warning:** Universal link forwarding requires access to the application entitlements. When running the application in a simulator, these entitlements are not directly available and universal links are not forwarded to the system handlers. To add support to simulator builds, you can add the application `.entitlements` file to the _Copy Bundle Resources_ build phase. See [`forwardUniversalLinks`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/forwarduniversallinks) documentation for more details. **Note:** The SDK does not query your domains' `apple-app-site-association` file. It performs the differentiation between universal links and regular URLs by looking at the domain name only. As a result, the SDK does not respect any exclusion rule defined in the `apple-app-site-association` per [Supporting associated domains](https://developer.apple.com/documentation/xcode/supporting-associated-domains). ## Examples ### BrazeDelegate Here's an example using `BrazeDelegate`. For more information, see [Braze Swift SDK reference](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazedelegate). ```swift func braze(_ braze: Braze, shouldOpenURL context: Braze.URLContext) -> Bool { if context.url.host == "MY-DOMAIN.com" { // Custom handle link here return false } // Let Braze handle links otherwise return true } ``` ```objc - (BOOL)braze:(Braze *)braze shouldOpenURL:(BRZURLContext *)context { if ([[context.url.host lowercaseString] isEqualToString:@"MY-DOMAIN.com"]) { // Custom handle link here return NO; } // Let Braze handle links otherwise return YES; } ``` # Braze SDKのアプリ内メッセージにGIFを埋め込む Source: /docs/ja/developer_guide/in_app_messages/gifs/index.md # アプリ内メッセージにGIFを埋め込む > Braze SDK のアプリ内メッセージにGIF を埋め込む方法について説明します。 ## About GIFs Braze offers the ability to use a custom image library to display animated GIFs. Although the example below uses [Glide](https://bumptech.github.io/glide/), any image library that supports GIFs is compatible. ## Integrating a custom image library ### Step 1: Creating the image loader delegate The Image Loader delegate must implement the following methods: * [`getInAppMessageBitmapFromUrl()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/get-in-app-message-bitmap-from-url.html) * [`getPushBitmapFromUrl()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/get-push-bitmap-from-url.html) * [`renderUrlIntoCardView()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/render-url-into-card-view.html) * [`renderUrlIntoInAppMessageView()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/render-url-into-in-app-message-view.html) * [`setOffline()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/set-offline.html) The integration example below is taken from the [Glide integration sample app](https://github.com/braze-inc/braze-android-sdk/tree/master/samples/glide-image-integration) included with the Braze Android SDK. ```java import com.braze.support.BrazeLogger; import com.bumptech.glide.load.resource.gif.GifDrawable; import android.graphics.drawable.Drawable; public class GlideBrazeImageLoader implements IBrazeImageLoader { private static final String TAG = GlideBrazeImageLoader.class.getName(); private RequestOptions mRequestOptions = new RequestOptions(); @Override public void renderUrlIntoCardView(Context context, Card card, String imageUrl, ImageView imageView, BrazeViewBounds viewBounds) { renderUrlIntoView(context, imageUrl, imageView); } @Override public void renderUrlIntoInAppMessageView(Context context, IInAppMessage inAppMessage, String imageUrl, ImageView imageView, BrazeViewBounds viewBounds) { renderUrlIntoView(context, imageUrl, imageView); } @Override public Bitmap getPushBitmapFromUrl(Context context, Bundle extras, String imageUrl, BrazeViewBounds viewBounds) { return getBitmapFromUrl(context, imageUrl, viewBounds); } @Override public Bitmap getInAppMessageBitmapFromUrl(Context context, IInAppMessage inAppMessage, String imageUrl, BrazeViewBounds viewBounds) { return getBitmapFromUrl(context, imageUrl, viewBounds); } private void renderUrlIntoView(Context context, String imageUrl, ImageView imageView) { try { final Drawable drawable = Glide.with(context) .load(imageUrl) .apply(mRequestOptions) .submit() .get(); imageView.post(() -> { imageView.setImageDrawable(drawable); if (drawable instanceof GifDrawable) { ((GifDrawable) drawable).start(); } }); } catch (Exception e) { BrazeLogger.e(TAG, "Failed to render URL into view: " + imageUrl, e); } } private Bitmap getBitmapFromUrl(Context context, String imageUrl, BrazeViewBounds viewBounds) { try { return Glide.with(context) .asBitmap() .apply(mRequestOptions) .load(imageUrl).submit().get(); } catch (Exception e) { Log.e(TAG, "Failed to retrieve bitmap at url: " + imageUrl, e); } return null; } @Override public void setOffline(boolean isOffline) { // If the loader is offline, then we should only be retrieving from the cache mRequestOptions = mRequestOptions.onlyRetrieveFromCache(isOffline); } } ``` ```kotlin import com.braze.support.BrazeLogger import com.bumptech.glide.load.resource.gif.GifDrawable class GlideBrazeImageLoader : IBrazeImageLoader { companion object { private val TAG = GlideBrazeImageLoader::class.qualifiedName } private var mRequestOptions = RequestOptions() override fun renderUrlIntoCardView(context: Context, card: Card, imageUrl: String, imageView: ImageView, viewBounds: BrazeViewBounds) { renderUrlIntoView(context, imageUrl, imageView) } override fun renderUrlIntoInAppMessageView(context: Context, inAppMessage: IInAppMessage, imageUrl: String, imageView: ImageView, viewBounds: BrazeViewBounds) { renderUrlIntoView(context, imageUrl, imageView) } override fun getPushBitmapFromUrl(context: Context, extras: Bundle, imageUrl: String, viewBounds: BrazeViewBounds): Bitmap? { return getBitmapFromUrl(context, imageUrl, viewBounds) } override fun getInAppMessageBitmapFromUrl(context: Context, inAppMessage: IInAppMessage, imageUrl: String, viewBounds: BrazeViewBounds): Bitmap? { return getBitmapFromUrl(context, imageUrl, viewBounds) } private fun renderUrlIntoView(context: Context, imageUrl: String, imageView: ImageView) { try { val drawable = Glide.with(context) .load(imageUrl) .apply(mRequestOptions) .submit() .get() imageView.post { imageView.setImageDrawable(drawable) if (drawable is GifDrawable) { drawable.start() } } } catch (e: Exception) { BrazeLogger.e(TAG, "Failed to render URL into view: $imageUrl", e) } } private fun getBitmapFromUrl(context: Context, imageUrl: String, viewBounds: BrazeViewBounds): Bitmap? { try { return Glide.with(context) .asBitmap() .apply(mRequestOptions) .load(imageUrl).submit().get() } catch (e: Exception) { Log.e(TAG, "Failed to retrieve bitmap at url: $imageUrl", e) } return null } override fun setOffline(isOffline: Boolean) { // If the loader is offline, then we should only be retrieving from the cache mRequestOptions = mRequestOptions.onlyRetrieveFromCache(isOffline) } } ``` ### Fixing image loading for Android SDK 36.0.0 and later In Android SDK 36.0.0 and later, `displayInAppMessage()` is a `suspend` function. This means `renderUrlIntoInAppMessageView()` runs on a background thread instead of the main thread. If your custom image loader calls `Glide.into(imageView)` in `renderUrlIntoInAppMessageView()`, your app can fail with "You must call this method on the main thread." To avoid this: 1. Load the image on the background thread with `submit().get()`. 2. Post the UI update to the main thread with `imageView.post { ... }`. 3. If the loaded result is a GIF drawable, start the animation after setting it on the view. This separates image loading from UI rendering, and keeps your custom image loader compatible with Android SDK 36.0.0 and later. This guidance applies to Android custom image loaders. Web in-app messages support GIFs out of the box. The following Kotlin sample uses placeholder values to show this pattern: ```kotlin private const val TAG = "SampleGlideLoader" private const val glideBrazeImageLoaderTag = "sample-loader" private fun renderUrlIntoView( context: Context, imageUrl: String, imageView: ImageView ) { try { val drawable: Drawable = Glide.with(context) .load(imageUrl) .apply(mRequestOptions) .submit() .get() imageView.post { imageView.setImageDrawable(drawable) if (drawable is GifDrawable) { drawable.start() } } } catch (e: Exception) { Log.e(TAG, "$glideBrazeImageLoaderTag renderUrlIntoView failed: url=$imageUrl", e) } } ``` ### Step 2: Setting the image loader delegate The Braze SDK will use any custom image loader set with [`IBrazeImageLoader`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.images/-i-braze-image-loader/index.html). We recommend setting the custom image loader in a custom application subclass: ```java public class GlideIntegrationApplication extends Application { @Override public void onCreate() { super.onCreate(); Braze.getInstance(context).setImageLoader(new GlideBrazeImageLoader()); } } ``` ```kotlin class GlideIntegrationApplication : Application() { override fun onCreate() { super.onCreate() Braze.getInstance(context).imageLoader = GlideBrazeImageLoader() } } ``` ## Custom Image Loading with Jetpack Compose To override image loading with Jetpack Compose, you can pass in a value to [`imageComposable`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.jetpackcompose.contentcards.styling/-content-card-styling/index.html#-808910455%2FProperties%2F-1725759721). This function will take a `Card` and render the image and the modifiers needed. Alternatively, you can use `customCardComposer` of `ContentCardsList` to render the entire card. In the following example, Glide's Compose library is used for the cards listed in the `imageComposable` function: ```kotlin ContentCardsList( cardStyle = ContentCardStyling( imageComposable = { card -> when (card.cardType) { CardType.CAPTIONED_IMAGE -> { val captionedImageCard = card as CaptionedImageCard GlideImage( modifier = Modifier .fillMaxWidth() .wrapContentHeight() .run { if (captionedImageCard.aspectRatio > 0) { aspectRatio(captionedImageCard.aspectRatio) } else { this } }, contentScale = ContentScale.Crop, model = captionedImageCard.url, loading = placeholder(R.drawable.pushpin), contentDescription = "" ) } CardType.IMAGE -> { val imageOnlyCard = card as ImageOnlyCard GlideImage( modifier = Modifier .fillMaxWidth() .run { if (imageOnlyCard.aspectRatio > 0) { aspectRatio(imageOnlyCard.aspectRatio) } else { this } }, contentScale = ContentScale.Crop, model = imageOnlyCard.url, loading = placeholder(R.drawable.pushpin), contentDescription = "" ) } CardType.SHORT_NEWS -> { val shortNews = card as ShortNewsCard GlideImage( modifier = Modifier .width(100.dp) .height(100.dp), model = shortNews.url, loading = placeholder(R.drawable.pushpin), contentDescription = "" ) } else -> Unit } } ) ) ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). ## Integrating a custom image library ### Step 1: Integrate SDWebImage Integrate the [SDWebImage repository](https://github.com/SDWebImage/SDWebImage) into your Xcode project. ### Step 2: Create a new Swift file In your Xcode project, create a new file named `SDWebImageGIFViewProvider.swift` and import the following: ```swift import UIKit import BrazeUI import SDWebImage ``` ### Step 3: Add `GIFViewProvider` Next, add our sample SDWebImage [`GIFViewProvider`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/gifviewprovider/). Your file should be similar to the following: ```swift import UIKit import BrazeUI import SDWebImage extension GIFViewProvider { /// A GIF view provider using [SDWebImage](https://github.com/SDWebImage/SDWebImage) as a /// rendering library. public static let sdWebImage = Self( view: { SDAnimatedImageView(image: image(for: $0)) }, updateView: { ($0 as? SDAnimatedImageView)?.image = image(for: $1) } ) private static func image(for url: URL?) -> UIImage? { guard let url else { return nil } return url.pathExtension == "gif" ? SDAnimatedImage(contentsOfFile: url.path) : UIImage(contentsOfFile: url.path) } } ``` ### Step 4: Modify your `AppDelegate.swift` In your project's `AppDelegate.swift`, add GIF support to your `BrazeUI` components using `GIFViewProvider`. Your file should be similar to the following: ```swift import UIKit import BrazeKit import BrazeUI @main class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { /* ... */ GIFViewProvider.shared = .sdWebImage return true } } ``` # Braze SDKを通じてアプリ内メッセージデータを記録する Source: /docs/ja/developer_guide/in_app_messages/logging_message_data/index.md # アプリ内メッセージデータを記録する > Braze SDK を使用してアプリメッセージ(IAM) データにログインする方法について説明します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ## Logging message data Logging in-app message [impressions](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#loginappmessageimpression) and [clicks](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#loginappmessagebuttonclick) is performed automatically when you use the `showInAppMessage` or `automaticallyShowInAppMessage` method. If you do not use either method and opt to manually display the message using your own UI code, use the following methods to log analytics: ```javascript // Registers that a user has viewed an in-app message with the Braze server. braze.logInAppMessageImpression(inAppMessage); // Registers that a user has clicked on the specified in-app message with the Braze server. braze.logInAppMessageClick(inAppMessage); // Registers that a user has clicked a specified in-app message button with the Braze server. braze.logInAppMessageButtonClick(button, inAppMessage); // Registers that a user has clicked on a link in an HTML in-app message with the Braze server. braze.logInAppMessageHtmlClick(inAppMessage, buttonId?, url?) ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Flutter Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=flutter). ## Logging message data To log analytics using your `BrazeInAppMessage`, pass the instance into the desired analytics function: - `logInAppMessageClicked` - `logInAppMessageImpression` - `logInAppMessageButtonClicked` (along with the button index) For example: ```dart // Log a click braze.logInAppMessageClicked(inAppMessage); // Log an impression braze.logInAppMessageImpression(inAppMessage); // Log button index `0` being clicked braze.logInAppMessageButtonClicked(inAppMessage, 0); ``` ## Accessing message data To access in-app message data in your Flutter app, the `BrazePlugin` supports sending in-app message data using [Dart Streams](https://dart.dev/tutorials/language/streams). The `BrazeInAppMessage` object supports a subset of fields available in the native model objects, including `uri`, `message`, `header`, `buttons`, `extras`, and more. ### Listen for in-app message data in the Dart layer To receive in-app message data in the Dart layer, use the code below to create a `StreamSubscription` and call `braze.subscribeToInAppMessages()`. Remember to `cancel()` the stream subscription when it is no longer needed. ```dart // Create stream subscription StreamSubscription inAppMessageStreamSubscription; inAppMessageStreamSubscription = braze.subscribeToInAppMessages((BrazeInAppMessage inAppMessage) { // Handle in-app messages } // Cancel stream subscription inAppMessageStreamSubscription.cancel(); ``` For an example, see [main.dart](https://github.com/braze-inc/braze-flutter-sdk/blob/master/example/lib/main.dart) in the Braze Flutter SDK sample application. ### Forward in-app message data from the native layer In-app message data is automatically forwarded from both the Android and iOS native layers. No additional setup is required. If you're using Flutter SDK 17.1.0 or earlier, in-app message data forwarding from the iOS native layer requires manual setup. Your application likely contains one of the following. To migrate to Flutter SDK 18.0.0, remove the `BrazePlugin.processInAppMessage(_:)` call—data forwarding is now handled automatically. Remove the `BrazePlugin.processInAppMessage(_:)` call from your [`willPresent` delegate implementation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:willpresent:view:)-4pzvv). Remove the `BrazePlugin.processInAppMessage(message)` call from your custom presenter's [`present(message:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/present(message:)-f2ra) implementation: ```swift class CustomInAppMessagePresenter: BrazeInAppMessageUI { override func present(message: Braze.InAppMessage) { // Pass in-app message data to the Dart layer. BrazePlugin.processInAppMessage(message) // If you want the default UI to display the in-app message. super.present(message: message) } } ``` ### Replaying the callback for in-app messages (optional) To store any in-app messages triggered before the callback is available and replay them after it is set, add the following entry to the `customConfigs` map when initializing the `BrazePlugin`: ```dart BrazePlugin braze = new BrazePlugin(customConfigs: {replayCallbacksConfigKey: true}); ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Methods for logging You can use these methods by passing your `BrazeInAppMessage` instance to log analytics and perform actions: | Method | Description | | --------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `logInAppMessageClicked(inAppMessage)` | Logs a click for the provided in-app message data. | | `logInAppMessageImpression(inAppMessage)` | Logs an impression for the provided in-app message data. | | `logInAppMessageButtonClicked(inAppMessage, buttonId)` | Logs a button click for the provided in-app message data and button ID. | | `hideCurrentInAppMessage()` | Dismisses the currently displayed in-app message. | | `performInAppMessageAction(inAppMessage)` | Performs the action for an in-app message. | | `performInAppMessageButtonAction(inAppMessage, buttonId)` | Performs the action for an in-app message button. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Methods for logging" } ## Handling message data In most cases, you can use the `Braze.addListener` method to register event listeners to handle data coming from in-app messages. Additionally, you can access the in-app message data in the JavaScript layer by calling the `Braze.subscribeToInAppMessage` method to have the SDKs publish an `inAppMessageReceived` event when an in-app message is triggered. Pass a callback to this method to execute your own code when the in-app message is triggered and received by the listener. To customize how message data is handled, refer to the following implementation examples: To enhance the default behavior, or if you don't have access to customize the native iOS or Android code, we recommend that you disable the default UI while still receiving in-app message events from Braze. To disable the default UI, pass `false` to the `Braze.subscribeToInAppMessage` method and use the in-app message data to construct your own message in JavaScript. Note that you will need to manually log analytics on your messages if you choose to disable the default UI. ```javascript import Braze from "@braze/react-native-sdk"; // Option 1: Listen for the event directly via `Braze.addListener`. // // You may use this method to accomplish the same thing if you don't // wish to make any changes to the default Braze UI. Braze.addListener(Braze.Events.IN_APP_MESSAGE_RECEIVED, (event) => { console.log(event.inAppMessage); }); // Option 2: Call `subscribeToInAppMessage`. // // Pass in `false` to disable the automatic display of in-app messages. Braze.subscribeToInAppMessage(false, (event) => { console.log(event.inAppMessage); // Use `event.inAppMessage` to construct your own custom message UI. }); ``` To include more advanced logic to determine whether or not to show an in-app message using the built-in UI, implement in-app messages through the native layer. **Warning:** Since this is an advanced customization option, note that overriding the default Braze implementation will also nullify the logic to emit in-app message events to your JavaScript listeners. If you wish to still use `Braze.subscribeToInAppMessage` or `Braze.addListener` as described in [Accessing in-app message data](#accessing-in-app-message-data), you will need to handle publishing the events yourself. Implement the `IInAppMessageManagerListener` as described in our Android article on [Custom Manager Listener](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization/?sdktab=android#android_setting-custom-manager-listeners). In your `beforeInAppMessageDisplayed` implementation, you can access the `inAppMessage` data, send it to the JavaScript layer, and decide to show or not show the native message based on the return value. For more on these values, see our [Android documentation](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/). ```java // In-app messaging @Override public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessage) { WritableMap parameters = new WritableNativeMap(); parameters.putString("inAppMessage", inAppMessage.forJsonPut().toString()); getReactNativeHost() .getReactInstanceManager() .getCurrentReactContext() .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("inAppMessageReceived", parameters); // Note: return InAppMessageOperation.DISCARD if you would like // to prevent the Braze SDK from displaying the message natively. return InAppMessageOperation.DISPLAY_NOW; } ``` ### Overriding the default UI delegate By default, [`BrazeInAppMessageUI`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/) is created and assigned when you initialize the `braze` instance. `BrazeInAppMessageUI` is an implementation of the [`BrazeInAppMessagePresenter`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazeinappmessagepresenter) protocol and comes with a `delegate` property that can be used to customize the handling of in-app messages that have been received. 1. Implement the `BrazeInAppMessageUIDelegate` delegate as described in [our iOS article here](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/c1-inappmessageui). 2. In the `inAppMessage(_:displayChoiceForMessage:)` delegate method, you can access the `inAppMessage` data, send it to the JavaScript layer, and decide to show or not show the native message based on the return value. For more details on these values, see our [iOS documentation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/). ```objc - (enum BRZInAppMessageUIDisplayChoice)inAppMessage:(BrazeInAppMessageUI *)ui displayChoiceForMessage:(BRZInAppMessageRaw *)message { // Convert the message to a JavaScript representation. NSData *inAppMessageData = [message json]; NSString *inAppMessageString = [[NSString alloc] initWithData:inAppMessageData encoding:NSUTF8StringEncoding]; NSDictionary *arguments = @{ @"inAppMessage" : inAppMessageString }; // Send to JavaScript. [self sendEventWithName:@"inAppMessageReceived" body:arguments]; // Note: Return `BRZInAppMessageUIDisplayChoiceDiscard` if you would like // to prevent the Braze SDK from displaying the message natively. return BRZInAppMessageUIDisplayChoiceNow; } ``` To use this delegate, assign it to `brazeInAppMessagePresenter.delegate` after initializing the `braze` instance. **Note:** `BrazeUI` can only be imported in Objective-C or Swift. If you are using Objective-C++, you will need to handle this in a separate file. ```objc @import BrazeUI; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:apiKey endpoint:endpoint]; Braze *braze = [BrazeReactBridge initBraze:configuration]; ((BrazeInAppMessageUI *)braze.inAppMessagePresenter).delegate = [[CustomDelegate alloc] init]; AppDelegate.braze = braze; } ``` ### Overriding the default native UI If you wish to fully customize the presentation of your in-app messages at the native iOS layer, conform to the [`BrazeInAppMessagePresenter`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazeinappmessagepresenter) protocol and assign your custom presenter following the sample below: ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:apiKey endpoint:endpoint]; Braze *braze = [BrazeReactBridge initBraze:configuration]; braze.inAppMessagePresenter = [[MyCustomPresenter alloc] init]; AppDelegate.braze = braze; ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Logging message data You will need to make sure certain functions are called to handle the analytics for your campaign. ### Displayed messages When a message is displayed or seen, log an impression: ```brightscript LogInAppMessageImpression(in_app_message.id, brazetask) ``` ### Clicked messages Once a user clicks on the message, log a click and then process `in_app_message.click_action`: ```brightscript LogInAppMessageClick(in_app_message.id, brazetask) ``` ### Clicked buttons If the user clicks on a button, log the button click and then process `inappmessage.buttons[selected].click_action`: ```brightscript LogInAppMessageButtonClick(inappmessage.id, inappmessage.buttons[selected].id, brazetask) ``` ### After processing a message After processing an in-app message, you should clear the field: ```brightscript m.BrazeTask.BrazeInAppMessage = invalid ``` ## Subscribing to in-app messages You may register Unity game objects to be notified of incoming in-app messages. We recommend setting game object listeners from the Braze configuration editor. In the configuration editor, listeners must be set separately for Android and iOS. If you need to configure your game object listener at runtime, use `AppboyBinding.ConfigureListener()` and specify `BrazeUnityMessageType.IN_APP_MESSAGE`. ## Parsing messages Incoming `string` messages received in your in-app message game object callback can be parsed into our pre-supplied model objects for convenience. Use `InAppMessageFactory.BuildInAppMessage()` to parse your in-app message. The resulting object will either be an instance of [`IInAppMessage.cs`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/IInAppMessage.cs) or [`IInAppMessageImmersive.cs`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/IInAppMessageImmersive.cs) depending on its type. ```csharp // Automatically logs a button click, if present. void InAppMessageReceivedCallback(string message) { IInAppMessage inApp = InAppMessageFactory.BuildInAppMessage(message); if (inApp is IInAppMessageImmersive) { IInAppMessageImmersive inAppImmersive = inApp as IInAppMessageImmersive; if (inAppImmersive.Buttons != null && inAppImmersive.Buttons.Count > 0) { inAppImmersive.LogButtonClicked(inAppImmersive.Buttons[0].ButtonID); } } } ``` ## Logging message data Clicks and impressions must be manually logged for in-app messages not displayed directly by Braze. Use `LogClicked()` and `LogImpression()` on [`IInAppMessage`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/IInAppMessage.cs) to log clicks and impressions on your message. Use `LogButtonClicked(int buttonID)` on [`IInAppMessageImmersive`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/IInAppMessageImmersive.cs) to log button clicks. Note that buttons are represented as lists of[`InAppMessageButton`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/InAppMessageButton.cs) instances, each of which contains a `ButtonID`. # Braze SDKのテストメッセージを送信する Source: /docs/ja/developer_guide/in_app_messages/sending_test_messages/index.md # Sending test messages > Before sending out a messaging campaign to your users, you may want to test it to make sure it looks right and operates in the intended manner. You can use the dashboard to create and send test messages with push notifications, in-app messages (IAM), or email. ## Sending a test message ### Step 1: Create a designated test segment After you set up a test segment, you can use it to test any of your Braze messaging channels. When set up correctly, this only needs to be done a single time. To set up a test segment, go to **Segments** and create a new segment. Select **Add Filter**, then choose a one of the test filters. ![A Braze test campaign displaying the filters available in the targeting step.](https://www.braze.com/docs/ja/ja/assets/img_archive/testmessages1.png?c440e858d187b30c92b316dfa12b9774) With test filters, you can ensure that only users with a specific email address or [external user ID](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/analytics/setting_user_ids/#setting-user-ids) are sent the test message. ![A dropdown menu displaying several filters listed under a heading that reads Testing](https://www.braze.com/docs/ja/ja/assets/img_archive/testmessages2.png?8c289defede0c6ba588c9b8ba8d0c9f5) Both email address and external user ID filters offer the following options: | Operator | Description | |------------------|--------------------------------------------------------------------------------------------------------------------------------| | `equals` | This will look for an exact match of the email or user ID that you provide. Use this if you only want to send the test campaigns to devices associated with a single email or user ID. | | `does not equal` | Use this if you want to exclude a particular email or user ID from test campaigns. | | `matches` | This will find users that have email addresses or user IDs that match part of the search term you provide. You could use this to find only the users that have an `@yourcompany.com` address, allowing you to send messages to everyone on your team. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Step 1: Create a designated test segment a class="margin-fix" name="test-segment"/a" } You can select multiple specific emails using the "`matches`" option and separating the email addresses with a | character. For example: "`matches`" "`email1@braze.com` | `email2@braze.com`". You can also combine multiple operators together. For example, the test segment could include an email address filter that "`matches`" "`@braze.com`" and another filter that "`does not equal`" "`sales@braze.com`". After adding the testing filters to your test segment, you can verify it's working by selecting **Preview** or by selecting **Settings** > **CSV Export All User Data** to export that segment's user data to a CSV file. ![A section of a Braze campaign titled Segment Details](https://www.braze.com/docs/ja/ja/assets/img_archive/testmessages3.png?78e031a18aad06f510fd2ac4946bf7c5) **Note:** Exporting the segment's User Data to a CSV file is the most accurate verification method, as the preview will only show a sample of your users and may not include all users. ### Step 2: Send the message You can send a message using the Braze dashboard or the command line. To send test push notifications or in-app messages, you need to target your previously created test segment. Begin by creating your campaign and following the usual steps. When you reach the **Target Audiences** step, select your test segment from the dropdown menu. ![A Braze test campaign displaying the segments available in the targeting step.](https://www.braze.com/docs/ja/ja/assets/img_archive/test_segment.png?25ae32cc99d02e6dcdd9b66a0adf75e4) Confirm your campaign and launch it to test your push notification and in-app messages. **Note:** Be sure to select **Allow users to become re-eligible to receive campaign** under the **Schedule** portion of the campaign composer if you intend to use a single campaign to send a test message to yourself more than once. If you're only testing email messages, you do not necessarily have to set up a test segment. In the first step of the campaign composer where you compose your campaign's email message, click **Send Test** and enter the email address to which you wish to send a test email. ![A Braze campaign with the Test Send tab selected](https://www.braze.com/docs/ja/ja/assets/img_archive/testmessages45.png?883cb58cd3adf2e8315817db896b7914) **Tip:** You can also enable or disable [TEST (or SEED)](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/email_settings/#append-email-subject-lines) being appended on your test messages. Alternatively, you can send a single notification using cURL and the [Braze Messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/). Note that these examples make a request using the `US-01` instance. To find out yours, refer to [API endpoints](https://www.braze.com/docs/ja/ja/api/basics/#endpoints). ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer {BRAZE_API_KEY}" -d '{ "external_user_ids":["EXTERNAL_USER_ID"], "messages": { "android_push": { "title":"Test push title", "alert":"Test push", "extra":{ "CUSTOM_KEY":"CUSTOM_VALUE" } } } }' https://rest.iad-01.braze.com/messages/send ``` ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer {BRAZE_API_KEY}" -d '{ "external_user_ids":["EXTERNAL_USER_ID"], "messages": { "apple_push": { "alert": "Test push", "extra": { "CUSTOM_KEY" :"CUSTOM_VALUE" } } } }' https://rest.iad-01.braze.com/messages/send ``` ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer {BRAZE_API_KEY}" -d '{ "external_user_ids":["EXTERNAL_USER_ID"], "messages": { "kindle_push": { "title":"Test push title", "alert":"Test push", "extra":{ "CUSTOM_KEY":"CUSTOM_VALUE" } } } }' https://rest.iad-01.braze.com/messages/send ``` Replace the following: | Placeholder | Description | |---------------------|-----------------------------------------------------------| | `BRAZE_API_KEY` | Your Braze API key used for authentication. In Braze, go to **Settings** > **API Keys** to locate your key. | | `EXTERNAL_USER_ID` | The external user ID used to send your message to a specific user. In Braze, go to **Audience** > **Search users**, then search for a user. | | `CUSTOM_KEY` | (Optional) A custom key for additional data. | | `CUSTOM_VALUE` | (Optional) A custom value assigned to your custom key. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Step 2: Send the message" } ## Test limitations There are a few situations where test messages don't have complete feature parity with launching a campaign or Canvas to a real set of users. In these instances, to validate this behavior, you should launch the campaign or Canvas to a limited set of test users. - Viewing the Braze [preference center](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/managing_user_subscriptions/#subscription-groups) from **Test Messages** will cause the submit button to be grayed out. - The list-unsubscribe header is not included in emails sent by the test message functionality. - For in-app messages and Content Cards, the target user must have a push token for the target device. # チュートリアル Source: /docs/ja/developer_guide/in_app_messages/tutorials/index.md
# チュートリアル: 条件付きでアプリ内メッセージを表示する Source: /docs/ja/developer_guide/in_app_messages/tutorials/conditionally_displaying_messages/index.md # チュートリアル: 条件付きでアプリ内メッセージを表示する {#tutorial-conditionally-displaying-in-app-messages} > このチュートリアルのサンプルコードに従って、Braze SDKを使用してアプリ内メッセージを条件付きで表示する方法を学びます。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ただし、追加の設定は不要です。 ## Webでアプリ内メッセージを条件付きで表示する {#conditionally-displaying-in-app-messages-for-web} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```js file=index.js import * as braze from "@braze/web-sdk"; // Remove any calls to `braze.automaticallyShowInAppMessages()` braze.initialize("YOUR-API-KEY", { baseUrl: "YOUR-ENDPOINT", enableLogging: true, }); braze.subscribeToInAppMessage(function (message) { if ( location.pathname === "/checkout" || document.getElementById("#checkout") ) { // do not show the message } else { braze.showInAppMessage(message); } }); ``` !!step lines-index.js=2 ### 1. `automaticallyShowInAppMessages()` の呼び出しを削除する {#1-remove-calls-to-automaticallyshowinappmessages} [`automaticallyShowInAppMessages()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#automaticallyshowinappmessages) の呼び出しは、後で実装するカスタムロジックをオーバーライドするため、すべて削除してください。 !!step lines-index.js=6 #### 2. デバッグを有効にする(オプション) {#2-enable-debugging-optional} 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-index.js=9-18 #### 3. アプリ内メッセージの更新を購読する {#3-subscribe-to-in-app-message-updates} [`subscribeToInAppMessage(callback)`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#subscribetoinappmessage) にコールバックを登録して、アプリ内メッセージがトリガーされるたびに `message` を受信します。 !!step lines-index.js=10-13 #### 4. 条件付きロジックを作成する {#4-create-conditional-logic} メッセージを表示するタイミングをコントロールするカスタムロジックを作成します。この例では、URLに `"checkout"` が含まれているかどうか、またはページに `#checkout` 要素が存在するかどうかをチェックします。 !!step lines-index.js=16 #### 5. `showInAppMessage` でメッセージを表示する {#5-display-messages-with-showinappmessage} メッセージを表示するには、[`showInAppMessage(message)`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#showinappmessage) を呼び出します。省略した場合、メッセージはスキップされます。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). また、[Androidでアプリ内メッセージを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=android#android_enabling-in-app-messages)必要もあります。 ## Androidでアプリ内メッセージを条件付きで表示する {#conditionally-displaying-in-app-messages-for-android} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```kotlin file=MainApplication.kt import android.app.Application import com.braze.Braze import com.braze.support.BrazeLogger import com.braze.configuration.BrazeConfig import com.braze.ui.inappmessage.BrazeInAppMessageManager import com.braze.BrazeActivityLifecycleCallbackListener import com.braze.ui.inappmessage.listeners.IInAppMessageManagerListener import com.braze.models.inappmessage.IInAppMessage import com.braze.ui.inappmessage.InAppMessageOperation import android.util.Log class MyApplication : Application() { override fun onCreate() { super.onCreate() // Enable verbose Braze SDK logs BrazeLogger.logLevel = Log.VERBOSE // Initialize Braze val brazeConfig = BrazeConfig.Builder() .setApiKey("YOUR-API-KEY") .setCustomEndpoint("YOUR-ENDPOINT") .build() Braze.configure(this, brazeConfig) registerActivityLifecycleCallbacks( BrazeActivityLifecycleCallbackListener() ) // Set up in-app message listener BrazeInAppMessageManager.getInstance().setCustomInAppMessageManagerListener(object : IInAppMessageManagerListener { override fun beforeInAppMessageDisplayed(inAppMessage: IInAppMessage): InAppMessageOperation { // Check if we should show the message val shouldShow = inAppMessage.extras["should_display_message"] == "true" return if (shouldShow) { // Show the message using Braze's UI InAppMessageOperation.DISPLAY_NOW } else { // Discard the message (or we could also create our own UI using KVP values) InAppMessageOperation.DISCARD } } }) } } ``` !!step lines-MainApplication.kt=17 ### 1. デバッグを有効にする(オプション) {#1-enable-debugging-optional} 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-MainApplication.kt=26-28 #### 2. アクティビティライフサイクルコールバックを登録する {#2-register-activity-lifecycle-callbacks} アプリ内メッセージのライフサイクルを処理するBrazeのデフォルトリスナーを登録します。 !!step lines-MainApplication.kt=30-44 #### 3. アプリ内メッセージリスナーを設定する {#3-set-up-an-in-app-message-listener} `BrazeInAppMessageManager` を使用して、メッセージが表示される前にインターセプトするカスタムリスナーを設定します。 !!step lines-MainApplication.kt=34-42 #### 4. 条件付きロジックを作成する カスタムロジックを使用して、メッセージの表示タイミングをコントロールします。この例では、`should_display_message` エクストラが `"true"` に設定されているかどうかをチェックします。 !!step lines-MainApplication.kt=38,41 #### 5. メッセージを返すか破棄する {#5-return-or-discard-the-message} メッセージを表示するには `DISPLAY_NOW` を、非表示にするには `DISCARD` を指定して `InAppMessageOperation` を返します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). また、[Swiftでアプリ内メッセージを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=swift#swift_enabling-in-app-messages)必要もあります。 ## Swiftでアプリ内メッセージを条件付きで表示する {#conditionally-displaying-in-app-messages-for-swift} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```swift file=AppDelegate.swift import SwiftUI import BrazeKit import BrazeUI class AppDelegate: NSObject, UIApplicationDelegate, BrazeInAppMessageUIDelegate { static var braze: Braze? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { // 1. Braze configuration with your SDK API key and endpoint let configuration = Braze.Configuration(apiKey: "YOUR_API_ENDPOINT", endpoint: "YOUR_API_KEY") configuration.logger.level = .debug // 2. Initialize Braze SDK instance let brazeInstance = Braze(configuration: configuration) AppDelegate.braze = brazeInstance // 3. Set up Braze In-App Message UI and delegate let inAppMessageUI = BrazeInAppMessageUI() inAppMessageUI.delegate = self brazeInstance.inAppMessagePresenter = inAppMessageUI return true } func inAppMessage(_ ui: BrazeInAppMessageUI, displayChoiceForMessage message: Braze.InAppMessage) -> BrazeInAppMessageUI.DisplayChoice { if let showFlag = message.extras["should_display_message"] as? String, showFlag == "true" { return .now } else { return .discard } } } ``` ```swift file=SampleApp.swift import SwiftUI @main struct SampleApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { YourView() } } } ``` !!step lines-AppDelegate.swift=5 ### 1. `BrazeInAppMessageUIDelegate` を実装する {#1-implement-the-brazeinappmessageuidelegate} AppDelegateクラスで [`BrazeInAppMessageUIDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/delegate) を実装し、後で `inAppMessage` メソッドをオーバーライドできるようにします。 !!step lines-AppDelegate.swift=12 #### 2. デバッグを有効にする(オプション) 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-AppDelegate.swift=19-21 #### 3. Braze UIとデリゲートを設定する {#3-set-up-your-braze-ui-and-delegate} `BrazeInAppMessageUI()` はデフォルトでアプリ内メッセージをレンダリングします。`self` をデリゲートとして割り当てることで、メッセージが表示される前にインターセプトして処理できます。 !!step lines-AppDelegate.swift=26-33 #### 4. `DisplayChoice` を条件付きロジックでオーバーライドする {#4-override-displaychoice-with-conditional-logic} [`inAppMessage(_:displayChoiceForMessage:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:displaychoiceformessage:)-9w1nb) をオーバーライドして、メッセージを表示するかどうかを決定します。メッセージを表示する場合は `.now` を、非表示にする場合は `.discard` を返します。 # チュートリアル: キーと値のペアを使用したスタイルのカスタマイズ Source: /docs/ja/developer_guide/in_app_messages/tutorials/customizing_message_styling/index.md # チュートリアル: キーと値のペアを使用したメッセージスタイルのカスタマイズ {#tutorial-customizing-message-styling-using-key-value-pairs} > このチュートリアルのサンプルコードに従って、Braze SDKのキーと値のペアを使用してアプリ内メッセージのスタイルをカスタマイズしましょう。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ただし、追加の設定は不要です。 ## Webのキーと値のペアを使用したメッセージスタイルのカスタマイズ {#customizing-message-styling-using-key-value-pairs-for-web} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```js file=index.js import * as braze from "@braze/web-sdk"; // Remove any calls to `braze.automaticallyShowInAppMessages()` braze.initialize("YOUR-API-KEY", { baseUrl: "YOUR-ENDPOINT", enableLogging: true, }); braze.subscribeToInAppMessage(function (message) { const extras = message.extras; const customTemplateType = extras["custom-template"] || ""; const customColor = extras["custom-color"] || ""; const customMessageId = extras["message-id"] || ""; if (customTemplateType) { // add your own custom code to render this message } else { // otherwise, use Braze built-in UI braze.showInAppMessage(message); } }); ``` !!step lines-index.js=2 ### 1. `automaticallyShowInAppMessages()` の呼び出しを削除する {#1-remove-calls-to-automaticallyshowinappmessages} 後で実装するカスタムロジックがオーバーライドされるため、[`automaticallyShowInAppMessages()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#automaticallyshowinappmessages) のすべての呼び出しを削除してください。 !!step lines-index.js=6 #### 2. デバッグを有効にする(オプション) {#2-enable-debugging-optional} 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-index.js=9-21 #### 3. アプリ内メッセージコールバックハンドラーにサブスクライブする {#3-subscribe-to-the-in-app-message-callback-handler} [`subscribeToInAppMessage(callback)`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#subscribetoinappmessage) を使用してコールバックを登録し、アプリ内メッセージがトリガーされるたびにメッセージを受信できるようにします。 !!step lines-index.js=10-13 #### 4. `message.extras` プロパティにアクセスする {#4-access-the-messageextras-property} `message.extras` を使用して、カスタマイズタイプ、スタイル属性、またはダッシュボードで定義されたその他の値にアクセスします。すべての値は文字列として返されます。 !!step lines-index.js=19 #### 5. 条件付きで `showInAppMessage` を呼び出す {#5-conditionally-call-showinappmessage} メッセージを表示するには、[`showInAppMessage(message)`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#showinappmessage) を呼び出します。それ以外の場合は、必要に応じてカスタムプロパティを使用してください。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). また、[Androidのアプリ内メッセージを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=android#android_enabling-in-app-messages)必要もあります。 ## Androidのキーと値のペアを使用したメッセージスタイルのカスタマイズ {#customizing-message-styling-using-key-value-pairs-for-android} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```kotlin file=MainApplication.kt package com.example.brazedevlab import android.app.Application import com.braze.Braze import com.braze.support.BrazeLogger import com.braze.configuration.BrazeConfig import com.braze.ui.inappmessage.BrazeInAppMessageManager import com.braze.BrazeActivityLifecycleCallbackListener import com.braze.ui.inappmessage.listeners.IInAppMessageManagerListener import com.braze.models.inappmessage.IInAppMessage import com.braze.ui.inappmessage.InAppMessageOperation import android.util.Log class MyApplication : Application() { override fun onCreate() { super.onCreate() // Enable verbose Braze SDK logs BrazeLogger.logLevel = Log.VERBOSE // Initialize Braze val brazeConfig = BrazeConfig.Builder() .setApiKey("YOUR-API-KEY") .setCustomEndpoint("YOUR-ENDPOINT") .build() Braze.configure(this, brazeConfig) registerActivityLifecycleCallbacks( BrazeActivityLifecycleCallbackListener() ) // Set up custom in-app message view factory BrazeInAppMessageManager.getInstance() .setCustomInAppMessageViewFactory(CustomInAppMessageViewFactory()) } } ``` ```kotlin file=CustomInAppMessageViewFactory.kt import android.app.Activity import android.graphics.Color import android.view.View import com.braze.models.inappmessage.IInAppMessage import com.braze.ui.inappmessage.BrazeInAppMessageManager import com.braze.ui.inappmessage.IInAppMessageViewFactory class CustomInAppMessageViewFactory : IInAppMessageViewFactory { override fun createInAppMessageView( activity: Activity, inAppMessage: IInAppMessage ): View { // 1) Obtain Braze’s default view factory for this message type val defaultFactory = BrazeInAppMessageManager.getInstance() .getDefaultInAppMessageViewFactory(inAppMessage) ?: throw IllegalStateException( "Braze default IAM view factory is missing" ) // 2) Inflate the default view val iamView = defaultFactory .createInAppMessageView(activity, inAppMessage) ?: throw IllegalStateException( "Braze default IAM view is null" ) // 3) Get your KVP extras val extras = inAppMessage.extras ?: emptyMap() val customization = extras["customization"] val overrideColor = extras["custom-color"] // 4) Style your root view if (customization == "slideup-attributes" && overrideColor != null) { try { iamView.setBackgroundColor(Color.parseColor(overrideColor)) } catch (_: IllegalArgumentException) { // ignore bad styling } } return iamView } } ``` !!step lines-MainApplication.kt=19 ### 1. デバッグを有効にする(オプション) {#1-enable-debugging-optional} 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-MainApplication.kt=28-30 #### 2. アクティビティライフサイクルコールバックを登録する {#2-register-activity-lifecycle-callbacks} アプリ内メッセージのライフサイクルを処理するために、Brazeのデフォルトリスナーを登録します。 !!step lines-CustomInAppMessageViewFactory.kt=8 #### 3. カスタムビューファクトリクラスを作成する {#3-create-your-custom-view-factory-class} カスタムメッセージビューを構築して返せるように、クラスが [`IInAppMessageViewFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-factory/index.html) に準拠していることを確認してください。 !!step lines-CustomInAppMessageViewFactory.kt=15-20 #### 4. Brazeのデフォルトファクトリに委任する {#4-delegate-to-brazes-default-factory} 独自の条件付き変更を適用する前に、デフォルトのファクトリに委任してBrazeの組み込みスタイリングを保持します。 !!step lines-CustomInAppMessageViewFactory.kt=30-32,35-41 #### 5. `inAppMessage.extras` からキーと値のペアにアクセスする {#5-access-key-value-pairs-from-inappmessageextras} `inAppMessage.extras` を使用して、カスタマイズタイプ、スタイル属性、またはダッシュボードで定義されたその他の値にアクセスします。ビューを返す前にスタイルのオーバーライドを適用してください。 !!step lines-MainApplication.kt=33-34 #### 6. カスタム `IInAppMessageViewFactory` を実装する {#6-implement-a-custom-iinappmessageviewfactory} カスタムクラスに [`IInAppMessageViewFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.inappmessage/-i-in-app-message-view-factory/index.html) を実装して、アプリ内メッセージビューを構築およびレンダリングします。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). また、[Swiftのアプリ内メッセージを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=swift#swift_enabling-in-app-messages)必要もあります。 ## Swiftのキーと値のペアを使用したメッセージスタイルのカスタマイズ {#customizing-message-styling-using-key-value-pairs-for-swift} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```swift file=AppDelegate.swift import UIKit import BrazeKit import BrazeUI class AppDelegate: UIResponder, UIApplicationDelegate, BrazeInAppMessageUIDelegate { var window: UIWindow? static var braze: Braze? func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let configuration = Braze.Configuration( apiKey: "YOUR-API-KEY", endpoint: "YOUR-ENDPOINT" ) configuration.logger.level = .debug let braze = Braze(configuration: configuration) AppDelegate.braze = braze // Set up Braze In-App Message UI and delegate let inAppMessageUI = BrazeInAppMessageUI() inAppMessageUI.delegate = self brazeInstance.inAppMessagePresenter = inAppMessageUI return true } func inAppMessage( _ ui: BrazeInAppMessageUI, prepareWith context: inout BrazeInAppMessageUI.PresentationContext ) { let customization = context.message.extras["customization"] as? String if customization == "slideup-attributes" { // Create a new attributes object and make customizations. var attributes = context.attributes?.slideup attributes?.font = UIFont(name: "Chalkduster", size: 17)! attributes?.imageSize = CGSize(width: 65, height: 65) attributes?.cornerRadius = 20 attributes?.imageCornerRadius = 10 if #available(iOS 13.0, *) { attributes?.cornerCurve = .continuous attributes?.imageCornerCurve = .continuous } context.attributes?.slideup = attributes } } } ``` ```swift file=SampleApp.swift import SwiftUI @main struct SampleApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { YourView() } } } ``` !!step lines-AppDelegate.swift=5 ### 1. `BrazeInAppMessageUIDelegate` を実装する {#1-implement-brazeinappmessageuidelegate} `AppDelegate` クラスで [`BrazeInAppMessageUIDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/delegate) を実装し、後で `inAppMessage` メソッドをオーバーライドできるようにします。 !!step lines-AppDelegate.swift=17 #### 2. デバッグを有効にする(オプション) 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-AppDelegate.swift=30-50 #### 3. 表示前にメッセージを準備する {#3-prepare-messages-before-theyre-displayed} メッセージの準備中に、Brazeは `inAppMessage(_:prepareWith:)` を呼び出します。これを使用してスタイルをカスタマイズしたり、キーと値のペアに基づいてロジックを適用したりできます。 !!step lines-AppDelegate.swift=34 #### 4. `message.extras` からキーと値のペアにアクセスする {#4-access-key-value-pairs-from-messageextras} `message.extras` を使用して、カスタマイズタイプ、スタイル属性、またはダッシュボードで定義されたその他の値にアクセスします。 !!step lines-AppDelegate.swift=38-46 #### 5. メッセージのスタイル属性を更新する {#5-update-the-messages-styling-attributes} [`inAppMessage(_:prepareWith:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:preparewith:)-11fog) を使用して `PresentationContext` にアクセスし、スタイル属性を直接変更できます。各アプリ内メッセージタイプは、それぞれ異なる属性を公開しています。 # チュートリアル: トリガーメッセージの延期と復元 Source: /docs/ja/developer_guide/in_app_messages/tutorials/deferring_triggered_messages/index.md # チュートリアル: トリガーメッセージの延期と復元 {#tutorial-deferring-and-restoring-triggered-messages} > このチュートリアルのサンプルコードに従って、Braze SDKを使用してトリガーされたアプリ内メッセージを延期および復元する方法を学びます。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ただし、追加の設定は不要です。 ## Webのトリガーメッセージの延期と復元 {#deferring-and-restoring-triggered-messages-for-web} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```js file=index.js import * as braze from "@braze/web-sdk"; // Remove any calls to `braze.automaticallyShowInAppMessages()` braze.initialize("YOUR-API-KEY", { baseUrl: "YOUR-ENDPOINT", enableLogging: true, }); braze.subscribeToInAppMessage(function (message) { const shouldDefer = true; // customize for your own logic if (shouldDefer) { braze.deferInAppMessage(message); } else { braze.showInAppMessage(message); } }); // elsewhere in your app document.getElementById("button").onclick = function () { const deferredMessage = braze.getDeferredInAppMessage(); if (deferredMessage) { braze.showInAppMessage(deferredMessage); } }; ``` !!step lines-index.js=2 ### 1. `automaticallyShowInAppMessages()` の呼び出しを削除する {#1-remove-calls-to-automaticallyshowinappmessages} 後で実装するカスタムロジックをオーバーライドしてしまうため、[`automaticallyShowInAppMessages()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#automaticallyshowinappmessages) のすべての呼び出しを削除します。 !!step lines-index.js=6 #### 2. デバッグを有効にする(オプション) {#2-enable-debugging-optional} 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-index.js=9-16 #### 3. アプリ内メッセージコールバックハンドラーにサブスクライブする {#3-subscribe-to-the-in-app-message-callback-handler} [`subscribeToInAppMessage(callback)`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#subscribetoinappmessage) を使用してコールバックを登録し、アプリ内メッセージがトリガーされるたびにメッセージを受信します。 !!step lines-index.js=11-12 #### 4. `message` インスタンスを延期する {#4-defer-the-message-instance} メッセージを延期するには、[`deferInAppMessage(message)`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#deferinappmessage) を呼び出します。Brazeはこのメッセージをシリアライズして保存し、将来のページ読み込み時に表示できるようにします。 !!step lines-index.js=18-24 #### 5. 以前に延期されたメッセージを取得する {#5-retrieve-a-previously-deferred-message} 以前に延期されたメッセージを取得するには、[`getDeferredInAppMessage()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#getdeferredinappmessage) を呼び出します。 !!step lines-index.js=21-23 #### 6. 延期されたメッセージを表示する {#6-display-the-deferred-message} 延期されたメッセージを取得したら、[`showInAppMessage(message)`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#showinappmessage) にメッセージを渡して表示します。 !!step lines-index.js=13-15 #### 7. メッセージをすぐに表示する {#7-display-a-message-immediately} メッセージを延期するのではなくすぐに表示するには、`subscribeToInAppMessage` コールバックで [`showInAppMessage(message)`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#showinappmessage) を直接呼び出します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). また、[Androidのアプリ内メッセージを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=android#android_enabling-in-app-messages)必要もあります。 ## Androidのトリガーメッセージの延期と復元 {#deferring-and-restoring-triggered-messages-for-android} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```kotlin file=MainApplication.kt import android.app.Application import com.braze.Braze import com.braze.support.BrazeLogger import com.braze.configuration.BrazeConfig import com.braze.ui.inappmessage.BrazeInAppMessageManager import com.braze.BrazeActivityLifecycleCallbackListener import com.braze.ui.inappmessage.listeners.IInAppMessageManagerListener import com.braze.models.inappmessage.IInAppMessage import com.braze.ui.inappmessage.InAppMessageOperation import android.util.Log class MyApplication : Application() { companion object { private var instance: MyApplication? = null fun getInstance(): MyApplication = instance!! } private var showMessage = false override fun onCreate() { super.onCreate() instance = this // Enable verbose Braze SDK logs BrazeLogger.logLevel = Log.VERBOSE // Initialize Braze val brazeConfig = BrazeConfig.Builder() .setApiKey("YOUR-API-KEY") .setCustomEndpoint("YOUR-ENDPOINT") .build() Braze.configure(this, brazeConfig) registerActivityLifecycleCallbacks( BrazeActivityLifecycleCallbackListener() ) // Set up in-app message listener BrazeInAppMessageManager.getInstance().setCustomInAppMessageManagerListener(object : IInAppMessageManagerListener { override fun beforeInAppMessageDisplayed(inAppMessage: IInAppMessage): InAppMessageOperation { return if (showMessage) { // Show the message using Braze's UI InAppMessageOperation.DISPLAY_NOW } else { // Re-enqueue the message for later InAppMessageOperation.DISPLAY_LATER } } }) } fun showDeferredMessage(show: Boolean) { showMessage = show BrazeInAppMessageManager.getInstance().requestDisplayInAppMessage() } } ``` ```kotlin file=MainActivity.kt import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.* import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { ContentView() } } } @Composable fun ContentView() { Column( modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(20.dp) ) { // ... your UI Button(onClick = { MyApplication.getInstance().showDeferredMessage(true) }) { Text("Show Deferred IAM") } } } ``` !!step lines-MainApplication.kt=13-16 ### 1. シングルトン `Application` インスタンスを作成する {#1-create-a-singleton-application-instance} コンパニオンオブジェクトを使って `Application` クラスをシングルトンとして公開し、コード内で後からアクセスできるようにします。 !!step lines-MainApplication.kt=25 #### 2. デバッグを有効にする(オプション) 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-MainApplication.kt=34-36 #### 3. アクティビティライフサイクルコールバックを登録する {#3-register-activity-lifecycle-callbacks} アプリ内メッセージのライフサイクルを処理するBrazeのデフォルトリスナーを登録します。 !!step lines-MainApplication.kt=39-49 #### 4. アプリ内メッセージリスナーを設定する {#4-set-up-an-in-app-message-listener} `BrazeInAppMessageManager` を使用して、メッセージが表示される前にインターセプトするカスタムリスナーを設定します。 !!step lines-MainApplication.kt=43,46 #### 5. 条件付きロジックを作成する {#5-create-conditional-logic} タイミングを制御するには `showMessage` フラグを使用します—メッセージをすぐに表示する場合は `DISPLAY_NOW` を返し、延期する場合は `DISPLAY_LATER` を返します。 !!step lines-MainApplication.kt=52-55 #### 6. 延期メッセージを表示するメソッドを作成する {#6-create-a-method-for-displaying-deferred-messages} `showDeferredMessage` を使って次のアプリ内メッセージをトリガーします。`showMessage` が `true` の場合、リスナーは `DISPLAY_NOW` を返します。 !!step lines-MainActivity.kt=29 #### 7. UIからメソッドをトリガーする {#7-trigger-the-method-from-your-ui} 以前に延期されたメッセージを表示するには、ボタンやタップなどのUIから `showDeferredMessage(true)` を呼び出します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). また、[Swiftのアプリ内メッセージを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages?sdktab=swift#swift_enabling-in-app-messages)必要もあります。 ## Swiftのトリガーメッセージの延期と復元 {#deferring-and-restoring-triggered-messages-for-swift} **Important:** We're piloting this new tutorial format. [Tell us what you think](https://docs.google.com/forms/d/e/1FAIpQLSe_5uhWM7eXXk9F_gviO_pvA4rkYO3WA9B6tNJZ3TY91md5bw/viewform?usp=pp_url&entry.569173304=General+Feedback) — your feedback helps us improve future guides. ```swift file=AppDelegate.swift import SwiftUI import BrazeKit import BrazeUI class AppDelegate: UIResponder, UIApplicationDelegate, BrazeInAppMessageUIDelegate { static private(set) var shared: AppDelegate! private var braze: Braze! public var showMessage: Bool = false func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { AppDelegate.shared = self // 1. Braze configuration with your SDK API key and endpoint let configuration = Braze.Configuration(apiKey: "a1fc095b-ae3d-40f4-bb33-3fb5176562c0", endpoint: "sondheim.braze.com") configuration.logger.level = .debug // 2. Initialize Braze SDK instance braze = Braze(configuration: configuration) // 3. Set up Braze In-App Message UI and delegate let ui = BrazeInAppMessageUI() ui.delegate = self braze.inAppMessagePresenter = ui return true } func inAppMessage( _ ui: BrazeInAppMessageUI, displayChoiceForMessage message: Braze.InAppMessage ) -> BrazeInAppMessageUI.DisplayChoice { if !showMessage { return .reenqueue } return .now } func showDeferredMessage(showMessage: Bool) { self.showMessage = showMessage (braze.inAppMessagePresenter as? BrazeInAppMessageUI)?.presentNext() } } ``` ```swift file=SampleApp.swift import SwiftUI @main struct IAMDeferApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { ContentView() } } } ``` ```swift file=ContentView.swift import SwiftUI struct ContentView: View { var body: some View { VStack(spacing: 20) { // ...your UI Button("Show Deferred IAM") { AppDelegate.shared.showDeferredMessage(showMessage: true) } } .padding() } } ``` !!step lines-AppDelegate.swift=5 ### 1. `BrazeInAppMessageUIDelegate` を実装する {#1-implement-the-brazeinappmessageuidelegate} `AppDelegate` クラスで [`BrazeInAppMessageUIDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate) を実装して、後で `inAppMessage` メソッドをオーバーライドできるようにします。 !!step lines-AppDelegate.swift=19 #### 2. デバッグを有効にする(オプション) 開発中のトラブルシューティングを容易にするために、デバッグを有効にすることを検討してください。 !!step lines-AppDelegate.swift=25-27 #### 3. Braze UIとデリゲートを設定する {#3-set-up-your-braze-ui-and-delegate} `BrazeInAppMessageUI()` はデフォルトでアプリ内メッセージをレンダリングします。`self` をデリゲートとして割り当てることで、メッセージが表示される前にインターセプトして処理できます。インスタンスは必ず保存してください。後で延期したメッセージを復元するときに必要になります。 !!step lines-AppDelegate.swift=32-41 #### 4. `DisplayChoice` を条件付きロジックでオーバーライドする {#4-override-displaychoice-with-conditional-logic} メッセージを表示するタイミングを決定するには、[`inAppMessage(_:displayChoiceForMessage:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:displaychoiceformessage:)-9w1nb) をオーバーライドします。すぐに表示する場合は `.now` を返し、後で表示する場合は `.reenqueue` を返します。 !!step lines-AppDelegate.swift=43-46 #### 5. 延期メッセージを表示するメソッドを作成する {#5-create-a-method-to-show-deferred-messages} `showDeferredMessage(true)` を呼び出してスタック内の次の延期メッセージを表示するメソッドを作成します。呼び出されると `showMessage` が `true` に設定され、デリゲートは `.now` を返します。 !!step lines-ContentView.swift=1-14 #### 6. UIからメソッドをトリガーする {#5-trigger-the-method-from-your-ui} 以前に延期されたメッセージを表示するには、ボタンやタップなどのUIから `showDeferredMessage(true)` を呼び出します。 # Braze SDKのアプリ内メッセージのトラブルシューティング Source: /docs/ja/developer_guide/in_app_messages/troubleshooting/index.md # アプリ内メッセージのトラブルシューティング {#troubleshoot-in-app-messages} > このページでは、アプリ内メッセージがデバイスに配信または表示されない原因を診断します。ダッシュボード側の設定(優先度、トリガー、セグメント、再適格性)については、[アプリ内メッセージFAQ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/faq)を参照してください。 デバッグを始める前に、自分自身を[テストユーザー](https://www.braze.com/docs/ja/ja/user_guide/administer/global/user_management/internal_groups#adding-test-users)として追加し、[テストメッセージの送信](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/sending_test_messages)を確認してください。 ## まずはここから:症状を確認する {#start-here-match-your-symptom} | 症状 | 参照先 | | --- | --- | | 1人のユーザーにアプリ内メッセージが表示されなかった | [1人のユーザー](#in-app-message-not-shown-for-one-user) | | 1つのプラットフォーム(Android、iOS、またはWeb)でアプリ内メッセージが表示されなかった | [1つのプラットフォーム](#in-app-message-not-shown-on-one-platform) | | **キャンバス**ステップのアプリ内メッセージが表示されなかった | [キャンバスのアプリ内メッセージ](#canvas-in-app-messages) | | アプリ内メッセージが遅れて表示された、または遅延後に表示された | [タイミングと遅延表示](#timing-and-delayed-display) | | インプレッションやクリックが正しくない | [インプレッションと分析](#impressions-and-analytics) | | イベントユーザーログで`triggers`が欠落または空 | [配信のトラブルシューティング](#delivery-troubleshooting) | | トリガーは返されたがデバイスに何も表示されない | [プラットフォーム固有の表示トラブルシューティング](#platform-specific-display-troubleshooting) | | アプリ内メッセージのアセットの読み込みに失敗する(iOS、`NSURLError` -1008) | [アセットの読み込み(Swiftタブ)](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/troubleshooting?sdktab=swift#asset-loading) | {: .reset-td-br-1 .reset-td-br-2 aria-label="アプリ内メッセージの症状" } ## 標準的な調査パス {#standard-investigation-path} すべてのインシデントでこのワークフローを使用してください。ステップ 1から開始してください。 1. テストデバイスで**セッション開始**がログに記録されていることを確認します。アプリ内メッセージはセッション開始時にリクエストされます。 2. [イベントユーザーログ](https://www.braze.com/docs/ja/ja/user_guide/administer/global/workspace_settings/logs_and_alerts/event_user_log)を開き、そのセッション開始に対するSDKリクエストを見つけます。**Response Data**で以下を確認します。 - 生のJSONで、`respond_with`に`"triggers": true`が含まれていることを確認します。 - **Requested Responses**行に**`triggers`**が含まれている必要があります。 - **Trigger In-App Message**行には、そのリクエストに対して返された各アプリ内メッセージが一覧表示されます。 - `triggers`キーまたは**Trigger In-App Message**行がない場合は、[メッセージがリクエストされない場合のトラブルシューティング](#troubleshoot-messages-not-being-requested)を参照してください。 - `triggers`が存在するが空(`[]`)の場合は、[メッセージが返されない場合のトラブルシューティング](#troubleshoot-messages-not-being-returned)を参照してください。 - **Trigger In-App Message**行が存在するが何も表示されない場合は、[プラットフォーム固有の表示トラブルシューティング](#platform-specific-display-troubleshooting)を参照してください。 - 各トリガーペイロードには`type`が含まれます:`inapp`(標準)または`templated_iam`(表示前にテンプレートリクエストが必要)。[アプリ内メッセージの種類](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/triggering_messages#types-of-in-app-messages)を参照してください。 3. ダッシュボード側の適格性(セグメント、再適格性、フリークエンシーキャップ、優先度、コントロールグループ)については、[配信のトラブルシューティング](#delivery-troubleshooting)と[アプリ内メッセージFAQ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/faq)を参照してください。 4. デバイス側の表示の問題(デリゲート、レート制限、画面の向き、セッションタイムアウト)については、[プラットフォーム固有の表示トラブルシューティング](#platform-specific-display-troubleshooting)でSDKタブを選択してください。 ## キャンバスのアプリ内メッセージ {#canvas-in-app-messages} **症状:** ユーザーがキャンバスのアプリ内メッセージステップに入ったが、期待したタイミングでメッセージが表示されなかった。 キャンバスとアプリ内メッセージに関するチケットの大半は、以下の3つの動作に起因します。 1. **次のセッションでの表示:** キャンバスのアプリ内メッセージは、ステップが処理された後の*次の*セッション開始時に適格になります。セッション中にすぐに表示されるわけではありません。キャンバス FAQの[キャンバスのアプリ内メッセージはいつ送信されますか?](https://www.braze.com/docs/ja/ja/user_guide/messaging/canvas/faqs#when-are-in-app-messages-in-canvas-sent)を参照してください。 2. **ステップエントリ時の配信バリデーション:** メッセージステップで**メッセージ送信時にオーディエンスを検証**が有効になっている場合、セグメントメンバーシップとフリークエンシーキャップは、表示時ではなくユーザーが**ステップに入った時点**で評価されます。[配信バリデーション](https://www.braze.com/docs/ja/ja/user_guide/messaging/canvas/canvas_components/message_step#delivery-validations)を参照してください。 3. **遅延とセッションタイムアウト:** ユーザーがSDKのセッションタイムアウトよりも長い遅延ステップに入った場合、アプリ内メッセージステップの前に新しいセッションが開始される可能性があります。期待するタイミングのセッション開始時にメッセージが取得されない場合があります。 利用可能時間枠、有効期限、キャンバス分析での_送信数_ゼロについては、キャンバス FAQの[アプリ内メッセージと配信](https://www.braze.com/docs/ja/ja/user_guide/messaging/canvas/faqs#messages-and-delivery)を参照してください。 **Important:** キャンバスのアプリ内メッセージは、SDKを通じて送信されたイベントによってのみトリガーできます。REST APIではトリガーできません。 ## 1人のユーザーにアプリ内メッセージが表示されなかった {#in-app-message-not-shown-for-one-user} **症状:** 1人のユーザーが期待したアプリ内メッセージを受信しなかった。他のユーザーには影響がない可能性があります。 以下を確認してください。 - SDKが新しいアプリ内メッセージをリクエストする**セッション開始**時に、ユーザーがセグメントに含まれていましたか? - キャンペーンまたはキャンバスのターゲティングルールに基づいて、ユーザーは適格または再適格でしたか?[キャンペーンとキャンバスの再適格性](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/re_eligibility)を参照してください。 - [フリークエンシーキャップ](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/frequency_capping)が適用されましたか? - ユーザーはキャンペーンのコントロールグループに含まれていましたか?キャンペーンがABテスト用に設定されているかどうかを確認してください。 - より優先度の高いアプリ内メッセージが代わりに表示されましたか?アプリ内メッセージFAQの[同じセッションで複数のアプリ内メッセージを表示できますか?](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/faq#can-multiple-in-app-messages-display-in-the-same-session)を参照してください。 - デバイスはキャンペーンで指定された画面の向きでしたか? - トリガー間のデフォルトの最小間隔(30秒)によってメッセージが抑制されましたか?[デフォルトのレート制限のオーバーライド](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/triggering_messages#overriding-the-default-rate-limit)を参照してください。 その後、[標準的な調査パス](#standard-investigation-path)に従ってください。 ## 1つのプラットフォームでアプリ内メッセージが表示されなかった {#in-app-message-not-shown-on-one-platform} **症状:** Android、iOS、またはWebでアプリ内メッセージが表示されないが、他のプラットフォームでは動作する可能性があります。 | 考えられる原因 | 確認事項 | | --- | --- | | **Send To**ターゲットが間違っている | キャンペーンまたはキャンバスステップが適切に**モバイルアプリ**または**Webブラウザー**をターゲットにしていることを確認してください。Web専用のキャンペーンはAndroidデバイスには送信されません。 | | カスタムUIまたはハンドラーが表示を抑制している | デリゲート(モバイル)または[`braze.subscribeToInAppMessage`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#subscribetoinappmessage)(Web)を確認してください。[カスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization)および以下のSDKタブを参照してください。 | | このプラットフォームで統合が一度も動作していない | このプラットフォームとアプリバージョンで以前にアプリ内メッセージが表示されたことがあるか確認してください。 | | デバイスでトリガーが発火しなかった | トリガーはSDKを通じてローカルで発生する必要があります。REST API呼び出しではSDKのアプリ内メッセージをトリガーできません。[メッセージのトリガー](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/triggering_messages)を参照してください。 | | イベントユーザーログで`triggers`が空 | セグメント、再適格性、フリークエンシーキャップ、またはコントロールグループの問題です。[メッセージが返されない場合のトラブルシューティング](#troubleshoot-messages-not-being-returned)を参照してください。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="プラットフォームの症状と原因" } ## すべてのユーザーにアプリ内メッセージが表示されなかった {#in-app-message-not-shown-for-all-users} **症状:** ユーザーが誰もアプリ内メッセージを受信しなかった、または期待より少ないユーザーしか受信しなかった。 以下を確認してください。 - ダッシュボードとアプリの統合の両方で、トリガーアクションが正しく設定されていますか? - より優先度の高いアプリ内メッセージがキャンペーンを横取りしましたか?[アプリ内メッセージFAQ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/faq#can-multiple-in-app-messages-display-in-the-same-session)を参照してください。 - 最新のSDKバージョンを使用していますか?一部のアプリ内メッセージタイプには最小SDKバージョンの要件があります。 - セッションが正しく統合されていますか?このアプリでセッション分析が動作していることを確認してください。 - カスタマイズされたUIライブラリーが表示を妨げていませんか?[カスタマイズ](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization)を参照してください。 その後、[標準的な調査パス](#standard-investigation-path)に従ってください。 ## タイミングと遅延表示 {#timing-and-delayed-display} **症状:** アプリ内メッセージが期待より遅れて表示された、または新しいセッションまで表示されなかった。 一般的な原因: - **キャンペーンのセッション開始時プリフェッチ:** アプリ内メッセージはセッション開始時にキャッシュされ、トリガーが発火した時に表示されます。次のセッション開始前に発生したトリガーは、そのセッションまで表示されません。[メッセージのトリガー](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/triggering_messages)を参照してください。 - **キャンバスの次のセッション動作:** [キャンバスのアプリ内メッセージ](#canvas-in-app-messages)を参照してください。 - **ダッシュボードでスケジュールされた遅延:** キャンペーンまたはステップに遅延が設定されていないか確認してください。 - **トリガー同期の競合:** ユーザーがセッション開始直後にイベントをログに記録した場合、トリガーがまだ同期されていない可能性があります。セッション開始でトリガーし、意図したイベントでセグメントを設定することで、イベント後の次のセッションで配信されるようにすることを検討してください。 - **連続するアプリ内メッセージ:** ツアーでメッセージを遅延または復元している場合は、[トリガーされたアプリ内メッセージの遅延](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/tutorials/deferring_triggered_messages)を参照してください。 - **大きなアセットまたは遅いCDN:** HTMLアプリ内メッセージの画像と動画を最適化してください。モバイルでは、低速ネットワークで表示前に画像がダウンロードされる場合があります。プラットフォーム固有の注意事項については、以下のSDKタブを選択してください。 **Note:** アプリ内メッセージがセッション開始でトリガーされ、セッションタイムアウトを延長している場合、その時間枠内でアプリを閉じて再度開いてもセッションは更新されません。たとえば、300秒のタイムアウトの場合、セッション開始のアプリ内メッセージはセッションが実際に更新されるまで表示されません。これがテストに影響する場合は、セッションタイムアウトまたはトリガータイプを調整してください。 ## 配信のトラブルシューティング {#delivery-troubleshooting} アプリ内メッセージの問題の大半は、**配信**(デバイスがトリガーを受信しなかった)または**表示**(トリガーは到着したが表示されなかった)のいずれかです。まず[配信](#troubleshooting-in-app-message-delivery)を確認し、次に[表示](#platform-specific-display-troubleshooting)を確認してください。 ### 配信のトラブルシューティング {#troubleshooting-in-app-message-delivery} SDKはセッション開始時にBrazeサーバーにアプリ内メッセージをリクエストします。SDKがトリガーをリクエストし、Brazeがそれらを返していることを確認してください。 #### メッセージがリクエストされ返されているか確認する {#check-if-messages-are-requested-and-returned} 1. 自分自身を[テストユーザー](https://www.braze.com/docs/ja/ja/user_guide/administer/global/user_management/internal_groups#adding-test-users)として追加します。 2. 自分のユーザーをターゲットにしたアプリ内メッセージキャンペーンを設定します。 3. アプリケーションで新しいセッションを開始します。 4. [イベントユーザーログ](https://www.braze.com/docs/ja/ja/user_guide/administer/global/workspace_settings/logs_and_alerts/event_user_log)で、セッション開始イベントに対するSDKリクエストを見つけます。**Response Data**で以下を確認します。 - 生のJSONで、`respond_with`に`"triggers": true`が含まれていることを確認します。 - **Requested Responses**行には、レスポンスのトップレベルキーが一覧表示されます。アプリ内メッセージの場合、**`triggers`**が含まれている必要があります。 - **Trigger In-App Message**行には、そのリクエストに対して返された各アプリ内メッセージが一覧表示されます。 次にトリアージします。 - `triggers`キーまたは**Trigger In-App Message**行がない場合は、[メッセージがリクエストされない場合のトラブルシューティング](#troubleshoot-messages-not-being-requested)を参照してください。 - `triggers`が存在するが空(`[]`)の場合は、[メッセージが返されない場合のトラブルシューティング](#troubleshoot-messages-not-being-returned)を参照してください。 - **Trigger In-App Message**行が存在するがデバイスに何も表示されない場合は、[プラットフォーム固有の表示トラブルシューティング](#platform-specific-display-troubleshooting)を参照してください。 - 各トリガーペイロードには`type`が含まれます:`inapp`(標準)または`templated_iam`(表示前にテンプレートリクエストが必要)。[アプリ内メッセージの種類](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/triggering_messages#types-of-in-app-messages)を参照してください。 5. レスポンスデータに正しいアプリ内メッセージが表示されていることを確認します。 ![SDKリクエストとレスポンスデータを含むイベントユーザーログ。](https://www.braze.com/docs/ja/ja/assets/img_archive/event_user_log_iams.png?fd8f7c0f05a549b6a529b92744f37f96) ##### メッセージがリクエストされない場合のトラブルシューティング {#troubleshoot-messages-not-being-requested} アプリ内メッセージがリクエストされていない場合、アプリがセッションを正しくトラッキングしていない可能性があります。アプリ内メッセージはセッション開始時に更新されます。セッションタイムアウトのセマンティクスに基づいて、アプリがセッションを開始していることを確認してください。 ![セッション開始イベントの成功を表示するイベントユーザーログのSDKリクエスト。](https://www.braze.com/docs/ja/ja/assets/img_archive/event_user_log_session_start.png?972201c9c20f018bc85d97167638f04e) ##### メッセージが返されない場合のトラブルシューティング {#troubleshoot-messages-not-being-returned} アプリ内メッセージが返されていない場合、ターゲティングまたは適格性の問題が発生している可能性があります。 1. セグメントにユーザーが含まれていない。 - ユーザーの[**エンゲージメント**](https://www.braze.com/docs/ja/ja/user_guide/audience/manage_audience/user_profiles#engagement-tab)タブで、期待するセグメントを確認してください。 2. ユーザーがすでにメッセージを受信しており、再適格ではなかった。 - [再適格性の設定](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/re_eligibility)と[アプリ内メッセージFAQ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/faq#campaigns)を確認してください。 3. ユーザーがフリークエンシーキャップに達した。 - [フリークエンシーキャップの設定](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/frequency_capping)を確認してください。 4. ユーザーがコントロールグループに入った。 - **キャンペーンバリアントを受信した**フィルターを**コントロール**に設定したセグメントを作成するか、統合テスト中はコントロールグループをオプトアウトしてください。 5. より優先度の高いアプリ内メッセージが優先された。[アプリ内メッセージFAQ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/faq#can-multiple-in-app-messages-display-in-the-same-session)を参照してください。 アーカイブ済みキャンペーン、トリガー設定、サイレント時間については、[アプリ内メッセージFAQ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/faq)を参照してください。 ## インプレッションと分析 {#impressions-and-analytics} **症状:** インプレッション数またはクリック数が期待と一致しない。 - **_インプレッション_が_ユニークインプレッション_より多い:** ユーザーが複数のデバイスを持っている場合や、スケジュールされた遅延により同じユーザーが複数回適格になった場合に想定される動作です。[キャンペーンとキャンバスの再適格性](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/re_eligibility)を参照してください。 - **インプレッションが期待より少ない:** ユーザーがメッセージを閲覧しなかった可能性(インプレッションは表示時にログに記録されます)、複数の高優先度メッセージが互いに横取りした可能性、またはトリガー同期の競合が適用された可能性があります。キャンバスのアプリ内メッセージについては、[キャンバスのアプリ内メッセージ](#canvas-in-app-messages)を参照してください。指標の完全な定義については、[アプリ内メッセージレポート](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/reporting)と[アプリ内メッセージFAQ](https://www.braze.com/docs/ja/ja/user_guide/channels/in_app_messages/faq)を参照してください。 - **インプレッションが以前より少ない:** セグメントとキャンペーンの変更ログを確認してください。より優先度の高いキャンペーンで同じトリガーイベントを再利用していないか確認してください。 ![キャンペーン詳細ページの変更ログを表示するリンク。ユーザーが最後にキャンペーンを閲覧してから7件の変更があります。](https://www.braze.com/docs/ja/ja/assets/img_archive/trouble4.png?d1b004eed1ccaf74f475397ebbae7958) デリゲートまたはカスタムハンドラーを使用してアプリ内メッセージを手動で表示している場合は、インプレッションとクリックを自分でログに記録する必要があります。SwiftとAndroidの詳細については、[プラットフォーム固有の表示トラブルシューティング](#platform-specific-display-troubleshooting)のSDKタブを参照してください。Webについては、[アプリ内メッセージデータのログ記録](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/logging_message_data)を参照してください。 ## プラットフォーム固有の表示トラブルシューティング {#platform-specific-display-troubleshooting} イベントユーザーログに**Trigger In-App Message**行が表示されているがデバイスに何も表示されない場合は、SDKタブを選択して表示チェック(デリゲート、レート制限、画面の向き、カスタムハンドラー)を確認してください。 ### Troubleshooting display {#troubleshooting-in-app-message-display} If your app is requesting and receiving in-app messages but they aren't showing, device-side logic may be preventing display: 1. Is the trigger event firing as expected? To test, configure the message to trigger on a different action (such as session start) and verify whether it displays. 3. Failed image downloads prevent in-app messages with images from displaying. Check device logs for download failures. Try removing the image temporarily to see if the message displays. ### Troubleshooting display {#troubleshooting-in-app-message-display} If your app is requesting and receiving in-app messages but they aren't showing, device-side logic may be preventing display: 1. Is the trigger event firing as expected? To test, configure the message to trigger on a different action (such as session start) and verify whether it displays. 3. Failed image downloads prevent in-app messages with images from displaying. Check device logs for download failures. Try removing the image temporarily to see if the message displays. ### Troubleshooting display {#troubleshooting-in-app-message-display} If your app is requesting and receiving in-app messages but they aren't showing, device-side logic may be preventing display: 1. Is the trigger event firing as expected? To test, configure the message to trigger on a different action (such as session start) and verify whether it displays. 3. Failed image downloads prevent in-app messages with images from displaying. Check device logs for download failures. Try removing the image temporarily to see if the message displays. ### Troubleshooting asset loading (`NSURLError` code `-1008`) {#asset-loading} When integrating Braze alongside third-party network logging libraries, developers can commonly run into an `NSURLError` with the domain code `-1008`. This error indicates that assets like images and fonts could not be retrieved or failed to cache. To work around such cases, you must register Braze CDN URLs to the list of domains that should be ignored by these libraries. #### Domains The full list of CDN domains is as listed below: * `"appboy-images.com"` * `"braze-images.com"` * `"cdn.braze.eu"` * `"cdn.braze.com"` #### Examples Below are libraries that are known to conflict with Braze asset caching, along with example code to work around the issue. If your project uses a library that causes an unavailable resource error and is not listed below, consult the documentation of that library for similar usage APIs. ##### Netfox ```swift NFX.sharedInstance().ignoreURLs(["https://cdn.braze.com"]) ``` ```objc [NFX.sharedInstance ignoreURLs:@[@"https://cdn.braze.com"]]; ``` ##### NetGuard ```swift NetGuard.blackListHosts.append(contentsOf: ["cdn.braze.com"]) ``` ```objc NSMutableArray *blackListHosts = [NetGuard.blackListHosts mutableCopy]; [blackListHosts addObject:@"cdn.braze.com"]; NetGuard.blackListHosts = blackListHosts; ``` ##### XNLogger ```swift let brazeAssetsHostFilter = XNHostFilter(host: "https://cdn.braze.com") XNLogger.shared.addFilters([brazeAssetsHostFilter]) ``` ```objc XNHostFilter *brazeAssetsHostFilter = [[XNHostFilter alloc] initWithHost: @"https://cdn.braze.com"]; [XNLogger.shared addFilters:@[brazeAssetsHostFilter]]; ``` # Braze SDKのプッシュ通知 Source: /docs/ja/developer_guide/push_notifications/index.md # プッシュ通知 {#push-notifications} > [プッシュ通知](https://www.braze.com/docs/ja/ja/user_guide/channels/push)を使用すると、重要なイベントが発生したときにアプリから通知を送ることができます。新しいインスタントメッセージを配信したり、ニュース速報を送信したり、ユーザーのお気に入りのテレビ番組の最新エピソードがオフライン視聴用にダウンロードできるようになったときに、プッシュ通知を送信できます。また、必要なときにのみアプリケーションが起動するため、バックグラウンドでの取得よりも効率的です。 **Note:** **Web URLにリダイレクト**で**アプリ内でWeb URLを開く**が選択されていないにもかかわらず、リンクがアプリ内で開かれる場合、アプリがそのURLを処理している可能性があります(例えば、iOSのユニバーサルリンクやAndroidのApp Linksなど)。代わりにブラウザーでリンクを開くには、ユーザーが通知をタップしたときにアプリがURLをシステムブラウザーに委任していることを確認するか、クリックアクションがBrazeダッシュボードの設定と一致するようにアプリのURL処理を調整してください。クリックアクションとURL処理の設定方法については、各プラットフォームのプッシュ通知ドキュメントを参照してください。 **Note:** This guide uses code samples from the Braze Web SDK 4.0.0+. To upgrade to the latest Web SDK version, see [SDK Upgrade Guide](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md). ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ## Push protocols Web push notifications are implemented using the [W3C push standard](http://www.w3.org/TR/push-api/), which most major browsers support. For more information on specific push protocol standards and browser support, you can review resources from [Apple](https://developer.apple.com/notifications/safari-push-notifications/) [Mozilla](https://developer.mozilla.org/en-us/docs/web/api/push_api#browser_compatibility) and [Microsoft](https://developer.microsoft.com/en-us/microsoft-edge/status/pushapi/). ## Setting up push notifications ### Step 1: Configure your service worker In your project's `service-worker.js` file, add the following snippet and set the [`manageServiceWorkerExternally`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initialize) initialization option to `true` when initializing the Web SDK. **Important:** Your web server must return a `Content-Type: application/javascript` when serving your service worker file. Additionally, if your service worker file is not `service-worker.js` named, you'll need to use the `serviceWorkerLocation` [initialization option](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initializationoptions). ### Step 2: Register the browser To immediately request push permissions from a user so their browser can receive push notifications, call `braze.requestPushPermission()`. To test if push is supported in their browser first, call `braze.isPushSupported()`. You can also [send a soft push prompt](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/soft_push_prompts/?sdktab=web) to the user before requesting push permission to show your own push-related UI. **Important:** On macOS, both **Google Chrome** and **Google Chrome Helper (Alerts)** must be enabled by the end-user in **System Settings > Notifications** before push notifications can be displayed—even if permissions are granted. ### Step 3: Disable `skipWaiting` (optional) The Braze service worker file will automatically call `skipWaiting` upon install. If you'd like to disable this functionality, add the following code to your service worker file, after importing Braze: ## Unsubscribing a user To unsubscribe a user, call `braze.unregisterPush()`. **Important:** Recent versions of Safari and Firefox require that you call this method from a short-lived event handler (such as from a button-click handler or soft push prompt). This is consistent with [Chrome's user experience best practices](https://docs.google.com/document/d/1WNPIS_2F0eyDm5SS2E6LZ_75tk6XtBSnR1xNjWJ_DPE) for push registration. ## Alternate domains To integrate web push, your domain must be [secure](https://w3c.github.io/webappsec-secure-contexts/), which generally means `https`, `localhost`, and other exceptions as defined in the [W3C push standard](https://www.w3.org/TR/service-workers/#security-considerations). You'll also need to be able to register a Service Worker at the root of your domain, or at least be able to control the HTTP headers for that file. This article covers how to integrate Braze Web Push on an alternate domain. ### Use cases If you can't meet all of the criteria outlined in the [W3C push standard](https://www.w3.org/TR/service-workers/#security-considerations), you can use this method to add a push prompt dialog to your website instead. This can be helpful if you want to let your users opt-in from an `http` website or a browser extension popup that's preventing your push prompt from displaying. ### Considerations Keep in mind, like many workarounds on the web, browsers continually evolve, and this method may not be viable in the future. Before continuing, ensure that: - You own a separate secure domain (`https://`) and permissions to register a Service Worker on that domain. - Users are logged in to your website which ensures push tokens are match to the correct profile. **Important:** You cannot use this method to implement push notifications for Shopify. Shopify will automatically remove the headers need to deliver push this way. ### Setting up an alternate push domain To make the following example clear, we'll use use `http://insecure.com` and `https://secure.com` as our two domains with the goal of getting visitors to register for push on `http://insecure.com`. This example could also be applied to a `chrome-extension://` scheme for a browser extension's popup page. #### Step 1: Initiate prompting flow On `insecure.com`, open a new window to your secure domain using a URL parameter to pass the currently logged-in user's Braze external ID. **http://insecure.com** ```html ``` #### Step 2: Register for push At this point, `secure.com` will open a popup window in which you can initialize the Braze Web SDK for the same user ID and request the user's permission for Web push. **https://secure.com/push-registration.html** #### Step 3: Communicate between domains (optional) Now that users can opt-in from this workflow originating on `insecure.com`, you may want to modify your site based on if the user is already opted-in or not. There's no point in asking the user to register for push if they already are. You can use iFrames and the [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) API to communicate between your two domains. **insecure.com** On our `insecure.com` domain, we will ask the secure domain (where push is _actually_ registered) for information on the current user's push registration: ```html ``` **secure.com/push-status.html** ## Frequently Asked Questions (FAQ) ### Service workers #### What if I can't register a service worker in the root directory? By default, a service worker can only be used within the same directory it is registered in. For example, if your service worker file exists in `/assets/service-worker.js`, it would only be possible to register it within `example.com/assets/*` or a subdirectory of the `assets` folder, but not on your homepage (`example.com/`). For this reason, it is recommended to host and register the service worker in the root directory (such as `https://example.com/service-worker.js`). If you cannot register a service worker in your root domain, an alternative approach is to use the [`Service-Worker-Allowed`](https://w3c.github.io/ServiceWorker/#service-worker-script-response) HTTP header when serving your service worker file. By configuring your server to return `Service-Worker-Allowed: /` in the response for the service worker, this will instruct the browser to broaden the scope and allow it to be used from within a different directory. #### Can I create a service worker using a Tag Manager? No, service workers must be hosted on your website's server and can't be loaded via Tag Manager. ### Site security #### Is HTTPS required? Yes. Web standards require that the domain requesting push notification permission be secure. #### When is a site considered "secure"? A site is considered secure if it matches one of the following secure-origin patterns. Braze Web push notifications are built on this open standard, so man-in-the-middle attacks are prevented. - `(https, , *)` - `(wss, *, *)` - `(, localhost, )` - `(, .localhost, *)` - `(, 127/8, )` - `(, ::1/128, *)` - `(file, *, —)` - `(chrome-extension, *, —)` #### What if a secure site is not available? While industry best practice is to make your whole site secure, customers who cannot secure their site domain can work around the requirement by using a secure modal. Read more in our guide to using [Alternate push domain](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/push_notifications/alternate_push_domain) or view a [working demo](http://appboyj.com/modal-test.html). ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Built-in features The following features are built into the Braze Android SDK. To use any other push notification features, you will need to [set up push notifications](#android_setting-up-push-notifications) for your app. |Feature|Description| |-------|-----------| |Push Stories|Android Push Stories are built into the Braze Android SDK by default. To learn more, see [Push Stories](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/advanced_push_options/push_stories/).| |Push Primers|Push primer campaigns encourage your users to enable push notifications on their device for your app. This can be done without SDK customization using our [no code push primer](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/best_practices/push_primer_messages/).| {: .reset-td-br-1 .reset-td-br-2 aria-label="Built-in features" } ## About the push notification lifecycle {#push-notification-lifecycle} The following flowchart shows how Braze handles the push notification lifecycle, such as permission prompts, token generation, and message delivery. ```mermaid --- config: theme: neutral --- flowchart TD %% Permission flow subgraph Permission[Push Permissions] B{Android version of the device?} B -->|Android 13+| C["requestPushPermissionPrompt() called"] B -->|Android 12 and earlier| D[No permissions required] %% Connect Android 12 path to Braze state D --> H3[Braze: user subscription state] H3 --> J3[Defaults to 'subscribed' when user profile created] C --> E{Did the user grant push permission?} E -->|Yes| F[POST_NOTIFICATIONS permission granted] E -->|No| G[POST_NOTIFICATIONS permission denied] %% Braze subscription state updates F --> H1[Braze: user subscription state] G --> H2[Braze: user subscription state] H1 --> I1{Automatically opt in after permission granted?} I1 -->|true| J1[Set to 'opted-in'] I1 -->|false| J2[Remains 'subscribed'] H2 --> K1[Remains 'subscribed'
or 'unsubscribed'] %% Subscription state legend subgraph BrazeStates[Braze subscription states] L1['Subscribed' - default state
when user profile created] L2['Opted-in' - user explicitly
wants push notifications] L3['Unsubscribed' - user explicitly
opted out of push] end %% Note about user-level states note1[Note: These states are user-level
and apply across all devices for the user] %% Connect states to legend J1 -.-> L2 J2 -.-> L1 J3 -.-> L1 K1 -.-> L3 note1 -.-> BrazeStates end %% Styling classDef permissionClass fill:#e3f2fd,stroke:#1565c0,stroke-width:2px classDef tokenClass fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px classDef sdkClass fill:#fff3e0,stroke:#e65100,stroke-width:2px classDef configClass fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px classDef displayClass fill:#ffebee,stroke:#c62828,stroke-width:2px classDef deliveryClass fill:#fce4ec,stroke:#c2185b,stroke-width:2px classDef brazeClass fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px class A,B,C,E,F,G permissionClass class H,I tokenClass class J,K sdkClass class N,O,P configClass class R,S,S1,T,U,V displayClass class W,X,X1,X2,Y,Z deliveryClass class H1,H2,H3,I1,J1,J2,J3,K1,L1,L2,L3,note1 brazeClass ``` ```mermaid --- config: theme: neutral --- flowchart TD %% Token generation flow subgraph Token[Token Generation] H["Braze SDK initialized"] --> Q{Is FCM auto-registration enabled?} Q -->|Yes| L{Is required configuration present?} Q -->|No| M[No FCM token generated] L -->|Yes| I[Generate FCM token] L -->|No| M I --> K[Register token with Braze] %% Configuration requirements subgraph Config[Required configuration] N['google-services.json' file is present] O['com.google.firebase:firebase-messaging' in gradle] P['com.google.gms.google-services' plugin in gradle] end %% Connect config to check N -.-> L O -.-> L P -.-> L end %% Styling classDef permissionClass fill:#e3f2fd,stroke:#1565c0,stroke-width:2px classDef tokenClass fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px classDef sdkClass fill:#fff3e0,stroke:#e65100,stroke-width:2px classDef configClass fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px classDef displayClass fill:#ffebee,stroke:#c62828,stroke-width:2px classDef deliveryClass fill:#fce4ec,stroke:#c2185b,stroke-width:2px classDef brazeClass fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px class A,B,C,E,F,G permissionClass class H,I tokenClass class J,K sdkClass class N,O,P configClass class R,S,S1,T,U,V displayClass class W,X,X1,X2,Y,Z deliveryClass class H1,H2,H3,I1,J1,J2,J3,K1,L1,L2,L3,note1 brazeClass ``` ```mermaid --- config: theme: neutral fontSize: 10 --- flowchart TD subgraph Display[Push Display] %% Push delivery flow W[Push sent to FCM servers] --> X{Did FCM receive push?} X -->|App is terminated| Y[FCM cannot deliver push to the app] X -->|Delivery conditions met| X1[App receives push from FCM] X1 --> X2[Braze SDK receives push] X2 --> R[Push type?] %% Push Display Flow R -->|Standard push| S{Is push permission required?} R -->|Silent push| T[Braze SDK processes silent push] S -->|Yes| S1{Did the user grant push permission?} S -->|No| V[Notification is shown to the user] S1 -->|Yes| V S1 -->|No| U[Notification is not shown to the user] end %% Styling classDef permissionClass fill:#e3f2fd,stroke:#1565c0,stroke-width:2px classDef tokenClass fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px classDef sdkClass fill:#fff3e0,stroke:#e65100,stroke-width:2px classDef configClass fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px classDef displayClass fill:#ffebee,stroke:#c62828,stroke-width:2px classDef deliveryClass fill:#fce4ec,stroke:#c2185b,stroke-width:2px classDef brazeClass fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px class A,B,C,E,F,G permissionClass class H,I tokenClass class J,K sdkClass class N,O,P configClass class R,S,S1,T,U,V displayClass class W,X,X1,X2,Y,Z deliveryClass class H1,H2,H3,I1,J1,J2,J3,K1,L1,L2,L3,note1 brazeClass ``` ## Setting up push notifications **Tip:** To check out a sample app using FCM with the Braze Android SDK, see [Braze: Firebase Push Sample App](https://github.com/braze-inc/braze-android-sdk/tree/master/samples/firebase-push). ### Rate limits Firebase Cloud Messaging (FCM) API has a default rate limit of 600,000 requests per minute. If you reach this limit, Braze will automatically try again in a few minutes. To request an increase, contact [Firebase Support](https://firebase.google.com/support). ### Step 1: Add Firebase to your project First, add Firebase to your Android project. For step-by-step instructions, see Google's [Firebase setup guide](https://firebase.google.com/docs/android/setup). ### Step 2: Add Cloud Messaging to your dependencies Next, add the Cloud Messaging library to your project dependencies. In your Android project, open `build.gradle`, then add the following line to your `dependencies` block. ```gradle implementation "google.firebase:firebase-messaging:+" ``` Your dependencies should look similar to the following: ```gradle dependencies { implementation project(':android-sdk-ui') implementation "com.google.firebase:firebase-messaging:+" } ``` ### Step 3: Enable the Firebase Cloud Messaging API In Google Cloud, select the project your Android app is using, then enable the [Firebase Cloud Messaging API](https://console.cloud.google.com/apis/library/fcm.googleapis.com). ![Enabled Firebase Cloud Messaging API](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/create_a_service_account/firebase-cloud-messaging-api-enabled.png?da5af516c5eab2865056a248406f7a8f){: style="max-width:80%;"} ### Step 4: Create a service account {#service-account} Next, create a new service account, so Braze can make authorized API calls when registering FCM tokens. In Google Cloud, go to **Service Accounts**, then choose your project. On the **Service Accounts** page, select **Create Service Account**. ![A project's service account home page with "Create Service Account" highlighted.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/create_a_service_account/select-create-service-account.png?06a4afaf11e0d044900fbf49eaf980c5) Enter a service account name, ID, and description, then select **Create and continue**. In the **Role** field, find and select **Firebase Cloud Messaging API Admin** from the list of roles. For more restrictive access, create a [custom role](https://cloud.google.com/iam/docs/creating-custom-roles) with the `cloudmessaging.messages.create` permission, then choose it from the list instead. When you're finished, select **Done**. **Warning:** Be sure to select **Firebase Cloud Messaging _API_ Admin**, not **Firebase Cloud Messaging Admin**. ![The form for "Grant this service account access to project" with "Firebase Cloud Messaging API Admin" selected as the role.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/create_a_service_account/add-fcm-api-admin.png?f4552c25937169d7eb2d9e09f4fea296) ### Step 5: Generate JSON credentials {#json} Next, generate JSON credentials for your FCM service account. On Google Cloud IAM & Admin, go to **Service Accounts**, then choose your project. Locate the FCM service account [you created earlier](#android_service-account), then select  **Actions** > **Manage Keys**. ![The project's service account homepage with the "Actions" menu open.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/generate_json_credentials/select-manage-keys.png?3da57ece332b89e7d332a240ee4405e3) Select **Add Key** > **Create new key**. ![The selected service account with the "Add Key" menu open.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/generate_json_credentials/select-create-new-key.png?8ed2f8cc053903ccef9c098604e6c26e) Choose **JSON**, then select **Create**. If you created your service account using a different Google Cloud project ID than your FCM project ID, you'll need to manually update the value assigned to the `project_id` in your JSON file. Be sure to remember where you downloaded the key—you'll need it in the next step. ![The form for creating a private key with "JSON" selected.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/generate_json_credentials/select-create.png?a9f9ec288b77f9e2922e2fd68fc5e3e1){: style="max-width:65%;"} **Warning:** Private keys could pose a security risk if compromised. Store your JSON credentials in a secure location for now—you'll delete your key after you upload it to Braze. ### Step 6: Upload your JSON credentials to Braze Next, upload your JSON credentials to your Braze dashboard. In Braze, select  **Settings** > **App Settings**. ![The "Settings" menu open in Braze with "App Settings" highlighted.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/upload_json_credentials/select-app-settings.png?8f1231dc6eac885988f3201d6921cec3) Under your Android app's **Push Notification Settings**, choose **Firebase**, then select **Upload JSON File** and upload the credentials [you generated earlier](#android_json). When you're finished, select **Save**. ![The form for "Push Notification Settings" with "Firebase" selected as the push provider.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/upload_json_credentials/upload-json-file.png?98d4a93fa663294fccb3db920980da70) **Warning:** Private keys could pose a security risk if compromised. Now that your key is uploaded to Braze, delete the file [you generated previously](#android_json). ### Step 7: Set up automatic token registration When one of your users opt-in for push notifications, your app needs to generate an FCM token on their device before you can send them push notifications. With the Braze SDK, you can enable automatic FCM token registration for each user's device in your project's Braze configuration files. First, go to Firebase Console, open your project, then select  **Settings** > **Project settings**. ![The Firebase project with the "Settings" menu open.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/set_up_automatic_token_registration/select-project-settings.png?9f5e0865e0fb698d08b31cc74069c256) Select **Cloud Messaging**, then under **Firebase Cloud Messaging API (V1)**, copy the number in the **Sender ID** field. ![The Firebase project's "Cloud Messaging" page with the "Sender ID" highlighted.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/set_up_automatic_token_registration/copy-sender-id.png?f27e894f55060ddb1e698581ed8bb912) Next, open your Android Studio project and use your Firebase Sender ID to enable automatic FCM token registration within your `braze.xml` or `BrazeConfig`. To configure automatic FCM token registration, add the following lines to your `braze.xml` file: ```xml true FIREBASE_SENDER_ID ``` Replace `FIREBASE_SENDER_ID` with the value you copied from your Firebase project settings. Your `braze.xml` should look similar to the following: ```xml 12345ABC-6789-DEFG-0123-HIJK456789LM true 603679405392 ``` To configure automatic FCM token registration, add the following lines to your `BrazeConfig`: ```java .setIsFirebaseCloudMessagingRegistrationEnabled(true) .setFirebaseCloudMessagingSenderIdKey("FIREBASE_SENDER_ID") ``` ```kotlin .setIsFirebaseCloudMessagingRegistrationEnabled(true) .setFirebaseCloudMessagingSenderIdKey("FIREBASE_SENDER_ID") ``` Replace `FIREBASE_SENDER_ID` with the value you copied from your Firebase project settings. Your `BrazeConfig` should look similar to the following: ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setApiKey("12345ABC-6789-DEFG-0123-HIJK456789LM") .setCustomEndpoint("sdk.iad-01.braze.com") .setSessionTimeout(60) .setHandlePushDeepLinksAutomatically(true) .setGreatNetworkDataFlushInterval(10) .setIsFirebaseCloudMessagingRegistrationEnabled(true) .setFirebaseCloudMessagingSenderIdKey("603679405392") .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setApiKey("12345ABC-6789-DEFG-0123-HIJK456789LM") .setCustomEndpoint("sdk.iad-01.braze.com") .setSessionTimeout(60) .setHandlePushDeepLinksAutomatically(true) .setGreatNetworkDataFlushInterval(10) .setIsFirebaseCloudMessagingRegistrationEnabled(true) .setFirebaseCloudMessagingSenderIdKey("603679405392") .build() Braze.configure(this, brazeConfig) ``` **Tip:** If you'd like to manually register FCM tokens instead, set the [`registeredPushToken`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/registered-push-token.html) property on the Braze instance inside your app's [`onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()) method. ```kotlin // Kotlin Braze.getInstance(context).registeredPushToken = "FCM_TOKEN" ``` ```java // Java Braze.getInstance(context).setRegisteredPushToken("FCM_TOKEN"); ``` ### Step 8: Remove automatic requests in your application class To prevent Braze from triggering unnecessary network requests every time you send silent push notifications, remove any automatic network requests configured in your `Application` class's `onCreate()` method. For more information see, [Android Developer Reference: Application](https://developer.android.com/reference/android/app/Application). ## Displaying notifications ### Step 1: Register Braze Firebase Messaging Service You can either create a new, existing, or non-Braze Firebase Messaging Service. Choose whichever best meets your specific needs. Braze includes a service to handle push receipt and open intents. Our `BrazeFirebaseMessagingService` class will need to be registered in your `AndroidManifest.xml`: ```xml ``` Our notification code also uses `BrazeFirebaseMessagingService` to handle open and click action tracking. This service must be registered in the `AndroidManifest.xml` to function correctly. Also, remember that Braze prefixes notifications from our system with a unique key so that we only render notifications sent from our systems. You may register additional services separately to render notifications sent from other FCM services. See [`AndroidManifest.xml`](https://github.com/braze-inc/braze-android-sdk/blob/master/samples/firebase-push/src/main/AndroidManifest.xml) in the Firebase push sample app. **Important:** Before Braze SDK 3.1.1, `AppboyFcmReceiver` was used to handle FCM push. The `AppboyFcmReceiver` class should be removed from your manifest and replaced with the preceding integration. If you already have a Firebase Messaging Service registered, you can pass [`RemoteMessage`](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/RemoteMessage) objects to Braze via [`BrazeFirebaseMessagingService.handleBrazeRemoteMessage()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.push/-braze-firebase-messaging-service/-companion/handle-braze-remote-message.html). This method will only display a notification if the [`RemoteMessage`](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/RemoteMessage) object originated from Braze and will safely ignore if not. ```java public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); if (BrazeFirebaseMessagingService.handleBrazeRemoteMessage(this, remoteMessage)) { // This Remote Message originated from Braze and a push notification was displayed. // No further action is needed. } else { // This Remote Message did not originate from Braze. // No action was taken and you can safely pass this Remote Message to other handlers. } } } ``` ```kotlin class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage?) { super.onMessageReceived(remoteMessage) if (BrazeFirebaseMessagingService.handleBrazeRemoteMessage(this, remoteMessage)) { // This Remote Message originated from Braze and a push notification was displayed. // No further action is needed. } else { // This Remote Message did not originate from Braze. // No action was taken and you can safely pass this Remote Message to other handlers. } } } ``` If you have another Firebase Messaging Service you would also like to use, you can also specify a fallback Firebase Messaging Service to call if your application receives a push that isn't from Braze. In your `braze.xml`, specify: ```xml true com.company.OurFirebaseMessagingService ``` or set via [runtime configuration:](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization/?sdktab=android) ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setFallbackFirebaseMessagingServiceEnabled(true) .setFallbackFirebaseMessagingServiceClasspath("com.company.OurFirebaseMessagingService") .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setFallbackFirebaseMessagingServiceEnabled(true) .setFallbackFirebaseMessagingServiceClasspath("com.company.OurFirebaseMessagingService") .build() Braze.configure(this, brazeConfig) ``` ### Step 2: Conform small icons to design guidelines For general information about Android notification icons, visit the [Notifications overview](https://developer.android.com/guide/topics/ui/notifiers/notifications). Starting in Android N, you should update or remove small notification icon assets that involve color. The Android system (not the Braze SDK) ignores all non-alpha and transparency channels in action icons and the notification small icon. In other words, Android will convert all parts of your notification small icon to monochrome except for transparent regions. To create a notification small icon asset that displays properly: - Remove all colors from the image except for white. - All other non-white regions of the asset should be transparent. **Note:** A common symptom of an improper asset is the small notification icon rendering as a solid monochrome square. This is due to the Android system not being able to find any transparent regions in the notification small icon asset. The following large and small icons pictured are examples of properly designed icons: ![A small icon appearing in the bottom corner of a large icons beside a message that says "Hey I'm on my way to the bar but.."](https://www.braze.com/docs/ja/ja/assets/img_archive/large_and_small_notification_icon.png?3231bf42436a261175a9cc890b4443bf "Large and Small Notification Icon") ### Step 3: Configure notification icons {#configure-icons} #### Specifying icons in braze.xml Braze allows you to configure your notification icons by specifying drawable resources in your `braze.xml`: ```xml REPLACE_WITH_YOUR_ICON REPLACE_WITH_YOUR_ICON ``` Setting a small notification icon is required. **If you do not set one, Braze will default to using the application icon as the small notification icon, which may look suboptimal.** Setting a large notification icon is optional but recommended. #### Specifying icon accent color The notification icon accent color can be overridden in your `braze.xml`. If the color is not specified, the default color is the same gray Lollipop uses for system notifications. ```xml 0xFFf33e3e ``` You may also optionally use a color reference: ```xml @color/my_color_here ``` ### Step 4: Add deep links #### Enabling automatic deep link opening To enable Braze to automatically open your app and any deep links when a push notification is clicked, set `com_braze_handle_push_deep_links_automatically` to `true`, in your `braze.xml`: ```xml true ``` This flag can also be set via [runtime configuration](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization/?sdktab=android): ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setHandlePushDeepLinksAutomatically(true) .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setHandlePushDeepLinksAutomatically(true) .build() Braze.configure(this, brazeConfig) ``` If you want to custom handle deep links, you will need to create a push callback that listens for push received and opened intents from Braze. For more information, see [Using a callback for push events](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/customization#android_using-a-callback-for-push-events). ## Handling foreground notifications By default, when a push notification arrives while your app is in the foreground on Android, the system displays it automatically. To have Braze process the push notification payload (for analytics tracking, deep link handling, and custom processing), route the incoming push data to Braze inside your `FirebaseMessagingService.onMessageReceived` method. ### How it works When you call `BrazeFirebaseMessagingService.handleBrazeRemoteMessage`, Braze determines if the payload is a Braze push notification and, if so, creates and displays the notification with the `NotificationManagerCompat` method. Unlike iOS, Android displays notifications regardless of whether the app is in the foreground or background. ```java package com.example.push; import com.braze.push.BrazeFirebaseMessagingService; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); // Let Braze process the payload and display the notification if (BrazeFirebaseMessagingService.handleBrazeRemoteMessage(this, remoteMessage)) { // Braze successfully handled the push notification } else { // Handle non-Braze messages } } } ``` ```kotlin package com.example.push import com.braze.push.BrazeFirebaseMessagingService import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // Let Braze process the payload and display the notification if (BrazeFirebaseMessagingService.handleBrazeRemoteMessage(this, remoteMessage)) { // Braze successfully handled the push notification } else { // Handle non-Braze messages } } } ``` For more information, see the [Firebase integration sample](https://github.com/braze-inc/braze-android-sdk/blob/master/samples/firebase-push/src/main/java/com/braze/firebasepush/FirebaseMessagingService.kt) in the Braze Android SDK repository. ### Customizing foreground behavior If you want custom foreground behavior, such as suppressing the system notification or showing an in-app UI instead, you can: - Use `subscribeToPushNotificationEvents` to react to push events and handle deep links with the `BrazeNotificationUtils.routeUserWithNotificationOpenedIntent` method. For more information, see the [Firebase push sample](https://github.com/braze-inc/braze-android-sdk/blob/master/samples/firebase-push/src/main/java/com/braze/firebasepush/FirebaseApplication.kt). - Build and post your own notification using a custom `IBrazeNotificationFactory`, or suppress the notification by not calling `notificationManager.notify` in your handling path. For more information on customizing notifications, see [Custom notification factory](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/customization/?sdktab=android#custom-notification-factory). #### Creating custom deep links Follow the instructions found within the [Android developer documentation](http://developer.android.com/training/app-indexing/deep-linking.html) on deep linking if you have not already added deep links to your app. To learn more about what deep links are, see our [FAQ article](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize/actions_and_media_urls/#what-is-deep-linking). #### Adding deep links The Braze dashboard supports setting deep links or web URLs in push notifications campaigns and Canvases that will be opened when the notification is clicked. ![The 'On Click Behavior' setting in the Braze dashboard with 'Deep Link Into Application' selected from the dropdown.](https://www.braze.com/docs/ja/ja/assets/img_archive/deep_link_click_action.png?7414cf7c78b097ac301be69fca3c5547 "Deep Link Click Action") #### Customizing back stack behavior The Android SDK, by default, will place your host app's main launcher activity in the back stack when following push deep links. Braze allows you to set a custom activity to open in the back stack in place of your main launcher activity or to disable the back stack altogether. For example, to set an activity called `YourMainActivity` as the back stack activity using [runtime configuration](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization/?sdktab=android): ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setPushDeepLinkBackStackActivityEnabled(true) .setPushDeepLinkBackStackActivityClass(YourMainActivity.class) .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setPushDeepLinkBackStackActivityEnabled(true) .setPushDeepLinkBackStackActivityClass(YourMainActivity.class) .build() Braze.configure(this, brazeConfig) ``` See the equivalent configuration for your `braze.xml`. Note that the class name must be the same as returned by `Class.forName()`. ```xml true your.package.name.YourMainActivity ``` ### Step 5: Define notification channels The Braze Android SDK supports [Android notification channels](https://developer.android.com/preview/features/notification-channels.html). If a Braze notification does not contain the ID for a notification channel or that a Braze notification contains an invalid channel ID, Braze will display the notification with the default notification channel defined in the SDK. Company users use [Android Notification Channels](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/android/notification_channels/) within the platform to group notifications. To set the user facing name of the default Braze notification channel, use [`BrazeConfig.setDefaultNotificationChannelName()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-default-notification-channel-name.html). To set the user facing description of the default Braze notification channel, use [`BrazeConfig.setDefaultNotificationChannelDescription()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-default-notification-channel-description.html). Update any API campaigns with the [Android push object](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/android_object/) parameter to include the `notification_channel` field. If this field is not specified, Braze will send the notification payload with the [dashboard fallback](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/android/notification_channels/#dashboard-fallback-channel) channel ID. Other than the default notification channel, Braze will not create any channels. All other channels must be programmatically defined by the host app and then entered into the Braze dashboard. The default channel name and description can also be configured in `braze.xml`. ```xml Your channel name Your channel description ``` ### Step 6: Test notification display and analytics #### Testing display At this point, you should be able to see notifications sent from Braze. To test this, go to the **Campaigns** page on your Braze dashboard and create a **Push Notification** campaign. Choose **Android Push** and design your message. Then click the eye icon in the composer to get the test sender. Enter the user ID or email address of your current user and click **Send Test**. You should see the push show up on your device. ![The 'Test' tab of a push notification campaign in the Braze dashboard.](https://www.braze.com/docs/ja/ja/assets/img_archive/android_push_test.png?ee8f7372a8c3f7d77dc9ebd5e131a1f0 "Android Push Test") For issues related to push display, see our [troubleshooting guide](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/troubleshooting/?sdktab=android). #### Testing analytics At this point, you should also have analytics logging for push notification opens. Clicking on the notification when it arrives should result in the **Direct Opens** on your campaign results page to increase by 1. Check out our [push reporting](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/push_reporting/) article for a break down on push analytics. For issues related to push analytics, see our [troubleshooting guide](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/troubleshooting/?sdktab=android). #### Testing from command line If you'd like to test in-app and push notifications via the command-line interface, you can send a single notification through the terminal via cURL and the [messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/). You will need to replace the following fields with the correct values for your test case: - `YOUR_API_KEY` (Go to **Settings** > **API Keys**.) - `YOUR_EXTERNAL_USER_ID` (Search for a profile on the **Search Users** page.) - `YOUR_KEY1` (optional) - `YOUR_VALUE1` (optional) ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer {YOUR_API_KEY}" -d '{ "external_user_ids":["YOUR_EXTERNAL_USER_ID"], "messages": { "android_push": { "title":"Test push title", "alert":"Test push", "extra": { "YOUR_KEY1":"YOUR_VALUE1" } } } }' https://rest.iad-01.braze.com/messages/send ``` This example uses the `US-01` instance. If you are not on this instance, replace the `US-01` endpoint with [your endpoint](https://www.braze.com/docs/ja/ja/api/basics/#endpoints). ## Conversation push notifications ![Android notification shade showing a Conversations section with three grouped conversation notifications from different contacts.](https://www.braze.com/docs/ja/ja/assets/img/android/push/conversations_android.png?e93b0b2e074ac12cac3a56619b22117b){: style="float:right;max-width:35%;margin-left:15px;border: 0;"} The [people and conversations initiative](https://developer.android.com/guide/topics/ui/conversations) is a multi-year Android initiative that aims to elevate people and conversations in the system surfaces of the phone. This priority is based on the fact that communication and interaction with other people is still the most valued and important functional area for the majority of Android users across all demographics. ### Usage requirements - This notification type requires the Braze Android SDK v15.0.0+ and Android 11+ devices. - Unsupported devices or SDKs will fallback to a standard push notification. This feature is only available over the Braze REST API. See the [Android push object](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/android_object#android-conversation-push-object) for more information. ## FCM quota exceeded errors When your limit for Firebase Cloud Messaging (FCM) is exceeded, Google returns "quota exceeded" errors. The default limit for FCM is 600,000 requests per minute. Braze retries sending according to Google's recommended best practices. However, a large volume of these errors can prolong sending time by several minutes. To mitigate potential impact, Braze will send you an alert that the rate limit is being exceeded and steps you can take to prevent the errors. To check your current limit, go to your **Google Cloud Console** > **APIs & Services** > **Firebase Cloud Messaging API** > **Quotas & System Limits**, or visit the [FCM API Quotas page](https://console.cloud.google.com/apis/api/fcm.googleapis.com/quotas). ### Best practices We recommend these best practices to keep these error volumes low. #### Request a rate limit increase from FCM To request a rate limit increase from FCM, you can contact [Firebase Support](https://firebase.google.com/support) directly or do the following: 1. Go to the [FCM API Quotas page](https://console.cloud.google.com/apis/api/fcm.googleapis.com/quotas). 2. Locate the **Send requests per minute** quota. 3. Select **Edit Quota**. 4. Enter a new value and submit your request. #### Apply a workspace rate limit You can apply a workspace rate limit for Android push notifications. This can help regulate the delivery rate of your outgoing messages. For more details, see [Workspace messaging rate limits](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/messaging_rate_limits). ## Rate limits Push notifications are rate-limited, so don't be afraid of sending as many as your application needs. iOS and the Apple Push Notification service (APNs) servers will control how often they are delivered, and you won't get into trouble for sending too many. If your push notifications are throttled, they might be delayed until the next time the device sends a keep-alive packet or receives another notification. ## Setting up push notifications ### Step 1: Upload your APNs token Before you can send an iOS push notification using Braze, you need to upload your `.p8` push notification file, as described in [Apple's developer documentation](https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns): 1. In your Apple developer account, go to [**Certificates, Identifiers & Profiles**](https://developer.apple.com/account/ios/certificate). 2. Under **Keys**, select **All** and click the add button (+) in the upper-right corner. 3. Under **Key Description**, enter a unique name for the signing key. 4. Under **Key Services**, select the **Apple Push Notification service (APNs)** checkbox, then click **Continue**. Click **Confirm**. 5. Note the key ID. Click **Download** to generate and download the key. Make sure to save the downloaded file in a secure place, as you cannot download this more than once. 6. In Braze, go to **Settings** > **App Settings** and upload the `.p8` file under **Apple Push Certificate**. You can upload either your development or production push certificate. To test push notifications after your app is live in the App Store, its recommended to set up a separate workspace for the development version of your app. 7. When prompted, enter your app's [bundle ID](https://developer.apple.com/documentation/foundation/nsbundle/1418023-bundleidentifier), [key ID](https://developer.apple.com/help/account/manage-keys/get-a-key-identifier/), and [team ID](https://developer.apple.com/help/account/manage-your-team/locate-your-team-id). You'll also need to specify whether to send notifications to your app's development or production environment, which is defined by its provisioning profile. 8. When you're finished, select **Save**. ### Step 2: Enable push capabilities In Xcode, go to the **Signing & Capabilities** section of the main app target and add the push notifications capability. ![The 'Signing & Capabilities' section in an Xcode project.](https://www.braze.com/docs/ja/ja/assets/img_archive/Enable_push_capabilities.png?8a3957eea917ba442294b7dbbe60732f) ### Step 3: Set up push handling You can use the Swift SDK to automate the processing of remote notifications received from Braze. This is the simplest way to handle push notifications and is the recommended handling method. #### Step 3.1: Enable automation in the push property To enable the automatic push integration, set the `automation` property of the `push` configuration to `true`: ```swift let configuration = Braze.Configuration(apiKey: "{YOUR-BRAZE-API-KEY}", endpoint: "{YOUR-BRAZE-API-ENDPOINT}") configuration.push.automation = true ``` ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:@"{YOUR-BRAZE-API-KEY}" endpoint:@"{YOUR-BRAZE-API-ENDPOINT}"]; configuration.push.automation = [[BRZConfigurationPushAutomation alloc] initEnablingAllAutomations:YES]; ``` This instructs the SDK to: - Register your application for push notification on the system. - Request the push notification authorization/permission at initialization. - Dynamically provide implementations for the push notification related system delegate methods. **Note:** The automation steps performed by the SDK are compatible with pre-existing push notification handling integrations in your codebase. The SDK only automates the processing of remote notification received from Braze. Any system handler implemented to process your own or another third party SDK remote notifications will continue to work when `automation` is enabled. **Warning:** The SDK must be initialized on the main thread to enable push notification automation. SDK initialization must happen before the application has finished launching or in your AppDelegate [`application(_:didFinishLaunchingWithOptions:)`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622921-application) implementation. If your application requires additional setup before initializing the SDK, please refer to the [Delayed Initialization](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization/?sdktab=swift) documentation page. #### Step 3.2: Override individual configurations (optional) For more granular control, each automation step can be enabled or disabled individually: ```swift // Enable all automations and disable the automatic notification authorization request at launch. configuration.push.automation = true configuration.push.automation.requestAuthorizationAtLaunch = false ``` ```objc // Enable all automations and disable the automatic notification authorization request at launch. configuration.push.automation = [[BRZConfigurationPushAutomation alloc] initEnablingAllAutomations:YES]; configuration.push.automation.requestAuthorizationAtLaunch = NO; ``` See [`Braze.Configuration.Push.Automation`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/push-swift.class/automation-swift.class) for all available options and [`automation`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/push-swift.class/automation-swift.property) for more information on the automation behavior. **Note:** If you rely on push notifications for additional behavior specific to your app, you may still be able to use automatic push integration instead of manual push notification integration. The [`subscribeToUpdates(_:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/notifications-swift.class/subscribetoupdates(_:)) method provides a way to be notified of remote notifications processed by Braze. #### Step 3.1: Register for push notifications with APNs Include the appropriate code sample within your app's [`application:didFinishLaunchingWithOptions:` delegate method](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622921-application) so that your users' devices can register with APNs. Ensure that you call all push integration code in your application's main thread. Braze also provides default push categories for push action button support, which must be manually added to your push registration code. Refer to [push action buttons](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/customization/?sdktab=swift#swift_customizing-push-categories) for additional integration steps. Add the following code to the `application:didFinishLaunchingWithOptions:` method of your app delegate. **Note:** The following code sample includes integration for provisional push authentication (lines 5 and 6). If you are not planning on using provisional authorization in your app, you can remove the lines of code that add `UNAuthorizationOptionProvisional` to the `requestAuthorization` options.
Visit [iOS notification options](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/ios/notification_options/) to learn more about push provisional authentication. ```swift application.registerForRemoteNotifications() let center = UNUserNotificationCenter.current() center.setNotificationCategories(Braze.Notifications.categories) center.delegate = self var options: UNAuthorizationOptions = [.alert, .sound, .badge] if #available(iOS 12.0, *) { options = UNAuthorizationOptions(rawValue: options.rawValue | UNAuthorizationOptions.provisional.rawValue) } center.requestAuthorization(options: options) { granted, error in print("Notification authorization, granted: \(granted), error: \(String(describing: error))") } ``` ```objc [application registerForRemoteNotifications]; UNUserNotificationCenter *center = UNUserNotificationCenter.currentNotificationCenter; [center setNotificationCategories:BRZNotifications.categories]; center.delegate = self; UNAuthorizationOptions options = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge; if (@available(iOS 12.0, *)) { options = options | UNAuthorizationOptionProvisional; } [center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError *_Nullable error) { NSLog(@"Notification authorization, granted: %d, " @"error: %@)", granted, error); }]; ``` **Warning:** You must assign your delegate object using `center.delegate = self` synchronously before your app finishes launching, preferably in `application:didFinishLaunchingWithOptions:`. Not doing so may cause your app to miss incoming push notifications. Visit Apple's [`UNUserNotificationCenterDelegate`](https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate) documentation to learn more. If your app calls `wipeData()` and later re-enables the Braze SDK in the same app run, you must call `registerForRemoteNotifications()` again to re-populate the device token used by the SDK. #### Step 3.2: Register push tokens with Braze Once APNs registration is complete, pass the resulting `deviceToken` to Braze to enable for push notifications for the user. Add the following code to your app's `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)` method: ```swift AppDelegate.braze?.notifications.register(deviceToken: deviceToken) ``` Add the following code to your app's `application:didRegisterForRemoteNotificationsWithDeviceToken:` method: ```objc [AppDelegate.braze.notifications registerDeviceToken:deviceToken]; ``` **Important:** The `application:didRegisterForRemoteNotificationsWithDeviceToken:` delegate method is called every time after `application.registerForRemoteNotifications()` is called.

If you are migrating to Braze from another push service and your user's device has already registered with APNs, this method will collect tokens from existing registrations the next time the method is called, and users will not have to re-opt-in to push. #### Step 3.3: Enable push handling Next, pass the received push notifications along to Braze. This step is necessary for logging push analytics and link handling. Ensure that you call all push integration code in your application's main thread. ##### Default push handling To enable the Braze default push handling, add the following code to your app's `application(_:didReceiveRemoteNotification:fetchCompletionHandler:)` method: ```swift if let braze = AppDelegate.braze, braze.notifications.handleBackgroundNotification( userInfo: userInfo, fetchCompletionHandler: completionHandler ) { return } completionHandler(.noData) ``` Next, add the following to your app's `userNotificationCenter(_:didReceive:withCompletionHandler:)` method: ```swift if let braze = AppDelegate.braze, braze.notifications.handleUserNotification( response: response, withCompletionHandler: completionHandler ) { return } completionHandler() ``` To enable the Braze default push handling, add the following code to your application's `application:didReceiveRemoteNotification:fetchCompletionHandler:` method: ```objc BOOL processedByBraze = AppDelegate.braze != nil && [AppDelegate.braze.notifications handleBackgroundNotificationWithUserInfo:userInfo fetchCompletionHandler:completionHandler]; if (processedByBraze) { return; } completionHandler(UIBackgroundFetchResultNoData); ``` Next, add the following code to your app's `(void)userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:` method: ```objc BOOL processedByBraze = AppDelegate.braze != nil && [AppDelegate.braze.notifications handleUserNotificationWithResponse:response withCompletionHandler:completionHandler]; if (processedByBraze) { return; } completionHandler(); ``` ##### Foreground push handling To enable foreground push notifications and let Braze recognize them when they're received, implement `UNUserNotificationCenter.userNotificationCenter(_:willPresent:withCompletionHandler:)`. If a user taps your foreground notification, the `userNotificationCenter(_:didReceive:withCompletionHandler:)` push delegate will be called and Braze will log the push click event. ```swift func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions ) -> Void) { if let braze = AppDelegate.braze { // Forward notification payload to Braze for processing. braze.notifications.handleForegroundNotification(notification: notification) } // Configure application's foreground notification display options. if #available(iOS 14.0, *) { completionHandler([.list, .banner]) } else { completionHandler([.alert]) } } ``` To enable foreground push notifications and let Braze recognize them when they're received, implement `userNotificationCenter:willPresentNotification:withCompletionHandler:`. If a user taps your foreground notification, the `userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:` push delegate will be called and Braze will log the push click event. ```objc - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { if (AppDelegate.braze != nil) { // Forward notification payload to Braze for processing. [AppDelegate.braze.notifications handleForegroundNotificationWithNotification:notification]; } // Configure application's foreground notification display options. if (@available(iOS 14.0, *)) { completionHandler(UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner); } else { completionHandler(UNNotificationPresentationOptionAlert); } } ``` ## Testing notifications {#push-testing} If you'd like to test in-app and push notifications via the command line, you can send a single notification through the terminal via CURL and the [messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages/). You will need to replace the following fields with the correct values for your test case: - `YOUR_API_KEY` - available at **Settings** > **API Keys**. - `YOUR_EXTERNAL_USER_ID` - available on the **Search Users** page. See [assigning user IDs](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/analytics/setting_user_ids/#assigning-a-user-id) for more information. - `YOUR_KEY1` (optional) - `YOUR_VALUE1` (optional) In the following example, the `US-01` instance is being used. If you're not on this instance, refer to our [API documentation](https://www.braze.com/docs/ja/ja/api/basics/) to see which endpoint to make requests to. ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer {YOUR_API_KEY}" -d '{ "external_user_ids":["YOUR_EXTERNAL_USER_ID"], "messages": { "apple_push": { "alert":"Test push", "extra": { "YOUR_KEY1":"YOUR_VALUE1" } } } }' https://rest.iad-01.braze.com/messages/send ``` ## Subscribing to push notifications updates To access the push notification payloads processed by Braze, use the [`Braze.Notifications.subscribeToUpdates(payloadTypes:_:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/notifications-swift.class/subscribetoupdates(payloadtypes:_:)/) method. You can use the `payloadTypes` parameter to specify whether you'd like to subscribe to notifications involving push open events, push received events, or both. ```swift // This subscription is maintained through a Braze cancellable, which will observe for changes until the subscription is cancelled. // You must keep a strong reference to the cancellable to keep the subscription active. // The subscription is canceled either when the cancellable is deinitialized or when you call its `.cancel()` method. let cancellable = AppDelegate.braze?.notifications.subscribeToUpdates(payloadTypes: [.open, .received]) { payload in print("Braze processed notification with title '\(payload.title)' and body '\(payload.body)'") } ``` **Important:** Keep in mind, push received events will only trigger for foreground notifications and `content-available` background notifications. It will not trigger for notifications received while terminated or for background notifications without the `content-available` field. ```objc NSInteger filtersValue = BRZNotificationsPayloadTypeFilter.opened.rawValue | BRZNotificationsPayloadTypeFilter.received.rawValue; BRZNotificationsPayloadTypeFilter *filters = [[BRZNotificationsPayloadTypeFilter alloc] initWithRawValue: filtersValue]; BRZCancellable *cancellable = [notifications subscribeToUpdatesWithPayloadTypes:filters update:^(BRZNotificationsPayload * _Nonnull payload) { NSLog(@"Braze processed notification with title '%@' and body '%@'", payload.title, payload.body); }]; ``` **Important:** Keep in mind, push received events will only trigger for foreground notifications and `content-available` background notifications. It will not trigger for notifications received while terminated or for background notifications without the `content-available` field. **Note:** When using the automatic push integration, `subscribeToUpdates(_:)` is the only way to be notified of remote notifications processed by Braze. The `UIAppDelegate` and `UNUserNotificationCenterDelegate` system methods are not called when the notification is automatically processed by Braze. **Tip:** Create your push notification subscription in `application(_:didFinishLaunchingWithOptions:)` to ensure your subscription is triggered after an end-user taps a notification while your app is in a terminated state. ## Handling foreground notifications By default, when a push notification arrives while your app is in the foreground, iOS does not display it automatically. To display push notifications in the foreground and track them with Braze analytics, call the `handleForegroundNotification(notification:)` method inside your `UNUserNotificationCenterDelegate.userNotificationCenter(_:willPresent:withCompletionHandler:)` implementation. ### How it works When you call `handleForegroundNotification(notification:)`, Braze processes the notification payload to log analytics and handle any deep links or button actions. The actual display behavior is controlled by the `UNNotificationPresentationOptions` you pass to the completion handler. ```swift import BrazeKit import UserNotifications extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void ) { // Let Braze process the notification payload if let braze = AppDelegate.braze { braze.notifications.handleForegroundNotification(notification: notification) } // Control how the notification appears in the foreground if #available(iOS 14.0, *) { completionHandler([.banner, .list, .sound]) } else { completionHandler([.alert, .sound]) } } } ``` For a complete example, see the [push notifications manual integration sample](https://github.com/braze-inc/braze-swift-sdk/blob/e31907eaa0dbd151dc2e6826de66cc494242ba60/Examples/Swift/Sources/PushNotifications-Manual/AppDelegate.swift#L1-L120) in the Braze Swift SDK repository. ## Push primers {#push-primers} Push primer campaigns encourage your users to enable push notifications on their device for your app. This can be done without SDK customization using our [no code push primer](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/best_practices/push_primer_messages/). ## Dynamic APNs gateway management Dynamic Apple Push Notification Service (APNs) gateway management enhances the reliability and efficiency of iOS push notifications by automatically detecting the correct APNs environment. Previously, you would manually select APNs environments (development or production) for your push notifications, which sometimes led to incorrect gateway configurations, delivery failures, and `BadDeviceToken` errors. With dynamic APNs gateway management, you'll have: - **Improved reliability:** Notifications are always delivered to the correct APNs environment, reducing failed deliveries. - **Simplified configuration:** You no longer need to manually manage APNs gateway settings. - **Error resilience:** Invalid or missing gateway values are gracefully handled, providing uninterrupted service. ### Prerequisites Braze supports Dynamic APNs gateway management for push notifications on iOS with the following SDK version requirement: ### How it works When an iOS app integrates with the Braze Swift SDK, it sends device-related data, including [`aps-environment`](https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment) to the Braze SDK API, if available. The `apns_gateway` value indicates whether the app is using the development (`dev`) or production (`prod`) APNs environment. Braze also stores the reported gateway value for each device. If a new, valid gateway value is received, Braze updates the stored value automatically. When Braze sends a push notification: - If a valid gateway value (dev or prod) is stored for the device, Braze uses it to determine the correct APNs environment. - If no gateway value is stored, Braze defaults to the APNs environment configured in the **App Settings** page. ### Frequently asked questions #### Why was this feature introduced? With dynamic APNs gateway management, the correct environment is selected automatically. Previously, you had to manually configure the APNs gateway, which could lead to `BadDeviceToken` errors, token invalidation, and potential APNs rate-limiting issues. #### How does this impact push delivery performance? This feature improves delivery rates by always routing push tokens to the correct APNs environment, avoiding failures caused by misconfigured gateways. #### Can I disable this feature? Dynamic APNs Gateway Management is turned on by default and provides reliability improvements. If you have specific use cases that require manual gateway selection, contact [Braze Support](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/support/). ## About push notifications for Android TV ![](https://www.braze.com/docs/ja/ja/assets/img/Television.png?bf36c19525c113aaa61e5554d969b4b3){: style="float:right;max-width:25%;margin-left:15px; border: 0"} While not a native feature, Android TV push integration is made possible by leveraging the Braze Android SDK and Firebase Cloud Messaging to register a push token for Android TV. It is, however, necessary to build a UI to display the notification payload after it is received. ## Prerequisites To use this feature, you'll need to complete the following: - [Integrate the Braze Android SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android) - [Set up push notifications for the Braze Android SDK](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/?tab=android) ## Setting up push notifications To set up push notifications for Android TV: 1. Create a custom view in your app to display your notifications. 2. Create a [custom notification factory](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/customization#customization-display). This will override the default SDK behavior and allow you to manually display the notifications. By returning `null`, this will prevent the SDK from processing and will require custom code to display the notification. After these steps have been completed, you can start sending push to Android TV!

3. (Optional) To track click analytics effectively, set up click analytics tracking. This can be achieved by creating a [push callback](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/customization#push-callback) to listen for Braze push opened and received intents. **Note:** These notifications **will not persist** and will only be visible to the user when the device displays them. This is due to Android TV's notification center not supporting historical notifications. ## Testing Android TV push notifications To test if your push implementation is successful, send a notification from the Braze dashboard as you would normally for an Android device. - **If the application is closed**: The push message will display a toast notification on the screen. - **If the application is open**: You have the opportunity to display the message in your own hosted UI. We recommend following the UI styling of our Android Mobile SDK in-app messages. ## Best practices For marketers using Braze, launching a campaign to Android TV will be identical to launching a push to Android mobile apps. To target these devices exclusively, we recommend selecting the Android TV App in segmentation. The delivered and clicked response returned by FCM will follow the same convention as a mobile Android device; therefore, any errors will be visible in the message activity log. ## Prerequisites Before you can use this feature, you'll need to [integrate the Cordova Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=cordova). After you integrate the SDK, basic push notification functionality is enabled by default. To use [rich push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/rich/?sdktab=cordova) and [push stories](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/push_stories/?sdktab=cordova), you'll need to set them up individually. To use iOS push messages, you also need to upload a valid push certificate. **Warning:** Anytime you add, remove, or update your Cordova plugins, Cordova will overwrite the Podfile in your iOS app's Xcode project. This means you’ll need to set these features up again anytime you modify your Cordova plugins. ## Enabling push deep linking By default, the Braze Cordova SDK doesn't automatically handle deep links from push notifications. To enable push deep linking, follow the configuration steps in [Deep linking](https://www.braze.com/docs/ja/ja/developer_guide/cordova/deep_linking/). For more details about these and other push configuration options, see [Optional configurations](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=cordova#optional). ## Disabling basic push notifications (iOS only) After you integrate the Braze Cordova SDK for iOS, basic push notification functionality is enabled by default. To disable this functionality in your iOS app, add the following to your `config.xml` file. For more information, see [Optional configurations](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=cordova#optional). ```xml ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Flutter Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=flutter). ## Setting up push notifications ### Step 1: Complete the initial setup #### Step 1.1: Register for push Register for push using Google’s Firebase Cloud Messaging (FCM) API. For a full walkthrough, refer to the following steps from the [Native Android push integration guide](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/?tab=android/): 1. [Add Firebase to your project](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#step-1-add-firebase-to-your-project). 2. [Add Cloud Messaging to your dependencies](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#step-2-add-cloud-messaging-to-your-dependencies). 3. [Create a service account](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#step-3-create-a-service-account). 4. [Generate JSON credentials](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#step-4-generate-json-credentials). 5. [Upload your JSON credentials to Braze](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#step-5-upload-your-json-credentials-to-braze). #### Step 1.2: Get your Google Sender ID First, go to Firebase Console, open your project, then select  **Settings** > **Project settings**. ![The Firebase project with the "Settings" menu open.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/set_up_automatic_token_registration/select-project-settings.png?9f5e0865e0fb698d08b31cc74069c256) Select **Cloud Messaging**, then under **Firebase Cloud Messaging API (V1)**, copy the **Sender ID** to your clipboard. ![The Firebase project's "Cloud Messaging" page with the "Sender ID" highlighted.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/set_up_automatic_token_registration/copy-sender-id.png?f27e894f55060ddb1e698581ed8bb912) #### Step 1.3: Update your `braze.xml` Add the following to your `braze.xml` file. Replace `FIREBASE_SENDER_ID` with the sender ID you copied previously. ```xml true FIREBASE_SENDER_ID ``` #### Step 1.1: Upload APNs certificates Generate an Apple Push Notification service (APNs) certificate and uploaded it to the Braze dashboard. For a full walkthrough, see [Uploading your APNs certificate](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/#step-1-upload-your-apns-certificate). #### Step 1.2: Add push notification support to your app Follow the [native iOS integration guide](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/?tab=objective-c#automatic-push-integration). ### Step 2: Listen for push notification events (optional) To listen for push notification events that Braze has detected and handled, call `subscribeToPushNotificationEvents()` and pass in an argument to execute. **Note:** Braze push notification events are available on both Android and iOS. Due to platform differences, iOS will only detect Braze push events when a user has interacted with a notification. ```dart // Create stream subscription StreamSubscription pushEventsStreamSubscription; pushEventsStreamSubscription = braze.subscribeToPushNotificationEvents((BrazePushEvent pushEvent) { print("Push Notification event of type ${pushEvent.payloadType} seen. Title ${pushEvent.title}\n and deeplink ${pushEvent.url}"); // Handle push notification events }); // Cancel stream subscription pushEventsStreamSubscription.cancel(); ``` ##### Push notification event fields **Note:** Because of platform limitations on iOS, the Braze SDK can only process push payloads while the app is in the foreground. Listeners will only trigger for the `push_opened` event type on iOS after a user has interacted with a push. For a full list of push notification fields, refer to the table below: | Field Name | Type | Description | | ------------------ | --------- | ----------- | | `payloadType` | String | Specifies the notification payload type. The two values that are sent from the Braze Flutter SDK are `push_opened` and `push_received`. Only `push_opened` events are supported on iOS. | | `url` | String | Specifies the URL that was opened by the notification. | | `useWebview` | Boolean | If `true`, URL will open in-app in a modal webview. If `false`, the URL will open in the device browser. | | `title` | String | Represents the title of the notification. | | `body` | String | Represents the body or content text of the notification. | | `summaryText` | String | Represents the summary text of the notification. This is mapped from `subtitle` on iOS. | | `badgeCount` | Number | Represents the badge count of the notification. | | `timestamp` | Number | Represents the time at which the payload was received by the application. | | `isSilent` | Boolean | If `true`, the payload is received silently. For details on sending Android silent push notifications, refer to [Silent push notifications on Android](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent/?sdktab=android). For details on sending iOS silent push notifications, refer to [Silent push notifications on iOS](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent/?sdktab=swift). | | `isBrazeInternal`| Boolean | This will be `true` if a notification payload was sent for an internal SDK feature, such as Feature Flag sync or uninstall tracking. The payload is received silently for the user. | | `imageUrl` | String | Specifies the URL associated with the notification image. | | `brazeProperties` | Object | Represents Braze properties associated with the campaign (key-value pairs). | | `ios` | Object | Represents iOS-specific fields. | | `android` | Object | Represents Android-specific fields. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Push notification event fields" } ### Step 3: Test displaying push notifications To test your integration after configuring push notifications in the native layer: 1. Set an active user in the Flutter application. To do so, initialize your plugin by calling `braze.changeUser('your-user-id')`. 2. Head to **Campaigns** and create a new push notification campaign. Choose the platforms that you'd like to test. 3. Compose your test notification and head over to the **Test** tab. Add the same `user-id` as the test user and click **Send Test**. 4. You should receive the notification on your device shortly. You may need to check in the Notification Center or update Settings if it doesn't display. **Tip:** Starting with Xcode 14, you can test remote push notifications on an iOS simulator. ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Setting up push notifications Newer phones manufactured by [Huawei](https://huaweimobileservices.com/) come equipped with Huawei Mobile Services (HMS) - a service used to deliver push instead of Google's Firebase Cloud Messaging (FCM). ### Step 1: Register for a Huawei developer account Before getting started, you'll need to register and set up a [Huawei Developer account](https://developer.huawei.com/consumer/en/console). In your Huawei account, go to **My Projects > Project Settings > App Information**, and take note of the `App ID` and `App secret`. ![](https://www.braze.com/docs/ja/ja/assets/img/huawei/huawei-credentials.png?b06eeb235330781a1d837e9d2d1733b7) ### Step 2: Create a new Huawei app in the Braze dashboard In the Braze dashboard, go to **App Settings**, listed under the **Settings** navigation. Click **+ Add App**, provide a name (such as My Huawei App), select `Android` as the platform. ![](https://www.braze.com/docs/ja/ja/assets/img/huawei/huawei-create-app.png?a6844b04811452719ae57875b2eb1261){: style="max-width:60%;"} Once your new Braze app has been created, locate the push notification settings and select `Huawei` as the push provider. Next, provide your `Huawei Client Secret` and `Huawei App ID`. ![](https://www.braze.com/docs/ja/ja/assets/img/huawei/huawei-dashboard-credentials.png?c91a9f413f10a2ef3043876640b61dac) ### Step 3: Integrate the Huawei messaging SDK into your app Huawei has provided an [Android integration codelab](https://developer.huawei.com/consumer/en/codelab/HMSPushKit/index.html) detailing integrating the Huawei Messaging Service into your application. Follow those steps to get started. After completing the codelab, you will need to create a custom [Huawei Message Service](https://developer.huawei.com/consumer/en/doc/development/HMS-References/push-HmsMessageService-cls) to obtain push tokens and forward messages to the Braze SDK. ```java public class CustomPushService extends HmsMessageService { @Override public void onNewToken(String token) { super.onNewToken(token); Braze.getInstance(this.getApplicationContext()).setRegisteredPushToken(token); } @Override public void onMessageReceived(RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); if (BrazeHuaweiPushHandler.handleHmsRemoteMessageData(this.getApplicationContext(), remoteMessage.getDataOfMap())) { // Braze has handled the Huawei push notification } } } ``` ```kotlin class CustomPushService: HmsMessageService() { override fun onNewToken(token: String?) { super.onNewToken(token) Braze.getInstance(applicationContext).setRegisteredPushToken(token!!) } override fun onMessageReceived(hmsRemoteMessage: RemoteMessage?) { super.onMessageReceived(hmsRemoteMessage) if (BrazeHuaweiPushHandler.handleHmsRemoteMessageData(applicationContext, hmsRemoteMessage?.dataOfMap)) { // Braze has handled the Huawei push notification } } } ``` After adding your custom push service, add the following to your `AndroidManifest.xml`: ```xml ``` ### Step 4: Handle foreground notifications By default, when a push notification arrives while your app is in the foreground, Huawei displays it automatically. To have Braze process the push notification payload (for analytics tracking, deep link handling, and custom processing), route the incoming push data to Braze inside your `HmsMessageService.onMessageReceived` method. When you call `BrazeHuaweiPushHandler.handleHmsRemoteMessageData`, Braze determines if the payload is a Braze push notification and, if so, creates and displays the notification. For more information, see [Handling foreground notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=android#handling-foreground-notifications) in the Android push notifications documentation. For a complete example, see the [Huawei handler reference](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.push/-braze-huawei-push-handler/index.html) in the Braze Android SDK documentation. ### Step 5: Test your push notifications (optional) At this point, you've created a new Huawei Android app in the Braze dashboard, configured it with your Huawei developer credentials, and have integrated the Braze and Huawei SDKs into your app. Next, we can test out the integration by testing a new push campaign in Braze. #### Step 5.1: Create a new push notification campaign In the **Campaigns** page, create a new campaign, and choose **Push Notification** as your message type. After you name your campaign, choose **Android Push** as the push platform. ![The campaign creation composer displaying the available push platforms.](https://www.braze.com/docs/ja/ja/assets/img/huawei/huawei-test-push-platforms.png?8e7eecaa5984912c2a042862716c2398) Next, compose your push campaign with a title and message. #### Step 5.2: Send a test push In the **Test** tab, enter your user ID, which you've set in your app using the [`changeUser(USER_ID_STRING)` method](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/analytics/setting_user_ids/#assigning-a-user-id), and click **Send Test** to send a test push. ![The test tab in the campaign creation composer shows you can send a test message to yourself by providing your user ID and entering it into the "Add Individual Users" field.](https://www.braze.com/docs/ja/ja/assets/img/huawei/huawei-test-send.png?42dce83b469c90564ae79d3f4d37c572) At this point, you should receive a test push notification on your Huawei (HMS) device from Braze. #### Step 5.3: Set up Huawei segmentation (optional) Since your Huawei app in the Braze dashboard is built upon the Android push platform, you have the flexibility to send push to all Android users (Firebase Cloud Messaging and Huawei Mobile Services), or you can choose to segment your campaign audience to specific apps. To send push to only Huawei apps, [create a new Segment](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/segments/creating_a_segment/#step-3-choose-your-app-or-platform) and select your Huawei App within the **Apps** section. ![](https://www.braze.com/docs/ja/ja/assets/img/huawei/huawei-segmentation.png?3e7b24b199a37e61f4606496cda6f982) Of course, if you want to send the same push to all Android push providers, you can choose not to specify the app which will send to all Android apps configured within the current workspace. ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Setting up push notifications {#setting-up-push-notifications} ### Step 1: Complete the initial setup #### Prerequisites Before you can use Expo for push notifications, you'll need to [set up the Braze Expo plugin](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/react_native/sdk_integration/?tab=expo). #### Step 1.1: Update your `app.json` file Next update your `app.json` file for Android and iOS: - **Android:** Add the `enableFirebaseCloudMessaging` option. - **iOS:** Add the `enableBrazeIosPush` option. #### Step 1.2: Add your Google Sender ID First, go to Firebase Console, open your project, then select  **Settings** > **Project settings**. ![The Firebase project with the "Settings" menu open.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/set_up_automatic_token_registration/select-project-settings.png?9f5e0865e0fb698d08b31cc74069c256) Select **Cloud Messaging**, then under **Firebase Cloud Messaging API (V1)**, copy the **Sender ID** to your clipboard. ![The Firebase project's "Cloud Messaging" page with the "Sender ID" highlighted.](https://www.braze.com/docs/ja/ja/assets/img/android/push_integration/set_up_automatic_token_registration/copy-sender-id.png?f27e894f55060ddb1e698581ed8bb912) Next, open your project's `app.json` file and set your `firebaseCloudMessagingSenderId` property to the Sender ID in your clipboard. For example: ``` "firebaseCloudMessagingSenderId": "693679403398" ``` #### Step 1.3: Add the path to your Google Services JSON In your project's `app.json` file, add the path to your `google-services.json` file. This file is required when setting `enableFirebaseCloudMessaging: true` in your configuration. ```json { "expo": { "android": { "googleServicesFile": "PATH_TO_GOOGLE_SERVICES" }, "plugins": [ [ "@braze/expo-plugin", { "androidApiKey": "YOUR-ANDROID-API-KEY", "iosApiKey": "YOUR-IOS-API-KEY", "enableBrazeIosPush": true, "enableFirebaseCloudMessaging": true, "firebaseCloudMessagingSenderId": "YOUR-FCM-SENDER-ID", "androidHandlePushDeepLinksAutomatically": true } ], ] } } ``` Note that you will need to use these settings instead of the native setup instructions if you are depending on additional push notification libraries like [Expo Notifications](https://docs.expo.dev/versions/latest/sdk/notifications/). If you are not using the Braze Expo plugin, or would like to configure these settings natively instead, register for push by referring to the [Native Android push integration guide](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/?tab=android/). If you are not using the Braze Expo plugin, or would like to configure these settings natively instead, register for push by referring to the following steps from the [Native iOS push integration guide](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift): #### Step 1.1: Request for push permissions If you don't plan on requesting push permissions when the app is launched, omit the `requestAuthorizationWithOptions:completionHandler:` call in your AppDelegate. Then, skip to [Step 2](#reactnative_step-2-request-push-notifications-permission). Otherwise, follow the [native iOS integration guide](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/?tab=objective-c#automatic-push-integration). #### Step 1.2 (Optional): Migrate your push key If you were previously using `expo-notifications` to manage your push key, run `expo fetch:ios:certs` from your application's root folder. This will download your push key (a .p8 file), which can then be uploaded to the Braze dashboard. ### Step 2: Request push notifications permission Use the `Braze.requestPushPermission()` method (available on v1.38.0 and up) to request permission for push notifications from the user on iOS and Android 13+. For Android 12 and below, this method is a no-op. This method takes in a required parameter that specifies which permissions the SDK should request from the user on iOS. These options have no effect on Android. ```javascript const permissionOptions = { alert: true, sound: true, badge: true, provisional: false }; Braze.requestPushPermission(permissionOptions); ``` #### Step 2.1: Listen for push notifications (optional) You can additionally subscribe to events where Braze has detected and handled an incoming push notification. Use the listener key `Braze.Events.PUSH_NOTIFICATION_EVENT`. **Important:** iOS push received events will only trigger for foreground notifications and `content-available` background notifications. It will not trigger for notifications received while terminated or for background notifications without the `content-available` field. ```javascript Braze.addListener(Braze.Events.PUSH_NOTIFICATION_EVENT, data => { console.log(`Push Notification event of type ${data.payload_type} seen. Title ${data.title}\n and deeplink ${data.url}`); console.log(JSON.stringify(data, undefined, 2)); }); ``` ##### Push notification event fields For a full list of push notification fields, refer to the table below: | Field Name | Type | Description | | ------------------ | --------- | ----------- | | `payload_type` | String | Specifies the notification payload type. The two values that are sent from the Braze React Native SDK are `push_opened` and `push_received`. | | `url` | String | Specifies the URL that was opened by the notification. | | `use_webview` | Boolean | If `true`, URL will open in-app in a modal webview. If `false`, the URL will open in the device browser. | | `title` | String | Represents the title of the notification. | | `body` | String | Represents the body or content text of the notification. | | `summary_text` | String | Represents the summary text of the notification. This is mapped from `subtitle` on iOS. | | `badge_count` | Number | Represents the badge count of the notification. | | `timestamp` | Number | Represents the time at which the payload was received by the application. | | `is_silent` | Boolean | If `true`, the payload is received silently. For details on sending Android silent push notifications, refer to [Silent push notifications on Android](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent/?sdktab=android). For details on sending iOS silent push notifications, refer to [Silent push notifications on iOS](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent/?sdktab=swift). | | `is_braze_internal`| Boolean | This will be `true` if a notification payload was sent for an internal SDK feature, such as Feature Flag sync or uninstall tracking. The payload is received silently for the user. | | `image_url` | String | Specifies the URL associated with the notification image. | | `braze_properties` | Object | Represents Braze properties associated with the campaign (key-value pairs). | | `ios` | Object | Represents iOS-specific fields. | | `android` | Object | Represents Android-specific fields. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Push notification event fields" } ### Step 3: Enable deep linking (optional) To enable Braze to handle deep links inside React components when a push notification is clicked, first implement the steps described in [React Native Linking](https://reactnative.dev/docs/linking) library, or with your solution of choice. Then, follow the additional steps below. To learn more about what deep links are, see our [FAQ article](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize/actions_and_media_urls/#what-is-deep-linking). **Important:** If you're migrating an existing React Native push integration, re-test deep linking after you upgrade the Braze SDK, React Native, Expo, or related libraries. Confirm that: - [React Native Linking](https://reactnative.dev/docs/linking) is still configured and handling your deep link URLs. - Your iOS initial push payload handling (see [Step 3.1: Store the push notification payload on app launch](#step-3-1)) is implemented and still called on app launch. - Any native delegate or listener methods you use to handle push click events are still registered and invoked as expected. If you're using the [Braze Expo plugin](https://www.braze.com/docs/ja/ja/developer_guide/platforms/react_native/sdk_integration/?tab=expo#step-2-choose-a-setup-option), you can handle push notification deep links automatically by setting `androidHandlePushDeepLinksAutomatically` to `true` in your `app.json`. To handle deep links manually instead, refer to the native Android documentation: [Adding deep links](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking). #### Step 3.1: Store the push notification payload on app launch **Note:** This is supported as of React Native SDK 19.1.0. Add `populateInitialPushPayloadFromIntent` to your main activity's `onCreate()` method. This must be called before React Native initializes to capture the initial Intent data. For example: ```kotlin override fun onCreate(savedInstanceState: Bundle?) { BrazeReactUtils.populateInitialPushPayloadFromIntent(intent) super.onCreate(savedInstanceState) } ``` #### Step 3.2: Handle deep links from a closed state In addition to the base scenarios handled by [React Native Linking](https://reactnative.dev/docs/linking), implement the `Braze.getInitialPushPayload` method and retrieve the `url` value to account for deep links from push notifications that open your app when it isn't running. For example: ```javascript // Handles deep links when an app is launched from a hard close via push click. Braze.getInitialPushPayload(pushPayload => { if (pushPayload) { console.log('Braze.getInitialPushPayload is ' + pushPayload); showToast('Initial URL is ' + pushPayload.url); handleOpenUrl({ pushPayload.url }); } }); ``` **Note:** This method requires the native setup in Step 3.1 for your platform. If you're using the Braze Expo plugin, this may be handled automatically. **Important:** To handle deep links from push notifications on iOS, you must also configure link handling in your native iOS layer. This includes registering a custom URL scheme and implementing a URL handler in your `AppDelegate`. For full setup instructions, see [Handling deep links](https://www.braze.com/docs/ja/ja/developer_guide/platforms/swift/in_app_messages/deep_linking/?tab=objective-c) in the native iOS documentation. #### Step 3.1: Store the push notification payload on app launch {#step-3-1} **Note:** Skip step 3.1 if you're using the Braze Expo plugin, as this functionality is handled automatically. For iOS, add `populateInitialPayloadFromLaunchOptions` to your AppDelegate's `didFinishLaunchingWithOptions` method. For example: ```objc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ... Perform regular React Native setup BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:apiKey endpoint:endpoint]; configuration.triggerMinimumTimeInterval = 1; configuration.logger.level = BRZLoggerLevelInfo; Braze *braze = [BrazeReactBridge initBraze:configuration]; AppDelegate.braze = braze; [self registerForPushNotifications]; [[BrazeReactUtils sharedInstance] populateInitialPayloadFromLaunchOptions:launchOptions]; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } ``` ```swift func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { // ... Perform regular React Native setup let configuration = Braze.Configuration(apiKey: apiKey, endpoint: endpoint) configuration.triggerMinimumTimeInterval = 1 configuration.logger.level = .info let braze = BrazeReactBridge.initBraze(configuration) AppDelegate.braze = braze registerForPushNotifications() BrazeReactUtils.shared().populateInitialPayload(fromLaunchOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } ``` #### Step 3.2: Handle deep links from a closed state In addition to the base scenarios handled by [React Native Linking](https://reactnative.dev/docs/linking), implement the `Braze.getInitialPushPayload` method and retrieve the `url` value to account for deep links from push notifications that open your app when it isn't running. For example: ```javascript // Handles deep links when an app is launched from a hard close via push click. Braze.getInitialPushPayload(pushPayload => { if (pushPayload) { console.log('Braze.getInitialPushPayload is ' + pushPayload); showToast('Initial URL is ' + pushPayload.url); handleOpenUrl({ pushPayload.url }); } }); ``` **Note:** This method requires the native setup in Step 3.1 for your platform. If you're using the Braze Expo plugin, this may be handled automatically. #### Step 3.3: Enable Universal Links (optional) To enable [universal linking](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking/?sdktab=swift#universal-links) support, implement a Braze delegate that determines whether to open a given URL, then register it with your Braze instance. Create a `BrazeReactDelegate.swift` file in your `iOS` directory and add the following. Replace `YOUR_DOMAIN_HOST` with your actual domain. ```swift import Foundation import BrazeKit import UIKit class BrazeReactDelegate: NSObject, BrazeDelegate { /// This delegate method determines whether to open a given URL. /// Reference the context to get additional details about the URL payload. func braze(_ braze: Braze, shouldOpenURL context: Braze.URLContext) -> Bool { if let host = context.url.host, host.caseInsensitiveCompare("YOUR_DOMAIN_HOST") == .orderedSame { // Sample custom handling of universal links let application = UIApplication.shared let userActivity = NSUserActivity(activityType: NSUserActivityTypeBrowsingWeb) userActivity.webpageURL = context.url // Routes to the `continueUserActivity` method, which should be handled in your AppDelegate. application.delegate?.application?( application, continue: userActivity, restorationHandler: { _ in } ) return false } // Let Braze handle links otherwise return true } } ``` Then, create and register your `BrazeReactDelegate` in `didFinishLaunchingWithOptions` of your project's `AppDelegate.swift` file. ```swift import BrazeKit class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? // Keep a strong reference to the BrazeDelegate so it is not deallocated. private var brazeDelegate: BrazeReactDelegate? func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { // Other setup code (e.g., Braze initialization) brazeDelegate = BrazeReactDelegate() AppDelegate.braze?.delegate = brazeDelegate return true } } ``` Create a `BrazeReactDelegate.h` file in your `iOS` directory and then add the following code snippet. ```objc #import #import @interface BrazeReactDelegate: NSObject @end ``` Next, create a `BrazeReactDelegate.m` file and then add the following code snippet. Replace `YOUR_DOMAIN_HOST` with your actual domain. ```objc #import "BrazeReactDelegate.h" #import @implementation BrazeReactDelegate /// This delegate method determines whether to open a given URL. /// /// Reference the `BRZURLContext` object to get additional details about the URL payload. - (BOOL)braze:(Braze *)braze shouldOpenURL:(BRZURLContext *)context { if ([[context.url.host lowercaseString] isEqualToString:@"YOUR_DOMAIN_HOST"]) { // Sample custom handling of universal links UIApplication *application = UIApplication.sharedApplication; NSUserActivity* userActivity = [[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb]; userActivity.webpageURL = context.url; // Routes to the `continueUserActivity` method, which should be handled in your `AppDelegate`. [application.delegate application:application continueUserActivity:userActivity restorationHandler:^(NSArray> * _Nullable restorableObjects) {}]; return NO; } // Let Braze handle links otherwise return YES; } @end ``` Then, create and register your `BrazeReactDelegate` in `didFinishLaunchingWithOptions` of your project's `AppDelegate.m` file. ```objc #import "BrazeReactUtils.h" #import "BrazeReactDelegate.h" @interface AppDelegate () // Keep a strong reference to the BrazeDelegate to ensure it is not deallocated. @property (nonatomic, strong) BrazeReactDelegate *brazeDelegate; @end - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Other setup code self.brazeDelegate = [[BrazeReactDelegate alloc] init]; braze.delegate = self.brazeDelegate; } ``` For an example integration, reference our sample app [here](https://github.com/braze-inc/braze-react-native-sdk/blob/master/BrazeProject/ios/BrazeProject/AppDelegate.mm). ### Step 4: Handle foreground notifications Foreground notification handling works differently depending on your platform and setup. Choose the approach that matches your integration: For iOS, foreground notification handling is the same as the native Swift integration. Call `handleForegroundNotification(notification:)` inside your `UNUserNotificationCenterDelegate.userNotificationCenter(_:willPresent:withCompletionHandler:)` implementation. For complete details and code examples, see [Handling foreground notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift#handling-foreground-notifications) in the Swift push notifications documentation. For Android, foreground notification handling is the same as the native Android integration. Call `BrazeFirebaseMessagingService.handleBrazeRemoteMessage` inside your `FirebaseMessagingService.onMessageReceived` method. For complete details and code examples, see [Handling foreground notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=android#handling-foreground-notifications) in the Android push notifications documentation. In Expo-managed workflow, you don't call native notification handlers directly. Instead, use the Expo Notifications API to control foreground presentation, while the Braze Expo Plugin handles native processing automatically. ```javascript import * as Notifications from 'expo-notifications'; import Braze from '@braze/react-native-sdk'; // Control foreground presentation in Expo Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: true, // Show alert while in foreground shouldPlaySound: false, shouldSetBadge: false, }), }); // React to Braze push events const subscription = Braze.addListener('pushNotificationEvent', (event) => { console.log('Braze push event', { type: event.payload_type, // "push_received" | "push_opened" title: event.title, url: event.url, is_silent: event.is_silent, }); // Handle deep links, custom behavior, etc. }); // Handle initial payload when app launches via push Braze.getInitialPushPayload((payload) => { if (payload) { console.log('Initial push payload', payload); } }); ``` **Note:** In Expo-managed workflow, the Braze Expo Plugin handles native push processing automatically. You control foreground UI via the Expo Notifications presentation options shown above. For bare workflow integrations, follow the native iOS and Android approaches instead. ### Step 5: Send a test push notification At this point, you should be able to send notifications to the devices. Adhere to the following steps to test your push integration. **Note:** Starting in macOS 13, on certain devices, you can test iOS push notifications on an iOS 16+ simulator running on Xcode 14 or higher. For further details, refer to the [Xcode 14 Release Notes](https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes). 1. Set an active user in the React Native application by calling `Braze.changeUserId('your-user-id')` method. 2. Head to **Campaigns** and create a new push notification campaign. Choose the platforms that you'd like to test. 3. Compose your test notification and head over to the **Test** tab. Add the same `user-id` as the test user and click **Send Test**. You should receive the notification on your device shortly. ![A Braze push campaign showing you can add your own user ID as a test recipient to test your push notification.](https://www.braze.com/docs/ja/ja/assets/img/react-native/push-notification-test.png?567f5b19e26e7493613a19f9d1204549 "Push Campaign Test") ## Using the Expo plugin After you [set up push notifications for Expo](#reactnative_setting-up-push-notifications), you can use it to handle the following push notifications behaviors—without needing to write any code in the native Android or iOS layers. ### Forwarding Android push to additional FMS If you want to use an additional Firebase Messaging Service (FMS), you can specify a fallback FMS to call if your application receives a push that isn't from Braze. For example: ```json { "expo": { "plugins": [ [ "@braze/expo-plugin", { ... "androidFirebaseMessagingFallbackServiceEnabled": true, "androidFirebaseMessagingFallbackServiceClasspath": "com.company.OurFirebaseMessagingService" } ] ] } } ``` ### Using app extensions with Expo Application Services {#app-extensions} If you are using Expo Application Services (EAS) and have enabled `enableBrazeIosRichPush` or `enableBrazeIosPushStories`, you will need to declare the corresponding bundle identifiers for each app extension in your project. There are multiple ways you can approach this step, depending on how your project is configured to manage code signing with EAS. One approach is to use the `appExtensions` configuration in your `app.json` file by following Expo's [app extensions documentation](https://docs.expo.dev/build-reference/app-extensions/). Alternatively, you can set up the `multitarget` setting in your `credentials.json` file by following Expo's [local credentials documentation](https://docs.expo.dev/app-signing/local-credentials/#multi-target-project). ### Troubleshooting These are common troubleshooting steps for push notification integrations with the Braze React Native SDK and Expo plugin. #### Push notifications stopped working {#troubleshooting-stopped-working} If push notifications through the Expo plugin have stopped working: 1. Check that the Braze SDK is still tracking sessions. 2. Check that the SDK wasn't disabled by an explicit or implicit call to `wipeData`. 3. Review any recent upgrades to Expo or it's related libraries, as there may be conflicts with your Braze configuration. 4. Review recently added project dependencies and check if they are manually overriding your existing push notification delegate methods. **Tip:** For iOS integrations, you can also reference our [push notification setup tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b1-standard-push-notifications) to help you identify potential conflicts with your project dependencies. #### Device token won't register with Braze {#troubleshooting-token-registration} If your device token won't register with Braze, first review [Push notifications stopped working](#troubleshooting-stopped-working). If your issue persists, there may be a separate dependency interfering with your Braze push notification configuration. You can try removing it or manually call `Braze.registerPushToken` instead. #### Deep links from push notifications don't open {#troubleshooting-deep-links} If deep links from push notifications stop opening after a migration, check the following: 1. Verify your [React Native Linking](https://reactnative.dev/docs/linking) setup is still valid in your upgraded app. 2. For iOS native integrations, confirm you implemented `populateInitialPayloadFromLaunchOptions` and `Braze.getInitialPushPayload` so that, when the app is launched from a terminated state, it can retrieve the initial push payload and pass its `url` into your deep link handler. 3. If you're using the Braze Expo plugin, verify `androidHandlePushDeepLinksAutomatically` is set correctly for your implementation. 4. Review recently added dependencies for overrides to notification handling or app delegate behavior. If you've completed these checks and the issue persists, [open a support ticket](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/support/) and include SDK logs plus reproduction steps. ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=web) for the Web SDK. Note that you can only send push notifications to iOS and iPadOS users that are using [Safari v16.4](https://developer.apple.com/documentation/safari-release-notes/safari-16_4-release-notes) or later. ## Setting up Safari push for mobile ### Step 1: Create a manifest file {#manifest} A [Web Application Manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) is a JSON file that controls how your website is presented when installed to a user's home screen. For example, you can set the background theme color and icon that the [App Switcher](https://support.apple.com/en-us/HT202070) uses, whether it renders as full screen to resemble a native app, or whether the app should open in landscape or portrait mode. Create a new `manifest.json` file in your website's root directory, with the following mandatory fields. ```json { "name": "your app name", "short_name": "your app name", "display": "fullscreen", "icons": [{ "src": "favicon.ico", "sizes": "128x128", }] } ``` The full list of supported fields can be found [here](https://developer.mozilla.org/en-US/docs/Web/Manifest). ### Step 2: Link the manifest file {#manifest-link} Add the following `` tag to your website's `` element pointing to where your manifest file is hosted. ```html ``` ### Step 3: Add a service worker {#service-worker} Your website must have a service worker file that imports the Braze service-worker library, as described in our [web push integration guide](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/push_notifications/integration/#step-1-configure-your-sites-service-worker). ### Step 4: Add to home screen {#add-to-homescreen} Popular browsers (such as Safari, Chrome, FireFox, and Edge) all support web push notifications in their later versions. To request push permission on iOS or iPadOS, your website must be added to the user's home screen by selecting **Share To** > **Add to Home Screen**. [Add to Homescreen](https://support.apple.com/guide/iphone/bookmark-favorite-webpages-iph42ab2f3a7/ios#iph4f9a47bbc) lets users bookmark your website, adding your icon to their valuable home screen real estate. ![An iPhone showing options to bookmark a website and save to the home screen](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/add-to-homescreen.png?f05fb625cce85d8d4b4816deae375bf8){: style="max-width:40%"} ### Step 5: Show the native push prompt {#push-prompt} After the app has been added to your home screen you can now request push permission when the user takes an action (such as clicking a button). This can be done using the [`requestPushPermission`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#requestpushpermission) method, or with a [no-code push primer in-app message](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/best_practices/push_primer_messages/). **Note:** After you accept or decline the prompt, you need to delete and reinstall the website to your home screen to be able to show the prompt again. ![A push prompt asking to "allow" or "don't allow" Notifications](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/safari-mobile-push-prompt.png?f6652f453a2f06d6b173c92d3cd85dc1){: style="max-width:40%"} For example: ```typescript import { requestPushPermission } from "@braze/web-sdk"; button.onclick = function(){ requestPushPermission(() => { console.log(`User accepted push prompt`); }, (temporary) => { console.log(`User ${temporary ? "temporarily dismissed" : "permanently denied"} push prompt`); }); }; ``` ## Next steps Next, send yourself a [test message](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/sending_test_messages/) to validate the integration. After your integration is complete, you can use our [no-code push primer messages](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/best_practices/push_primer_messages/) to optimize your push opt-in rates. ## Prerequisites Before you can use this feature, you'll need to [integrate the Unity Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=unity). ## Setting up push notification ### Step 1: Set up the platform #### Step 1.1: Enable Firebase To get started, follow the [Firebase Unity setup documentation](https://firebase.google.com/docs/unity/setup). **Note:** Integrating the Firebase Unity SDK may cause your `AndroidManifest.xml` to be overridden. If that occurs, make sure to revert it to the original. #### Step 1.2: Set your Firebase credentials You need to input your Firebase Server Key and Sender ID into the Braze dashboard. To do this, log in to the [Firebase Developers Console](https://console.firebase.google.com/) and select your Firebase project. Next, select **Cloud Messaging** under **Settings** and copy the Server Key and Sender ID:
![](https://www.braze.com/docs/ja/ja/assets/img_archive/finding_firebase_server_key.png?de34d7ce2b1ae4b9c4a9d543b5b40585 "FirebaseServerKey") In Braze, select your Android app on the **App Settings** page under **Manage Settings**. Next, enter your Firebase Server Key in the **Firebase Cloud Messaging Server Key** field and Firebase Sender ID in the **Firebase Cloud Messaging Sender** ID field. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/fcm_api_insert.png?f02bb98f5a702d5268f5ddaeee0c27cc "FCMKey") #### Step 1.1: Verify integration method Braze provides a native Unity solution for automating iOS push integrations. If you you'd like to set up and manage your integration manually instead, see [Swift: Push Notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift). Otherwise, continue to the next step. **Note:** Our automatic push notification solution takes advantage of iOS 12's Provisional Authorization feature and is not available to use with the native push prompt pop-up. #### Step 1.1: Enable ADM 1. Create an account with the [Amazon Apps & Games Developer Portal](https://developer.amazon.com/public) if you have not already done so. 2. Obtain [OAuth credentials (Client ID and Client Secret) and an ADM API key](https://developer.amazon.com/public/apis/engage/device-messaging/tech-docs/02-obtaining-adm-credentials). 3. Enable **Automatic ADM Registration Enabled** in the Unity Braze Configuration window. - Alternatively, you may add the following line to your `res/values/braze.xml` file to enable ADM registration: ```xml true ``` ### Step 2: Configure push notifications #### Step 2.1: Configure push settings {#unity_step-21-configure-push-settings} The Braze SDK can automatically handle push registration with the Firebase Cloud Messaging Servers to have devices receive push notifications. In Unity, enable **Automate Unity Android Integration**, then configure the following **Push Notification** settings. | Setting | Description | |----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| | Automatic Firebase Cloud Messaging Registration Enabled | Instructs the Braze SDK to automatically retrieve and send an FCM push token for a device. | | Firebase Cloud Messaging Sender ID | The Sender ID from your Firebase console. | | Handle Push Deeplinks Automatically | Whether the SDK should handle opening deep links or opening the app when push notifications are clicked. | | Small Notification Icon Drawable | Android drawable resource reference for the small icon shown when a push arrives. Enter the full reference including the `@drawable/` prefix (for example, `@drawable/hourglass_icon`). The automated integration writes this value into `braze.xml` as entered. If you leave this empty, the notification uses the application icon as the small icon. | | Large Notification Icon Drawable | Optional large icon for notifications. Use the same `@drawable/` format as the small icon (for example, `@drawable/my_large_icon`). | {: .reset-td-br-1 .reset-td-br-2 aria-label="Step 2.1: Configure push settings" } **Note:** **Small Notification Icon Drawable** and **Large Notification Icon Drawable** appear under **Push Configuration** in **Braze > Braze Configuration**. Both values are written into `braze.xml` as you enter them. Include the `@drawable/` prefix yourself—the Braze Unity integration does not add it for you (for example, `@drawable/hourglass_icon`). #### Step 2.1: Upload your APNs token Before you can send an iOS push notification using Braze, you need to upload your `.p8` push notification file, as described in [Apple's developer documentation](https://developer.apple.com/documentation/usernotifications/establishing-a-token-based-connection-to-apns): 1. In your Apple developer account, go to [**Certificates, Identifiers & Profiles**](https://developer.apple.com/account/ios/certificate). 2. Under **Keys**, select **All** and click the add button (+) in the upper-right corner. 3. Under **Key Description**, enter a unique name for the signing key. 4. Under **Key Services**, select the **Apple Push Notification service (APNs)** checkbox, then click **Continue**. Click **Confirm**. 5. Note the key ID. Click **Download** to generate and download the key. Make sure to save the downloaded file in a secure place, as you cannot download this more than once. 6. In Braze, go to **Settings** > **App Settings** and upload the `.p8` file under **Apple Push Certificate**. You can upload either your development or production push certificate. To test push notifications after your app is live in the App Store, its recommended to set up a separate workspace for the development version of your app. 7. When prompted, enter your app's [bundle ID](https://developer.apple.com/documentation/foundation/nsbundle/1418023-bundleidentifier), [key ID](https://developer.apple.com/help/account/manage-keys/get-a-key-identifier/), and [team ID](https://developer.apple.com/help/account/manage-your-team/locate-your-team-id). You'll also need to specify whether to send notifications to your app's development or production environment, which is defined by its provisioning profile. 8. When you're finished, select **Save**. #### Step 2.2: Enable automatic push Open the Braze Configuration Settings in the Unity Editor by navigating to **Braze > Braze Configuration**. Check **Integrate Push With Braze** to automatically register users for push notifications, pass push tokens to Braze, track analytics for push opens, and take advantage of our default push notification handling. #### Step 2.3: Enable background push (optional) Check **Enable Background Push** if you want to enable `background mode` for push notifications. This allows the system to wake your application from the `suspended` state when a push notification arrives, enabling your application to download content in response to push notifications. Checking this option is required for our uninstall tracking functionality. ![The Unity editor shows the Braze configuration options. In this editor, the "Automate Unity iOS integration", "Integrate push with braze", and "Enable background push" are enabled.](https://www.braze.com/docs/ja/ja/assets/img/unity/ios/unity_ios_enable_background.png?df3d5a5cc6379f663c3451fe060d71e6) #### Step 2.4: Disable automatic registration (optional) Users who have not yet opted-in to push notifications will automatically be authorized for push upon opening your application. To disable this feature and manually register users for push, check **Disable Automatic Push Registration**. - If **Disable Provisional Authorization** is not checked on iOS 12 or later, the user will be provisionally (silently) authorized to receive quiet push. If checked, the user will be shown the native push prompt. - If you need to configure exactly when the prompt is shown at runtime, disable automatic registration from the Braze configuration editor and use `AppboyBinding.PromptUserForPushPermissions()` instead. ![The Unity editor shows the Braze configuration options. In this editor, the "Automate Unity iOS integration", "integrate push with braze", and "disable automatic push registration" are enabled.](https://www.braze.com/docs/ja/ja/assets/img/unity/ios/unity_ios_disable_auto_push.png?9699a7386b70856be28344c6b6d884ee) #### Step 2.1: Update `AndroidManifest.xml` If your app does not have an `AndroidManifest.xml`, you can use the following as a template. Otherwise, if you already have an `AndroidManifest.xml`, ensure that any of the following missing sections are added to your existing `AndroidManifest.xml`. ```xml ``` #### Step 2.2: Store your ADM API key First, [generate an ADM API Key for your app](https://developer.amazon.com/public/apis/engage/device-messaging/tech-docs/02-obtaining-adm-credentials), then save the key to a file named `api_key.txt` and add it in your project's [`Assets/`](https://docs.unity3d.com/Manual/AndroidAARPlugins.html) directory. **Important:** Amazon will not recognize your key if `api_key.txt` contains any white space characters, such as a trailing line break. Next, in your `mainTemplate.gradle` file, add the following: ```gradle task copyAmazon(type: Copy) { def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/") from unityProjectPath + '/Assets/api_key.txt' into new File(projectDir, 'src/main/assets') } preBuild.dependsOn(copyAmazon) ``` #### Step 2.3: Add ADM Jar The required ADM Jar file may be placed anywhere in your project according to the [Unity JAR documentation](https://docs.unity3d.com/Manual/AndroidJARPlugins.html). #### Step 2.4: Add Client Secret and Client ID to your Braze dashboard Lastly, you must add the Client Secret and Client ID you obtained in [Step 1](#unity_step-1-enable-adm) to the Braze dashboard's **Manage Settings** page. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/fire_os_dashboard.png?725b1fd9d8208f4a861323e5fc16a376) ### Step 3: Set push listeners #### Step 3.1: Enable push received listener The push received listener is fired when a user receives a push notification. To send the push payload to Unity, set the name of your game object and push the received listener callback method under the **Set Push Received Listener**. #### Step 3.2: Enable push opened listener The push opened listener is fired when a user launches the app by clicking on a push notification. To send the push payload to Unity, set the name of your game object and push opened listener callback method under the **Set Push Opened Listener**. #### Step 3.3: Enable push deleted listener The push deleted listener is fired when a user swipes away or dismisses a push notification. To send the push payload to Unity, set the name of your game object and push deleted listener callback method under the **Set Push Deleted Listener**. #### Push listener example The following example implements the `BrazeCallback` game object using a callback method name of `PushNotificationReceivedCallback`, `PushNotificationOpenedCallback`, and `PushNotificationDeletedCallback` respectively. ![This implementation example graphic shows the Braze configuration options mentioned in the preceding sections and a C# code snippet.](https://www.braze.com/docs/ja/ja/assets/img/unity/android/unity_android_full_push_listener.png?c39b6b947880ebfe57b14dd66a2e6b73 "Android Full Listener Example") ```csharp public class MainMenu : MonoBehaviour { void PushNotificationReceivedCallback(string message) { #if UNITY_ANDROID Debug.Log("PushNotificationReceivedCallback message: " + message); PushNotification pushNotification = new PushNotification(message); Debug.Log("Push Notification received: " + pushNotification); #elif UNITY_IOS ApplePushNotification pushNotification = new ApplePushNotification(message); Debug.Log("Push received Notification event: " + pushNotification); #endif } void PushNotificationOpenedCallback(string message) { #if UNITY_ANDROID Debug.Log("PushNotificationOpenedCallback message: " + message); PushNotification pushNotification = new PushNotification(message); Debug.Log("Push Notification opened: " + pushNotification); #elif UNITY_IOS ApplePushNotification pushNotification = new ApplePushNotification(message); Debug.Log("Push opened Notification event: " + pushNotification); #endif } void PushNotificationDeletedCallback(string message) { #if UNITY_ANDROID Debug.Log("PushNotificationDeletedCallback message: " + message); PushNotification pushNotification = new PushNotification(message); Debug.Log("Push Notification dismissed: " + pushNotification); #endif } } ``` #### Step 3.1: Enable push received listener The push received listener is fired when a user receives a push notification while actively using the application (such as when the app is foregrounded). Set the push received listener in the Braze configuration editor. If you need to configure your game object listener at runtime, use `AppboyBinding.ConfigureListener()` and specify `BrazeUnityMessageType.PUSH_RECEIVED`. ![The Unity editor shows the Braze configuration options. In this editor, the "Set Push Received Listener" option is expanded, and the "Game Object Name" (AppBoyCallback) and "Callback Method Name" (PushNotificationReceivedCallback) are provided.](https://www.braze.com/docs/ja/ja/assets/img/unity/ios/unity_ios_push_received.png?c740dcf00019a0c74d243db9dfda0bfc) #### Step 3.2: Enable push opened listener The push opened listener is fired when a user launches the app by clicking on a push notification. To send the push payload to Unity, set the name of your game object and push opened listener callback method under the **Set Push Opened Listener** option: ![The Unity editor shows the Braze configuration options. In this editor, the "Set Push Received Listener" option is expanded, and the "Game Object Name" (AppBoyCallback) and "Callback Method Name" (PushNotificationOpenedCallback) are provided.](https://www.braze.com/docs/ja/ja/assets/img/unity/ios/unity_ios_push_opened.png?ac12ca0b1e4ab041389ac74ccac979c6) If you need to configure your game object listener at runtime, use `AppboyBinding.ConfigureListener()` and specify `BrazeUnityMessageType.PUSH_OPENED`. #### Push listener example The following example implements the `AppboyCallback` game object using a callback method name of `PushNotificationReceivedCallback` and `PushNotificationOpenedCallback`, respectively. ![This implementation example graphic shows the Braze configuration options mentioned in the preceding sections and a C# code snippet.](https://www.braze.com/docs/ja/ja/assets/img/unity/ios/unity_ios_appboy_callback.png?aae6baaf6053cd5ff3c6c512a94bfcfe) ```csharp public class MainMenu : MonoBehaviour { void PushNotificationReceivedCallback(string message) { #if UNITY_ANDROID Debug.Log("PushNotificationReceivedCallback message: " + message); PushNotification pushNotification = new PushNotification(message); Debug.Log("Push Notification received: " + pushNotification); #elif UNITY_IOS ApplePushNotification pushNotification = new ApplePushNotification(message); Debug.Log("Push received Notification event: " + pushNotification); #endif } void PushNotificationOpenedCallback(string message) { #if UNITY_ANDROID Debug.Log("PushNotificationOpenedCallback message: " + message); PushNotification pushNotification = new PushNotification(message); Debug.Log("Push Notification opened: " + pushNotification); #elif UNITY_IOS ApplePushNotification pushNotification = new ApplePushNotification(message); Debug.Log("Push opened Notification event: " + pushNotification); #endif } } ``` By updating your `AndroidManifest.xml` in the [previous step](#unity_step-21-update-androidmanifestxml), push listeners were automatically set up when you added the following lines. So, no further setup is required. ```xml ``` **Note:** To learn more about ADM push listeners, see [Amazon: Integrate Amazon Device Messaging](https://developer.amazon.com/docs/video-skills-fire-tv-apps/integrate-adm.html). ## Optional configurations #### Deep linking to in-app resources Although Braze can handle standard deep links (such as website URLs, Android URIs, etc.) by default, creating custom deep links requires an additional Manifest setup. For setup guidance, visit [Deep Linking to In-App Resources](https://developer.android.com/training/app-links/deep-linking). #### Adding Braze push notification icons **Important:** Do not add notification icon images under `Assets/Plugins/Android/res`. Unity [deprecated providing Android resources in that path](https://support.unity.com/hc/en-us/articles/115005875443-Providing-Android-resources-in-Assets-Plugins-Android-res-is-deprecated), which can surface build warnings or validation errors. Package your icon drawables in an [Android Archive (AAR) plug-in](https://docs.unity3d.com/Manual/AndroidAARPlugins.html) or Android library project instead so they merge into the built app's resources like any other drawable. To add push icons to your project, create an AAR plug-in or Android library that contains the icon image files under `res/drawable*` (or density-specific folders), then reference each icon in **Braze > Braze Configuration** using the full `@drawable/` resource name (see [Step 2.1: Configure push settings](#unity_step-21-configure-push-settings)). For Unity's packaging and import steps, see [Android Library Projects and Android Archive plug-ins](https://docs.unity3d.com/Manual/AndroidAARPlugins.html). For small icon artwork rules (alpha-only, no color), see [Android push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=android), Step 2: Conform small icons to design guidelines. #### Push token callback To receive a copy of Braze device tokens from the OS, set a delegate using `AppboyBinding.SetPushTokenReceivedFromSystemDelegate()`. There are no optional configurations for ADM at this time. ## Prerequisites Before you can use this feature, you'll need to [integrate the .NET MAUI Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=.net%20maui%20(xamarin)). ## Setting up push notifications **Tip:** To see how namespaces change between Java and C#, check out our [Xample sample app on GitHub](https://github.com/braze-inc/braze-xamarin-sdk/tree/master/appboy-component/samples/android-net-maui/BrazeAndroidMauiSampleApp/BrazeAndroidMauiSampleApp). To integrate push notifications for .NET MAUI (formerly Xamarin), you'll need to complete the steps for native Android push notifications. The following steps are only a summary. For a full walkthrough, see the [native push notification guide](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/?tab=android/). ### Step 1: Update your project 1. Add Firebase to your Android project. 2. Add the Cloud Messaging library to your Android project's `build.gradle`: ```gradle implementation "google.firebase:firebase-messaging:+" ``` ### Step 2: Create your JSON credentials 1. In Google Cloud, enable the [Firebase Cloud Messaging API](https://console.cloud.google.com/apis/library/fcm.googleapis.com). 2. Select **Service Accounts** > your project > **Create Service Account**, then enter a service account name, ID, and description. When you're finished, select **Create and continue**. 3. In the **Role** field, find and select **Firebase Cloud Messaging API Admin** from the list of roles. 4. In **Service Accounts**, choose your project, then select  **Actions** > **Manage Keys** > **Add Key** > **Create new key**. Choose **JSON**, then select **Create**. ### Step 3: Upload your JSON credentials 1. In Braze, select  **Settings** > **App Settings**. Under your Android app's **Push Notification Settings**, choose **Firebase**, then select **Upload JSON File** and upload the credentials you generated earlier. When you're finished, select **Save**. 2. Enable automatic FCM token registration, by going to Firebase Console. Open your project, then select  **Settings** > **Project settings**. Select **Cloud Messaging**, then under **Firebase Cloud Messaging API (V1)**, copy the number in the **Sender ID** field. 3. In your Android Studio project and the following to your `braze.xml`. ```xml true FIREBASE_SENDER_ID ``` **Important:** To prevent Braze from triggering unnecessary network requests every time you send silent push notifications, remove any automatic network requests configured in your `Application` class's `onCreate()` method. For more information see, [Android Developer Reference: Application](https://developer.android.com/reference/android/app/Application). ### Step 1: Complete the initial setup See the [Swift integration instructions](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift) for information about setting up your application with push and storing your credentials on our server. Refer to the [iOS MAUI](https://github.com/braze-inc/braze-xamarin-sdk/tree/master/appboy-component/samples/ios-net-maui/BrazeiOSMauiSampleApp) sample application for more details. ### Step 2: Request push notifications permission Our .NET MAUI SDK now supports automatic push set up. Set up push automation and permissions by adding the following code to your Braze instance configuration: ```csharp configuration.Push.Automation = new BRZConfigurationPushAutomation(true); configuration.Push.Automation.RequestAuthorizationAtLaunch = false; ``` Refer to the [iOS MAUI](https://github.com/braze-inc/braze-xamarin-sdk/tree/master/appboy-component/samples/ios-net-maui/BrazeiOSMauiSampleApp) sample application for more details. For more details, see the Xamarin documentation for [Enhanced User Notifications in Xamarin.iOS](https://learn.microsoft.com/en-us/previous-versions/xamarin/ios/platform/user-notifications/enhanced-user-notifications?tabs=macos). # Braze SDKのプッシュ通知をカスタマイズする Source: /docs/ja/developer_guide/push_notifications/customization/index.md # プッシュ通知をカスタマイズする > Braze SDKのプッシュ通知をカスタマイズする方法を学習。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=android). ## Using a callback for push events {#push-callback} Braze provides a [`subscribeToPushNotificationEvents()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/subscribe-to-push-notification-events.html) callback for when push notifications are received, opened, or dismissed. It is recommended to place this callback in your `Application.onCreate()` in order to not miss any events occurring while your application is not running. **Note:** If previously using a Custom Broadcast Receiver for this functionality in your application, you can safely remove it in favor of this integration option. ```java Braze.getInstance(context).subscribeToPushNotificationEvents(event -> { final BrazeNotificationPayload parsedData = event.getNotificationPayload(); // // The type of notification itself // final boolean isPushOpenEvent = event.getEventType() == BrazePushEventType.NOTIFICATION_OPENED; final boolean isPushReceivedEvent = event.getEventType() == BrazePushEventType.NOTIFICATION_RECEIVED; // Sent when a user has dismissed a notification final boolean isPushDeletedEvent = event.getEventType() == BrazePushEventType.NOTIFICATION_DELETED; // // Notification data // final String pushTitle = parsedData.getTitleText(); final Long pushArrivalTimeMs = parsedData.getNotificationReceivedTimestampMillis(); final String deeplink = parsedData.getDeeplink(); // // Custom KVP data // final String myCustomKvp1 = parsedData.getBrazeExtras().getString("my first kvp"); final String myCustomKvp2 = parsedData.getBrazeExtras().getString("my second kvp"); }); ``` ```kotlin Braze.getInstance(context).subscribeToPushNotificationEvents { event -> val parsedData = event.notificationPayload // // The type of notification itself // val isPushOpenEvent = event.eventType == BrazePushEventType.NOTIFICATION_OPENED val isPushReceivedEvent = event.eventType == BrazePushEventType.NOTIFICATION_RECEIVED // Sent when a user has dismissed a notification val isPushDeletedEvent = event.eventType == BrazePushEventType.NOTIFICATION_DELETED // // Notification data // val pushTitle = parsedData.titleText val pushArrivalTimeMs = parsedData.notificationReceivedTimestampMillis val deeplink = parsedData.deeplink // // Custom KVP data // val myCustomKvp1 = parsedData.brazeExtras.getString("my first kvp") val myCustomKvp2 = parsedData.brazeExtras.getString("my second kvp") } ``` **Tip:** With notification action buttons, `BRAZE_PUSH_INTENT_NOTIFICATION_OPENED` intents fire when buttons with `opens app` or `deep link` actions are clicked. Deep link and extras handling remains the same. Buttons with `close` actions don't fire `BRAZE_PUSH_INTENT_NOTIFICATION_OPENED` intents and dismiss the notification automatically. **Important:** Create your push notification listener in `Application.onCreate` to ensure your listener is triggered after an end-user taps a notification while your app is in a terminated state. ## Customizing notification display {#customization-display} ### Step 1: Create your custom notification factory In some scenarios, you may wish to customize push notifications in ways that would be cumbersome or unavailable server side. To give you complete control of notification display, we've added the ability to define your own [`IBrazeNotificationFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze-notification-factory/index.html) to create notification objects for display by Braze. If a custom `IBrazeNotificationFactory` is set, Braze will call your factory's `createNotification()` method upon push receipt before the notification is displayed to the user. Braze will pass in a `Bundle` containing Braze push data and another `Bundle` containing custom key-value pairs sent either via the dashboard or the messaging APIs: Braze will pass in a [`BrazeNotificationPayload`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.push/-braze-notification-payload/index.html) containing data from the Braze push notification. ```java // Factory method implemented in your custom IBrazeNotificationFactory @Override public Notification createNotification(BrazeNotificationPayload brazeNotificationPayload) { // Example of getting notification title String title = brazeNotificationPayload.getTitleText(); // Example of retrieving a custom KVP ("my_key" -> "my_value") String customKvp = brazeNotificationPayload.getBrazeExtras().getString("my_key"); } ``` ```kotlin // Factory method implemented in your custom IBrazeNotificationFactory override fun createNotification(brazeNotificationPayload: BrazeNotificationPayload): Notification { // Example of getting notification title val title = brazeNotificationPayload.getTitleText() // Example of retrieving a custom KVP ("my_key" -> "my_value") val customKvp = brazeNotificationPayload.getBrazeExtras().getString("my_key") } ``` You can return `null` from your custom `createNotification()` method to not show the notification at all, use `BrazeNotificationFactory.getInstance().createNotification()` to obtain our default `notification` object for that data and modify it before display, or generate a completely separate `notification` object for display. **Note:** For documentation on Braze push data keys, refer to the [Android SDK](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-constants/index.html). ### Step 2: Set your custom notification factory To instruct Braze to use your custom notification factory, use the `setCustomBrazeNotificationFactory` method to set your [`IBrazeNotificationFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze-notification-factory/index.html): ```java setCustomBrazeNotificationFactory(IBrazeNotificationFactory brazeNotificationFactory); ``` ```kotlin setCustomBrazeNotificationFactory(brazeNotificationFactory: IBrazeNotificationFactory) ``` The recommended place to set your custom `IBrazeNotificationFactory` is in the `Application.onCreate()` application lifecycle method (not activity). This will allow the notification factory to be set correctly whenever your app process is active. **Important:** Creating your own notification from scratch is an advanced use case and should be done only with thorough testing and a deep understanding of the Braze push functionality. For example, you must make sure your notification logs push opens correctly. To unset your custom [`IBrazeNotificationFactory`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze-notification-factory/index.html) and return to default Braze handling for push, pass in `null` to our custom notification factory setter: ```java setCustomBrazeNotificationFactory(null); ``` ```kotlin setCustomBrazeNotificationFactory(null) ``` ## Rendering multicolor text In Braze SDK version 3.1.1, HTML can be sent to a device to render multicolor text in push notifications. ![An Android push message "Multicolor Push test message" where the letters are different colors, italicized and given a background color.](https://www.braze.com/docs/ja/ja/assets/img/multicolor_android_push.png?5a515501661c5953a76737951378e789){: style="max-width:40%;"} This example is rendered with the following HTML: ```html

MultiColor Push

test message

``` Keep in mind that, Android limits which HTML elements and tags are valid in your push notifications. For example, `marquee` is not allowed. **Important:** Multicolor text rendering is device-specific and may not display based on Android device or version. To render multicolor text in a push notification, you can update your `braze.xml` or `BrazeConfig`: Add the following in your `braze.xml`: ```xml true ``` Add the following in your [`BrazeConfig`](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/advanced_use_cases/runtime_configuration/#runtime-configuration): ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setPushHtmlRenderingEnabled(true) .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setPushHtmlRenderingEnabled(true) .build() Braze.configure(this, brazeConfig) ``` ### Supported HTML tags Currently, Google doesn't list their supported HTML tags for Android directly in their documentation—this information can only be found in their [Git repository's `Html.java` file](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/text/Html.java). Keep this in mind when referencing the following table, as this information was pulled from this file, and their supported HTML tags could be subject to change.
Category HTML Tag Description
Basic Text Styling <b>, <strong> Bold text
<i>, <em> Italic text
<u> Underline text
<s>, <strike>, <del> Strikethrough text
<sup> Superscript text
<sub> Subscript text
<tt> Monospace text
Size/Font <big>, <small> Relative text size changes
<font color="..."> Sets foreground color
<span> (with inline CSS) Inline styles (e.g., color, background)
Paragraph & Block <p>, <div> Block-level sections
<br> Line break
<blockquote> Quoted block
<ul> + <li> Unordered list with bullets
Headings <h1> - <h6> Headings (various sizes)
Links & Images <a href="..."> Clickable link
<img src="..."> Inline image
Other Inline <em>, <strong>, <dfn>, <cite> Synonyms for italic or bold
{: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Supported HTML tags" } ## Rendering inline images ### How it works You can showcase a larger image within your Android push notification using inline image push. With this design, users won't have to manually expand the push to enlarge the image. Unlike regular Android push notifications, inline image push images are in a 3:2 aspect ratio. ![](https://www.braze.com/docs/ja/ja/assets/img/android/push/inline_image_push_android_1.png?bf2ba99d9b6423b4d8d94e5d8d9c5908){: style="max-width:50%;"} ### Compatibility While you can send inline images to any device, devices and SDKs that don't meet the minimum versions will display a standard image instead. For inline images to display properly, both the Android Braze SDK v10.0.0+ and a device running Android M+ are required. The SDK must also be enabled for the image to render. **Note:** Devices running Android 12 will render differently due to changes in custom push notification styles. ### Sending an inline image push When creating an Android push message, this feature is available in the **Notification Type** dropdown. ![The push campaign editor showing the location of the "Notification Type" dropdown (above the standard push preview).](https://www.braze.com/docs/ja/ja/assets/img/android/push/android_inline_image_notification_type.png?fc31f4cadbcef37649e3b980d03ce868) ## Settings There are many advanced settings available for Android push notifications sent through the Braze dashboard. This article will describe these features and how to use them successfully. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/android_advanced_settings.png?8131f34243617db90fdf5780cbc3cf33) ### Notification ID {#notification-id} A **Notification ID** is a unique identifier for a message category of your choosing that informs the messaging service to only respect the most recent message from that ID. Setting a notification ID allows you to send just the most recent and relevant message, rather than a stack of outdated, irrelevant ones. ### Firebase Messaging Delivery priority {#fcm-priority} The [Firebase Messaging Delivery Priority](https://firebase.google.com/docs/cloud-messaging/android/message-priority#setting-priority-for-messages) field lets you control whether a push is sent with "normal" or "high" priority to Firebase Cloud Messaging. ### Time to live (TTL) {#ttl} The **Time to Live** (TTL) field allows you to set a custom length of time to store messages with the push messaging service. The default values for time to live are four weeks for FCM and 31 days for ADM. ### Summary text {#summary-text} The summary text allows you to set additional text in the expanded notification view. It also serves as a caption for notifications with images. ![An Android message with the title "This is the title for the notification." and summary text "This is the summary text for the notification."](https://www.braze.com/docs/ja/ja/assets/img/android/push/collapsed-android-notification.png?fd42100702f714bd5cb65f742509c9b7){: style="max-width:65%;"} The summary text will display under the body of the message in the expanded view. ![An Android message with the title "This is the title for the notification." and summary text "This is the summary text for the notification."](https://www.braze.com/docs/ja/ja/assets/img/android/push/expanded-android-notification.png?18786f441d0d9d6b65bfcce34c43198d){: style="max-width:65%;"} For push notifications that include images, the message text will be shown in the collapsed view, while the summary text will be displayed as the image caption when the notification is expanded. ### Custom URIs {#custom-uri} The **Custom URI** feature allows you to specify a Web URL or an Android resource to navigate to when the notification is clicked. If no custom URI is specified, clicking on the notification brings users into your app. You can use the custom URI to deep link inside your app and direct users to resources that exist outside of your app. This can be specified via the [Messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/) or our dashboard under **Advanced Settings** in the push composer as pictured: ![The deep linking advanced setting in the Braze push composer.](https://www.braze.com/docs/ja/ja/assets/img_archive/deep_link.png?30080909d43633ac9ca7ac8d115a686a) ### Notification display priority {#notification-priority} **Important:** The Notification Display Priority setting is no longer used on devices running Android O or newer. For newer devices, set the priority through [notification channel configuration](https://developer.android.com/training/notify-user/channels#importance). The priority level of a push notification affects how your notification is displayed in the notification tray relative to other notifications. It can also affect the speed and manner of delivery, as normal and lower priority messages may be sent with slightly higher latency or batched to preserve battery life, whereas high priority messages are always sent immediately. In Android O, notification priority became a property of notification channels. You will need to work with your developer to define the priority for a channel during its configuration and then use the dashboard to select the proper channel when sending your notification sounds. For devices running versions of Android before O, specifying a priority level for Android notifications is possible via the Braze dashboard and messaging API. To message your full user base with a specific priority, we recommend that you indirectly specify the priority through [notification channel configuration](https://developer.android.com/training/notify-user/channels#importance) (to target O+ devices) *and* send the individual priority from the dashboard (to target <O devices). The priority levels that you can set on Android or Fire OS push notifications are: | Priority | Description/Intended Use | `priority` value (for API messages) | |----------|--------------------------|-------------------------------------| | Max | Urgent or time-critical messages | `2` | | High | Important communication, such as a new message from a friend | `1` | | Default | Most notifications - use if your message doesn't explicitly fall under any of the other priority types | `0` | | Low | Information that you want users to know about but does not require immediate action | `-1` | | Min | Contextual or background information. | `-2` | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Notification display priority #notification-priority" } For more information, refer to Google's [Android notification](http://developer.android.com/design/patterns/notifications.html) documentation. ### Sounds {#sounds} In Android O, notification sounds became a property of notification channels. You will need to work with your developer to define the sound for a channel during its configuration and then use the dashboard to select the proper channel when sending your notifications. For devices running versions of Android before O, Braze allows you to set the sound of an individual push message through the dashboard composer. You can do so by specifying a local sound resource on the device (for example, `android.resource://com.mycompany.myapp/raw/mysound`). Specifying "default" in this field will play the default notification sound on the device. This can be specified via the [Messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/) or the dashboard under **Advanced Settings** in the push composer. ![The sound advanced setting in the Braze push composer.](https://www.braze.com/docs/ja/ja/assets/img_archive/sound_android.png?70e53c2fdff6155d172b0399de090593) Enter the full sound resource URI (for example, `android.resource://com.mycompany.myapp/raw/mysound`) into the dashboard prompt. To message your full user base with a specific sound, we recommend that you indirectly specify the sound through [notification channel configuration](https://developer.android.com/training/notify-user/channels) (to target O+ devices) *and* send the individual sound from the dashboard (to target <O devices). ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift). ## Customizing action buttons {#push-action-buttons-integration} The Braze Swift SDK provides URL handling support for push action buttons. There are four sets of default push action buttons for Braze default push categories: `Accept/Decline`, `Yes/No`, `Confirm/Cancel`, and `More`. ![A GIF of a push message being pulled down to display two customizable action buttons.](https://www.braze.com/docs/ja/ja/assets/img_archive/iOS8Action.gif?d3553a68ae1aa0c3a58da9e65174f404){: style="max-width:60%"} ### Manually registering action buttons **Important:** Manually registering push action buttons are not recommended. If you [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift) using the `configuration.push.automation` configuration option, Braze automatically registers the action buttons for the default push categories and handles the push action button click analytics and URL routing. However, you can choose to manually register push action buttons instead. #### Step 1: Adding Braze default push categories {#registering} Use the following code to register for the default push categories when you [register for push](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/#step-4-register-push-tokens-with-braze): a ```swift UNUserNotificationCenter.current().setNotificationCategories(Braze.Notifications.categories) ``` ```objc [[UNUserNotificationCenter currentNotificationCenter] setNotificationCategories:BRZNotifications.categories]; ``` **Note:** Clicking on push action buttons with background activation mode will only dismiss the notification and not open the app. The next time the user opens the app, the button click analytics for these actions will be flushed to the server. #### Step 2: Enable interactive push handling {#enable-push-handling} To enable our push action button handling, including click analytics and URL routing, add the following code to your app's `didReceive(_:completionHandler:)` delegate method: ```swift AppDelegate.braze?.notifications.handleUserNotification(response: response, withCompletionHandler: completionHandler) ``` ```objc [AppDelegate.braze.notifications handleUserNotificationWithResponse:response withCompletionHandler:completionHandler]; ``` If you use the `UNNotification` framework and have implemented the Braze [notification methods](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/#step-5-enable-push-handling), you should already have this method integrated. ## Customizing push categories {#customizing-push-categories} In addition to providing a set of default push categories, Braze supports custom notification categories and actions. After you register categories in your application, you can use the Braze dashboard to send these custom notification categories to your users. Here's an example that leverages the `LIKE_CATEGORY` displayed on the device: ![A push message displaying two push action buttons "unlike" and "like".](https://www.braze.com/docs/ja/ja/assets/img_archive/push_example_category.png?342eb7b8bc6d24142ee32606e22f8eee) ### Step 1: Register a category To register a category in your app, use a similar approach to the following: ```swift Braze.Notifications.categories.insert( .init(identifier: "LIKE_CATEGORY", actions: [ .init(identifier: "LIKE_IDENTIFIER", title: "Like", options: [.foreground]), .init(identifier: "UNLIKE_IDENTIFIER", title: "Unlike", options: [.foreground]) ], intentIdentifiers: [] ) ) UNUserNotificationCenter.current().setNotificationCategories(Braze.Notifications.categories) ``` ```objc NSMutableSet *categories = [BRZNotifications.categories mutableCopy]; UNNotificationAction *likeAction = [UNNotificationAction actionWithIdentifier:@"LIKE_IDENTIFIER" title:@"Like" options:UNNotificationActionOptionForeground]; UNNotificationAction *unlikeAction = [UNNotificationAction actionWithIdentifier:@"UNLIKE_IDENTIFIER" title:@"Unlike" options:UNNotificationActionOptionForeground]; UNNotificationCategory *likeCategory = [UNNotificationCategory categoryWithIdentifier:@"LIKE_CATEGORY" actions:@[likeAction, unlikeAction] intentIdentifiers:@[] options:UNNotificationCategoryOptionNone]; [categories addObject:likeCategory]; [UNUserNotificationCenter.currentNotificationCenter setNotificationCategories:categories]; ``` **Note:** When you create a `UNNotificationAction`, you can specify a list of action options. For example, `.foreground` lets your users open your app after tapping the action button. This is necessary for navigational on-click behaviors, such as "Open App" and "Deep Link into Application". If you want an action button that simply dismisses the notification without opening the app, leave `.foreground` out of the action's `options` array. For more information, see [`UNNotificationActionOptions`](https://developer.apple.com/documentation/usernotifications/unnotificationactionoptions). ### Step 2: Select your categories After you register a category, use the Braze dashboard to send notifications of that type to users. **Tip:** You only need to define action buttons on the Braze dashboard for behaviors that can't be created locally in your Swift code, such as deep linking into your app or redirecting to a web URL. These actions need to be configured on the dashboard so they can define what URL or deep link to open. For action buttons that simply dismiss the notification without opening the app, you don't need to configure them on the dashboard—dismissal behavior is handled automatically by iOS. Just register your custom category and its actions in your app code, then enter the matching category name on the dashboard. 1. In the Braze dashboard, select **Messaging** > **Push Notifications**, then choose your iOS [push campaign](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/creating_a_push_message). 2. Under **Compose push notification**, turn on **Action Buttons**. 3. In the **iOS Notification Category** dropdown, select **Enter pre-registered custom iOS Category**. 4. Finally, enter one of the categories you created earlier. The following example, uses the custom category: `LIKE_CATEGORY`. ![The push notification campaign dashboard with the setup for custom categories.](https://www.braze.com/docs/ja/ja/assets/img_archive/ios-notification-category.png?3773374b98a8bfab3549164f0b8eedd1) ### Example: Custom push category {#example-custom-push-category} Suppose you want to create a push notification with two action buttons: **Manage**, which deep links into your app, and **Keep**, which simply dismisses the notification. In the following example, the `MANAGE_IDENTIFIER` action includes the `.foreground` option, which opens the app when tapped—this is necessary because it will deep link into a specific part of the app. The `KEEP_IDENTIFIER` action uses an empty options array, meaning it will dismiss the notification without opening the app. ```swift Braze.Notifications.categories.insert( .init(identifier: "YOUR_CATEGORY", actions: [ .init(identifier: "KEEP_IDENTIFIER", title: "Keep", options: []), .init(identifier: "MANAGE_IDENTIFIER", title: "Manage", options: [.foreground]) ], intentIdentifiers: [] ) ) UNUserNotificationCenter.current().setNotificationCategories(Braze.Notifications.categories) ``` Because `MANAGE_IDENTIFIER` deep links into the app, you would set up that action button on the Braze dashboard with the associated deep link URL. However, you don't need to define a button on the dashboard for `KEEP_IDENTIFIER` because it only dismisses the notification. On the dashboard, you only need to enter the category name (for example, `YOUR_CATEGORY`) to match what you registered in your app code. ## Customizing badges Badges are small icons that are ideal for getting a user's attention. You can specify a badge count in the [**Settings**](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/customization/?sdktab=swift#swift_settings) tab when you compose a push notification using the Braze dashboard. You may also update your badge count manually through your application's [`applicationIconBadgeNumber`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instp/UIApplication/applicationIconBadgeNumber) property or the [remote notification payload](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW1). Braze will automatically clear the badge count when a Braze notification is received while the app is in the foreground. Manually setting the badge number to 0 will also clear notifications in the notification center. If you do not have a plan for clearing badges as part of normal app operation or by sending pushes that clear the badge, you should clear the badge when the app becomes active by adding the following code to your app's `applicationDidBecomeActive:` delegate method: ```swift // For iOS 16.0+ let center = UNUserNotificationCenter.current() do { try await center.setBadgeCount(0) } catch { // Handle errors } // Prior to iOS 16. Deprecated in iOS 17+. UIApplication.shared.applicationIconBadgeNumber = 0 ``` ```objc // For iOS 16.0+ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center setBadgeCount:0 withCompletionHandler:^(NSError * _Nullable error) { if (error != nil) { // Handle errors } }]; // Prior to iOS 16. Deprecated in iOS 17+. [UIApplication sharedApplication].applicationIconBadgeNumber = 0; ``` ## Customizing sounds ### Step 1: Host the sound in your app Custom push notification sounds must be hosted locally within the main bundle of your app. The following audio data formats are accepted: - Linear PCM - MA4 - µLaw - aLaw You can package the audio data in an AIFF, WAV, or CAF file. In Xcode, add the sound file to your project as a non-localized resource of the application bundle. **Note:** Custom sounds must be under 30 seconds when played. If a custom sound is over that limit, the default system sound is played instead. #### Converting sound files You can use the afconvert tool to convert sounds. For example, to convert the 16-bit linear PCM system sound Submarine.aiff to IMA4 audio in a CAF file, use the following command in the terminal: ```bash afconvert /System/Library/Sounds/Submarine.aiff ~/Desktop/sub.caf -d ima4 -f caff -v ``` **Tip:** You can inspect a sound to determine its data format by opening it in QuickTime Player and choosing **Show Movie Inspector** from the **Movie** menu. ### Step 2: Provide a protocol URL for the sound You must specify a protocol URL that directs to the location of the sound file in your app. There are two methods for doing this: * Use the `sound` parameter of the [Apple push object](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/apple_object#apple-push-object) to pass the URL to Braze. * Specify the URL in the dashboard. In the [push composer](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/creating_a_push_message/#step-3-select-notification-type-ios-and-android), select **Settings** and enter the protocol URL in the **Sound** field. ![The push composer in the Braze dashboard](https://www.braze.com/docs/ja/ja/assets/img_archive/sound_push_ios.png?c035b34ffb6c0f720f6d2c08ca1ba2b2) If the specified sound file doesn't exist or the keyword "default" is entered, Braze will use the default device alert sound. Aside from our dashboard, sound can also be configured via our [messaging API][12]. See the Apple Developer Documentation regarding [preparing custom alert sounds](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/SupportingNotificationsinYourApp.html) for additional information. ## Settings When creating a push campaign through the dashboard, click the **Settings** tab on the **Compose** step to view the advanced settings available. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/ios_advanced_settings.png?16f142abe70d854830708b0cb21d9465) ### Key-value pairs Braze allows you to send custom-defined string key-value pairs, known as `extras`, along with a push notification to your application. Extras can be defined via the dashboard or API and will be available as key-value pairs within the `notification` dictionary passed to your push delegate implementations. ### Alert options Select the **Alert Options** checkbox to see a dropdown of key-values available to adjust how the notification appears on devices. ### Adding content-available flag Check the **Add Content-Available Flag** checkbox to instruct devices to download new content in the background. Most commonly, this can be checked if you are interested in sending [silent notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent/?sdktab=swift). ### Adding mutable-content flag Check the **Add Mutable-Content Flag** checkbox to enable advanced receiver customization. This flag will automatically be sent when composing a [rich notification](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/rich/?sdktab=swift), regardless of the value of this checkbox. ### Collapse ID Specify a collapse ID to coalesce similar notifications. If you send multiple notifications with the same collapse ID, the device will only show the most recently received notification. Refer to Apple's documentation on [coalesced notifications](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1). ### Expiry Checking the **Expiry** checkbox will allow setting an expiration time for your message. Should a user's device lose connectivity, Braze will continue to try and send the message until the specified time. If this is not set, the platform will default to an expiration of 30 days. Note that push notifications that expire before delivery are not considered failed and will not be recorded as a bounce. ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=android). ## Settings There are many advanced settings available for FireOS push notifications sent through the Braze dashboard. This article will describe these features and how to use them successfully. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/android_advanced_settings.png?8131f34243617db90fdf5780cbc3cf33) ### Time to live (TTL) {#ttl} The **Time to Live** (TTL) field allows you to set a custom length of time to store messages with the push messaging service. The default values for time to live are four weeks for FCM and 31 days for ADM. ### Summary text {#summary-text} The summary text allows you to set additional text in the expanded notification view. It also serves as a caption for notifications with images. ![An Android message with the title "This is the title for the notification." and summary text "This is the summary text for the notification."](https://www.braze.com/docs/ja/ja/assets/img/android/push/collapsed-android-notification.png?fd42100702f714bd5cb65f742509c9b7){: style="max-width:65%;"} The summary text will display under the body of the message in the expanded view. ![An Android message with the title "This is the title for the notification." and summary text "This is the summary text for the notification."](https://www.braze.com/docs/ja/ja/assets/img/android/push/expanded-android-notification.png?18786f441d0d9d6b65bfcce34c43198d){: style="max-width:65%;"} For push notifications that include images, the message text will be shown in the collapsed view, while the summary text will be displayed as the image caption when the notification is expanded. ### Custom URIs {#custom-uri} The **Custom URI** feature allows you to specify a Web URL or an Android resource to navigate to when the notification is clicked. If no custom URI is specified, clicking on the notification brings users into your app. You can use the custom URI to deep link inside your app and direct users to resources that exist outside of your app. This can be specified via the [Messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging) or our dashboard under **Advanced Settings** in the push composer as pictured: ![The deep linking advanced setting in the Braze push composer.](https://www.braze.com/docs/ja/ja/assets/img_archive/deep_link.png?30080909d43633ac9ca7ac8d115a686a) ### Notification display priority **Important:** The Notification Display Priority setting is no longer used on devices running Android O or newer. For newer devices, set the priority through [notification channel configuration](https://developer.android.com/training/notify-user/channels#importance). The priority level of a push notification affects how your notification is displayed in the notification tray relative to other notifications. It can also affect the speed and manner of delivery, as normal and lower priority messages may be sent with slightly higher latency or batched to preserve battery life whereas high priority messages are always sent immediately. In Android O, notification priority became a property of notification channels. You will need to work with your developer to define the priority for a channel during its configuration and then use the dashboard to select the proper channel when sending your notification sounds. For devices running versions of Android before O, specifying a priority level for FireOS notifications is possible via the Braze dashboard and messaging API. To message your full user base with a specific priority, we recommend that you indirectly specify the priority through [notification channel configuration](https://developer.android.com/training/notify-user/channels#importance) (to target O+ devices) *and* send the individual priority from the dashboard (to target <O devices). The priority levels that you can set on Fire OS push notifications are: | Priority | Description/Intended Use | `priority` value (for API messages) | |----------|--------------------------|-------------------------------------| | Max | Urgent or time-critical messages | `2` | | High | Important communication, such as a new message from a friend | `1` | | Default | Most notifications - use if your message doesn't explicitly fall under any of the other priority types | `0` | | Low | Information that you want users to know about but does not require immediate action | `-1` | | Min | Contextual or background information. | `-2` | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Notification display priority" } For more information, refer to Google's [Android notification](http://developer.android.com/design/patterns/notifications.html) documentation. ### Sounds {#sounds} In Android O, notification sounds became a property of notification channels. You will need to work with your developer to define the sound for a channel during its configuration and then use the dashboard to select the proper channel when sending your notifications. For devices running versions of Android before O, Braze allows you to set the sound of an individual push message through the dashboard composer. You can do so by specifying a local sound resource on the device (for example, `android.resource://com.mycompany.myapp/raw/mysound`). Specifying "default" in this field will play the default notification sound on the device. This can be specified via the [Messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging) or the dashboard under **Settings** in the push composer. ![The sound advanced setting in the Braze push composer.](https://www.braze.com/docs/ja/ja/assets/img_archive/sound_android.png?70e53c2fdff6155d172b0399de090593) Enter the full sound resource URI (for example, `android.resource://com.mycompany.myapp/raw/mysound`) into the dashboard prompt. To message your full user base with a specific sound, we recommend that you indirectly specify the sound through [notification channel configuration](https://developer.android.com/training/notify-user/channels) (to target O+ devices) *and* send the individual sound from the dashboard (to target <O devices). ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). You must also [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=react%20native). ## Push customization in React Native The Braze React Native SDK does not expose push notification customization (action buttons, categories, custom notification factories) through its JavaScript API. These features require native configuration in your iOS and Android projects. The following table shows which features require native configuration: | Feature | iOS | Android | | --- | --- | --- | | Action buttons | Configure in native Swift/Objective-C | Configure in native Java/Kotlin | | Push categories | Configure in native Swift/Objective-C | Configure in native Java/Kotlin | | Custom notification factory | N/A | Configure in native Java/Kotlin | | Badge customization | Configure in native Swift/Objective-C | N/A | | Custom sounds | Configure in native Swift/Objective-C | Configure in native Java/Kotlin | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Push customization in React Native" } ### iOS customization To add push action buttons, categories, badges, or custom sounds on iOS, implement the native configuration in your `AppDelegate` (Swift or Objective-C). See [Customize push notifications – Swift](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/customization/?sdktab=swift) for step-by-step instructions. ### Android customization To add push action buttons, categories, or a custom notification factory on Android, implement the native configuration in your Android project. See [Customize push notifications – Android](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/customization/?sdktab=android) for step-by-step instructions. # Braze SDKのプッシュ通知のディープリンク Source: /docs/ja/developer_guide/push_notifications/deep_linking/index.md # プッシュ通知のディープリンク > Braze SDK のサイレントプッシュ通知を設定する方法について説明します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Creating a universal delegate The Android SDK provides the ability to set a single delegate object to custom handle all deep links opened by Braze across Content Cards, in-app messages, and push notifications. Your delegate object should implement the [`IBrazeDeeplinkHandler`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-deeplink-handler/index.html) interface and be set using [`BrazeDeeplinkHandler.setBrazeDeeplinkHandler()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-deeplink-handler/-companion/set-braze-deeplink-handler.html). In most cases, the delegate should be set in your app's `Application.onCreate()`. The following is an example of overriding the default [`UriAction`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.actions/-uri-action/index.html) behavior with custom intent flags and custom behavior for YouTube URLs: ```java public class CustomDeeplinkHandler implements IBrazeDeeplinkHandler { private static final String TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler.class); @Override public void gotoUri(Context context, UriAction uriAction) { String uri = uriAction.getUri().toString(); // Open YouTube URLs in the YouTube app and not our app if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) { uriAction.setUseWebView(false); } CustomUriAction customUriAction = new CustomUriAction(uriAction); customUriAction.execute(context); } public static class CustomUriAction extends UriAction { public CustomUriAction(@NonNull UriAction uriAction) { super(uriAction); } @Override protected void openUriWithActionView(Context context, Uri uri, Bundle extras) { Intent intent = getActionViewIntent(context, uri, extras); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); if (intent.resolveActivity(context.getPackageManager()) != null) { context.startActivity(intent); } else { BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link " + uri + "."); } } } } ``` ```kotlin class CustomDeeplinkHandler : IBrazeDeeplinkHandler { override fun gotoUri(context: Context, uriAction: UriAction) { val uri = uriAction.uri.toString() // Open YouTube URLs in the YouTube app and not our app if (!StringUtils.isNullOrBlank(uri) && uri.contains("youtube.com")) { uriAction.useWebView = false } val customUriAction = CustomUriAction(uriAction) customUriAction.execute(context) } class CustomUriAction(uriAction: UriAction) : UriAction(uriAction) { override fun openUriWithActionView(context: Context, uri: Uri, extras: Bundle) { val intent = getActionViewIntent(context, uri, extras) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP if (intent.resolveActivity(context.packageManager) != null) { context.startActivity(intent) } else { BrazeLogger.w(TAG, "Could not find appropriate activity to open for deep link $uri.") } } } companion object { private val TAG = BrazeLogger.getBrazeLogTag(CustomDeeplinkHandler::class.java) } } ``` ## Deep linking to app settings To allow deep links to directly open your app's settings, you'll need a custom `BrazeDeeplinkHandler`. In the following example, the presence of a custom key-value pair called `open_notification_page` will make the deep link open the app's settings page: ```java BrazeDeeplinkHandler.setBrazeDeeplinkHandler(new IBrazeDeeplinkHandler() { @Override public void gotoUri(Context context, UriAction uriAction) { final Bundle extras = uriAction.getExtras(); if (extras.containsKey("open_notification_page")) { Intent intent = new Intent(); intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //for Android 5-7 intent.putExtra("app_package", context.getPackageName()); intent.putExtra("app_uid", context.getApplicationInfo().uid); // for Android 8 and later intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName()); context.startActivity(intent); } } }); ``` ```kotlin BrazeDeeplinkHandler.setBrazeDeeplinkHandler(object : IBrazeDeeplinkHandler { override fun gotoUri(context: Context, uriAction: UriAction) { val extras = uriAction.extras if (extras.containsKey("open_notification_page")) { val intent = Intent() intent.action = "android.settings.APP_NOTIFICATION_SETTINGS" intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK //for Android 5-7 intent.putExtra("app_package", context.packageName) intent.putExtra("app_uid", context.applicationInfo.uid) // for Android 8 and later intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName) context.startActivity(intent) } } }) ``` ## Customizing WebView activity {#Custom_Webview_Activity} When Braze opens website deeplinks inside the app, the deeplinks are handled by [`BrazeWebViewActivity`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui/-braze-web-view-activity/index.html). **Note:** For custom HTML in-app messages, links configured with `target="_blank"` open in the device's default web browser and are not handled by `BrazeWebViewActivity`. To change this: 1. Create a new Activity that handles the target URL from `Intent.getExtras()` with the key `com.braze.Constants.BRAZE_WEBVIEW_URL_EXTRA`. For an example, see [`BrazeWebViewActivity.kt`](https://github.com/braze-inc/braze-android-sdk/blob/master/android-sdk-ui/src/main/java/com/braze/ui/BrazeWebViewActivity.kt). 2. Add that activity to `AndroidManifest.xml` and set `exported` to `false`. ```xml ``` 3. Set your custom Activity in a `BrazeConfig` [builder object](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-custom-web-view-activity-class.html). Build the builder and pass it to [`Braze.configure()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/configure.html) in your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application.html#onCreate()). ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setCustomWebViewActivityClass(MyCustomWebViewActivity::class) ... .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setCustomWebViewActivityClass(MyCustomWebViewActivity::class.java) ... .build() Braze.configure(this, brazeConfig) ``` ## Troubleshooting If deep links from push notifications aren't working on Android, try the following steps: 1. **Test the deep link outside of Braze.** Open the deep link URL from another app, such as email or a browser. If it doesn't open your app, the deep link may not be configured correctly in your `AndroidManifest.xml`. For more information, see Android's [Create Deep Links](https://developer.android.com/training/app-links/deep-linking) documentation. 2. **Check that automatic deep link handling is enabled.** Verify that `com_braze_handle_push_deep_links_automatically` is set to `true` in `braze.xml`, or set this option through [runtime configuration](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization/?sdktab=android). Without this setting, Braze doesn't automatically open your app and deep link destination when someone taps a push notification. 3. **Verify your deep link handler delegate.** If you set a custom `IBrazeDeeplinkHandler`, confirm that your `gotoUri` implementation handles the URI and doesn't drop it. 4. **Test across channels.** If the same deep link works in an in-app message but not from push, the issue is likely in your push deep link handling, not in the deep link itself. ## Using Jetpack Compose To handle deeplinks when using Jetpack Compose with NavHost: 1. Ensure that the activity handling your deeplink is registered in the Android Manifest. ```xml ``` 2. In NavHost, specify which deeplinks you want it to handle. ```kotlin composableWithCompositionLocal( route = "YOUR_ROUTE_HERE", deepLinks = listOf(navDeepLink { uriPattern = "myapp://articles/{${MainDestinations.ARTICLE_ID_KEY}}" }), arguments = listOf( navArgument(MainDestinations.ARTICLE_ID_KEY) { type = NavType.LongType } ), ) { backStackEntry -> val arguments = requireNotNull(backStackEntry.arguments) val articleId = arguments.getLong(MainDestinations.ARTICLE_ID_KEY) ArticleDetail( articleId ) } ``` 3. Depending on your app architecture, you may need to handle the new intent that's sent to your current activity as well. ```kotlin DisposableEffect(Unit) { val listener = Consumer { navHostController.handleDeepLink(it) } addOnNewIntentListener(listener) onDispose { removeOnNewIntentListener(listener) } } ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). **Tip:** For help choosing between custom scheme deep links, universal links, and "Open Web URL Inside App," see [iOS deep linking guide](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/ios_deep_linking_guide). For troubleshooting, see [Deep linking troubleshooting](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking_troubleshooting). ## Handling deep links ### Step 1: Register a scheme {#register-a-scheme} To handle deep linking, a custom scheme must be stated in your `Info.plist` file. The navigation structure is defined by an array of dictionaries. Each of those dictionaries contains an array of strings. Use Xcode to edit your `Info.plist` file: 1. Add a new key, `URL types`. Xcode will automatically make this an array containing a dictionary called `Item 0`. 2. Within `Item 0`, add a key `URL identifier`. Set the value to your custom scheme. 3. Within `Item 0`, add a key `URL Schemes`. This will automatically be an array containing a `Item 0` string. 4. Set `URL Schemes` >> `Item 0` to your custom scheme. Alternatively, if you wish to edit your `Info.plist` file directly, you can follow this spec: ```html CFBundleURLTypes CFBundleURLName YOUR.SCHEME CFBundleURLSchemes YOUR.SCHEME ``` ### Step 2: Add a scheme allowlist You must declare the URL schemes you wish to pass to `canOpenURL(_:)` by adding the `LSApplicationQueriesSchemes` key to your app's Info.plist file. Attempting to call schemes outside this allowlist will cause the system to record an error in the device's logs, and the deep link will not open. An example of this error will look like this: ``` : -canOpenURL: failed for URL: "yourapp://deeplink" – error: "This app is not allowed to query for scheme yourapp" ``` For example, if an in-app message should open the Facebook app when tapped, the app has to have the Facebook custom scheme (`fb`) in your allowlist. Otherwise, the system will reject the deep link. Deep links that direct to a page or view inside your own app still require that your app's custom scheme be listed in your app's `Info.plist`. Your example allowlist might look something like: ```html LSApplicationQueriesSchemes myapp fb twitter ``` For more information, refer to [Apple's documentation](https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/LaunchServicesKeys.html#//apple_ref/doc/uid/TP40009250-SW14) on the `LSApplicationQueriesSchemes` key. ### Step 3: Implement a handler After activating your app, iOS will call the method [`application:openURL:options:`](https://developer.apple.com/reference/uikit/uiapplicationdelegate/1623112-application?language=objc). The important argument is the [NSURL](https://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSURL_Class/Reference/Reference.html#//apple_ref/doc/c_ref/NSURL) object. ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let path = url.path let query = url.query // Insert your code here to take some action based upon the path and query. return true } ``` ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *path = [url path]; NSString *query = [url query]; // Insert your code here to take some action based upon the path and query. return YES; } ``` ## App Transport Security (ATS) As defined by [Apple](https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS9.html#//apple_ref/doc/uid/TP40016198-SW14), "App Transport Security is a feature that improves the security of connections between an app and web services. The feature consists of default connection requirements that conform to best practices for secure connections. Apps can override this default behavior and turn off transport security." ATS is applied by default. It requires that all connections use HTTPS and are encrypted using TLS 1.2 with forward secrecy. Refer to [Requirements for Connecting Using ATS](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW35) for more information. All images served by Braze to end devices are handled by a content delivery network ("CDN") that supports TLS 1.2 and is compatible with ATS. Unless they are specified as exceptions in your application's `Info.plist`, connections that do not follow these requirements will fail with errors that are similar to the following. **Example Error 1:** ```bash CFNetwork SSLHandshake failed (-9801) Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred, and a secure connection to the server cannot be made." ``` **Example Error 2:** ```bash NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802) ``` ATS compliance is enforced for links opened within the mobile app (our default handling of clicked links) and does not apply to sites opened externally via a web browser. ### Working with ATS You can handle ATS in either of the following ways, but we recommend **complying with ATS requirements**. Your Braze integration can satisfy ATS requirements by ensuring that any existing links you drive users to (for example, though in-app message and push campaigns) satisfy ATS requirements. While there are ways to bypass ATS restrictions, our recommendation is to ensure that all linked URLs are ATS-compliant. Given Apple's increasing emphasis on application security, the following approaches to allowing ATS exceptions are not guaranteed to be supported by Apple. You can allow a subset of links with certain domains or schemes to be treated as exceptions to the ATS rules. Your Braze integration will satisfy ATS requirements if every link you use in a Braze messaging channel is either ATS compliant or handled by an exception. To add a domain as an exception of the ATS, add following to your app's `Info.plist` file: ```html NSAppTransportSecurity NSAllowsArbitraryLoads NSExceptionDomains example.com NSExceptionAllowsInsecureHTTPLoads NSIncludesSubdomains ``` Refer to Apple's article on [app transport security keys](https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33) for more information. You can turn off ATS entirely. Note that this is not recommended practice, due to both lost security protections and future iOS compatibility. To disable ATS, insert the following in your app's `Info.plist` file: ```html NSAppTransportSecurity NSAllowsArbitraryLoads ``` ## Decoding URLs The SDK percent-encodes links to create valid `URL`s. All link characters that are not allowed in a properly formed URL, such as Unicode characters, will be percent escaped. To decode an encoded link, use the `String` property [`removingPercentEncoding`](https://developer.apple.com/documentation/swift/stringprotocol/removingpercentencoding). You must also return `true` in the `BrazeDelegate.braze(_:shouldOpenURL:)`. A call to action is required to trigger the handling of the URL by your app. For example: ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { let urlString = url.absoluteString.removingPercentEncoding // Handle urlString return true } ``` ```objc - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { NSString *urlString = [url.absoluteString stringByRemovingPercentEncoding]; // Handle urlString return YES; } ``` ## Deep linking to app settings You can take advantage of `UIApplicationOpenSettingsURLString` to deep link users to your app's settings from Braze push notifications and in-app messages. To take users from your app into the iOS settings: 1. First, make sure your application is set up for either [scheme-based deep links](#swift_register-a-scheme) or [universal links](#swift_universal-links). 2. Decide on a URI for deep linking to the **Settings** page (for example, `myapp://settings` or `https://www.braze.com/settings`). 3. If you are using custom scheme-based deep links, add the following code to your `application:openURL:options:` method: ```swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { let path = url.path if (path == "settings") { UIApplication.shared.openURL(URL(string:UIApplication.openSettingsURLString)!) } return true } ``` ```objc - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *path = [url path]; if ([path isEqualToString:@"settings"]) { NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; [[UIApplication sharedApplication] openURL:settingsURL]; } return YES; } ``` ## Customization options {#customization-options} ### Default WebView customization The `Braze.WebViewController` class displays web URLs opened by the SDK, typically when "Open Web URL Inside App" is selected for a web deep link. You can customize the `Braze.WebViewController` via the [`BrazeDelegate.braze(_:willPresentModalWithContext:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazedelegate/braze(_:willpresentmodalwithcontext:)-12sqy/) delegate method. ### Linking handling customization The `BrazeDelegate` protocol can be used to customize the handling of URLs such as deep links, web URLs, and universal links. To set the delegate during Braze initialization, set a delegate object on the `Braze` instance. Braze will then call your delegate's implementation of `shouldOpenURL` before handling any URIs. When a push notification or in-app message uses **Open web URL inside mobile app**, Braze passes `context.useWebView == true` on [`Braze.URLContext`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/urlcontext). When the message opens the URL in the system browser instead, `useWebView` is `false`. Inspect `context.useWebView` in `braze(_:shouldOpenURL:)` to branch your custom handling—for example, to open an in-app `WebViewController` only when the campaign requested in-app display. #### Universal links {#universal-links} Braze supports universal links in push notifications, in-app messages, and Content Cards. To enable universal link support, [`configuration.forwardUniversalLinks`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/forwarduniversallinks) must be set to `true`. When enabled, Braze will forward universal links to your app's `AppDelegate` via the [`application:continueUserActivity:restorationHandler:`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623072-application) method. Your application also needs to be set up to handle universal links. Refer to [Apple's documentation](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) to ensure your application is configured correctly for universal links. **Warning:** Universal link forwarding requires access to the application entitlements. When running the application in a simulator, these entitlements are not directly available and universal links are not forwarded to the system handlers. To add support to simulator builds, you can add the application `.entitlements` file to the _Copy Bundle Resources_ build phase. See [`forwardUniversalLinks`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/forwarduniversallinks) documentation for more details. **Note:** The SDK does not query your domains' `apple-app-site-association` file. It performs the differentiation between universal links and regular URLs by looking at the domain name only. As a result, the SDK does not respect any exclusion rule defined in the `apple-app-site-association` per [Supporting associated domains](https://developer.apple.com/documentation/xcode/supporting-associated-domains). ## Examples ### BrazeDelegate Here's an example using `BrazeDelegate`. For more information, see [Braze Swift SDK reference](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazedelegate). ```swift func braze(_ braze: Braze, shouldOpenURL context: Braze.URLContext) -> Bool { if context.url.host == "MY-DOMAIN.com" { // Custom handle link here return false } // Let Braze handle links otherwise return true } ``` ```objc - (BOOL)braze:(Braze *)braze shouldOpenURL:(BRZURLContext *)context { if ([[context.url.host lowercaseString] isEqualToString:@"MY-DOMAIN.com"]) { // Custom handle link here return NO; } // Let Braze handle links otherwise return YES; } ``` ## Prerequisites Before you can implement deep linking into your Flutter iOS app, configure your URL schemes in your `Info.plist` file. For details, refer to [Deep linking for iOS](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking/?sdktab=swift#url-schemes). For Flutter Android, no additional native setup is required if you're handling deep links on the Dart layer. The minimal implementation shown in this article is sufficient for most Flutter apps. If you need advanced native-layer link handling (such as custom `IBrazeDeeplinkHandler` implementations), refer to [Deep linking for Android](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking/?sdktab=android). ## Implementing deep linking ### Step 1: Set up Flutter's built-in handling 1. In your Xcode project, open your `Info.plist` file. 2. Add a new key-value pair. 3. Set the key to `FlutterDeepLinkingEnabled`. 4. Set the type to `Boolean`. 5. Set the value to `YES`. ![An example project's `Info.plist` file with the added key-value pair.](https://www.braze.com/docs/ja/ja/assets/img/flutter/flutter-ios-deep-link-info-plist.png?a14c27fd33268008de35220161f94242 "Xcode Project Info.plist File") 1. In your Android Studio project, open your `AndroidManifest.xml` file. 2. Locate `.MainActivity` in your `activity` tags. 3. Within the `activity` tag, add the following `meta-data` tag: ```xml ``` ### Step 2: Forward data to the Dart layer (optional) You can use native, first-party, or third-party link handling for complex use cases, such as sending a user to a specific location in your app, or calling a specific function. #### Example: Deep linking to an alert dialog **Note:** While the following example does not rely on additional packages, you can use a similar approach to implement native, first-party, or third-party packages, such as [`go_router`](https://pub.dev/packages/go_router). Additional Dart code may be required. First, a method channel is used in the native layer to forward the deep link's URL string data to the Dart layer. ```swift extension AppDelegate { // Delegate method for handling custom scheme links. override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { forwardURL(url) return true } // Delegate method for handling universal links. override func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { return false } forwardURL(url) return true } private func forwardURL(_ url: URL) { guard let controller: FlutterViewController = window?.rootViewController as? FlutterViewController else { return } let deepLinkChannel = FlutterMethodChannel(name: "deepLinkChannel", binaryMessenger: controller.binaryMessenger) deepLinkChannel.invokeMethod("receiveDeepLink", arguments: url.absoluteString) } } ``` ```kotlin class MainActivity : FlutterActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) handleDeepLink(intent) } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) handleDeepLink(intent) } private fun handleDeepLink(intent: Intent) { val binaryMessenger = flutterEngine?.dartExecutor?.binaryMessenger if (intent?.action == Intent.ACTION_VIEW && binaryMessenger != null) { MethodChannel(binaryMessenger, "deepLinkChannel") .invokeMethod("receivedDeepLink", intent?.data.toString()) } } } ``` Next, a callback function is used in the Dart layer to display an alert dialogue using the URL string data sent previously. ```dart MethodChannel('deepLinkChannel').setMethodCallHandler((call) async { deepLinkAlert(call.arguments, context); }); void deepLinkAlert(String link, BuildContext context) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("Deep Link Alert"), content: Text("Opened with deep link: $link"), actions: [ TextButton( child: Text("Close"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); } ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Cordova Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=cordova). ## Enabling push deep linking By default, the Braze Cordova SDK doesn't automatically handle push deep linking from notifications. To enable push deep linking, add the following preferences to the `platform` element in your project's `config.xml` file. ```xml ``` ```xml ``` To customize back stack behavior when deep links are followed, you can also add these optional preferences: ```xml ``` For a full list of available push configuration options, see [Optional configurations](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=cordova#optional). # iOSディープリンクガイド Source: /docs/ja/developer_guide/push_notifications/ios_deep_linking_guide/index.md # iOSディープリンクガイド {#ios-deep-linking-guide} > このガイドでは、使用するメッセージングチャネルやBranchなどのサードパーティリンクプロバイダーの利用有無に応じて、iOSアプリに適したディープリンク戦略を選択する方法を説明します。 実装の詳細については、[ディープリンク](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking?sdktab=swift)を参照してください。トラブルシューティングについては、[ディープリンクのトラブルシューティング](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking_troubleshooting)を参照してください。 ## リンクの種類を選ぶ {#choosing-a-link-type} iOSアプリでBrazeメッセージからのリンクを処理する方法は3つあります。それぞれ動作が異なり、適したチャネルやユースケースも異なります。 | リンクの種類 | 例 | 最適な用途 | アプリ未インストールでも開けるか? | |---|---|---|---| | **カスタムスキーム** | `myapp://products/123` | プッシュ通知、アプリ内メッセージ、Content Cards | いいえ — リンクは失敗します | | **ユニバーサルリンク** | `https://myapp.com/products/123` | メール、SMS、クリックトラッキング付きチャネル | はい — Webにフォールバックします | | **アプリ内でWeb URLを開く** | 任意の `https://` URL | モーダルWebViewでWebコンテンツを表示する | N/A — WebViewに表示されます | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="リンクの種類を選ぶ" } ### カスタムスキームディープリンク {#custom-scheme-deep-links} カスタムスキームディープリンク(例:`myapp://products/123`)は、アプリを特定の画面に直接開きます。リンクがサードパーティによって変更されないチャネルにおいて、最もシンプルな選択肢です。 **カスタムスキームディープリンクを使用する場合:** - プッシュ通知、アプリ内メッセージ、またはContent Cardsを送信する場合 - アプリがインストールされていない場合にリンクが機能する必要がない場合 - クリックトラッキング(メールESPリンクラッピング)が不要な場合 **カスタムスキームディープリンクを使用しない場合:** - メールを送信する場合 — メールサービスプロバイダー (ESP)がクリックトラッキングのためにリンクをラップするため、カスタムスキームが機能しなくなります - アプリがインストールされていない場合にWebページへフォールバックするリンクが必要な場合 ### ユニバーサルリンク {#universal-links} ユニバーサルリンク(例:`https://myapp.com/products/123`)は標準的なHTTPS URLであり、iOSはブラウザで開く代わりにアプリにルーティングできます。サーバー側の設定(AASAファイル)とアプリ側の設定(Associated Domainsエンタイトルメント)が必要です。 **ユニバーサルリンクを使用する場合:** - メールを送信する場合。メールサービスプロバイダー (ESP)がクリックトラッキングのためにリンクをラップするため、リンクはHTTPSである必要があります。 - SMSやその他のチャネルで、リンクがラップまたは短縮される場合。 - アプリがインストールされていない場合にWebページへフォールバックするリンクが必要な場合。 - BranchやAppsFlyerなどのサードパーティリンクプロバイダーを使用している場合。 **ユニバーサルリンクを使用しない場合:** - プッシュ通知、アプリ内メッセージ、またはContent Cardsからのディープリンクのみが必要な場合。カスタムスキームの方がシンプルです。 ### 「アプリ内でWeb URLを開く」 {#open-web-url-inside-app} このオプションは、アプリ内のモーダルWebViewでWebページを開きます。Braze SDKの`Braze.WebViewController`によって完全に処理されるため、URL処理コードを記述する必要はありません。 **「アプリ内でWeb URLを開く」を使用する場合:** - アプリを離れることなくWebページ(プロモーションや記事など)を表示したい場合。 - URLが標準的なHTTPS Webページであり、特定のアプリ画面へのディープリンクではない場合。 **「アプリ内でWeb URLを開く」を使用しない場合:** - アプリ内の特定のビューに移動する必要がある場合。代わりにカスタムスキームまたはユニバーサルリンクを使用してください。 - Webページが認証を必要とする場合、または埋め込みをブロックするContent Security Policyヘッダーがある場合。 ## 各リンクタイプに必要なもの {#what-you-need-for-each-link-type} ### カスタムスキームディープリンク | 要件 | 詳細 | |---|---| | AASAファイル | 不要 | | `Info.plist` | `CFBundleURLTypes`にスキームを登録し、`LSApplicationQueriesSchemes`に追加します | | アプリデリゲートメソッド | `application(_:open:options:)`を実装してURLを解析しナビゲーションします | | Braze SDKの設定 | なし — SDKはデフォルトでカスタムスキームURLを開きます | {: .reset-td-br-1 .reset-td-br-2 aria-label="カスタムスキームディープリンク" } ### ユニバーサルリンク | 要件 | 詳細 | |---|---| | AASAファイル | 必須 — `https://yourdomain.com/.well-known/apple-app-site-association`にホストします | | Associated Domains | Xcodeの**Signing & Capabilities**で`applinks:yourdomain.com`を追加します | | アプリデリゲートメソッド | `application(_:continue:restorationHandler:)`を実装して`NSUserActivity`を処理します | | Braze SDKの設定 | `configuration.forwardUniversalLinks = true`を設定します | | BrazeDelegate(オプション) | カスタムルーティング(例:Branch)のために`braze(_:shouldOpenURL:)`を実装します | {: .reset-td-br-1 .reset-td-br-2 aria-label="ユニバーサルリンク" } **Important:** Braze経由でメールを送信する場合、メールサービスプロバイダー (ESP)(SendGrid、SparkPost、またはAmazon SES)がリンクをクリックトラッキングドメインでラップします。AASAファイルは、メインドメインだけでなくクリックトラッキングドメインにもホストする必要があります。完全な設定については、[ユニバーサルリンクとアプリリンク](https://www.braze.com/docs/ja/ja/user_guide/channels/email/customize/universal_links_and_app_links)を参照してください。 ### 「アプリ内でWeb URLを開く」 | 要件 | 詳細 | |---|---| | AASAファイル | 不要 | | アプリデリゲートメソッド | 不要 — SDKが自動的に処理します | | Braze SDKの設定 | なし — キャンペーンコンポーザーで**Open Web URL Inside App**を選択します | {: .reset-td-br-1 .reset-td-br-2 aria-label="アプリ内でWeb URLを開く" } ## AASAファイルが必要な場合 {#when-aasa} Apple App Site Association(AASA)ファイルは、**ユニバーサルリンク**を使用する場合にのみ必要です。AASAファイルは、アプリが処理できるURLをiOSに伝えます。 AASAファイルが必要な場合: - メールキャンペーンでディープリンクを送信する場合(メールサービスプロバイダー (ESP)がリンクをHTTPSクリックトラッキングURLでラップするため)。 - SMSキャンペーンでディープリンクを送信する場合(リンクがHTTPS URLに短縮される可能性があるため)。 - Branch、AppsFlyer、またはその他のリンクプロバイダーを使用する場合(独自のHTTPSドメインを使用するため)。 - プッシュ通知、アプリ内メッセージ、またはContent Cardsからユニバーサルリンクを使用する場合(一般的ではありませんが、`forwardUniversalLinks = true`で可能です)。 AASAファイルが不要な場合: - プッシュ通知、アプリ内メッセージ、またはContent Cardsからカスタムスキームディープリンク(例:`myapp://`)のみを使用する場合。 - **Open Web URL Inside App**オプションを使用する場合。 AASAの設定手順については、[ユニバーサルリンクとアプリリンク](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/universal_links#setting-up-universal-links-and-app-links)を参照してください。 ## リンクを処理するためにアプリコードが必要な場合 {#when-app-code} 実装するデリゲートメソッドは、使用するリンクの種類によって異なります。 | デリゲートメソッド | 処理対象 | 実装するタイミング | |---|---|---| | `application(_:open:options:)` | カスタムスキームディープリンク(`myapp://`) | 任意のチャネルからカスタムスキームディープリンクを使用する場合 | | `application(_:continue:restorationHandler:)` | ユニバーサルリンク(`https://`) | メール、SMSから、または`forwardUniversalLinks = true`でユニバーサルリンクを使用する場合 | | `BrazeDelegate.braze(_:shouldOpenURL:)` | SDKによって開かれるすべてのURL | カスタムルーティングロジックが必要な場合(例:Branch、条件分岐処理、分析) | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="リンクを処理するためにアプリコードが必要な場合" } **Tip:** Branchなどのサードパーティリンクプロバイダーを使用する場合は、`BrazeDelegate.braze(_:shouldOpenURL:)`を実装してURLをインターセプトし、プロバイダーのSDKに転送します。完全な例については、[ディープリンク用のBranch](https://www.braze.com/docs/ja/ja/partners/message_orchestration/deeplinking/branch_for_deeplinking)を参照してください。 ## BrazeとBranchを併用する {#branch} [Branch](https://www.braze.com/docs/ja/ja/partners/message_orchestration/deeplinking/branch_for_deeplinking)をリンクプロバイダーとして使用する場合、標準的なユニバーサルリンクの設定に加えて、いくつかの追加ステップが必要です。 1. **Branch SDK**:[Branchのドキュメント](https://help.branch.io/developers-hub/docs/native-sdks-overview)に従ってBranch SDKを統合します。 2. **Associated Domains**:Xcodeの**Signing & Capabilities**でBranchドメイン(例:`applinks:yourapp.app.link`)を追加します。 3. **BrazeDelegate**:BranchリンクをBrazeが直接処理するのではなく、Branch SDKにルーティングするために`braze(_:shouldOpenURL:)`を実装します。 4. **ユニバーサルリンクの転送**:Braze SDKの設定で`configuration.forwardUniversalLinks = true`を設定します。 実装の詳細とデバッグのガイダンスについては、[ディープリンク用のBranch](https://www.braze.com/docs/ja/ja/partners/message_orchestration/deeplinking/branch_for_deeplinking)を参照してください。 # ディープリンクのトラブルシューティング Source: /docs/ja/developer_guide/push_notifications/deep_linking_troubleshooting/index.md # ディープリンクのトラブルシューティング {#deep-linking-troubleshooting} > このページでは、iOSにおける一般的なディープリンクの問題と、その診断方法について説明します。適切なリンクタイプの選び方については、[iOSディープリンクガイド](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/ios_deep_linking_guide)を参照してください。実装の詳細については、[ディープリンク](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking?sdktab=swift)を参照してください。 ## カスタムスキームのディープリンクが正しいビューを開かない {#custom-scheme-deep-link-doesnt-open-the-correct-view} カスタムスキームのディープリンク(例:`myapp://products/123`)がアプリを開くものの、意図した画面に遷移しない場合: 1. **スキームが登録されていることを確認します。** Xcodeで、`Info.plist`の`CFBundleURLTypes`にスキームがリストされていることを確認してください。 2. **ハンドラーを確認します。** `application(_:open:options:)`にブレークポイントを設定し、呼び出されていることを確認して`url`パラメーターを検査してください。 3. **リンクを単独でテストします。** ターミナルから以下のコマンドを実行して、Brazeの外でディープリンクをテストしてください: ```bash xcrun simctl openurl booted "myapp://products/123" ``` ここでリンクが機能しない場合、問題はアプリのURL処理にあり、Brazeの問題ではありません。 4. **URLの形式を確認します。** キャンペーンに設定されたURLが、ハンドラーが期待する形式と一致しているか確認してください。よくある間違いには、パスコンポーネントの欠落や大文字小文字の誤りがあります。 ## ユニバーサルリンクがアプリではなくSafariで開く {#universal-link-opens-in-safari-instead-of-the-app} ユニバーサルリンク(例:`https://myapp.com/products/123`)がアプリではなくSafariで開く場合: ### Associated Domainsエンタイトルメントを確認する {#verify-the-associated-domains-entitlement} Xcodeで、アプリターゲット > **Signing & Capabilities** に移動し、**Associated Domains** の下に`applinks:yourdomain.com`がリストされていることを確認してください。 ### AASAファイルを検証する {#validate-the-aasa-file} Apple App Site Association(AASA)ファイルは、以下のいずれかの場所にホストされている必要があります: - `https://yourdomain.com/.well-known/apple-app-site-association` - `https://yourdomain.com/apple-app-site-association` 以下を確認してください: - ファイルが有効な証明書を使用してHTTPS経由で提供されていること。 - `Content-Type`が`application/json`であること。 - ファイルサイズが128 KB未満であること。 - `appID`がチームIDとバンドルIDに一致していること(例:`ABCDE12345.com.example.myapp`)。 - `paths`または`components`配列に、期待するURLパターンが含まれていること。 AASAの検証は、[Appleの検索検証ツール](https://search.developer.apple.com/appsearch-validation-tool/)を使用するか、以下のコマンドを実行して行えます: ```bash swcutil dl -d yourdomain.com ``` ### `AppDelegate`を確認する {#check-the-appdelegate} `application(_:continue:restorationHandler:)`が`AppDelegate`に実装されており、`NSUserActivity`を正しく処理していることを確認してください: ```swift func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { return false } // Handle the URL return true } ``` ### Braze SDKの設定を確認する {#verify-braze-sdk-configuration} Brazeから配信されるプッシュ通知、アプリ内メッセージ、またはContent Cardsからユニバーサルリンクを使用している場合、`forwardUniversalLinks`が有効になっていることを確認してください: ```swift let configuration = Braze.Configuration(apiKey: "", endpoint: "") configuration.forwardUniversalLinks = true ``` **Note:** ユニバーサルリンクの転送には、アプリケーションのエンタイトルメントへのアクセスが必要です。シミュレーターで実行している場合、これらのエンタイトルメントは直接利用できません。シミュレーターでテストするには、**Copy Bundle Resources** ビルドフェーズに`.entitlements`ファイルを追加してください。 ### 長押しの問題を確認する {#check-for-the-long-press-issue} ユニバーサルリンクを長押しして**開く**を選択すると、iOSがそのドメインのユニバーサルリンクの関連付けを「解除」する場合があります。これはiOSの既知の動作です。リセットするには、リンクをもう一度長押しして**[アプリ名]で開く**を選択してください。 ## メールからのディープリンクでアプリが開かない {#deep-link-from-email-doesnt-open-the-app} メール内のリンクは、メールサービスプロバイダー(ESP)のクリックトラッキングシステムを経由します。このシステムはリンクをトラッキングドメイン(例:`https://click.yourdomain.com/...`)でラップします。メールからユニバーサルリンクを機能させるには、メインドメインだけでなく、クリックトラッキングドメイン上でもAASAファイルを設定する必要があります。 ### クリックトラッキングドメインのAASAを確認する {#verify-click-tracking-domain-aasa} 1. メールサービスプロバイダー(ESP)の設定(SendGrid、SparkPost、またはAmazon SES)から、クリックトラッキングドメインを特定します。 2. AASAファイルを`https://your-click-tracking-domain/.well-known/apple-app-site-association`にホストします。 3. クリックトラッキングドメイン上のAASAファイルに、同じ`appID`と有効なパスパターンが含まれていることを確認してください。 ESP固有の設定手順については、[ユニバーサルリンクとアプリリンク](https://www.braze.com/docs/ja/ja/user_guide/channels/email/customize/universal_links_and_app_links)を参照してください。 ### リダイレクトチェーンを確認する {#check-the-redirect-chain} 一部のESPは、クリックトラッキングURLから最終URLへのリダイレクトを行います。ユニバーサルリンクは、iOSが*最初の*ドメイン(クリックトラッキングドメイン)をアプリに関連付けられていると認識した場合にのみ機能します。リダイレクトがAASAチェックをバイパスした場合、リンクはSafariで開きます。 テスト方法: 1. テストメールを自分に送信します。 2. リンクを長押ししてURLを確認します。これがクリックトラッキングURLです。 3. このドメインに有効なAASAファイルがあることを確認してください。 ## ディープリンクがプッシュ通知からは機能するが、アプリ内メッセージからは機能しない(またはその逆) {#deep-link-works-from-push-but-not-from-in-app-messages-or-vice-versa} ### BrazeDelegateを確認する {#check-the-brazedelegate} `BrazeDelegate.braze(_:shouldOpenURL:)`を実装している場合、すべてのチャネルでリンクが一貫して処理されていることを確認してください。`context`パラメーターにはソースチャネルが含まれます。特定のチャネルからのリンクを誤ってフィルタリングしている条件付きロジックがないか確認してください。 ### 詳細ログを有効にする {#enable-verbose-logging} [詳細ログを有効にして](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging)、問題を再現します。`Opening`ログエントリを探してください: ``` Opening '': - channel: - useWebView: - isUniversalLink: ``` 機能しているチャネルと機能していないチャネルのログ出力を比較してください。`useWebView`や`isUniversalLink`の違いは、SDKがリンクを異なる方法で解釈していることを示しています。 ### カスタム表示デリゲートを確認する {#check-for-custom-display-delegates} カスタムのアプリ内メッセージ表示デリゲートやContent Cardsのクリックハンドラーを使用している場合、リンクイベントがBraze SDKに正しく渡されて処理されていることを確認してください。 ## 「アプリ内でWeb URLを開く」で空白ページや壊れたページが表示される {#open-web-url-inside-app-shows-a-blank-or-broken-page} **アプリ内でWeb URLを開く**を選択した結果、WebViewが空白または壊れた状態で表示される場合: 1. **URLがHTTPSを使用していることを確認します。** SDKのWebViewはATS準拠のURLを必要とします。HTTPリンクはサイレントに失敗します。 2. **Content Security Policyヘッダーを確認します。** 対象のWebページが`X-Frame-Options: DENY`または制限的な`Content-Security-Policy`を設定している場合、WebViewでのレンダリングがブロックされます。 3. **カスタムスキームへのリダイレクトを確認します。** Webページがカスタムスキーム(例:`myapp://`)にリダイレクトする場合、WebViewはそれを処理できません。 4. **SafariでURLをテストします。** デバイス上のSafariでページが読み込まれない場合、WebViewでも読み込まれません。 ## BranchとBrazeのトラブルシューティング {#branch} [Branch](https://www.braze.com/docs/ja/ja/partners/message_orchestration/deeplinking/branch_for_deeplinking)をリンクプロバイダーとして使用している場合: ### BrazeDelegateがBranchにルーティングしていることを確認する {#verify-the-brazedelegate-routes-to-branch} `BrazeDelegate`がBranchリンクをインターセプトし、Branch SDKに渡す必要があります。以下を確認してください: ```swift func braze(_ braze: Braze, shouldOpenURL context: Braze.URLContext) -> Bool { if let host = context.url.host, host.contains("app.link") { // Route to Branch SDK Branch.getInstance.handleDeepLink(context.url) return false } // Let Braze handle other links return true } ``` `shouldOpenURL`がBranchリンクに対して`true`を返す場合、BrazeはBranchにルーティングせず直接処理します。 ### Branchリンクドメインを確認する {#check-branch-link-domain} `BrazeDelegate`内のBranchドメインが、実際のBranchリンクドメインと一致していることを確認してください。Branchはいくつかのドメイン形式を使用します: - `yourapp.app.link`(デフォルト) - `yourapp-alternate.app.link`(代替) - カスタムドメイン(Branchダッシュボードで設定されている場合) ### 両方のSDKのログを有効にする {#enable-both-sdks-logging} リンクがチェーンのどこで途切れているかを診断するには: 1. [Brazeの詳細ログ](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging)を有効にします。SDKがリンクを受信したことを確認するために、`Opening '':`エントリを探してください。 2. [Branchテストモード](https://help.branch.io/developers-hub/docs/ios-basic-integration#test-deep-linking)を有効にします。Branchダッシュボードでリンククリックイベントを確認してください。 3. Brazeがリンクを記録しているのにBranchがクリックを認識しない場合、`BrazeDelegate`のルーティングロジックに問題がある可能性が高いです。 ### Branchダッシュボードの設定を確認する {#check-branch-dashboard-configuration} Branchダッシュボードで以下を確認してください: - アプリの**バンドルID**と**チームID**がXcodeプロジェクトと一致していること。 - **Associated Domains**にBranchリンクドメインが含まれていること。 - BranchのAASAファイルが有効であること(Branchは`app.link`ドメイン上で自動的にホストします)。 ### Branchリンクを単独でテストする {#test-branch-links-independently} 問題を切り分けるために、Brazeの外でBranchリンクをテストしてください: 1. デバイスのSafariでBranchリンクを開きます。アプリが開かない場合、問題はBranchまたはAASAの設定にあり、Brazeの問題ではありません。 2. Branchリンクをメモアプリに貼り付けてタップします。ユニバーサルリンクは、Safariのアドレスバーからよりもメモアプリからの方が確実に動作します。 ## 一般的なデバッグのヒント {#general-debugging-tips} ### 詳細ログを使用する {#use-verbose-logging} [詳細ログを有効にする](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging)と、SDKがリンクをどのように処理しているかを正確に確認できます。探すべき主要なエントリ: | ログエントリ | 意味 | |---|---| | `Opening '': - channel: notification` | SDKがプッシュ通知からのリンクを処理しています | | `Opening '': - channel: inAppMessage` | SDKがアプリ内メッセージからのリンクを処理しています | | `Opening '': - channel: contentCard` | SDKがContent Cardsからのリンクを処理しています | | `useWebView: true` | SDKがアプリ内WebViewでURLを開きます | | `isUniversalLink: true` | SDKがURLをユニバーサルリンクとして識別しました | {: .reset-td-br-1 .reset-td-br-2 aria-label="詳細ログの使用" } これらのログの読み方について詳しくは、[詳細ログの読み方](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging)を参照してください。 ### リンクを単独でテストする {#test-links-in-isolation} Braze経由でテストする前に、ディープリンクまたはユニバーサルリンクが単独で動作することを確認してください: - **カスタムスキーム**:ターミナルで`xcrun simctl openurl booted "myapp://path"`を実行します。 - **ユニバーサルリンク**:物理デバイスのメモアプリにURLを貼り付けてタップします。Safariのアドレスバーからはテストしないでください。iOSは入力されたURLとタップされたリンクを異なる方法で処理します。 - **Branchリンク**:デバイスのメモアプリからBranchリンクを開きます。 ### 物理デバイスでテストする {#test-on-a-physical-device} ユニバーサルリンクはiOSシミュレーターでは限定的なサポートしかありません。正確な結果を得るために、必ず物理デバイスでテストしてください。シミュレーターでテストする必要がある場合は、**Copy Bundle Resources** ビルドフェーズに`.entitlements`ファイルを追加してください。 # Braze SDKのサイレントプッシュ通知を設定する Source: /docs/ja/developer_guide/push_notifications/silent/index.md # サイレントプッシュ通知 > Braze SDKのサイレントプッシュ通知の設定方法を学習する。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=android). ## Setting up silent push notifications Silent notifications are available through the Braze [Messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/). To take advantage of them, you need to set the `send_to_sync` flag to `true` within the [Android push object](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/android_object/) and ensure there are no `title` or `alert` fields set as it will cause errors when used alongside `send_to_sync`—however, you can include data `extras` within the object. ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift). ## iOS limitations The iOS operating system may gate notifications for some features. Note that if you are experiencing difficulties with these features, the iOS's silent notifications gate might be the cause. For more details, refer to Apple's [instance method](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application) and [unreceived notifications](https://developer.apple.com/library/content/technotes/tn2265/_index.html#//apple_ref/doc/uid/DTS40010376-CH1-TNTAG23) documentation. ## Setting up silent push notifications To use silent push notifications to trigger background work, you must configure your app to receive notifications even when it is in the background. To do this, add the Background Modes capability using the **Signing & Capabilities** pane to the main app target in Xcode. Select the **Remote notifications** checkbox. ![Xcode showing the "remote notifications" mode checkbox under "capabilities".](https://www.braze.com/docs/ja/ja/assets/img_archive/background_mode.png?15bb65e9a98f4b01af0c73c3917d6950 "background mode enabled") Even with the remote notifications background mode enabled, the system will not launch your app into the background if the user has force-quit the application. The user must explicitly launch the application or reboot the device before the app can be automatically launched into the background by the system. For more information, refer to [pushing background updates](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app) and the `application:didReceiveRemoteNotification:fetchCompletionHandler:` [documentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplicationDelegate_Protocol/index.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:didReceiveRemoteNotification:fetchCompletionHandler:). ## Sending silent push notifications To send a silent push notification, set the `content-available` flag to `1` in a push notification payload. **Note:** What Apple calls a remote notification is just a normal push notification with the `content-available` flag set. The `content-available` flag can be set in the Braze dashboard as well as within our [Apple push object](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/apple_object/) in the [messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/). **Warning:** Attaching both a title and body with `content-available=1` is not recommended because it can lead to undefined behavior. To ensure that a notification is truly silent, exclude both the title and body when setting the `content-available` flag to `1.` For further details, refer to the official [Apple documentation on background updates](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app). ![The Braze dashboard showing the "content-available" checkbox found in the "settings" tab of the push composer.](https://www.braze.com/docs/ja/ja/assets/img_archive/remote_notification.png?7c9ef06cb8e9c148d37019f5e01d0ce6 "content available") When sending a silent push notification, you might also want to include some data in the notification payload, so your application can reference the event. This could save you a few networking requests and increase the responsiveness of your app. ## Ignoring internal push notifications Braze uses silent push notifications to internally handle certain advanced features, such as uninstall tracking. If your app takes automatic actions on application launches or background pushes, consider gating that activity so it's not triggered by any internal push notifications. For example, if you have logic that calls your servers for new content upon every background push or application launch, you may want to prevent triggering Braze’s internal pushes to avoid unnecessary network traffic. Because Braze sends certain kinds of internal pushes to all users at approximately the same time, significant server load may occur if on-launch network calls from internal pushes are not gated. ### Step 1: Check your app for automatic actions Check your application for automatic actions in the following places and update your code to ignore Braze’s internal pushes: 1. **Push Receivers.** Background push notifications will call `application:didReceiveRemoteNotification:fetchCompletionHandler:` on the `UIApplicationDelegate`. 2. **Application Delegate.** Background pushes can launch [suspended](https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle) apps into the background, triggering the `application:willFinishLaunchingWithOptions:` and `application:didFinishLaunchingWithOptions:` methods on your `UIApplicationDelegate`. Check the `launchOptions` of these methods to determine if the application has been launched from a background push. ### Step 2: Use the internal push utility method You can use the static utility method in `Braze.Notifications` to check if your app has received or was launched by a Braze internal push. [`Braze.Notifications.isInternalNotification(_:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/notifications-swift.class/isinternalnotification(_:)) returns `true` for all Braze internal push notifications, which include uninstall tracking and [Feature flags](https://www.braze.com/docs/ja/ja/user_guide/messaging/feature_flags/) sync notifications. For example: ```swift func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { if (!Braze.Notifications.isInternalNotification(userInfo)) { // Gated logic here (for example pinging server for content) } } ``` ```objc - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { if (![BRZNotifications isInternalNotification:userInfo]) { // Gated logic here (for example pinging server for content) } } ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=android). ## Setting up silent push notifications Silent notifications are available through the Braze [Messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/). To take advantage of them, you need to set the `send_to_sync` flag to `true` within the [Android push object](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/android_object/) and ensure there are no `title` or `alert` fields set as it will cause errors when used alongside `send_to_sync`—however, you can include data `extras` within the object. # Braze SDK向けにリッチプッシュ通知を設定する Source: /docs/ja/developer_guide/push_notifications/rich/index.md # リッチプッシュ通知 > Braze SDKのリッチプッシュ通知の設定方法を学習。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift). ## Setting up rich push notifications ### Step 1: Creating a service extension To create a [notification service extension](https://developer.apple.com/reference/usernotifications/unnotificationserviceextension), navigate to **File > New > Target** in Xcode and select **Notification Service Extension**. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/ios10_se_at.png?ad077697c9a4c7c7bc3ca07a6405c05d){: style="max-width:90%"} Ensure that **Embed In Application** is set to embed the extension in your application. ### Step 2: Setting up the notification service extension A notification service extension is its own binary that is bundled with your app. It must be set up in the [Apple Developer Portal](https://developer.apple.com) with its own app ID and provisioning profile. The notification service extension's bundle ID must be distinct from your main app target's bundle ID. For example, if your app's bundle ID is `com.company.appname`, you can use `com.company.appname.AppNameServiceExtension` for your service extension. ### Step 3: Adding an App Group In Xcode, add the App Groups capability from the **Signing & Capabilities** pane to your main app target as well as the Notification Service Extension target. Then, click the **+** button. Use your app's bundle ID to create the app group. For example, if your app's bundle ID is `com.company.appname`, you can name your app group `group.com.company.appname.xyz`. **Important:** App Groups in this context refer to Apple's [App Groups Entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups) and not your Braze workspace (previously app group) ID. You need a shared App Group so your main app and the Notification Service Extension can access shared data. If you do not add your app to an app group, your app may fail to populate certain fields from the push payload and will not work fully as expected. ### Step 4: Integrating rich push notifications For a step-by-step guide on integrating rich push notifications with `BrazeNotificationService`, refer to our [tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b2-rich-push-notifications). To see a sample, refer to the usage in [`NotificationService`](https://github.com/braze-inc/braze-swift-sdk/blob/main/Examples/Swift/Sources/PushNotificationsServiceExtension/NotificationService.swift) of our Examples app. #### Adding the rich push framework to your app After following the [Swift Package Manager integration guide](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/sdk_integration/?tab=swift%20package%20manager/), add `BrazeNotificationService` to your `Notification Service Extension` by doing the following: 1. In Xcode, under frameworks and libraries, select the add icon to add a framework.

![The plus icon is located under frameworks and libraries in Xcode.](https://www.braze.com/docs/ja/ja/assets/img_archive/rich_notification.png?aacc2bc0878ec1e3bf74e346f2cd7132)

2. Select the "BrazeNotificationService" framework.

![The "BrazeNotificationService framework can be selected in the modal that opens.](https://www.braze.com/docs/ja/ja/assets/img_archive/rich_notification2.png?13b077cd5a0a9723eff10fc48a6bc70c) Add the following to your Podfile: ```ruby target 'YourAppTarget' do pod 'BrazeKit' pod 'BrazeUI' pod 'BrazeLocation' end target 'YourNotificationServiceExtensionTarget' do pod 'BrazeNotificationService' end # Only include the below if you want to also integrate Push Stories target 'YourNotificationContentExtensionTarget' do pod 'BrazePushStory' end ``` **Note:** For instructions to implement Push Stories, see the [documentation](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/push_story/?tab=swift%20package%20manager). After updating the Podfile, navigate to the directory of your Xcode app project within your terminal and run `pod install`. To add `BrazeNotificationService.xcframework` to your `Notification Service Extension`, see [Manual integration](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/sdk_integration?tab=manual/). ![](https://www.braze.com/docs/ja/ja/assets/img/swift/rich_push/manual1.png?43f3a21a35ff7bd8ba2e787947a860b3) #### Using your own UNNotificationServiceExtension If you need to use your own UNNotificationServiceExtension, you can instead call [`brazeHandle`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazenotificationservice/brazehandle(request:contenthandler:)) in your `didReceive` method. ```swift import BrazeNotificationService import UserNotifications class NotificationService: UNNotificationServiceExtension { override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { if brazeHandle(request: request, contentHandler: contentHandler) { return } // Custom handling here contentHandler(request.content) } } ``` ### Step 5: Configuring the App Group in Braze Before initializing Braze, assign the name of your app group to your Braze configuration's [`push.appGroup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/push-swift.class/appgroup) property. ```swift let configuration = Braze.Configuration(apiKey: "", endpoint: "") configuration.push.appGroup = "REPLACE_WITH_APPGROUP" let braze = Braze(configuration: configuration) ``` ### Step 6: Creating a rich notification in your dashboard Your marketing team can also create rich notifications from the dashboard. Create a push notification through the push composer and attach an image or GIF, or provide a URL that hosts an image, GIF, or video. Note that assets are downloaded on the receipt of push notifications, so you should plan for large, synchronous spikes in requests if you are hosting your content. ## Prerequisites Before you can use this feature, you'll need to [integrate the Cordova Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=cordova). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=cordova). ## Setting up rich push notifications ### Step 1: Create a notification service extension In your Xcode project, create a notification service extension. For a full walkthrough, see [iOS Rich Push Notifications Tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b2-rich-push-notifications). ### Step 2: Add a new target Open your Podfile and add `BrazeNotificationService` to the notification service extension target [you just created](#cordova_step-1-create-a-notification-service-extension). If `BrazeNotificationService` is already added to a target, remove it before continuing. To avoid duplicate symbol errors, use static linking. ```ruby target 'NOTIFICATION_SERVICE_EXTENSION' do use_frameworks! :linkage => :static pod 'BrazeNotificationService' end ``` Replace `NOTIFICATION_SERVICE_EXTENSION` with the name of your notification service extension. Your Podfile should be similar to the following: ```ruby target 'MyAppRichNotificationService' do use_frameworks! :linkage => :static pod 'BrazeNotificationService' end ``` ### Step 3: Reinstall your CocoaPods dependencies In the terminal, go to your project's iOS directory and reinstall your CocoaPod dependencies. ```bash cd PATH_TO_PROJECT/platform/ios pod install ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=react%20native). ## Using Expo to enable rich push notifications For the React Native SDK, **rich push notifications are available for Android by default**. To enable rich push notifications on iOS using Expo, configure the `enableBrazeIosRichPush` property to `true` in your `expo.plugins` object in `app.json`: ```json { "expo": { "plugins": [ [ "@braze/expo-plugin", { ... "enableBrazeIosRichPush": true } ] ] } } ``` Lastly, add the bundle identifier for this app extension to your project's credentials configuration: `.BrazeExpoRichPush`. For further details on this process, refer to [Using app extensions with Expo Application Services](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=react%20native#reactnative_app-extensions). # Braze SDKのプッシュ通知を設定する Source: /docs/ja/developer_guide/push_notifications/push_stories/index.md # プッシュ通知ストーリー > Braze SDK のプッシュストーリーを設定する方法について説明します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift), which includes implementing the `UNNotification` framework. The following minimum SDK version is required to receive Push Stories: ## Setting up Push Stories ### Step 1: Adding the Notification Content Extension target {#notification-content-extension} In your app project, go to menu **File > New > Target** and add a new `Notification Content Extension` target and activate it. ![](https://www.braze.com/docs/ja/ja/assets/img/swift/push_story/add_content_extension.png?ad9e5d8cc83d88d9e26dbd2c4c8dba67) Xcode should generate a new target for you and create files automatically for you including: - `NotificationViewController.swift` - `MainInterface.storyboard` ### Step 2: Enable capabilities {#enable-capabilities} In Xcode, add the Background Modes capability using the **Signing & Capabilities** pane to the main app target. Select both the **Background fetch** and **Remote notifications** checkboxes. ![](https://www.braze.com/docs/ja/ja/assets/img/swift/push_story/enable_background_mode.png?37d0c9c4c59fb04aa930729a5539ed59) #### Adding an App Group Additionally, from the **Signing & Capabilities** pane in Xcode, add the App Groups capability to your main app target as well as the Notification Content Extension targets. Then, click the **+** button. Use your app's bundle ID to create the app group. For example, if your app's bundle ID is `com.company.appname`, you can name your app group `group.com.company.appname.xyz`. **Important:** App Groups in this context refer to Apple's [App Groups Entitlement](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_application-groups) and not your Braze workspace (previously app group) ID. If you do not add your app to an App Group, your app may fail to populate certain fields from the push payload and will not work fully as expected. ### Step 3: Adding the Push Story framework to your app {#enable-capabilities} After following the [Swift Package Manager integration guide](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/sdk_integration/?tab=swift%20package%20manager/), add `BrazePushStory` to your `Notification Content Extension`: ![In Xcode, under frameworks and libraries, select the "+" icon to add a framework.](https://www.braze.com/docs/ja/ja/assets/img/swift/push_story/spm1.png?00b81a1ac272e7247a67cd7c176a79f8) ![](https://www.braze.com/docs/ja/ja/assets/img/swift/push_story/spm2.png?9df11322d50bd385f7151ba062c0319c) Add the following line to your Podfile: ```ruby target 'YourAppTarget' do pod 'BrazeKit' pod 'BrazeUI' pod 'BrazeLocation' end target 'YourNotificationContentExtensionTarget' do pod 'BrazePushStory' end # Only include the below if you want to also integrate Rich Push target 'YourNotificationServiceExtensionTarget' do pod 'BrazeNotificationService' end ``` **Note:** For instructions to implement Rich Push, see [Rich notifications](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/customization/rich_notifications/?tab=swift%20package%20manager). After updating the Podfile, navigate to the directory of your Xcode app project within your terminal and run `pod install`. Download the latest `BrazePushStory.zip` from the [GitHub release page](https://github.com/braze-inc/braze-swift-sdk/releases), extract it, and add the `BrazePushStory.xcframework` to your project's `Notification Content Extension`. ![](https://www.braze.com/docs/ja/ja/assets/img/swift/push_story/manual1.png?cdc5b6905a824611c983facc8b541026) **Important:** Make sure that **Do Not Embed** is selected for **BrazePushStory.xcframework** under the **Embed** column. ### Step 4: Updating your notification view controller {#enable-capabilities} In `NotificationViewController.swift`, add the following line to import the header files: ```swift import BrazePushStory ``` Next, replace the default implementation by inheriting [`BrazePushStory.NotificationViewController`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazepushstory/notificationviewcontroller/): ```swift class NotificationViewController: BrazePushStory.NotificationViewController {} ``` #### Custom handling push story events If you want to implement your own custom logic to handle push story notification events, inherit `BrazePushStory.NotificationViewController` as above and override the [`didReceive`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazepushstory/notificationviewcontroller/didreceive(_:)) methods as below. ```swift import BrazePushStory import UserNotifications import UserNotificationsUI class NotificationViewController: BrazePushStory.NotificationViewController { override func didReceive(_ notification: UNNotification) { super.didReceive(notification) // Custom handling logic } override func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) { super.didReceive(response, completionHandler: completion) // Custom handling logic } } ``` ### Step 5: Setting the Notification Content Extension plist {#notification-content-extension} Open the `Info.plist` file of the `Notification Content Extension`, then add and change the following keys under `NSExtension \ NSExtensionAttributes`: | Key | Type | Value | |--------------------------------------------------|---------|------------------------| | `UNNotificationExtensionCategory` | String | `ab_cat_push_story_v2` | | `UNNotificationExtensionDefaultContentHidden` | Boolean | `YES` | | `UNNotificationExtensionInitialContentSizeRatio` | Number | `0.6` | | `UNNotificationExtensionUserInteractionEnabled` | Boolean | `YES` | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Step 5: Setting the Notification Content Extension plist #notification-content-extension" } Additionally, add the following top-level `Braze` dictionary to the same `Info.plist` file, replacing `REPLACE_WITH_APPGROUP` with the App Group you created in [Step 2](#enable-capabilities): | Key | Type | Value | |------------------|--------|--------------------------| | `Braze.AppGroup` | String | `REPLACE_WITH_APPGROUP` | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Step 5: Setting the Notification Content Extension plist #notification-content-extension" } Your `Info.plist` file should match the following image: ![](https://www.braze.com/docs/ja/ja/assets/img/swift/push_story/notificationcontentextension_plist.png?781099250e344b0bfbf448d47af7a25c) ### Step 6: Updating the Braze integration in your main app {#update-braze} Before initializing Braze, assign the name of your app group to your Braze configuration's [`push.appGroup`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/push-swift.class/appgroup) property. ```swift let configuration = Braze.Configuration(apiKey: "", endpoint: "") configuration.push.appGroup = "REPLACE_WITH_APPGROUP" let braze = Braze(configuration: configuration) ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Cordova Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=cordova). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=cordova). ## Setting up push stories ### Step 1: Create a notification content extension In your Xcode project, create a notification content extension. For a full walkthrough, see [iOS Push Stories Tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/b3-push-stories/). ### Step 2: Configure your push app group In your project's `config.xml` file, configure the push app group [you just created](#cordova_step-1-create-a-notification-content-extension). ```xml ``` Replace `PUSH_APP_GROUP` with the name of your push app group. Your `config.xml` should be similar to the following: ```xml ``` ### Step 3: Add a new target Open your Podfile and add `BrazePushStory` to the notification content extension target [you created previously](#cordova_step-1-create-a-notification-content-extension). To avoid duplicate symbol errors, use static linking. ```ruby target 'NOTIFICATION_CONTENT_EXTENSION' do use_frameworks! :linkage => :static pod 'BrazePushStory' end ``` Replace `NOTIFICATION_CONTENT_EXTENSION` with the name of your notification content extension. Your Podfile should be similar to the following: ```ruby target 'MyAppNotificationContentExtension' do use_frameworks! :linkage => :static pod 'BrazePushStory' end ``` ### Step 4: Reinstall your CocoaPods dependencies In the terminal, go to your iOS directory and reinstall your CocoaPod dependencies. ```bash cd PATH_TO_PROJECT/platform/ios pod install ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=react%20native). ## Enabling push stories For the React Native SDK, **push stories are available for Android by default**. To enable Push Stories on iOS using Expo, ensure you have an app group defined for your application. For more information, see [Adding an App Group](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/push_story/#adding-an-app-group). Next, configure the `enableBrazeIosPushStories` property to `true` and assign your app group ID to `iosPushStoryAppGroup` in your `expo.plugins` object in `app.json`: ```json { "expo": { "plugins": [ [ "@braze/expo-plugin", { ... "enableBrazeIosPushStories": true, "iosPushStoryAppGroup": "group.com.company.myApp.PushStories" } ] ] } } ``` Lastly, add the bundle identifier for this app extension to your project's credentials configuration: `.BrazeExpoPushStories`. For further details on this process, refer to [Using app extensions with Expo Application Services](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=react%20native#reactnative_app-extensions). **Warning:** If you are using Push Stories with Expo Application Services, be sure to use the `EXPO_NO_CAPABILITY_SYNC=1` flag when running `eas build`. There is a known issue in the command line which removes the App Groups capability from your extension's provisioning profile. # Braze SDK向けにソフトプッシュ通知の設定を行う Source: /docs/ja/developer_guide/push_notifications/soft_push_prompts/index.md # Web用ソフトプッシュプロンプト > Braze SDKのソフトプッシュプロンプトの設定方法を学習する。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). You'll also need to [set up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=web). If you're integrating Braze through mParticle's embedded kit on the web, see [Step 3 in mParticle's Braze Web event integration](https://docs.mparticle.com/integrations/braze/event/#web) for instructions to implement soft push prompts. ## About soft push prompts It's often a good idea for sites to implement a "soft" push prompt where you "prime" the user and make your case for sending them push notifications before requesting push permission. This is useful because the browser throttles how often you may prompt the user directly, and if the user denies permission you can never ask them again. Alternatively, if you would like to include special custom handling, instead of calling `requestPushPermission()` directly as described in the standard [Web push integration](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/web/push_notifications/integration/#step-2-browser-registration), use our [triggered in-app messages](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/triggering_messages/?tab=web). **Tip:** This can be done without SDK customization using our new [no code push primer](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/best_practices/push_primer_messages/). ## Setting up soft push prompts **Note:** This guide uses code samples from the Braze Web SDK 4.0.0+. To upgrade to the latest Web SDK version, see [SDK Upgrade Guide](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md). ### Step 1: Create a push primer campaign First, you must create a "Prime for Push" in-app messaging campaign in the Braze dashboard: 1. Create a **Modal** in-app message with the text and styling you want. 2. Next, set the on-click behavior to **Close Message**. This behavior will be customized later. 3. Add a key-value pair to the message where the key is `msg-id`, and the value is `push-primer`. 4. Assign a custom event trigger action (such as "prime-for-push") to the message. You can create the custom event manually from the dashboard if needed. ### Step 2: Remove calls In your Braze SDK integration, find and remove any calls to `automaticallyShowInAppMessages()` from within your loading snippet. ### Step 3: Update integration Finally, replace the removed call with the following snippet. Call `subscribeToInAppMessage()` before calling `openSession()`. This ensures your in-app message listener is registered in time to receive the push primer message. ```javascript import * as braze from "@braze/web-sdk"; // Be sure to remove any calls to braze.automaticallyShowInAppMessages() braze.subscribeToInAppMessage(function(inAppMessage) { // check if message is not a control variant if (inAppMessage instanceof braze.inAppMessage) { // access the key-value pairs, defined as `extras` const keyValuePairs = inAppMessage.extras || {}; // check the value of our key `msg-id` defined in the Braze dashboard if (keyValuePairs["msg-id"] === "push-primer") { // We don't want to display the soft push prompt to users on browsers // that don't support push, or if the user has already granted/blocked permission if ( braze.isPushSupported() === false || braze.isPushPermissionGranted() || braze.isPushBlocked() ) { // do not call `showInAppMessage` return; } // user is eligible to receive the native prompt // register a click handler on one of the two buttons if (inAppMessage.buttons[0]) { // Prompt the user when the first button is clicked inAppMessage.buttons[0].subscribeToClickedEvent(function() { braze.requestPushPermission( function() { // success! }, function() { // user declined } ); }); } } } // show the in-app message now braze.showInAppMessage(inAppMessage); }); ``` When you wish to display the soft push prompt to the user, call `braze.logCustomEvent` - with whatever event name triggers this in-app message. # プッシュ分析とカスタムイベントのログ記録 Source: /docs/ja/developer_guide/push_notifications/logging_message_data/index.md # プッシュ分析とカスタムイベントのログ記録 {#push-analytics-and-custom-event-logging} > このページでは、ネイティブプッシュ分析(開封、影響を受けた開封、キャンペーンレポート)とプッシュペイロードからのカスタムデータのログ記録(カスタムイベントと属性)のワークフローについて説明します。このガイドを使用して、ユースケースに該当するワークフローを特定し、プラットフォームに応じた手順に従ってください。 ## 前提条件 {#prerequisites} 開始する前に、プラットフォームの初期プッシュ通知統合を完了してください: - [Androidプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications?sdktab=android) - [Swiftプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications?sdktab=swift) - [Webプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications?sdktab=web) ## ネイティブプッシュ分析とカスタムイベントのログ記録の違い {#native-push-analytics-vs-custom-event-logging} 以下のワークフローはそれぞれ異なるレポート画面を持っています。 | 分析カテゴリ | 説明 | 表示場所 | | --- | --- | --- | | ネイティブプッシュ分析 | 開封や影響を受けた開封など、Brazeプッシュキャンペーンに紐づくプッシュ指標 | プッシュキャンペーン分析、Currentsメッセージエンゲージメントイベント、レポートビルダー | | カスタムイベントと属性 | SDKメソッドまたは`/users/track`エンドポイントを通じて定義・ログ記録する分析 | ユーザープロファイル、セグメンテーション、アクションベースのキャンペーンとキャンバス、カスタムイベント分析 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="ネイティブプッシュ分析とカスタムイベントのログ記録の違い" } **Important:** カスタムイベント(`push_notification_opened`など)のログ記録は、Brazeのネイティブプッシュ開封トラッキングとは異なります。カスタムイベントは、ネイティブプッシュキャンペーンの開封指標やプッシュアトリビューションには反映されません。 ## Brazeが自動的にログ記録するもの {#what-braze-logs-automatically} SDK統合が設定されている場合、Brazeはプッシュ開封や影響を受けた開封を含むコアチャネルインタラクションデータを自動的にログ記録します。標準的なプッシュ分析には追加のコードは不要です。自動的に収集されるデータの完全なリストについては、[SDKデータ収集](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/sdk_data_collection)を参照してください。 詳細については、以下を参照してください: - [SDKデータ収集](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/sdk_data_collection):自動的に収集されるデータとオプションデータの完全なリスト。 - [影響を受けた開封](https://www.braze.com/docs/ja/ja/user_guide/analytics/tracking/influenced_opens):Brazeが影響を受けた開封を計算する方法。 - [メッセージエンゲージメントイベント](https://www.braze.com/docs/ja/ja/user_guide/data/distribution/braze_currents/event_glossary/message_engagement_events):Currentsのダウンストリームイベントスキーマ。 ## カスタムプッシュ処理でネイティブプッシュ分析を維持する {#preserving-native-push-analytics-with-custom-push-handling} 複数のプッシュプロバイダーの統合、追加のペイロードデータの処理、またはカスタム通知表示ロジックの実装が必要な場合、カスタムプッシュハンドラーを使用することがあります。カスタムプッシュハンドラーを使用する場合でも、プッシュペイロードをBraze SDKメソッドに渡す必要があります。これにより、Brazeは埋め込まれたトラッキングデータを抽出し、ネイティブプッシュ分析(開封、影響を受けた開封、配信指標)をログ記録できます。 カスタム`FirebaseMessagingService`がある場合、`onMessageReceived`メソッド内で`BrazeFirebaseMessagingService.handleBrazeRemoteMessage(...)`を呼び出してください。`FirebaseMessagingService`サブクラスは、Androidシステムによって[フラグ付けまたは終了](https://firebase.google.com/docs/cloud-messaging/android/receive)されないよう、呼び出しから9秒以内に実行を完了する必要があることに注意してください。 ```java public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); if (BrazeFirebaseMessagingService.handleBrazeRemoteMessage(this, remoteMessage)) { // Braze processed a Braze push payload. } else { // Non-Braze payload: pass to your other handlers. } } } ``` 完全な実装例については、[Braze Android SDK Firebaseプッシュサンプルアプリ](https://github.com/braze-inc/braze-android-sdk/tree/master/samples/firebase-push)を参照してください。 手動プッシュ統合では、バックグラウンドおよびユーザー通知のコールバックをBrazeに転送します。 **バックグラウンド通知:** ```swift if let braze = AppDelegate.braze, braze.notifications.handleBackgroundNotification( userInfo: userInfo, fetchCompletionHandler: completionHandler ) { return } completionHandler(.noData) ``` **ユーザー通知レスポンス:** ```swift if let braze = AppDelegate.braze, braze.notifications.handleUserNotification( response: response, withCompletionHandler: completionHandler ) { return } completionHandler() ``` **フォアグラウンド通知:** ```swift func userNotificationCenter( _ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void ) { if let braze = AppDelegate.braze { braze.notifications.handleForegroundNotification(notification: notification) } if #available(iOS 14.0, *) { completionHandler([.banner, .list, .sound]) } else { completionHandler([.alert, .sound]) } } ``` 完全な実装例については、[Braze Swift SDK手動プッシュサンプル(`AppDelegate.swift`)](https://github.com/braze-inc/braze-swift-sdk/blob/main/Examples/Swift/Sources/PushNotifications-Manual/AppDelegate.swift)を参照してください。 Webプッシュの場合、[Webプッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications?sdktab=web)の説明に従って、サービスワーカーとSDKの初期化を設定してください。 その他のコードサンプルについては、[Braze Web SDKリポジトリ](https://github.com/braze-inc/braze-web-sdk)を参照してください。 ## プッシュペイロードからカスタムデータをログ記録する {#logging-custom-data-from-push-payloads} プッシュペイロードのキーと値のペアから、ビジネスロジックに紐づくカスタムイベントや属性などの追加データをログ記録する必要がある場合は、このセクションを使用してください。 カスタムイベントの詳細については、[カスタムイベント](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/custom_events)を参照してください。SDKメソッドを通じてカスタムイベントをログ記録するには、[カスタムイベントのログ記録](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events)を参照してください。 ### オプションA:`/users/track`エンドポイントでログ記録する {#option-a-log-with-the-userstrack-endpoint} [`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)エンドポイントを呼び出すことで、リアルタイムに分析をログ記録できます。 ユーザープロファイルを識別するには、プッシュペイロードのキーと値のペアに`braze_id`を含めてください。 **Note:** `braze_id`を渡すとプロファイルの識別のみが行われます。ペイロードの値を読み取り、ログ記録したいイベントや属性を含む`/users/track`リクエストを送信する実装ロジックは別途必要です。 ### オプションB:アプリ起動後にSDKメソッドでログ記録する {#option-b-log-with-sdk-methods-after-app-launch} ペイロードデータをローカルに保存し、アプリの初期化後にSDKメソッドを通じてカスタムイベントと属性をログ記録することもできます。このアプローチは、分析データを先に永続化し、次回のアプリ起動時にフラッシュする通知コンテンツエクステンションのフローで一般的です。 **Important:** 分析はアプリが起動するまでBrazeに送信されません。解除設定によっては、ユーザーが通知を解除してからアプリが開いて分析をフラッシュするまでに遅延が生じる場合があります。 ## 通知コンテンツエクステンションからのログ記録(Swift) {#logging-from-a-notification-content-extension-swift} 以下の手順では、Swift通知コンテンツエクステンションからカスタムイベント、カスタム属性、ユーザー属性を保存・送信する方法を説明します。 ### ステップ1:XcodeでApp Groupsを設定する {#step-1-configure-app-groups-in-xcode} Xcodeで、メインアプリターゲットに`App Groups`機能を追加します。**App Groups**をオンにし、**+**をクリックして新しいグループを追加します。アプリのバンドルIDを使用してグループ識別子を作成します(例:`group.com.company.appname.xyz`)。メインアプリターゲットとコンテンツエクステンションターゲットの両方で**App Groups**をオンにしてください。 ![メインアプリと通知エクステンションでApp Groups機能が有効になっているXcodeの画面](https://www.braze.com/docs/ja/ja/assets/img/swift/push_story/add_app_groups.png?44e3d92af533e6323db33236364b99e1) ### ステップ2:ログ記録する内容を選択する {#step-2-choose-what-to-log} スニペットを実装する前に、ログ記録したい分析カテゴリを選択してください: - **カスタムイベント:** ユーザーが行うアクション(例:フローの完了や特定のUI要素のタップ)。カスタムイベントは、アクションベースのトリガー、セグメンテーション、イベント分析に使用します。詳細については、[カスタムイベント](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/custom_events)と[カスタムイベントのログ記録](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events)を参照してください。 - **カスタム属性:** 定義するプロファイルフィールド(例:`plan_tier`や`preferred_language`)で、時間の経過とともに更新されます。詳細については、[カスタム属性](https://www.braze.com/docs/ja/ja/user_guide/data/activation/custom_data/data_types)と[ユーザー属性の設定](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_attributes)を参照してください。 - **ユーザー属性:** 標準プロファイルフィールド(例:メール、名、電話番号)。サンプルコードでは、型付き`UserAttribute`モデルで表現され、Brazeのユーザーフィールドにマッピングされます。 このセクションのヘルパーファイル(`RemoteStorage`、`UserAttribute`、`EventName Dictionary`)は、このサンプル実装で使用されるローカルユーティリティファイルです。SDK組み込みのクラスではありません。ペイロード由来のデータを`UserDefaults`に保存し、保留中のユーザー更新の型付きモデルを定義し、イベントペイロードの構築を標準化します。ローカルデータストレージの動作の詳細については、[ストレージ](https://www.braze.com/docs/ja/ja/developer_guide/storage?tab=swift)を参照してください。 **Note:** このセクションのヘルパーファイルの例はiOS固有(SwiftおよびObjective-C)です。AndroidおよびWebでのカスタムイベントと属性のログ記録方法については、[カスタムイベントのログ記録](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events)([Android](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=android)、[Web](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=web))と[ユーザー属性の設定](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_attributes)([Android](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_attributes?tab=android)、[Web](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_attributes?tab=web))を参照してください。 #### カスタムイベントの保存 {#saving-custom-events} ディクショナリを構築し、メタデータを入力し、ヘルパーファイルで保存することで分析ペイロードを作成します。 1. イベントメタデータでディクショナリを初期化します。 2. `userDefaults`を初期化してイベントデータを取得・保存します。 3. 既存の配列が見つかった場合、追加して保存します。 4. 配列が存在しない場合、新しい配列を保存します。 ```swift func saveCustomEvent(with properties: [String: Any]? = nil) { // 1 let customEventDictionary = Dictionary(eventName: "YOUR-EVENT-NAME", properties: properties) // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] { pendingEvents.append(contentsOf: [customEventDictionary]) remoteStorage.store(pendingEvents, forKey: .pendingCustomEvents) } else { // 4 remoteStorage.store([customEventDictionary], forKey: .pendingCustomEvents) } } ``` ```objc - (void)saveCustomEvent:(NSDictionary *)properties { // 1 NSDictionary *customEventDictionary = [[NSDictionary alloc] initWithEventName:@"YOUR-EVENT-NAME" properties:properties]; // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingEvents = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents] mutableCopy]; // 3 if (pendingEvents) { [pendingEvents addObject:customEventDictionary]; [remoteStorage store:pendingEvents forKey:RemoteStorageKeyPendingCustomEvents]; } else { // 4 [remoteStorage store:@[ customEventDictionary ] forKey:RemoteStorageKeyPendingCustomEvents]; } } ``` #### カスタムイベントをBrazeに送信する {#sending-custom-events-to-braze} SDKの初期化直後に、保存された分析をログ記録します。 1. 保留中のイベントをループ処理します。 2. 各イベントのキーと値のペアをループ処理します。 3. `event_name`キーを確認します。 4. 残りのキーと値のペアを`properties`ディクショナリに追加します。 5. 各カスタムイベントをログ記録します。 6. 保留中のイベントをストレージから削除します。 ```swift func logPendingCustomEventsIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] else { return } // 1 for event in pendingEvents { var eventName: String? var properties: [AnyHashable: Any] = [:] // 2 for (key, value) in event { if key == "event_name" { // 3 if let eventNameValue = value as? String { eventName = eventNameValue } else { print("Invalid type for event_name key") } } else { // 4 properties[key] = value } } // 5 if let eventName = eventName { AppDelegate.braze?.logCustomEvent(name: eventName, properties: properties) } } // 6 remoteStorage.removeObject(forKey: .pendingCustomEvents) } ``` ```objc - (void)logPendingEventsIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingEvents = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents]; // 1 for (NSDictionary *event in pendingEvents) { NSString *eventName = nil; NSMutableDictionary *properties = [NSMutableDictionary dictionary]; // 2 for (NSString* key in event) { if ([key isEqualToString:@"event_name"]) { // 3 if ([[event objectForKey:key] isKindOfClass:[NSString class]]) { eventName = [event objectForKey:key]; } else { NSLog(@"Invalid type for event_name key"); } } else { // 4 properties[key] = event[key]; } } // 5 if (eventName != nil) { [AppDelegate.braze logCustomEvent:eventName properties:properties]; } } // 6 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomEvents]; } ``` #### カスタム属性の保存 {#saving-custom-attributes} 分析ディクショナリをゼロから作成し、永続化します。 1. 属性メタデータでディクショナリを初期化します。 2. `userDefaults`を初期化して属性データを取得・保存します。 3. 既存の配列が見つかった場合、追加して保存します。 4. 配列が存在しない場合、新しい配列を保存します。 ```swift func saveCustomAttribute() { // 1 let customAttributeDictionary: [String: Any] = ["YOUR-CUSTOM-ATTRIBUTE-KEY": "YOUR-CUSTOM-ATTRIBUTE-VALUE"] // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] { pendingAttributes.append(contentsOf: [customAttributeDictionary]) remoteStorage.store(pendingAttributes, forKey: .pendingCustomAttributes) } else { // 4 remoteStorage.store([customAttributeDictionary], forKey: .pendingCustomAttributes) } } ``` ```objc - (void)saveCustomAttribute { // 1 NSDictionary *customAttributeDictionary = @{ @"YOUR-CUSTOM-ATTRIBUTE-KEY": @"YOUR-CUSTOM-ATTRIBUTE-VALUE" }; // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes] mutableCopy]; // 3 if (pendingAttributes) { [pendingAttributes addObject:customAttributeDictionary]; [remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingCustomAttributes]; } else { // 4 [remoteStorage store:@[ customAttributeDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes]; } } ``` #### カスタム属性をBrazeに送信する {#sending-custom-attributes-to-braze} SDKの初期化直後に、保存された分析をログ記録します。 1. 保留中の属性をループ処理します。 2. 各キーと値のペアをループ処理します。 3. 各カスタム属性のキーと値をログ記録します。 4. 保留中の属性をストレージから削除します。 ```swift func logPendingCustomAttributesIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] else { return } // 1 pendingAttributes.forEach { setCustomAttributesWith(keysAndValues: $0) } // 4 remoteStorage.removeObject(forKey: .pendingCustomAttributes) } func setCustomAttributesWith(keysAndValues: [String: Any]) { // 2 for (key, value) in keysAndValues { // 3 if let value = value as? [String] { setCustomAttributeArrayWithKey(key, andValue: value) } else { setCustomAttributeWithKey(key, andValue: value) } } } ``` ```objc - (void)logPendingCustomAttributesIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes]; // 1 for (NSDictionary *attribute in pendingAttributes) { [self setCustomAttributeWith:attribute]; } // 4 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomAttributes]; } - (void)setCustomAttributeWith:(NSDictionary *)keysAndValues { // 2 for (NSString *key in keysAndValues) { // 3 [self setCustomAttributeWith:key andValue:[keysAndValues objectForKey:key]]; } } ``` #### ユーザー属性の保存 {#saving-user-attributes} ユーザー属性を保存する際は、更新されるユーザーフィールド(`email`、`first_name`、`phone_number`など)をキャプチャするカスタムオブジェクトを作成します。このオブジェクトは`UserDefaults`を介した保存と取得に対応している必要があります。`UserAttribute`ヘルパーファイルの例については、**ヘルパーファイル**タブを参照してください。 1. 対応する型でエンコードされた`UserAttribute`オブジェクトを初期化します。 2. `userDefaults`を初期化してデータを取得・保存します。 3. 既存の配列が見つかった場合、追加して保存します。 4. 配列が存在しない場合、新しい配列を保存します。 ```swift func saveUserAttribute() { // 1 guard let data = try? PropertyListEncoder().encode(UserAttribute.email("USER-ATTRIBUTE-VALUE")) else { return } // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] { pendingAttributes.append(contentsOf: [data]) remoteStorage.store(pendingAttributes, forKey: .pendingUserAttributes) } else { // 4 remoteStorage.store([data], forKey: .pendingUserAttributes) } } ``` ```objc - (void)saveUserAttribute { // 1 UserAttribute *userAttribute = [[UserAttribute alloc] initWithUserField:@"USER-ATTRIBUTE-VALUE" attributeType:UserAttributeTypeEmail]; NSError *error; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:userAttribute requiringSecureCoding:YES error:&error]; if (error != nil) { // log error } // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes] mutableCopy]; // 3 if (pendingAttributes) { [pendingAttributes addObject:data]; [remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingUserAttributes]; } else { // 4 [remoteStorage store:@[data] forKey:RemoteStorageKeyPendingUserAttributes]; } } ``` #### ユーザー属性をBrazeに送信する {#sending-user-attributes-to-braze} SDKの初期化直後に、保存された分析をログ記録します。 1. `pendingAttributes`データをループ処理します。 2. 各`UserAttribute`をデコードします。 3. 属性タイプに基づいてユーザーフィールドを設定します。 4. 保留中のユーザー属性をストレージから削除します。 ```swift func logPendingUserAttributesIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] else { return } // 1 for attributeData in pendingAttributes { // 2 guard let userAttribute = try? PropertyListDecoder().decode(UserAttribute.self, from: attributeData) else { continue } // 3 switch userAttribute { case .email(let email): AppDelegate.braze?.user.set(email: email) } } // 4 remoteStorage.removeObject(forKey: .pendingUserAttributes) } ``` ```objc - (void)logPendingUserAttributesIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes]; // 1 for (NSData *attributeData in pendingAttributes) { NSError *error; // 2 UserAttribute *userAttribute = [NSKeyedUnarchiver unarchivedObjectOfClass:[UserAttribute class] fromData:attributeData error:&error]; if (error != nil) { // log error } // 3 if (userAttribute) { switch (userAttribute.attributeType) { case UserAttributeTypeEmail: [self user].email = userAttribute.userField; break; } } } // 4 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingUserAttributes]; } ``` #### RemoteStorageヘルパーファイル {#remotestorage-helper-file} ```swift enum RemoteStorageKey: String, CaseIterable { // MARK: - Notification Content Extension Analytics case pendingCustomEvents = "pending_custom_events" case pendingCustomAttributes = "pending_custom_attributes" case pendingUserAttributes = "pending_user_attributes" } enum RemoteStorageType { case standard case suite } class RemoteStorage: NSObject { private var storageType: RemoteStorageType = .standard private lazy var defaults: UserDefaults = { switch storageType { case .standard: return .standard case .suite: // Use the App Group identifier you created in Step 1. return UserDefaults(suiteName: "group.com.company.appname.xyz")! } }() init(storageType: RemoteStorageType = .standard) { self.storageType = storageType } func store(_ value: Any, forKey key: RemoteStorageKey) { defaults.set(value, forKey: key.rawValue) } func retrieve(forKey key: RemoteStorageKey) -> Any? { return defaults.object(forKey: key.rawValue) } func removeObject(forKey key: RemoteStorageKey) { defaults.removeObject(forKey: key.rawValue) } func resetStorageKeys() { for key in RemoteStorageKey.allCases { defaults.removeObject(forKey: key.rawValue) } } } ``` ```objc @interface RemoteStorage () @property (nonatomic) StorageType storageType; @property (nonatomic, strong) NSUserDefaults *defaults; @end @implementation RemoteStorage - (id)initWithStorageType:(StorageType)storageType { if (self = [super init]) { self.storageType = storageType; } return self; } - (void)store:(id)value forKey:(RemoteStorageKey)key { [[self defaults] setValue:value forKey:[self rawValueForKey:key]]; } - (id)retrieveForKey:(RemoteStorageKey)key { return [[self defaults] objectForKey:[self rawValueForKey:key]]; } - (void)removeObjectForKey:(RemoteStorageKey)key { [[self defaults] removeObjectForKey:[self rawValueForKey:key]]; } - (void)resetStorageKeys { [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomEvents]]; [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomAttributes]]; [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingUserAttributes]]; } - (NSUserDefaults *)defaults { if (!_defaults) { switch (self.storageType) { case StorageTypeStandard: _defaults = [NSUserDefaults standardUserDefaults]; break; case StorageTypeSuite: _defaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.company.appname.xyz"]; break; } } return _defaults; } - (NSString*)rawValueForKey:(RemoteStorageKey)remoteStorageKey { switch(remoteStorageKey) { case RemoteStorageKeyPendingCustomEvents: return @"pending_custom_events"; case RemoteStorageKeyPendingCustomAttributes: return @"pending_custom_attributes"; case RemoteStorageKeyPendingUserAttributes: return @"pending_user_attributes"; default: [NSException raise:NSGenericException format:@"Unexpected FormatType."]; } } ``` #### UserAttributeヘルパーファイル {#userattribute-helper-file} ```swift enum UserAttribute: Hashable { case email(String?) } // MARK: - Codable extension UserAttribute: Codable { private enum CodingKeys: String, CodingKey { case email } func encode(to encoder: Encoder) throws { var values = encoder.container(keyedBy: CodingKeys.self) switch self { case .email(let email): try values.encodeIfPresent(email, forKey: .email) } } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) let email = try values.decodeIfPresent(String.self, forKey: .email) self = .email(email) } } ``` ```objc @implementation UserAttribute - (id)initWithUserField:(NSString *)userField attributeType:(UserAttributeType)attributeType { if (self = [super init]) { self.userField = userField; self.attributeType = attributeType; } return self; } - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.userField forKey:@"userField"]; [encoder encodeInteger:self.attributeType forKey:@"attributeType"]; } - (id)initWithCoder:(NSCoder *)decoder { if (self = [super init]) { self.userField = [decoder decodeObjectForKey:@"userField"]; NSInteger attributeRawValue = [decoder decodeIntegerForKey:@"attributeType"]; self.attributeType = (UserAttributeType) attributeRawValue; } return self; } @end ``` #### EventNameディクショナリヘルパーファイル {#eventname-dictionary-helper-file} ```swift extension Dictionary where Key == String, Value == Any { init(eventName: String, properties: [String: Any]? = nil) { self.init() self[PushNotificationKey.eventName.rawValue] = eventName if let properties = properties { for (key, value) in properties { self[key] = value } } } } ``` ```objc @implementation NSMutableDictionary (Helper) + (instancetype)dictionaryWithEventName:(NSString *)eventName properties:(NSDictionary *)properties { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; dict[@"event_name"] = eventName; if (properties) { for (id key in properties) { dict[key] = properties[key]; } } return dict; } @end ``` ## 結果の分析 {#analyzing-results} 分析カテゴリに対応するレポート画面を使用してください: | 分析カテゴリ | Brazeでの確認場所 | | --- | --- | | ネイティブプッシュ分析 | キャンペーンレベルのプッシュ開封指標を確認するには、プッシュキャンペーンの**キャンペーン Analytics**ページに移動します。指標の定義については、[影響を受けた開封](https://www.braze.com/docs/ja/ja/user_guide/analytics/tracking/influenced_opens)を参照してください。カスタム分析ビューを作成するには、**Analytics** > **Report Builder (New)**に移動します。操作手順については、[レポートビルダー](https://www.braze.com/docs/ja/ja/user_guide/analytics/reports/report_builder)を参照してください。ウェアハウスレベルのイベントスキーマについては、[メッセージエンゲージメントイベント](https://www.braze.com/docs/ja/ja/user_guide/data/distribution/braze_currents/event_glossary/message_engagement_events)を参照してください。 | | カスタムイベントと属性 | カスタムイベントのトレンドを確認するには、**Analytics** > **カスタムイベントレポート**に移動します。詳細については、[カスタムイベント](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/custom_events)を参照してください。ユーザーレベルの値を確認するには、**ユーザーを検索**ページに移動してプロファイルを開きます。手順については、[ユーザープロファイル](https://www.braze.com/docs/ja/ja/user_guide/audience/manage_audience/user_profiles)を参照してください。これらの値でオーディエンスをフィルタリングするには、**Audience** > **セグメント**に移動します。操作手順については、[セグメントの作成](https://www.braze.com/docs/ja/ja/user_guide/audience/segments/creating_a_segment)と[セグメンテーションフィルター](https://www.braze.com/docs/ja/ja/user_guide/audience/segments/segmentation_filters)のフィルターオプションを参照してください。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="結果の分析" } カスタムレポートの作成については、[レポートビルダー](https://www.braze.com/docs/ja/ja/user_guide/analytics/reports/report_builder)を参照してください。 ## 関連リファレンス {#related-references} - [プッシュ通知](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications) - [カスタムイベントのログ記録](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events) - [カスタムイベント](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/custom_events) - [ユーザートラッキングエンドポイント(`/users/track`)](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track) - [Braze Android SDKリポジトリ](https://github.com/braze-inc/braze-android-sdk) - [Braze Swift SDKリポジトリ](https://github.com/braze-inc/braze-swift-sdk) - [Braze Web SDKリポジトリ](https://github.com/braze-inc/braze-web-sdk) # テストメッセージを送信する Source: /docs/ja/developer_guide/push_notifications/sending_test_messages/index.md # Sending test messages > Before sending out a messaging campaign to your users, you may want to test it to make sure it looks right and operates in the intended manner. You can use the dashboard to create and send test messages with push notifications, in-app messages (IAM), or email. ## Sending a test message ### Step 1: Create a designated test segment After you set up a test segment, you can use it to test any of your Braze messaging channels. When set up correctly, this only needs to be done a single time. To set up a test segment, go to **Segments** and create a new segment. Select **Add Filter**, then choose a one of the test filters. ![A Braze test campaign displaying the filters available in the targeting step.](https://www.braze.com/docs/ja/ja/assets/img_archive/testmessages1.png?c440e858d187b30c92b316dfa12b9774) With test filters, you can ensure that only users with a specific email address or [external user ID](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/analytics/setting_user_ids/#setting-user-ids) are sent the test message. ![A dropdown menu displaying several filters listed under a heading that reads Testing](https://www.braze.com/docs/ja/ja/assets/img_archive/testmessages2.png?8c289defede0c6ba588c9b8ba8d0c9f5) Both email address and external user ID filters offer the following options: | Operator | Description | |------------------|--------------------------------------------------------------------------------------------------------------------------------| | `equals` | This will look for an exact match of the email or user ID that you provide. Use this if you only want to send the test campaigns to devices associated with a single email or user ID. | | `does not equal` | Use this if you want to exclude a particular email or user ID from test campaigns. | | `matches` | This will find users that have email addresses or user IDs that match part of the search term you provide. You could use this to find only the users that have an `@yourcompany.com` address, allowing you to send messages to everyone on your team. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Step 1: Create a designated test segment a class="margin-fix" name="test-segment"/a" } You can select multiple specific emails using the "`matches`" option and separating the email addresses with a | character. For example: "`matches`" "`email1@braze.com` | `email2@braze.com`". You can also combine multiple operators together. For example, the test segment could include an email address filter that "`matches`" "`@braze.com`" and another filter that "`does not equal`" "`sales@braze.com`". After adding the testing filters to your test segment, you can verify it's working by selecting **Preview** or by selecting **Settings** > **CSV Export All User Data** to export that segment's user data to a CSV file. ![A section of a Braze campaign titled Segment Details](https://www.braze.com/docs/ja/ja/assets/img_archive/testmessages3.png?78e031a18aad06f510fd2ac4946bf7c5) **Note:** Exporting the segment's User Data to a CSV file is the most accurate verification method, as the preview will only show a sample of your users and may not include all users. ### Step 2: Send the message You can send a message using the Braze dashboard or the command line. To send test push notifications or in-app messages, you need to target your previously created test segment. Begin by creating your campaign and following the usual steps. When you reach the **Target Audiences** step, select your test segment from the dropdown menu. ![A Braze test campaign displaying the segments available in the targeting step.](https://www.braze.com/docs/ja/ja/assets/img_archive/test_segment.png?25ae32cc99d02e6dcdd9b66a0adf75e4) Confirm your campaign and launch it to test your push notification and in-app messages. **Note:** Be sure to select **Allow users to become re-eligible to receive campaign** under the **Schedule** portion of the campaign composer if you intend to use a single campaign to send a test message to yourself more than once. If you're only testing email messages, you do not necessarily have to set up a test segment. In the first step of the campaign composer where you compose your campaign's email message, click **Send Test** and enter the email address to which you wish to send a test email. ![A Braze campaign with the Test Send tab selected](https://www.braze.com/docs/ja/ja/assets/img_archive/testmessages45.png?883cb58cd3adf2e8315817db896b7914) **Tip:** You can also enable or disable [TEST (or SEED)](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/email_settings/#append-email-subject-lines) being appended on your test messages. Alternatively, you can send a single notification using cURL and the [Braze Messaging API](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/). Note that these examples make a request using the `US-01` instance. To find out yours, refer to [API endpoints](https://www.braze.com/docs/ja/ja/api/basics/#endpoints). ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer {BRAZE_API_KEY}" -d '{ "external_user_ids":["EXTERNAL_USER_ID"], "messages": { "android_push": { "title":"Test push title", "alert":"Test push", "extra":{ "CUSTOM_KEY":"CUSTOM_VALUE" } } } }' https://rest.iad-01.braze.com/messages/send ``` ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer {BRAZE_API_KEY}" -d '{ "external_user_ids":["EXTERNAL_USER_ID"], "messages": { "apple_push": { "alert": "Test push", "extra": { "CUSTOM_KEY" :"CUSTOM_VALUE" } } } }' https://rest.iad-01.braze.com/messages/send ``` ```bash curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer {BRAZE_API_KEY}" -d '{ "external_user_ids":["EXTERNAL_USER_ID"], "messages": { "kindle_push": { "title":"Test push title", "alert":"Test push", "extra":{ "CUSTOM_KEY":"CUSTOM_VALUE" } } } }' https://rest.iad-01.braze.com/messages/send ``` Replace the following: | Placeholder | Description | |---------------------|-----------------------------------------------------------| | `BRAZE_API_KEY` | Your Braze API key used for authentication. In Braze, go to **Settings** > **API Keys** to locate your key. | | `EXTERNAL_USER_ID` | The external user ID used to send your message to a specific user. In Braze, go to **Audience** > **Search users**, then search for a user. | | `CUSTOM_KEY` | (Optional) A custom key for additional data. | | `CUSTOM_VALUE` | (Optional) A custom value assigned to your custom key. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Step 2: Send the message" } ## Test limitations There are a few situations where test messages don't have complete feature parity with launching a campaign or Canvas to a real set of users. In these instances, to validate this behavior, you should launch the campaign or Canvas to a limited set of test users. - Viewing the Braze [preference center](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/managing_user_subscriptions/#subscription-groups) from **Test Messages** will cause the submit button to be grayed out. - The list-unsubscribe header is not included in emails sent by the test message functionality. - For in-app messages and Content Cards, the target user must have a push token for the target device. # プッシュサブスクリプションの状態について Source: /docs/ja/developer_guide/push_notifications/subscription_states/index.md # プッシュサブスクリプションの状態について ## Push subscription states {#push-sub-states} A "Push Subscription State" in Braze identifies a **user's** global preference for their desire to receive push notifications. Because the subscription state is user-based, it is not specific to any individual app. Subscription states become helpful flags when deciding which users to target for push notifications. **Note:** A user's push subscription state applies to their entire user profile, which includes all of the user's devices. The following subscription state options exist: `Subscribed`, `Opted-In`, and `Unsubscribed`. By default, for your user to receive your messages through push, their push subscription state must be either `Subscribed` or `Opted-In`, and they must have foreground push enabled. You can override this setting if needed when composing a message. |Opt-in State|Description| |---|---| |`Subscribed`| Default push subscription state when a user profile is created in Braze. | |`Opted-In`| A user has explicitly expressed a preference to receive push notifications. Braze automatically moves a user's opt-in state to `Opted-In` if the user accepts an OS-level push prompt.

This does not apply to Android 12 or below users.| |`Unsubscribed`| A user explicitly unsubscribed from push through your application or other methods your brand provides. By default, Braze push campaigns target only users that are `Subscribed` or `Opted-in` for push.| {: .reset-td-br-1 .reset-td-br-2 aria-label="Push subscription states #push-sub-states" } **Important:** Braze does not automatically change a user's push subscription state to `Unsubscribed`. Remember that if a user's push subscription state is `Unsubscribed`, then the user's `Foreground Push Enabled` filter in segmentation is `false`. ### Push registration and reachable users Push subscription state reflects a user's preference, but whether they count as **reachable** for push in the dashboard also depends on [push registration](https://www.braze.com/docs/ja/ja/user_guide/channels/push/push_setup/push_token_lifecycle/)—that is, a valid foreground push token on their profile. For how Braze calculates channel-level counts, see [Measure segment size](https://www.braze.com/docs/ja/ja/user_guide/audience/segments/measuring_segment_size/). - **Push campaigns and Canvases:** Users who aren't push registered aren't included in **Reachable users** for Android Push or iOS Push in audience statistics, even when their push subscription state is `Subscribed` or `Opted-In`. - **Other channels:** The same users can still count as reachable for other channels they qualify for (for example, email or in-app messages). - **Segments:** Segment membership follows your filters. Users without push registration remain in the segment unless a filter excludes them (for example, **Foreground Push Enabled**). Total segment membership can be higher than the sum of users shown in push-specific **Reachable users** rows. A user profile can show push subscription state `Subscribed` while no push token is assigned. Those users still don't count toward **Reachable users** for Android Push or iOS Push until Braze records a valid token. For filter definitions, see [Segmentation filters](https://www.braze.com/docs/ja/ja/user_guide/audience/segments/segmentation_filters/). ### Updating push subscription states {#update-push-subscription-state} Review the following ways to update a user's push subscription state: #### Automatic opt-in (default) By default, Braze sets a user's push subscription state to `Opted-In` when they first authorize push notifications for your app. Braze also does this when a user re-enables push permissions in their system settings after previously disabling them. To disable this default behavior, add the following property to your Android Studio project's `braze.xml` file: ```xml false ``` On iOS, a new install typically shows push subscription state **`Subscribed`** until the user allows notifications. After the user selects **Allow** on the OS prompt, Braze sets the state to **`Opted-In`** when automatic opt-in is enabled. If the user selects **Don't Allow** and later turns push on in iOS Settings, the state updates after the user logs a session—not at the moment they change Settings. Starting with [Braze Swift SDK version 7.5.0](https://github.com/braze-inc/braze-swift-sdk/releases/tag/7.5.0), you can disable or further customize this behavior by adding the `optInWhenPushAuthorized` configuration to your Xcode project's `AppDelegate.swift` file: ```swift configuration.optInWhenPushAuthorized = false // disables the default behavior let braze = Braze(configuration: configuration) AppDelegate.braze = braze ``` #### SDK integration You can update a user's subscription state with the Braze SDK using the `setPushNotificationSubscriptionType` method on [Web](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.user.html#setpushnotificationsubscriptiontype), [Android](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze-user/set-push-notification-subscription-type.html), or [iOS](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/user-swift.class/set(pushnotificationsubscriptionstate:)). For example, you can use this method to create a settings page in your app where users can manually enable or disable push notifications. #### REST API You can update a user's subscription state with the Braze REST API using the [`/users/track` endpoint](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track/) to update their [`push_subscribe`](https://www.braze.com/docs/ja/ja/api/objects_filters/user_attributes_object) attribute. ### Differences between push enablement and push subscription status Push enablement refers to whether a user has granted OS- or browser-level permission to receive notifications on a specific device. Push subscription state is a Braze-level setting that represents a user's global preference for receiving push across their profile. When automatic opt-in is enabled (the default), Braze updates a user's push subscription state to `Opted-In` when they authorize push notifications for your app or re-enable permissions in their system settings (for example, on iOS, Android 13+, and supported web browsers). Otherwise, the user's push subscription state remains `Subscribed` until you explicitly change it using an SDK method or REST API call. Braze does not automatically change a user's push subscription state to `Unsubscribed` when they opt out of notifications at the OS, browser, or app level. To update a user's push subscription state, you must update it in Braze. For example, if a user disables push from an in-app preference center, update the push subscription state to `Unsubscribed` in Braze. Braze does not update user profiles based on your preference center. To align subscription states with a user's in-app preferences, call the appropriate methods using the [SDK](https://www.braze.com/docs/ja/ja/user_guide/channels/push/push_setup/push_subscription_states/#sdk-integration) (iOS or Android) or [REST API](https://www.braze.com/docs/ja/ja/user_guide/channels/push/push_setup/push_subscription_states/#rest-api). ### Imported push tokens (iOS) When you [import iOS push tokens](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track/#push-token-import) with `push_token_import`, the user's push subscription state is typically **`Subscribed`** until they log a session in your Braze-integrated app. After the first session, Braze may update the state to **`Opted-In`** if [automatic opt-in](#automatic-opt-in-default) applies (for example, when the user authorizes push on iOS and `optInWhenPushAuthorized` is enabled). Review **Contact Settings** on the user's profile after import and again after the user's first in-app session to confirm the expected state. ### Checking push subscription state ![User profile for John Doe with their push subscription state set to Subscribed.](https://www.braze.com/docs/ja/ja/assets/img/push_example.png?35176b34da21057d058dc0b0f0e3d9f7){: style="float:right;max-width:35%;margin-left:15px;"} You can check a user's push subscription state with Braze in any of the following ways: * **User profile:** You can access individual user profiles through the Braze dashboard on the **[User Search](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/segments/user_profiles/)** page. After finding a user's profile (via email address, phone number, or external user ID), you can select the **Engagement** tab to view and manually adjust a user's subscription state. * **REST API export:** You can export individual user profiles in JSON format using the export [Users by segment](https://www.braze.com/docs/ja/ja/api/endpoints/export/user_data/post_users_segment/) or [Users by identifier](https://www.braze.com/docs/ja/ja/api/endpoints/export/user_data/post_users_identifier/) endpoints. Braze returns a push tokens object that contains push enablement information per device. # Braze SDKのプッシュ通知のトラブルシューティング Source: /docs/ja/developer_guide/push_notifications/troubleshooting/index.md # プッシュ通知のトラブルシューティング {#troubleshoot-push-notifications} > Braze SDKのプッシュ通知のトラブルシューティング方法について説明します。 ## Troubleshooting If you're experiencing issues after setting up push notifications, consider the following: - Web push notifications require that your site be HTTPS. - Not all browsers can receive push messages. Ensure that `braze.isPushSupported()` returns `true` in the browser. - Some browsers, such as Firefox, do not display images in push notifications. For details on browser support, refer to the [MDN documentation for Notification images](https://developer.mozilla.org/en-US/docs/Web/API/Notification/image). - If a user has denied a site push access, they won't be prompted for permission again unless they remove the denied status from their browser preferences. ## Understanding the Braze push workflow The Firebase Cloud Messaging (FCM) service is Google's infrastructure for push notifications sent to Android applications. Here is the simplified structure of how push notifications are enabled for your users' devices and how Braze can send push notifications to them: ```mermaid --- config: theme: mc --- sequenceDiagram participant Device as User Device participant App as Android App participant BrazeSDK as Braze SDK participant BrazeAPI as Braze Server participant Firebase as Google Firebase Note over Device, Firebase: Register Option 1
Register Automatically using `com_braze_firebase_cloud_messaging_registration_enabled` in braze.xml App ->> Braze: App initializes Braze with the first Braze call
This could be automatic session handling BrazeSDK ->> App: Get push token from Firebase Manager BrazeSDK ->> BrazeAPI: Send push token to Braze Server Note right of BrazeAPI: Braze will remove push token from any
other user who may have previously
been logged in on the same device. Note over Device, Firebase: Register Option 2
Manual registration. App ->> BrazeSDK: App sets `Braze.registeredPushToken` BrazeSDK ->> BrazeAPI: Send push token to Braze Server Note right of BrazeAPI: Braze will remove push token from any
other user who may have previously
been logged in on the same device. Note over Device, Firebase: Push permission BrazeAPI ->> BrazeSDK: In-App Message containing push prompt BrazeSDK -> App: In-App Message is displayed App -> BrazeSDK: User requests permissions BrazeSDK -> App: Displays the Push Authorization prompt BrazeSDK -> BrazeAPI: If authorized and `com_braze_optin_when_push_authorized`, Opt-In value is sent. Note over Device, Firebase: Push Notification Is Sent BrazeAPI ->> Firebase: Sends push message Firebase ->> Device: Push message sent Device ->> App: Android will send the push to the App.
This could be blocked to Do Not Disturb, Power Saving Mode, etc. App ->> BrazeSDK: Message is sent to BrazeFirebaseMessagingService BrazeSDK ->> Device: SDK will check if the push is from Braze.
If so, push data is transformed into a Push Notification and displayed. ``` ### Step 1: Configuring your Google Cloud API key In developing your app, you'll need to provide the Braze Android SDK with your Firebase sender ID. Additionally, you'll need to provide an API Key for server applications to the Braze dashboard. Braze will use this API key to send messages to your devices. You will also need to check that FCM service is enabled in Google Developer's console. **Note:** A common mistake during this step is using the app identifier API key instead of the REST API key. ### Step 2: Devices register for FCM and provide Braze with push tokens In typical integrations, the Braze Android SDK will handle registering devices for FCM capability. This will usually happen immediately upon opening the app for the first time. After registration, Braze will be provided with an FCM Registration ID, which is used to send messages to that device specifically. We will store the Registration ID for that user, and that user will become "push registered" if they previously did not have a push token for any of your apps. ### Step 3: Launching a Braze push campaign When a push campaign is launched, Braze will make requests to FCM to deliver your message. Braze will use the API key copied in the dashboard to authenticate and verify that we can send push notifications to the push tokens provided. ### Step 4: Removing invalid tokens If FCM informs us that any of the push tokens we were attempting to send a message to are invalid, we remove those tokens from the user profiles they were associated with. If users have no other push tokens, they will no longer show up as "Push Registered" under the **Segments** page. For more details about FCM, visit [Cloud messaging](https://firebase.google.com/docs/cloud-messaging/). ## Utilizing the push error logs Braze provides push notification errors within the message activity log. This error log provides a variety of warnings which can be very helpful for identifying why your campaigns aren't working as expected. Clicking on an error message will redirect you to relevant documentation to help you troubleshoot a particular incident. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/message_activity_log.png?6577302323ab3f2df3196a973320b8d3) ## Troubleshooting scenarios ### Push isn't sending Your push messages might not be sending because of the following situations: - Your credentials exist in the wrong Google Cloud Platform project ID (wrong sender ID). - Your credentials have the wrong permission scope. - You uploaded wrong credentials to the wrong Braze workspace (wrong sender ID). For other issues that may prevent you from sending a push message, refer to [User Guide: Troubleshooting Push Notifications](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/troubleshooting/). ### No "push registered" users showing in the Braze dashboard (prior to sending messages) Confirm that your app is correctly configured to allow push notifications. Common failure points to check include: #### Incorrect sender ID Check that the correct FCM sender ID is included in the `braze.xml` file. An incorrect sender ID will lead to `MismatchSenderID` errors reported in the dashboard's message activity log. #### Braze registration not occurring Since FCM registration is handled outside of Braze, failure to register can only occur in two places: 1. During registration with FCM 2. When passing the FCM-generated push token to Braze We recommend setting a breakpoint or logging to confirm that the FCM-generated push token is being sent to Braze. If a token is not generated correctly or at all, we recommend consulting the [FCM documentation](https://firebase.google.com/docs/cloud-messaging/android/client). #### Google Play Services not present For FCM push to work, Google Play Services must be present on the device. If Google Play Services isn't on a device, push registration will not occur. **Note:** Google Play Services is not installed on Android emulators without Google APIs installed. #### Device not connected to the internet Check that your device has good internet connectivity and isn't sending network traffic through a proxy. ### Tapping push notification doesn't open the app Check if `com_braze_handle_push_deep_links_automatically` is set to `true` or `false`. To enable Braze to automatically open the app and any deep links when a push notification is tapped, set `com_braze_handle_push_deep_links_automatically` to `true` in your `braze.xml` file. If `com_braze_handle_push_deep_links_automatically` is set to its default of `false`, you need to use a Braze Push Callback to listen for and handle the push received and opened intents. ### Push notifications bounced If a push notification isn't delivered, make sure it didn't bounce by looking in the [developer console](https://www.braze.com/docs/ja/ja/developer_guide/platforms/android/push_notifications/troubleshooting/#utilizing-the-push-error-logs). The following are descriptions of common errors that may be logged in the developer console: #### Error: MismatchSenderID `MismatchSenderID` indicates an authentication failure. Confirm your Firebase sender ID and FCM API key are correct. #### Error: InvalidRegistration `InvalidRegistration` can be caused by a malformed push token. 1. Make sure to pass a valid push token to Braze from [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/android/client#retrieve-the-current-registration-token). #### Error: NotRegistered 1. `NotRegistered` typically occurs when an app has been deleted from a device. Braze uses `NotRegistered` internally to signal that an app has been uninstalled from a device. 2. `NotRegistered` may also occur when multiple registrations occur and a second registration invalidates the first token. ### Push notifications sent but not displayed on users' devices There are a few reasons why this could be occurring: #### Application was force quit If you force-quit your application through your system settings, your push notifications will not be sent. Launching the app again will re-enable your device to receive push notifications. #### BrazeFirebaseMessagingService not registered The BrazeFirebaseMessagingService must be properly registered in `AndroidManifest.xml` for push notifications to appear: ```xml ``` #### Firewall is blocking push If you are testing push over Wi-Fi, your firewall may be blocking ports necessary for FCM to receive messages. Confirm that ports `5228`, `5229`, and `5230` are open. Additionally, since FCM doesn't specify its IPs, you must also allow your firewall to accept outgoing connections to all IP addresses contained in the IP blocks listed in Google's ASN of `15169`. #### Custom notification factory returning null If you have implemented a [custom notification factory](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#custom-displaying-notifications), ensure that it is not returning `null`. This will cause notifications not to be displayed. ### "Push registered" users no longer enabled after sending messages There are a few reasons why this could be happening: #### Application was uninstalled Users have uninstalled the application. This will invalidate their FCM push token. #### Invalid Firebase Cloud Messaging server key The Firebase Cloud Messaging server key provided in the Braze dashboard is invalid. The sender ID provided should match the one referenced in your app's `braze.xml` file. The server key and sender ID are found here in your Firebase Console: ![The Firebase platform under "Settings" and then "Cloud Messaging" will display your server ID and server key.](https://www.braze.com/docs/ja/ja/assets/img_archive/finding_firebase_server_key.png?de34d7ce2b1ae4b9c4a9d543b5b40585 "FirebaseServerKey") ### Push clicks not logged Braze logs push clicks automatically, so this scenario should be comparatively rare. If push clicks are not being logged, it is possible that push click data has not been flushed to our servers yet. Braze throttles the frequency of its flushes based on the strength of the network connection. With a good network connection, push click-data should arrive at the server within a minute in most circumstances. ### Deep links not working #### Verify deep link configuration Deep links can be [tested with ADB](https://developer.android.com/training/app-indexing/deep-linking.html#testing-filters). We recommend testing your deep link with the following command: `adb shell am start -W -a android.intent.action.VIEW -d "THE_DEEP_LINK" THE_PACKAGE_NAME` If the deep link fails to work, the deep link may be misconfigured. A misconfigured deep link will not work when sent through Braze push. #### Verify custom handling logic If the deep link [works correctly with ADB](https://developer.android.com/training/app-indexing/deep-linking.html#testing-filters) but fails to work from Braze push, check whether any [custom push open handling](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#android-push-listener-callback) has been implemented. If so, verify that the custom handling code properly handles the incoming deep link. #### Disable back stack behavior If the deep link [works correctly with ADB](https://developer.android.com/training/app-indexing/deep-linking.html#testing-filters) but fails to work from Braze push, try disabling [back stack](https://developer.android.com/guide/components/activities/tasks-and-back-stack). To do so, update your **braze.xml** file to include: ```xml false ``` ## Understanding the Braze/APNs workflow The Apple Push Notification service (APNs) is the infrastructure for sending push notifications to applications running on Apple's platforms. Here is the simplified structure of how push notifications are enabled for your users' devices and how Braze can send push notifications to them: 1. You configure the push certificate and provisioning profile 2. Devices register for APNs and provide Braze with push tokens 3. You launch a Braze push campaign 4. Braze removes invalid tokens ### Step 1: Configuring the push certificate and provisioning profile In developing your app, you'll need to create an SSL certificate to enable push notifications. This certificate will be included in the provisioning profile your app is built with and will also need to be uploaded to the Braze dashboard. The certificate allows Braze to tell APNs that we are allowed to send push notifications on your behalf. There are two types of [provisioning profiles](https://developer.apple.com/library/content/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingProfiles/MaintainingProfiles.html) and certificates: development and distribution. We recommend just using distribution profiles and certificates to avoid any confusion. If you choose to use different profiles and certificates for development and distribution, ensure that the certificate uploaded to the dashboard matches the provisioning profile you are currently using. **Warning:** Do not change the push certificate environment (development versus production). Changing the push certificate to the wrong environment can lead to your users having their push token accidentally removed, making them unreachable by push. ### Step 2: Devices register for APNs and provide Braze with push tokens When users open your app, they will be prompted to accept push notifications. If they accept this prompt, APNs will generate a push token for that particular device. The Swift SDK will immediately and asynchronously send up the push token for apps using the default [automatic flush policy](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/advanced_use_cases/fine_network_traffic_control/#automatic-request-processing). After we have a push token associated with a user, they will show as "Push Registered" in the dashboard on their user profile under the **Engagement** tab and will be eligible to receive push notifications from Braze campaigns. **Note:** Starting in macOS 13, on certain devices, you can test push notifications on an iOS 16 Simulator running on Xcode 14. For further details, refer to the [Xcode 14 Release Notes](https://developer.apple.com/documentation/xcode-release-notes/xcode-14-release-notes). #### Considerations for push token generation - If users install your app on another device, another token will be created and captured in the same way. - If users reinstall your app, a new token will be generated and passed to Braze. However, the original token may still be logged as valid by APNs and Braze. - If users uninstall your app, Braze doesn't get immediately notified of this and the token will still appear as valid until it is retired by APNs. - At some point, APNs will retire old tokens. Braze doesn't have control or visibility of this. ### Step 3: Launching a Braze push campaign When a push campaign is launched, Braze will make requests to APNs to deliver your message. Specifically, the requests are passed to APNs for each current valid push token unless **Send to a user's most recent device** is selected. After Braze receives a successful response from APNs, we will log a successful delivery on the user profile, though the user may not have received the actual message for reasons including: - Their device is powered off. - Their device isn't connected to the internet (Wi-Fi or cellular). - They recently uninstalled the app. Braze will use the SSL push certificate uploaded in the dashboard to authenticate and verify that we are allowed to send push notifications to the push tokens provided. If a device is online, the notification should be received shortly after the campaign has been sent. Note that Braze sets the default APNs [expiration date](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607) for notifications to 30 days. ### Step 4: Removing invalid tokens If [APNs](https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1) informs us that any of the push tokens we were attempting to send a message to are invalid, we remove those tokens from the user profiles they were associated with. **Note:** It's normal for APNs to initially return a success status even if a token becomes unregistered, as APNs doesn't immediately report token invalidation events. APNs intentionally delays returning a `410` status for invalid tokens on a randomized schedule, designed to protect user privacy and prevent tracking of app uninstalls. You can safely continue sending notifications to an unregistered token until APNs returns a `410` status. ## Using the push error logs The [Message Activity Log](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/message_activity_log_tab/) gives you the opportunity to see any messages (especially error messages) associated with your campaigns and sends, including push notification errors. This error log provides a variety of warnings which can be very helpful for identifying why your campaigns aren't working as expected. Clicking on an error message will redirect you to relevant documentation to help you troubleshoot a particular incident. ![Push error logs displaying the time the error occurred, the app name, the channel, error type, and error message.](https://www.braze.com/docs/ja/ja/assets/img_archive/message_activity_log.png?6577302323ab3f2df3196a973320b8d3) Common errors you might see here include user-specific notifications, such as ["Received Unregistered Sending to Push Token"](#swift_received-unregistered-sending). In addition, Braze also provides a push changelog on the user profile under the **Engagement** tab. This changelog provides insight into push registration behavior such as token invalidation, push registration errors, tokens being moved to new users, etc. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/push_changelog.gif?36d10186d33121a195e943385dd0d02a){: style="max-width:50%;" } ### Message Activity Log errors #### Received unregistered sending to push token {#received-unregistered-sending} - Make sure that the push token being sent to Braze from the method `AppDelegate.braze?.notifications.register(deviceToken:)` is valid. You can look in the **Message Activity Log** to see the push token. It should look something like `6e407a9be8d07f0cdeb9e724733a89445f57a89ec890d63867c482a483506fa6`, a long string containing a mix of letters and numbers. If your push token looks different, check your [code](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/#step-4-register-push-tokens-with-braze) for sending Braze the push tokens. - Ensure that your push provisioning profile matches the environment you're testing. Universal certificates may be configured in the Braze dashboard to send to either the development or production APNs environment. Using a development certificate for a production app or a production certificate for a development app will not work. - Check that the push token you have uploaded to Braze matches the provisioning profile you used to build the app you sent the push token from. #### Device token not for topic APNs returns `DeviceTokenNotForTopic` (HTTP status 400) when the push token doesn't match the topic (bundle ID) configured for your credentials. Braze may surface this in **Message Activity Log** or push delivery logs as `DeviceTokenNotForTopic`. To resolve the mismatch: 1. Confirm the app's **bundle ID** matches the **App Bundle ID** in Braze (**Settings** > **App Settings** > **Push Notification Settings**). 2. Verify the provisioning profile used to build the app includes push capability for that bundle ID. 3. Confirm the push credential uploaded to Braze matches the app's environment (development versus production). 4. For `.p8` keys, verify **Team ID** and **Key ID** in Braze match your Apple Developer account. 5. Re-upload a valid `.p8` key or `.p12` certificate if credentials were rotated or revoked. Prefer `.p8` authentication keys when possible. For credential types and dashboard status indicators, see [Migrate to a .p8 authentication key](https://www.braze.com/docs/ja/ja/user_guide/channels/push/troubleshooting/#migrate-to-a-p8-authentication-key). #### BadDeviceToken sending to push token The `BadDeviceToken` is an APNs error code and does not originate from Braze. There could be a number of reasons for this response being returned, including the following: - The app received a push token that was invalid for the credentials uploaded to the dashboard. - Push was disabled for this workspace. - The user has opted out of push. - The app was uninstalled. - Apple refreshed the push token, which invalidated the old token. - The app was built for a production environment, but the push credentials uploaded to Braze are set for a development environment (or the other way around). ## Push registration issues ### No push registration prompt If the application does not prompt you to register for push notifications, there is likely an issue with your push registration integration. Ensure you have followed our [documentation](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift) and correctly integrated our push registration. You can also set breakpoints in your code to ensure the push registration code is running. ### No "push registered" users showing in the dashboard (prior to sending messages) Ensure that your app is correctly configured to allow push notifications. Common failure points to check include: - Check that your app is prompting you to allow push notifications. Typically, this prompt will appear upon your first open of the app, but it can be programmed to appear elsewhere. If it does not appear where it should be, the problem is likely with the basic configuration of your app's push capabilities. - Verify the steps for [push integration](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift) were successfully completed. - Check that the provisioning profile your app was built with includes permissions for push. Make sure that you're pulling down all of the available provisioning profiles from your Apple developer account. To confirm this, perform the following steps: 1. In Xcode, navigate to **Preferences > Accounts** (or use the keyboard shortcut Command+,). 2. Select the Apple ID you use for your developer account and click **View Details**. 3. On the next page, click ** Refresh** and confirm that you're pulling all available provisioning profiles. - Check you have [properly enabled push capability](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/#step-2-enable-push-capabilities) in your app. - Check your push provisioning profile matches the environment you're testing in. Universal certificates may be configured in the Braze dashboard to send to either the development or production APNs environment. Using a development certificate for a production app or a production certificate for a development app will not work. - Check that you are calling our `registerPushToken` method by setting a breakpoint in your code. - Make sure you're testing using a device (push will not work on a simulator) and have good network connectivity. ## Push notifications sent but not displayed on users’ devices ### "Push registered" users no longer enabled after sending messages This likely indicates that the user had an invalid push token. This can happen for several reasons: #### Dashboard and app certificate mismatch If the push certificate you uploaded in the dashboard is not the same one in the provisioning profile that your app was built with, APNs will reject the token. Verify that you have uploaded the correct certificate and completed another session in the app before attempting another test notification. #### Application was uninstalled If a user has uninstalled your application, their push token will be invalid and removed upon the next send. #### Regenerating your provisioning profile As a last resort, starting over fresh and creating a whole new provisioning profile can clear up configuration errors that come from working with multiple environments, profiles, and apps at the same time. There are many "moving parts" in setting up push notifications, so sometimes, it is best to retry from the beginning. This will also help isolate the problem if you need to continue troubleshooting. ### Messages not delivered to "push registered" users #### App is foregrounded On iOS versions that do not integrate push via the `UserNotifications` framework, if the app is in the foreground when the push message is received, it will not be displayed. You should background the app on your test devices before sending test messages. #### Test notification scheduled incorrectly Check the schedule you set for your test message. If it is set to local time zone delivery or [Intelligent Timing](https://www.braze.com/docs/ja/ja/user_guide/brazeai/intelligence/intelligent_timing/), you may have just not received the message yet (or had the app in the foreground when it was received). ### User not "push registered" for the app being tested Check the user profile of the user you are trying to send a test message to. Under the **Engagement** tab, there should be a list of "pushable apps." Verify the app you are trying to send test messages to is in this list. Users will show up as "Push Registered" if they have a push token for any app in your workspace, so this could be something of a false positive. The following would indicate a problem with push registration or that the user's token had been returned to Braze as invalid by APNs after being pushed: ![A user profile displaying the contact settings of a user. Under Push, "No Apps" are displayed.](https://www.braze.com/docs/ja/ja/assets/img_archive/registration_problem.png?b01abd4f8f8ddd58425f6ecc82c256ea){: style="max-width:50%"} ## Push clicks not logged {#push-clicks-not-logged} - Make sure you have followed the [push integration steps](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/#step-5-enable-push-handling). - Braze does not handle push notifications received silently in the foreground (default foreground push behavior prior to the `UserNotifications` framework). This means that links will not be opened, and push clicks will not be logged. If your application has not yet integrated the `UserNotifications` framework, Braze will not handle push notifications when the application state is `UIApplicationStateActive`. Ensure that your app does not delay calls to [push handling methods](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/push_notifications/integration/#step-5-enable-push-handling); otherwise, the Swift SDK may treat push notifications as silent foreground push events and not handle them. ## Deep links not working For comprehensive troubleshooting across all channels—including universal links, custom schemes, email, and third-party providers like Branch—see [Deep linking troubleshooting](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/deep_linking_troubleshooting). ### Web links from push clicks not opening Links in push notifications need to be ATS compliant to be opened in web views. Ensure that your web links use HTTPS. For more information, refer to [ATS compliance](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/advanced_use_cases/linking/#app-transport-security-ats). ### Deep links from push clicks not opening Most of the code that handles deep links also handles push opens. First, ensure that push opens are being logged. If not, fix that issue (as the fix often fixes link handling). If opens are being logged, check whether it is an issue with the deep link in general or with the deep linking push click handling. To do this, test to see if a deep link from an in-app message click works. ## Understanding the Braze push workflow The Firebase Cloud Messaging (FCM) service is Google's infrastructure for push notifications sent to Android applications. Here is the simplified structure of how push notifications are enabled for your users' devices and how Braze can send push notifications to them: ```mermaid --- config: theme: mc --- sequenceDiagram participant Device as User Device participant App as Android App participant BrazeSDK as Braze SDK participant BrazeAPI as Braze Server participant Firebase as Google Firebase Note over Device, Firebase: Register Option 1
Register Automatically using `com_braze_firebase_cloud_messaging_registration_enabled` in braze.xml App ->> Braze: App initializes Braze with the first Braze call
This could be automatic session handling BrazeSDK ->> App: Get push token from Firebase Manager BrazeSDK ->> BrazeAPI: Send push token to Braze Server Note right of BrazeAPI: Braze will remove push token from any
other user who may have previously
been logged in on the same device. Note over Device, Firebase: Register Option 2
Manual registration. App ->> BrazeSDK: App sets `Braze.registeredPushToken` BrazeSDK ->> BrazeAPI: Send push token to Braze Server Note right of BrazeAPI: Braze will remove push token from any
other user who may have previously
been logged in on the same device. Note over Device, Firebase: Push permission BrazeAPI ->> BrazeSDK: In-App Message containing push prompt BrazeSDK -> App: In-App Message is displayed App -> BrazeSDK: User requests permissions BrazeSDK -> App: Displays the Push Authorization prompt BrazeSDK -> BrazeAPI: If authorized and `com_braze_optin_when_push_authorized`, Opt-In value is sent. Note over Device, Firebase: Push Notification Is Sent BrazeAPI ->> Firebase: Sends push message Firebase ->> Device: Push message sent Device ->> App: Android will send the push to the App.
This could be blocked to Do Not Disturb, Power Saving Mode, etc. App ->> BrazeSDK: Message is sent to BrazeFirebaseMessagingService BrazeSDK ->> Device: SDK will check if the push is from Braze.
If so, push data is transformed into a Push Notification and displayed. ``` ### Step 1: Configuring your Google Cloud API key In developing your app, you'll need to provide the Braze Android SDK with your Firebase sender ID. Additionally, you'll need to provide an API Key for server applications to the Braze dashboard. Braze will use this API key to send messages to your devices. You will also need to check that FCM service is enabled in Google Developer's console. **Note:** A common mistake during this step is using the app identifier API key instead of the REST API key. ### Step 2: Devices register for FCM and provide Braze with push tokens In typical integrations, the Braze Android SDK will handle registering devices for FCM capability. This will usually happen immediately upon opening the app for the first time. After registration, Braze will be provided with an FCM Registration ID, which is used to send messages to that device specifically. We will store the Registration ID for that user, and that user will become "push registered" if they previously did not have a push token for any of your apps. ### Step 3: Launching a Braze push campaign When a push campaign is launched, Braze will make requests to FCM to deliver your message. Braze will use the API key copied in the dashboard to authenticate and verify that we can send push notifications to the push tokens provided. ### Step 4: Removing invalid tokens If FCM informs us that any of the push tokens we were attempting to send a message to are invalid, we remove those tokens from the user profiles they were associated with. If users have no other push tokens, they will no longer show up as "Push Registered" under the **Segments** page. For more details about FCM, visit [Cloud messaging](https://firebase.google.com/docs/cloud-messaging/). ## Utilizing the push error logs Braze provides push notification errors within the message activity log. This error log provides a variety of warnings which can be very helpful for identifying why your campaigns aren't working as expected. Clicking on an error message will redirect you to relevant documentation to help you troubleshoot a particular incident. ![](https://www.braze.com/docs/ja/ja/assets/img_archive/message_activity_log.png?6577302323ab3f2df3196a973320b8d3) ## Troubleshooting scenarios ### Push isn't sending Your push messages might not be sending because of the following situations: - Your credentials exist in the wrong Google Cloud Platform project ID (wrong sender ID). - Your credentials have the wrong permission scope. - You uploaded wrong credentials to the wrong Braze workspace (wrong sender ID). For other issues that may prevent you from sending a push message, refer to [User Guide: Troubleshooting Push Notifications](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/troubleshooting/). ### No "push registered" users showing in the Braze dashboard (prior to sending messages) Confirm that your app is correctly configured to allow push notifications. Common failure points to check include: #### Incorrect sender ID Check that the correct FCM sender ID is included in the `braze.xml` file. An incorrect sender ID will lead to `MismatchSenderID` errors reported in the dashboard's message activity log. #### Braze registration not occurring Since FCM registration is handled outside of Braze, failure to register can only occur in two places: 1. During registration with FCM 2. When passing the FCM-generated push token to Braze We recommend setting a breakpoint or logging to confirm that the FCM-generated push token is being sent to Braze. If a token is not generated correctly or at all, we recommend consulting the [FCM documentation](https://firebase.google.com/docs/cloud-messaging/android/client). #### Google Play Services not present For FCM push to work, Google Play Services must be present on the device. If Google Play Services isn't on a device, push registration will not occur. **Note:** Google Play Services is not installed on Android emulators without Google APIs installed. #### Device not connected to the internet Check that your device has good internet connectivity and isn't sending network traffic through a proxy. ### Tapping push notification doesn't open the app Check if `com_braze_handle_push_deep_links_automatically` is set to `true` or `false`. To enable Braze to automatically open the app and any deep links when a push notification is tapped, set `com_braze_handle_push_deep_links_automatically` to `true` in your `braze.xml` file. If `com_braze_handle_push_deep_links_automatically` is set to its default of `false`, you need to use a Braze Push Callback to listen for and handle the push received and opened intents. ### Push notifications bounced If a push notification isn't delivered, make sure it didn't bounce by looking in the [developer console](https://www.braze.com/docs/ja/ja/developer_guide/platforms/android/push_notifications/troubleshooting/#utilizing-the-push-error-logs). The following are descriptions of common errors that may be logged in the developer console: #### Error: MismatchSenderID `MismatchSenderID` indicates an authentication failure. Confirm your Firebase sender ID and FCM API key are correct. #### Error: InvalidRegistration `InvalidRegistration` can be caused by a malformed push token. 1. Make sure to pass a valid push token to Braze from [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/android/client#retrieve-the-current-registration-token). #### Error: NotRegistered 1. `NotRegistered` typically occurs when an app has been deleted from a device. Braze uses `NotRegistered` internally to signal that an app has been uninstalled from a device. 2. `NotRegistered` may also occur when multiple registrations occur and a second registration invalidates the first token. ### Push notifications sent but not displayed on users' devices There are a few reasons why this could be occurring: #### Application was force quit If you force-quit your application through your system settings, your push notifications will not be sent. Launching the app again will re-enable your device to receive push notifications. #### BrazeFirebaseMessagingService not registered The BrazeFirebaseMessagingService must be properly registered in `AndroidManifest.xml` for push notifications to appear: ```xml ``` #### Firewall is blocking push If you are testing push over Wi-Fi, your firewall may be blocking ports necessary for FCM to receive messages. Confirm that ports `5228`, `5229`, and `5230` are open. Additionally, since FCM doesn't specify its IPs, you must also allow your firewall to accept outgoing connections to all IP addresses contained in the IP blocks listed in Google's ASN of `15169`. #### Custom notification factory returning null If you have implemented a [custom notification factory](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#custom-displaying-notifications), ensure that it is not returning `null`. This will cause notifications not to be displayed. ### "Push registered" users no longer enabled after sending messages There are a few reasons why this could be happening: #### Application was uninstalled Users have uninstalled the application. This will invalidate their FCM push token. #### Invalid Firebase Cloud Messaging server key The Firebase Cloud Messaging server key provided in the Braze dashboard is invalid. The sender ID provided should match the one referenced in your app's `braze.xml` file. The server key and sender ID are found here in your Firebase Console: ![The Firebase platform under "Settings" and then "Cloud Messaging" will display your server ID and server key.](https://www.braze.com/docs/ja/ja/assets/img_archive/finding_firebase_server_key.png?de34d7ce2b1ae4b9c4a9d543b5b40585 "FirebaseServerKey") ### Push clicks not logged Braze logs push clicks automatically, so this scenario should be comparatively rare. If push clicks are not being logged, it is possible that push click data has not been flushed to our servers yet. Braze throttles the frequency of its flushes based on the strength of the network connection. With a good network connection, push click-data should arrive at the server within a minute in most circumstances. ### Deep links not working #### Verify deep link configuration Deep links can be [tested with ADB](https://developer.android.com/training/app-indexing/deep-linking.html#testing-filters). We recommend testing your deep link with the following command: `adb shell am start -W -a android.intent.action.VIEW -d "THE_DEEP_LINK" THE_PACKAGE_NAME` If the deep link fails to work, the deep link may be misconfigured. A misconfigured deep link will not work when sent through Braze push. #### Verify custom handling logic If the deep link [works correctly with ADB](https://developer.android.com/training/app-indexing/deep-linking.html#testing-filters) but fails to work from Braze push, check whether any [custom push open handling](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#android-push-listener-callback) has been implemented. If so, verify that the custom handling code properly handles the incoming deep link. #### Disable back stack behavior If the deep link [works correctly with ADB](https://developer.android.com/training/app-indexing/deep-linking.html#testing-filters) but fails to work from Braze push, try disabling [back stack](https://developer.android.com/guide/components/activities/tasks-and-back-stack). To do so, update your **braze.xml** file to include: ```xml false ``` ## Troubleshooting ### Push doesn't appear after app is closed from task switcher If you observe that push notifications no longer appear after the app is closed from the task switcher, your app is likely in Debug mode. .NET MAUI adds scaffolding in Debug mode that prevents apps from receiving push after their process is killed. If you run your app in Release Mode, you should see push even after the app is closed from the task switcher. ### Custom notification factory not being set correctly Custom notification factories (and all delegates) must extend [`Java.Lang.Object`](https://developer.xamarin.com/api/type/Android.Runtime.IJavaObject/) to work properly across the C# and Java divide. See [Xamarin](https://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/working_with_jni/#Implementing_Interfaces) on implementing Java interfaces for more information. ## プッシュ通知の改行 {#push-linebreaks} Liquidタグを使用してプッシュ通知を作成する場合、Liquidタグに隣接する改行はメッセージ送信前に自動的に削除されます。[プッシュ通知コンポーザー](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/push/creating_a_push_message)では、編集中にメッセージが読みやすいようにこれらの改行が再追加されます。メッセージを保存する際にLiquidタグの前後に改行が表示される場合、これは想定どおりの動作です。 # Braze SDKの高度なプッシュ通知例 Source: /docs/ja/developer_guide/push_notifications/examples/index.md # Braze SDKのライブアクティビティ Source: /docs/ja/developer_guide/live_notifications/index.md ライブアクティビティ > ユーザーのロック画面に直接、永続的でダイナミックな通知を送信し、アプリを開くことなくリアルタイムの更新を受け取れるようにする方法について説明します。Swiftではネイティブにサポートされています。 永続的でダイナミックな通知をユーザーのロック画面に直接送信し、アプリを開くことなくリアルタイムの更新を受け取れるようにする方法について説明します。 Featured: - Swift のライブアクティビティの実装 # Swift Braze SDKのライブアクティビティ Source: /docs/ja/developer_guide/live_notifications/live_activities/index.md # Swift のライブアクティビティ {#live-activities-for-swift} > Swift Braze SDK用にライブアクティビティを実装する方法について説明します。ライブアクティビティは、ロック画面に直接表示される永続的でインタラクティブな通知で、ユーザーはデバイスのロックを解除することなく、ダイナミックなリアルタイム更新を得ることができます。 ## 仕組み {#how-it-works} ![iPhoneロック画面の配信トラッカーのライブアクティビティ。車のついたステータスバーがほぼ半分まで進んでいる。「ピックアップまであと2分」と表示されている](https://www.braze.com/docs/ja/ja/assets/img/swift/live_activities/example_2.png?3675f3043731a76345f8790b4417a5dd){: style="max-width:40%;float:right;margin-left:15px;"} ライブアクティビティは、静的情報と更新可能な動的情報を組み合わせて表示します。たとえば、配達のステータス追跡機能を提供するライブアクティビティを作成できます。このライブアクティビティには、会社名が静的情報として含まれ、さらに配達ドライバーが目的地に近づくにつれて更新される「配達までの時間」が動的情報として含まれます。 開発者はBrazeを使用して、ライブアクティビティのライフサイクルを管理し、Braze REST APIを呼び出してライブアクティビティの更新を行い、サブスクライブ済みのすべてのデバイスが可能な限り早く更新を受信できるようにすることができます。また、Brazeでライブアクティビティを管理しているため、プッシュ通知、アプリ内メッセージ、Content Cardsなど、その他のメッセージングチャネルと連携させて活用を促進できます。 ## シーケンス図 {#sequence-diagram} **図を表示** ```mermaid --- config: theme: mc --- sequenceDiagram participant Server as Client Server participant Device as User Device participant App as iOS App / Braze SDK participant BrazeAPI as Braze API participant APNS as Apple Push Notification Service Note over Server, APNS: Launch Option 1
Locally Start Activities App ->> App: Register a Live Activity using
`launchActivity(pushTokenTag:activity:)` App ->> App: Get push token from iOS App ->> BrazeAPI: Activity ID & Push token
automatically sent to Braze Note over Server, APNS: Launch Option 2
Remotely Start Activities Device ->> App: Call `registerPushToStart`
to collect push tokens early App ->> BrazeAPI: Push-to-start tokens sent to Braze Server ->> BrazeAPI: POST /messages/live_activity/start Note right of BrazeAPI: Payload includes:
- push_token
- activity_id
- external_id
- event_name
- content_state (optional) BrazeAPI ->> APNS: Live activity start request APNS ->> Device: APNS sends activity to device App ->> App: Get push token from iOS App ->> BrazeAPI: Activity ID & Push token
automatically sent to Braze Note over Server, APNS: Resuming activities upon app launch App ->> App: Call `resumeActivities(ofType:)` on each app launch Note over Server, APNS: Updating a Live Activity loop update a live activity Server ->> BrazeAPI: POST /messages/live_activity/update Note right of BrazeAPI: Payload includes changes
to ContentState (dynamic variables) BrazeAPI ->> APNS: Update sent to APNS APNS ->> Device: APNS sends update to device end Note over Server, APNS: Ending a Live Activity Server ->> BrazeAPI: POST /messages/live_activity/update Note right of BrazeAPI: Activity can be ended via:
- User manually dismisses
- Times out after 12 hours
- Setting `end_activity: true` on `/messages/live_activity/update` APNS ->> Device: Live activity is dismissed ``` ## ライブアクティビティの実装 {#implementing-a-live-activity} ### Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). 以下の項目も完了する必要があります。 - プロジェクトがiOS 16.1以降をターゲットにしていることを確認します。 - Xcodeプロジェクトの**Signing & Capabilities**に`Push Notification`エンタイトルメントを追加します。 - 通知の送信に`.p8`キーが使用されていることを確認します。`.p12`や`.pem`などの古いファイルはサポートされていません。 - Braze Swift SDKのバージョン8.2.0以降では、[ライブアクティビティをリモートで登録](#swift_step-2-start-the-activity)できます。この機能を使用するには、iOS 17.2以降が必要です。 **Note:** ライブアクティビティとプッシュ通知は似ていますが、システム権限は別個のものです。デフォルトでは、すべてのライブアクティビティ機能が有効になっていますが、ユーザーはアプリごとにこの機能を無効にすることができます。 ### ステップ 1: アクティビティを作成する {#create-an-activity} まず、Appleのドキュメントの[ライブアクティビティでライブデータを表示する](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities)手順に従い、iOSアプリケーションにライブアクティビティをセットアップします。このタスクの一部として、`Info.plist`に`NSSupportsLiveActivities`を`YES`に設定して含めてください。 ライブアクティビティの正確な内容はビジネスケースに固有であるため、[Activity](https://developer.apple.com/documentation/activitykit/activityattributes)オブジェクトを設定して初期化する必要があります。以下を定義することが重要です。 * `ActivityAttributes`: このプロトコルは、ライブアクティビティに表示される静的(不変)コンテンツと動的(可変)コンテンツを定義します。 * `ActivityAttributes.ContentState`: この型は、アクティビティの進行に伴って更新される動的データを定義します。 また、SwiftUIを使用して、サポートされているデバイスでロック画面とダイナミックアイランドのUI表示を作成します。 ライブアクティビティに関するAppleの[前提条件と制限](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities#Understand-constraints)をよく理解してください。これらの制約はBrazeとは独立しています。 **Note:** 同じライブアクティビティに頻繁にプッシュを送信する場合は、`Info.plist`ファイルで`NSSupportsLiveActivitiesFrequentUpdates`を`YES`に設定することで、Appleの予算制限によるスロットリングを回避できます。詳細については、ActivityKitドキュメントの[`Determine the update frequency`](https://developer.apple.com/documentation/activitykit/updating-and-ending-your-live-activity-with-activitykit-push-notifications#Determine-the-update-frequency)セクションを参照してください。 #### 例 {#example} 競争している2つの野生動物救助チームに、保護しているフクロウに対してポイントが与えられるSuperb Owlショーの更新をユーザーに提供するライブアクティビティを作成すると想定してみましょう。この例では、`SportsActivityAttributes`という構造体を作成しましたが、`ActivityAttributes`の独自の実装を使用することもできます。 ```swift #if canImport(ActivityKit) import ActivityKit #endif @available(iOS 16.1, *) struct SportsActivityAttributes: ActivityAttributes { public struct ContentState: Codable, Hashable { var teamOneScore: Int var teamTwoScore: Int } var gameName: String var gameNumber: String } ``` ### ステップ 2: アクティビティを開始する {#start-the-activity} まず、アクティビティの登録方法を選択します。 - **リモート:** [`registerPushToStart`]()メソッドをユーザーライフサイクルの早い段階で、push-to-startトークンが必要になる前に呼び出し、[`/messages/live_activity/start`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/live_activity/start)エンドポイントを使用してアクティビティを開始します。 - **ローカル:** ライブアクティビティのインスタンスを作成し、[`launchActivity`]()メソッドを使用して、Brazeが管理するプッシュトークンを作成します。 **Important:** ライブアクティビティをリモートで登録するには、iOS 17.2以降が必要です。 #### ステップ 2.1: BrazeKitをウィジェット拡張に追加する {#step-21-add-brazekit-to-your-widget-extension} Xcodeプロジェクトで、アプリの名前を選択し、**General**を選択します。**Frameworks and Libraries**の下に`BrazeKit`がリストされていることを確認します。 ![サンプルXcodeプロジェクト内の「Frameworks and Libraries」にあるBrazeKitフレームワーク](https://www.braze.com/docs/ja/ja/assets/img/swift/live_activities/xcode_frameworks_and_libraries.png?cec8b144f4f7f25ba4df574c272bd622) #### ステップ 2.2: BrazeLiveActivityAttributesプロトコルを追加する {#brazeActivityAttributes} `ActivityAttributes`の実装に`BrazeLiveActivityAttributes`プロトコルへの準拠を追加し、属性モデルに`brazeActivityId`プロパティを追加します。 **Important:** iOSは`brazeActivityId`プロパティをライブアクティビティのpush-to-startペイロードの対応するフィールドにマップするため、名前を変更したり、他の値を割り当てたりしないでください。 ```swift import BrazeKit #if canImport(ActivityKit) import ActivityKit #endif @available(iOS 16.1, *) // 1. Add the `BrazeLiveActivityAttributes` conformance to your `ActivityAttributes` struct. struct SportsActivityAttributes: ActivityAttributes, BrazeLiveActivityAttributes { public struct ContentState: Codable, Hashable { var teamOneScore: Int var teamTwoScore: Int } var gameName: String var gameNumber: String // 2. Add the `String?` property to represent the activity ID. var brazeActivityId: String? } ``` #### ステップ 2.3: push-to-startの登録 {#step-23-register-for-push-to-start} 次にライブアクティビティのタイプを登録し、そのタイプに関連付けられたすべてのpush-to-startトークンとライブアクティビティインスタンスをBrazeが追跡できるようにします。 **Warning:** iOSオペレーティングシステムは、デバイスが再起動した後の最初のアプリインストール時にのみpush-to-startトークンを生成します。トークンが確実に登録されるようにするには、`didFinishLaunchingWithOptions`メソッドで`registerPushToStart`を呼び出してください。 ##### 例 次の例では、`LiveActivityManager`クラスがライブアクティビティオブジェクトを処理します。次に、`registerPushToStart`メソッドが`SportsActivityAttributes`を登録します。 ```swift import BrazeKit #if canImport(ActivityKit) import ActivityKit #endif class LiveActivityManager { @available(iOS 17.2, *) func registerActivityType() { // This method returns a Swift background task. // You may keep a reference to this task if you need to cancel it wherever appropriate, or ignore the return value if you wish. let pushToStartObserver: Task = Self.braze?.liveActivities.registerPushToStart( forType: Activity.self, name: SportsActivityAttributes.name ) } } ``` #### ステップ 2.4: push-to-start通知を送信する {#step-24-send-a-push-to-start-notification} [`/messages/live_activity/start`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/live_activity/start)エンドポイントを使用してリモートのpush-to-start通知を送信します。 [AppleのActivityKitフレームワーク](https://developer.apple.com/documentation/activitykit)を使用して、Braze SDKが管理できるプッシュトークンを取得できます。これにより、BrazeがバックエンドでAppleプッシュ通知サービス(APNs)にプッシュトークンを送信するため、Braze APIを通じてライブアクティビティを更新できます。 1. AppleのActivityKit APIを使用して、ライブアクティビティ実装のインスタンスを作成します。 2. `pushType`パラメータを`.token`に設定します。 3. 定義したライブアクティビティの`ActivitiesAttributes`と`ContentState`を渡します。 4. [`launchActivity(pushTokenTag:activity:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/liveactivities-swift.class)に渡して、Brazeインスタンスにアクティビティを登録します。`pushTokenTag`パラメータは、定義するカスタム文字列です。作成するライブアクティビティごとに一意である必要があります。 ライブアクティビティを登録すると、Braze SDKはプッシュトークンの変化を抽出して監視します。 #### 例 この例では、ライブアクティビティオブジェクトのインターフェイスとして`LiveActivityManager`というクラスを作成します。次に、`pushTokenTag`を`"sports-game-2024-03-15"`に設定します。 ```swift import BrazeKit #if canImport(ActivityKit) import ActivityKit #endif class LiveActivityManager { @available(iOS 16.2, *) func createActivity() { let activityAttributes = SportsActivityAttributes(gameName: "Superb Owl", gameNumber: "Game 1") let contentState = SportsActivityAttributes.ContentState(teamOneScore: "0", teamTwoScore: "0") let activityContent = ActivityContent(state: contentState, staleDate: nil) if let activity = try? Activity.request(attributes: activityAttributes, content: activityContent, // Setting your pushType as .token allows the Activity to generate push tokens for the server to watch. pushType: .token) { // Register your Live Activity with Braze using the pushTokenTag. // This method returns a Swift background task. // You may keep a reference to this task if you need to cancel it wherever appropriate, or ignore the return value if you wish. let liveActivityObserver: Task = AppDelegate.braze?.liveActivities.launchActivity(pushTokenTag: "sports-game-2024-03-15", activity: activity) } } } ``` ライブアクティビティウィジェットによって、この初期コンテンツがユーザーに表示されます。 ![2つのチームのスコアが表示されたiPhoneロック画面のライブアクティビティ。Wild Bird FundとOwl Rehabのスコアはどちらも0。](https://www.braze.com/docs/ja/ja/assets/img/swift/live_activities/example_1_1.png?b9615bf4d416a7865420f5364951ccd6){: style="max-width:40%;"} ### ステップ 3: アクティビティトラッキングを再開する {#resume-activity-tracking} Brazeがアプリ起動時にライブアクティビティを追跡できるようにするには、次の手順を実行します。 1. `AppDelegate`ファイルを開きます。 2. 使用可能な場合は、`ActivityKit`モジュールをインポートします。 3. アプリケーションで登録したすべての`ActivityAttributes`タイプについて、`application(_:didFinishLaunchingWithOptions:)`で[`resumeActivities(ofType:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/liveactivities-swift.class/resumeactivities(oftype:))を呼び出します。 これにより、Brazeはすべてのアクティブなライブアクティビティのプッシュトークン更新を追跡するタスクを再開できます。ユーザーがデバイス上のライブアクティビティを明示的に削除した場合、そのアクティビティは削除されたと見なされ、Brazeはそれを追跡しなくなります。 #### 例 ```swift import UIKit import BrazeKit #if canImport(ActivityKit) import ActivityKit #endif @main class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { if #available(iOS 16.1, *) { Self.braze?.liveActivities.resumeActivities( ofType: Activity.self ) } return true } } ``` ### ステップ 4: アクティビティを更新する {#update-the-activity} ![2チームのスコアが表示されたiPhoneロック画面のライブアクティビティ。Wild Bird Fundは2ポイント、Owl Rehabは4ポイント。](https://www.braze.com/docs/ja/ja/assets/img/swift/live_activities/example_1_2.png?c9ac24cf3bad2d8d1cc815a44699160e){: style="max-width:40%;float:right;margin-left:15px;"} [`/messages/live_activity/update`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/live_activity/update)エンドポイントを使用すると、Braze REST APIを介して渡されたプッシュ通知を通じてライブアクティビティを更新できます。このエンドポイントを使用して、ライブアクティビティの`ContentState`を更新します。 `ContentState`を更新すると、ライブアクティビティウィジェットに新しい情報が表示されます。前半終了時のSuperb Owlショーの表示例を以下に示します。 詳細については、[`/messages/live_activity/update`エンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/live_activity/update)の記事を参照してください。 ### ステップ 5: アクティビティを終了する {#end-the-activity} ライブアクティビティがアクティブな場合、ユーザーのロック画面とダイナミックアイランドの両方に表示されます。Brazeを通じて終了するには、[`/messages/live_activity/update`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/live_activity/update)エンドポイントで`end_activity`を`true`に設定します。 ライブアクティビティの終了の信頼性を向上させるには、以下のオプションの手順を実行します。 1. 同じ`update`リクエストにオプションで`dismissal_date`を含め、iOSがライブアクティビティUIを削除するタイミングを指定します。 2. [メッセージアクティビティログ](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/message_activity_log_tab)で配信結果を確認します。 #### 自動削除の設定 {#arranging-automatic-dismissal} 自動削除を設定するには、ライブアクティビティを開始した後に、更新エンドポイントへのフォローアップリクエストをスケジュールします。 1. 追跡可能な`activity_id`を含む`/messages/live_activity/start`リクエストを送信します。 2. その`activity_id`とターゲット終了時刻をバックエンドスケジューラーに保存します。 3. ターゲット終了時刻に、`end_activity`を`true`に設定した`/messages/live_activity/update`リクエストを送信します。 4. 同じ更新リクエストで削除日を設定します。詳細については、[`/messages/live_activity/update`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/live_activity/update)エンドポイントを参照してください。 削除のタイミングはiOSによって制御されることに注意してください。有効な終了リクエストを送信した後でも、ロック画面やダイナミックアイランドからの削除は、OSレベルの条件に基づいて遅延したり、異なる動作をしたりする場合があります。 ライブアクティビティはBrazeの外部でも終了できます。 * **ユーザーによる削除**: ユーザーは手動でライブアクティビティを削除できます。 * **タイムアウト**: デフォルトの8時間が経過すると、iOSはユーザーのダイナミックアイランドからライブアクティビティを削除します。デフォルトの12時間が経過すると、iOSはユーザーのロック画面からライブアクティビティを削除します。 詳細については、[`/messages/live_activity/update`エンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/live_activity/update)の記事を参照してください。 ## ライブアクティビティのトラッキング {#tracking-live-activities} ライブアクティビティのイベントは、Currents、Snowflakeデータ共有、およびクエリビルダーで利用できます。以下のイベントは、ライブアクティビティのライフサイクルの理解と監視、トークンの利用可能性の追跡、問題の独立した診断や配信ステータスの確認に役立ちます。 - [ライブアクティビティのPush To Startトークン変更](https://www.braze.com/docs/ja/ja/user_guide/data/braze_currents/event_glossary/customer_behavior_events#live-activity-push-to-start-token-change-events): push-to-start(PTS)トークンがBrazeで追加または更新されたタイミングをキャプチャし、ユーザーごとのトークン登録状況と利用可能性を追跡できます。 - [ライブアクティビティ更新トークンの変更](https://www.braze.com/docs/ja/ja/user_guide/data/braze_currents/event_glossary/customer_behavior_events#live-activity-update-token-change-events): ライブアクティビティ更新(LAU)トークンの追加、更新、または削除を追跡します。 - [ライブアクティビティ送信](https://www.braze.com/docs/ja/ja/user_guide/data/braze_currents/event_glossary/message_engagement_events#live-activity-send-events): Brazeによってライブアクティビティが開始、更新、または終了されるたびにログを記録します。 - [ライブアクティビティの結果](https://www.braze.com/docs/ja/ja/user_guide/data/braze_currents/event_glossary/message_engagement_events#live-activity-outcome-events): Brazeから送信された各ライブアクティビティについて、Appleプッシュ通知サービス(APNs)への最終的な配信ステータスを示します。 ## ライブアクティビティ送信の確認 {#verify-live-activity-sends} ワークスペースがiOSライブアクティビティを送信しているかどうかを確認する必要がある場合は、以下の方法を使用できます。 ### メッセージアクティビティログ {#message-activity-log} **設定** > **メッセージアクティビティログ**に移動し、ライブアクティビティのエラーでフィルタリングして、予想される期間中のライブアクティビティ関連の配信結果を確認します。詳細については、[メッセージアクティビティログ](https://www.braze.com/docs/ja/ja/user_guide/administer/global/workspace_settings/logs_and_alerts/message_activity_log)を参照してください。 ### クエリビルダー、Currents、またはSnowflakeデータ共有 {#query-builder-currents-or-snowflake-data-sharing} 以下のライブアクティビティイベントを確認して、ライブアクティビティのライフサイクルと配信を検証します。 - **ライブアクティビティ送信:** Brazeによってライブアクティビティが開始、更新、または終了されるたびにログを記録します - **ライブアクティビティの結果:** 送信された各ライブアクティビティについて、APNsへの最終的な配信ステータスを示します オプションで、トークンの利用可能性シグナルも確認できます。 - **ライブアクティビティのPush To Startトークン変更** - **ライブアクティビティ更新トークンの変更** ### API使用状況ダッシュボード {#api-usage-dashboard} **設定** > **APIキー** > **ダッシュボード**に移動し、**フィルター**を選択して**エンドポイント**でフィルタリングし、APIレスポンスを確認します。たとえば、`/messages/live_activity/update`(または`/messages/live_activity/start`)を選択して、過去30日間のリクエスト量を表示します。APIレスポンスは、APIが呼び出されており、このワークスペースでiOSライブアクティビティ通知が使用されていることを示します。詳細については、[API使用状況ダッシュボード](https://www.braze.com/docs/ja/ja/user_guide/analytics/dashboards/api_usage)を参照してください。 ## ライブアクティビティイベントの監視(オプション) {#observe-live-activity-events} **Important:** 以下のActivityKitストリームをAppleに直接サブスクライブしないでください。Brazeのサブスクリプションと競合し、ライブアクティビティが正しく機能しなくなります。 1. [`pushTokenUpdates`](https://developer.apple.com/documentation/activitykit/activity/pushtokenupdates-swift.property) 2. [`activityStateUpdates`](https://developer.apple.com/documentation/activitykit/activity/activitystateupdates-swift.property) 3. [`contentUpdates`](https://developer.apple.com/documentation/activitykit/activity/contentupdates-swift.property) 4. [`pushToStartTokenUpdates`](https://developer.apple.com/documentation/activitykit/activity/pushtostarttokenupdates) 5. [`activityUpdates`](https://developer.apple.com/documentation/activitykit/activity/activityupdates-swift.type.property) 代わりに、以下で説明するサブスクリプションを使用してください。 Braze SDKは、`braze.liveActivities`に2つのサブスクリプションメソッドを提供し、ライブアクティビティの完全なライフサイクルを監視できます。詳細なステップバイステップのウォークスルーについては、[ライブアクティビティチュートリアル](https://braze-inc.github.io/braze-swift-sdk/tutorials/brazekit/b4-live-activities)を参照してください。 - [`subscribeToStateUpdates(_:)`](#subscribe-to-state-updates): push-to-startトークン登録と実行中のアクティビティインスタンスの両方のライフサイクルイベントを配信します。 - [`subscribeToErrors(_:)`](#subscribe-to-errors): ライブアクティビティのトラッキング中に発生したSDKおよびサーバー側のエラーを配信します。 **Note:** 両方のメソッドは[`Braze.Cancellable`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/cancellable-swift.typealias)を返します。サブスクリプションは、返された値が強参照で保持されている限りアクティブなままです(たとえば、`Braze`インスタンスと同じライフサイクルを持つプロパティに格納します)。 ### サブスクリプションの設定 {#set-up-subscriptions} `application(_:didFinishLaunchingWithOptions:)`でサブスクリプションを一度設定し、アプリのライフタイム全体にわたって保持します。 ```swift class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? var stateSubscription: Braze.Cancellable? var errorSubscription: Braze.Cancellable? func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let braze = Braze(configuration: config) Self.braze = braze if #available(iOS 16.1, *) { stateSubscription = Self.braze?.liveActivities.subscribeToStateUpdates { event in self.handleStateUpdate(event) } errorSubscription = Self.braze?.liveActivities.subscribeToErrors { error in self.handleLiveActivityError(error) } } return true } } ``` **Note:** コールバックは将来のライブアクティビティイベントに対してのみトリガーされます。サブスクリプション時の現在の状態はリプレイされません。現在の状態のスナップショットを取得するには、`Activity.activities`を使用してください。 ### subscribeToStateUpdates {#subscribe-to-state-updates} `subscribeToStateUpdates(_:)`は、ライブアクティビティの完全なライフサイクルをカバーする`UpdateEvent`値を配信します。イベントは2つのスコープに分かれています。 - `.activityType(ActivityType)`: push-to-startトークン登録のためのタイプレベルイベント(iOS 17.2以降)。アクティビティインスタンスはまだ存在しません。 - `.activityInstance(ActivityInstance)`: 特定の実行中のアクティビティのインスタンスレベルイベント。 複数のサブスクライバーがサポートされており、各アクティブなサブスクリプションはすべてのイベントを独立して受信します。 #### タイプスコープのイベント {#type-scoped-events} | イベント | 発火タイミング | | ----- | ------------- | | `.pushToStartTokenRead(activityType:)` | push-to-startトークンがOSから読み取られました。Brazeはこのタイプの新しいアクティビティをリモートで開始できるようになりました。 | | `.pushToStartTokenFlushed(activityType:)` | トークンがBrazeサーバーに送信されました。Brazeはこのタイプのpush-to-start通知を送信できます。 | | `.pushToStartOptedOut(activityType:)` | ユーザーが`optOutPushToStart(type:)`を通じてこのアクティビティタイプのpush-to-startをオプトアウトしました。 | | `.pushToStartOptOutFlushed(activityType:)` | オプトアウトがBrazeサーバーに送信されました。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="タイプスコープのイベント" } #### インスタンススコープのイベント {#instance-scoped-events} | イベント | 発火タイミング | | ----- | ------------- | | `.started(activityId:activityType:pushTokenTag:launchSource:)` | SDKが`launchActivity(pushTokenTag:activity:)`を通じてこのアクティビティの追跡を開始しました。`launchSource`の値は、アプリが開始したアクティビティの場合は`.local`、リモートで開始されたアクティビティの場合は`.pushToStart`です。 | | `.resumed(activityId:activityType:pushTokenTag:)` | SDKが`resumeActivities(ofType:)`を通じてこのアクティビティの追跡を再開しました。 | | `.pushTokenFlushed(activityId:activityType:pushTokenTag:)` | アクティビティのプッシュトークンがBrazeサーバーに受け入れられました。アクティビティはリモート更新を受信できるようになりました。 | | `.active(activityId:activityType:)` | アクティビティは現在アクティブで、ユーザーに表示されています。 | | `.stale(activityId:activityType:staleDate:)` | アクティビティのコンテンツが古くなりました。iOS 16.2以降でのみ発行されます。 | | `.dismissed(activityId:activityType:)` | ユーザーがアクティビティを手動で削除しました。 | | `.ended(activityId:activityType:)` | アクティビティが終了しました。 | | `.contentUpdated(activityId:activityType:)` | アクティビティのコンテンツ状態が更新されました(iOS 16.2以降)。カスタムロジックを使用して、`Activity.activities`からIDで`Activity`を検索し、`activity.content.state`を通じて型付き状態にアクセスします。 | | `.pushTokenUpdated(activityId:activityType:)` | ActivityKitがアクティビティのプッシュトークンをローテーションしました。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="インスタンススコープのイベント" } ##### 例 ```swift func handleStateUpdate(_ event: Braze.LiveActivities.UpdateEvent) { switch event { // Type-scoped: push-to-start token lifecycle (iOS 17.2+) case .activityType(.pushToStartTokenRead(let activityType)): print("[\(activityType)] Push-to-start token read by SDK") // ... // Instance-scoped: SDK tracking case .activityInstance(.started(let id, let type, let tag, let source)): print("[\(type)] Activity \(id) started via \(source), tag: \(tag)") // ... // Instance-scoped: ActivityKit lifecycle case .activityInstance(.active(let id, let type)): print("[\(type)] Activity \(id) is active") // ... case .activityInstance(.ended(let id, let type)): print("[\(type)] Activity \(id) ended") // Instance-scoped: content updates (iOS 16.2+) case .activityInstance(.contentUpdated(let id, let type)): // For more advanced use cases of `contentUpdated`, see the section below print("[\(type)] Content updated for activity \(id)") case .activityInstance(.pushTokenUpdated(let id, let type)): print("[\(type)] Activity \(id) push token rotated") } } ``` ### subscribeToErrors {#subscribe-to-errors} `subscribeToErrors(_:)`は、`UpdateEvent`と同じ2つのスコープを使用して`ErrorEvent`値を配信します。 - `.activityType(ActivityType)`: push-to-start登録失敗のタイプレベルエラー。 - `.activityInstance(ActivityInstance)`: 実行中のアクティビティのインスタンスレベルエラー。 リトライが適切かどうかを判断するには、`isTransient`フラグを使用します。SDKは一時的な失敗を自動的にリトライします。 #### タイプスコープのエラー {#type-scoped-errors} | エラー | 発火タイミング | | ----- | ------------- | | `.pushToStartRegistrationFailed(activityType:isTransient:reason:)` | push-to-startトークンがBrazeサーバーに到達できませんでした。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="タイプスコープのエラー" } #### インスタンススコープのエラー {#instance-scoped-errors} | エラー | 発火タイミング | | ----- | ------------- | | `.registrationFailed(activityId:activityType:pushTokenTag:isTransient:reason:)` | アクティビティのプッシュトークンがBrazeへの登録に失敗しました。 | | `.activityNotFound(activityId:activityType:)` | `resumeActivities(ofType:)`が、もう実行されていないアクティビティの保存済みマッピングを検出しました。アプリが強制終了されている間にアクティビティが終了した可能性があります。 | | `.invalidPushTokenTag(activityId:activityType:tag:)` | `launchActivity(pushTokenTag:activity:)`が無効なタグで呼び出されました。タグは空でなく、256バイト未満である必要があります。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="インスタンススコープのエラー" } ##### 例 ```swift func handleLiveActivityError(_ error: Braze.LiveActivities.ErrorEvent) { switch error { // Type-scoped errors case .activityType(.pushToStartRegistrationFailed(let type, let isTransient, let reason)): if isTransient { print("[\(type)] Push-to-start registration failed (transient, will retry): \(reason)") } else { print("[\(type)] Push-to-start registration failed (permanent): \(reason)") } // Instance-scoped errors case .activityInstance(.registrationFailed(let id, let type, _, let isTransient, let reason)): if isTransient { print("[\(type)] Activity \(id) registration failed (transient, retrying): \(reason)") } else { print("[\(type)] Activity \(id) registration failed (permanent): \(reason)") } case .activityInstance(.activityNotFound(let id, let type)): print("[\(type)] Stored activity \(id) not found on resume") case .activityInstance(.invalidPushTokenTag(let id, let type, let tag)): print("[\(type)] Activity \(id) has invalid push token tag '\(tag)'") } } ``` ### コンテンツ状態の更新を処理する(オプション) {#handle-content-state} 実際のライブアクティビティインスタンスのコンテンツ状態を使用する場合は、このセクションに従ってください。 `.contentUpdated`イベントが発火したら、カスタムロジックを使用して`Activity.activities`からIDで実行中の`Activity`を検索し、`activity.content.state`を通じて型付き`ContentState`にアクセスします。 #### 単一の属性タイプ {#single-attributes-type} ```swift case .activityInstance(.contentUpdated(let id, let type)): #if canImport(ActivityKit) // Add custom logic look up the Activity by ID and access your app's typed ContentState. // In this example, `SportsActivityAttributes` is the app's custom type. if #available(iOS 16.2, *), let activity = findActivityInstance(id: id, as: SportsActivityAttributes.self) { // `activityContent` is now strongly typed as a `SportsActivityAttributes` let activityContent = activity.content.state print("[\(type)] Game \(id) — score: \(activityContent.teamOneScore)–\(activityContent.teamTwoScore)") return } #endif print("[\(type)] Content updated for activity \(id)") // ... // - MARK: Helper methods @available(iOS 16.2, *) func findActivityInstance( id: String, as type: Attributes.Type ) -> Activity? { // Use Apple's API to find the matching Live Activity instance: // - https://developer.apple.com/documentation/activitykit/activity/activities Activity.activities.first(where: { $0.id == id }) } ``` #### 複数の属性タイプ {#multiple-attributes-types} アプリが複数の`ActivityAttributes`タイプを使用している場合は、`type`文字列を確認して適切な`Activity`を検索します。 ```swift case .activityInstance(.contentUpdated(let id, let type)): #if canImport(ActivityKit) if #available(iOS 16.2, *) { if type == SportsActivityAttributes.name, let activity = findActivityInstance(id: id, as: SportsActivityAttributes.self) { let activityContent = activity.content.state print("[\(type)] Game \(id) — score: \(activityContent.teamOneScore)–\(activityContent.teamTwoScore)") return } else if type == OrderActivityAttributes.name, let activity = findActivityInstance(id: id, as: OrderActivityAttributes.self) { let activityContent = activity.content.state print("[\(type)] Order \(id) — status: \(activityContent.status), ETA: \(activityContent.eta)") return } } #endif print("[\(type)] Content updated for activity \(id)") // ... // - MARK: Helper methods @available(iOS 16.2, *) func findActivityInstance( id: String, as type: Attributes.Type ) -> Activity? { // Use Apple's API to find the matching Live Activity instance: // - https://developer.apple.com/documentation/activitykit/activity/activities Activity.activities.first(where: { $0.id == id }) } ``` ## よくある質問(FAQ) {#faq} ### 機能とサポート {#functionality-and-support} #### ライブアクティビティをサポートしているプラットフォームは? {#what-platforms-support-live-activities} 現在、ライブアクティビティはiOSとiPadOSに固有の機能です。デフォルトでは、iPhoneやiPadで起動したアクティビティは、ペアリングされたwatchOS 11以降またはmacOS 26以降のデバイスにも表示されます。 ![macOSのメニューバーにライブアクティビティがアラートとして表示されているスクリーンショット](https://www.braze.com/docs/ja/ja/assets/img/live-activity-macos.png?ae4757435bb769d2eb1ea1d297477a1c){: style="max-width:60%;"} ライブアクティビティの記事では、Braze Swift SDKを使用してライブアクティビティを管理するための[前提条件](https://www.braze.com/docs/ja/ja/developer_guide/platforms/swift/live_activities#prerequisites)について説明しています。 #### React Nativeアプリはライブアクティビティをサポートしていますか? {#do-react-native-apps-support-live-activities} はい、React Native SDK 3.0.0以降は、Braze Swift SDKを介してライブアクティビティをサポートしています。つまり、Braze Swift SDKの上に直接React Native iOSのコードを記述する必要があります。 Appleが提供するライブアクティビティ機能は、JavaScriptでは変換できない言語機能(Swift Concurrency、generics、SwiftUIなど)を使用しているため、ライブアクティビティ用のReact Native固有のJavaScriptコンビニエンスAPIは存在しません。 #### Brazeはキャンペーンやキャンバスステップとしてのライブアクティビティをサポートしていますか? {#does-braze-support-live-activities-as-a-campaign-or-canvas-step} いいえ、現在サポートされていません。 ### プッシュ通知とライブアクティビティ {#push-notifications-and-live-activities} #### ライブアクティビティがアクティブな状態でプッシュ通知が送信された場合はどうなりますか? {#what-happens-if-a-push-notification-is-sent-while-a-live-activity-is-active} ![ブルズ対ベアーズのスポーツ中継のライブアクティビティが画面中央に、プッシュ通知のlorem ipsumテキストが画面下部に表示された携帯電話の画面](https://www.braze.com/docs/ja/ja/assets/img/push-vs-live-activities.png?e6bf39f47386b7741f04078c5b0f55fc){: style="max-width:30%;float:right;margin-left:15px;"} ライブアクティビティとプッシュ通知は異なる画面領域を占有するため、ユーザーの画面上で競合することはありません。 #### ライブアクティビティがプッシュメッセージ機能を活用する場合、ライブアクティビティを受信するためにプッシュ通知を有効にする必要がありますか? {#if-live-activities-leverage-push-message-functionality-do-push-notifications-need-to-be-enabled-to-receive-live-activities} ライブアクティビティは更新にプッシュ通知を利用しますが、異なるユーザー設定によって制御されています。ユーザーはライブアクティビティにオプトインしつつプッシュ通知はオプトアウトでき、その逆も可能です。 ライブアクティビティ更新トークンは8時間後に期限切れになります。 #### ライブアクティビティにはプッシュプライマーが必要ですか? {#do-live-activities-require-push-primers} [プッシュプライマー](https://www.braze.com/docs/ja/ja/user_guide/channels/push/best_practices/push_primer_messages)は、ユーザーにアプリからのプッシュ通知をオプトインするよう促すベストプラクティスです。しかし、ライブアクティビティにオプトインするためのシステムプロンプトはありません。デフォルトでは、ユーザーがiOS 16.1以降でアプリをインストールすると、そのアプリのライブアクティビティにオプトインされます。この権限は、アプリごとにデバイス設定で無効化または再有効化できます。 ### 技術的なトピックとトラブルシューティング {#technical-topics-and-troubleshooting} #### ライブアクティビティにエラーがあるかどうかを確認するには? {#how-do-i-know-if-live-activities-has-errors} ライブアクティビティのエラーは、Brazeダッシュボードの[メッセージアクティビティログ](https://www.braze.com/docs/ja/ja/user_guide/administer/global/workspace_settings/logs_and_alerts/message_activity_log)に記録されます。ここで「LiveActivity Errors」でフィルタリングできます。 #### push-to-start通知を送信した後、ライブアクティビティを受信できないのはなぜですか? {#after-sending-a-push-to-start-notification-why-havent-i-received-my-live-activity} まず、[`messages/live_activity/start`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/live_activity/start)エンドポイントで説明されているすべての必須フィールドがペイロードに含まれていることを確認します。`activity_attributes`および`content_state`フィールドは、プロジェクトのコードで定義されているプロパティと一致する必要があります。ペイロードが正しいことが確かな場合は、APNsによってレート制限されている可能性があります。この制限はBrazeではなくAppleによって課されています。 push-to-start通知がデバイスに正常に届いたがレート制限のために表示されなかったことを確認するには、Macのコンソールアプリを使用してプロジェクトをデバッグします。目的のデバイスの記録プロセスをアタッチし、検索バーで`process:liveactivitiesd`を使用してログをフィルタリングします。 #### push-to-startでライブアクティビティを開始した後、新しい更新を受信しないのはなぜですか? {#after-starting-my-live-activity-with-push-to-start-why-isnt-it-receiving-new-updates} [上記](#swift_brazeActivityAttributes)の手順が正しく実装されていることを確認してください。`ActivityAttributes`には、`BrazeLiveActivityAttributes`プロトコルへの準拠と`brazeActivityId`プロパティの両方が含まれている必要があります。 ライブアクティビティのpush-to-start通知を受信したら、Braze URLの`/push_token_tag`エンドポイントへの送信ネットワークリクエストが表示され、`"tag"`フィールドの下に正しいアクティビティIDが含まれていることを再確認してください。 最後に、更新ペイロード内のライブアクティビティ属性タイプが、SDKメソッド呼び出しの`registerPushToStart`で使用した文字列とクラスに完全に一致していることを確認してください。定数を使用してタイプミスを防いでください。 #### `live_activity/update`エンドポイントを使用しようとすると、アクセス拒否の応答が返されます。なぜですか? {#i-am-receiving-an-access-denied-response-when-i-try-to-use-the-live_activityupdate-endpoint-why} 使用するAPIキーには、さまざまなBraze APIエンドポイントにアクセスするための適切な権限を付与する必要があります。以前に作成したAPIキーを使用している場合、権限の更新を忘れている可能性があります。[APIキーセキュリティの概要](https://www.braze.com/docs/ja/ja/api/basics#rest-api-key-security)を確認してください。 #### `messages/send`エンドポイントは`messages/live_activity/update`エンドポイントとレート制限を共有していますか? {#does-the-messagessend-endpoint-share-rate-limits-with-the-messageslive_activityupdate-endpoint} デフォルトでは、`messages/live_activity/update`エンドポイントのレート制限は、ワークスペースごとに、複数のエンドポイントにわたって、1時間あたり250,000リクエストです。詳細については、[APIレート制限](https://www.braze.com/docs/ja/ja/api/api_limits)を参照してください。 # Android Braze SDKのライブ更新 Source: /docs/ja/developer_guide/live_notifications/live_updates/index.md # Braze SDKのフィーチャーフラグ Source: /docs/ja/developer_guide/feature_flags/index.md # Feature flags > Feature flags allow you to remotely enable or disable functionality for a specific or random selection of users. Importantly, they let you turn a feature on and off in production without additional code deployment or app store updates. This allows you to safely roll out new features with confidence. **Tip:** When you're ready to create your own feature flags, check out [Creating feature flags](https://www.braze.com/docs/ja/ja/developer_guide/feature_flags/create/). ## Prerequisites These are the minimum SDK versions needed to start using feature flags: ## Use cases ### Gradual rollouts Use feature flags to gradually enable features to a sample population. For example, you can soft launch a new feature to your VIP users first. This strategy helps mitigate risks associated with shipping new features to everyone at once and helps catch bugs early. ![Moving image of rollout traffic slider going from 0% to 100%.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature-flags-rollout.gif?9a18c29013c714574f37682a1e7b0637) For example, let's say we've decided to add a new "Live Chat Support" link to our app for faster customer service. We could release this feature to all customers at once. However, a wide release carries risks, such as: * Our Support team is still in training, and customers can start support tickets after it's released. This doesn't give us any leeway in case the Support team needs more time. * We're unsure of the actual volume of new support cases we'll get, so we might not be staffed appropriately. * If our Support team is overwhelmed, we have no strategy to quickly turn this feature off again. * There might be bugs introduced in the chat widget, and we don't want customers to have a negative experience. With Braze feature flags, we can instead gradually roll out the feature and mitigate all of these risks: * We will turn on the "Live Chat Support" feature when the Support team says they're ready. * We will enable this new feature for only 10% of users to determine if we're staffed appropriately. * If there are any bugs, we can quickly disable the feature instead of rushing to ship a new release. To gradually roll out this feature, we can [create a feature flag](https://www.braze.com/docs/ja/ja/developer_guide/feature_flags/create/) named "Live Chat Widget." ![Feature flag details for an example named Live Chat Widget. The ID is enable_live_chat. This feature flag description reads that the live chat widget will show on the support page.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature-flags-use-case-livechat-1.png?f87ac91f3de136edd7784b806876d8c0) In our app code, we will only show the **Start Live Chat** button when the Braze feature flag is enabled: ```javascript import {useState} from "react"; import * as braze from "@braze/web-sdk"; // Get the initial value from the Braze SDK const featureFlag = braze.getFeatureFlag("enable_live_chat"); const [liveChatEnabled, setLiveChatEnabled] = useState(featureFlag.enabled); // Listen for updates from the Braze SDK braze.subscribeToFeatureFlagsUpdates(() => { const newValue = braze.getFeatureFlag("enable_live_chat").enabled; setLiveChatEnabled(newValue); }); // Only show the Live Chat if the Braze SDK determines it is enabled return (<> Need help? {liveChatEnabled && } ) ``` ```java // Get the initial value from the Braze SDK FeatureFlag featureFlag = braze.getFeatureFlag("enable_live_chat"); Boolean liveChatEnabled = featureFlag != null && featureFlag.getEnabled(); // Listen for updates from the Braze SDK braze.subscribeToFeatureFlagsUpdates(event -> { FeatureFlag newFeatureFlag = braze.getFeatureFlag("enable_live_chat"); Boolean newValue = newFeatureFlag != null && newFeatureFlag.getEnabled(); liveChatEnabled = newValue; }); // Only show the Live Chat view if the Braze SDK determines it is enabled if (liveChatEnabled) { liveChatView.setVisibility(View.VISIBLE); } else { liveChatView.setVisibility(View.GONE); } ``` ```kotlin // Get the initial value from the Braze SDK val featureFlag = braze.getFeatureFlag("enable_live_chat") var liveChatEnabled = featureFlag?.enabled // Listen for updates from the Braze SDK braze.subscribeToFeatureFlagsUpdates() { event -> val newValue = braze.getFeatureFlag("enable_live_chat")?.enabled liveChatEnabled = newValue } // Only show the Live Chat view if the Braze SDK determines it is enabled if (liveChatEnabled) { liveChatView.visibility = View.VISIBLE } else { liveChatView.visibility = View.GONE } ``` ```swift // Get the initial value from the Braze SDK let featureFlag = braze.featureFlags.featureFlag(id: "enable_live_chat") var liveChatEnabled = featureFlag?.enabled ?? false // Listen for updates from the Braze SDK braze.featureFlags.subscribeToUpdates() { _ in let newValue = braze.featureFlags.featureFlag(id: "enable_live_chat")?.enabled ?? false liveChatEnabled = newValue } // Only show the Live Chat view if the Braze SDK determines it is enabled liveChatView.isHidden = !liveChatEnabled ``` ### Remotely control app variables Use feature flags to modify your app's functionality in production. This can be particularly important for mobile apps, where app store approvals prevent rolling out changes quickly to all users. For example, let's say that our marketing team wants to list our current sales and promotions in our app's navigation. Normally, our engineers require one week's lead time for any changes and three days for an app store review. But with Thanksgiving, Black Friday, Cyber Monday, Hanukkah, Christmas, and New Year's Day all within two months, we won't be able to meet these tight deadlines. With feature flags, we can let Braze power the content of our app navigation link, letting our marketing manager make changes in minutes rather than days. To remotely configure this feature, we'll create a new feature flag called `navigation_promo_link` and define the following initial properties: ![Feature flag with link and text properties directing to a generic sales page.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature-flags-use-case-navigation-link-1.png?bb61c2aee4c725233b491bdb762a99f8) In our app, we'll use getter methods by Braze to retrieve this feature flag's properties and build the navigation links based on those values: ```javascript import * as braze from "@braze/web-sdk"; import {useState} from "react"; const featureFlag = braze.getFeatureFlag("navigation_promo_link"); // Check if the feature flag is enabled const [promoEnabled, setPromoEnabled] = useState(featureFlag.enabled); // Read the "link" property const [promoLink, setPromoLink] = useState(featureFlag.getStringProperty("link")); // Read the "text" property const [promoText, setPromoText] = useState(featureFlag.getStringProperty("text")); return (<>
Home { promoEnabled && {promoText} } Products Categories
) ``` ```java // liveChatView is the View container for the Live Chat UI FeatureFlag featureFlag = braze.getFeatureFlag("navigation_promo_link"); if (featureFlag != null && featureFlag.getEnabled()) { liveChatView.setVisibility(View.VISIBLE); } else { liveChatView.setVisibility(View.GONE); } liveChatView.setPromoLink(featureFlag.getStringProperty("link")); liveChatView.setPromoText(featureFlag.getStringProperty("text")); ``` ```kotlin // liveChatView is the View container for the Live Chat UI val featureFlag = braze.getFeatureFlag("navigation_promo_link") if (featureFlag?.enabled == true) { liveChatView.visibility = View.VISIBLE } else { liveChatView.visibility = View.GONE } liveChatView.promoLink = featureFlag?.getStringProperty("link") liveChatView.promoText = featureFlag?.getStringProperty("text") ``` ```swift let featureFlag = braze.featureFlags.featureFlag(id: "navigation_promo_link") if let featureFlag { liveChatView.isHidden = !featureFlag.enabled } else { liveChatView.isHidden = true } liveChatView.promoLink = featureFlag?.stringProperty("link") liveChatView.promoText = featureFlag?.stringProperty("text") ``` Now, the day before Thanksgiving, we only have to change those property values in the Braze dashboard. ![Feature flag with link and text properties directing to a Thanksgiving sales page.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature-flags-use-case-navigation-link-2.png?161a40a2366fc2441facbd206639b55c) As a result, the next time someone loads the app, they will see the new Thanksgiving deals. ### Message coordination Use feature flags to synchronize a feature's rollout and messaging and strengthen collaboration between product and marketing teams. By coordinating feature releases and messaging through feature flags, both teams can align their strategies and create consistent user experiences. For example, let's say that we're launching a new loyalty rewards program for our users. It can be difficult for marketing and product teams to perfectly coordinate the timing of promotional messaging with a feature's rollout. However, with feature flags in Canvas, our product team can apply sophisticated logic to enable a feature for a specific audience, while our marketing team controls the related messaging to those same users. To effectively coordinate feature rollout and messaging, we'll create a new feature flag called `show_loyalty_program`. For our initial phased release, we'll let Canvas control when and for whom the feature flag is enabled. For now, we'll leave the rollout percentage at 0% and not select any target segments. ![A feature flag with the name Loyalty Rewards Program. The ID is show_loyalty_program, and the description that this shows the new loyalty rewards program on the home screen and profile page.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature-flags-use-case-loyalty.png?8df52467dc60091b3ee90869d4c0c688) Then, in Canvas, we'll create a [Feature Flag step](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/canvas/canvas_components/feature_flags/) that enables the `show_loyalty_program` feature flag for our "High Value Customers" segment: ![An example of a Canvas with an Audience Split step where the high-value customers segment turns on the show_loyalty_program feature flag.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature-flags-use-case-canvas-flow.png?20b6eb4882f8f131848dff0c70948c92) Now, users in this segment start to see the new loyalty program, and after it's enabled, an email and survey are sent out automatically to help our teams gather feedback. ### Feature experimentation Use feature flags to experiment and confirm your hypotheses around your new feature. By splitting traffic into two or more groups, you can compare the impact of a feature flag across groups, and determine the best course of action based on the results. An [A/B test](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/testing/multivariant_testing/) is a powerful tool that compares users' responses to multiple versions of a variable. In this example, our team has built a new checkout flow for our eCommerce app. Even though we're confident it's improving the user experience, we want to run an A/B test to measure its impact on our app's revenue. To begin, we'll create a new feature flag called `enable_checkout_v2`. We won't add an audience or rollout percentage. Instead, we'll use a feature flag experiment to split traffic, enable the feature, and measure the outcome. In our app, we'll check if the feature flag is enabled or not and swap out the checkout flow based on the response: ```javascript import * as braze from "@braze/web-sdk"; const featureFlag = braze.getFeatureFlag("enable_checkout_v2"); braze.logFeatureFlagImpression("enable_checkout_v2"); if (featureFlag?.enabled) { return } else { return } ``` ```java FeatureFlag featureFlag = braze.getFeatureFlag("enable_checkout_v2"); braze.logFeatureFlagImpression("enable_checkout_v2"); if (featureFlag != null && featureFlag.getEnabled()) { return new NewCheckoutFlow(); } else { return new OldCheckoutFlow(); } ``` ```kotlin val featureFlag = braze.getFeatureFlag("enable_checkout_v2") braze.logFeatureFlagImpression("enable_checkout_v2") if (featureFlag?.enabled == true) { return NewCheckoutFlow() } else { return OldCheckoutFlow() } ``` ```swift let featureFlag = braze.featureFlags.featureFlag(id: "enable_checkout_v2") braze.featureFlags.logFeatureFlagImpression(id: "enable_checkout_v2") if let featureFlag, featureFlag.enabled { return NewCheckoutFlow() } else { return OldCheckoutFlow() } ``` We'll set up our A/B test in a [Feature Flag Experiment](https://www.braze.com/docs/ja/ja/developer_guide/feature_flags/experiments/). Now, 50% of users will see the old experience, while the other 50% will see the new experience. We can then analyze the two variants to determine which checkout flow resulted in a higher conversion rate. ![A feature flag experiment splitting traffic into two 50 percent groups.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature-flag-use-case-campaign-experiment.png?e8202a94961d079e7676f6d8345ab8cc) Once we determine our winner, we can stop this campaign and increase the rollout percentage on the feature flag to 100% for all users while our engineering team hard-codes this into our next app release. ### Segmentation Use the **Feature Flag** filter to create a segment or target messaging at users based on whether they have a feature flag enabled. For example, let's say we have a feature flag that controls premium content in our app. We could create a segment that filters for users who don't have the feature flag enabled, and then send that segment a message urging them to upgrade their account to view premium content. ![](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature_flag_segmentation_filter.png?1e1d240bffb7e96c29d06a6fe26298aa) For more information about filtering on segments, see [Creating a segment](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/segments/creating_a_segment/). **Note:** To prevent recursive segments, it is not possible to create a segment that references other feature flags. ## Plan limitations These are the feature flag limitations for free and paid plans. | Feature | Free version | Paid version | | :---------------------------------------------------------------------------------------------------------------- | :--------------- | ----------------- | | [Active feature flags](#active-feature-flags) | 10 per workspace | 110 per workspace | | [Active campaign experiments](https://www.braze.com/docs/ja/ja/developer_guide/feature_flags/experiments/) | 1 per workspace | 100 per workspace | | [Feature Flag Canvas steps](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/canvas/canvas_components/feature_flags/) | Unlimited | Unlimited | {: .reset-td-br-1 .reset-td-br-2 aria-label="Plan limitations" } A feature flag is considered active and will count toward your limit if any of the following apply: - Rollout is more than 0% - Used in an active Canvas - Used in an active experiment Even if the same feature flag matches multiple criteria, such as if it's used in a Canvas and the rollout is 50%, it will only count as 1 active feature flag toward your limit. **Note:** To purchase the paid version of feature flags, contact your Braze account manager, or request an upgrade in the Braze dashboard. # フィーチャーフラグを作成する Source: /docs/ja/developer_guide/feature_flags/create/index.md # Create feature flags > Feature flags allow you to remotely enable or disable functionality for a selection of users. Create a new feature flag within the Braze dashboard. Provide a name and an `ID`, a target audience, and a percentage of users for whom to enable to this feature. Then, using that same `ID` in your app or website's code, you can conditionally run certain parts of your business logic. To learn more about feature flags and how you can use them in Braze, see [About feature flags](https://www.braze.com/docs/ja/ja/developer_guide/feature_flags/). ## Prerequisites ### SDK version To use feature flags, ensure your SDKs are up to date with at least these minimum versions: ### Braze permissions To manage feature flags in the dashboard, you'll either need to be an Administrator, or have the following [permissions](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/manage_your_braze_users/user_permissions/): | Permission | What you can do | |-------------------------------------------------------------------------------|-------------------------------------------| | **Manage Feature Flags** | View, create, and edit feature flags. | | **Access Campaigns, Canvases, Cards, Feature Flags, Segments, Media Library** | View the list of available feature flags. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Braze permissions" } ## Creating a feature flag ### Step 1: Create a new feature flag Go to **Messaging** > **Feature Flags**, then select **Create Feature Flag**. ![A datatable showing an existing feature flag and how to create a new one.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/create_ff.png?c5a473da4c9497a16786b50273e89722){: style="max-width:75%"} ### Step 2: Fill out the details Under **Feature flag details**, enter a name, ID, and description for your feature flag. ![A form showing that you can add a name, ID, description and properties to a feature flag.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/create_ff_properties.png?08b4de8b7b9b76779e97203d614e6689){: style="max-width:75%"} | Field | Description | |--------------|----------------------------------------------------------------------------| | Name | A human-readable title for your marketers and administrators. | | ID | The unique ID you'll use in your code to check if this feature is [enabled for a user](#enabled). This ID cannot be changed later, so review the [ID naming best practices](#naming-conventions) before continuing. | | Description | An optional description that gives some context about your feature flag. | | Properties | Optional properties that remotely configure your feature flag. They can be overwritten in Canvas steps or feature flag experiments. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Step 2: Fill out the details" } ### Step 2a: Create custom properties Under **Properties**, you can optionally create custom properties your app can access through the Braze SDK when your feature is enabled. You can assign a string, boolean, image, timestamp, JSON, or a number value to each variable, as well as set a default value. In the following example, the feature flag shows an out-of-stock banner for an eCommerce store using the custom properties listed: |Property Name|Type|Value| |--|--|--| |`banner_height`|`number`|`75`| |`banner_color`|`string`|`blue`| |`banner_text`|`string`|`Widgets are out of stock until July 1.`| |`dismissible`|`boolean`|`false`| |`homepage_icon`|`image`|`http://s3.amazonaws.com/[bucket_name]/`| |`account_start`|`timestamp`|`2011-01-01T12:00:00Z`| |`footer_settings`|`JSON`|`{ "colors": [ "red", "blue", "green" ], "placement": 123 }`| {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Step 2a: Create custom properties" } **Tip:** There is no limit to the number of properties you can add. However, a feature flag's properties are limited to a total of 10,000 characters. ### Step 4: Choose segments to target Before rolling out a feature flag, you need to choose a [segment](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/segments/) of users to target. Select **Add Rule** on your newly created flag and then use the filter group and segment dropdown menus to filter users out of your target audience. Add multiple filters to further narrow your audience. ![A textbox labeled Rollout Traffic with the ability to add segments and filters.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/segmentation_ff.png?32d97ed8745dd0fa1a0e3be1b416dc65){: style="max-width:75%;"} ### Step 5: Set the rollout traffic {#rollout} By default, feature flags are always inactive, which allows you to separate your feature release's date from your total user activation. To begin your rollout, use the **Rollout Traffic** section to enter a percentage in the text box. This will choose the percentage of random users in your selected segment to receive this new feature. **Important:** Do not set your rollout traffic above 0% until you are ready for your new feature to go live. When you initially define your feature flag in the dashboard, leave this setting at 0%. **Important:** To roll out a flag with just one rule or to a singular audience, add your first rule with segmentation criteria and rollout percentages selected. Lastly, confirm the **Everyone Else** rule is toggled off, and save your flag. ## Multi-rule feature flag rollouts Use multi-rule feature flag rollouts to define a sequence of rules for evaluating users, which allows for precise segmentation and controlled feature releases. This method is ideal for deploying the same feature to diverse audiences. ### Evaluation order Feature flag rules are evaluated from top to bottom, in the order they're listed. A user qualifies for the first rule they meet. If a user doesn't meet any rules, their eligibility is determined by the default "Everyone Else" rule. ### User qualification - If a user meets the criteria for the first rule, they are immediately eligible to receive the feature flag. - If a user doesn't qualify for the first rule, they're evaluated against the second rule, and so on. The sequential evaluation continues until a user qualifies for a rule or reaches the "Everyone Else" rule at the bottom of the list. ### "Everyone Else" rule The "Everyone Else" rule acts as a default. If a user doesn't qualify for any preceding rules, their eligibility for the feature flag will be determined by the toggle setting of the "Everyone Else" rule. For example, if the "Everyone Else" rule is toggled "Off", in the default state, a user who doesn't meet the criteria for any other rules won't receive the feature flag upon their session start. ### Re-ordering rules By default, rules are ordered in the sequence that they're created, but you can reorder these rules by dragging and dropping them in the dashboard. ![An image showing that a user can add a rule to a feature flag.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/add_rule.png?5e7f228358ecd02cb9f215d94a96b050){: style="max-width:80%;"} ![An image showing a summary of a feature flag with multiple rules added and an everyone else rule.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/mr_rules_overview.png?6b3828dbafe8adf27aa654af59b30a3f){: style="max-width:80%;"} ### Multi-rule feature flag use cases #### Gradually release a checkout page Let's say you work for an eCommerce brand and have a new checkout page that you want to rollout across different geographies to ensure stability. Using multi-rule feature flags, you can set the following: - **Rule 1:** Your US segment is set to 100%. - **Rule 2:** Your segment is set to 50% of your Brazilian users, so not all of them receive the flow at one time. - **Rule 3 (Everyone Else):** For all other users, toggle on your "Everyone Else" rule and set it to 15%, so that a portion of all users can check out with the new flow. #### Reach internal testers first Let's say you're a product manager who wants to make sure your internal testers always receive the feature flag when you release a new product. You can add your internal testers segment to your first rule and set it to 100%, so that your internal testers are eligible during every feature rollout. ## Using the "enabled" field for your feature flags {#enabled} After you've defined your feature flag, configure your app or site to check whether or not it is enabled for a particular user. When it is enabled, you'll set some action or reference the feature flag's variable properties based on your use case. The Braze SDK provides getter methods to pull your feature flag's status and its properties into your app. Feature flags are refreshed automatically at session start so that you can display the most up-to-date version of your feature upon launch. The SDK caches these values so they can be used while offline. **Note:** Be sure to log [feature flag impressions](#impressions). Let's say you were to rolling out a new type of user profile for your app. You might set the `ID` as `expanded_user_profile`. Then, you would have your app check to see if it should display this new user profile to a particular user. For example: ```javascript const featureFlag = braze.getFeatureFlag("expanded_user_profile"); if (featureFlag?.enabled) { console.log(`expanded_user_profile is enabled`); } else { console.log(`expanded_user_profile is not enabled`); } ``` ```swift let featureFlag = braze.featureFlags.featureFlag(id: "expanded_user_profile") if featureFlag?.enabled == true { print("expanded_user_profile is enabled") } else { print("expanded_user_profile is not enabled") } ``` ```java FeatureFlag featureFlag = braze.getFeatureFlag("expanded_user_profile"); if (featureFlag != null && featureFlag.getEnabled()) { Log.i(TAG, "expanded_user_profile is enabled"); } else { Log.i(TAG, "expanded_user_profile is not enabled"); } ``` ```kotlin val featureFlag = braze.getFeatureFlag("expanded_user_profile") if (featureFlag?.enabled == true) { Log.i(TAG, "expanded_user_profile is enabled.") } else { Log.i(TAG, "expanded_user_profile is not enabled.") } ``` ```javascript const featureFlag = await Braze.getFeatureFlag("expanded_user_profile"); if (featureFlag?.enabled) { console.log(`expanded_user_profile is enabled`); } else { console.log(`expanded_user_profile is not enabled`); } ``` ```csharp var featureFlag = Appboy.AppboyBinding.GetFeatureFlag("expanded_user_profile"); if (featureFlag != null && featureFlag.Enabled) { Console.WriteLine("expanded_user_profile is enabled"); } else { Console.WriteLine("expanded_user_profile is not enabled"); } ``` ```javascript const featureFlag = await BrazePlugin.getFeatureFlag("expanded_user_profile"); if (featureFlag?.enabled) { console.log(`expanded_user_profile is enabled`); } else { console.log(`expanded_user_profile is not enabled`); } ``` ```dart BrazeFeatureFlag? featureFlag = await braze.getFeatureFlagByID("expanded_user_profile"); if (featureFlag?.enabled == true) { print("expanded_user_profile is enabled"); } else { print("expanded_user_profile is not enabled"); } ``` ```brightscript featureFlag = m.braze.getFeatureFlag("expanded_user_profile") if featureFlag <> invalid and featureFlag.enabled print "expanded_user_profile is enabled" else print "expanded_user_profile is not enabled" end if ``` ### Logging a feature flag impression {#impressions} Track a feature flag impression whenever a user has had an opportunity to interact with your new feature, or when they __could__ have interacted if the feature is disabled (in the case of a control group in an A/B test). Feature flag impressions are only logged once per session. Usually, you can put this line of code directly underneath where you reference your feature flag in your app: ```javascript braze.logFeatureFlagImpression("expanded_user_profile"); ``` ```swift braze.featureFlags.logFeatureFlagImpression(id: "expanded_user_profile") ``` ```java braze.logFeatureFlagImpression("expanded_user_profile"); ``` ```kotlin braze.logFeatureFlagImpression("expanded_user_profile") ``` ```javascript Braze.logFeatureFlagImpression("expanded_user_profile"); ``` ```csharp Appboy.AppboyBinding.LogFeatureFlagImpression("expanded_user_profile"); ``` ```javascript BrazePlugin.logFeatureFlagImpression("expanded_user_profile"); ``` ```dart braze.logFeatureFlagImpression("expanded_user_profile"); ``` ```brightscript m.Braze.logFeatureFlagImpression("expanded_user_profile"); ``` ### Accessing properties {#accessing-properties} To access the properties of a feature flag, use one of the following methods depending on the type you defined in the dashboard. If there is no such property of the corresponding type for the key you provided, these methods will return `null`. ```javascript // Returns the Feature Flag instance const featureFlag = braze.getFeatureFlag("expanded_user_profile"); // Returns the String property const stringProperty = featureFlag.getStringProperty("color"); // Returns the boolean property const booleanProperty = featureFlag.getBooleanProperty("expanded"); // Returns the number property const numberProperty = featureFlag.getNumberProperty("height"); // Returns the Unix UTC millisecond timestamp property as a number const timestampProperty = featureFlag.getTimestampProperty("account_start"); // Returns the image property as a String of the image URL const imageProperty = featureFlag.getImageProperty("homepage_icon"); // Returns the JSON object property as a FeatureFlagJsonPropertyValue const jsonProperty = featureFlag.getJsonProperty("footer_settings"); ``` ```swift // Returns the Feature Flag instance let featureFlag: FeatureFlag = braze.featureFlags.featureFlag(id: "expanded_user_profile") // Returns the string property let stringProperty: String? = featureFlag.stringProperty(key: "color") // Returns the boolean property let booleanProperty: Bool? = featureFlag.boolProperty(key: "expanded") // Returns the number property as a double let numberProperty: Double? = featureFlag.numberProperty(key: "height") // Returns the Unix UTC millisecond timestamp property as an integer let timestampProperty: Int? = featureFlag.timestampProperty(key: "account_start") // Returns the image property as a String of the image URL let imageProperty: String? = featureFlag.imageProperty(key: "homepage_icon") // Returns the JSON object property as a [String: Any] dictionary let jsonObjectProperty: [String: Any]? = featureFlag.jsonObjectProperty(key: "footer_settings") ``` ```java // Returns the Feature Flag instance FeatureFlag featureFlag = braze.getFeatureFlag("expanded_user_profile"); // Returns the String property String stringProperty = featureFlag.getStringProperty("color"); // Returns the boolean property Boolean booleanProperty = featureFlag.getBooleanProperty("expanded"); // Returns the number property Number numberProperty = featureFlag.getNumberProperty("height"); // Returns the Unix UTC millisecond timestamp property as a long Long timestampProperty = featureFlag.getTimestampProperty("account_start"); // Returns the image property as a String of the image URL String imageProperty = featureFlag.getImageProperty("homepage_icon"); // Returns the JSON object property as a JSONObject JSONObject jsonObjectProperty = featureFlag.getJSONProperty("footer_settings"); ``` ```kotlin // Returns the Feature Flag instance val featureFlag = braze.getFeatureFlag("expanded_user_profile") // Returns the String property val stringProperty: String? = featureFlag.getStringProperty("color") // Returns the boolean property val booleanProperty: Boolean? = featureFlag.getBooleanProperty("expanded") // Returns the number property val numberProperty: Number? = featureFlag.getNumberProperty("height") // Returns the Unix UTC millisecond timestamp property as a long val timestampProperty: Long? = featureFlag.getTimestampProperty("account_start") // Returns the image property as a String of the image URL val imageProperty: String? = featureFlag.getImageProperty("homepage_icon") // Returns the JSON object property as a JSONObject val jsonObjectProperty: JSONObject? = featureFlag.getJSONProperty("footer_settings") ``` ```javascript // Returns the String property const stringProperty = await Braze.getFeatureFlagStringProperty("expanded_user_profile", "color"); // Returns the boolean property const booleanProperty = await Braze.getFeatureFlagBooleanProperty("expanded_user_profile", "expanded"); // Returns the number property const numberProperty = await Braze.getFeatureFlagNumberProperty("expanded_user_profile", "height"); // Returns the Unix UTC millisecond timestamp property as a number const timestampProperty = await Braze.getFeatureFlagTimestampProperty("expanded_user_profile", "account_start"); // Returns the image property as a String of the image URL const imageProperty = await Braze.getFeatureFlagImageProperty("expanded_user_profile", "homepage_icon"); // Returns the JSON object property as an object const jsonObjectProperty = await Braze.getFeatureFlagJSONProperty("expanded_user_profile", "footer_settings"); ``` ```csharp // Returns the Feature Flag instance var featureFlag = Appboy.AppboyBinding.GetFeatureFlag("expanded_user_profile"); // Returns the String property var stringProperty = featureFlag.GetStringProperty("color"); // Returns the boolean property var booleanProperty = featureFlag.GetBooleanProperty("expanded"); // Returns the number property as an integer var integerProperty = featureFlag.GetIntegerProperty("height"); // Returns the number property as a double var doubleProperty = featureFlag.GetDoubleProperty("height"); // Returns the Unix UTC millisecond timestamp property as a long var timestampProperty = featureFlag.GetTimestampProperty("account_start"); // Returns the image property as a String of the image URL var imageProperty = featureFlag.GetImageProperty("homepage_icon"); // Returns the JSON object property as a JSONObject var jsonObjectProperty = featureFlag.GetJSONProperty("footer_settings"); ``` ```javascript // Returns the String property const stringProperty = await BrazePlugin.getFeatureFlagStringProperty("expanded_user_profile", "color"); // Returns the boolean property const booleanProperty = await BrazePlugin.getFeatureFlagBooleanProperty("expanded_user_profile", "expanded"); // Returns the number property const numberProperty = await BrazePlugin.getFeatureFlagNumberProperty("expanded_user_profile", "height"); // Returns the Unix UTC millisecond timestamp property as a number const timestampProperty = await BrazePlugin.getFeatureFlagTimestampProperty("expanded_user_profile", "account_start"); // Returns the image property as a String of the image URL const imageProperty = await BrazePlugin.getFeatureFlagImageProperty("expanded_user_profile", "homepage_icon"); // Returns the JSON object property as an object const jsonObjectProperty = await BrazePlugin.getFeatureFlagJSONProperty("expanded_user_profile", "footer_settings"); ``` ```dart // Returns the Feature Flag instance BrazeFeatureFlag featureFlag = await braze.getFeatureFlagByID("expanded_user_profile"); // Returns the String property var stringProperty = featureFlag.getStringProperty("color"); // Returns the boolean property var booleanProperty = featureFlag.getBooleanProperty("expanded"); // Returns the number property var numberProperty = featureFlag.getNumberProperty("height"); // Returns the Unix UTC millisecond timestamp property as an integer var timestampProperty = featureFlag.getTimestampProperty("account_start"); // Returns the image property as a String of the image URL var imageProperty = featureFlag.getImageProperty("homepage_icon"); // Returns the JSON object property as a Map collection var jsonObjectProperty = featureFlag.getJSONProperty("footer_settings"); ``` ```brightscript ' Returns the String property color = featureFlag.getStringProperty("color") ' Returns the boolean property expanded = featureFlag.getBooleanProperty("expanded") ' Returns the number property height = featureFlag.getNumberProperty("height") ' Returns the Unix UTC millisecond timestamp property account_start = featureFlag.getTimestampProperty("account_start") ' Returns the image property as a String of the image URL homepage_icon = featureFlag.getImageProperty("homepage_icon") ' Returns the JSON object property footer_settings = featureFlag.getJSONProperty("footer_settings") ``` ### Getting a list of all feature flags {#get-list-of-flags} ```javascript const features = getAllFeatureFlags(); for(const feature of features) { console.log(`Feature: ${feature.id}`, feature.enabled); } ``` ```swift let features = braze.featureFlags.featureFlags for let feature in features { print("Feature: \(feature.id)", feature.enabled) } ``` ```java List features = braze.getAllFeatureFlags(); for (FeatureFlag feature: features) { Log.i(TAG, "Feature: ", feature.getId(), feature.getEnabled()); } ``` ```kotlin val featureFlags = braze.getAllFeatureFlags() featureFlags.forEach { feature -> Log.i(TAG, "Feature: ${feature.id} ${feature.enabled}") } ``` ```javascript const features = await Braze.getAllFeatureFlags(); for(const feature of features) { console.log(`Feature: ${feature.id}`, feature.enabled); } ``` ```csharp List features = Appboy.AppboyBinding.GetAllFeatureFlags(); foreach (FeatureFlag feature in features) { Console.WriteLine("Feature: {0} - enabled: {1}", feature.ID, feature.Enabled); } ``` ```javascript const features = await BrazePlugin.getAllFeatureFlags(); for(const feature of features) { console.log(`Feature: ${feature.id}`, feature.enabled); } ``` ```dart List featureFlags = await braze.getAllFeatureFlags(); featureFlags.forEach((feature) { print("Feature: ${feature.id} ${feature.enabled}"); }); ``` ```brightscript features = m.braze.getAllFeatureFlags() for each feature in features print "Feature: " + feature.id + " enabled: " + feature.enabled.toStr() end for ``` ### Refreshing feature flags {#refreshing} You can refresh the current user's feature flags mid-session to pull the latest values from Braze. **Tip:** Refreshing happens automatically upon session start. Refreshing is only needed prior to important user actions, such as before loading a checkout page, or if you know a feature flag will be referenced. ```javascript braze.refreshFeatureFlags(() => { console.log(`Feature flags have been refreshed.`); }, () => { console.log(`Failed to refresh feature flags.`); }); ``` ```swift braze.featureFlags.requestRefresh { result in switch result { case .success(let features): print("Feature flags have been refreshed:", features) case .failure(let error): print("Failed to refresh feature flags:", error) } } ``` ```java braze.refreshFeatureFlags(); ``` ```kotlin braze.refreshFeatureFlags() ``` ```javascript Braze.refreshFeatureFlags(); ``` ```csharp Appboy.AppboyBinding.RefreshFeatureFlags(); ``` ```javascript BrazePlugin.refreshFeatureFlags(); ``` ```dart braze.refreshFeatureFlags(); ``` ```brightscript m.Braze.refreshFeatureFlags() ``` ### Listening for changes {#updates} You can configure the Braze SDK to listen and update your app when the SDK refreshes any feature flags. This is useful if you want to update your app if a user is no longer eligible for a feature. For example, setting some state in your app based on whether or not a feature is enabled, or one of its property values. ```javascript // Register an event listener const subscriptionId = braze.subscribeToFeatureFlagsUpdates((features) => { console.log(`Features were updated`, features); }); // Unregister this event listener braze.removeSubscription(subscriptionId); ``` ```swift // Create the feature flags subscription // - You must keep a strong reference to the subscription to keep it active let subscription = braze.featureFlags.subscribeToUpdates { features in print("Feature flags were updated:", features) } // Cancel the subscription subscription.cancel() ``` ```java braze.subscribeToFeatureFlagsUpdates(event -> { Log.i(TAG, "Feature flags were updated."); for (FeatureFlag feature: event.getFeatureFlags()) { Log.i(TAG, "Feature: ", feature.getId(), feature.getEnabled()); } }); ``` ```kotlin braze.subscribeToFeatureFlagsUpdates() { event -> Log.i(TAG, "Feature flags were updated.") event.featureFlags.forEach { feature -> Log.i(TAG, "Feature: ${feature.id}") } } ``` ```javascript // Register an event listener Braze.addListener(braze.Events.FEATURE_FLAGS_UPDATED, (featureFlags) => { console.log(`featureFlagUpdates`, JSON.stringify(featureFlags)); }); ``` To listen for changes, set the values for **Game Object Name** and **Callback Method Name** under **Braze Configuration** > **Feature Flags** to the corresponding values in your application. ```javascript // Register an event listener BrazePlugin.subscribeToFeatureFlagUpdates((featureFlags) => { console.log(`featureFlagUpdates`, JSON.stringify(featureFlags)); }); ``` In the Dart code in your app, use the following sample code: ```dart // Create stream subscription StreamSubscription featureFlagsStreamSubscription; featureFlagsStreamSubscription = braze.subscribeToFeatureFlags((featureFlags) { print("Feature flags were updated"); }); // Cancel stream subscription featureFlagsStreamSubscription.cancel(); ``` Feature flag data is automatically forwarded from both the Android and iOS native layers. No additional setup is required. If you're using Flutter SDK 17.1.0 or earlier, feature flag data forwarding from the iOS native layer requires manual setup. Your application likely contains a `featureFlags.subscribeToUpdates` callback that calls `BrazePlugin.processFeatureFlags(featureFlags)`. To migrate to Flutter SDK 18.0.0, remove the `BrazePlugin.processFeatureFlags(_:)` call—data forwarding is now handled automatically. For an example, see [AppDelegate.swift](https://github.com/braze-inc/braze-flutter-sdk/blob/master/example/ios/Runner/AppDelegate.swift) in the Braze Flutter SDK sample application. ```brightscript ' Define a function called `onFeatureFlagChanges` to be called when feature flags are refreshed m.BrazeTask.ObserveField("BrazeFeatureFlags", "onFeatureFlagChanges") ``` ```typescript import { useEffect, useState } from "react"; import { FeatureFlag, getFeatureFlag, removeSubscription, subscribeToFeatureFlagsUpdates, } from "@braze/web-sdk"; export const useFeatureFlag = (id: string): FeatureFlag => { const [featureFlag, setFeatureFlag] = useState( getFeatureFlag(id) ); useEffect(() => { const listener = subscribeToFeatureFlagsUpdates(() => { setFeatureFlag(getFeatureFlag(id)); }); return () => { removeSubscription(listener); }; }, [id]); return featureFlag; }; ``` ## Checking user eligibility To check which feature flags a user is eligible for in Braze, go to **Audience** > **Search Users**, then search for and select a user. In the **Feature Flags Eligibility** tab, you can filter the list of eligible feature flags by platform, application, or device. You can also preview the payload that will be returned to the user by selecting next to a feature flag. ![An image showing the table of feature flags a user is eligible for.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/eligibility.png?faa287e849be2508f0622972e0fb2ed9){: style="max-width:85%;"} ## Viewing the changelog To view a feature flag's changelog, open a feature flag and select **Changelog**. ![A feature flag's "Edit" page, with the "Changelog" button highlighted.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/changelog/open_changelog.png?45a939d4bb3aa60da211695f6b60a4f2){: style="max-width:60%;"} Here, you can review when a change happened, who made the change, which category it belongs to, and more. ![The changelog of the selected feature flag.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/changelog/changelog.png?eced90e7169fdea5c5a40287f59afb38){: style="max-width:90%;"} ## Segmenting with feature flags {#segmentation} Braze automatically keeps track of which users are currently enabled for a feature flag. You can create a segment or target messaging using the [**Feature Flag** filter](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/segments/segmentation_filters/#feature-flags). For more information about filtering on segments, see [Creating a segment](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/segments/creating_a_segment/). ![The "Filters" section with "Feature Flag" typed into the filter search bar.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature-flags-filter-name.png?ad7d0b8534a8f300591cbb11fd2d9f10){: style="max-width:75%;"} **Note:** To prevent recursive segments, it is not possible to create a segment that references other feature flags. ## Best practices ### Don't combine rollouts with Canvases or experiments To avoid users being enabled and disabled by different entry points, you should either set the rollouts slider to a value greater than zero OR enable the feature flag in a Canvas or experiment. As a best practice, if you plan to use a feature flag in a Canvas or experiment, keep the rollout percentage at zero. ### Naming conventions To keep your code clear and consistent, consider using the following format when naming your feature flag ID: ```plaintext BEHAVIOR_PRODUCT_FEATURE ``` Replace the following: | Placeholder | Description | |-------------|---------------------------------------------------------------------------------------------------------------------------| | `BEHAVIOR` | The behavior of the feature. In your code, be sure the behavior is disabled by default and avoid using phrases like `disabled` in the feature flag name. | | `PRODUCT` | The product the feature belongs to. | | `FEATURE` | The name of the feature. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Naming conventions" } Here's an example feature flag where `show` is the behavior, `animation_profile` is the product, and `driver` is the feature: ```plaintext show_animation_profile_driver ``` ### Planning ahead Always play it safe. When considering new features that may require an off switch, it's better to release new code with a feature flag and not need it than it is to realize a new app update is required. ### Be descriptive Add a description to your feature flag. While this is an optional field in Braze, it can help answer questions others may have when browsing available feature flags. - Contact details for who is responsible for the enablement and behavior of this flag - When this flag should be disable - Links to documentation or notes about the new feature this flag controls - Any dependencies or notes on how to use the feature ### Clean up old feature flags We're all guilty of leaving features on at 100% rollout for longer than necessary. To help keep your code (and Braze dashboard) clean, remove permanent feature flags from your code base after all users have upgraded and you no longer need the option to disable the feature. This helps reduce the complexity of your development environment, but also keeps your list of feature flags tidy. # フィーチャー・フラッグの実験 Source: /docs/ja/developer_guide/feature_flags/experiments/index.md # Feature flag experiments > Feature flag experiments let you A/B test changes to your applications to optimize conversion rates. Marketers can use feature flags to determine whether a new feature positively or negatively impacts conversion rates, or which set of feature flag properties is most optimal. ## Prerequisites Before you can track user data in the experiment, your app needs to record when a user interacts with a feature flag. This is called a feature flag impression. Make sure to log a feature flag impression whenever a user sees or could have seen the feature you're testing, even if they're in the control group. To learn more about logging feature flag impressions, see [Creating feature flags](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/feature_flags/create/#impressions). ```javascript const featureFlag = braze.getFeatureFlag("my-new-feature"); braze.logFeatureFlagImpression("my-new-feature"); if (featureFlag?.enabled) { return } else { return } ``` ```java FeatureFlag featureFlag = braze.getFeatureFlag("my-new-feature"); braze.logFeatureFlagImpression("my-new-feature"); if (featureFlag != null && featureFlag.getEnabled()) { return new NewFeature(); } else { return new ExistingFeature(); } ``` ```kotlin val featureFlag = braze.getFeatureFlag("my-new-feature") braze.logFeatureFlagImpression("my-new-feature") if (featureFlag?.enabled == true) { return NewFeature() } else { return ExistingFeature() } ``` ## Creating a feature flag experiment ### Step 1: Create an experiment 1. Go to **Messaging** > **Campaigns**, then select **+ Create Campaign**. 2. Select **Feature Flag Experiment**. 3. Give your campaign a clear and meaningful name. ### Step 2: Add experiment variants Next, create variations. For each variant, choose the feature flag you want to turn on or off, then review its assigned properties. To test the impact of your feature, use variants to split traffic into two or more groups. Name one group "My control group" and turn its feature flags off. ### Step 3: Overwrite properties (optional) You can choose to overwrite the default properties you initially set up for users who receive a specific campaign variant. To edit, add, or remove additional default properties, edit the feature flag itself from **Messaging** > **Feature Flags**. When a variant is disabled, the SDK will return an empty properties object for the given feature flag. ![The 'Experiment Variants' section with the 'link' variable key overwritten with '/sales'.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/feature_flag_experiment_override.png?6831378a3d27f8755821b4d118771eff){: style="max-width:80%"} ### Step 4: Choose users to target Use one of your segments or filters to choose your [target users](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/messaging_fundamentals/targeting_users/). For example, you can use the **Received Feature Flag Variant** filter to retarget users who have already received an A/B test. ![The 'Target' page in a feature flag experiment with 'Received Feature Flag Variant' highlighted in the filter group search bar.](https://www.braze.com/docs/ja/ja/assets/img/feature_flags/variant-filter-dropdown.png?f937119488b7aa7ef186d1e82b125a96){: style="max-width:70%"} **Note:** Segment membership is calculated when feature flags are refreshed for a given user. Changes are made available after your app refreshes feature flags, or when a new session is started. ### Step 5: Distribute variants Choose the percentage distribution for your experiment. As a best practice, you should not change the distribution after your experiment has been launched. ### Step 6: Assign conversions Braze lets you to track how often users perform specific actions, [conversion events](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/messaging_fundamentals/conversion_events/), after receiving a campaign. Specify up to a 30-day window during which a conversion will be counted if the user takes the specified action. ### Step 7: Review and launch After you’ve finished building the last of your experiment, review its details, then select **Launch Experiment**. ## Reviewing the results After your feature flag experiment is finished, you can review impression data for your experiment. Go to **Messaging** > **Campaigns** and select the campaign with your feature flag experiment. ### Campaign analytics **Campaign Analytics** offers a high-level overview of your experiment's performance, such as: - The total number of impressions - The number of unique impressions - The primary conversion rate - The total revenue generated by the message - The estimated audience You can also view the experiment's settings for delivery, audience, and conversion. ### Feature flag experiment performance **Feature Flags Experiments Performance** shows how well your message performed across various dimensions. The specific metrics you see will vary depending on your chosen messaging channel, and whether you're running a multivariate test. To see the feature flag values associated with each variant, select **Preview**. # よくある質問 Source: /docs/ja/developer_guide/feature_flags/faq/index.md # Frequently asked questions > This article provides answers to some frequently asked questions about feature flags. ## Functionality and support ### What platforms are Braze feature flags supported on? {#platforms} Braze supports feature flags on iOS, Android, and Web platforms with the following SDK version requirements: Do you need support on other platforms? Email our team: [feature-flags-feedback@braze.com](mailto:feature-flags-feedback@braze.com). ### What is the level of effort involved when implementing a feature flag? {#level-of-effort} A feature flag can be created and integrated in a few minutes. Most of the effort involved will be related to your engineering team building the new feature you plan to roll out. But when it comes to adding a feature flag, it's as simple as an `IF`/`ELSE` statement in your app or website's code: ```javascript import { getFeatureFlag } from "@braze/web-sdk"; if (getFeatureFlag("new_shopping_cart").enabled) { // Show the new homepage your team has built } else { // Show the old homepage } ``` ```java if (braze.getFeatureFlag("new_shopping_cart").getEnabled()) { // Show the new homepage your team has built } else { // Show the old homepage } ``` ```kotlin if (braze.getFeatureFlag("new_shopping_cart")?.enabled == true) { // Show the new homepage your team has built } else { // Show the old homepage } ``` ### How can feature flags benefit Marketing teams? {#marketing-teams} Marketing teams can use feature flags to coordinate product announcements (such as product launch emails) when a feature is only enabled for a small percentage of users. For example, with Braze feature flags, you can roll out a new Customer Loyalty program to 10% of users in your app, and send an email, push, or other messaging to that same 10% of enabled users using the Canvas Feature Flag step. ### How can feature flags benefit Product teams? {#product-teams} Product teams can use feature flags to perform gradual rollouts or soft launches of new features in order to monitor key performance indicators and customer feedback before making it available to all users. Product teams can use [feature flag properties](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/feature_flags/create/#properties) to remotely populate content in an app, such as deep links, text, imagery, or other dynamic content. Using the Canvas Feature Flag step, Product teams can also run an A/B split test to measure how a new feature impacts conversion rates compared to users with the feature disabled. ### How can feature flags benefit engineering teams? {#engineering-teams} Engineering teams can use feature flags to reduce the risk inherent in launching new features and avoid rushing to deploy code fixes in the middle of the night. By releasing new code hidden behind a feature flag, your team can turn the feature on or off remotely from the Braze dashboard, bypassing the delay of pushing out new code or waiting for an app store update approval. ## Feature rollouts and targeting ### Can a feature flag be rolled out to only a select group of users? {#target-users} Yes, create a segment in Braze that targets specific users—by email address, `user_id`, or any other attribute on your user profiles. Then, deploy the feature flag for 100% of that segment. ### How does adjusting the rollout percentage affect users who were previously bucketed into the enabled group? {#random-buckets} Feature flag rollouts remain consistent for users across devices and sessions. - When a feature flag is rolled out to 10% of random users, that 10% will remain enabled and persist for the lifetime of that feature flag. - If you increase the rollout from 10% to 20%, the same 10% will remain enabled, plus a new, additional 10% of users will be added to the enabled group. - If you lower the rollout from 20% to 10%, only the original 10% of users will remain enabled. This strategy helps ensure that users are shown a consistent experience in your app and don't flip-flop back and forth across sessions. Of course, disabling a feature down to 0% will remove all users from the feature flag, which is helpful if you discover a bug or need to disable the feature altogether. ## Technical topics ### Can feature flags be used to control when the Braze SDK is initialized? {#initialization} No, the SDK must be initialized to download and synchronize feature flags for the current user. This means you can't use feature flags to limit which users are created or tracked in Braze. ### How frequently does the SDK refresh feature flags? {#refresh-frequency} Feature flags are refreshed at session start and when changing active users. Feature flags can also be manually refreshed using the SDK's [refresh method](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/feature_flags/create/#refreshing). Feature flag refreshes are rate limited to once every five minutes (subject to change). Keep in mind that good data practices recommend not refreshing feature flags too quickly (with potential rate limiting if done so), so it's best only to refresh before a user interacts with new features or periodically in the app if necessary. ### Are feature flags available while a user is offline? {#offline} Yes, after feature flags are refreshed, they are stored locally on the user's device and can be accessed while offline. ### What happens if feature flags are refreshed mid-session? {#listen-for-updates} Feature flags may be refreshed mid-session. There are scenarios where you may want to update your app if certain variables or your configuration should change. There are other scenarios where you may not want to update your app, to avoid a shocking change in how your UI is rendered. To control this, [listen for updates](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/feature_flags/create/#updates) to feature flags and determine whether to re-render your app based on which feature flags have changed. ### Why aren't users in my Global Control Group receiving feature flags experiments? You can't enable feature flags for users in your [Global Control Group](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/testing/global_control_group/). This means users in your Global Control Group also can't be part of Feature Flag experiments. ## Additional questions? Have questions or feedback? Email our team: [feature-flags-feedback@braze.com](mailto:feature-flags-feedback@braze.com). # Braze SDKの分析について Source: /docs/ja/developer_guide/analytics/index.md # 分析 {#analytics} > Braze SDKの分析について学習し、Brazeが収集するデータ、カスタムイベントとカスタム属性の違い、分析を管理するためのベストプラクティスについて理解を深めましょう。 **Tip:** Brazeを実装する際には、マーケティング目標についてチームとよく話し合い、Brazeでトラッキングしたいデータとトラッキング方法を最適に決定できるようにしてください。例については、このガイドの最後にある[タクシー/ライドシェアアプリ](#example-case)のケーススタディを参照してください。 ## 自動的に収集されるデータ {#automatically-collected-data} 最初に使用したアプリ、最後に使用したアプリ、合計セッション数、デバイスOSなど、特定のユーザーデータはSDKで自動的に収集されます。統合ガイドに従ってSDKを実装すると、この[デフォルトデータ収集](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/sdk_data_collection)を利用できるようになります。このリストを確認することで、ユーザーに関する同じ情報を複数回保存しなくて済みます。セッションの開始と終了を除き、その他の自動的にトラッキングされるデータは、データポイント使用量にはカウントされません。 特定のデータ項目のデフォルト収集をブロックするプロセスを許可リストに登録するには、[SDKプライマー](https://www.braze.com/docs/ja/ja/developer_guide/getting_started/sdk_overview)に関する記事を参照してください。 ## カスタムイベント {#custom-events} カスタムイベントは、ユーザーによって行われるアクションです。これらは、アプリケーションとの高価値なユーザーインタラクションをトラッキングするのに最適です。カスタムイベントをログに記録すると、構成可能な遅延を設定して任意の数のフォローアップキャンペーンをトリガーできます。また、そのイベントの最新性と頻度に基づいて次のセグメンテーションフィルターが有効になります。 | セグメンテーションオプション | ドロップダウンフィルター | 入力オプション | | ---------------------| --------------- | ------------- | | カスタムイベントが**X回以上**発生したかどうかをチェックする | **MORE THAN** | **NUMBER** | | カスタムイベントの発生**回数がX回未満か**どうかをチェックする | **LESS THAN** | **NUMBER** | | カスタムイベントが**正確にX回**発生したかどうかをチェックする | **EXACTLY** | **NUMBER** | | カスタムイベントが**日付Xより後**に発生したかどうかをチェックする | **AFTER** | **TIME** | | カスタムイベントが**日付Xより前**に発生したかどうかをチェックする | **BEFORE** | **TIME** | | カスタムイベントが最後に発生したのが**X日以上前か**どうかをチェックする | **MORE THAN** | **NUMBER OF DAYS AGO**(正の数) | | カスタムイベントが最後に発生したのが**X日未満**かどうかをチェックする | **LESS THAN** | **NUMBER OF DAYS AGO**(正の数) | | カスタムイベントが**X(最大値 = 50)回以上**発生したかどうかを確認する | **MORE THAN** | 過去**Y日間 (Y = 1,3,7,14,21,30)** | | カスタムイベントが**X(最大 = 50)回未満**発生したかどうかを確認する | **LESS THAN** | 過去**Y日間 (Y = 1,3,7,14,21,30)** | | カスタムイベントが**正確にX(最大 = 50)回**発生したかどうかを確認する | **EXACTLY** | 過去**Y日間 (Y = 1,3,7,14,21,30)** | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Custom events" } Brazeはセグメンテーション用として、これらのイベントが発生した回数と、各ユーザーの最終実行時刻を記録します。**カスタムイベント**の分析ページで、各カスタムイベントが発生する頻度を集約して表示できます。また、より詳細な分析を行うために、経時的にセグメントごとに表示することもできます。これは、キャンペーンがカスタムイベントのアクティビティにどのように影響したかを確認するのに特に役立ちます。Brazeが時系列にオーバーレイする灰色の線を見て、最後にキャンペーンが送信された時を確認できます。 ![クレジットカードを追加して30日間にわたって検索を行ったユーザーに関する統計を示すカスタムイベント分析グラフ。](https://www.braze.com/docs/ja/ja/assets/img_archive/custom_event_analytics_example.png?345ada8684baf98a23ceb1a80341f24b "custom_event_analytics_example.png") **Note:** [カスタム属性の増分](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)を使用すると、カスタムイベントと同様にユーザーアクションのカウンターを保持できます。ただし、時系列でカスタム属性データを表示することはできません。時系列で分析する必要がないユーザーアクションは、この方法で記録する必要があります。 ### カスタムイベントの保存 {#custom-event-storage} すべてのユーザープロファイルデータ(カスタムイベント、カスタム属性、カスタムデータ)は、それらのプロファイルがアクティブである限り保存されます。 ### カスタムイベントプロパティ {#custom-event-properties} カスタムイベントプロパティを使用すると、Brazeはカスタムイベントおよび購入にプロパティを設定できます。これらのプロパティを使用して、トリガー条件の絞り込み、メッセージングのパーソナライゼーションの強化、未加工データのエクスポートによるより高度な分析の生成を行えます。プロパティ値は文字列、数値、ブール値、または時間オブジェクトにすることができます。ただし、プロパティ値は配列オブジェクトにすることはできません。 例えば、あるeコマースアプリケーションが、ユーザーがカートを放棄したときにメッセージを送りたい場合、ユーザーのカートの`cart_value`のカスタムイベントプロパティを追加することで、ターゲットオーディエンスをさらに改善し、キャンペーンのパーソナライゼーションを高めることができます。 ![カスタムイベントの例では、カートを放棄し、カートの価値が100以上200未満のユーザーにキャンペーンを送信します。](https://www.braze.com/docs/ja/ja/assets/img_archive/customEventProperties.png?03200b17e56f8f8ad0c6ab439de76832 "customEventProperties.png") カスタムイベントプロパティは、メッセージングテンプレート内でパーソナライゼーションのためにも使用できます。トリガーイベントを持つ[アクションベースの配信](https://www.braze.com/docs/ja/ja/user_guide/messaging/campaigns/schedule_your_campaign/triggered_delivery)を使用するキャンペーンは、メッセージングパーソナライゼーションのために、そのイベントのカスタムイベントプロパティを使用できます。ゲームアプリケーションがレベルをクリアしたユーザーにメッセージを送信したい場合、そのレベルをクリアするのにかかった時間のプロパティを使用してメッセージをさらにパーソナライズできます。この例では、メッセージは[条件付きロジック](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize/liquid/conditional_logic)を使用して3つの異なるセグメントに対してパーソナライズされています。カスタムイベントプロパティ``time_spent``は、`` } ``を呼び出すことでメッセージに含めることができます。 ```liquid Congratulations on beating that level so fast! Check out our online portal where you can play against top players from around the world! Don't forget to visit the town store between levels to upgrade your tools. Talk to villagers for essential tips on how to beat levels! ``` カスタムイベントプロパティは、メッセージングをパーソナライズしたり、アクションベースの詳細な配信キャンペーンを構築したりするのに役立ちます。イベントプロパティの直近性と頻度に基づいてセグメントを作成したい場合は、カスタマーサクセスマネージャーまたはサポートチームにお問い合わせください。 ## カスタム属性 {#custom-attributes} カスタム属性は、標準属性項目を使用した場合よりも高い特異性でユーザーをターゲットにすることができる非常に柔軟性の高いツールです。カスタム属性は、ユーザーに関するブランド固有の情報を保存するのに最適です。カスタム属性の時系列情報は保存されないため、前のカスタムイベントの例のようには時系列情報に基づくグラフを取得できないことに注意してください。 ### カスタム属性の保存 {#custom-attribute-storage} すべてのユーザープロファイルデータ(カスタムイベント、カスタム属性、カスタムデータ)は、それらのプロファイルがアクティブである限り保存されます。 ### カスタム属性のデータタイプ {#custom-attribute-data-types} カスタム属性として格納できるデータタイプを以下に示します。 #### 文字列(英数字) {#strings-alphanumeric-characters} 文字列属性は、お気に入りのブランド、電話番号、アプリケーション内での最後の検索文字列など、ユーザー入力の保存に役立ちます。文字列属性はカスタムデータの[長さ制約](#length-constraints)(479バイト。約479文字の半角文字、または日本語などの多バイト文字では約160文字)に従います。 次の表は、文字列属性に利用可能なセグメンテーションオプションについて説明しています。 | セグメンテーションオプション | ドロップダウンフィルター | 入力オプション | | ---------------------| --------------- | ------------- | | 文字列属性が入力された文字列と**完全に一致する**かどうかを確認します | **EQUALS** | **STRING** | | 文字列属性が入力された文字列に**部分的に一致するかどうか**、**または**正規表現を確認します | **MATCHES REGEX** | **STRING** **OR** **REGULAR EXPRESSION** | | 文字列属性が、入力された文字列**または**正規表現と**部分的に一致しない**かどうかを確認します | **DOES NOT MATCH REGEX** | **STRING** **OR** **REGULAR EXPRESSION** | | 文字列属性が入力された文字列と**一致しない**かどうかを確認します | **DOES NOT EQUAL** | **STRING** | | ユーザーのプロファイルに文字列属性**が存在する**かどうかを確認します | **IS BLANK** | **N/A** | | ユーザーのプロファイルに文字列属性**が存在しない**かどうかを確認します | **IS NOT BLANK** | **N/A** | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Strings (alphanumeric characters)" } **Important:** セグメント化に**DOES NOT MATCH REGEX**フィルターを使用する場合、そのユーザープロファイルに値が割り当てられたカスタム属性が既に存在している必要があります。Brazeは、ユーザーを適切にターゲットするためにカスタム属性が空白かどうかを確認するために「OR」ロジックを使用することを推奨しています。 **Tip:** 正規表現フィルターの使用方法の詳細については、[Perl compatible regular expressions (PCRE)](http://www.regextester.com/pregsyntax.html)のドキュメントを参照してください。
正規表現に関するその他のリソース: - [Brazeでの正規表現](https://www.braze.com/docs/ja/ja/user_guide/audience/segments/regex) - [正規表現のデバッガーおよびテスター](https://regex101.com/) - [正規表現のチュートリアル](https://medium.com/factory-mind/regex-tutorial-a-simple-cheatsheet-by-examples-649dc1c3f285) #### 配列 {#arrays} 配列属性は、ユーザーに関する情報の関連リストの保存に適しています。例えば、ユーザーが視聴した最後のコンテンツ100個を配列内に保存すると、特定の関心に基づくセグメンテーションができます。 カスタム属性の配列は一次元のセットです。多次元配列はサポートされていません。**カスタム属性配列に要素を追加すると、その要素が配列の最後に追加されます。ただし、既に存在する場合は、現在の位置から配列の最後に移動されます。**例えば、配列`['hotdog','hotdog','hotdog','pizza']`がインポートされた場合、一意の値のみがサポートされるため、配列属性には`['hotdog', 'pizza']`として表示されます。 配列が最大数の要素を含んでいる場合、最初の要素は破棄され、新しい要素が最後に追加されます。次に、Web SDKでの配列の動作を示すいくつかの例コードを示します: ```js var abUser = appboy.getUser(); // initialize array for this user, assuming max length of favorite_foods is set to 4. abUser.setCustomUserAttribute('favorite_foods', ['pizza', 'wings', 'pasta']); // => ['pizza', 'wings', 'pasta'] abUser.addToCustomAttributeArray('favorite_foods', 'fries'); // => ['pizza', 'wings', 'pasta', 'fries'] abUser.addToCustomAttributeArray('favorite_foods', 'pizza'); // => ['wings', 'pasta', 'fries', 'pizza'] abUser.addToCustomAttributeArray('favorite_foods', 'ice cream'); // => ['pasta', 'fries', 'pizza', 'ice cream'] ``` 配列内の要素のデフォルトおよび最大数は500です。最大数は、Brazeダッシュボードの**データ設定** > **カスタム属性**で更新できます。要素数が最大値を超える配列は、最大要素数を含むように切り詰められます。 次の表は、配列属性の利用可能なセグメンテーションオプションについて説明しています。 | セグメンテーションオプション | ドロップダウンフィルター | 入力オプション | | ---------------------| --------------- | ------------- | | 配列属性に、入力された値と**完全一致する値が含まれている**かを確認します | **INCLUDES VALUE** | **STRING** | | 配列属性に、入力された値と**完全一致する値が含まれていない**かを確認します | **DOESN'T INCLUDE VALUE** | **STRING** | | 配列属性に、入力された値、**または**正規表現と**部分一致する値が含まれている**かを確認します | **MATCHES REGEX** | **STRING** **OR** **REGULAR EXPRESSION** | | 配列属性**に値があるかどうか**を確認します | **HAS A VALUE** | **N/A** | | 配列属性**が空であるかどうか**を確認します | **IS EMPTY** | **N/A** | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Arrays" } **Note:** [Perl互換正規表現(PCRE)](http://www.regextester.com/pregsyntax.html)を使用します。 #### 日付 {#dates} 時刻属性は、特定のアクションが最後に実行された時刻の保存に役立ちます。そのため、コンテンツ固有の再エンゲージメントメッセージをユーザーに提供できます。 **Note:** カスタムイベントまたは購入イベントが最後に発生した日付は自動的に記録されるため、カスタム時刻属性を使用して重複記録しないでください。 相対日付(1日超前、2日未満など)を使用した日付フィルターでは、1日を24時間として扱います。これらのフィルターを使用して実行するキャンペーンには、24時間単位ですべてのユーザーが含まれます。例えば、最後に使用したアプリが1日以上前の場合、キャンペーンが実行される正確な時刻から「最後にアプリを使用したのが24時間以上前」のすべてのユーザーをキャプチャします。同じことが、より長い日付範囲で設定されたキャンペーンにも当てはまります。つまり、アクティベーションから5日後は、過去120時間を意味します。 次の表は、時間属性に利用可能なセグメンテーションオプションについて説明しています。 | セグメンテーションオプション | ドロップダウンフィルター | 入力オプション | | ---------------------| --------------- | ------------- | | 時間属性が、**選択した日付****よりも前**であるかを確認します | **BEFORE** | **CALENDAR DATE SELECTOR** | | 時間属性が、**選択した日付****よりも後**であるかを確認します | **AFTER** | **CALENDAR DATE SELECTOR** | | 時間属性が**X日以上前**かどうかを確認します | **MORE THAN** | **NUMBER OF DAYS AGO** | | 時間属性が**X日未満前**かどうかを確認します | **LESS THAN** | **NUMBER OF DAYS AGO** | | 時間属性が**X日以上先の未来**であるかどうかを確認します | **IN MORE THAN** | **NUMBER OF DAYS IN FUTURE** | | 時間属性が**X日未満先の未来**であるかどうかを確認します | **IN LESS THAN** | **NUMBER OF DAYS IN FUTURE** | | ユーザーのプロファイルに時間属性**が存在する**かどうかを確認します | **BLANK** | **N/A** | | ユーザーのプロファイルに時間属性**が存在しない**かどうかを確認します | **IS NOT BLANK** | **N/A** | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Dates" } #### 数値 {#integers} 数値属性にはさまざまなユースケースがあります。数値のカスタム属性を増分すると、特定のアクションやイベントが発生した回数を保存する場合に便利です。標準的な数値には、靴のサイズ、ウエストのサイズ、ユーザーが特定の製品の特徴やカテゴリーを見た回数の記録など、あらゆる種類の用途があります。 **Note:** 支出した金額はこの方法で記録すべきではありません。むしろ、[購入メソッド](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/analytics_overview#purchase-events--revenue-tracking)で記録してください。 次の表は、数値属性に利用可能なセグメンテーションオプションについて説明しています。 | セグメンテーションオプション | ドロップダウンフィルター | 入力オプション | | ---------------------| --------------- | ------------- | | 数値属性が**数値**より**大きい**かどうかを確認します | **MORE THAN** | **NUMBER** | | 数値属性が**数値**より**小さい**かどうかを確認します | **LESS THAN** | **NUMBER** | | 数値属性が**正確に****数値**であるかどうかを確認します | **EXACTLY** | **NUMBER** | | 数値属性が**数値**と**等しくない**かどうかを確認します | **DOES NOT EQUAL** | **NUMBER** | | ユーザーのプロファイルに数値属性**が存在する**かどうかを確認します | **EXISTS** | **N/A** | | ユーザーのプロファイルに数値属性**が存在しない**かどうかを確認します | **DOES NOT EXIST** | **N/A** | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Numbers #integers" } #### ブール値(true/false) {#booleans-truefalse} ブール属性は、サブスクリプションステータスやユーザーに関するその他の単純なバイナリデータを保存するのに役立ちます。提供される入力オプションを使用すると、変数がブール値に明示的に設定されているユーザーと、その属性がまだ記録されていないユーザーを見つけることができます。 次の表は、ブール属性の利用可能なセグメンテーションオプションについて説明しています。 | セグメンテーションオプション | ドロップダウンフィルター | 入力オプション | | ---------------------| --------------- | ------------- | | ブール値**である**かを確認します | **IS** | **TRUE**、**FALSE**、**TRUE OR NOT SET**、または**FALSE OR NOT SET** | | ユーザーのプロファイルにブール値**が存在する**かどうかを確認します | **EXISTS** | **N/A** | | ユーザーのプロファイルにブール値**が存在しない**かどうかを確認します | **DOES NOT EXIST** | **N/A** | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Booleans (true/false)" } ## 購入イベントと収益トラッキング {#purchase-events-revenue-tracking} アプリ内購入の記録に購入メソッドを使用すると、個々のユーザープロファイルに生涯価値(LTV)が設定されます。このデータは、時系列グラフで収益ページ内で表示できます。 次の表は、購入イベントのために利用可能なセグメンテーションオプションを説明しています。 | セグメンテーションオプション | ドロップダウンフィルター | 入力オプション | | ---------------------| --------------- | ------------- | | 合計支出額が**数値**より**大きい**かどうかを確認します | **GREATER THAN** | **NUMBER** | | 合計支出額が**数値****未満**であるかを確認します | **LESS THAN** | **NUMBER** | | 合計支出額が**正確に****数値**であるか確認します | **EXACTLY** | **NUMBER** | | 購入の最終発生時期が**日付Xより後**かを確認します | **AFTER** | **TIME** | | 購入の最終発生時期が**日付Xより前**かを確認します | **BEFORE** | **TIME** | | 前回の購入が**X日以上前**かどうか確認します | **MORE THAN** | **TIME** | | 購入が最後に発生したのが**X日未満**かどうか確認します | **LESS THAN** | **TIME** | | 購入が**X(最大=50)回以上**発生したかどうかを確認します | **MORE THAN** | 過去**Y日間 (Y = 1,3,7,14,21,30)** | | 購入が**X(最大50)回未満**で発生したかどうかを確認します | **LESS THAN** | 過去**Y日間 (Y = 1,3,7,14,21,30)** | | 購入が**正確にX(最大50)回**発生したかどうかを確認します | **EXACTLY** | 過去**Y日間 (Y = 1,3,7,14,21,30)** | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Purchase events / revenue tracking" } **Note:** 特定の購入の発生回数でセグメンテーションを行う場合は、その購入を個別に[増分カスタム属性](#integers)として記録する必要もあります。 ## タクシー/ライドシェアアプリのユースケース {#example-case} この例では、どのユーザーデータを収集するかを決定したいライドシェアアプリを考えてみましょう。以下の質問とブレインストーミングのプロセスは、マーケティングチームと開発チームが参考にできる優れたモデルです。この演習を終了すると、両方のチームは、目標を達成するためにどのカスタムイベントと属性を収集するとよいかが明確にわかるでしょう。 **ケースの質問 No.1: 目標は何ですか?** 目標は明確で、ユーザーにアプリ経由でタクシーを呼んでもらうことです。 **ケースの質問 No.2: アプリをインストールしてからその目標に至るまで、どのような中間ステップがありますか?** 1. ユーザーは登録プロセスを開始して、個人情報を入力する必要があります。 2. ユーザーは登録プロセスを完了し、SMS経由で受け取ったコードをアプリに入力して確認する必要があります。 3. ユーザーはタクシーを呼ぶ必要があります。 4. タクシーを呼ぶには、ユーザーが検索したときにタクシーが利用できなければなりません。 これらのアクションには、以下のカスタムイベントとしてタグを付けることができます。 - 登録開始 - 登録完了 - タクシーの呼び出し成功 - タクシーの呼び出し失敗 イベントを実装した後、次のキャンペーンを実行できます。 1. 登録を開始したが、一定期間内に登録完了イベントをトリガーしなかったユーザーにメッセージを送信する。 2. 登録を完了したユーザーにお祝いのメッセージを送信します。 3. タクシーの呼び出しに失敗し、一定時間内に成功したタクシーの呼び出しがなかったユーザーに謝罪とプロモーションクレジットを送信します。 4. タクシーの呼び出し成功数が多いパワーユーザーに、ロイヤルティへの感謝の気持ちを示すプロモーションを送信します。 そして他にもたくさんあります! **ケースの質問 No.3: メッセージングに役立つ、ユーザーに関する他のどのような情報が必要でしょうか?** - プロモーションクレジットを持っているかどうか? - ユーザーによるドライバーの平均評価は? - ユーザー固有のプロモーションコードがあるか? これらの特性には、以下のカスタム属性のタグを付けることができます。 - プロモーションクレジット残高(10進数型) - ドライバーの平均評価(数値型) - 固有のプロモーションコード(文字列型) これらの属性を追加することで、次のようなキャンペーンをユーザーに送信できるようになります。 1. 7日間ログインしていないがプロモーションクレジットを持っているユーザーに、そのクレジットが存在することと、アプリに戻って使用するよう通知する。 2. 低いドライバー評価を与えたユーザーにメッセージを送り、なぜ乗車を楽しめなかったのかを確認するために直接フィードバックを得る。 3. [メッセージテンプレートとパーソナライゼーション機能](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize)を使用して、固有のプロモーションコード属性をユーザー向けのメッセージングに付け加えます。 ## ベストプラクティス {#best-practices} ### 一般的なベストプラクティス {#general-best-practices} #### イベントプロパティを使用する {#use-event-properties} - ユーザーが行うアクションを説明するカスタムイベントに名前を付けます。 - カスタムイベントプロパティを十分に活用して、イベントに関する重要なデータを表現してください。 - 例えば、50本の異なる映画のそれぞれを視聴するために別々のカスタムイベントをキャプチャするのではなく、映画を視聴することをイベントとしてキャプチャし、イベントプロパティに映画の名前を含める方が効果的です。 ### 開発のベストプラクティス {#development-best-practices} #### すべてのユーザーにユーザーIDを設定する {#set-user-ids-for-every-user} ユーザーIDは、各ユーザーに設定する必要があります。これらは変更されず、ユーザーがアプリを開いたときにアクセスできるようにする必要があります。この識別子を提供することを**強くお勧めします**。これにより、次のことが可能になります: - デバイスやプラットフォームを超えてユーザーをトラッキングし、行動データや人口統計データの質を向上させます。 - [ユーザーデータAPI](https://www.braze.com/docs/ja/ja/api/endpoints/user_data)を使用して、ユーザーに関するデータをインポートします。 - [メッセージングAPI](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)を使用して、一般的なメッセージとトランザクションメッセージの両方で特定のユーザーをターゲットにします。 ユーザーIDは512文字未満でなければならず、プライベートで簡単に取得できないものであるべきです(例えば、単純なメールアドレスやユーザー名ではない)。そのような識別子が利用できない場合、Brazeはユーザーに一意の識別子を割り当てますが、ユーザーIDに対してリストされている機能が欠けることになります。個人として紐づけられた固有の識別子を持たないユーザーに対して、ユーザーIDの設定は避けるべきです。デバイス識別子を渡すことは、Brazeがデフォルトで提供する自動匿名ユーザートラッキングに対して何の利益も提供しません。以下は、適切および不適切なユーザーIDの例です。 適切なユーザーIDの例: - ハッシュ化されたメールアドレスまたは一意のユーザー名 - 一意のデータベース識別子 これらはユーザーIDとして使用しないでください: - デバイスID - ランダムな数値またはセッションID - 一意でないID - メールアドレス - 別のサードパーティベンダーのユーザーID #### カスタムイベントと属性に読みやすい名前を付ける {#give-custom-events-and-attributes-readable-names} マーケターが導入から1〜2年後にBrazeを使い始めるとしましょう。文脈もなしに「usr_no_acct」のような名前がずらりと並んだドロップダウンリストを読むのは、気が重くなるかもしれません。イベントと属性に識別可能で読みやすい名前を付けることで、プラットフォームのすべてのユーザーにとって物事が容易になります。次のベストプラクティスを考慮してください: - カスタムイベントは数字で始めないでください。ドロップダウンリストはアルファベット順に並べられ、数字で始まると、選択したフィルターでセグメンテーションするのが難しくなります。 - 可能な限り難解な略語や専門用語を使用しないようにしてください。 - 例: `usr_ctry`はコード内のユーザーの国を示す変数名としては問題ないかもしれませんが、カスタム属性はBrazeに`user_country`のように送信して、後でダッシュボードを使用するマーケターに明確さを提供する必要があります。 #### 属性が変更されたときにのみログに記録する {#only-log-attributes-when-they-change} Brazeに渡されたすべての属性は、たとえ渡された属性が以前に保存されたものと同じ値を含んでいても、データポイントとしてカウントされます。変更時にのみデータを記録することで、冗長なデータポイントの使用を回避し、不必要なAPI呼び出しを避けることでスムーズな体験をサポートします。 #### プログラムでイベント名を生成するのを避ける {#avoid-programmatically-generating-event-names} 新しいイベント名を常に作成している場合、ユーザーを意味のあるセグメントに分割することは不可能になります。一般的なイベント(「動画を見た」や「記事を読んだ」)をキャプチャするべきであり、「江南スタイルを見た」や「記事を読んだ: ミッドタウンマンハッタンのベスト10ランチスポット」のような非常に具体的なイベントではありません。イベントに関する具体的なデータは、イベント名の一部ではなく、イベントプロパティとして含める必要があります。 ### 技術的な制限と制約 {#technical-limitations-and-constraints} カスタムイベントを実装する際の次の制限と制約に注意してください: #### 長さの制約 {#length-constraints} Brazeはカスタムイベント名、カスタム属性名(キー)、およびカスタムイベントの文字列値に対して、バイト単位の長さ制限(479バイト)を設けています。この制限を超える値は切り詰められます。文字数で表すと、これは約479の半角文字(例: ASCII)に相当します。あるいは日本語などの多バイト文字では約160文字となります(UTF-8で1文字あたり約3バイトと仮定した場合)。理想的には、アプリにおけるネットワークとバッテリーのパフォーマンスを向上させるため、名前と値は可能な限り短く保ってください。可能であれば、50文字以内に制限してください。 #### コンテンツの制約 {#content-constraints} 次のコンテンツは、属性とイベントからプログラムによってトリミングされます。次のものを使用しないように注意してください: - 先頭と末尾の空白 - 改行 - 電話番号内のすべての数字以外の文字 - 例: "(732) 178-1038" は "7321781038" に凝縮されます - 空白以外の文字はスペースに変換する必要があります - $は、カスタムイベントのプレフィックスとして使用しないでください - 無効なUTF-8エンコーディング値 - "My \x80 Field" は "My Field" に凝縮されます #### 予約済みのキー {#reserved-keys} 以下のキーは予約されているため、カスタムイベントプロパティとして使用できません。 - `time` - `product_id` - `quantity` - `event_name` - `price` - `currency` #### 値の定義 {#value-definitions} - 整数値は64ビットです - デフォルトで小数は15桁の小数桁数を持っています ### 一般名フィールドの解析 {#parsing-a-generic-name-field} ユーザーに対して1つの汎用名フィールドしか存在しない場合(例:「JohnDoe」)、このタイトル全体をユーザーの名属性に割り当てることができます。さらに、スペースを使用してユーザーの名と姓の両方を解析しようとすることもできますが、この後者の方法には一部のユーザーの名前を誤って認識するリスクがあります。 # Braze SDKを通じてユーザー IDを設定する Source: /docs/ja/developer_guide/analytics/setting_user_ids/index.md # ユーザー IDを設定する {#set-user-ids} > Braze SDKでユーザー IDを設定する方法を学習します。これは、デバイスやプラットフォームを超えてユーザーを追跡し、[ユーザーデータAPI](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data#user-data)を通じてユーザーデータをインポートし、[メッセージングAPI](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)を通じてターゲットメッセージを送信するための一意の識別子です。ユーザーに固有のIDを割り当てない場合、Brazeは代わりに匿名IDを割り当てますが、割り当てるまでこれらの機能を使用することはできません。 **Note:** リストされていないラッパーSDKの場合は、代わりに関連するネイティブAndroidまたはSwiftメソッドを使用してください。 ## 匿名ユーザーについて {#about-anonymous-users} After you [integrate the Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/), users who launch your app for the first time will be considered "anonymous" until you call the `changeUser` method and assign them an `external_id`. Once assigned, you can't make them anonymous again. However, if they uninstall and reinstall your app, they will become anonymous again until `changeUser` is called. If a previously-identified user starts a session on a new device, all of their anonymous activity will automatically sync to their existing profile after you call `changeUser` on that device using their `external_id`. This includes any attributes, events, or history collected during the session on the new device. ### 匿名ユーザーのトラッキングを防止する {#preventing-anonymous-user-tracking} ユーザーが識別される前にデータを収集しないユースケースの場合、ユーザーがログインして `external_id` が利用可能になるまでBraze SDKの初期化を遅延させることができます。コード内にフラグを設定し、ユーザーがサインインしたときに `true` に切り替え、そのフラグが設定されている場合にのみSDKを初期化します。 **Warning:** 初期化の遅延は、ユーザーがアプリを**初めて**ダウンロードしたとき(`external_id` が設定される前)にのみ行ってください。ユーザーがサインアウトしたり新しいセッションを開始したりするたびにSDKの初期化を妨げると、アプリ内メッセージやコンテンツカードアセットのプリフェッチに干渉し、それらのキャンペーンの配信エラーにつながる可能性があります。 ## ユーザー IDの設定 {#setting-a-user-id} ユーザー IDを設定するには、ユーザーが最初にログインした後に `changeUser()` メソッドを呼び出します。IDは一意であり、[命名のベストプラクティス](#naming-best-practices)に従っている必要があります。 代わりに一意な識別子をハッシュする場合は、ハッシュ関数の入力を正規化してください。たとえば、メールアドレスをハッシュする場合は、先頭または末尾のスペースを削除し、ローカライゼーションを考慮します。 標準のWeb SDK実装では、以下の方法を使用できます。 ```javascript braze.changeUser(YOUR_USER_ID_STRING); ``` 代わりにGoogle Tag Managerを使いたい場合は、**Change User** タグタイプを使って[`changeUser` メソッド](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#changeuser)を呼び出すことができます。ユーザーがログインするとき、あるいは一意の `external_id` 識別子で識別されるときは、必ずこれを使用してください。 現在のユーザーの一意のIDを**External User ID** フィールドに入力してください。通常は、Webサイトから送信されたデータレイヤー変数を使用して入力します。 ![Brazeアクションタグの設定を示すダイアログボックス。設定項目には「tag type」と「external user ID」が含まれます。](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-change-user.png?a4edbf312c5ba1fa6d32ecdd559361b0) ```java Braze.getInstance(context).changeUser(YOUR_USER_ID_STRING); ``` ```kotlin Braze.getInstance(context).changeUser(YOUR_USER_ID_STRING) ``` ```swift AppDelegate.braze?.changeUser(userId: "YOUR_USER_ID") ``` ```objc [AppDelegate.braze changeUser:@"YOUR_USER_ID_STRING"]; ``` ```javascript BrazePlugin.changeUser("YOUR_USER_ID"); ``` ```brightscript m.Braze.setUserId(YOUR_USER_ID_STRING) ``` ```csharp AppboyBinding.ChangeUser("YOUR_USER_ID_STRING"); ``` ```javascript Braze.changeUser("YOUR_USER_ID_STRING"); ``` ### `changeUser()` の仕組み {#how-changeuser-works} `changeUser()` を呼び出すと、以下の動作が適用されます。 - すでに設定されている**同じ**ユーザー IDで `changeUser()` を呼び出しても、セッション数には影響しません。 - **異なる**ユーザー IDで `changeUser()` を呼び出すと、現在のセッションが自動的に終了し、新しいセッションが開始されます。 - 匿名ユーザーが**新しい**ユーザー ID(Brazeにまだ存在しないもの)で `changeUser()` を呼び出すと、匿名プロファイルのデータが新しい識別済みプロファイルにマージされます。 - 匿名ユーザーが**既存の**ユーザー IDで `changeUser()` を呼び出すと、匿名プロファイルのデータは識別済みプロファイルにマージされません。 **Note:** `changeUser()` を呼び出すと、現在のユーザーのセッションを閉じる過程でデータフラッシュがトリガーされます。SDKは新しいユーザーに切り替える前に、前のユーザーの保留中のデータを自動的にフラッシュするため、`changeUser()` を呼び出す前に手動でデータフラッシュをリクエストする必要はありません。 **Warning:** 単一の共有ユーザー ID(たとえば、静的なデフォルトのexternal ID)を割り当てたり、ユーザーがログアウトしたときに `changeUser()` を呼び出したりしないでください。そうすると、共有デバイスで以前ログインしたユーザーに再度エンゲージすることができなくなり、すべてのデータが単一のユーザー IDに対して記録されるため、他の機能が期待どおりに動作しなくなる可能性があります。代わりに、すべてのユーザー IDを個別に管理し、アプリのログアウトプロセスで以前にログインしたユーザーに切り替えられるようにしてください。新しいセッションが始まると、Brazeは新しくアクティブになったプロファイルのデータを自動的に更新します。 ## ユーザーエイリアス {#user-aliases} ### 仕組み {#how-they-work} Although anonymous users don’t have `external_ids`, you can assign them a [user alias](https://www.braze.com/docs/ja/ja/user_guide/data/user_data_collection/user_profile_lifecycle/#user-aliases) instead. You should assign a user alias when you want to add other identifiers to the user but don't know what their `external_id` is (for example, they aren't logged in). With user aliases, you also can: - Use the Braze API to log events and attributes associated with anonymous users - Use the [External User ID is blank](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/segments/segmentation_filters#external-user-id) segmentation filter to target anonymous users in your messaging ### ユーザーエイリアスの設定 {#setting-a-user-alias} ユーザーエイリアスは、名前とラベルの2つの部分で構成されます。名前は識別子そのものを指し、ラベルはその識別子が属するタイプを指します。たとえば、サードパーティのカスタマーサポートプラットフォームにexternal ID `987654` を持つユーザーがいる場合、Brazeでそのユーザーに `987654` という名前と `support_id` というラベルのエイリアスを割り当てることで、プラットフォーム間でそのユーザーを追跡できます。 ```javascript braze.getUser().addAlias(ALIAS_NAME, ALIAS_LABEL); ``` ```java Braze.getInstance(context).getCurrentUser().addAlias(ALIAS_NAME, ALIAS_LABEL); ``` ```kotlin Braze.getInstance(context).currentUser?.addAlias(ALIAS_NAME, ALIAS_LABEL) ``` ```swift Appboy.sharedInstance()?.user.addAlias(ALIAS_NAME, ALIAS_LABEL) ``` ```objc [[Appboy sharedInstance].user addAlias:ALIAS_NAME withLabel:ALIAS_LABEL]; ``` ```json { "alias_name" : (required, string), "alias_label" : (required, string) } ``` ```javascript Braze.addAlias("ALIAS_NAME", "ALIAS_LABEL"); ``` ## ID命名のベストプラクティス {#naming-best-practices} ユーザー IDは、[Universally Unique Identifier (UUID)](https://en.wikipedia.org/wiki/Universally_unique_identifier) 標準を使用して作成することをおすすめします。UUIDは、ランダムで適切に分散された128ビットの文字列です。 あるいは、既存の一意識別子(名前やメールアドレスなど)をハッシュ化してユーザー IDを生成することもできます。その場合は、必ず[SDK認証](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/authentication)を実装し、ユーザーのなりすましを防いでください。 **Warning:** ユーザー IDには推測されやすい値や連番を使用しないでください。これにより、組織が悪意のある攻撃やデータ漏洩にさらされる可能性があります。 セキュリティを強化するには、[SDK認証](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/authentication)を使用してください。 最初からユーザー IDに正しい名前をつけることが重要ですが、将来的にはいつでも[`/users/external_ids/rename`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/external_id_migration)エンドポイントを使って変更できます。 | 推奨されないIDの種類 | 推奨されない例 | | ------------ | ----------- | | ユーザーが閲覧可能なプロファイルIDまたはユーザー名 | JonDoe829525552 | | メールアドレス | Anna@email.com | | 自動増分するユーザー ID | 123 | {: .reset-td-br-1 .reset-td-br-2 aria-label="ID命名のベストプラクティス" } **Warning:** ユーザー IDの作成方法に関する詳細を共有することは避けてください。これにより、組織が悪意のある攻撃やデータ漏洩にさらされる可能性があります。 # Braze SDKを通じてユーザー属性を設定する Source: /docs/ja/developer_guide/analytics/setting_user_attributes/index.md # ユーザー属性を設定する > Braze SDKを通してユーザー属性を設定する方法を学習する。 **Note:** リストされていないラッパーSDK の場合は、代わりに関連するネイティブAndroid またはSwift メソッドを使用します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ## Default user attributes ### Predefined methods Braze provides predefined methods for setting the following user attributes within the [`User` class](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.user.html): - First Name - Last Name - Language - Country - Date of Birth - Email - Gender - Home City - Phone Number ### Setting default attributes To set a default attribute for a user, call the `getUser()` method on your Braze instance to get a reference to the current user of your app. Then you can call methods to set a user attribute. ```javascript braze.getUser().setFirstName("SomeFirstName"); ``` ```javascript braze.getUser().setGender(braze.User.Genders.FEMALE); ``` ```javascript braze.getUser().setDateOfBirth(2000, 12, 25); ``` Using Google Tag Manager, standard user attributes (such as a user's first name), should be logged in the same manner as custom user attributes. Ensure the values you're passing in for standard attributes match the expected format specified in the [User class](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.user.html) documentation. For example, the gender attribute can accept any of the following as values: `"m" | "f" | "o" | "u" | "n" | "p"`. Therefore to set a user's gender as female, create a Custom HTML tag with the following content: ```html ``` ### Unsetting default attributes You can remove or unset a user attribute through your app code, a REST API request, or a [User Update](https://www.braze.com/docs/ja/ja/user_guide/messaging/canvas/canvas_components/user_update/) Canvas step. For array and boolean attributes, use `null`. For other data types, use an empty string (`""`). To unset a default user attribute with the Web SDK, pass `null` to the related method. For example: ```javascript braze.getUser().setFirstName(null); ``` ```javascript braze.getUser().setGender(null); ``` ```javascript braze.getUser().setDateOfBirth(null, null, null); ``` ## Custom user attributes ### Setting custom attributes In addition to the default user attribute methods, you can also set [custom attributes](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/custom_data/custom_attributes/#custom-attribute-data-types) for your users. Full method specifications, see [our JSDocs](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.user.html). To set a custom attribute with a `string` value: ```javascript braze.getUser().setCustomUserAttribute( YOUR_ATTRIBUTE_KEY_STRING, YOUR_STRING_VALUE ); ``` To set a custom attribute with a `integer` value: ```javascript braze.getUser().setCustomUserAttribute( YOUR_ATTRIBUTE_KEY_STRING, YOUR_INT_VALUE ); // Integer attributes may also be incremented using code like the following braze.getUser().incrementCustomUserAttribute( YOUR_ATTRIBUTE_KEY_STRING, THE_INTEGER_VALUE_BY_WHICH_YOU_WANT_TO_INCREMENT_THE_ATTRIBUTE ); ``` To set a custom attribute with a `date` value: ```javascript braze.getUser().setCustomUserAttribute( YOUR_ATTRIBUTE_KEY_STRING, YOUR_DATE_VALUE ); // This method will assign the current time to a custom attribute at the time the method is called braze.getUser().setCustomUserAttribute( YOUR_ATTRIBUTE_KEY_STRING, new Date() ); // This method will assign the date specified by secondsFromEpoch to a custom attribute braze.getUser().setCustomUserAttribute( YOUR_ATTRIBUTE_KEY_STRING, new Date(secondsFromEpoch * 1000) ); ``` The default and maximum number of elements in an array is 500. You can update the maximum number of arrays in the Braze dashboard, under **Data Settings** > **Custom Attributes**. Arrays exceeding the maximum number of elements are truncated to contain the maximum number of elements. To set a custom attribute with an `array` value: ```javascript braze.getUser().setCustomUserAttribute(YOUR_ATTRIBUTE_KEY_STRING, YOUR_ARRAY_OF_STRINGS); // Adding a new element to a custom attribute with an array value braze.getUser().addToCustomAttributeArray(YOUR_ATTRIBUTE_KEY_STRING, "new string"); // Removing an element from a custom attribute with an array value braze.getUser().removeFromCustomAttributeArray(YOUR_ATTRIBUTE_KEY_STRING, "value to be removed"); ``` **Important:** Dates passed to Braze with this method must be JavaScript Date objects. **Important:** Custom attribute keys and values can only have a maximum of 255 characters. For more information about valid custom attribute values, refer to the [reference documentation](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.user.html). Custom user attributes are not available due to a limitation in Google Tag Manager's scripting language. To log custom attributes, create a Custom HTML tag with the following content: ```html ``` **Important:** The GTM template does not support nested properties on events or purchases. You can use the preceding HTML to log any events or purchases that require nested properties. ### Unsetting custom attributes To unset a custom attribute, pass `null` to the related method. ```javascript braze.getUser().setCustomUserAttribute(YOUR_ATTRIBUTE_KEY_STRING, null); ``` ### Nesting custom attributes You can also nest properties within custom attributes. In the following example, a `favorite_book` object with nested properties is set as a custom attribute on the user profile. For more details, refer to [Nested Custom Attributes](https://www.braze.com/docs/ja/ja/user_guide/data/custom_data/custom_attributes/nested_custom_attribute_support). ```javascript import * as braze from "@braze/web-sdk"; const favoriteBook = { title: "The Hobbit", author: "J.R.R. Tolkien", publishing_date: "1937" }; braze.getUser().setCustomUserAttribute("favorite_book", favoriteBook); ``` ### Using the REST API You can also use our REST API to set or unset user attributes. For more information, refer to [User Data Endpoints](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data/#user-data). ## Setting user subscriptions To set up a subscription for your users (either email or push), call the functions `setEmailNotificationSubscriptionType()` or `setPushNotificationSubscriptionType()`, respectively. Both functions take the `enum` type `braze.User.NotificationSubscriptionTypes` as arguments. This type has three different states: | Subscription Status | Definition | | ------------------- | ---------- | | `braze.User.NotificationSubscriptionTypes.OPTED_IN` | Subscribed, and explicitly opted in | | `braze.User.NotificationSubscriptionTypes.SUBSCRIBED` | Subscribed, but not explicitly opted in | | `braze.User.NotificationSubscriptionTypes.UNSUBSCRIBED` | Unsubscribed and/or explicitly opted out | {: .reset-td-br-1 .reset-td-br-2 aria-label="Setting user subscriptions" } When a user is registered for push, the browser forces them to choose to allow or block notifications, and if they choose to allow push, they are set `OPTED_IN` by default. Visit [Managing user subscriptions](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/managing_user_subscriptions/#managing-user-subscriptions) for more information on implementing subscriptions and explicit opt-ins. ### Unsubscribing a user from email ```javascript braze.getUser().setEmailNotificationSubscriptionType(braze.User.NotificationSubscriptionTypes.UNSUBSCRIBED); ``` ### Unsubscribing a user from push ```java braze.getUser().setPushNotificationSubscriptionType(braze.User.NotificationSubscriptionTypes.UNSUBSCRIBED); ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Default user attributes ### Predefined methods Braze provides predefined methods for setting the following user attributes within the [`BrazeUser`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze-user/index.html) class. For method specifications, refer to [our KDoc](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze-user/index.html). - First name - Last name - Country - Language - Date of birth - Email - Gender - Home city - Phone number **Note:** All string values such as first name, last name, country, and home city are limited to 255 characters. ### Setting default attributes To set a default attribute for a user, call the `getCurrentUser()` method on your Braze instance to get a reference to the current user of your app. Then you can call methods to set a user attribute. ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setFirstName("first_name"); } } ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setFirstName("first_name") } ``` ### Unsetting default attributes To unset a user attribute, pass `null` to the relevant method. ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setFirstName(null); } } ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setFirstName(null) } ``` ## Custom user attributes In addition to the default user attributes, Braze also allows you to define custom attributes using several different data types. For more information on each attribute's segmentation option, see [User data collection](https://www.braze.com/docs/ja/ja/developer_guide/analytics). ### Setting custom attributes To set a custom attribute with a `string` value: ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setCustomUserAttribute("your_attribute_key", "your_attribute_value"); } } ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setCustomUserAttribute("your_attribute_key", "your_attribute_value") } ``` To set a custom attribute with an `int` value: ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_INT_VALUE); // Integer attributes may also be incremented using code like the following: brazeUser.incrementCustomUserAttribute("your_attribute_key", YOUR_INCREMENT_VALUE); } } ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_INT_VALUE) // Integer attributes may also be incremented using code like the following: brazeUser.incrementCustomUserAttribute("your_attribute_key", YOUR_INCREMENT_VALUE) } ``` To set a custom attribute with a `long` integer value: ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_LONG_VALUE); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_LONG_VALUE) } ``` To set a custom attribute with a `float` value: ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_FLOAT_VALUE); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_FLOAT_VALUE) } ``` To set a custom attribute with a `double` value: ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_DOUBLE_VALUE); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_DOUBLE_VALUE) } ``` To set a custom attribute with a `boolean` value: ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_BOOLEAN_VALUE); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_BOOLEAN_VALUE) } ``` ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_DATE_VALUE); // This method will assign the current time to a custom attribute at the time the method is called: brazeUser.setCustomUserAttributeToNow("your_attribute_key"); // This method will assign the date specified by SECONDS_FROM_EPOCH to a custom attribute: brazeUser.setCustomUserAttributeToSecondsFromEpoch("your_attribute_key", SECONDS_FROM_EPOCH); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setCustomUserAttribute("your_attribute_key", YOUR_DATE_VALUE) // This method will assign the current time to a custom attribute at the time the method is called: brazeUser.setCustomUserAttributeToNow("your_attribute_key") // This method will assign the date specified by SECONDS_FROM_EPOCH to a custom attribute: brazeUser.setCustomUserAttributeToSecondsFromEpoch("your_attribute_key", SECONDS_FROM_EPOCH) } ``` **Warning:** Dates passed to Braze with this method must either be in the [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) format (e.g `2013-07-16T19:20:30+01:00`) or in the `yyyy-MM-dd'T'HH:mm:ss:SSSZ` format (e.g `2016-12-14T13:32:31.601-0800`). The default and maximum number of elements in an array is 500. You can update the maximum number of arrays in the Braze dashboard, under **Data Settings** > **Custom Attributes**. Arrays exceeding the maximum number of elements are truncated to contain the maximum number of elements. For more information on custom attribute arrays and their behavior, see [Arrays](https://www.braze.com/docs/ja/ja/developer_guide/analytics/#arrays). ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { // Setting a custom attribute with an array value brazeUser.setCustomAttributeArray("your_attribute_key", testSetArray); // Adding to a custom attribute with an array value brazeUser.addToCustomAttributeArray("your_attribute_key", "value_to_add"); // Removing a value from an array type custom attribute brazeUser.removeFromCustomAttributeArray("your_attribute_key", "value_to_remove"); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> // Setting a custom attribute with an array value brazeUser.setCustomAttributeArray("your_attribute_key", testSetArray) // Adding to a custom attribute with an array value brazeUser.addToCustomAttributeArray("your_attribute_key", "value_to_add") // Removing a value from an array type custom attribute brazeUser.removeFromCustomAttributeArray("your_attribute_key", "value_to_remove") } ``` ### Unsetting custom attributes To unset a custom attribute, pass the relevant attribute key to the `unsetCustomUserAttribute` method. ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.unsetCustomUserAttribute("your_attribute_key"); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.unsetCustomUserAttribute("your_attribute_key") } ``` ### Nesting custom attributes You can also nest properties within custom attributes. In the following example, a `favorite_book` object with nested properties is set as a custom attribute on the user profile. For more details, refer to [Nested Custom Attributes](https://www.braze.com/docs/ja/ja/user_guide/data/custom_data/custom_attributes/nested_custom_attribute_support). ```java JSONObject favoriteBook = new JSONObject(); try { favoriteBook.put("title", "The Hobbit"); favoriteBook.put("author", "J.R.R. Tolkien"); favoriteBook.put("publishing_date", "1937"); } catch (JSONException e) { e.printStackTrace(); } braze.getCurrentUser(user -> { user.setCustomUserAttribute("favorite_book", favoriteBook); return null; }); ``` ```kotlin val favoriteBook = JSONObject() .put("title", "The Hobbit") .put("author", "J.R.R. Tolkien") .put("publishing_date", "1937") braze.getCurrentUser { user -> user.setCustomUserAttribute("favorite_book", favoriteBook) } ``` ### Using the REST API You can also use our REST API to set or unset user attributes. For more information, refer to [User Data Endpoints](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data/#user-data). ## Setting user subscriptions To set up a subscription for your users (either email or push), call the functions `setEmailNotificationSubscriptionType()` or `setPushNotificationSubscriptionType()`, respectively. Both of these functions take the enum type `NotificationSubscriptionType` as arguments. This type has three different states: | Subscription status | Definition | | ------------------- | ---------- | | `OPTED_IN` | Subscribed, and explicitly opted in | | `SUBSCRIBED` | Subscribed, but not explicitly opted in | | `UNSUBSCRIBED` | Unsubscribed and/or explicitly opted out | {: .reset-td-br-1 .reset-td-br-2 aria-label="Setting user subscriptions" } **Important:** No explicit opt-in is required by Android to send users push notifications. When a user is registered for push, they are set to `SUBSCRIBED` rather than `OPTED_IN` by default. Refer to [managing user subscriptions](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/managing_user_subscriptions/#managing-user-subscriptions) for more information on implementing subscriptions and explicit opt-ins. ### Setting email subscriptions ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setEmailNotificationSubscriptionType(emailNotificationSubscriptionType); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setEmailNotificationSubscriptionType(emailNotificationSubscriptionType) } ``` ### Setting push notification subscription ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setPushNotificationSubscriptionType(pushNotificationSubscriptionType); } }); ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setPushNotificationSubscriptionType(pushNotificationSubscriptionType) } ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). ## Default user attributes ### Supported attributes The following attributes should be set on the `Braze.User` object: - `firstName` - `lastName` - `email` - `dateOfBirth` - `country` - `language` - `homeCity` - `phone` - `gender` ### Setting default attributes To set a default user attribute, set the appropriate field on the shared `Braze.User` object. The following is an example of setting the first name attribute: ```swift AppDelegate.braze?.user.set(firstName: "Alex") ``` ```objc [AppDelegate.braze.user setFirstName:@"Alex"]; ``` ### Unsetting default attributes To unset a default user attribute, pass `nil` to the relevant method. ```swift AppDelegate.braze?.user.set(firstName: nil) ``` ```objc [AppDelegate.braze.user setFirstName:nil]; ``` ## Custom user attributes In addition to the default user attributes, Braze also allows you to define custom attributes using several different data types. For more information on each attribute's segmentation option, see [User data collection](https://www.braze.com/docs/ja/ja/developer_guide/analytics/). **Important:** Custom attribute values have a maximum length of 255 characters; longer values will be truncated. For more information, refer to [`Braze.User`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/user-swift.class). ### Setting custom attributes To set a custom attribute with a `string` value: ```swift AppDelegate.braze?.user.setCustomAttribute(key: "your_attribute_key", value: "your_attribute_value") ``` ```objc [AppDelegate.braze.user setCustomAttributeWithKey:@"your_attribute_key" stringValue:"your_attribute_value"]; ``` To set a custom attribute with an `integer` value: ```swift AppDelegate.braze?.user.setCustomAttribute(key: "your_attribute_key", value: yourIntegerValue) ``` ```objc [AppDelegate.braze.user setCustomAttributeWithKey:@"your_attribute_key" andIntegerValue:yourIntegerValue]; ``` Braze treats `float` and `double` values the same within our database. To set a custom attribute with a double value: ```swift AppDelegate.braze?.user.setCustomAttribute(key: "your_attribute_key", value: yourDoubleValue) ``` ```objc [AppDelegate.braze.user setCustomAttributeWithKey:@"your_attribute_key" andDoubleValue:yourDoubleValue]; ``` To set a custom attribute with a `boolean` value: ```swift AppDelegate.braze?.user.setCustomAttribute("your_attribute_key", value: yourBoolValue) ``` ```objc [AppDelegate.braze.user setCustomAttributeWithKey:@"your_attribute_key" andBOOLValue:yourBOOLValue]; ``` To set a custom attribute with a `date` value: ```swift AppDelegate.braze?.user.setCustomAttribute("your_attribute_key", dateValue:yourDateValue) ``` ```objc [AppDelegate.braze.user setCustomAttributeWithKey:@"your_attribute_key" andDateValue:yourDateValue]; ``` The default and maximum number of elements in an array is 500. You can update the maximum number of arrays in the Braze dashboard, under **Data Settings** > **Custom Attributes**. Arrays exceeding the maximum number of elements are truncated to contain the maximum number of elements. To set a custom attribute with an `array` value: ```swift // Setting a custom attribute with an array value AppDelegate.braze?.user.setCustomAttributeArray(key: "array_name", array: ["value1", "value2"]) // Adding to a custom attribute with an array value AppDelegate.braze?.user.addToCustomAttributeArray(key: "array_name", value: "value3") // Removing a value from an array type custom attribute AppDelegate.braze?.user.removeFromCustomAttributeArray(key: "array_name", value: "value2") ``` ```objc // Setting a custom attribute with an array value [AppDelegate.braze.user setCustomAttributeArrayWithKey:@"array_name" array:@[@"value1", @"value2"]]; // Adding to a custom attribute with an array value [AppDelegate.braze.user addToCustomAttributeArrayWithKey:@"array_name" value:@"value3"]; // Removing a value from an array type custom attribute [AppDelegate.braze.user removeFromCustomAttributeArrayWithKey:@"array_name" value:@"value2"]; // Removing an entire array and key [AppDelegate.braze.user setCustomAttributeArrayWithKey:@"array_name" array:nil]; ``` ### Incrementing or decrementing custom attributes This code is an example of an incrementing custom attribute. You may increment the value of a custom attribute by any `integer` or `long` value: ```swift AppDelegate.braze?.user.incrementCustomUserAttribute(key: "your_attribute_key", by: incrementIntegerValue) ``` ```objc [AppDelegate.braze.user incrementCustomUserAttribute:@"your_attribute_key" by:incrementIntegerValue]; ``` ### Unsetting custom attributes To unset a custom attribute, pass the relevant attribute key to the `unsetCustomAttribute` method. ```swift AppDelegate.braze?.user.unsetCustomAttribute(key: "your_attribute_key") ``` To unset a custom attribute, pass the relevant attribute key to the `unsetCustomAttributeWithKey` method. ```objc [AppDelegate.braze.user unsetCustomAttributeWithKey:@"your_attribute_key"]; ``` ### Nesting custom attributes You can also nest properties within custom attributes. In the following example, a `favorite_book` object with nested properties is set as a custom attribute on the user profile. For more details, refer to [Nested Custom Attributes](https://www.braze.com/docs/ja/ja/user_guide/data/custom_data/custom_attributes/nested_custom_attribute_support). ```swift let favoriteBook: [String: Any?] = [ "title": "The Hobbit", "author": "J.R.R. Tolkien", "publishing_date": "1937" ] braze.user.setCustomAttribute(key: "favorite_book", dictionary: favoriteBook) ``` ```objc NSDictionary *favoriteBook = @{ @"title": @"The Hobbit", @"author": @"J.R.R. Tolkien", @"publishing_date": @"1937" }; [AppDelegate.braze.user setCustomAttributeWithKey:@"favorite_book" dictionary:favoriteBook]; ``` ### Using the REST API You can also use our REST API to set or unset user attributes. For more information, refer to [User Data Endpoints](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data/#user-data). ## Setting user subscriptions To set up a subscription for your users (either email or push), call the functions `set(emailSubscriptionState:)` or `set(pushNotificationSubscriptionState:)`, respectively. Both of these functions take the enum type `Braze.User.SubscriptionState` as arguments. This type has three different states: | Subscription Status | Definition | | ------------------- | ---------- | | `optedIn` | Subscribed, and explicitly opted in | | `subscribed` | Subscribed, but not explicitly opted in | | `unsubscribed` | Unsubscribed and/or explicitly opted out | {: .reset-td-br-1 .reset-td-br-2 aria-label="Setting user subscriptions" } Users who grant permission for an app to send them push notifications default to the status of `optedIn` as iOS requires an explicit opt-in. Users will be set to `subscribed` automatically upon receipt of a valid email address; however, we suggest that you establish an explicit opt-in process and set this value to `optedIn` upon receipt of explicit consent from your user. Refer to [Managing user subscriptions](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/managing_user_subscriptions/) for more details. ### Setting email subscriptions ```swift AppDelegate.braze?.user.set(emailSubscriptionState: Braze.User.SubscriptionState) ``` ```objc [AppDelegate.braze.user setEmailSubscriptionState: BRZUserSubscriptionState] ``` ### Setting push notification subscriptions ```swift AppDelegate.braze?.user.set(pushNotificationSubscriptionState: Braze.User.SubscriptionState) ``` ```objc [AppDelegate.braze.user setPushNotificationSubscriptionState: BRZUserSubscriptionState] ``` Refer to [Managing user subscriptions](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/managing_user_subscriptions/) for more details. ## Prerequisites Before you can use this feature, you'll need to [integrate the Flutter Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=flutter). ## Default user attributes ### Supported attributes The following attributes are supported: - First Name - Last Name - Gender - Date of Birth - Home City - Country - Phone Number - Language - Email **Important:** All string values such as first name, last name, country, and home city are limited to 255 characters. ### Setting default attributes To set user attributes automatically collected by Braze, you can use the setter methods included with the SDK. ```dart braze.setFirstName('Name'); ``` ## Custom user attributes ### Setting custom attributes In addition to the default user attributes, Braze also allows you to define custom attributes using a number of different data types: To set a custom attribute with a `string` value: ```dart braze.setStringCustomUserAttribute("custom string attribute", "string custom attribute"); ``` To set a custom attribute with an `integer` value: ```dart // Set Integer Attribute braze.setIntCustomUserAttribute("custom int attribute key", integer); // Increment Integer Attribute braze.incrementCustomUserAttribute("key", integer); ``` To set a custom attribute with a `double` value: ```dart braze.setDoubleCustomUserAttribute("custom double attribute key", double); ``` To set a custom attribute with a `boolean` value: ```dart braze.setBoolCustomUserAttribute("custom boolean attribute key", boolean); ``` To set a custom attribute with a `date` value: ```dart braze.setDateCustomUserAttribute("custom date attribute key", date); ``` To set a custom attribute with an `array` value: ```dart // Adding to an Array braze.addToCustomAttributeArray("key", "attribute"); // Removing an item from an Array braze.removeFromCustomAttributeArray("key", "attribute"); ``` **Important:** Custom attribute values have a maximum length of 255 characters; longer values will be truncated. ### Unsetting custom attributes To unset a custom attribute, pass the relevant attribute key to the `unsetCustomUserAttribute` method. ```dart braze.unsetCustomUserAttribute('attribute_key'); ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Roku Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=roku). ## Default user attributes ### Predefined methods Braze provides predefined methods for setting the following user attributes using the `m.Braze` object. - `FirstName` - `LastName` - `Email` - `Gender` - `DateOfBirth` - `Country` - `Language` - `HomeCity` - `PhoneNumber` ### Setting default attributes To set a default attribute, call the relevant method on the `m.Braze` object. ```brightscript m.Braze.setFirstName("Alex") ``` ```brightscript m.Braze.setLastName("Smith") ``` ```brightscript m.Braze.setEmail("alex@example.com") ``` ```brightscript m.Braze.setGender("m") ' Accepts: "m", "f", "o", "n", "u", "p" ``` ```brightscript m.Braze.setDateOfBirth(1990, 5, 15) ' Year, month, day ``` ```brightscript m.Braze.setCountry("United States") ``` ```brightscript m.Braze.setLanguage("en") ``` ```brightscript m.Braze.setHomeCity("New York") ``` ```brightscript m.Braze.setPhoneNumber("+1234567890") ``` ## Custom user attributes In addition to the default user attributes, Braze also allows you to define custom attributes using several different data types. ### Settings custom attributes To set a custom attribute a `string` value: ```brightscript m.Braze.setCustomAttribute("stringAttribute", "stringValue") ``` To set a custom attribute with an `integer` value: ```brightscript m.Braze.setCustomAttribute("intAttribute", 5) ``` Braze treats `float` and `double` values exactly the same. To set a custom attribute with either value: ```brightscript m.Braze.setCustomAttribute("floatAttribute", 3.5) ``` To set a custom attribute with a `boolean` value: ```brightscript m.Braze.setCustomAttribute("boolAttribute", true) ``` To set a custom attribute with a `date` value: ```brightscript dateAttribute = CreateObject("roDateTime") dateAttribute.fromISO8601String("1992-11-29 00:00:00.000") m.Braze.setCustomAttribute("dateAttribute", dateAttribute) ``` To set a custom attribute with an `array` value: ```brightscript stringArray = createObject("roArray", 3, true) stringArray.Push("string1") stringArray.Push("string2") stringArray.Push("string3") m.Braze.setCustomAttribute("arrayAttribute", stringArray) ``` **Important:** Custom attribute values have a maximum length of 255 characters; longer values will be truncated. ### Incrementing and decrementing custom attributes This code is an example of an incrementing custom attribute. You may increment the value of a custom attribute by any positive or negative integer value. ```brightscript m.Braze.incrementCustomUserAttribute("intAttribute", 3) ``` ### Unsetting custom attributes To unset a custom attribute, pass the relevant attribute key to the `unsetCustomAttribute` method. ```brightscript m.Braze.unsetCustomAttribute("attributeName") ``` ### Using the REST API You can also use our REST API to set or unset user attributes. For more information, refer to [User Data Endpoints](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data/#user-data). ## Setting email subscriptions You can set the following email subscription statuses for your users programmatically through the SDK. | Subscription Status | Definition | | ------------------- | ---------- | | `OptedIn` | Subscribed, and explicitly opted in | | `Subscribed` | Subscribed, but not explicitly opted in | | `UnSubscribed` | Unsubscribed and/or explicitly opted out | {: .reset-td-br-1 .reset-td-br-2 aria-label="Setting email subscriptions" } **Note:** These types fall under `BrazeConstants().SUBSCRIPTION_STATES`. The method for setting email subscription status is `setEmailSubscriptionState()`. Users will be set to `Subscribed` automatically upon receipt of a valid email address, however, we suggest that you establish an explicit opt-in process and set this value to `OptedIn` upon receipt of explicit consent from your user. For more details, visit [Managing user subscriptions](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/managing_user_subscriptions/#managing-user-subscriptions). ```brightscript m.Braze.setEmailSubscriptionState(BrazeConstants().SUBSCRIPTION_STATES.OPTED_IN) ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Unity Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=unity). ## Default user attributes ### Predefined methods Braze provides predefined methods for setting the following user attributes using the `BrazeBinding` object. For more information, see [Braze Unity declaration file](https://github.com/braze-inc/braze-unity-sdk/blob/master/Assets/Plugins/Appboy/BrazePlatform.cs). - First name - Last name - User email - Gender - Birth date - User country - User home city - User email subscription - User push subscription - User phone number ### Setting default attributes To set a default attribute, call the relevant method on the `BrazeBinding` object. ```csharp BrazeBinding.SetUserFirstName("first name"); ``` ```csharp BrazeBinding.SetUserLastName("last name"); ``` ```csharp BrazeBinding.SetUserEmail("user@example.com"); ``` ```csharp BrazeBinding.SetUserGender(Appboy.Models.Gender); ``` ```csharp BrazeBinding.SetUserDateOfBirth("year(int)", "month(int)", "day(int)"); ``` ```csharp BrazeBinding.SetUserCountry("country name"); ``` ```csharp BrazeBinding.SetUserHomeCity("city name"); ``` ```csharp BrazeBinding.SetUserEmailNotificationSubscriptionType(AppboyNotificationSubscriptionType); ``` ```csharp BrazeBinding.SetUserPushNotificationSubscriptionType(AppboyNotificationSubscriptionType); ``` ```csharp BrazeBinding.SetUserPhoneNumber("phone number"); ``` ### Unsetting default attributes To unset a default user attribute, pass `null` to the relevant method. ```csharp BrazeBinding.SetUserFirstName(null); ``` ## Custom user attributes In addition to the default user attributes, Braze also allows you to define custom attributes using several different data types. For more information on each attribute's segmentation option, see [User data collection](https://www.braze.com/docs/ja/ja/developer_guide/analytics). ### Setting custom attributes To set a custom attribute, use the corresponding method for the attribute type: ```csharp AppboyBinding.SetCustomUserAttribute("custom string attribute key", "string custom attribute"); ``` ```csharp // Set Integer Attribute AppboyBinding.SetCustomUserAttribute("custom int attribute key", 'integer value'); // Increment Integer Attribute AppboyBinding.IncrementCustomUserAttribute("key", increment(int)) ``` ```csharp AppboyBinding.SetCustomUserAttribute("custom float attribute key", 'float value'); ``` ```csharp AppboyBinding.SetCustomUserAttribute("custom boolean attribute key", 'boolean value'); ``` ```csharp AppboyBinding.SetCustomUserAttributeToNow("custom date attribute key"); ``` ```csharp AppboyBinding.SetCustomUserAttributeToSecondsFromEpoch("custom date attribute key", 'integer value'); ``` **Note:** Dates passed to Braze must either be in the [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) format (such as `2013-07-16T19:20:30+01:00`) or in the `yyyy-MM-dd'T'HH:mm:ss:SSSZ` format (such as`2016-12-14T13:32:31.601-0800`). ```csharp // Setting An Array AppboyBinding.SetCustomUserAttributeArray("key", array(List), sizeOfTheArray(int)) // Adding to an Array AppboyBinding.AddToCustomUserAttributeArray("key", "Attribute") // Removing an item from an Array AppboyBinding.RemoveFromCustomUserAttributeArray("key", "Attribute") ``` **Important:** Custom attribute values have a maximum length of 255 characters; longer values will be truncated. ### Unsetting custom attributes To unset a custom attribute, pass the relevant attribute key to the `UnsetCustomUserAttribute` method. ```csharp AppboyBinding.UnsetCustomUserAttribute("custom attribute key"); ``` ### Using the REST API You can also use our REST API to set or unset user attributes. For more information, refer to [User Data Endpoints](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data/#user-data). ## Setting user subscriptions To set up an email or push subscription for your users, call one of the following functions. ```csharp // Email notifications AppboyBinding.SetUserEmailNotificationSubscriptionType() // Push notifications AppboyBinding.SetPushNotificationSubscriptionType()` ``` Both functions take `Appboy.Models.AppboyNotificationSubscriptionType` as arguments, which has three different states: | Subscription Status | Definition | | ------------------- | ---------- | | `OPTED_IN` | Subscribed, and explicitly opted in | | `SUBSCRIBED` | Subscribed, but not explicitly opted in | | `UNSUBSCRIBED` | Unsubscribed and/or explicitly opted out | {: .reset-td-br-1 .reset-td-br-2 aria-label="Setting user subscriptions" } **Note:** No explicit opt-in is required by Windows to send users push notifications. When a user is registered for push, they are set to `SUBSCRIBED` rather than `OPTED_IN` by default. To learn more, check out our documentation on [implementing subscriptions and explicit opt-ins](https://www.braze.com/docs/ja/ja/user_guide/message_building_by_channel/email/managing_user_subscriptions/#managing-user-subscriptions). | Subscription Type | Description | |------------------------------------------|-------------| | `EmailNotificationSubscriptionType` | Users will be set to `SUBSCRIBED` automatically upon receipt of a valid email address. However, we suggest that you establish an explicit opt-in process and set this value to `OPTED_IN` upon receipt of explicit consent from your user. Visit our [Changing User Subscriptions](https://www.braze.com/docs/ja/ja/user_guide/administrative/manage_your_users/managing_user_subscriptions/#changing-subscriptions) doc for more details. | | `PushNotificationSubscriptionType` | Users will be set to `SUBSCRIBED` automatically upon valid push registration. However, we suggest that you establish an explicit opt-in process and set this value to `OPTED_IN` upon receipt of explicit consent from your user. Visit our [Changing User Subscriptions](https://www.braze.com/docs/ja/ja/user_guide/administrative/manage_your_users/managing_user_subscriptions/#changing-subscriptions) doc for more details. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Setting user subscriptions" } **Note:** These types fall under `Appboy.Models.AppboyNotificationSubscriptionType`. ### Setting email subscriptions ```csharp AppboyBinding.SetUserEmailNotificationSubscriptionType(AppboyNotificationSubscriptionType.OPTED_IN); ``` ### Setting push notification subscriptions ```csharp AppboyBinding.SetUserPushNotificationSubscriptionType(AppboyNotificationSubscriptionType.OPTED_IN); ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Logging custom attributes Braze provides methods for assigning attributes to users. You'll be able to filter and segment your users according to these attributes on the dashboard. ### Default user attributes To set user attributes automatically collected by Braze, you can use setter methods that come with the SDK. ```javascript Braze.setFirstName("Name"); ``` The following attributes are supported: - First Name - Last Name - Gender - Date of Birth - Home City - Country - Phone Number - Language - Email All string values such as first name, last name, country, and home city are limited to 255 characters. ### Custom user attributes In addition to our predefined user attribute methods, Braze also provides [custom attributes](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/custom_data/custom_attributes/#custom-attribute-data-types) to track data from your applications. ```javascript Braze.setCustomUserAttribute("attribute_key", "attribute_value", function(){ // optional onResult callback }); ``` #### Unsetting custom attributes ```javascript Braze.unsetCustomUserAttribute("attribute_key", function(){ // optional onResult callback }); ``` #### Custom Attribute Arrays ```javascript // Adds a string to a custom attribute string array, or creates that array if one doesn't exist. Braze.addToCustomUserAttributeArray("my-attribute-array", "new or existing value", optionalCallback); // Removes a string from a custom attribute string array. Braze.removeFromCustomUserAttributeArray("my-attribute-array", "existing value", optionalCallback); ``` # Braze SDKを通じてカスタムイベントをログに記録する Source: /docs/ja/developer_guide/analytics/logging_events/index.md # カスタムイベントをログに記録する {#log-custom-events} > Braze SDKを通じてカスタムイベントを記録する方法を説明します。 **Note:** リストされていないラッパーSDKの場合は、代わりに関連するネイティブAndroidまたはSwiftメソッドを使用してください。 eコマースの推奨イベントについては、[eコマースイベントを記録する](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_ecommerce_events)を参照してください。 ## カスタムイベントをログに記録する {#logging-a-custom-event} カスタムイベントを記録するには、以下のイベントロギングメソッドを使用します。 標準のWeb SDK実装では、以下のメソッドを使用できます。 ```javascript braze.logCustomEvent("YOUR_EVENT_NAME"); ``` 代わりにGoogle Tag Managerを使用したい場合は、**カスタムイベント**タグタイプを使用して、[`logCustomEvent`メソッド](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logcustomevent)を呼び出し、カスタムイベントプロパティをオプションで含めて、カスタムイベントをBrazeに送信できます。これを行うには: 1. 変数を使用するか、イベント名を入力して、**Event Name**を入力します。 2. イベントプロパティを追加するには、**Add Row**ボタンを使用します。 ![Brazeアクションタグの設定を示すダイアログボックス。設定項目には「タグタイプ」(カスタムイベント)、「イベント名」(ボタンクリック)、「イベントプロパティ」が含まれます。](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-custom-event.png?f5c76a9c9b8c1e0f2a24ddd36d3fffba) ネイティブAndroidの場合は、以下のメソッドを使用できます。 ```java Braze.getInstance(context).logCustomEvent(YOUR_EVENT_NAME); ``` ```kotlin Braze.getInstance(context).logCustomEvent(YOUR_EVENT_NAME) ``` ```swift AppDelegate.braze?.logCustomEvent(name: "YOUR_EVENT_NAME") ``` ```objc [AppDelegate.braze logCustomEvent:@"YOUR_EVENT_NAME"]; ``` ```dart braze.logCustomEvent('YOUR_EVENT_NAME'); ``` Braze Cordovaプラグインメソッドを使用します: ```javascript BrazePlugin.logCustomEvent("YOUR_EVENT_NAME"); ``` `logCustomEvent` APIは以下を受け付けます: - `eventName`(必須の文字列):最大255文字まで使用できます。名前を`$`で始めないでください。英数字と句読点を使用してください。 - `eventProperties`(オプションのオブジェクト):イベントメタデータ用のキーと値のペアを追加します。キーは最大255文字まで使用でき、キーを`$`で始めないでください。 プロパティ値には、`string`(最大255文字)、`numeric`、`boolean`、配列、またはネストされたJSONオブジェクトを使用します。 実装の詳細については、Braze Cordova SDKのソースを参照してください: - [`www/BrazePlugin.js`の`logCustomEvent`メソッド(138行目から140行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/www/BrazePlugin.js#L138-L140) - [`www/BrazePlugin.js` JSDoc(128行目から140行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/www/BrazePlugin.js#L128-L140) - [Androidハンドラー`src/android/BrazePlugin.kt`(108行目から115行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/src/android/BrazePlugin.kt#L108-L115) - [iOSハンドラー`src/ios/BrazePlugin.m`(308行目から313行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/src/ios/BrazePlugin.m#L308-L313) - [iOSメソッド宣言`src/ios/BrazePlugin.h`(24行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/src/ios/BrazePlugin.h#L24) [Infillion Beacons](https://infillion.com/software/beacons/)をAndroidアプリに統合している場合は、オプションで`visit.getPlace()`を使用してロケーション固有のイベントをログに記録できます。`requestImmediateDataFlush`を使用すると、アプリがバックグラウンドで動作している場合でも、イベントが確実に記録されます。 ```java Braze.getInstance(context).logCustomEvent("Entered " + visit.getPlace()); Braze.getInstance(context).requestImmediateDataFlush(); ``` ```kotlin Braze.getInstance(context).logCustomEvent("Entered " + visit.getPlace()) Braze.getInstance(context).requestImmediateDataFlush() ``` ```javascript Braze.logCustomEvent("YOUR_EVENT_NAME"); ``` ```brightscript m.Braze.logEvent("YOUR_EVENT_NAME") ``` ```csharp AppboyBinding.LogCustomEvent("YOUR_EVENT_NAME"); ``` ## メタデータプロパティを追加する {#adding-metadata-properties} カスタムイベントを記録する際、そのイベントにプロパティオブジェクトを渡すことで、カスタムイベントに関するメタデータを追加できます。プロパティはキーと値のペアとして定義されます。キーは文字列であり、値は`string`、`numeric`、`boolean`、[`Date`](http://www.w3schools.com/jsref/jsref_obj_date.asp)オブジェクト、配列、またはネストされたJSONオブジェクトです。 メタデータプロパティを追加するには、以下のイベントロギングメソッドを使用します。 ```javascript braze.logCustomEvent("YOUR-EVENT-NAME", { you: "can", pass: false, orNumbers: 42, orDates: new Date(), or: ["any", "array", "here"], andEven: { deeply: ["nested", "json"] } }); ``` ```java Braze.logCustomEvent("YOUR-EVENT-NAME", new BrazeProperties(new JSONObject() .put("you", "can") .put("pass", false) .put("orNumbers", 42) .put("orDates", new Date()) .put("or", new JSONArray() .put("any") .put("array") .put("here")) .put("andEven", new JSONObject() .put("deeply", new JSONArray() .put("nested") .put("json")) ) )); ``` ```kotlin Braze.logCustomEvent("YOUR-EVENT-NAME", BrazeProperties(JSONObject() .put("you", "can") .put("pass", false) .put("orNumbers", 42) .put("orDates", Date()) .put("or", JSONArray() .put("any") .put("array") .put("here")) .put("andEven", JSONObject() .put("deeply", JSONArray() .put("nested") .put("json")) ) )) ``` ```swift AppDelegate.braze?.logCustomEvent( name: "YOUR-EVENT-NAME", properties: [ "you": "can", "pass": false, "orNumbers": 42, "orDates": Date(), "or": ["any", "array", "here"], "andEven": [ "deeply": ["nested", "json"] ] ] ) ``` ```objc [AppDelegate.braze logCustomEvent:@"YOUR-EVENT-NAME" properties:@{ @"you": @"can", @"pass": @(NO), @"orNumbers": @42, @"orDates": [NSDate date], @"or": @[@"any", @"array", @"here"], @"andEven": @{ @"deeply": @[@"nested", @"json"] } }]; ``` ```dart braze.logCustomEvent('custom_event_with_properties', properties: { 'key1': 'value1', 'key2': ['value2', 'value3'], 'key3': false, }); ``` プロパティオブジェクトを使ってカスタムイベントをログに記録します: ```javascript var properties = {}; properties["key1"] = "value1"; properties["key2"] = ["value2", "value3"]; properties["key3"] = false; BrazePlugin.logCustomEvent("YOUR-EVENT-NAME", properties); ``` プロパティをインラインで渡すこともできます: ```javascript BrazePlugin.logCustomEvent("YOUR-EVENT-NAME", { "key": "value", "amount": 42, }); ``` 公式のCordovaサンプルアプリには、文字列、数値、ブール値、配列、およびネストされたオブジェクトのプロパティが含まれています: - [`sample-project/www/js/index.js`(230行目から251行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/sample-project/www/js/index.js#L230-L251) サンプルプロジェクトの抜粋: ```javascript var properties = {}; properties["One"] = "That's the Way of the World"; properties["Two"] = "After the Love Has Gone"; properties["Three"] = "Can't Hide Love"; BrazePlugin.logCustomEvent("cordovaCustomEventWithProperties", properties); BrazePlugin.logCustomEvent("cordovaCustomEventWithoutProperties"); BrazePlugin.logCustomEvent("cordovaCustomEventWithFloatProperties", { "Cart Value": 4.95, "Cart Item Name": "Spicy Chicken Bites 5 pack" }); BrazePlugin.logCustomEvent("cordovaCustomEventWithNestedProperties", { "array key": [1, "2", false], "object key": { "k1": "1", "k2": 2, "k3": false, }, "deep key": { "key": [1, "2", true] } }); ``` APIとネイティブブリッジの詳細については、以下を参照してください: - [`www/BrazePlugin.js` JSDoc(128行目から140行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/www/BrazePlugin.js#L128-L140) - [Androidハンドラー`src/android/BrazePlugin.kt`(108行目から115行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/src/android/BrazePlugin.kt#L108-L115) - [iOSハンドラー`src/ios/BrazePlugin.m`(308行目から313行目)](https://github.com/braze-inc/braze-cordova-sdk/blob/86132bc7f0b6ddf1b598b0e612db70f11744801c/src/ios/BrazePlugin.m#L308-L313) ```javascript Braze.logCustomEvent("custom_event_with_properties", { key1: "value1", key2: ["value2", "value3"], key3: false, }); ``` ```brightscript m.Braze.logEvent("YOUR_EVENT_NAME", {"stringPropKey" : "stringPropValue", "intPropKey" : Integer intPropValue}) ``` ```csharp AppboyBinding.LogCustomEvent("event name", properties(Dictionary)); ``` **Important:** `time`および`event_name`キーは予約されているため、カスタムイベントプロパティとして使用できません。 ## ベストプラクティス {#best-practices} カスタムイベントのプロパティが期待通りに記録されるようにするには、次の3つの重要な確認事項を実施してください: * [記録されるイベントを確認する](#verify-events) * [ログを確認する](#verify-log) * [値を確認する](#verify-values) カスタムイベントがログに記録されるたびに、複数のプロパティを記録できます。 ### イベントを確認する {#verify-events} どのイベントプロパティがトラッキングされているかを開発者に確認してください。すべてのイベントプロパティは大文字と小文字を区別することに留意してください。カスタムイベントのトラッキングに関する追加情報については、プラットフォーム別に以下の記事を参照してください: * [Android](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=android) * [iOS](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=swift) * [Web](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=web) ### ログを確認する {#verify-log} イベントプロパティが正常にトラッキングされていることを確認するには、**カスタムイベント**ページからすべてのイベントプロパティを表示できます。 1. **データ設定** > **カスタムイベント**に移動します。 2. リストからカスタムイベントを探します。 3. イベントの**Manage Properties**を選択すると、そのイベントに関連付けられたプロパティの名前が表示されます。 ### 値を確認する {#verify-values} [テストユーザーとしてユーザーを追加](https://www.braze.com/docs/ja/ja/user_guide/administrative/app_settings/internal_groups_tab#adding-test-users)した後、以下のステップで値を確認します: 1. アプリ内でカスタムイベントを実行します。 2. データがフラッシュされるまで約10秒待ちます。 3. [イベントユーザーログ](https://www.braze.com/docs/ja/ja/user_guide/administer/global/workspace_settings/logs_and_alerts/event_user_log)を更新して、カスタムイベントと渡されたイベントプロパティの値を確認します。 ## カスタムイベントのトラブルシューティング {#troubleshooting-custom-events} 以下のシナリオを使用して、SDK全体でのカスタムイベントロギングのトラブルシューティングを行います。 ### カスタムイベントトリガーの検証 {#verifying-the-custom-event-trigger} カスタムイベントが表示されない場合、アプリでトラッキングされているアクションがテストしているアクションと一致していない可能性があります。 - 開発者チームに、どのアプリアクションがカスタムイベントをトリガーするかを確認してください。 - SDKアップグレード後に非推奨のコードパスがないか確認してください。例えば、`braze`ではなく`appboy`への参照がないか確認します。 ### カスタムイベントが匿名プロファイルに記録される {#custom-events-are-logged-to-an-anonymous-profile} カスタムイベントを記録する前にユーザーを識別しない場合、Brazeはそのイベントを匿名プロファイルに関連付ける可能性があります。 - カスタムイベントを実行する前に`changeUser()`を呼び出して、Brazeが識別済みのユーザープロファイルにイベントを記録するようにしてください。 - 識別済みのテストユーザーでテストし、[イベントユーザーログ](https://www.braze.com/docs/ja/ja/user_guide/administer/global/workspace_settings/logs_and_alerts/event_user_log)を確認してください。 ### カスタムイベントロギングの設定を検証する {#verifying-custom-event-logging-setup} カスタムイベントが期待通りに表示されない場合、開発者チームが正しいアプリアクションに対してカスタムイベントロギングを実装しているか確認してください。 - 開発者チームに、イベントが正しくログに記録され、期待されるユーザーアクションからトリガーされていることを確認するよう依頼してください。 - チームがBrazeサポートにチケットを開く際は、[詳細ログ](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging)と関連するコードスニペットを含めてください。 - アプリがSwiftまたはAndroidを使用している場合、開発者チームは[SDKデバッガーの前提条件](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/debugging#prerequisites)を使用して詳細ログの生成を支援できます。 - 開発者チームが問題を特定できない場合は、[Brazeサポートチケット](https://www.braze.com/docs/ja/ja/user_guide/administer/personal/braze_support)を開いてください。 # Braze SDKを通じて購入を記録する Source: /docs/ja/developer_guide/analytics/logging_purchases/index.md # 購入記録 {#log-purchases} > Braze SDKを使用してアプリ内購入を記録する方法について説明します。これにより、売上を経時的にトラッキングしたり、売上源を横断してトラッキングしたりできます。カスタムイベント、カスタム属性、および購入イベントを使用して、[生涯価値に基づいて](https://www.braze.com/docs/ja/ja/developer_guide/analytics#purchase-events--revenue-tracking)ユーザーをセグメント化できます。 **Note:** リストされていないラッパーSDKの場合は、代わりに関連するネイティブAndroidまたはSwiftメソッドを使用してください。 米ドル以外の通貨でレポートされた購入は、レポートされた日付の為替レートに基づいて米ドル単位でBrazeに表示されます。通貨換算を防ぐには、通貨をUSDにハードコードしてください。 ## 購入と売上の記録 {#logging-purchases-and-revenue} 購入と収益を記録するには、アプリでの購入が正常に完了した後に`logPurchase()`を呼び出します。製品IDが空の場合、購入はBrazeに記録されません。 標準のWeb SDK実装では、以下のメソッドを使用できます。 ```javascript braze.logPurchase(product_id, price, "USD", quantity); ``` 代わりにGoogle Tag Managerを使用したい場合は、**Purchase**タグタイプを使用して[`logPurchase`メソッド](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logpurchase)を呼び出すことができます。このタグを使用して、Brazeへの購入をトラッキングします。オプションで購入プロパティを含めることもできます。そのためには以下を行います。 1. **Product ID**と**Price**フィールドは必須です。 2. 購入プロパティを追加するには、**Add Row**ボタンを使用します。 ![Brazeアクションタグの設定を示すダイアログボックス。設定項目には「tag type」「external ID」「price」「currency code」「quantity」「purchase properties」が含まれます。](https://www.braze.com/docs/ja/ja/assets/img/web-gtm/gtm-purchase.png?279d50ab49cb4e7f80e5fcd04cddf15e) ```java Braze.getInstance(context).logPurchase( String productId, String currencyCode, BigDecimal price, int quantity ); ``` ```kotlin Braze.getInstance(context).logPurchase( productId: String, currencyCode: String, price: BigDecimal, quantity: Int ) ``` ```swift AppDelegate.braze?.logPurchase(productID: "product_id", currency: "USD", price: price) ``` ```objc [AppDelegate.braze logPurchase:"product_id" currency:@"USD" price:price]; ``` ```javascript var properties = {}; properties["KEY"] = "VALUE"; BrazePlugin.logPurchase("PRODUCT_ID", 10, "USD", 5, properties); ``` ```dart braze.logPurchase(productId, currencyCode, price, quantity, properties: properties); ``` ```javascript Braze.logPurchase(productId, price, currencyCode, quantity, properties); ``` ```brightscript m.Braze.logPurchase("product_id", "currency_code", Double price, Integer quantity) ``` ```csharp AppboyBinding.LogPurchase("product_id", "currencyCode", price(decimal)); ``` **Warning:** `productID`の最大文字数は255文字です。また、製品IDが空の場合、購入はBrazeに記録されません。 ### プロパティの追加 {#adding-properties} `Int`、`Double`、`String`、`Bool`、または`Date`の値が入力されたディクショナリを渡すことで、購入に関するメタデータを追加できます。 標準のWeb SDK実装では、以下のメソッドを使用できます。 ```javascript braze.logPurchase(product_id, price, "USD", quantity, {key: "value"}); ``` サイトで標準の[eコマースイベント](https://developers.google.com/analytics/devguides/collection/ga4/ecommerce?client_type=gtm)データレイヤーアイテムを使用してGoogle Tag Managerに購入を記録する場合は、**E-commerce Purchase**タグタイプを使用できます。このアクションタイプでは、`items`のリストで送信されたアイテムごとに個別の「購入」をBrazeに記録します。 購入プロパティリストでキーを指定することで、購入プロパティとして含める追加のプロパティ名を指定することもできます。Brazeは、リストに追加した購入プロパティについて、記録されている個々の`item`内を検索します。 たとえば、次のeコマースペイロードがあるとします。 ``` items: [{ item_name: "5 L WIV ECO SAE 5W/30", item_id: "10801463", price: 24.65, item_brand: "EUROLUB", quantity: 1 }] ``` `item_brand`と`item_name`だけを購入プロパティとして渡す場合は、これら2つのフィールドを購入プロパティテーブルに追加するだけです。プロパティを指定しない場合、Brazeへの[`logPurchase`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logpurchase)呼び出しで購入プロパティは送信されません。 ```java BrazeProperties purchaseProperties = new BrazeProperties(); purchaseProperties.addProperty("key", "value"); Braze.getInstance(context).logPurchase(..., purchaseProperties); ``` ```kotlin val purchaseProperties = BrazeProperties() purchaseProperties.addProperty("key", "value") Braze.getInstance(context).logPurchase(..., purchaseProperties) ``` ```swift let purchaseProperties = ["key": "value"] AppDelegate.braze?.logPurchase(productID: "product_id", currency: "USD", price: price, properties: purchaseProperties) ``` ```objc NSDictionary *purchaseProperties = @{@"key": @"value"}; [AppDelegate.braze logPurchase:@"product_id" currency:@"USD" price:price properties:purchaseProperties]; ``` ```javascript var properties = {}; properties["key"] = "value"; BrazePlugin.logPurchase("PRODUCT_ID", 10, "USD", 5, properties); ``` ```dart braze.logPurchase(productId, currencyCode, price, quantity, properties: {"key": "value"}); ``` ```javascript Braze.logPurchase(productId, price, currencyCode, quantity, { key: "value" }); ``` ```brightscript m.Braze.logPurchase("product_id", "currency_code", Double price, Integer quantity, {"stringPropKey" : "stringPropValue", "intPropKey" : Integer intPropValue}) ``` ```csharp Dictionary purchaseProperties = new Dictionary { { "key", "value" } }; AppboyBinding.LogPurchase("product_id", "currencyCode", price(decimal), purchaseProperties); ``` ### 数量の追加 {#adding-quantity} デフォルトでは、`quantity`は`1`に設定されています。ただし、顧客が1回のチェックアウトで同じ購入を複数回行う場合は、購入に数量を追加できます。数量を追加するには、`Int`値を`quantity`に渡します。 ### REST APIの使用 {#using-the-rest-api} REST APIを使用して購入を記録することもできます。詳細については、[ユーザーデータエンドポイント](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/user_data#user-data)を参照してください。 ## 注文の記録 {#logging-orders} 商品レベルではなく、注文レベルで購入を記録したい場合、注文名または注文カテゴリを`product_id`として使用できます。詳細については、[購入オブジェクトの仕様](https://www.braze.com/docs/ja/ja/api/objects_filters/purchase_object#product-id-naming-conventions)を参照してください。 ## 予約済みのキー {#reserved-keys} 以下のキーは予約されているため、購入プロパティとして使用できません。 - `time` - `product_id` - `quantity` - `event_name` - `price` - `currency` ## 対応通貨 {#supported-currencies} Brazeは以下の通貨記号をサポートしています。これ以外の通貨記号を指定すると警告が記録され、購入はBrazeに記録されません。 - `AED`, `AFN`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN` - `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL` - `BSD`, `BTC`, `BTN`, `BWP`, `BYR`, `BZD` - `CAD`, `CDF`, `CHF`, `CLF`, `CLP`, `CNY`, `COP`, `CRC`, `CUC`, `CUP`, `CVE`, `CZK` - `DJF`, `DKK`, `DOP`, `DZD` - `EEK`, `EGP`, `ERN`, `ETB`, `EUR` - `FJD`, `FKP` - `GBP`, `GEL`, `GGP`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD` - `HKD`, `HNL`, `HRK`, `HTG`, `HUF` - `IDR`, `ILS`, `IMP`, `INR`, `IQD`, `IRR`, `ISK` - `JEP`, `JMD`, `JOD`, `JPY` - `KES`, `KGS`, `KHR`, `KMF`, `KPW`, `KRW`, `KWD`, `KYD`, `KZT` - `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LTL`, `LVL`, `LYD` - `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRO`, `MTL`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN` - `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD` - `OMR` - `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG` - `QAR` - `RON`, `RSD`, `RUB`, `RWF` - `SAR`, `SBD`, `SCR`, `SDG`, `SEK`, `SGD`, `SHP`, `SLL`, `SOS`, `SRD`, `STD`, `SVC`, `SYP`, `SZL` - `THB`, `TJS`, `TMT`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS` - `UAH`, `UGX`, `USD`, `UYU`, `UZS` - `VEF`, `VND`, `VUV` - `WST` - `XAF`, `XAG`, `XAU`, `XCD`, `XDR`, `XOF`, `XPD`, `XPF`, `XPT` - `YER` - `ZAR`, `ZMK`, `ZMW`, `ZWL` # Braze SDKを使用したeコマースイベントの記録 Source: /docs/ja/developer_guide/analytics/logging_ecommerce_events/index.md # eコマースイベントの記録 {#log-ecommerce-events} > Braze Android、Swift、Web SDKで型付きイベントクラスと`logEcommerceEvent`を使用して、[eコマース推奨イベント](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/recommended_events/ecommerce_events)を記録する方法を説明します。イベントプロパティスキーマ、プラットフォーム機能、取り込みバリデーションについては、[推奨イベント](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/recommended_events)および[イベントのバリデーションとトラブルシューティング](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/recommended_events#event-validation-and-troubleshooting)を参照してください。 **Note:** 一覧にないラッパーSDKの場合は、代わりに該当するネイティブAndroidまたはSwiftメソッドを使用してください。 ## イベントスキーマ {#event-schemas} 6つのeコマース推奨イベントは、すべてのプラットフォームで共通の注文レベルスキーマを共有しています。各イベントペイロードを構築する際は、以下のプロパティテーブルを使用してください。完全なバリデーション動作とREST APIの例を含む正規スキーマについては、[推奨イベント](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/recommended_events#event-schemas)を参照してください。セグメンテーション、キャンバステンプレート、レポートなどのプラットフォーム機能については、[eコマースイベントの使用方法](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/recommended_events/ecommerce_events)を参照してください。 ユーザーが製品詳細ページを閲覧したときにトリガーします。 **イベントプロパティ** | プロパティ名 | データタイプ | 必須 | 説明 | | ------------- | --------- | -------- | ----------- | | `product_id` | 文字列 | はい | 一意の製品識別子(例: SKUまたはアイテムID)。 | | `product_name` | 文字列 | はい | 製品の表示名。 | | `variant_id` | 文字列 | はい | 製品バリアント識別子(例: `shirt_medium_blue`)。 | | `image_url` | 文字列 | いいえ | 製品画像のURL。 | | `product_url` | 文字列 | いいえ | 製品ページの詳細URL。 | | `price` | Float | はい | 閲覧時のバリアント単価。 | | `currency` | 文字列 | はい | 3文字のISO 4217コード(例: `USD`または`EUR`)。 | | `source` | 文字列 | はい | イベントの発生元ソース(例: `web`、`ios`、または`android`)。 | | `type` | 文字列の配列 | いいえ | 在庫復活や値下げアラートのBrazeカタログトリガー機能を使用するために必須です。許容される値: `"price_drop"`、`"back_in_stock"`。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア。認識されるサブプロパティ: `sku`(文字列)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Product viewed event properties" } ユーザーのカートの内容が変更されるたびにトリガーします。カート全体の置き換え(`action`を省略するか`replace`に設定)または増分更新(`add`または`remove`)を使用します。 **イベントプロパティ** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `cart_id` | 文字列 | はい | カートの一意の識別子。ユーザーのカートマッピングのために、カート、チェックアウト、注文イベント間で共有されます。 | | `action` | 文字列 | いいえ | `add`(数量を増やすかラインを追加)、`remove`(数量を減らす。`0`でラインを削除)、または`replace`(カート全体の置き換え。`action`を省略した場合と同じ)。 | | `total_value` | Float | 条件付き | `action`が省略されているか`replace`の場合は必須。`action`が`add`または`remove`の場合はオプション。 | | `subtotal_value` | Float | いいえ | カートの小計(割引後、税・送料前)。 | | `tax` | Float | いいえ | カートに適用される合計税額。 | | `shipping` | Float | いいえ | カートの合計送料。 | | `currency` | 文字列 | はい | 3文字のISO 4217コード。 | | `products` | 配列 | はい | この更新のラインアイテム。製品プロパティテーブルを参照してください。 | | `source` | 文字列 | はい | イベントの発生元ソース。 | | `metadata` | オブジェクト | いいえ | 追加のイベントレベルデータ用の柔軟なキーと値のペア。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Cart updated event properties" } **製品プロパティ(`products[]`)** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `product_id` | 文字列 | はい | 一意の製品識別子。 | | `product_name` | 文字列 | はい | 製品の表示名。 | | `variant_id` | 文字列 | はい | バリアント識別子。 | | `image_url` | 文字列 | いいえ | 製品画像のURL。 | | `product_url` | 文字列 | いいえ | 製品ページのURL。 | | `quantity` | Integer | はい | カート全体の置き換えの場合、このラインのカート内数量。`add`または`remove`の場合、追加または削除する数量。 | | `price` | Float | はい | バリアント単価。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア(例: `color`や`size`)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Cart updated product properties" } ユーザーがチェックアウトフローを開始したときにトリガーします。 **イベントプロパティ** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `checkout_id` | 文字列 | はい | チェックアウトセッションの一意の識別子。 | | `cart_id` | 文字列 | いいえ | カート識別子。ユーザーのカートマッピングのために、カート、チェックアウト、注文イベント間で共有されます。 | | `total_value` | Float | はい | チェックアウトの合計金額。 | | `subtotal_value` | Float | いいえ | 小計(割引後、税・送料前)。 | | `tax` | Float | いいえ | チェックアウトに適用される合計税額。 | | `shipping` | Float | いいえ | 合計送料。 | | `currency` | 文字列 | はい | 3文字のISO 4217コード。 | | `products` | 配列 | はい | チェックアウト対象のアイテム。製品プロパティテーブルを参照してください。 | | `source` | 文字列 | はい | イベントの発生元ソース。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア。認識されるサブプロパティ: `checkout_url`(文字列)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Checkout started event properties" } **製品プロパティ(`products[]`)** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `product_id` | 文字列 | はい | 一意の製品識別子。 | | `product_name` | 文字列 | はい | 製品の表示名。 | | `variant_id` | 文字列 | はい | バリアント識別子。 | | `image_url` | 文字列 | いいえ | 製品画像のURL。 | | `product_url` | 文字列 | いいえ | 製品ページのURL。 | | `quantity` | Integer | はい | カート内の数量。 | | `price` | Float | はい | バリアント単価。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア(例: `color`や`size`)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Checkout started product properties" } 注文が正常に完了した場合、または支払いが確認されたときにトリガーします。 **イベントプロパティ** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `order_id` | 文字列 | はい | 注文の一意の識別子。 | | `cart_id` | 文字列 | いいえ | カート識別子。ユーザーのカートマッピングのために、カート、チェックアウト、注文イベント間で共有されます。 | | `total_value` | Float | はい | 注文の合計金額。 | | `subtotal_value` | Float | いいえ | 小計(割引後、税・送料前)。 | | `tax` | Float | いいえ | 注文に適用される合計税額。 | | `shipping` | Float | いいえ | 合計送料。 | | `currency` | 文字列 | はい | 3文字のISO 4217コード。 | | `total_discounts` | Float | いいえ | 注文に適用された割引の合計額。 | | `discounts` | 配列 | いいえ | 適用された割引の詳細リスト。各割引オブジェクトは`code`(文字列)、`amount`(Float)、`type`(文字列)をサポートします。 | | `products` | 配列 | はい | 注文内のアイテム。製品プロパティテーブルを参照してください。 | | `source` | 文字列 | はい | イベントの発生元ソース。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア。認識されるサブプロパティ: `order_status_url`(文字列)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Order placed event properties" } **製品プロパティ(`products[]`)** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `product_id` | 文字列 | はい | 一意の製品識別子。 | | `product_name` | 文字列 | はい | 製品の表示名。 | | `variant_id` | 文字列 | はい | バリアント識別子。 | | `image_url` | 文字列 | いいえ | 製品画像のURL。 | | `product_url` | 文字列 | いいえ | 製品ページのURL。 | | `quantity` | Integer | はい | 注文内の数量。 | | `price` | Float | はい | バリアント単価。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア(例: `color`や`size`)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Order placed product properties" } 注文がキャンセルされたときにトリガーします。 **イベントプロパティ** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `order_id` | 文字列 | はい | 注文の一意の識別子。 | | `total_value` | Float | はい | キャンセルされる注文の合計金額。絶対値(`0`以上)を送信してください。Brazeが減額を処理します。 | | `subtotal_value` | Float | いいえ | 小計(割引後、税・送料前)。 | | `tax` | Float | いいえ | 注文に適用される合計税額。 | | `shipping` | Float | いいえ | 合計送料。 | | `currency` | 文字列 | はい | 3文字のISO 4217コード。 | | `total_discounts` | Float | いいえ | 注文に適用された割引の合計額。 | | `discounts` | 配列 | いいえ | 適用された割引の詳細リスト。 | | `cancel_reason` | 文字列 | はい | 注文がキャンセルされた理由。 | | `products` | 配列 | はい | キャンセルされた注文内のアイテム。製品プロパティテーブルを参照してください。 | | `source` | 文字列 | はい | イベントの発生元ソース。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア。認識されるサブプロパティ: `order_status_url`(文字列)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Order cancelled event properties" } **製品プロパティ(`products[]`)** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `product_id` | 文字列 | はい | 一意の製品識別子。 | | `product_name` | 文字列 | はい | 製品の表示名。 | | `variant_id` | 文字列 | はい | バリアント識別子。 | | `image_url` | 文字列 | いいえ | 製品画像のURL。 | | `product_url` | 文字列 | いいえ | 製品ページのURL。 | | `quantity` | Integer | はい | 注文内の数量。 | | `price` | Float | はい | バリアント単価。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア(例: `color`や`size`)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Order cancelled product properties" } 全額または一部の返金が発行されたときにトリガーします。一部返金の場合、`total_value`には元の注文合計ではなく、返金額のみを設定してください。 **イベントプロパティ** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `order_id` | 文字列 | はい | 元の注文の一意の識別子。 | | `total_value` | Float | はい | 返金の合計金額。絶対値(`0`以上)を送信してください。Brazeが収益の調整を処理します。 | | `currency` | 文字列 | はい | 3文字のISO 4217コード。 | | `total_discounts` | Float | いいえ | 元々適用されていた割引の合計額。 | | `discounts` | 配列 | いいえ | 割引の詳細リスト。 | | `products` | 配列 | はい | 返金対象のアイテム。製品プロパティテーブルを参照してください。 | | `source` | 文字列 | はい | イベントの発生元ソース。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア。認識されるサブプロパティ: `order_status_url`(文字列)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Order refunded event properties" } **製品プロパティ(`products[]`)** | プロパティ | データタイプ | 必須 | 説明 | | -------- | --------- | -------- | ----------- | | `product_id` | 文字列 | はい | 一意の製品識別子。 | | `product_name` | 文字列 | はい | 製品の表示名。 | | `variant_id` | 文字列 | はい | バリアント識別子。 | | `image_url` | 文字列 | いいえ | 製品画像のURL。 | | `product_url` | 文字列 | いいえ | 製品ページのURL。 | | `quantity` | Integer | はい | 返金された数量。 | | `price` | Float | はい | バリアント単価。 | | `metadata` | オブジェクト | いいえ | 柔軟なキーと値のペア(例: `color`や`size`)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Order refunded product properties" } ## Android Android SDK [42.3.0以降](https://github.com/braze-inc/braze-android-sdk/releases/tag/v42.3.0)では、構築時のクライアントサイドバリデーションと、`Braze.logEcommerceEvent`呼び出し時の自動`snake_case`シリアライゼーションを備えた型付きeコマースイベントクラスが提供されています。 | Androidクラス | イベント名 | 備考 | | ------------- | ---------- | ----- | | `ProductViewedEvent` | `ecommerce.product_viewed` | 製品フィールドを`properties`のトップレベルにフラット化します(`products`配列なし)。このクラスはカタログトリガー用のトップレベル`type`プロパティをサポートしていません。`type`が必要な場合は、[`logCustomEvent`](#manual-logging-with-logcustomevent)またはREST APIを使用してください。 | | `CartUpdatedEvent` | `ecommerce.cart_updated` | `action`プロパティには`CartUpdatedAction`(`ADD`、`REMOVE`、`REPLACE`)を使用します。 | | `CheckoutStartedEvent` | `ecommerce.checkout_started` | | | `OrderPlacedEvent` | `ecommerce.order_placed` | オプションの`cartId`、`totalDiscounts`、`discounts`をサポートしています。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Android SDK eCommerce event classes" } **Important:** `ecommerce.order_cancelled`と`ecommerce.order_refunded`は、型付きAndroid SDKクラスとして利用できません。[`logCustomEvent`](#manual-logging-with-logcustomevent)またはREST APIを使用して記録してください。 ### 共通のビルディングブロック {#shared-building-blocks} - `EcommerceProduct`: カート、チェックアウト、注文イベントのラインアイテムです。 - 必須: `productId`、`productName`、`variantId`、`price`、`quantity`(非負の`Long`) - オプション: `imageUrl`、`productUrl`、`metadata` - `BrazeProperties`: イベントレベルまたは製品レベルの`metadata`です。キーは先頭にドル記号($)のない、255文字以内の空でない文字列である必要があります。 ### クライアントサイドバリデーション {#client-side-validation} 無効なペイロードは、イベントクラスの構築時に`IllegalArgumentException`をスローするため、イベントはキューに入りません。一般的なルール: | フィールドまたはルール | バリデーション | | ------------ | ---------- | | 文字列IDおよび名前(`product_id`、`product_name`、`variant_id`、`cart_id`、`checkout_id`、`order_id`、`source`、オプションのURL) | 空白でないこと、最大255文字 | | `price`、`total_value`、`total_discounts` | `0`以上であること | | `currency` | 有効なISO 4217コード(SDKによりトリムされ大文字に変換されます) | | `products`(カート、チェックアウト、注文イベント) | 1つ以上の`EcommerceProduct` | | `quantity`(製品ごと) | 非負の整数 | {: .reset-td-br-1 .reset-td-br-2 aria-label="Android client-side validation rules for eCommerce events" } ディスパッチ時に、シリアライズされたプロパティがSDKのサイズ制限を超えた場合、`logEcommerceEvent`はエラーをログに記録し、イベントを送信しません。 ### コード例 {#code-examples} ```kotlin import com.braze.Braze import com.braze.models.outgoing.BrazeProperties import com.braze.models.recommended.ecommerce.ProductViewedEvent val metadata = BrazeProperties() .addProperty("sku", "SS-R-101") .addProperty("category", "Apparel") val productViewedEvent = ProductViewedEvent( productId = "PROD101", productName = "Silk Scarf", variantId = "SCARF_RED_SILK", price = 150.00, currency = "EUR", source = "https://braze-fashion.eu", imageUrl = "https://braze-fashion.eu/images/scarf_red.jpg", productUrl = "https://braze-fashion.eu/products/scarf", metadata = metadata, ) Braze.getInstance(context).logEcommerceEvent(productViewedEvent) ``` `CartUpdatedAction`を使用して`action`を設定します: | 値 | ワイヤー値 | 説明 | | ----- | ---------- | ----------- | | `CartUpdatedAction.ADD` | `add` | 数量を増やすか、ラインを追加します。 | | `CartUpdatedAction.REMOVE` | `remove` | 数量を減らします。`0`でラインを削除します。 | | `CartUpdatedAction.REPLACE` | `replace` | カート全体を置き換えます(デフォルト)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="CartUpdatedAction values for ecommerce.cart_updated" } ```kotlin import com.braze.Braze import com.braze.models.recommended.ecommerce.CartUpdatedAction import com.braze.models.recommended.ecommerce.CartUpdatedEvent import com.braze.models.recommended.ecommerce.EcommerceProduct val product = EcommerceProduct( productId = "SKU-RUN-4821", productName = "Ultraboost Running Shoe", variantId = "UB-BLK-11", price = 189.99, quantity = 1, ) val cartUpdatedEvent = CartUpdatedEvent( cartId = "cart_abc123", currency = "USD", source = "android", totalValue = 189.99, products = listOf(product), action = CartUpdatedAction.ADD, ) Braze.getInstance(context).logEcommerceEvent(cartUpdatedEvent) ``` ```kotlin import com.braze.Braze import com.braze.models.outgoing.BrazeProperties import com.braze.models.recommended.ecommerce.CheckoutStartedEvent import com.braze.models.recommended.ecommerce.EcommerceProduct val products = listOf( EcommerceProduct( productId = "SKU-RUN-4821", productName = "Ultraboost Running Shoe", variantId = "UB-BLK-11", price = 189.99, quantity = 1, ), ) val checkoutStartedEvent = CheckoutStartedEvent( checkoutId = "chk_88291", currency = "USD", source = "android", totalValue = 234.96, products = products, cartId = "cart_abc123", metadata = BrazeProperties().addProperty("checkout_url", "https://www.example.com/checkout/chk_88291"), ) Braze.getInstance(context).logEcommerceEvent(checkoutStartedEvent) ``` ```kotlin import com.braze.Braze import com.braze.models.outgoing.BrazeProperties import com.braze.models.recommended.ecommerce.EcommerceProduct import com.braze.models.recommended.ecommerce.OrderPlacedEvent val products = listOf( EcommerceProduct( productId = "SKU-RUN-4821", productName = "Ultraboost Running Shoe", variantId = "UB-BLK-11", price = 189.99, quantity = 1, ), ) val orderPlacedEvent = OrderPlacedEvent( orderId = "ord_77821", currency = "USD", source = "android", totalValue = 224.96, products = products, cartId = "cart_abc123", totalDiscounts = 10.0, discounts = listOf( mapOf("code" to "SPRING10", "amount" to 10.0, "type" to "percentage"), ), metadata = BrazeProperties().addProperty("order_status_url", "https://www.example.com/orders/ord_77821/status"), ) Braze.getInstance(context).logEcommerceEvent(orderPlacedEvent) ``` Brazeはこのイベント用の型付きSDKクラスを提供していません。`ecommerce.order_cancelled`イベントスキーマに一致するペイロードで`logCustomEvent`を使用してください。 ```kotlin import com.braze.Braze import com.braze.models.outgoing.BrazeProperties import org.json.JSONArray import org.json.JSONObject val properties = BrazeProperties( JSONObject() .put("order_id", "ord_77821") .put("total_value", 224.96) .put("currency", "USD") .put("cancel_reason", "customer_request") .put("source", "android") .put( "products", JSONArray().put( JSONObject() .put("product_id", "SKU-RUN-4821") .put("product_name", "Ultraboost Running Shoe") .put("variant_id", "UB-BLK-11") .put("quantity", 1) .put("price", 189.99), ), ), ) Braze.getInstance(context).logCustomEvent("ecommerce.order_cancelled", properties) ``` Brazeはこのイベント用の型付きSDKクラスを提供していません。`ecommerce.order_refunded`イベントスキーマに一致するペイロードで`logCustomEvent`を使用してください。 ```kotlin import com.braze.Braze import com.braze.models.outgoing.BrazeProperties import org.json.JSONArray import org.json.JSONObject val properties = BrazeProperties( JSONObject() .put("order_id", "ord_77821") .put("total_value", 189.99) .put("currency", "USD") .put("source", "android") .put( "products", JSONArray().put( JSONObject() .put("product_id", "SKU-RUN-4821") .put("product_name", "Ultraboost Running Shoe") .put("variant_id", "UB-BLK-11") .put("quantity", 1) .put("price", 189.99), ), ), ) Braze.getInstance(context).logCustomEvent("ecommerce.order_refunded", properties) ``` ```java import com.braze.Braze; import com.braze.models.outgoing.BrazeProperties; import com.braze.models.recommended.ecommerce.ProductViewedEvent; BrazeProperties metadata = new BrazeProperties() .addProperty("sku", "SS-R-101") .addProperty("category", "Apparel"); ProductViewedEvent productViewedEvent = new ProductViewedEvent( /* productId */ "PROD101", /* productName */ "Silk Scarf", /* variantId */ "SCARF_RED_SILK", /* price */ 150.00, /* currency */ "EUR", /* source */ "https://braze-fashion.eu", /* imageUrl */ "https://braze-fashion.eu/images/scarf_red.jpg", /* productUrl */ "https://braze-fashion.eu/products/scarf", /* metadata */ metadata ); Braze.getInstance(context).logEcommerceEvent(productViewedEvent); ``` `CartUpdatedAction`を使用して`action`を設定します: | 値 | ワイヤー値 | 説明 | | ----- | ---------- | ----------- | | `CartUpdatedAction.ADD` | `add` | 数量を増やすか、ラインを追加します。 | | `CartUpdatedAction.REMOVE` | `remove` | 数量を減らします。`0`でラインを削除します。 | | `CartUpdatedAction.REPLACE` | `replace` | カート全体を置き換えます(デフォルト)。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="CartUpdatedAction values for ecommerce.cart_updated" } ```java import com.braze.Braze; import com.braze.models.recommended.ecommerce.CartUpdatedAction; import com.braze.models.recommended.ecommerce.CartUpdatedEvent; import com.braze.models.recommended.ecommerce.EcommerceProduct; import java.util.Collections; EcommerceProduct product = new EcommerceProduct( /* productId */ "SKU-RUN-4821", /* productName */ "Ultraboost Running Shoe", /* variantId */ "UB-BLK-11", /* price */ 189.99, /* quantity */ 1 ); CartUpdatedEvent cartUpdatedEvent = new CartUpdatedEvent( /* cartId */ "cart_abc123", /* currency */ "USD", /* source */ "android", /* totalValue */ 189.99, /* products */ Collections.singletonList(product), /* metadata */ null, /* action */ CartUpdatedAction.ADD ); Braze.getInstance(context).logEcommerceEvent(cartUpdatedEvent); ``` ```java import com.braze.Braze; import com.braze.models.outgoing.BrazeProperties; import com.braze.models.recommended.ecommerce.CheckoutStartedEvent; import com.braze.models.recommended.ecommerce.EcommerceProduct; import java.util.Collections; EcommerceProduct product = new EcommerceProduct( /* productId */ "SKU-RUN-4821", /* productName */ "Ultraboost Running Shoe", /* variantId */ "UB-BLK-11", /* price */ 189.99, /* quantity */ 1 ); BrazeProperties metadata = new BrazeProperties() .addProperty("checkout_url", "https://www.example.com/checkout/chk_88291"); CheckoutStartedEvent checkoutStartedEvent = new CheckoutStartedEvent( /* checkoutId */ "chk_88291", /* currency */ "USD", /* source */ "android", /* totalValue */ 234.96, /* products */ Collections.singletonList(product), /* cartId */ "cart_abc123", /* metadata */ metadata ); Braze.getInstance(context).logEcommerceEvent(checkoutStartedEvent); ``` ```java import com.braze.Braze; import com.braze.models.outgoing.BrazeProperties; import com.braze.models.recommended.ecommerce.EcommerceProduct; import com.braze.models.recommended.ecommerce.OrderPlacedEvent; import java.util.Collections; EcommerceProduct product = new EcommerceProduct( /* productId */ "SKU-RUN-4821", /* productName */ "Ultraboost Running Shoe", /* variantId */ "UB-BLK-11", /* price */ 189.99, /* quantity */ 1 ); BrazeProperties metadata = new BrazeProperties() .addProperty("order_status_url", "https://www.example.com/orders/ord_77821/status"); OrderPlacedEvent orderPlacedEvent = new OrderPlacedEvent( /* orderId */ "ord_77821", /* currency */ "USD", /* source */ "android", /* totalValue */ 224.96, /* products */ Collections.singletonList(product), /* cartId */ "cart_abc123", /* totalDiscounts */ 10.0, /* discounts */ null, /* metadata */ metadata ); Braze.getInstance(context).logEcommerceEvent(orderPlacedEvent); ``` Brazeはこのイベント用の型付きSDKクラスを提供していません。`ecommerce.order_cancelled`イベントスキーマに一致するペイロードで`logCustomEvent`を使用してください。 ```java import com.braze.Braze; import com.braze.models.outgoing.BrazeProperties; import org.json.JSONArray; import org.json.JSONObject; Braze.getInstance(context).logCustomEvent( "ecommerce.order_cancelled", new BrazeProperties(new JSONObject() .put("order_id", "ord_77821") .put("total_value", 224.96) .put("currency", "USD") .put("cancel_reason", "customer_request") .put("source", "android") .put("products", new JSONArray() .put(new JSONObject() .put("product_id", "SKU-RUN-4821") .put("product_name", "Ultraboost Running Shoe") .put("variant_id", "UB-BLK-11") .put("quantity", 1) .put("price", 189.99))))); ``` Brazeはこのイベント用の型付きSDKクラスを提供していません。`ecommerce.order_refunded`イベントスキーマに一致するペイロードで`logCustomEvent`を使用してください。 ```java import com.braze.Braze; import com.braze.models.outgoing.BrazeProperties; import org.json.JSONArray; import org.json.JSONObject; Braze.getInstance(context).logCustomEvent( "ecommerce.order_refunded", new BrazeProperties(new JSONObject() .put("order_id", "ord_77821") .put("total_value", 189.99) .put("currency", "USD") .put("source", "android") .put("products", new JSONArray() .put(new JSONObject() .put("product_id", "SKU-RUN-4821") .put("product_name", "Ultraboost Running Shoe") .put("variant_id", "UB-BLK-11") .put("quantity", 1) .put("price", 189.99))))); ``` ## iOS Swift SDKは型付きeコマースイベントクラス(`ProductViewedEvent`、`CartUpdatedEvent`、`CheckoutStartedEvent`、`OrderPlacedEvent`)を提供しており、これらを構築して`logEcommerceEvent`に渡します。カート、チェックアウト、注文イベントの製品には`ProductLineItem`を使用します。各イニシャライザはスロー可能なため、`try?`でラップし、構築が成功した場合にのみイベントを記録してください。 これはSwift SDKバージョン`15.0.0`以降で利用可能です。 `ecommerce.order_cancelled`と`ecommerce.order_refunded`は、型付きSwift SDKクラスとして利用できません。`logCustomEvent`を使用して記録してください。 ### コード例 ```swift if let productViewedEvent = try? Braze.Ecommerce.ProductViewedEvent( productId: "4111176", productName: "Torchie runners", variantId: "4111176700", imageUrl: "https://braze-apparel.com/images/products/large/torchie-runners.jpg", productUrl: "https://braze-apparel.com/footwear-categories/sneakers/braze-orange-torchie-runners/", price: 85, currency: "GBP", source: "https://braze-apparel.com/", metadata: [ "sku": "", "color": "ORANGE", "size": "6", "brand": "Braze" ], typeIdentifiers: ["price_drop", "back_in_stock"] ) { AppDelegate.braze?.logEcommerceEvent(productViewedEvent) } ``` ```swift if let productLine = try? Braze.Ecommerce.ProductLineItem( productId: "8266836345064", productName: "Classic T-Shirt", variantId: "44610569208040", imageUrl: "https://braze-apparel.com/images/tshirt-blue-medium.jpg", productUrl: "https://braze-apparel.com/products/classic-tshirt?variant=44610569208040", quantity: 2, price: 99.99, metadata: [ "sku": "TSH-BLU-M", "color": "BLUE", "size": "Medium", "brand": "Braze" ] ), let cartUpdatedEvent = try? Braze.Ecommerce.CartUpdatedEvent( cartId: "cart_12345", totalValue: 199.98, currency: "USD", products: [productLine], source: "https://braze-apparel.com", metadata: [:] ) { AppDelegate.braze?.logEcommerceEvent(cartUpdatedEvent) } ``` ```swift if let productLine = try? Braze.Ecommerce.ProductLineItem( productId: "632910392", productName: "Wireless Headphones", variantId: "808950810", quantity: 1, price: 199.98, metadata: [ "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" ] ), let checkoutStartedEvent = try? Braze.Ecommerce.CheckoutStartedEvent( checkoutId: "checkout_abc123", cartId: "cart_12345", totalValue: 199.98, currency: "USD", products: [productLine], source: "https://braze-audio.com", metadata: [ "checkout_url": "https://checkout.braze-audio.com/abc123" ] ) { AppDelegate.braze?.logEcommerceEvent(checkoutStartedEvent) } ``` ```swift if let productLine = try? Braze.Ecommerce.ProductLineItem( productId: "632910392", productName: "Wireless Headphones", variantId: "808950810", quantity: 1, price: 199.98, metadata: [ "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" ] ), let orderPlacedEvent = try? Braze.Ecommerce.OrderPlacedEvent( orderId: "order_67890", cartId: "cart_12345", totalValue: 189.98, currency: "USD", totalDiscounts: 10.00, discounts: [.structured(code: "SAVE10", amount: 10.00, type: "fixed")], products: [productLine], source: "https://braze-audio.com", metadata: [ "order_status_url": "https://braze-audio.com/orders/67890/status", "order_number": "ORD-2024-001234", "tags": ["electronics", "audio"], "referring_site": "https://www.e-referrals.com", "payment_gateway_names": ["tap2pay", "dotcash"] ] ) { AppDelegate.braze?.logEcommerceEvent(orderPlacedEvent) } ``` Brazeはこのイベント用の型付きSDKクラスを提供していません。`ecommerce.order_cancelled`イベントスキーマに一致するペイロードで`logCustomEvent`を使用してください。 ```swift let discounts: [[String: Any]] = [ [ "code": "SAVE10", "amount": 10.00 ] ] let products: [[String: Any]] = [ [ "product_id": "632910392", "product_name": "Wireless Headphones", "variant_id": "808950810", "quantity": 1, "price": 199.98, "metadata": [ "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" ] ] ] let properties: [String: Any] = [ "order_id": "order_67890", "cancel_reason": "customer changed mind", "total_value": 189.98, "subtotal_value": 169.98, "tax": 14.40, "shipping": 5.60, "currency": "USD", "total_discounts": 10.00, "discounts": discounts, "products": products, "source": "https://braze-audio.com", "metadata": [ "order_status_url": "https://braze-audio.com/orders/67890/status", "order_number": "ORD-2024-001234", "tags": ["cancelled", "customer_request"] ] ] AppDelegate.braze?.logCustomEvent(name: "ecommerce.order_cancelled", properties: properties) ``` Brazeはこのイベント用の型付きSDKクラスを提供していません。`ecommerce.order_refunded`イベントスキーマに一致するペイロードで`logCustomEvent`を使用してください。 ```swift let discounts: [[String: Any]] = [ [ "code": "SAVE5", "amount": 5.00 ] ] let products: [[String: Any]] = [ [ "product_id": "632910392", "product_name": "Wireless Headphones", "variant_id": "808950810", "quantity": 1, "price": 99.99, "metadata": [ "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" ] ] ] let properties: [String: Any] = [ "order_id": "order_67890", "total_value": 99.99, "currency": "USD", "total_discounts": 5.00, "discounts": discounts, "products": products, "source": "https://braze-audio.com", "metadata": [ "order_status_url": "https://braze-audio.com/orders/67890/status", "order_note": "Customer requested refund due to defective item", "order_number": "ORD-2024-001234", "tags": ["refund", "defective"] ] ] AppDelegate.braze?.logCustomEvent(name: "ecommerce.order_refunded", properties: properties) ``` ## Web Web SDK [6.8.0以降](https://github.com/braze-inc/braze-web-sdk)では、イベントの`name`と`properties`を指定して`logEcommerceEvent`を呼び出します。レガシーSDKバージョンでは、イベント名とプロパティオブジェクトを指定して`logCustomEvent`を呼び出します。`ecommerce.order_cancelled`と`ecommerce.order_refunded`は`logCustomEvent`を使用します。 ### コード例 新しいSDKバージョンでは、`logEcommerceEvent()`を呼び出します: ```javascript braze.logEcommerceEvent({ "name": "ecommerce.product_viewed", "properties": { "product_id": "4111176", "product_name": "Torchie runners", "variant_id": "4111176700", "image_url": "https://braze-apparel.com/images/products/large/torchie-runners.jpg", "product_url": "https://braze-apparel.com/footwear-categories/sneakers/braze-orange-torchie-runners/", "price": 85, "currency": "GBP", "source": "https://braze-apparel.com/", "metadata": { "sku": "", "color": "ORANGE", "size": "6", "brand": "Braze" } } }); ``` レガシーSDKバージョンでは、`logCustomEvent()`を呼び出します: ```javascript braze.logCustomEvent("ecommerce.product_viewed", { "product_id": "4111176", "product_name": "Torchie runners", "variant_id": "4111176700", "image_url": "https://braze-apparel.com/images/products/large/torchie-runners.jpg", "product_url": "https://braze-apparel.com/footwear-categories/sneakers/braze-orange-torchie-runners/", "price": 85, "currency": "GBP", "source": "https://braze-apparel.com/", "metadata": { "sku": "", "color": "ORANGE", "size": "6", "brand": "Braze" } }); ``` 新しいSDKバージョンでは、`logEcommerceEvent()`を呼び出します: ```javascript braze.logEcommerceEvent({ "name": "ecommerce.cart_updated", "properties": { "cart_id": "cart_12345", "currency": "USD", "total_value": 199.98, "products": [ { "product_id": "8266836345064", "product_name": "Classic T-Shirt", "variant_id": "44610569208040", "image_url": "https://braze-apparel.com/images/tshirt-blue-medium.jpg", "product_url": "https://braze-apparel.com/products/classic-tshirt?variant=44610569208040", "quantity": 2, "price": 99.99, "metadata": { "sku": "TSH-BLU-M", "color": "BLUE", "size": "Medium", "brand": "Braze" } } ], "source": "https://braze-apparel.com", "metadata": {} } }); ``` レガシーSDKバージョンでは、`logCustomEvent()`を呼び出します: ```javascript braze.logCustomEvent("ecommerce.cart_updated", { "cart_id": "cart_12345", "currency": "USD", "total_value": 199.98, "subtotal_value": 179.98, "tax": 15.00, "shipping": 5.00, "products": [ { "product_id": "8266836345064", "product_name": "Classic T-Shirt", "variant_id": "44610569208040", "image_url": "https://braze-apparel.com/images/tshirt-blue-medium.jpg", "product_url": "https://braze-apparel.com/products/classic-tshirt?variant=44610569208040", "quantity": 2, "price": 99.99, "metadata": { "sku": "TSH-BLU-M", "color": "BLUE", "size": "Medium", "brand": "Braze" } } ], "source": "https://braze-apparel.com", "metadata": {} }); ``` 新しいSDKバージョンでは、`logEcommerceEvent()`を呼び出します: ```javascript braze.logEcommerceEvent({ "name": "ecommerce.checkout_started", "properties": { "checkout_id": "checkout_abc123", "cart_id": "cart_12345", "total_value": 199.98, "currency": "USD", "products": [ { "product_id": "632910392", "product_name": "Wireless Headphones", "variant_id": "808950810", "quantity": 1, "price": 199.98, "metadata": { "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" } } ], "source": "https://braze-audio.com", "metadata": { "checkout_url": "https://checkout.braze-audio.com/abc123" } } }); ``` レガシーSDKバージョンでは、`logCustomEvent()`を呼び出します: ```javascript braze.logCustomEvent("ecommerce.checkout_started", { "checkout_id": "checkout_abc123", "cart_id": "cart_12345", "total_value": 199.98, "subtotal_value": 179.98, "tax": 15.00, "shipping": 5.00, "currency": "USD", "products": [ { "product_id": "632910392", "product_name": "Wireless Headphones", "variant_id": "808950810", "quantity": 1, "price": 199.98, "metadata": { "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" } } ], "source": "https://braze-audio.com", "metadata": { "checkout_url": "https://checkout.braze-audio.com/abc123" } }); ``` 新しいSDKバージョンでは、`logEcommerceEvent()`を呼び出します: ```javascript braze.logEcommerceEvent({ "name": "ecommerce.order_placed", "properties": { "order_id": "order_67890", "cart_id": "cart_12345", "total_value": 189.98, "currency": "USD", "total_discounts": 10.00, "discounts": [ { "code": "SAVE10", "amount": 10.00 } ], "products": [ { "product_id": "632910392", "product_name": "Wireless Headphones", "variant_id": "808950810", "quantity": 1, "price": 199.98, "metadata": { "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" } } ], "source": "https://braze-audio.com", "metadata": { "order_status_url": "https://braze-audio.com/orders/67890/status", "order_number": "ORD-2024-001234", "tags": ["electronics", "audio"], "referring_site": "https://www.e-referrals.com", "payment_gateway_names": ["tap2pay", "dotcash"] } } }); ``` レガシーSDKバージョンでは、`logCustomEvent()`を呼び出します: ```javascript braze.logCustomEvent("ecommerce.order_placed", { "order_id": "order_67890", "cart_id": "cart_12345", "total_value": 189.98, "subtotal_value": 169.98, "tax": 14.40, "shipping": 5.60, "currency": "USD", "total_discounts": 10.00, "discounts": [ { "code": "SAVE10", "amount": 10.00 } ], "products": [ { "product_id": "632910392", "product_name": "Wireless Headphones", "variant_id": "808950810", "quantity": 1, "price": 199.98, "metadata": { "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" } } ], "source": "https://braze-audio.com", "metadata": { "order_status_url": "https://braze-audio.com/orders/67890/status", "order_number": "ORD-2024-001234", "tags": ["electronics", "audio"], "referring_site": "https://www.e-referrals.com", "payment_gateway_names": ["tap2pay", "dotcash"] } }); ``` ```javascript braze.logCustomEvent("ecommerce.order_cancelled", { "order_id": "order_67890", "cancel_reason": "customer changed mind", "total_value": 189.98, "subtotal_value": 169.98, "tax": 14.40, "shipping": 5.60, "currency": "USD", "total_discounts": 10.00, "discounts": [ { "code": "SAVE10", "amount": 10.00 } ], "products": [ { "product_id": "632910392", "product_name": "Wireless Headphones", "variant_id": "808950810", "quantity": 1, "price": 199.98, "metadata": { "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" } } ], "source": "https://braze-audio.com", "metadata": { "order_status_url": "https://braze-audio.com/orders/67890/status", "order_number": "ORD-2024-001234", "tags": ["cancelled", "customer_request"] } }); ``` ```javascript braze.logCustomEvent("ecommerce.order_refunded", { "order_id": "order_67890", "total_value": 99.99, "currency": "USD", "total_discounts": 5.00, "discounts": [ { "code": "SAVE5", "amount": 5.00 } ], "products": [ { "product_id": "632910392", "product_name": "Wireless Headphones", "variant_id": "808950810", "quantity": 1, "price": 99.99, "metadata": { "sku": "WH-BLK-PRO", "color": "Black", "brand": "BrazeAudio" } } ], "source": "https://braze-audio.com", "metadata": { "order_status_url": "https://braze-audio.com/orders/67890/status", "order_note": "Customer requested refund due to defective item", "order_number": "ORD-2024-001234", "tags": ["refund", "defective"] } }); ``` ## `logCustomEvent`を使用した手動記録 {#manual-logging-with-logcustomevent} 推奨イベントを手動で記録するには、正確なイベント名(例: `ecommerce.product_viewed`)と、手動で構築した`BrazeProperties`または`JSONObject`ペイロードを指定して`logCustomEvent`を呼び出します。SDKは手動呼び出しに対して推奨イベントスキーマのバリデーションを行いません。Brazeは取り込み時にこれらのペイロードをバリデーションします: - 有効なペイロードは、完全な後処理を伴う推奨イベントとして処理されます。 - 無効なペイロード(必須フィールドの欠落、型の不一致、余分なトップレベルプロパティ)は取り込み後に破棄されます。失敗はワークスペースのSDK処理ログおよび[失敗サマリーメール](https://www.braze.com/docs/ja/ja/user_guide/data/activation/events/recommended_events#find-failures)に表示されます。 無効なデータがアプリから送信される前にキャッチできるよう、可能な限り`logEcommerceEvent`を使用してください。一般的な`logCustomEvent`の使用方法については、[カスタムイベントの記録](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=android)を参照してください。 # Braze SDKを通じてコンテンツカードのデータを記録する Source: /docs/ja/developer_guide/analytics/logging_channel_data/content_cards/index.md # ログコンテンツカードのデータを記録する > When building a custom UI for Content Cards, you must manually log analytics like impressions, clicks, and dismissals, as this is only handled automatically for default card models. Logging these events is a standard part of a Content Card integration and is essential for accurate campaign reporting and billing. To do this, populate your custom UI with data from the Braze data models and then manually log the events. Once you understand how to log analytics, you can see common ways Braze customers [create custom Content Cards](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/creating_cards/). ## Logging analytics When implementing your custom Content Cards, you can parse the Content Card objects and extract their payload data such as `title`, `cardDescription`, and `imageUrl`. Then, you can use the resulting model data to populate your custom UI. To obtain the Content Card data models, subscribe to Content Card updates. There are two properties to pay particular attention to: * **`id`**: Represents the Content Card ID string. This is the unique identifier used to log analytics from custom Content Cards. * **`extras`**: Encompasses all the key-value pairs from the Braze dashboard. All properties outside of `id` and `extras` are optional to parse for custom Content Cards. For more information on the data model, see each platform's integration article: [Android](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/?sdktab=android), [iOS](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/?sdktab=swift), [Web](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/?sdktab=web). Register a callback function to subscribe for updates when cards are refreshed. ```javascript import * as braze from "@braze/web-sdk"; braze.subscribeToContentCardsUpdates((updates) => { const cards = updates.cards; // For example: cards.forEach(card => { if (card.isControl) { // Do not display the control card, but remember to call `logContentCardImpressions([card])` } else if (card instanceof braze.ClassicCard || card instanceof braze.CaptionedImage) { // Use `card.title`, `card.imageUrl`, etc. } else if (card instanceof braze.ImageOnly) { // Use `card.imageUrl`, etc. } }) }); braze.openSession(); ``` **Note:** Content Cards will only refresh on session start if a subscribe request is called before `openSession()`. You can always choose to [manually refresh the feed](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/customizing_cards/feed/) as well. ### Step 1: Create a private subscriber variable To subscribe to card updates, first declare a private variable in your custom class to hold your subscriber: ```java // subscriber variable private IEventSubscriber mContentCardsUpdatedSubscriber; ``` ### Step 2: Subscribe to updates Next, add the following code to subscribe to Content Card updates from Braze, typically inside of your custom Content Cards activity's `Activity.onCreate()`: ```java // Remove the previous subscriber before rebuilding a new one with our new activity. Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class); mContentCardsUpdatedSubscriber = new IEventSubscriber() { @Override public void trigger(ContentCardsUpdatedEvent event) { // List of all Content Cards List allCards = event.getAllCards(); // Your logic below } }; Braze.getInstance(context).subscribeToContentCardsUpdates(mContentCardsUpdatedSubscriber); Braze.getInstance(context).requestContentCardsRefresh(); ``` ### Step 3: Unsubscribe We also recommend unsubscribing when your custom activity moves out of view. Add the following code to your activity's `onDestroy()` lifecycle method: ```java Braze.getInstance(context).removeSingleSubscription(mContentCardsUpdatedSubscriber, ContentCardsUpdatedEvent.class); ``` ### Step 1: Create a private subscriber variable To subscribe to card updates, first declare a private variable in your custom class to hold your subscriber: ```kotlin private var contentCardsUpdatedSubscriber: IEventSubscriber? = null ``` ### Step 2: Subscribe to updates Next, add the following code to subscribe to Content Card updates from Braze, typically inside of your custom Content Cards activity's `Activity.onCreate()`: ```kotlin // Remove the previous subscriber before rebuilding a new one with our new activity. Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java) contentCardsUpdatedSubscriber = IEventSubscriber { event -> // List of all Content Cards val allCards = event.allCards // Your logic below } Braze.getInstance(context).subscribeToContentCardsUpdates(contentCardsUpdatedSubscriber) Braze.getInstance(context).requestContentCardsRefresh(true) ``` ### Step 3: Unsubscribe We also recommend unsubscribing when your custom activity moves out of view. Add the following code to your activity's `onDestroy()` lifecycle method: ```kotlin Braze.getInstance(context).removeSingleSubscription(contentCardsUpdatedSubscriber, ContentCardsUpdatedEvent::class.java) ``` To access the Content Cards data model, call [`contentCards.cards`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class/cards) on your `braze` instance. ```swift let cards: [Braze.ContentCard] = AppDelegate.braze?.contentCards.cards ``` Additionally, you can also maintain a subscription to observe for changes in your Content Cards. You can do so in one of two ways: 1. Maintaining a cancellable; or 2. Maintaining an `AsyncStream`. ### Cancellable ```swift // This subscription is maintained through a Braze cancellable, which will observe for changes until the subscription is cancelled. // You must keep a strong reference to the cancellable to keep the subscription active. // The subscription is canceled either when the cancellable is deinitialized or when you call its `.cancel()` method. let cancellable = AppDelegate.braze?.contentCards.subscribeToUpdates { [weak self] contentCards in // Implement your completion handler to respond to updates in `contentCards`. } ``` ### AsyncStream ```swift let stream: AsyncStream<[Braze.ContentCard]> = AppDelegate.braze?.contentCards.cardsStream ``` ```objc NSArray *contentCards = AppDelegate.braze.contentCards.cards; ``` Additionally, if you wish to maintain a subscription to your content cards, you can call [`subscribeToUpdates`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcards-swift.class/subscribetoupdates(_:)): ```objc // This subscription is maintained through Braze cancellable, which will continue to observe for changes until the subscription is cancelled. BRZCancellable *cancellable = [self.braze.contentCards subscribeToUpdates:^(NSArray *contentCards) { // Implement your completion handler to respond to updates in `contentCards`. }]; ``` To get the Content Card data, use the `getContentCards` method: ```javascript import Braze from "@braze/react-native-sdk"; const cards = await Braze.getContentCards(); ``` To listen for updates, subscribe to Content Card update events: ```javascript const subscription = Braze.addListener(Braze.Events.CONTENT_CARDS_UPDATED, (update) => { const cards = update.cards; cards.forEach(card => { if (card.isControl) { // Do not display the control card, but remember to log an impression } else { // Use card.title, card.cardDescription, card.image, etc. } }); }); ``` To request a manual refresh of Content Cards from Braze servers: ```javascript Braze.requestContentCardsRefresh(); ``` To get cached Content Cards without a network request: ```javascript const cachedCards = await Braze.getCachedContentCards(); ``` ## Logging events Logging valuable metrics like impressions, clicks, and dismissals is quick and simple. Set a custom click listener to manually handle these analytics. Log impression events when cards are viewed by users using [`logContentCardImpressions`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logcontentcardimpressions): ```javascript import * as braze from "@braze/web-sdk"; braze.logContentCardImpressions([card1, card2, card3]); ``` Log card click events when users interact with a card using [`logContentCardClick`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#logcontentcardclick): ```javascript import * as braze from "@braze/web-sdk"; braze.logContentCardClick(card); ``` The [`BrazeManager`](https://github.com/braze-inc/braze-growth-shares-android-demo-app/blob/main/app/src/main/java/com/braze/advancedsamples/BrazeManager.kt) can reference Braze SDK dependencies such as the Content Card objects array list to get the [`Card`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/index.html) to call the Braze logging methods. Use the `ContentCardable` base class to easily reference and provide data to the `BrazeManager`. To log an impression or click on a card, call [`Card.logClick()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/log-click.html) or [`Card.logImpression()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/log-impression.html) respectively. You can manually log or set a Content Card as "dismissed" to Braze for a particular card with [`isDismissed`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/is-dismissed.html). If a card is already marked as dismissed, it cannot be marked as dismissed again. To create a custom click listener, create a class that implements [`IContentCardsActionListener`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.listeners/-i-content-cards-action-listener/index.html) and register it with [`BrazeContentCardsManager`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.managers/-braze-content-cards-manager/index.html). Implement the [`onContentCardClicked()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.listeners/-i-content-cards-action-listener/on-content-card-clicked.html) method, which will be called when the user clicks a Content Card. Then, instruct Braze to use your Content Card click listener. For example: ```java BrazeContentCardsManager.getInstance().setContentCardsActionListener(new IContentCardsActionListener() { @Override public boolean onContentCardClicked(Context context, Card card, IAction cardAction) { return false; } @Override public void onContentCardDismissed(Context context, Card card) { } }); ``` For example: ```kotlin BrazeContentCardsManager.getInstance().contentCardsActionListener = object : IContentCardsActionListener { override fun onContentCardClicked(context: Context, card: Card, cardAction: IAction): Boolean { return false } override fun onContentCardDismissed(context: Context, card: Card) { } } ``` **Important:** To handle control variant Content Cards in your custom UI, pass in your [`com.braze.models.cards.Card`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.cards/-card/index.html) object, then call the `logImpression` method as you would with any other Content Card type. The object will implicitly log a control impression to inform our analytics of when a user would have seen the control card. Implement the [`BrazeContentCardUIViewControllerDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcarduiviewcontrollerdelegate) protocol and set your delegate object as the `delegate` property of your `BrazeContentCardUI.ViewController`. This delegate will handle passing the data of your custom object back to Braze to be logged. For an example, see [Content Cards UI tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/c2-contentcardsui/). ```swift // Set the delegate when creating the Content Cards controller contentCardsController.delegate = delegate // Method to implement in delegate func contentCard( _ controller: BrazeContentCardUI.ViewController, shouldProcess clickAction: Braze.ContentCard.ClickAction, card: Braze.ContentCard ) -> Bool { // Intercept the content card click action here. return true } ``` ```objc // Set the delegate when creating the Content Cards controller contentCardsController.delegate = delegate; // Method to implement in delegate - (BOOL)contentCardController:(BRZContentCardUIViewController *)controller shouldProcess:(NSURL *)url card:(BRZContentCardRaw *)card { // Intercept the content card click action here. return YES; } ``` **Important:** To handle control variant Content Cards in your custom UI, pass in your [`Braze.ContentCard.Control`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/contentcard/control(_:)) object, then call the `logImpression` method as you would with any other Content Card type. The object will implicitly log a control impression to inform our analytics of when a user would have seen the control card. Log impression events when cards are viewed by users: ```javascript Braze.logContentCardImpression(card.id); ``` Log card click events when users interact with a card: ```javascript Braze.logContentCardClicked(card.id); ``` Log dismissal events when a user dismisses a card: ```javascript Braze.logContentCardDismissed(card.id); ``` ## Handling on-click behavior When a user clicks a Content Card in a custom feed, the on-click behavior (such as navigating to a URL, deep linking, or logging a custom event) is not handled automatically. Use [`handleBrazeAction`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#handlebrazeaction) to process the card's URL and execute the configured on-click action, including Braze actions (`brazeActions://` URLs). ```javascript import * as braze from "@braze/web-sdk"; // In your card click handler function onCardClick(card) { // Log the click braze.logContentCardClick(card); // Handle the on-click behavior if (card.url) { braze.handleBrazeAction(card.url); } } ``` | Parameter | Description | |---|---| | `url` | A valid URL, or a valid Braze action URL with the scheme `brazeActions://`. | | `openLinkInNewTab` | (Optional) Whether the URL should open in a new tab. Defaults to `false`. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Handling on-click behavior" } **Important:** If you don't call `handleBrazeAction()`, on-click behaviors configured in the Braze dashboard (such as "Log Custom Event" or "Navigate to URL") won't execute for cards displayed in a custom feed. On-click behavior is handled automatically by the default Content Cards UI. For custom implementations, use the [`IContentCardsActionListener`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.ui.contentcards.listeners/-i-content-cards-action-listener/index.html) interface described in the [Logging analytics](#logging-analytics) section above. On-click behavior is handled automatically by the default Content Cards UI. For custom implementations, use the [`BrazeContentCardUIViewControllerDelegate`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazecontentcarduiviewcontrollerdelegate) protocol described in the [Logging analytics](#logging-analytics) section above. # Braze SDKを通じてアプリ内メッセージデータを記録する Source: /docs/ja/developer_guide/analytics/logging_channel_data/in_app_messages/index.md # アプリ内メッセージデータを記録する > Braze SDK を使用してアプリメッセージ(IAM) データにログインする方法について説明します。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=web). ## Logging message data Logging in-app message [impressions](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#loginappmessageimpression) and [clicks](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#loginappmessagebuttonclick) is performed automatically when you use the `showInAppMessage` or `automaticallyShowInAppMessage` method. If you do not use either method and opt to manually display the message using your own UI code, use the following methods to log analytics: ```javascript // Registers that a user has viewed an in-app message with the Braze server. braze.logInAppMessageImpression(inAppMessage); // Registers that a user has clicked on the specified in-app message with the Braze server. braze.logInAppMessageClick(inAppMessage); // Registers that a user has clicked a specified in-app message button with the Braze server. braze.logInAppMessageButtonClick(button, inAppMessage); // Registers that a user has clicked on a link in an HTML in-app message with the Braze server. braze.logInAppMessageHtmlClick(inAppMessage, buttonId?, url?) ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Flutter Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=flutter). ## Logging message data To log analytics using your `BrazeInAppMessage`, pass the instance into the desired analytics function: - `logInAppMessageClicked` - `logInAppMessageImpression` - `logInAppMessageButtonClicked` (along with the button index) For example: ```dart // Log a click braze.logInAppMessageClicked(inAppMessage); // Log an impression braze.logInAppMessageImpression(inAppMessage); // Log button index `0` being clicked braze.logInAppMessageButtonClicked(inAppMessage, 0); ``` ## Accessing message data To access in-app message data in your Flutter app, the `BrazePlugin` supports sending in-app message data using [Dart Streams](https://dart.dev/tutorials/language/streams). The `BrazeInAppMessage` object supports a subset of fields available in the native model objects, including `uri`, `message`, `header`, `buttons`, `extras`, and more. ### Listen for in-app message data in the Dart layer To receive in-app message data in the Dart layer, use the code below to create a `StreamSubscription` and call `braze.subscribeToInAppMessages()`. Remember to `cancel()` the stream subscription when it is no longer needed. ```dart // Create stream subscription StreamSubscription inAppMessageStreamSubscription; inAppMessageStreamSubscription = braze.subscribeToInAppMessages((BrazeInAppMessage inAppMessage) { // Handle in-app messages } // Cancel stream subscription inAppMessageStreamSubscription.cancel(); ``` For an example, see [main.dart](https://github.com/braze-inc/braze-flutter-sdk/blob/master/example/lib/main.dart) in the Braze Flutter SDK sample application. ### Forward in-app message data from the native layer In-app message data is automatically forwarded from both the Android and iOS native layers. No additional setup is required. If you're using Flutter SDK 17.1.0 or earlier, in-app message data forwarding from the iOS native layer requires manual setup. Your application likely contains one of the following. To migrate to Flutter SDK 18.0.0, remove the `BrazePlugin.processInAppMessage(_:)` call—data forwarding is now handled automatically. Remove the `BrazePlugin.processInAppMessage(_:)` call from your [`willPresent` delegate implementation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/inappmessage(_:willpresent:view:)-4pzvv). Remove the `BrazePlugin.processInAppMessage(message)` call from your custom presenter's [`present(message:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/present(message:)-f2ra) implementation: ```swift class CustomInAppMessagePresenter: BrazeInAppMessageUI { override func present(message: Braze.InAppMessage) { // Pass in-app message data to the Dart layer. BrazePlugin.processInAppMessage(message) // If you want the default UI to display the in-app message. super.present(message: message) } } ``` ### Replaying the callback for in-app messages (optional) To store any in-app messages triggered before the callback is available and replay them after it is set, add the following entry to the `customConfigs` map when initializing the `BrazePlugin`: ```dart BrazePlugin braze = new BrazePlugin(customConfigs: {replayCallbacksConfigKey: true}); ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Methods for logging You can use these methods by passing your `BrazeInAppMessage` instance to log analytics and perform actions: | Method | Description | | --------------------------------------------------------- | ------------------------------------------------------------------------------------- | | `logInAppMessageClicked(inAppMessage)` | Logs a click for the provided in-app message data. | | `logInAppMessageImpression(inAppMessage)` | Logs an impression for the provided in-app message data. | | `logInAppMessageButtonClicked(inAppMessage, buttonId)` | Logs a button click for the provided in-app message data and button ID. | | `hideCurrentInAppMessage()` | Dismisses the currently displayed in-app message. | | `performInAppMessageAction(inAppMessage)` | Performs the action for an in-app message. | | `performInAppMessageButtonAction(inAppMessage, buttonId)` | Performs the action for an in-app message button. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Methods for logging" } ## Handling message data In most cases, you can use the `Braze.addListener` method to register event listeners to handle data coming from in-app messages. Additionally, you can access the in-app message data in the JavaScript layer by calling the `Braze.subscribeToInAppMessage` method to have the SDKs publish an `inAppMessageReceived` event when an in-app message is triggered. Pass a callback to this method to execute your own code when the in-app message is triggered and received by the listener. To customize how message data is handled, refer to the following implementation examples: To enhance the default behavior, or if you don't have access to customize the native iOS or Android code, we recommend that you disable the default UI while still receiving in-app message events from Braze. To disable the default UI, pass `false` to the `Braze.subscribeToInAppMessage` method and use the in-app message data to construct your own message in JavaScript. Note that you will need to manually log analytics on your messages if you choose to disable the default UI. ```javascript import Braze from "@braze/react-native-sdk"; // Option 1: Listen for the event directly via `Braze.addListener`. // // You may use this method to accomplish the same thing if you don't // wish to make any changes to the default Braze UI. Braze.addListener(Braze.Events.IN_APP_MESSAGE_RECEIVED, (event) => { console.log(event.inAppMessage); }); // Option 2: Call `subscribeToInAppMessage`. // // Pass in `false` to disable the automatic display of in-app messages. Braze.subscribeToInAppMessage(false, (event) => { console.log(event.inAppMessage); // Use `event.inAppMessage` to construct your own custom message UI. }); ``` To include more advanced logic to determine whether or not to show an in-app message using the built-in UI, implement in-app messages through the native layer. **Warning:** Since this is an advanced customization option, note that overriding the default Braze implementation will also nullify the logic to emit in-app message events to your JavaScript listeners. If you wish to still use `Braze.subscribeToInAppMessage` or `Braze.addListener` as described in [Accessing in-app message data](#accessing-in-app-message-data), you will need to handle publishing the events yourself. Implement the `IInAppMessageManagerListener` as described in our Android article on [Custom Manager Listener](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/customization/?sdktab=android#android_setting-custom-manager-listeners). In your `beforeInAppMessageDisplayed` implementation, you can access the `inAppMessage` data, send it to the JavaScript layer, and decide to show or not show the native message based on the return value. For more on these values, see our [Android documentation](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages/). ```java // In-app messaging @Override public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessage) { WritableMap parameters = new WritableNativeMap(); parameters.putString("inAppMessage", inAppMessage.forJsonPut().toString()); getReactNativeHost() .getReactInstanceManager() .getCurrentReactContext() .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit("inAppMessageReceived", parameters); // Note: return InAppMessageOperation.DISCARD if you would like // to prevent the Braze SDK from displaying the message natively. return InAppMessageOperation.DISPLAY_NOW; } ``` ### Overriding the default UI delegate By default, [`BrazeInAppMessageUI`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageui/) is created and assigned when you initialize the `braze` instance. `BrazeInAppMessageUI` is an implementation of the [`BrazeInAppMessagePresenter`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazeinappmessagepresenter) protocol and comes with a `delegate` property that can be used to customize the handling of in-app messages that have been received. 1. Implement the `BrazeInAppMessageUIDelegate` delegate as described in [our iOS article here](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/c1-inappmessageui). 2. In the `inAppMessage(_:displayChoiceForMessage:)` delegate method, you can access the `inAppMessage` data, send it to the JavaScript layer, and decide to show or not show the native message based on the return value. For more details on these values, see our [iOS documentation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazeui/brazeinappmessageuidelegate/). ```objc - (enum BRZInAppMessageUIDisplayChoice)inAppMessage:(BrazeInAppMessageUI *)ui displayChoiceForMessage:(BRZInAppMessageRaw *)message { // Convert the message to a JavaScript representation. NSData *inAppMessageData = [message json]; NSString *inAppMessageString = [[NSString alloc] initWithData:inAppMessageData encoding:NSUTF8StringEncoding]; NSDictionary *arguments = @{ @"inAppMessage" : inAppMessageString }; // Send to JavaScript. [self sendEventWithName:@"inAppMessageReceived" body:arguments]; // Note: Return `BRZInAppMessageUIDisplayChoiceDiscard` if you would like // to prevent the Braze SDK from displaying the message natively. return BRZInAppMessageUIDisplayChoiceNow; } ``` To use this delegate, assign it to `brazeInAppMessagePresenter.delegate` after initializing the `braze` instance. **Note:** `BrazeUI` can only be imported in Objective-C or Swift. If you are using Objective-C++, you will need to handle this in a separate file. ```objc @import BrazeUI; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:apiKey endpoint:endpoint]; Braze *braze = [BrazeReactBridge initBraze:configuration]; ((BrazeInAppMessageUI *)braze.inAppMessagePresenter).delegate = [[CustomDelegate alloc] init]; AppDelegate.braze = braze; } ``` ### Overriding the default native UI If you wish to fully customize the presentation of your in-app messages at the native iOS layer, conform to the [`BrazeInAppMessagePresenter`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazeinappmessagepresenter) protocol and assign your custom presenter following the sample below: ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:apiKey endpoint:endpoint]; Braze *braze = [BrazeReactBridge initBraze:configuration]; braze.inAppMessagePresenter = [[MyCustomPresenter alloc] init]; AppDelegate.braze = braze; ``` ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Logging message data You will need to make sure certain functions are called to handle the analytics for your campaign. ### Displayed messages When a message is displayed or seen, log an impression: ```brightscript LogInAppMessageImpression(in_app_message.id, brazetask) ``` ### Clicked messages Once a user clicks on the message, log a click and then process `in_app_message.click_action`: ```brightscript LogInAppMessageClick(in_app_message.id, brazetask) ``` ### Clicked buttons If the user clicks on a button, log the button click and then process `inappmessage.buttons[selected].click_action`: ```brightscript LogInAppMessageButtonClick(inappmessage.id, inappmessage.buttons[selected].id, brazetask) ``` ### After processing a message After processing an in-app message, you should clear the field: ```brightscript m.BrazeTask.BrazeInAppMessage = invalid ``` ## Subscribing to in-app messages You may register Unity game objects to be notified of incoming in-app messages. We recommend setting game object listeners from the Braze configuration editor. In the configuration editor, listeners must be set separately for Android and iOS. If you need to configure your game object listener at runtime, use `AppboyBinding.ConfigureListener()` and specify `BrazeUnityMessageType.IN_APP_MESSAGE`. ## Parsing messages Incoming `string` messages received in your in-app message game object callback can be parsed into our pre-supplied model objects for convenience. Use `InAppMessageFactory.BuildInAppMessage()` to parse your in-app message. The resulting object will either be an instance of [`IInAppMessage.cs`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/IInAppMessage.cs) or [`IInAppMessageImmersive.cs`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/IInAppMessageImmersive.cs) depending on its type. ```csharp // Automatically logs a button click, if present. void InAppMessageReceivedCallback(string message) { IInAppMessage inApp = InAppMessageFactory.BuildInAppMessage(message); if (inApp is IInAppMessageImmersive) { IInAppMessageImmersive inAppImmersive = inApp as IInAppMessageImmersive; if (inAppImmersive.Buttons != null && inAppImmersive.Buttons.Count > 0) { inAppImmersive.LogButtonClicked(inAppImmersive.Buttons[0].ButtonID); } } } ``` ## Logging message data Clicks and impressions must be manually logged for in-app messages not displayed directly by Braze. Use `LogClicked()` and `LogImpression()` on [`IInAppMessage`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/IInAppMessage.cs) to log clicks and impressions on your message. Use `LogButtonClicked(int buttonID)` on [`IInAppMessageImmersive`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/IInAppMessageImmersive.cs) to log button clicks. Note that buttons are represented as lists of[`InAppMessageButton`](https://github.com/braze-inc/braze-unity-sdk/blob/18cb8ee89f1841c576eb954793edb6e06f9130b4/Assets/Plugins/Appboy/Models/InAppMessage/InAppMessageButton.cs) instances, each of which contains a `ButtonID`. # Braze SDKを通じてプッシュ通知データをログに記録する Source: /docs/ja/developer_guide/analytics/logging_channel_data/push_notifications/index.md # プッシュ通知データを記録する > Braze SDKを通してプッシュ通知データを記録する方法を学習する。 ## Logging data with the Braze API (recommended) You can log analytics in real-time by making calls to the [`/users/track` endpoint](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track/). To log analytics, send the `braze_id` value from the Braze dashboard to identify which user profile to update. ![Personalized Push dashboard Example](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/android_braze_id_configuration.png?0cc22cde8cd194e7755f83b13d273806){: style="max-width:79%;"} ## Manually logging data Depending on the details of your payload, you can log analytics manually within your `FirebaseMessagingService.onMessageReceived` implementation or your startup activity. Keep in mind, your `FirebaseMessagingService` subclass must finish execution within 9 seconds of invocation to avoid being [flagged or terminated](https://firebase.google.com/docs/cloud-messaging/android/receive) by the Android system. ## Logging data with the Braze API (recommended) Logging analytics can be done in real-time with the help of the Braze API [`/users/track` endpoint](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track/). To log analytics, send down the `braze_id` value in the key-value pairs field (as seen in the following screenshot) to identify which user profile to update. ![A push message with three sets of key-value pairs. 1. "Braze_id" set as a Liquid call to retrieve Braze ID. 2. "cert_title" set as "Braze Marketer Certification". 3. "Cert_description" set as "Certified Braze marketers drive...".](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push18.png?ae37ef2a75d3afb0525cc480263728d7){: style="max-width:80%;"} ## Logging data manually Logging manually will require you to first configure workspaces within Xcode, and then create, save, and retrieve analytics. This will require some custom developer work on your end. The following code snippets shown will help address this. It's important to note that analytics are not sent to Braze until the mobile application is subsequently launched. This means that, depending on your dismissal settings, there often exists an indeterminate period of time between when a push notification is dismissed and the mobile app is launched and the analytics are retrieved. While this time buffer may not affect all use cases, you should consider this impact adjust your user journey as necessary to include opening the application to address this concern. ![A graphic describing how analytics are processed in Braze. 1. Analytics data is created. 2. Analytics data is saved. 3. Push notification is dismissed. 4. Indeterminate period of time between when push notification is dismissed and mobile app is launched. 5. Mobile app is launched. 6. Analytics data is received. 7. Analytics data is sent to Braze.](https://www.braze.com/docs/ja/ja/assets/img/push_implementation_guide/push13.png?817f7603e474002aae9a3b25bccd81bb) ### Step 1: Configure app groups within Xcode In Xcode, add the `App Groups` capability. If you haven’t had any workspaces in your app, go to the capability of the main app target, turn on the `App Groups`, and click the **+** Add button. Then, use your app’s bundle ID to create the workspace. For example, if your app’s bundle ID is `com.company.appname`, you can name your workspace `group.com.company.appname.xyz`. Make sure the `App Groups` are turned on for both your main app target and the content extension target. ![](https://www.braze.com/docs/ja/ja/assets/img/swift/push_story/add_app_groups.png?44e3d92af533e6323db33236364b99e1) ### Step 2: Integrate code snippets The following code snippets are a helpful reference on how to save and send custom events, custom attributes, and user attributes. This guide will be speaking in terms of `UserDefaults`, but the code representation will be in the form of the helper file `RemoteStorage`. There are additional helper files, `UserAttributes` and `EventName Dictionary`, that are used when sending and saving user attributes. #### Saving custom events To save custom events, you must create the analytics from scratch. This is done by creating a dictionary, populating it with metadata, and saving the data through the use of a helper file. 1. Initialize a dictionary with event metadata 2. Initialize `userDefaults` to retrieve and store the event data 3. If there is an existing array, append new data to the existing array and save 4. If there is not an existing array, save the new array to `userDefaults` ``` swift func saveCustomEvent(with properties: [String: Any]? = nil) { // 1 let customEventDictionary = Dictionary(eventName: "YOUR-EVENT-NAME", properties: properties) // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] { pendingEvents.append(contentsOf: [customEventDictionary]) remoteStorage.store(pendingEvents, forKey: .pendingCustomEvents) } else { // 4 remoteStorage.store([customEventDictionary], forKey: .pendingCustomEvents) } } ``` ```objc - (void)saveCustomEvent:(NSDictionary *)properties { // 1 NSDictionary *customEventDictionary = [[NSDictionary alloc] initWithEventName:@"YOUR-EVENT-NAME" properties:properties]; // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingEvents = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents] mutableCopy]; // 3 if (pendingEvents) { [pendingEvents addObject:customEventDictionary]; [remoteStorage store:pendingEvents forKey:RemoteStorageKeyPendingCustomAttributes]; } else { // 4 [remoteStorage store:@[ customEventDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes]; } } ``` #### Sending custom events to Braze The best time to log any saved analytics from a notification content app extension is right after the SDK is initialized. This can be done by looping through any pending events, checking for the "Event Name" key, setting the appropriate values in Braze, and then clearing the storage for the next time this function is needed. 1. Loop through the array of pending events 2. Loop through each key-value pair in the `pendingEvents` dictionary 3. Explicitly check the key for “Event Name” to set the value accordingly 4. Every other key-value will be added to the `properties` dictionary 5. Log individual custom event 6. Remove all pending events from storage ``` swift func logPendingCustomEventsIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingEvents = remoteStorage.retrieve(forKey: .pendingCustomEvents) as? [[String: Any]] else { return } // 1 for event in pendingEvents { var eventName: String? var properties: [AnyHashable: Any] = [:] // 2 for (key, value) in event { if key == PushNotificationKey.eventName.rawValue { // 3 if let eventNameValue = value as? String { eventName = eventNameValue } else { print("Invalid type for event_name key") } } else { // 4 properties[key] = value } } // 5 if let eventName = eventName { AppDelegate.braze?.logCustomEvent(eventName, properties: properties) } } // 6 remoteStorage.removeObject(forKey: .pendingCustomEvents) } ``` ```objc - (void)logPendingEventsIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingEvents = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomEvents]; // 1 for (NSDictionary *event in pendingEvents) { NSString *eventName = nil; NSMutableDictionary *properties = [NSMutableDictionary dictionary]; // 2 for (NSString* key in event) { if ([key isEqualToString:@"event_name"]) { // 3 if ([[event objectForKey:key] isKindOfClass:[NSString class]]) { eventName = [event objectForKey:key]; } else { NSLog(@"Invalid type for event_name key"); } } else { // 4 properties[key] = event[key]; } } // 5 if (eventName != nil) { [AppDelegate.braze logCustomEvent:eventName properties:properties]; } } // 6 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomEvents]; } ``` #### Saving custom attributes To save custom attributes, you must create the analytics from scratch. This is done by creating a dictionary, populating it with metadata, and saving the data through the use of a helper file. 1. Initialize a dictionary with attribute metadata 2. Initialize `userDefaults` to retrieve and store the attribute data 3. If there is an existing array, append new data to the existing array and save 4. If there is not an existing array, save the new array to `userDefaults` ``` swift func saveCustomAttribute() { // 1 let customAttributeDictionary: [String: Any] = ["YOUR-CUSTOM-ATTRIBUTE-KEY": "YOUR-CUSTOM-ATTRIBUTE-VALUE"] // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] { pendingAttributes.append(contentsOf: [customAttributeDictionary]) remoteStorage.store(pendingAttributes, forKey: .pendingCustomAttributes) } else { // 4 remoteStorage.store([customAttributeDictionary], forKey: .pendingCustomAttributes) } } ``` ``` objc - (void)saveCustomAttribute { // 1 NSDictionary *customAttributeDictionary = @{ @"YOUR-CUSTOM-ATTRIBUTE-KEY": @"YOUR-CUSTOM-ATTRIBUTE-VALUE" }; // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes] mutableCopy]; // 3 if (pendingAttributes) { [pendingAttributes addObject:customAttributeDictionary]; [remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingCustomAttributes]; } else { // 4 [remoteStorage store:@[ customAttributeDictionary ] forKey:RemoteStorageKeyPendingCustomAttributes]; } } ``` #### Sending custom attributes to Braze The best time to log any saved analytics from a notification content app extension is right after the SDK is initialized. This can be done by looping through the pending attributes, setting the appropriate custom attribute in Braze, and then clearing the storage for the next time this function is needed. 1. Loop through the array of pending attributes 2. Loop through each key-value pair in the `pendingAttributes` dictionary 3. Log individual custom attributes with corresponding key and value 4. Remove all pending attributes from storage ``` swift func logPendingCustomAttributesIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingCustomAttributes) as? [[String: Any]] else { return } // 1 pendingAttributes.forEach { setCustomAttributesWith(keysAndValues: $0) } // 4 remoteStorage.removeObject(forKey: .pendingCustomAttributes) } func setCustomAttributesWith(keysAndValues: [String: Any]) { // 2 for (key, value) in keysAndValues { // 3 if let value = value as? [String] { setCustomAttributeArrayWithKey(key, andValue: value) } else { setCustomAttributeWithKey(key, andValue: value) } } } ``` ```objc - (void)logPendingCustomAttributesIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingCustomAttributes]; // 1 for (NSDictionary *attribute in pendingAttributes) { [self setCustomAttributeWith:attribute]; } // 4 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingCustomAttributes]; } - (void)setCustomAttributeWith:(NSDictionary *)keysAndValues { // 2 for (NSString *key in keysAndValues) { // 3 [self setCustomAttributeWith:key andValue:[keysAndValues objectForKey:key]]; } } ``` #### Saving user attributes When saving user attributes, we recommend creating a custom object to decipher what type of attribute is being updated (`email`, `first_name`, `phone_number`, etc.). The object should be compatible with being stored/retrieved from `UserDefaults`. See the `UserAttribute` helper file for one example of how to accomplish this. 1. Initialize an encoded `UserAttribute` object with the corresponding type 2. Initialize `userDefaults` to retrieve and store the event data 3. If there is an existing array, append new data to the existing array and save 4. If there is not an existing array, save the new array to `userDefaults` ``` swift func saveUserAttribute() { // 1 guard let data = try? PropertyListEncoder().encode(UserAttribute.userAttributeType("USER-ATTRIBUTE-VALUE")) else { return } // 2 let remoteStorage = RemoteStorage(storageType: .suite) // 3 if var pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] { pendingAttributes.append(contentsOf: [data]) remoteStorage.store(pendingAttributes, forKey: .pendingUserAttributes) } else { // 4 remoteStorage.store([data], forKey: .pendingUserAttributes) } } ``` ```objc - (void)saveUserAttribute { // 1 UserAttribute *userAttribute = [[UserAttribute alloc] initWithUserField:@"USER-ATTRIBUTE-VALUE" attributeType:UserAttributeTypeEmail]; NSError *error; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:userAttribute requiringSecureCoding:YES error:&error]; if (error != nil) { // log error } // 2 RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSMutableArray *pendingAttributes = [[remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes] mutableCopy]; // 3 if (pendingAttributes) { [pendingAttributes addObject:data]; [remoteStorage store:pendingAttributes forKey:RemoteStorageKeyPendingUserAttributes]; } else { // 4 [remoteStorage store:@[data] forKey:RemoteStorageKeyPendingUserAttributes]; } } ``` #### Sending user attributes to Braze The best time to log any saved analytics from a notification content app extension is right after the SDK is initialized. This can be done by looping through the pending attributes, setting the appropriate custom attribute in Braze, and then clearing the storage for the next time this function is needed. 1. Loop through the array of `pendingAttributes` data 2. Initialize an encoded `UserAttribute` object from attribute data 3. Set specific user field based on the User Attribute type (email) 4. Remove all pending user attributes from storage ``` swift func logPendingUserAttributesIfNecessary() { let remoteStorage = RemoteStorage(storageType: .suite) guard let pendingAttributes = remoteStorage.retrieve(forKey: .pendingUserAttributes) as? [Data] else { return } // 1 for attributeData in pendingAttributes { // 2 guard let userAttribute = try? PropertyListDecoder().decode(UserAttribute.self, from: attributeData) else { continue } // 3 switch userAttribute { case .email(let email): user?.email = email } } // 4 remoteStorage.removeObject(forKey: .pendingUserAttributes) } ``` ```objc - (void)logPendingUserAttributesIfNecessary { RemoteStorage *remoteStorage = [[RemoteStorage alloc] initWithStorageType:StorageTypeSuite]; NSArray *pendingAttributes = [remoteStorage retrieveForKey:RemoteStorageKeyPendingUserAttributes]; // 1 for (NSData *attributeData in pendingAttributes) { NSError *error; // 2 UserAttribute *userAttribute = [NSKeyedUnarchiver unarchivedObjectOfClass:[UserAttribute class] fromData:attributeData error:&error]; if (error != nil) { // log error } // 3 if (userAttribute) { switch (userAttribute.attributeType) { case UserAttributeTypeEmail: [self user].email = userAttribute.userField; break; } } } // 4 [remoteStorage removeObjectForKey:RemoteStorageKeyPendingUserAttributes]; } ``` #### Helper files **RemoteStorage Helper File** ```swift enum RemoteStorageKey: String, CaseIterable { // MARK: - Notification Content Extension Analytics case pendingCustomEvents = "pending_custom_events" case pendingCustomAttributes = "pending_custom_attributes" case pendingUserAttributes = "pending_user_attributes" } enum RemoteStorageType { case standard case suite } class RemoteStorage: NSObject { private var storageType: RemoteStorageType = .standard private lazy var defaults: UserDefaults = { switch storageType { case .standard: return .standard case .suite: return UserDefaults(suiteName: "YOUR-DOMAIN-IDENTIFIER")! } }() init(storageType: RemoteStorageType = .standard) { self.storageType = storageType } func store(_ value: Any, forKey key: RemoteStorageKey) { defaults.set(value, forKey: key.rawValue) } func retrieve(forKey key: RemoteStorageKey) -> Any? { return defaults.object(forKey: key.rawValue) } func removeObject(forKey key: RemoteStorageKey) { defaults.removeObject(forKey: key.rawValue) } func resetStorageKeys() { for key in RemoteStorageKey.allCases { defaults.removeObject(forKey: key.rawValue) } } } ``` ```objc @interface RemoteStorage () @property (nonatomic) StorageType storageType; @property (nonatomic, strong) NSUserDefaults *defaults; @end @implementation RemoteStorage - (id)initWithStorageType:(StorageType)storageType { if (self = [super init]) { self.storageType = storageType; } return self; } - (void)store:(id)value forKey:(RemoteStorageKey)key { [[self defaults] setValue:value forKey:[self rawValueForKey:key]]; } - (id)retrieveForKey:(RemoteStorageKey)key { return [[self defaults] objectForKey:[self rawValueForKey:key]]; } - (void)removeObjectForKey:(RemoteStorageKey)key { [[self defaults] removeObjectForKey:[self rawValueForKey:key]]; } - (void)resetStorageKeys { [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomEvents]]; [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingCustomAttributes]]; [[self defaults] removeObjectForKey:[self rawValueForKey:RemoteStorageKeyPendingUserAttributes]]; } - (NSUserDefaults *)defaults { if (!self.defaults) { switch (self.storageType) { case StorageTypeStandard: return [NSUserDefaults standardUserDefaults]; break; case StorageTypeSuite: return [[NSUserDefaults alloc] initWithSuiteName:@"YOUR-DOMAIN-IDENTIFIER"]; } } else { return self.defaults; } } - (NSString*)rawValueForKey:(RemoteStorageKey)remoteStorageKey { switch(remoteStorageKey) { case RemoteStorageKeyPendingCustomEvents: return @"pending_custom_events"; case RemoteStorageKeyPendingCustomAttributes: return @"pending_custom_attributes"; case RemoteStorageKeyPendingUserAttributes: return @"pending_user_attributes"; default: [NSException raise:NSGenericException format:@"Unexpected FormatType."]; } } ``` **UserAttribute Helper File** ```swift enum UserAttribute: Hashable { case email(String?) } // MARK: - Codable extension UserAttribute: Codable { private enum CodingKeys: String, CodingKey { case email } func encode(to encoder: Encoder) throws { var values = encoder.container(keyedBy: CodingKeys.self) switch self { case .email(let email): try values.encode(email, forKey: .email) } } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) let email = try values.decode(String.self, forKey: .email) self = .email(email) } } ``` ```objc @implementation UserAttribute - (id)initWithUserField:(NSString *)userField attributeType:(UserAttributeType)attributeType { if (self = [super init]) { self.userField = userField; self.attributeType = attributeType; } return self; } - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.userField forKey:@"userField"]; [encoder encodeInteger:self.attributeType forKey:@"attributeType"]; } - (id)initWithCoder:(NSCoder *)decoder { if (self = [super init]) { self.userField = [decoder decodeObjectForKey:@"userField"]; NSInteger attributeRawValue = [decoder decodeIntegerForKey:@"attributeType"]; self.attributeType = (UserAttributeType) attributeRawValue; } return self; } @end ``` **EventName Dictionary Helper File** ```swift extension Dictionary where Key == String, Value == Any { init(eventName: String, properties: [String: Any]? = nil) { self.init() self[PushNotificationKey.eventName.rawValue] = eventName if let properties = properties { for (key, value) in properties { self[key] = value } } } } ``` ```objc @implementation NSDictionary (Helper) - (id)initWithEventName:(NSString *)eventName properties:(NSDictionary *)properties { self = [self init]; if (self) { dict[@"event_name"] = eventName; for(id key in properties) { dict[key] = properties[key]; } } return self; } @end ```
# Braze SDKを通じてセッションのトラッキングを行う Source: /docs/ja/developer_guide/analytics/tracking_sessions/index.md # トラックセッション {#track-sessions} > Braze SDKを使用してセッションを追跡する方法について説明します。 **Note:** リストされていないラッパーSDKの場合は、代わりに関連するネイティブAndroidまたはSwiftメソッドを使用してください。 ## About the session lifecycle A session refers to the period of time the Braze SDK tracks user activity in your app after it's launched. You can also force a new session by [calling the `changeUser()` method](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_ids/#setting-a-user-id). By default, a session starts when you first call `braze.openSession()`. The session will remain active for up to `30` minutes of inactivity (unless you [change the default session timeout](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions/?tab=web#change-session-timeout) or the user closes the app. **Note:** If you've set up the [activity lifecycle callback](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/initial_sdk_setup/android_sdk_integration/#step-4-tracking-user-sessions-in-android) for Android, Braze will automatically call [`openSession()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/open-session.html) and [`closeSession()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/close-session.html) for each activity in your app. By default, a session starts when `openSession()` is first called. If your app goes to the background and then returns to the foreground, the SDK will check if more than 10 seconds have passed since the session started (unless you [change the default session timeout](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions/?tab=android#change-session-timeout)). If so, a new session will begin. Keep in mind that if the user closes your app while it's in the background, session data may not be sent to Braze until they reopen the app. Calling `closeSession()` will not immediately end the session. Instead, it will end the session after 10 seconds if `openSession()` isn't called again by the user starting another activity. By default, a session starts when you call `Braze.init(configuration:)`. This occurs when the `UIApplicationWillEnterForegroundNotification` notification is triggered, meaning the app has entered the foreground. If your app goes to the background, `UIApplicationDidEnterBackgroundNotification` is triggered. The app does not remain in an active session while in the background. When your app returns to the foreground, the SDK compares the time elapsed since the session started against the session timeout (unless you [change the default session timeout](https://www.braze.com/docs/ja/ja/developer_guide/analytics/tracking_sessions/?tab=swift#change-session-timeout)). If the time since the session started exceeds the timeout period, a new session begins. ## 非アクティブ状態の定義 {#defining-inactivity} Web SDKでセッションライフサイクルを効果的に管理するには、非アクティブ状態の定義と測定方法を理解することが重要です。非アクティブ状態とは、Braze Web SDKがユーザーからのトラッキングイベントを一切検出しない期間を指します。 ### 非アクティブ状態の測定方法 {#how-inactivity-is-measured} Web SDKは[SDKがトラッキングするイベント](https://www.braze.com/docs/ja/ja/user_guide/data/activation/custom_data/events#events)に基づいて非アクティブ状態を追跡します。SDKは内部タイマーを維持しており、トラッキング対象のイベントが送信されるたびにリセットされます。設定されたタイムアウト期間内にSDKがトラッキングするイベントが発生しない場合、セッションは非アクティブと見なされ終了します。 Web SDKにおけるセッションライフサイクルの実装方法の詳細については、[Braze Web SDK GitHubリポジトリ](https://github.com/braze-inc/braze-web-sdk/blob/master/src/session.ts)内のセッション管理ソースコードを参照してください。 **デフォルトでアクティビティと見なされるもの:** - Webアプリを開くか更新する - Brazeが提供するUI要素([アプリ内メッセージ](https://www.braze.com/docs/ja/ja/developer_guide/in_app_messages)や[Content Cards](https://www.braze.com/docs/ja/ja/developer_guide/content_cards)など)とのインタラクション - トラッキングイベント([カスタムイベント](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events)や[ユーザー属性の更新](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_attributes)など)を送信するSDKメソッドの呼び出し **デフォルトではアクティビティとしてカウントされないもの:** - 別のブラウザタブへの切り替え - ブラウザウィンドウの最小化 - ブラウザのフォーカスまたはブラーイベント - ページ上のスクロールやマウスの動き **Note:** Web SDKは、ブラウザの表示状態の変化、タブの切り替え、またはユーザーのフォーカスを自動的にトラッキングしません。ただし、ブラウザの[Page Visibility API](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API)を使用してカスタムイベントリスナーを実装し、[カスタムイベント](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events?tab=web)をBrazeに送信することで、これらのブラウザレベルのインタラクションをトラッキングできます。実装例については、[カスタム非アクティブ状態のトラッキング](#tracking-custom-inactivity)を参照してください。 ### セッションタイムアウトの設定 {#session-timeout-configuration} デフォルトでは、Web SDKは30分間トラッキングイベントが発生しない場合、セッションを非アクティブと見なします。SDKを初期化する際に、`sessionTimeoutInSeconds`パラメータを使用してこのしきい値をカスタマイズできます。このパラメータの設定方法の詳細(コード例を含む)については、[デフォルトのセッションタイムアウトの変更](#changing-the-default-session-timeout)を参照してください。 ### 例:非アクティブ状態のシナリオを理解する {#example-understanding-inactivity-scenarios} 次のシナリオを考えてみましょう: 1. ユーザーがWebサイトを開くと、SDKは[`braze.openSession()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#opensession)を呼び出してセッションを開始します。 2. ユーザーは別のブラウザタブに切り替えて、30分間別のWebサイトを閲覧します。 3. この間、Webサイト上ではSDKがトラッキングするイベントは発生しません。 4. 30分間操作がないと、セッションは自動的に終了します。 5. ユーザーがWebサイトのタブに戻り、SDKイベント(ページ閲覧やコンテンツ操作など)をトリガーすると、新しいセッションが開始されます。 ### カスタム非アクティブ状態のトラッキング {#tracking-custom-inactivity} ブラウザの可視性やタブの切り替えに基づいて非アクティブ状態をトラッキングする必要がある場合は、JavaScriptコードにカスタムイベントリスナーを実装してください。`visibilitychange`などのブラウザイベントを使用してユーザーがページを離れたタイミングを検知し、必要に応じて[カスタムイベント](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events)を手動でBrazeに送信するか、[`braze.openSession()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#opensession)を呼び出してください。 ```javascript // Example: Track when user switches away from tab document.addEventListener('visibilitychange', function() { if (document.hidden) { // User switched away - optionally log a custom event braze.logCustomEvent('tab_hidden'); } else { // User returned - optionally start a new session and/or log an event // braze.openSession(); braze.logCustomEvent('tab_visible'); } }); ``` カスタムイベントの記録に関する詳細は、[カスタムイベントの記録](https://www.braze.com/docs/ja/ja/developer_guide/analytics/logging_events)を参照してください。セッションのライフサイクルとタイムアウト設定の詳細については、[デフォルトのセッションタイムアウトの変更](#change-session-timeout)を参照してください。 ## セッション更新のサブスクライブ {#subscribing-to-session-updates} ### ステップ1:更新をサブスクライブする {#step-1-subscribe-to-updates} セッション更新をサブスクライブするには、`subscribeToSessionUpdates()`メソッドを使用します。 現時点では、Web Braze SDKのセッション更新のサブスクライブはサポートされていません。 ```java Braze.getInstance(this).subscribeToSessionUpdates(new IEventSubscriber() { @Override public void trigger(SessionStateChangedEvent message) { if (message.getEventType() == SessionStateChangedEvent.ChangeType.SESSION_STARTED) { // A session has just been started } } }); ``` ```kotlin Braze.getInstance(this).subscribeToSessionUpdates { message -> if (message.eventType == SessionStateChangedEvent.ChangeType.SESSION_STARTED) { // A session has just been started } } ``` セッション終了コールバックを登録すると、アプリがフォアグラウンドに戻ったときに発火します。セッション時間は、アプリが開かれたときまたはフォアグラウンドになったときから、閉じられたときまたはバックグラウンドになったときまで測定されます。 ```swift // This subscription is maintained through a Braze cancellable, which will observe changes until the subscription is cancelled. // You must keep a strong reference to the cancellable to keep the subscription active. // The subscription is canceled either when the cancellable is deinitialized or when you call its `.cancel()` method. let cancellable = AppDelegate.braze?.subscribeToSessionUpdates { event in switch event { case .started(let id): print("Session \(id) has started") case .ended(let id): print("Session \(id) has ended") } } ``` 非同期ストリームをサブスクライブするには、代わりに[`sessionUpdatesStream`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/sessionupdatesstream)を使用できます。 ```swift for await event in braze.sessionUpdatesStream { switch event { case .started(let id): print("Session \(id) has started") case .ended(let id): print("Session \(id) has ended") } } ``` ```objc // This subscription is maintained through a Braze cancellable, which will observe changes until the subscription is cancelled. // You must keep a strong reference to the cancellable to keep the subscription active. // The subscription is canceled either when the cancellable is deinitialized or when you call its `.cancel()` method. BRZCancellable *cancellable = [AppDelegate.braze subscribeToSessionUpdates:^(BRZSessionEvent * _Nonnull event) { switch (event.state) { case BRZSessionStateStarted: NSLog(@"Session %@ has started", event.sessionId); break; case BRZSessionStateEnded: NSLog(@"Session %@ has ended", event.sessionId); break; default: break; } }]; ``` React Native SDKは、セッション更新を直接サブスクライブするためのメソッドを公開していません。セッションのライフサイクルは基盤となるネイティブSDKによって管理されます。更新をサブスクライブするには、**Android**または**Swift**タブのネイティブプラットフォーム向けアプローチを使用してください。 ### ステップ2:セッショントラッキングをテストする(オプション) {#step-2-test-session-tracking-optional} セッショントラッキングをテストするには、デバイスでセッションを開始し、Brazeダッシュボードを開いて関連するユーザーを検索します。ユーザープロファイルで、**Sessions Overview**を選択します。指標が期待どおりに更新された場合、セッショントラッキングは正常に動作しています。 ![ユーザープロファイルのセッション概要セクションには、セッション数、最終利用日、初回利用日が表示されます。](https://www.braze.com/docs/ja/ja/assets/img_archive/test_session.png?0428888ea3bd01a486d8c674fb973747){: style="max-width:50%;"} **Note:** アプリ固有の詳細は、複数のアプリを使用したユーザーにのみ表示されます。 ## デフォルトのセッションタイムアウトの変更 {#change-session-timeout} セッションが自動的にタイムアウトするまでの時間を変更できます。 デフォルトでは、セッションタイムアウトは`30`分に設定されています。これを変更するには、`sessionTimeoutInSeconds`オプションを[`initialize`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initialize)関数に渡します。`1`以上の任意の整数に設定できます。 ```js // Sets the session timeout to 15 minutes instead of the default 30 braze.initialize('YOUR-API-KEY-HERE', { sessionTimeoutInSeconds: 900 }); ``` デフォルトでは、セッションタイムアウトは`10`秒に設定されています。これを変更するには、`braze.xml`ファイルを開き、`com_braze_session_timeout`パラメータを追加します。`1`以上の任意の整数に設定できます。 ```xml 60 ``` デフォルトでは、セッションタイムアウトは`10`秒に設定されています。これを変更するには、[`init(configuration)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class)に渡される`configuration`オブジェクトで`sessionTimeout`を設定します。`1`以上の任意の整数に設定できます。 ```swift // Sets the session timeout to 60 seconds let configuration = Braze.Configuration( apiKey: "", endpoint: "" ) configuration.sessionTimeout = 60; let braze = Braze(configuration: configuration) AppDelegate.braze = braze ``` ```objc // Sets the session timeout to 60 seconds BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:brazeApiKey endpoint:brazeEndpoint]; configuration.sessionTimeout = 60; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; AppDelegate.braze = braze; ``` React Native SDKはセッション管理のためにネイティブSDKに依存しています。デフォルトのセッションタイムアウトを変更するには、ネイティブレイヤーで設定してください。 - **Android:**`braze.xml`ファイルで`com_braze_session_timeout`を設定します。詳細は、**Android**タブを選択してください。 - **iOS:**`Braze.Configuration`オブジェクトで`sessionTimeout`を設定します。詳細は、**Swift**タブを選択してください。 **Note:** セッションタイムアウトを設定すると、すべてのセッションセマンティクスが設定されたタイムアウトに自動的に拡張されます。 ## トラブルシューティング {#troubleshooting} ### ユーザープロファイルのセッション数が0件 {#user-profile-has-0-sessions} SDKの外部でユーザーが作成された場合、ユーザープロファイルのセッション数が0件になることがあります。 - **REST APIで作成された場合:**[`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)エンドポイントを通じてリクエストに`app_id`を含めてユーザーが作成された場合、プロファイルはそのアプリに関連付けられて表示されますが、そのユーザーに対してSDKが初期化されていないため、セッションデータはありません。 - **CSVインポートで作成された場合:**初回セッションまたは最終セッションのフィールドに値を含めずに[CSV](https://www.braze.com/docs/ja/ja/user_guide/audience/manage_audience/import_users/csv_import)でユーザーがインポートされた場合、プロファイルはセッション数0件で存在します。 ### 一部のユーザーがセッションを記録していない {#some-users-are-not-logging-sessions} セッションはSDKが初期化された後にのみトラッキングされるため、SDK初期化をトリガーしないユーザーはセッションを記録しません。これは通常、ログインフロー、同意プロンプト、またはフィーチャーフラグの背後で初期化を遅延させるなど、SDKを初期化する前に条件付きロジックを使用している場合に発生します。実装ガイダンスについては、[遅延初期化](https://www.braze.com/docs/ja/ja/developer_guide/sdk_initalization?sdktab=swift)を参照してください。これらのケースでは、条件を満たさないユーザーはセッションを開始しません。 一部のユーザーがセッションを記録し、他のユーザーが記録していない場合は、以下を確認してください。 - **初期化ロジックを確認する。**SDKが一部のユーザーやアプリのエントリポイントだけでなく、すべてのユーザーとエントリポイントで初期化されていることを確認してください。 - **最近のアプリの変更を確認する。**SDK初期化に関する新しい条件付きロジックにより、セッション数が急激に減少する可能性があります。 - **影響を受けたユーザーと受けていないユーザーを比較する。**アプリのバージョン、デバイスの種類、またはユーザーフローの違いを特定し、特定のユーザーで初期化がスキップされる理由を明らかにしてください。 実装を確認しても問題が解決しない場合は、問題を再現し、サポートに連絡する前に以下の情報を収集してください。 - 問題を再現する手順 - 影響を受けるアプリのバージョン - 問題が発生している間にキャプチャした[詳細SDKログ](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/verbose_logging)(またはプラットフォーム別:[Android](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=android#android_enabling-logs)、[Swift](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=swift#swift_setting-the-log-level)、[Web](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration?sdktab=web#web_logging)) - SDK初期化のコードスニペット - 初期化前に適用されている条件付きロジックの概要 # Braze SDKを通じて位置情報の追跡を行う Source: /docs/ja/developer_guide/analytics/tracking_location/index.md # 位置情報の追跡 > Braze SDK で位置を追跡する方法について説明します。 ## Logging the current location To get a user's current location, use the geolocation API's [`getCurrentPosition()`](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition) method. This will immediately prompt the user to allow or disallow tracking (unless they've already done so). ```javascript import * as braze from "@braze/web-sdk"; function success(position) { var coords = position.coords; braze.getUser().setLastKnownLocation( coords.latitude, coords.longitude, coords.accuracy, coords.altitude, coords.altitudeAccuracy ); } navigator.geolocation.getCurrentPosition(success); ``` Now when data is sent to Braze, the SDK can automatically detect the user's country using their IP address. For more information, see [setLastKnownLocation()](https://js.appboycdn.com/web-sdk/latest/doc/classes/braze.user.html#setlastknownlocation). ## Continuously tracking the location To continuously track a user's location during a page load, use the geolocation API's [`watchPosition()`](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition) method. Calling this method will immediately prompt the user to allow or disallow tracking (unless they've already done so). If they opt-in, a success callback will now be invoked every time their location is updated. ```javascript function success(position) { var coords = position.coords; braze.getUser().setLastKnownLocation( coords.latitude, coords.longitude, coords.accuracy, coords.altitude, coords.altitudeAccuracy ); } navigator.geolocation.watchPosition(success); ``` **Important:** To learn how to disable continuous tracking, refer to the [Mozilla developer docs](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/watchPosition). ## Logging the current location Even if continuous tracking is disabled, you can manually log the user's current location using the [`setLastKnownLocation()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze-user/set-last-known-location.html) method. ```java Braze.getInstance(context).getCurrentUser(new IValueCallback() { @Override public void onSuccess(BrazeUser brazeUser) { brazeUser.setLastKnownLocation(LATITUDE_DOUBLE_VALUE, LONGITUDE_DOUBLE_VALUE, ALTITUDE_DOUBLE_VALUE, ACCURACY_DOUBLE_VALUE); } } ``` ```kotlin Braze.getInstance(context).getCurrentUser { brazeUser -> brazeUser.setLastKnownLocation(LATITUDE_DOUBLE_VALUE, LONGITUDE_DOUBLE_VALUE, ALTITUDE_DOUBLE_VALUE, ACCURACY_DOUBLE_VALUE) } ``` ## Continuously tracking the location **Important:** [Starting with Android Marshmallow](https://developer.android.com/training/permissions/index.html), you must prompt your users to explicitly opt-in to location tracking. Once they do, Braze can start tracking their location at the beginning of the next session. This is unlike earlier versions of Android, where only declaring location permissions in your `AndroidManifest.xml` was required. To continuously track a user's location, you'll need to declare your app's intent to collect location data by adding at least one of the following permissions to your `AndroidManifest.xml` file. |Permission|Description| |---|---| | `ACCESS_COARSE_LOCATION` | Uses the most battery-efficient, non-GPS provider (such as a home network). Typically, this is sufficient for most location-data needs. Under the runtime permissions model, granting location permission implicitly authorizes the collection of fine location data. | | `ACCESS_FINE_LOCATION` | Includes GPS data for more precise location. Under the runtime permissions model, granting location permission also covers fine location access. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Continuously tracking the location" } Your `AndroidManifest.xml` should be similar to the following: ```xml ... ``` ## Disabling continuous tracking You can disable continuous tracking at compile time or runtime. To disable continuous location tracking at compile time, set `com_braze_enable_location_collection` to `false` in `braze.xml`: ```xml false ``` To selectively disable continuous location tracking at runtime, use [`BrazeConfig`](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/android/advanced_use_cases/runtime_configuration/#runtime-configuration): ```java BrazeConfig brazeConfig = new BrazeConfig.Builder() .setIsAutomaticLocationCollectionEnabled(false) .build(); Braze.configure(this, brazeConfig); ``` ```kotlin val brazeConfig = BrazeConfig.Builder() .setIsAutomaticLocationCollectionEnabled(false) .build() Braze.configure(this, brazeConfig) ``` ## Logging the current location ### Step 1: Configure your project **Important:** When using Braze location features, your application is responsible for requesting authorization for using location services. Be sure to review [Apple Developer: Requesting authorization to user location services](https://developer.apple.com/documentation/corelocation/requesting-authorization-to-use-location-services). To enable location tracking, open your Xcode project and select your app. In the **General** tab, add the `BrazeLocation` module. In your `AppDelegate.swift` file, import the `BrazeLocation` module at the top of the file. Add a `BrazeLocationProvider` instance to the Braze configuration, making sure all changes to the configuration are done prior to calling `Braze(configuration:)`. See `Braze.Configuration.Location` for the available configurations. ```swift import UIKit import BrazeKit import BrazeLocation @main class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Setup Braze let configuration = Braze.Configuration(apiKey: brazeApiKey, endpoint: brazeEndpoint) configuration.logger.level = .info configuration.location.brazeLocationProvider = BrazeLocationProvider() configuration.location.automaticLocationCollection = true configuration.location.geofencesEnabled = true configuration.location.automaticGeofenceRequests = true let braze = Braze(configuration: configuration) AppDelegate.braze = braze return true } } ``` In your `AppDelegate.m` file, import the `BrazeLocation` module at the top of the file. Add a `BrazeLocationProvider` instance to the Braze configuration, making sure all changes to the configuration are done prior to calling `Braze(configuration:)`. See `BRZConfigurationLocation` for the available configurations. ```objc #import "AppDelegate.h" @import BrazeKit; @import BrazeLocation; @implementation AppDelegate #pragma mark - Lifecycle - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Setup Braze BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:brazeApiKey endpoint:brazeEndpoint]; configuration.logger.level = BRZLoggerLevelInfo; configuration.location.brazeLocationProvider = [[BrazeLocationProvider alloc] init]; configuration.location.automaticLocationCollection = YES; configuration.location.geofencesEnabled = YES; configuration.location.automaticGeofenceRequests = YES; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; AppDelegate.braze = braze; [self.window makeKeyAndVisible]; return YES; } #pragma mark - AppDelegate.braze static Braze *_braze = nil; + (Braze *)braze { return _braze; } + (void)setBraze:(Braze *)braze { _braze = braze; } @end ``` ### Step 2: Log the user's location Next, log the user's last-known location to Braze. The following examples assume you’ve assigned the Braze instance as a variable in your `AppDelegate`. ```swift AppDelegate.braze?.user.setLastKnownLocation(latitude:latitude, longitude:longitude) ``` ```swift AppDelegate.braze?.user.setLastKnownLocation(latitude:latitude, longitude:longitude, altitude:altitude, horizontalAccuracy:horizontalAccuracy, verticalAccuracy:verticalAccuracy) ``` ```objc [AppDelegate.braze.user setLastKnownLocationWithLatitude:latitude longitude:longitude horizontalAccuracy:horizontalAccuracy]; ``` ```objc [AppDelegate.braze.user setLastKnownLocationWithLatitude:latitude longitude:longitude horizontalAccuracy:horizontalAccuracy altitude:altitude verticalAccuracy:verticalAccuracy]; ``` **Tip:** For more information, see [`Braze.User.swift`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/user-swift.class/). ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Setting the last known location To manually set the last known location for a user, use the `setLastKnownLocation` method. This is useful if you collect location data outside of the Braze SDK. ```javascript Braze.setLastKnownLocation(LATITUDE, LONGITUDE, ALTITUDE, HORIZONTAL_ACCURACY, VERTICAL_ACCURACY); ``` - On Android, `latitude` and `longitude` are required. `altitude`, `horizontalAccuracy`, and `verticalAccuracy` are optional. - On iOS, `latitude`, `longitude`, and `horizontalAccuracy` are required. `altitude` and `verticalAccuracy` are optional. For cross-platform compatibility, provide `latitude`, `longitude`, and `horizontalAccuracy` at a minimum. ## Setting a custom location attribute To set a custom location attribute on a user profile, use the `setLocationCustomAttribute` method. ```javascript Braze.setLocationCustomAttribute("favorite_restaurant", 40.7128, -74.0060, optionalCallback); ``` ## Requesting location initialization (Android only) Call `requestLocationInitialization` after a user grants location permissions to initialize Braze location features on Android. This method is not supported on iOS and is not required for iOS geofence or location features. ```javascript Braze.requestLocationInitialization(); ``` ## Geofences Geofences are supported on both iOS and Android. By default, the Braze SDK can automatically request and monitor geofences when location is available. You can rely on this automatic configuration for most integrations. ### Manually requesting geofences To manually request a geofence update for a specific GPS coordinate, use `requestGeofences`. This is available on both iOS and Android. If you use this method, disable automatic geofence requests in your native configuration so the SDK does not overwrite your manual requests. ```javascript Braze.requestGeofences(LATITUDE, LONGITUDE); ``` # Braze SDKを通じてアンインストールを追跡する Source: /docs/ja/developer_guide/analytics/tracking_uninstalls/index.md # アンインストール追跡 > Braze SDKを通してアンインストール追跡を設定する方法を学習する。一般情報については、[ユーザーガイド] を参照してください。アンインストール追跡](https://www.braze.com/docs/ja/ja/user_guide/analytics/tracking/uninstall_tracking). ## Setting up uninstall tracking ### Step 1: Set up FCM The Android Braze SDK uses Firebase Cloud Messaging (FCM) to send silent push notifications, which are used to collect uninstall tracking analytics. If you haven't already, [set up](https://www.braze.com/docs/ja/ja/developer_guide/platforms/android/push_notifications/#setting-up-push-notifications) or [migrate to](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=android) the Firebase Cloud Messaging API for push notifications. ### Step 2: Manually detect uninstall tracking (optional) By default, the Android Braze SDK will automatically detect and ignore silent push notifications related to uninstall tracking. However, you choose to manually detect uninstall tracking using the [`isUninstallTrackingPush()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.models.push/-braze-notification-payload/is-uninstall-tracking-push.html) method. **Important:** Because silent notifications for uninstall tracking are not forwarded to any Braze push callbacks, you can only use this method before you pass a push notification to Braze. ### Step 3: Remove automatic server pings A silent push notification will wake your app and instantiate the `Application` component if it app isn't already running. So, if you have a custom [`Application`](https://developer.android.com/reference/android/app/Application) subclass, remove any logic that automatically pings your servers during your [`Application.onCreate()`](https://developer.android.com/reference/android/app/Application#onCreate()) lifecycle method. ### Step 4: Enable uninstall tracking Finally, enable uninstall tracking in Braze. For a full walkthrough, see [Enable uninstall tracking](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/tracking/uninstall_tracking/#uninstall-tracking). **Important:** Tracking uninstalls can be imprecise. The metrics you see on Braze may be delayed or inaccurate. ## Setting up uninstall tracking ### Step 1: Enable background push In your Xcode project, go to **Capabilities** and ensure you have **Background Modes** enabled. For more information, see [silent push notification](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent/?sdktab=swift). ### Step 2: Ignore internal push notifications The Swift Braze SDK uses background push notifications to collect uninstall tracking analytics. To ensure your app doesn't make unwanted actions when these are sent, you'll need to ensure that [internal push notifications are ignored](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/silent/?sdktab=swift#swift_ignoring-internal-push-notifications). ### Step 3: Send a test push (optional) Next, send yourself a test push notification from the Braze dashboard (don't worry—it won't update your user profile). 1. Go to **Messaging** > **Campaigns** and create a push notification campaign using the relevant platform. 2. Go to **Settings** > **App Settings** and add the `appboy_uninstall_tracking` key with relevant `true` value, then check **Add Content-Available Flag**. 3. Use the **Preview** page to send yourself a test uninstall tracking push. 4. Check that your app does not make any unwanted automatic actions when it receives a push notification. **Note:** A badge number will be sent along with the test push notification—however a real uninstall tracking push won't send any badge numbers. ### Step 3: Enable uninstall tracking Finally, enable uninstall tracking in Braze. For a full walkthrough, see [Enable uninstall tracking](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/tracking/uninstall_tracking/#uninstall-tracking). **Important:** Tracking uninstalls can be imprecise. The metrics you see on Braze may be delayed or inaccurate. # Braze SDKのデータ収集を管理する Source: /docs/ja/developer_guide/analytics/managing_data_collection/index.md # データ収集を管理する {#manage-data-collection} > Braze SDKのデータ収集を管理する方法について説明します。必要に応じてデータプライバシー規制に準拠できます。 ## Disabling data tracking **Note:** This guide uses code samples from the Braze Web SDK 4.0.0+. To upgrade to the latest Web SDK version, see [SDK Upgrade Guide](https://github.com/braze-inc/braze-web-sdk/blob/master/UPGRADE_GUIDE.md). To disable data-tracking activity on the Web SDK, use the method [`disableSDK()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#disablesdk). This will sync any data logged before `disableSDK()` was called, and will cause all subsequent calls to the Braze Web SDK for this page and future page loads to be ignored. Use the **Disable Tracking** or **Resume Tracking** tag type to disable or re-enable web tracking, respectively. These two options call [`disableSDK`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#disablesdk) and [`enableSDK`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#enablesdk). ### Best practices To provide users with the option to stop tracking, we recommend building a simple page with two links or buttons: one that calls `disableSDK()` when clicked, and another that calls `enableSDK()` to allow users to opt back in. You can use these controls to start or stop tracking via other data sub-processors as well. **Note:** The Braze SDK does not need to be initialized to call `disableSDK()`, allowing you to disable tracking for fully anonymous users. Conversely,`enableSDK()` does not initialize the Braze SDK so you must also call `initialize()` afterward to enable tracking. ## Resuming data tracking To resume data collection, you can use the [`enableSDK()`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#enablesdk) method. ## Google Play privacy questionnaire {#privacy-questionnaire} Starting in April 2022, Android developers must complete Google Play's [Data safety form](https://support.google.com/googleplay/android-developer/answer/10787469) to disclose privacy and security practices. This guide provides instructions on how to fill out this new form with information on how Braze handles your app data. As the app developer, you are in control of what data you send to Braze. Data received by Braze is processed according to your instructions. This is what Google classifies as a [service provider](https://support.google.com/googleplay/android-developer/answer/10787469?hl=en#zippy=%2Cwhat-kinds-of-activities-can-service-providers-perform). **Important:** This article provides information related to the data the Braze SDK processes as related to the Google safety section questionnaire. This article is not providing legal advice, so we recommend consulting with your legal team before submitting any information to Google. ### Questions |Questions|Answers for Braze SDK| |---|---| |Does your app collect or share any of the required user data types?|Yes, the Braze Android SDK collects data as configured by the app developer. | |Is all of the user data collected by your app encrypted in transit?|Yes.| |Do you provide a way for users to request that their data be deleted?|Yes.| {: .reset-td-br-1 .reset-td-br-2 aria-label="Questions" } For more information about handling user requests for their data and deletion, see [Braze Data Retention Information](https://www.braze.com/docs/ja/ja/api/data_retention/). ### Data collection The data collected by Braze is determined by your specific integration and the user data you choose to collect. To learn more about what data Braze collects by default and how to disable certain attributes, see our [SDK data collection options](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/user_data_collection/sdk_data_collection/#minimum-integration).
Category Data type Braze Usage
Location Approximate location Not collected by default.
Precise location
Personal Info Name
Email address
User IDs
Address
Phone number
Race and ethnicity
Political or religious beliefs
Sexual orientation
Other info
Financial info User payment info
Purchase history
Credit score
Other financial info
Health and fitness Health info Not collected by default.
Fitness info
Messages Emails Not collected by default.
SMS or MMS
Other in-app messages If you send In-app messages or push notifications through Braze, we collect information on when users have opened or read these messages.
Photos and videos Photos Not collected.
Videos
Audio files Voice or sound recordings
Music files
Other audio files
Files and docs Files and docs
Calendar Calendar events
Contacts Contacts
App activity App interactions Braze collects session activity data by default. All other interactions and activity is determined by your app's custom integration.
In-app search history Not collected.
Installed apps Not collected.
Other user-generated content Not collected by default.
Other actions
Web browsing Web browsing history Not collected.
App information and performance Crash logs Braze collects crash logs for errors that occur within the SDK. This contains the user's phone model and OS level, along with a Braze specific user ID.
Diagnostics Not collected.
Other app performance data Not collected.
Device or other IDs Device or other IDs Braze generates a device ID to differentiate users' devices, and checks if messages are sent to the correct intended device.
To learn more about other device data that Braze collects which may fall outside the scope of Google Play's data safety guidelines, see our [Android storage overview](https://www.braze.com/docs/ja/ja/developer_guide/storage/?tab=android) and our [SDK data collection options](https://www.braze.com/docs/ja/ja/user_guide/data_and_analytics/user_data_collection/sdk_data_collection/#minimum-integration). ## Disabling data tracking To disable data-tracking activity on the Android SDK, use the method [`disableSDK()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/disable-sdk.html). This will cause all network connections to be canceled, meaning the Braze SDK will no longer pass any data to Braze servers. ## Wiping previously-stored data You can use the method [`wipeData()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/wipe-data.html) to fully clear all client-side data stored on the device. ## Resuming data tracking To resume data collection, you can use the [`enableSDK()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/enable-sdk.html) method. Keep in mind, this will not restore any previously wiped data. ## Apple's privacy manifest {#privacy-manifest} ### What is tracking data? Apple defines "tracking data" as data collected in your app about an end-user or device that's linked to third-party data (such as targeted advertising), or a data broker. For a complete definition with examples, see [Apple: Tracking](https://developer.apple.com/app-store/app-privacy-details/#user-tracking). By default, the Braze SDK does not collect tracking data. However, depending on your Braze SDK configuration, you may be required to list Braze-specific data in your app's privacy manifest. ### What is a privacy manifest? A privacy manifest is a file in your Xcode project that describes the reason your app and third-party SDKs collect data, along with their data-collection methods. Each of your third-party SDKs that track data require its own privacy manifest. When you [create your app's privacy report](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests#4239187), these privacy manifest files are automatically aggregated into a single report. ### API tracking-data domains Starting with iOS 17.2, Apple will block all declared tracking endpoints in your app until the end-user accepts an [Ad Tracking Transparency (ATT) prompt](https://support.apple.com/en-us/HT212025). Braze provides tracking endpoints to route your tracking data, while still allowing you to route non-tracking first-party data to the original endpoint. ## Declaring Braze tracking data **Tip:** For a full walkthrough, see the [Privacy Tracking Data tutorial](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/e1-privacy-tracking/). ### Prerequisites The following Braze SDK version is required to implement this feature: ### Step 1: Review your current policies Review your Braze SDK's current data-collection policies with your legal team to determine whether your app collects tracking data [as defined by Apple](#what-is-tracking-data). If you're not collecting any tracking data, you don't need to customize your privacy manifest for the Braze SDK at this time. For more information about the Braze SDK's data-collection policies, see [SDK data collection](https://www.braze.com/docs/ja/ja/user_guide/data/user_data_collection/sdk_data_collection/). **Important:** If any of your non-Braze SDKs collect tracking data, you'll need to review those policies separately. ### Step 2: Create a privacy manifest First, check if you already have a privacy manifest by searching for a `PrivacyInfo.xcprivacy` file in your Xcode project. If you already have this file, you can continue to the next step. Otherwise, see [Apple: Create a privacy manifest](sdk-tracking.iad-01.braze.com). ### Step 3: Add your endpoint to the privacy manifest In your Xcode project, open your app's `PrivacyInfo.xcprivacy` file, then right-click the table and check **Raw Keys and Values**. ![An Xcode project with the context menu open and "Raw Keys and Values" highlighted.](https://www.braze.com/docs/ja/ja/assets/img/apple/privacy_manifest/check_raw_keys_and_values.png?670eead9e29da0d52e7ae1a6d6205194) Under **App Privacy Configuration**, choose **NSPrivacyTracking** and set its value to **YES**. ![The 'PrivacyInfo.xcprivacy' file open with "NSPrivacyTracking" set to "YES".](https://www.braze.com/docs/ja/ja/assets/img/apple/privacy_manifest/add_nsprivacytracking.png?02325a36076d8716d2d1e340f7a8ecd7) Under **App Privacy Configuration**, choose **NSPrivacyTrackingDomains**. In the domains array, add a new element and set its value to the endpoint you [previously added to your `AppDelegate`](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/initial_sdk_setup/completing_integration/#update-your-app-delegate) prefixed with `sdk-tracking`. ![The 'PrivacyInfo.xcprivacy' file open with a Braze tracking endpoint listed under "NSPrivacyTrackingDomains".](https://www.braze.com/docs/ja/ja/assets/img/apple/privacy_manifest/add_nsprivacytrackingdomains.png?eb07fc3447c9380e0a20b912f9b22630) ### Step 4: Declare your tracking data Next, open `AppDelegate.swift` then list each [tracking property](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/trackingproperty/) you want to declare by creating a static or dynamic tracking list. Keep in mind, Apple will block these properties until the end-user accepts their ATT prompt, so only list the properties you and your legal team consider tracking. For example: In the following example, `dateOfBirth`, `customEvent`, and `customAttribute` are declared as tracking data within a static list. ```swift import UIKit import BrazeKit @main class AppDelegate: UIResponder, UIApplicationDelegate { static var braze: Braze? = nil func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { let configuration = Braze.Configuration(apiKey: brazeApiKey, endpoint: brazeEndpoint) // Declare which types of data you wish to collect for user tracking. configuration.api.trackingPropertyAllowList = [ .dateOfBirth, .customEvent(["event-1"]), .customAttribute(["attribute-1", "attribute-2"]) ] let braze = Braze(configuration: configuration) AppDelegate.braze = braze return true } } ``` In the following example, the tracking list is automatically updated after the end-user accepts the ATT prompt. ```swift func applicationDidBecomeActive(_ application: UIApplication) { // Request and check your user's tracking authorization status. ATTrackingManager.requestTrackingAuthorization { status in // Let Braze know whether user data is allowed to be collected for tracking. let enableAdTracking = status == .authorized AppDelegate.braze?.set(adTrackingEnabled: enableAdTracking) // Add the `.firstName` and `.lastName` properties, while removing the `.everything` configuration. AppDelegate.braze.updateTrackingAllowList( adding: [.firstName, .lastName], removing: [.everything] ) } } ``` ### Step 5: Prevent infinite retry loops To prevent the SDK from entering an infinite retry loop, use the `set(adTrackingEnabled: enableAdTracking)` method to handle ATT permissions. The `adTrackingEnabled` property in your method should be handled similar to the following: ```swift func applicationDidBecomeActive(_ application: UIApplication) { // Request and check your user's tracking authorization status. ATTrackingManager.requestTrackingAuthorization { status in // Let Braze know whether user data is allowed to be collected for tracking. let enableAdTracking = status == .authorized AppDelegate.braze?.set(adTrackingEnabled: enableAdTracking) } } ``` ## Disabling data tracking To disable data-tracking activity on the Swift SDK, set the [`enabled`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/enabled) property to `false` on your Braze instance. When `enabled` is set to `false`, the Braze SDK ignores any calls to the public API. The SDK also cancels all in-flight actions, such as network requests, event processing, etc. ## Wiping previously-stored data You can use the [`wipeData()`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/wipedata()) method to fully clear locally-stored SDK data on a user's device. For Braze Swift versions 7.0.0 and later, the SDK and the `wipeData()` method randomly generates a UUID for their device ID. However, if your `useUUIDAsDeviceId` is set to `false` _or_ you're using Swift SDK version 5.7.0 or earlier, you'll also need to make a post request to [`/users/delete`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_delete/) since your Identifier for Vendors (IDFV) will automatically be used as that user's device ID. If you use manual push integration, and your app calls `wipeData()` and later re-enables the SDK in the same app run, call `registerForRemoteNotifications()` again so Braze can receive a refreshed device token. For more information, see [setting up push notifications](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=swift). ## Resuming data tracking To resume data collection, set [`enabled`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/enabled/) to `true`. Keep in mind, this will not restore any previously wiped data. ## IDFV collection In previous versions of the Braze iOS SDK, the IDFV (Identifier for Vendor) field was automatically collected as the user's device ID. Beginning in Swift SDK `v5.7.0`, the IDFV field was optionally disabled, and instead, Braze would set a random UUID as the device ID. Starting in Swift SDK `v7.0.0`, the IDFV field will not be collected by default, and a UUID will be set as the device ID instead. The `useUUIDAsDeviceId` feature configures the [Swift SDK](https://github.com/braze-inc/braze-swift-sdk) to set the device ID as a UUID. Traditionally, the iOS SDK would assign the device ID equal to the Apple-generated IDFV value. With this feature enabled by default on your iOS app, all new users created via the SDK would be assigned a device ID equal to a UUID. If you still want to collect IDFV separately, you can use [`set(identifierforvendor:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/set(identifierforvendor:)). ### Considerations #### SDK Version In Swift SDK `v7.0.0+`, when `useUUIDAsDeviceId` is enabled (default), all new users created will be assigned a random device ID. All previously existing users will maintain their same device ID value, which may have been IDFV. When this feature is not enabled, devices will continue to be assigned IDFV upon creation. #### Downstream **Technology partners**: When this feature is enabled, any technology partners that derive the IDFV value from the Braze device ID will no longer have access to this data. If the IDFV value derived from the device is needed for your partner integration, we recommend that you set this feature to `false`. **Currents**: `useUUIDAsDeviceId` set to true means the device ID sent in Currents will no longer equal the IDFV value. ### Frequently asked questions #### Will this change impact my existing users in Braze? No. When enabled, this feature will not overwrite any user data in Braze. New UUID device IDs will only be created for new devices or when `wipedata()` is called. #### Can I turn this feature off after turning it on? Yes, this feature can be toggled on and off at your discretion. Previously stored device IDs will never be overwritten. #### Can I still capture the IDFV value via Braze elsewhere? Yes, you can still optionally collect the IDFV via the Swift SDK (collection is disabled by default). ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Disabling data tracking To disable data collection, use the `disableSDK` method. After calling this method, the Braze SDK stops sending data to Braze servers. ```javascript Braze.disableSDK(); ``` ## Resuming data tracking To resume data collection after disabling it, use the `enableSDK` method. ```javascript Braze.enableSDK(); ``` ## Wiping data To delete all locally stored Braze SDK data on the device, use the `wipeData` method. After calling this method, the SDK is disabled and must be re-enabled with `enableSDK`. ```javascript Braze.wipeData(); ``` ## Flushing data To request an immediate flush of any pending data to Braze servers, use `requestImmediateDataFlush`. ```javascript Braze.requestImmediateDataFlush(); ``` ## Setting ad-tracking enabled To inform Braze whether ad-tracking is enabled for this device, use the `setAdTrackingEnabled` method. The SDK does not automatically collect this data. ```javascript Braze.setAdTrackingEnabled(true, "GOOGLE_ADVERTISING_ID"); ``` The second parameter is the Google Advertising ID and is only used on Android. ## Updating the tracking property allow list (iOS only) To update the list of data types declared for tracking, use `updateTrackingPropertyAllowList`. This is a no-op on Android. ```javascript Braze.updateTrackingPropertyAllowList({ adding: [Braze.TrackingProperty.EMAIL, Braze.TrackingProperty.FIRST_NAME], removing: [], addingCustomEvents: ["my_custom_event"], removingCustomEvents: [], addingCustomAttributes: ["my_custom_attribute"], removingCustomAttributes: [] }); ``` For more information, refer to [Privacy Manifest](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/privacy_manifest/). ## Prerequisites Before you can use this feature, you'll need to [integrate the Roku Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=roku). ## Wiping previously-stored data The Roku SDK doesn't include a `wipeData` method. To produce a clean-slate state functionally equivalent to `wipeData()` on other Braze SDKs, clear the four Braze registry sections, then re-initialize the SDK. The Braze Roku SDK persists data across the following registry sections: | Section | Contents | |---------|----------| | `braze.section.device_id` | The device UUID used to identify this device in Braze. | | `braze.section.user_id` | The external user ID, if one has been set. | | `braze.section.session` | The active session UUID, start time, and end time. | | `braze.section.config` | Cached SDK configuration and feature flag data. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Wiping previously-stored data" } ### Step 1: Clear the registry sections Use [`roRegistry.Delete()`](https://developer.roku.com/docs/references/brightscript/components/roregistry.md) to delete each Braze section, then call `Flush()` to persist the changes: ```brightscript sub WipeBrazeData() registry = CreateObject("roRegistry") registry.Delete("braze.section.device_id") registry.Delete("braze.section.user_id") registry.Delete("braze.section.session") registry.Delete("braze.section.config") registry.Flush() end sub ``` ### Step 2: Re-initialize the Braze SDK When you [initialize the Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=roku) again, the SDK handles the missing registry data gracefully: - The device ID section is empty, so the SDK generates a new UUID and treats the device as anonymous. - The user ID section is empty, so the SDK defaults to an anonymous user (an empty string `""`). - The session section is empty, so the SDK starts a new session. - The config section is empty, so the SDK re-fetches the configuration from the server. **Note:** The Roku SDK doesn't generate any server-side delete request when you clear the registry. If you also need to remove the user from Braze, send a request to [`/users/delete`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_delete/) using the user's `external_id` or `braze_id`. # Braze MCPサーバーについて Source: /docs/ja/developer_guide/mcp_server/index.md # The Braze MCP server > Learn about the Braze MCP server, a secure connection that lets AI tools like Claude and Cursor access non-PII Braze data to answer questions, analyze trends, and provide insights. **Important:** This summer, Braze is launching a remote, Braze-hosted MCP server in early access. It replaces the locally hosted beta server (`braze-mcp-server` on [PyPI](https://pypi.org/project/braze-mcp-server/) and the Claude Desktop extension directory).

**What this means for you:**

- The locally hosted server will continue to work, but it is no longer supported. We won't be adding new endpoints or fixing issues in the beta. - When the remote server is available in early access, you'll need to switch to it. The remote server requires no local installation, uses OAuth instead of static API keys, and works with MCP clients like Claude, Copilot, Gemini CLI, Codex, and Cursor. - Watch this page for early access availability, or contact your Braze account team to express interest. ## What is Model Context Protocol (MCP)? ​​Model Context Protocol, or MCP, is a standard that lets AI agents connect to and work with data from another platform. It has two main parts: - **MCP client:** The application where the AI agent runs, such as Cursor or Claude. - **MCP server:** A service provided by another platform, like Braze, that defines which tools the AI can use and what data it can access. ## About the Braze MCP server After [setting up the Braze MCP server], you can connect AI tools like agents, assistants, and chatbots directly to Braze, allowing them to read aggregated data such as Canvas and Campaign analytics, custom attributes, segments, and more. The Braze MCP server is great for: - Building AI-powered tools that need Braze context. - CRM engineers creating multi-step agent workflows. - Technical marketers experimenting with natural language queries. The Braze MCP server includes both read-only and write endpoints. They do not return data from Braze user profiles. You choose which endpoints to assign to your Braze API key, and that choice controls what an agent can read, create, or update. For the full list of available endpoints and their required permissions, see [Available API functions]. **Warning:** Only assign the API key permissions you want your agent to have. If you don't want your agent to make changes in Braze, leave any write permissions off when you create your API key. Agents may try to write data through any write permission you grant. ## Usage example You can interact with Braze through natural language using tools like Claude or Cursor. For other examples and best practices, see [Using the Braze MCP server]. **Example prompt:** `What are my available Braze functions?` **Example response:** Used `list_functions` and returned the available Braze MCP function categories. **Example prompt:** `What are my available Braze functions?` **Example response:** Queried `list_functions` and listed functions such as `get_canvas_list`. ## Frequently Asked Questions (FAQ) {#faq} ### Which MCP clients are supported? Only [Claude](https://claude.ai/) and [Cursor](https://cursor.com/) are officially supported. You must have an account for one of these clients to use the Braze MCP server. ### What Braze data can my MCP client access? MCP clients can access endpoints that don't return PII. You control which endpoints an agent can use through the permissions you assign to your API key. ### Can my MCP client change Braze data? Yes. The server exposes a focused set of write endpoints that let agents create or update content in your workspace, such as media library assets, email templates, and content blocks. Each write endpoint requires its own API key permission. If you don't want your agent to make a given change in Braze, leave that permission off when you create your API key. For the full list of write functions and their required permissions, see [Available API functions]. ### Can I use a third-party MCP server for Braze? Using a third-party MCP server for Braze data is not recommended. Only use the official Braze MCP server hosted on [PyPi](https://pypi.org/project/braze-mcp-server/). ### Why doesn't the Braze MCP server offer PII access? To protect user data while supporting valuable use cases, the server is limited to endpoints that don't typically return PII. This reduces risk for your workspace and the people in it. ### Can I reuse my API keys? No. You'll need to create a new API key for your MCP client. Remember to only give your AI tools access to what you’re comfortable with, and avoid elevated permissions. ### Is the Braze MCP server hosted locally or remotely? The currently available Braze MCP server is hosted locally. A remote, Braze-hosted MCP server is coming to Early Access this summer and will replace the locally hosted beta server. ### Why is Cursor only listing functions? Check if you're in ask mode or agent mode. To use the MCP server, you need to be in agent mode. ### What do I do when the agent returns an answer that looks incorrect? When working with tools like Cursor, you may want to try changing the model used. For example, if you have it set to auto, try changing it to a specific model and experiment to find which model performs best for your use case. You can also try starting a new chat and retrying the prompt. If issues persist, you can email us at [mcp-product@braze.com](mailto:mcp-product@braze.com) to let us know. If possible, include a video and expand the call functions so we can see what calls the agent attempted. ## Disclaimer The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is a newly introduced open-source protocol that may be susceptible to security issues or vulnerabilities at this time. Braze MCP Server setup code and instructions are provided by Braze “as is” and without any warranties, and customers use it at their own risk. Braze shall not be responsible for any consequences arising from improper setup, misuse of the MCP, or any potential security issues that may arise. Braze strongly encourages customers to review their configurations carefully and to follow the outlined guidelines to reduce risks associated with the integrity and security of their Braze environment. For assistance or clarification, please contact [Braze Support](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/support). # Braze MCPサーバーを設定する Source: /docs/ja/developer_guide/mcp_server/setup/index.md # Setting up the Braze MCP server > Learn how to set up the Braze MCP server, so you can interact with your Braze data through natural language using tools like Claude and Cursor. For more general information, see [Braze MCP server]. **Important:** The locally hosted Braze MCP server (beta) is sunsetting this summer. It will continue to work, but we're no longer adding endpoints or supporting the beta. A remote, Braze-hosted MCP server is coming to Early Access this summer. ## Prerequisites Before you start, you'll need the following: | Prerequisite | Description | |--------------|-------------| | Braze API Key | A Braze API key with the required permissions. You'll create a new key when you [set up your Braze MCP server](#create-api-key). | | MCP client | [Claude](https://claude.ai/), [Cursor](https://cursor.com/), and [Google Gemini CLI](https://docs.cloud.google.com/gemini/docs/codeassist/gemini-cli) are officially supported. You must have an account for one of these clients to use the Braze MCP server. | | Terminal | A terminal app so you can run commands and install tooling. Use your preferred terminal app or the one that's pre-installed on your computer. | {: .reset-td-br-1 .reset-td-br-2 aria-label="Prerequisites" } ## Setting up the Braze MCP server ### Step 1: Install `uv` First, install `uv`—a [command-line tool by Astral](https://docs.astral.sh/uv/getting-started/installation/) for dependency management and Python package handling. Open your terminal application, paste the following command, then press Enter. ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` The output is similar to the following: ```bash $ curl -LsSf https://astral.sh/uv/install.sh | sh downloading uv 0.8.9 aarch64-apple-darwin no checksums to verify installing to /Users/Isaiah.Robinson/.local/bin uv uvx everything's installed! ``` Open Windows PowerShell, paste the following command, then press Enter. ```powershell irm https://astral.sh/uv/install.ps1 | iex ``` The output is similar to the following: ```powershell PS C:\Users\YourUser> irm https://astral.sh/uv/install.ps1 | iex Downloading uv 0.8.9 (x86_64-pc-windows-msvc) no checksums to verify installing to C:\Users\YourUser\.local\bin uv.exe uvx.exe everything's installed! ``` ### Step 2: Create an API key {#create-api-key} The Braze MCP server includes both read-only and write endpoints. They don't return data from Braze user profiles. Write endpoints let agents create or update content in your workspace. To create your API key: 1. Go to **Settings** > **APIs and Identifiers** > **API Keys**. 2. Create a new key. 3. Assign some or all of the following permissions to your key. **Important:** Only assign the permissions you want your agent to use. To prevent your agent from making changes in Braze, leave any write permissions off when you create your API key. **List of supported permissions** #### Campaigns | Endpoint | Required permission | |----------|---------------------| | [`/campaigns/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaign_analytics) | `campaigns.data_series` | | [`/campaigns/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaign_details) | `campaigns.details` | | [`/campaigns/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaigns) | `campaigns.list` | | [`/sends/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_send_analytics) | `sends.data_series` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Campaigns" } #### Canvas | Endpoint | Required permission | |----------|---------------------| | [`/canvas/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvas_analytics) | `canvas.data_series` | | [`/canvas/data_summary`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvas_analytics_summary) | `canvas.data_summary` | | [`/canvas/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvas_details) | `canvas.details` | | [`/canvas/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvases) | `canvas.list` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Canvas" } #### Catalogs | Endpoint | Required permission | |----------|---------------------| | [`/catalogs`](https://www.braze.com/docs/ja/ja/api/endpoints/catalogs/catalog_management/synchronous/get_list_catalogs) | `catalogs.get` | | [`/catalogs/{catalog_name}/items`](https://www.braze.com/docs/ja/ja/api/endpoints/catalogs/catalog_items/synchronous/get_catalog_items_details_bulk) | `catalogs.get_items` | | [`/catalogs/{catalog_name}/items/{item_id}`](https://www.braze.com/docs/ja/ja/api/endpoints/catalogs/catalog_items/synchronous/get_catalog_item_details) | `catalogs.get_item` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Catalogs" } #### Cloud Data Ingestion | Endpoint | Required permission | |----------|---------------------| | [`/cdi/integrations`](https://www.braze.com/docs/ja/ja/api/endpoints/cdi/get_integration_list) | `cdi.integration_list` | | [`/cdi/integrations/{integration_id}/job_sync_status`](https://www.braze.com/docs/ja/ja/api/endpoints/cdi/get_job_sync_status) | `cdi.integration_job_status` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Cloud Data Ingestion" } #### Content Blocks The `content_blocks.create` and `content_blocks.update` permissions are write permissions. Add them only if you want your agent to create or update content blocks in your workspace. | Endpoint | Required permission | |----------|---------------------| | [`/content_blocks/list`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/content_blocks_templates/get_list_email_content_blocks) | `content_blocks.list` | | [`/content_blocks/info`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/content_blocks_templates/get_see_email_content_blocks_information) | `content_blocks.info` | | [`/content_blocks/create`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/content_blocks_templates/post_create_email_content_block) | `content_blocks.create` | | [`/content_blocks/update`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/content_blocks_templates/post_update_content_block) | `content_blocks.update` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Content Blocks" } #### Custom Attributes | Endpoint | Required permission | |----------|---------------------| | [`/custom_attributes`](https://www.braze.com/docs/ja/ja/api/endpoints/export/custom_attributes/get_custom_attributes) | `custom_attributes.get` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Custom Attributes" } #### Events | Endpoint | Required permission | |----------|---------------------| | [`/events/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/custom_events/get_custom_events) | `events.list` | | [`/events/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/custom_events/get_custom_events_analytics) | `events.data_series` | | [`/events`](https://www.braze.com/docs/ja/ja/api/endpoints/export/custom_events/get_custom_events_data) | `events.get` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Events" } #### KPIs | Endpoint | Required permission | |----------|---------------------| | [`/kpi/new_users/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/kpi/get_kpi_daily_new_users_date) | `kpi.new_users.data_series` | | [`/kpi/dau/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/kpi/get_kpi_dau_date) | `kpi.dau.data_series` | | [`/kpi/mau/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/kpi/get_kpi_mau_30_days) | `kpi.mau.data_series` | | [`/kpi/uninstalls/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/kpi/get_kpi_uninstalls_date) | `kpi.uninstalls.data_series` | {: .reset-td-br-1 .reset-td-br-2 aria-label="KPIs" } #### Media Library The `media_library.create` permission is a write permission. Add it only if you want your agent to upload assets to your media library. | Endpoint | Required permission | |----------|---------------------| | [`/media_library/create`](https://www.braze.com/docs/ja/ja/api/endpoints/media_library/manage_assets/create) | `media_library.create` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Media Library" } #### Messages | Endpoint | Required permission | |----------|---------------------| | [`/messages/scheduled_broadcasts`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/schedule_messages/get_messages_scheduled) | `messages.schedule_broadcasts` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Messages" } #### Preference Center | Endpoint | Required permission | |----------|---------------------| | [`/preference_center/v1/list`](https://www.braze.com/docs/ja/ja/api/endpoints/preference_center/get_list_preference_center) | `preference_center.list` | | [`/preference_center/v1/{preferenceCenterExternalID}`](https://www.braze.com/docs/ja/ja/api/endpoints/preference_center/get_view_details_preference_center) | `preference_center.get` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Preference Center" } #### Purchases | Endpoint | Required permission | |----------|---------------------| | [`/purchases/product_list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/purchases/get_list_product_id) | `purchases.product_list` | | [`/purchases/revenue_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/purchases/get_revenue_series) | `purchases.revenue_series` | | [`/purchases/quantity_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/purchases/get_number_of_purchases) | `purchases.quantity_series` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Purchases" } #### Segments | Endpoint | Required permission | |----------|---------------------| | [`/segments/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment) | `segments.list` | | [`/segments/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment_analytics) | `segments.data_series` | | [`/segments/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment_details) | `segments.details` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Segments" } #### Sends | Endpoint | Required permission | |----------|---------------------| | [`/sends/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_send_analytics) | `sends.data_series` | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Sends" } #### Sessions | Endpoint | Required permission | |----------|---------------------| | [`/sessions/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/sessions/get_sessions_analytics) | `sessions.data_series` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Sessions" } #### SDK Authentication Keys | Endpoint | Required permission | |----------|---------------------| | [`/app_group/sdk_authentication/keys`](https://www.braze.com/docs/ja/ja/api/endpoints/sdk_authentication/get_sdk_authentication_keys) | `sdk_authentication.keys` | {: .reset-td-br-1 .reset-td-br-2 aria-label="SDK Authentication Keys" } #### Subscription | Endpoint | Required permission | |----------|---------------------| | [`/subscription/status/get`](https://www.braze.com/docs/ja/ja/api/endpoints/subscription_groups/get_list_user_subscription_group_status) | `subscription.status.get` | | [`/subscription/user/status`](https://www.braze.com/docs/ja/ja/api/endpoints/subscription_groups/get_list_user_subscription_groups) | `subscription.groups.get` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Subscription" } #### Templates The `templates.email.create` and `templates.email.update` permissions are write permissions. Add them only if you want your agent to create or update email templates in your workspace. | Endpoint | Required permission | |----------|---------------------| | [`/templates/email/list`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/get_list_email_templates) | `templates.email.list` | | [`/templates/email/info`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/get_see_email_template_information) | `templates.email.info` | | [`/templates/email/create`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/post_create_email_template) | `templates.email.create` | | [`/templates/email/update`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/post_update_email_template) | `templates.email.update` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Templates" } **Warning:** Don't reuse an existing API key. Create one specifically for your MCP client. Assign only the permissions your agent needs. Agents may try to use any permission you grant, so leave any write permissions off if you don't want your agent to make changes in Braze. ### Step 3: Get your identifier and endpoint When you configure your MCP client, you'll need your API key's identifier and your workspace's REST endpoint. To get these details, go back to the **API Keys** page in the dashboard—keep this page open, so you can reference it during [the next step](#configure-client). ![The 'API Keys' in Braze showing a newly created API key and the user's REST endpoint.](https://www.braze.com/docs/ja/ja/assets/img/mcp_server/get_indentifer_and_endpoint.png?e439a42a44d6fcaeb410fb209b2c39bd){: style="max-width:85%;"} ### Step 4: Configure your MCP client {#configure-client} Configure your MCP client using the pre-provided configuration file. Set up your MCP server using the [Claude Desktop](https://claude.ai/download) connector directory. 1. In Claude Desktop, go to **Settings** > **Connectors** > **Browse Connectors** > **Desktop Extensions** > **Braze MCP Server** > **Install**. 2. Enter your API key and base URL. 3. Save the configuration and restart Claude Desktop. In [Cursor](https://cursor.com/), go to **Settings** > **Tools and Integrations** > **MCP Tools** > **Add Custom MCP**, then add the following snippet: ```json { "mcpServers": { "braze": { "command": "uvx", "args": ["--native-tls", "braze-mcp-server@latest"], "env": { "BRAZE_API_KEY": "your-braze-api-key", "BRAZE_BASE_URL": "your-braze-endpoint-url" } } } } ``` Replace `key-identifier` and `rest-endpoint` with the corresponding values from the **API Keys** page in Braze. Your configuration should be similar to the following: ```json { "mcpServers": { "braze": { "command": "uvx", "args": ["--native-tls", "braze-mcp-server@latest"], "env": { "BRAZE_API_KEY": "2e8b-3c6c-d12e-bd75-4f0e2a8e5c71", "BRAZE_BASE_URL": "https://torchie.braze.com" } } } } ``` When you're finished, save the configuration and restart Cursor. Gemini CLI reads user settings from `~/.gemini/settings.json`. If this doesn't exist, you can create it by running the following in your terminal: ```powershell mkdir -p ~/.gemini nano ~/.gemini/settings.json ``` Next, replace `yourname` with the exact string before `@BZXXXXXXXX` in your terminal prompt. Then, replace `key-identifier` and `rest-endpoint` with the corresponding values from the **API Keys** page in Braze. Your configuration should be similar to the following: ```json { "mcpServers": { "braze": { "command": "/Users/yourname/.local/bin/uvx", "args": ["--native-tls", "braze-mcp-server@latest"], "env": { "BRAZE_API_KEY": "2e8b-3c6c-d12e-bd75-4f0e2a8e5c71", "BRAZE_BASE_URL": "https://torchie.braze.com" } } } } ``` When you're finished, save the configuration and restart Gemini CLI. Then, in Gemini, run the following commands to verify that the Braze MCP server is listed and that the tools and schema are available for use: ```powershell gemini /mcp /mcp desc /mcp schema ``` You should see the `braze` server listed with the tools and schema available for use. ### Step 5: Send a test prompt After you set up the Braze MCP server, try sending a test prompt to your MCP client. For other examples and best practices, see [Using the Braze MCP server]. **Example prompt:** `What are my available Braze functions?` **Example response:** Used `list_functions` and returned the available Braze MCP function categories. **Example prompt:** `What are my available Braze functions?` **Example response:** Queried `list_functions` and listed functions such as `get_canvas_list`. **Example prompt:** `What are my available Braze functions?` **Example response:** Queried `list_functions` in Gemini CLI and returned available Braze MCP function categories and sample functions. ## Troubleshooting ### Terminal errors #### `uvx` command not found If you receive an error that `uvx` command not found, reinstall `uv` and restart your terminal. ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` #### `spawn uvx ENOENT` error If you receive a `spawn uvx ENOENT` errors, you may need to update the filepath in your client's config file. First, open your terminal and run the following command: ```bash which uvx ``` The command should return a message similar to the following: ```bash /Users/alex-lee/.local/bin/uvx ``` Copy the message to your clipboard and open [your client's config file](#configure-client). Replace `"command": "uvx"` with the path you copied, then restart your client. For example: ```json "command": "/Users/alex-lee/.local/bin/uvx" ``` #### Package installation fails If your package installation fails, try installing a specific Python version instead. ```bash uvx --python 3.12 braze-mcp-server@latest ``` ### Client configuration #### "This extension is not compatible with your device" If you see this error when installing the Braze MCP server extension, it may indicate one of the following: - **Your device doesn't meet the requirements**: Some MCP server extensions require specific operating system versions or hardware. - **Missing development tools (macOS only)**: On macOS, the extension installation requires command line developer tools to run Python commands. If these tools aren't installed, the installation will fail with this error. To install command line developer tools on macOS, run the following in your terminal: ```bash xcode-select --install ``` After installation completes, restart your MCP client and try installing the extension again. #### MCP client can't find the Braze server 1. Verify your MCP client configuration syntax is correct. 2. Restart your MCP client after configuration changes. 3. Check that `uvx` is in your system `PATH`. #### Authentication errors 1. Verify your `BRAZE_API_KEY` is correct and active. 2. Ensure your `BRAZE_BASE_URL` matches your Braze instance. 3. Check that your API key has the [correct permissions](#create-api-key). #### Connection timeouts or network errors 1. Verify your `BRAZE_BASE_URL` is correct for your instance. 2. Check your network connection and firewall settings. 3. Ensure you're using HTTPS in your base URL. ## Disclaimer The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is a newly introduced open-source protocol that may be susceptible to security issues or vulnerabilities at this time. Braze MCP Server setup code and instructions are provided by Braze “as is” and without any warranties, and customers use it at their own risk. Braze shall not be responsible for any consequences arising from improper setup, misuse of the MCP, or any potential security issues that may arise. Braze strongly encourages customers to review their configurations carefully and to follow the outlined guidelines to reduce risks associated with the integrity and security of their Braze environment. For assistance or clarification, please contact [Braze Support](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/support). # Braze MCPサーバーを使用する Source: /docs/ja/developer_guide/mcp_server/usage/index.md # Using the Braze MCP server > Learn how to interact with your Braze data through natural language using tools like Claude and Cursor. For more general information, see [Braze MCP server]. **Important:** The locally hosted Braze MCP server (beta) is sunsetting this summer. It will continue to work, but we're no longer adding endpoints or supporting the beta. A remote, Braze-hosted MCP server is coming to Early Access this summer. ## Prerequisites Before you can use this feature, you'll need to [set up the Braze MCP server]. ## Best practices When using the Braze MCP server through natural-language tools like Claude and Cursor, keep these tips in mind to get the best results: - LLMs can make mistakes, so always be sure to double-check their answers. - For data analysis, be clear about the time range you need. Shorter ranges often give more accurate results. - Use exact [Braze terminology](https://www.braze.com/resources/articles/glossary) so your LLM calls the right function. - If results seem incomplete, prompt your LLM to continue or dig deeper. - Try creative prompts! Depending on your MCP client, you may be able to export a CSV or other useful files. ## Usage examples After [setting up the Braze MCP server], you can interact with Braze through natural language using tools like Claude or Cursor. Here's some examples to get you started: ### What are my available Braze functions? **Example prompt** `What are my available Braze functions?` **Example response** I checked the Braze MCP server with `list_functions` and found 38 available API functions. Here are a few examples by category: - **Campaign analytics and management** - `get_campaign_dataseries` - `get_campaign_details` - `get_campaign_list` - **Canvas analytics and management** - `get_canvas_data_series` - `get_canvas_data_summary` - `get_canvas_list` - `get_canvas_details` - **Templates** - `create_email_template` - **Content blocks** - `create_content_block` - `get_content_blocks` - `get_content_block_info` - `update_content_block` **Example prompt** `What are my available Braze functions?` **Example response** I'll check your available functions using the Braze MCP server. - Called `list_functions` Based on that result, you have 38 Braze API functions organized into categories such as: - Campaign analytics and management - Canvas analytics and management - Templates - Content blocks Example functions include: - `get_campaign_list` - `get_canvas_list` - `get_canvas_details` - `create_email_template` - `update_content_block` For more information on the `list_functions` function, see [Available API functions]. ### Get details about a Canvas ID **Example prompt** `Get details about canvas ID YOUR-TEST-CANVAS-ID-123` **Example response** I retrieved details for `YOUR-TEST-CANVAS-ID-123` using `get_canvas_details`. - **Canvas name:** `YOUR-TEST-CANVAS-NAME` - **ID:** `YOUR-TEST-CANVAS-ID-123` - **Status:** Draft (not enabled) - **Created at:** Jan 15, 2026 10:30 AM UTC - **Last updated:** Jan 16, 2026 02:45 PM UTC - **Schedule type:** Time-based - **Primary channel:** Email Email message details: - **Subject:** `YOUR-TEST-SUBJECT-LINE` - **From:** `YOUR-TEST-SENDER@example.com` - **Message ID:** `YOUR-TEST-MESSAGE-ID-123` **Example prompt** `Get details about canvas ID YOUR-TEST-CANVAS-ID-123` **Example response** I pulled this Canvas using `get_canvas_details`: - **Canvas ID:** `YOUR-TEST-CANVAS-ID-123` - **Canvas name:** `YOUR-TEST-CANVAS-NAME` - **Status:** Draft - **Channel:** Email - **Message ID:** `YOUR-TEST-MESSAGE-ID-123` Email content summary: 1. Header section with brand image 2. Main headline section 3. Hero section with CTA button 4. Feature section with supporting content For more information on the `get_canvas_details` function, see [Available API functions]. ### Show me my recent Canvases **Example prompt** `Show me my recent Canvases` **Example response** I checked your available tools with `list_functions`, then used `get_canvas_list` to return your most recently edited Canvases. Most recent Canvases: 1. **YOUR-TEST-CANVAS-ALPHA** - ID: `YOUR-TEST-ID-123` - Last edited: Jan 16, 2026 02:45 PM UTC 2. **YOUR-TEST-CANVAS-BETA** - ID: `YOUR-TEST-ID-456` - Last edited: Jan 15, 2026 11:10 AM UTC 3. **YOUR-TEST-CANVAS-GAMMA** - ID: `YOUR-TEST-ID-789` - Last edited: Jan 14, 2026 08:25 PM UTC **Example prompt** `Show me my recent Canvases` **Example response** I'll retrieve your recent Canvas list from the Braze MCP server. - Called `list_functions` - Called `get_canvas_list` Recent Canvases (sorted by most recently edited): - **Canvas name:** `YOUR-TEST-CANVAS-ALPHA` - **Last edited:** Jan 16, 2026 02:45 PM UTC - **Canvas ID:** `YOUR-TEST-ID-123` - **Tags:** `lifecycle`, `email` - **Canvas name:** `YOUR-TEST-CANVAS-BETA` - **Last edited:** Jan 15, 2026 11:10 AM UTC - **Canvas ID:** `YOUR-TEST-ID-456` - **Tags:** `promo` For more information on the `get_canvas_list` function, see [Available API functions]. ### Create an email template **Example prompt** `Create an email template named "YOUR-TEST-TEMPLATE-NAME" for onboarding messages.` **Example response** I created your template with `create_email_template`. - **Template name:** `YOUR-TEST-TEMPLATE-NAME` - **Template ID:** `YOUR-TEST-TEMPLATE-ID-123` - **Subject line:** `YOUR-TEST-SUBJECT-LINE` - **Preheader:** `YOUR-TEST-PREHEADER` - **Created at:** Jan 16, 2026 03:10 PM UTC You can now reference `YOUR-TEST-TEMPLATE-ID-123` when creating or updating campaigns and Canvases. **Example prompt** `Create an email template named "YOUR-TEST-TEMPLATE-NAME" for onboarding messages.` **Example response** I used `create_email_template` and created a new template successfully. - **Template ID:** `YOUR-TEST-TEMPLATE-ID-123` - **Template name:** `YOUR-TEST-TEMPLATE-NAME` - **Subject:** `YOUR-TEST-SUBJECT-LINE` - **Description:** `Onboarding lifecycle template` If you'd like, I can also generate a starter HTML body and plain-text fallback for this template. For more information on the `create_email_template` function, see [Available API functions]. ### Update a content block **Example prompt** `Update content block "YOUR-TEST-CONTENT-BLOCK-ID-123" with new body copy for our spring promotion.` **Example response** I updated your content block using `update_content_block`. - **Content block ID:** `YOUR-TEST-CONTENT-BLOCK-ID-123` - **Name:** `YOUR-TEST-CONTENT-BLOCK-NAME` - **Status:** Updated - **Updated at:** Jan 16, 2026 03:25 PM UTC Preview: `YOUR-TEST-CONTENT-BLOCK-BODY-V2` **Example prompt** `Update content block "YOUR-TEST-CONTENT-BLOCK-ID-123" with new body copy for our spring promotion.` **Example response** I ran `update_content_block` and confirmed the update completed. - **Content block ID:** `YOUR-TEST-CONTENT-BLOCK-ID-123` - **Previous version:** `v1` - **Current version:** `v2` - **Last updated:** Jan 16, 2026 03:25 PM UTC Updated content preview: `YOUR-TEST-CONTENT-BLOCK-BODY-V2` For more information on the `update_content_block` function, see [Available API functions]. ## Disclaimer The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is a newly introduced open-source protocol that may be susceptible to security issues or vulnerabilities at this time. Braze MCP Server setup code and instructions are provided by Braze “as is” and without any warranties, and customers use it at their own risk. Braze shall not be responsible for any consequences arising from improper setup, misuse of the MCP, or any potential security issues that may arise. Braze strongly encourages customers to review their configurations carefully and to follow the outlined guidelines to reduce risks associated with the integrity and security of their Braze environment. For assistance or clarification, please contact [Braze Support](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/support). # Braze MCPサーバーで利用可能なAPI関数 Source: /docs/ja/developer_guide/mcp_server/available_api_functions/index.md # Braze MCP server functions > The Braze MCP server exposes a set of API functions that map to specific Braze REST API endpoints. MCP clients like Claude and Cursor can call these functions to retrieve non-PII data and, with the right permissions, perform non-PII write actions. For more general information, see [Braze MCP server]. **Important:** The locally hosted Braze MCP server (beta) is sunsetting this summer. It will continue to work, but we're no longer adding endpoints or supporting the beta. A remote, Braze-hosted MCP server is coming to Early Access this summer. ## Prerequisites Before you can use this feature, you'll need to [set up the Braze MCP server]. ## Available Braze API functions Your MCP client references the following API functions to interact with the Braze MCP server. ### General functions These functions help your MCP client discover and run the available Braze API functions. | Function | Description | |----------|-------------| | `list_functions` | Lists all available Braze API functions with their descriptions and parameters. | | `call_function` | Calls a specific read-only Braze API function with the provided parameters. | | `call_write_function` | Calls a specific write-capable Braze API function with the provided parameters. | {: .reset-td-br-1 .reset-td-br-2 aria-label="General functions" } ### Campaigns | Function | Endpoint | Description | |----------|----------|-------------| | `get_campaign_list` | [`/campaigns/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaigns) | Export a list of campaigns with metadata. | | `get_campaign_details` | [`/campaigns/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaign_details) | Get detailed information about specific campaigns. | | `get_campaign_dataseries` | [`/campaigns/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaign_analytics) | Retrieve time series analytics data for campaigns. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Campaigns" } ### Canvases | Function | Endpoint | Description | |----------|----------|-------------| | `get_canvas_list` | [`/canvas/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvases) | Export a list of Canvases with metadata. | | `get_canvas_details` | [`/canvas/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvas_details) | Get detailed information about specific Canvases. | | `get_canvas_data_summary` | [`/canvas/data_summary`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvas_analytics_summary) | Get summary analytics for Canvas performance. | | `get_canvas_data_series` | [`/canvas/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvas_analytics) | Retrieve time series analytics data for Canvases. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Canvases" } ### Catalogs | Function | Endpoint | Description | |----------|----------|-------------| | `get_catalogs` | [`/catalogs`](https://www.braze.com/docs/ja/ja/api/endpoints/catalogs/catalog_management/synchronous/get_list_catalogs) | Return a list of catalogs in a workspace. | | `get_catalog_items` | [`/catalogs/{catalog_name}/items`](https://www.braze.com/docs/ja/ja/api/endpoints/catalogs/catalog_items/synchronous/get_catalog_items_details_bulk) | Return multiple catalog items and their content with pagination support. | | `get_catalog_item` | [`/catalogs/{catalog_name}/items/{item_id}`](https://www.braze.com/docs/ja/ja/api/endpoints/catalogs/catalog_items/synchronous/get_catalog_item_details) | Return a specific catalog item and its content by ID. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Catalogs" } ### Cloud Data Ingestion | Function | Endpoint | Description | |----------|----------|-------------| | `list_integrations` | [`/cdi/integrations`](https://www.braze.com/docs/ja/ja/api/endpoints/cdi/get_integration_list) | Return a list of existing CDI integrations. | | `get_integration_job_sync_status` | [`/cdi/integrations/{integration_id}/job_sync_status`](https://www.braze.com/docs/ja/ja/api/endpoints/cdi/get_job_sync_status) | Return past sync statuses for a given CDI integration. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Cloud Data Ingestion" } ### Content Blocks The `create_content_block` and `update_content_block` functions are write functions. Your MCP client must call them with `call_write_function`, and your API key must have the matching `content_blocks.create` or `content_blocks.update` permission. | Function | Endpoint | Description | |----------|----------|-------------| | `get_content_blocks_list` | [`/content_blocks/list`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/content_blocks_templates/get_list_email_content_blocks) | List your available content blocks. | | `get_content_blocks_info` | [`/content_blocks/info`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/content_blocks_templates/get_see_email_content_blocks_information) | Get information on your content blocks. | | `create_content_block` | [`/content_blocks/create`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/content_blocks_templates/post_create_email_content_block) | Create a content block. Requires `name` and `content`. Optional fields are `description`, `state` (must be `active` or `draft`), and `tags`. | | `update_content_block` | [`/content_blocks/update`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/content_blocks_templates/post_update_content_block) | Update an existing content block. Requires `content_block_id` and at least one updatable field: `name`, `content`, `description`, `state` (must be `active` or `draft`), or `tags`. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Content Blocks" } ### Custom Attributes | Function | Endpoint | Description | |----------|----------|-------------| | `get_custom_attributes` | [`/custom_attributes`](https://www.braze.com/docs/ja/ja/api/endpoints/export/custom_attributes/get_custom_attributes) | Export custom attributes recorded for your app. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Custom Attributes" } ### Events | Function | Endpoint | Description | |----------|----------|-------------| | `get_events_list` | [`/events/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/custom_events/get_custom_events) | Export a list of custom events recorded for your app. | | `get_events_data_series` | [`/events/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/custom_events/get_custom_events_analytics) | Retrieve time series data for custom events. | | `get_events` | [`/events`](https://www.braze.com/docs/ja/ja/api/endpoints/export/custom_events/get_custom_events_data) | Get detailed event data with pagination support. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Events" } ### KPIs | Function | Endpoint | Description | |----------|----------|-------------| | `get_new_users_data_series` | [`/kpi/new_users/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/kpi/get_kpi_daily_new_users_date) | Daily series of new user counts. | | `get_dau_data_series` | [`/kpi/dau/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/kpi/get_kpi_dau_date) | Daily Active Users time series data. | | `get_mau_data_series` | [`/kpi/mau/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/kpi/get_kpi_mau_30_days) | Monthly Active Users time series data. | | `get_uninstalls_data_series` | [`/kpi/uninstalls/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/kpi/get_kpi_uninstalls_date) | App uninstall time series data. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="KPIs" } ### Media Library The `create_media_library_asset` function is a write function. Your MCP client must call it with `call_write_function`, and your API key must have the `media_library.create` permission. | Function | Endpoint | Description | |----------|----------|-------------| | `create_media_library_asset` | [`/media_library/create`](https://www.braze.com/docs/ja/ja/api/endpoints/media_library/manage_assets/create) | Upload an asset to your Braze media library. You can provide either a publicly accessible URL (`asset_url`) or a base64-encoded file (`asset_file_base64`), but not both. Images have a 5 MB size limit. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Media Library" } ### Messages | Function | Endpoint | Description | |----------|----------|-------------| | `get_scheduled_broadcasts` | [`/messages/scheduled_broadcasts`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/schedule_messages/get_messages_scheduled) | List upcoming scheduled campaigns and Canvases. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Messages" } ### Preference Centers | Function | Endpoint | Description | |----------|----------|-------------| | `get_preference_centers` | [`/preference_center/v1/list`](https://www.braze.com/docs/ja/ja/api/endpoints/preference_center/get_list_preference_center) | List your available preference centers. | | `get_preference_center_details` | [`/preference_center/v1/{preferenceCenterExternalID}`](https://www.braze.com/docs/ja/ja/api/endpoints/preference_center/get_view_details_preference_center) | View details for a specific preference center including HTML content and options. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Preference Centers" } ### Purchases | Function | Endpoint | Description | |----------|----------|-------------| | `get_product_list` | [`/purchases/product_list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/purchases/get_list_product_id) | Export paginated list of product IDs. | | `get_revenue_series` | [`/purchases/revenue_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/purchases/get_revenue_series) | Revenue analytics time series data. | | `get_quantity_series` | [`/purchases/quantity_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/purchases/get_number_of_purchases) | Purchase quantity time series data. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Purchases" } ### Segments | Function | Endpoint | Description | |----------|----------|-------------| | `get_segment_list` | [`/segments/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment) | Export list of segments with analytics tracking status. | | `get_segment_data_series` | [`/segments/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment_analytics) | Time series analytics data for segments. | | `get_segment_details` | [`/segments/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment_details) | Detailed information about specific segments. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Segments" } ### Sends | Function | Endpoint | Description | |----------|----------|-------------| | `get_send_data_series` | [`/sends/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_send_analytics) | Daily analytics for tracked campaign sends. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Sends" } ### Sessions | Function | Endpoint | Description | |----------|----------|-------------| | `get_session_data_series` | [`/sessions/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/sessions/get_sessions_analytics) | Time series data for app session counts. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Sessions" } ### SDK Authentication Keys | Function | Endpoint | Description | |----------|----------|-------------| | `get_sdk_authentication_keys` | [`/app_group/sdk_authentication/keys`](https://www.braze.com/docs/ja/ja/api/endpoints/sdk_authentication/get_sdk_authentication_keys) | List all SDK Authentication keys for your app. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="SDK Authentication Keys" } ### Subscription | Function | Endpoint | Description | |----------|----------|-------------| | `get_user_subscription_groups` | [`/subscription/user/status`](https://www.braze.com/docs/ja/ja/api/endpoints/subscription_groups/get_list_user_subscription_groups) | List and get the subscription groups of a certain user. | | `get_subscription_group_status` | [`/subscription/status/get`](https://www.braze.com/docs/ja/ja/api/endpoints/subscription_groups/get_list_user_subscription_group_status) | Get the subscription state of a user in a subscription group. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Subscription" } ### Templates The `create_email_template` and `update_email_template` functions are write functions. Your MCP client must call them with `call_write_function`, and your API key must have the matching `templates.email.create` or `templates.email.update` permission. | Function | Endpoint | Description | |----------|----------|-------------| | `get_email_templates_list` | [`/templates/email/list`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/get_list_email_templates) | List your available email templates. | | `get_email_template_info` | [`/templates/email/info`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/get_see_email_template_information) | Get information on your email templates. | | `create_email_template` | [`/templates/email/create`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/post_create_email_template) | Create an email template. Requires `template_name`, `subject`, and `body`. Optional fields are `plaintext_body`, `preheader`, `tags`, and `should_inline_css`. | | `update_email_template` | [`/templates/email/update`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/post_update_email_template) | Update an existing email template. Requires `email_template_id` and at least one updatable field: `template_name`, `subject`, `body`, `plaintext_body`, `preheader`, `tags`, or `should_inline_css`. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Templates" } ## Disclaimer The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/docs/getting-started/intro) is a newly introduced open-source protocol that may be susceptible to security issues or vulnerabilities at this time. Braze MCP Server setup code and instructions are provided by Braze “as is” and without any warranties, and customers use it at their own risk. Braze shall not be responsible for any consequences arising from improper setup, misuse of the MCP, or any potential security issues that may arise. Braze strongly encourages customers to review their configurations carefully and to follow the outlined guidelines to reduce risks associated with the integrity and security of their Braze environment. For assistance or clarification, please contact [Braze Support](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/support). # BrazeAI Decisioning Studio™ を始める Source: /docs/ja/developer_guide/decisioning_studio/index.md # BrazeAI Decisioning Studio™ > Get started with BrazeAI Decisioning Studio™ (formerly OfferFit by Braze) to make 1:1 AI decisions that maximize your business metrics. ## What is BrazeAI Decisioning Studio™? [BrazeAI Decisioning Studio™](https://www.braze.com/product/brazeai-decisioning-studio/) replaces A/B testing with decisioning agents that personalize everything, and maximize any metric: drive dollars, not clicks—with Decisioning Studio, you can optimize any business metric. BrazeAI™ decisioning agents automatically discover the optimal action for every customer. Using your first-party data, BrazeAI™ can maximize any business KPI for a wide range of use cases, including cross-sell, upsell, repurchase, retention, renewal, referral, winback, and more. To learn more, or get started with Decisioning Studio, [book a call](https://www.braze.com/get-started/) with Braze. ![Overview of the Decisioning Studio feedback loop](https://www.braze.com/docs/ja/ja/assets/img/decisioning_studio/decisioniong_studio_feedback_loop.png?e6a6335904325ae3e2123e0e60cbac18) ## Key features - **Keep your tech stack, but add a brain:** BrazeAI™ plugs in as a decisioning layer between your data systems and your customer engagement platform. While Decisioning Studio works best with Braze, a variety of other platforms are supported. - **Pick winners for people, not segments:** Use all your first-party data to make the optimal 1:1 decision for each individual. - **Personalize everything:** AI decisioning agents find the best message, product, incentive, channel, timing, and frequency for each individual customer - **Maximize any metric:** Clicks aren’t dollars. Use BrazeAI™ to pick the offers or incentives that maximize revenue, profit, CLV, or any other business KPI. - **Open the black box:** See how AI decisioning agents personalize for deep insights into the drivers of customer behavior - **Expert support all the way:** Decisioning Studio Pro includes support from our AI Decisioning Services team, which will tailor your decisioning agents to the specific needs of your business. ## About Decisioning Studio ### How it works BrazeAI Decisioning Studio™ allows you to design and deploy decisioning agents that optimize any business metric. To set up Decisioning Studio, you will: - Connect data sources that tell the Agent how a customer reacts to its decisions - Configure orchestration to carry out the decisioning agent's actions - Design your decisioning agent to define what outcome you want to maximize, and what actions the agent can take to do so. - Launch your decisioning agent and let it continuously learn and optimize for your business outcomes. While Decisioning Studio Go is a self-service platform, Decisioning Studio Pro includes AI Decisioning Services support from Braze’s forward deployed data science team, which will help you design and configure your agent to maximize your business outcomes. See [Decisioning Studio Go vs. Decisioning Studio Pro](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/#decisioning-studio-go-vs-decisioning-studio-pro) for more details. For more details, see [Get Started with Decisioning Studio](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/get_started/). ### Decisioning Agents vs. BrazeAI Agents While both are powered by BrazeAI™, decisioning agents and Braze Agents serve different purposes in your marketing stack. **Decisioning agents** are the strategic orchestrators of your campaigns. They operate at the campaign level, continuously running experiments across dimensions like offer, channel, timing, and frequency to maximize a business metric such as revenue, conversions, or ARPU. A decisioning agent manages an entire use case—such as winback, cross-sell, or renewal—learning over time what combination of actions works best for each individual customer. **Braze Agents** are AI-powered helpers that live within individual Canvas steps or catalog fields. They use large language models (LLMs) to generate content (like personalized subject lines or message copy), make routing decisions based on customer context, or enrich your catalogs with dynamically generated values. Braze Agents excel at bringing creativity and personalization to specific touchpoints within your campaign. Think of it this way: a decisioning agent is the conductor orchestrating your entire campaign strategy, while Braze Agents are the musicians adding creativity and nuance to each individual moment in the customer journey. You can use them together—let a decisioning agent determine the optimal offer and channel for each customer, then use a Braze Agent to generate personalized copy for that specific message. ## Decisioning Studio Go vs. Decisioning Studio Pro Decisioning Studio offers two tiers: Go and Pro. Each tier is designed to meet different needs and use cases. ### Decisioning Studio Go Go is ideal for teams getting started with AI decisioning. It includes: - Self-serve creative configuration with a pre-designed decisioning agent - Success metric focused on clicks - Compatibility with three Customer Engagement Platforms (CEPs): Braze, Salesforce Marketing Cloud, and Klaviyo ### Decisioning Studio Pro Pro offers the full suite of Decisioning Studio capabilities for advanced use cases. Key features include: - A dedicated AI Decisioning Services team to support you from decisioning agent design through stable state - Success metric can be any business metric (not just clicks) - Ability to connect any customer data source for decisioning - Full suite of reporting and insights - Extended orchestration patterns ### About this guide In this guide, you first learn what decisioning agents are and how they work. Next, you set up the self-service Decisioning Studio Go, followed by the full-service Decisioning Studio Pro. Finally, you review reports and insights to understand the performance of your decisioning agents. ## Next steps 1. [Get Started with Decisioning Studio](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/get_started/) 2. [Setting up Decisioning Studio Go](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/decisioning_studio_go/) 3. [Get Started with Decisioning Studio](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/get_started/) 4. [Viewing reports and insights](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/reporting/) # BrazeAI Decisioning Studio™を統合する Source: /docs/ja/developer_guide/decisioning_studio/integration/index.md # Integrating BrazeAI Decisioning Studio™ > Learn how to integrate BrazeAI Decisioning Studio™ into Braze and partner with the AI Expert Services team to [build agents](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/building_agents) that apply AI for 1:1 decision-making to improve your key business metrics. **Important:** While BrazeAI Decisioning Studio™ works best with Braze, a variety of other platforms are already supported. We'll continue updating our documentation so you'll have everything you need—even if you're not using Braze. ## Prerequisites Before you can integrate, you'll need an active BrazeAI Decisioning Studio™ license. Interested in learning more? [Book a call](https://www.braze.com/get-started/). ## Integrating decision studio ### Step 1: Get your endpoint URL You'll need to get the endpoint URL associated with your specific Braze instance. For more information, see [Braze API endpoints](https://www.braze.com/docs/ja/ja/developer_guide/rest_api/basics/#endpoints). ### Step 2: Create an API key In Braze, go to **Settings** > **API Keys**, then create a new key with the following permissions: | Permission | Purpose | Required? | | :--- | ----- | :---: | | [`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track) | Updates custom attributes on user profiles, in addition to creating temporary user profiles when using test sends. | ✓ | | [`/users/delete`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_delete) | Deletes temporary user profiles that were created while using test sends. | Only for test sends | | [`/users/export/segment`](https://www.braze.com/docs/ja/ja/api/endpoints/export/user_data/post_users_segment) | Updates the available audience communications every morning by exporting the list of users from each selected segment. | ✓ | | [`/users/export/ids`](https://www.braze.com/docs/ja/ja/api/endpoints/export/user_data/post_users_identifier) | Retrieves a list of identifiers when targeting users using an `external_id` instead of a segment. Since Decisioning Studio doesn’t accept Personally Identifiable Information (PII), you'll need to ensure your `fields_to_export` parameter returns only non-PII fields. | Only if using `external_ids` | | [`/messages/send`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages) | Sends recommended variants at the recommended time using API Campaigns that are configured for Decisioning Studio's experimenter. | ✓ | | [`/campaigns/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaigns/#prerequisites) | Retrieves the list of active campaigns and extracts available email content for experimentation. | ✓ | | [`/campaigns/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaign_analytics) | Exports aggregated campaign data to enable reporting, validation, and troubleshooting in Decisioning Studio, so you can compare reporting values and analyze baseline performance.

While not required, this permission is recommended. | | | [`/campaigns/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/campaigns/get_campaign_details) | Retrieves HTML content, subject line, and image resources from existing Campaigns for experimentation. | ✓ | | [`/canvas/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvases) | Retrieves the list of active Canvases to extract available email content for experimentation. | ✓ | | [`/canvas/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvas_analytics) | Exports aggregated canvas data for reporting and validation, especially when BAU is orchestrated via Canvas.

While not required, this permission is recommended. | | | [`/canvas/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/canvas/get_canvas_details/#prerequisites) | Retrieves HTML content, subject line, and image resources from existing Canvases for experimentation. | ✓ | | [`/segments/list`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment) | Retrieves all existing segments as potential target audiences for the Decisioning Studio experimenter. | ✓ | | [`/segments/data_series`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment_analytics) | Exports segment size information, which is shown in Decisioning Studio when selecting an audience. | ✓ | | [`/segments/details`](https://www.braze.com/docs/ja/ja/api/endpoints/export/segments/get_segment_details/#prerequisites) | Retrieves segment details such as entry and exit criteria to help understand changes in audience size or performance. | | | [`/templates/email/create`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/post_create_email_template) | Creates copies of selected base HTML templates with [dynamic placeholders](https://www.braze.com/docs/ja/ja/user_guide/personalization_and_dynamic_content/liquid) (Braze liquid tags) for experimentation, avoiding changes to the originals. | ✓ | | [`/templates/email/update`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/post_update_email_template) | Pushes updates to Decisioning Studio-created template copies when experimentation criteria change, such as call-to-actions. | ✓ | | [`/templates/email/info`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/get_see_email_template_information/#prerequisites) | Retrieves information about Decisioning Studio-created templates in your Braze instance. | ✓ | | [`/templates/email/list`](https://www.braze.com/docs/ja/ja/api/endpoints/templates/email_templates/get_list_email_templates) | Validates that templates were successfully copied over to your Braze instance. | ✓ | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Table" } ### Step 3: Contact your BrazeAI Decisioning Studio™ customer success manager Contact your BrazeAI Decisioning Studio™ customer success manager and ask them to enable BrazeAI Decisioning Studio™. They'll use your Braze API key and endpoint URL to finish setting up your integration. When it's complete, you'll work alongside the AI Expert Services team to [start building agents for your product](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/building_agents). Each agent is tailor-made to a specific business goal, so you'll work together to design an implementation that's right for you. # BrazeAI Decisioning Studio™ のエージェントを構築する Source: /docs/ja/developer_guide/decisioning_studio/building_agents/index.md # Building AI decisioning agents > Learn how to build an agent for BrazeAI Decisioning Studio™, so you can automate personalized experimentation and optimize outcomes like conversions, retention, or revenue—without manual A/B testing. **Important:** While BrazeAI Decisioning Studio™ works best with Braze, a variety of other platforms are already supported. We'll continue updating our documentation so you'll have everything you need—even if you're not using Braze. ## About agents An AI decisioning agent is a custom configuration for the BrazeAI™ decisioning engine that's tailor-made to meet a specific business goal. For example, you could build a repeat purchase agent to increase follow-up conversions after an initial sale. You define the audience and message in Braze, while your decisioning agents runs daily experiments and automatically tests different combinations of product offers, message timing, and frequency for each customer. Over time, BrazeAI™ learns what works best and orchestrates personalized sends through Braze to maximize repurchase rates. To build a good agent, you'll: - Choose a success metric for BrazeAI™ to optimize for, such as revenue, conversions, or ARPU. - Define which dimensions to test, such as offer, subject line, creative, channel, or send time. - Select the options for each dimension, such as email versus SMS, or daily versus weekly frequency. ![Example diagram of a Decisioning Studio agent for referral emails.](https://www.braze.com/docs/ja/ja/assets/img/offerfit/example_use_cases_referral_email.png?5630af24b92ce66087a1fa741168a9e6) ## Sample agents Here are some examples of agents that you can build with BrazeAI Decisioning Studio™. Your AI decisioning agents will learn from every customer interaction and apply those insights to the next day's actions. | Agent use case | Business goal | Using typical methods | Using BrazeAI Decisioning Studio™ | |---------------------------------|----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Cross-Sell or Upsell** | Maximize average revenue per user (ARPU) from internet subscriptions. | Run annual campaigns offering every customer the next-highest tier plan. | Empirically discover the best message, sending time, discount, and plan to offer for each customer, learning which customers are susceptible to leapfrog offers and which customers require discounts or other incentives to upgrade. | | **Renewal & Retention** | Secure contract renewals, maximizing both contract length and net present value (NPV). | A/B test manually, and offer significant discounts to secure renewals. | Use automated experimentation to find the best renewal offer for each customer, and identify customers who are less price sensitive and need less significant discounts to renew. | | **Repeat Purchase** | Maximize purchase and repurchase rates. | All customers receive the same journey after making a website account (such as the same email sequence with the same cadence). | Automate experimentation to find the best menu item to offer each customer, as well as the most effective subject line, sending time, and frequency of communication. | | **Winback** | Increase reactivation by encouraging past subscribers to resubscribe. | Sophisticated A/B testing and segmentation. | Leverage automated experimentation to test thousands of variables at once, discovering the best creative, message, channel and cadence for each individual. | | **Referral** | Maximize new accounts opened through business credit card referrals from existing customers. | Fixed email sequence for all customers, with extensive A/B testing to determine the best sending times, cadence, etc. for the customer population. | Automate experimentation to determine ideal email, creative, sending time, and credit card to offer specific customers. | | **Lead Nurturing & Conversion** | Drive incremental revenue and pay the right amount for each customer. | As privacy policies change at Facebook and other platforms, prior approaches to personalized paid ads become last effective. | Leverage robust first-party data to automatically experiment on customer segments, biding methodology, bid levels, and creative. | | **Loyalty & Engagement** | Maximize purchases by new enrollees in a customer loyalty program. | Customers received a fixed sequence of emails in response to their actions. For example, all new enrollees in the loyalty program receive the same journey. | Experiment automatically with different email offers, sending times, and frequencies to maximize purchase and repurchase for each customer. | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="Table" } ## Building an agent ### Prerequisites Before you can build an agent, you'll need to [integrate BrazeAI Decisioning Studio™](https://www.braze.com/docs/ja/ja/user_guide/brazeai/decisioning_studio/integration). ### Step 1: Contact AI Expert Services The AI Expert Services team will work closely with you to scope, design, and build your decisioning agent. If you haven't already, [contact us](https://www.braze.com/get-started/) to get started. You'll complete the following steps together to build a custom agent that's right for you. ### Step 2: Design your agent Alongside the AI Expert Services team, you'll define: - a target audience, - the business metric to optimize, - the actions for BrazeAI™ decisioning agent, and - any first-party customer data the agent should leverage to drive your business outcomes. With the design in hand, the team will work with you to identify and complete any additional integration requirements. ### Step 3: Set up your delivery platform Next, the AI Expert Service team will help you set up your customer engagement platform. While the Decisioning Studio works best with Braze, a variety of other platforms are supported—contact your AI Expert Service team for additional resources. To set up Braze: 1. Create a [campaign](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/campaigns/building_campaigns/delivery_types/api_triggered_delivery/) or [Canvas](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/canvas/create_a_canvas/create_a_canvas/?tab=api-triggered%20delivery#step-2b-determine-your-canvas-entry-schedule). BrazeAI Decisioning Studio™ will use this delivery method to send 1:1 personalized activation events to the users in your defined audience. 2. Be sure you don't include a Braze [control group](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/testing/multivariant_testing/create_multivariate_campaign#including-a-control-group), so BrazeAI™ can be the dedicated control group instead. 3. Depending on your dimensions, you can configure Liquid tags in your creative content to dynamically populate your messaging with BrazeAI™ recommendations. BrazeAI™ will pass customer-specific content to the Liquid tags in your templates using the Braze API. ### Step 4: Launch and monitor After launching your agent, your AI Expert Services team will continue to monitor and tune it to your agreed-upon design. They'll also help you make any adjustments, expansions, or modifications to the agent, if needed. # REST APIを使ってメッセージを送信する Source: /docs/ja/developer_guide/rest_api/sending_messages/index.md # REST APIを使ってメッセージを送信する {#sending-messages-using-the-rest-api} > バックエンドからリアルタイムでメッセージを送信するには、2つの異なるBrazeエンドポイントを使用できます。それぞれリクエストの形式が異なります。1つはリクエストにメッセージの全内容を含める方式で、もう1つはキャンペーンIDを指定してダッシュボードで定義されたコンテンツを送信する方式です。 この方法は、APIがサポートするあらゆるメッセージングチャネル(WhatsApp、メール、SMS、プッシュ通知、Content Cards、webhookなど)で利用できます。 ## 2つの送信方法 {#two-ways-to-send} | | [`/messages/send`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages) | [`/campaigns/trigger/send`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_triggered_campaigns) | | --- | --- | --- | | **キャンペーンID** | オプション。ダッシュボードでのキャンペーントラッキングなしで送信する場合は省略します。または、各メッセージにAPIキャンペーンIDと`message_variation_id`を付加してダッシュボードでトラッキングします。 | 必須。 | | **メッセージの内容** | リクエストに`messages`オブジェクトを含める必要があります(例:`messages.whats_app`、`messages.email`)。 | 受け付けられません。メッセージの内容は、Brazeダッシュボード内のキャンペーンで定義されます。 | | **ユースケース** | APIリクエストで内容を完全に指定したメッセージを送信します。 | APIを介して、特定の受信者に対して事前作成されたキャンペーン(ダッシュボード内のコンテンツ)をトリガーします。 | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="2つの送信方法" } リクエストとレスポンスの詳細については、[メッセージを即時送信(APIのみ)](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages)および[APIトリガー配信を使用したキャンペーン送信](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_triggered_campaigns)のエンドポイントリファレンスを参照してください。 --- ## オプション1:リクエストにメッセージ内容を含めて送信する(`/messages/send`) {#option-1-send-with-message-content-in-the-request-messagessend} APIリクエストでメッセージの全内容を指定したい場合に、このエンドポイントを使用します。`messages`オブジェクトを含める**必要があります**(例:`messages.whats_app`、`messages.email`、`messages.sms`)。キャンペーントラッキングなしで送信するには`campaign_id`を省略できます。または、各メッセージにAPIキャンペーンIDと`message_variation_id`を含めることで、ダッシュボードで送信をトラッキングできます(詳細は[エンドポイントリファレンス](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages)を参照してください)。 **必須:** `messages.send`権限付きのAPIキー。 **Important:** `external_user_ids`の各受信者は、Brazeに既に存在している必要があります。送信の一環としてユーザーを作成するには、まず[`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)を使用するか、代わりに[オプション2](#option-2-trigger-a-campaign-with-content-in-the-dashboard-campaignstriggersend)(APIトリガー型キャンペーン)を使用してください。 ### 例:WhatsAppテンプレートメッセージ {#example-whatsapp-template-message} ``` POST YOUR_REST_ENDPOINT/messages/send Content-Type: application/json Authorization: Bearer YOUR_REST_API_KEY ``` ```json { "external_user_ids": ["user123"], "messages": { "whats_app": { "app_id": "YOUR_APP_ID", "subscription_group_id": "YOUR_WHATSAPP_SUBSCRIPTION_GROUP_ID", "message_type": "template_message", "message": { "template_name": "new_message_received", "template_language_code": "en_US" } } } } ``` WhatsAppオブジェクトの完全な仕様については、[WhatsAppオブジェクト](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/whats_app_object)を参照してください。 **Note:** `/messages/send`エンドポイントは、TEXTまたはIMAGEヘッダーを持つWhatsAppテンプレートのみをサポートしています。DOCUMENT、VIDEO、その他のメディアヘッダータイプについては、代わりに[APIトリガー型キャンペーンエンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_triggered_campaigns)またはBrazeダッシュボードを使用してください。 ### 例:メール {#example-email} ```json { "external_user_ids": ["user123"], "messages": { "email": { "app_id": "YOUR_APP_ID", "subject": "Your order has shipped", "from": "no-reply@example.com", "body": "

Your order #12345 is on its way.

" } } } ``` 他のチャネルについては、[メッセージングオブジェクト](https://www.braze.com/docs/ja/ja/api/objects_filters#messaging-objects)を参照してください。 --- ## オプション2:ダッシュボードのコンテンツでキャンペーンをトリガーする(`/campaigns/trigger/send`) {#option-2-trigger-a-campaign-with-content-in-the-dashboard-campaignstriggersend} メッセージの内容がBrazeダッシュボードで作成されている場合(APIトリガー型キャンペーン)に、このエンドポイントを使用します。**必須**の`campaign_id`と受信者を送信します。`messages`オブジェクトは送信**しません**。 **必須:** `campaigns.trigger.send`権限付きのAPIキー。 ### ステップ1:APIトリガー型キャンペーンを作成する {#step-1-create-an-api-triggered-campaign} 1. Brazeダッシュボードで、**メッセージング** > **キャンペーン**に移動します。 2. **キャンペーンを作成**を選択し、次に**APIトリガー型キャンペーン**(「APIキャンペーン」ではありません)を選択します。 3. メッセージチャネル(WhatsApp、メール、SMSなど)を追加し、ダッシュボードでメッセージ内容を作成します。 4. **キャンペーン ID**(複数のメッセージバリアントを使用する場合は**Send ID**も)をメモしておきます。これらをAPIリクエストで使用します。 APIトリガー型キャンペーンの作成に関する詳細は、[APIトリガー配信](https://www.braze.com/docs/ja/ja/user_guide/messaging/campaigns/schedule_your_campaign/api_triggered_delivery)を参照してください。 ### ステップ2:API経由でキャンペーンをトリガーする {#step-2-trigger-the-campaign-via-the-api} `campaign_id`と`recipients`(または`broadcast`/`audience`)を指定して、`/campaigns/trigger/send`にPOSTリクエストを送信します。`messages`オブジェクトは含めないでください。コンテンツはキャンペーンから取得されます。 ``` POST YOUR_REST_ENDPOINT/campaigns/trigger/send Content-Type: application/json Authorization: Bearer YOUR_REST_API_KEY ``` ```json { "campaign_id": "YOUR_CAMPAIGN_ID", "recipients": [ { "external_user_id": "user123" } ] } ``` リクエスト本文の全体(`trigger_properties`、`send_to_existing_only`、`attributes`などを含む)については、[APIトリガー配信を使用したキャンペーン送信](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_triggered_campaigns#request-body)のエンドポイントリファレンスを参照してください。 --- ## 統合を確認する {#verify-your-integration} 1. 上記のいずれかの方法でリクエストを送信します。その際、自分のユーザーIDを受信者として指定します。 2. メッセージが配信されたことを確認します。 3. オプション2を使用する場合、Brazeダッシュボードでキャンペーンを確認し、送信が記録されていることを確認します。 ## 考慮事項 {#considerations} - 対応している場合は、Brazeの[パーソナライゼーション機能](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize)を使ってコンテンツをカスタマイズしてください。 - メッセージングが関連規制に準拠していることを確認し、必要なオプトアウトオプションとプライバシー通知を含めてください。 - その他のエンドポイント(スケジューリング、キャンバストリガーなど)については、[メッセージングエンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)を参照してください。 # REST APIを使用したSMSメッセージの送信 Source: /docs/ja/developer_guide/rest_api/sending_sms_messages/index.md # REST APIを使用したSMSメッセージの送信 {#sending-sms-messages-using-the-rest-api} > Braze REST APIを使用して、バックエンドからトランザクションSMSメッセージをリアルタイムで送信します。この方法を使えば、プログラムでSMSメッセージを送信するサービスを構築しながら、Brazeダッシュボード上で他のキャンペーンやキャンバスと並行して配信分析をトラッキングできます。 これは特に、バックエンドシステムでコンテンツが定義されている大量のトランザクションメッセージングにおいて有用です。たとえば、他のユーザーからメッセージが届いた際に消費者に通知し、Webサイトにアクセスして受信トレイを確認するよう促すことができます。 この方法を使えば、次のことができます: - バックエンドからリアルタイムでSMSメッセージをトリガーする。 - マーケティング部門が所有するすべてのキャンペーンやキャンバスと並行して分析データをトラッキングする。 - メッセージ遅延、フォローアップリターゲティング、ABテストといった追加のBraze機能でユースケースを拡張する。 - 必要に応じて、[APIトリガー配信](https://www.braze.com/docs/ja/ja/user_guide/messaging/campaigns/schedule_your_campaign/api_triggered_delivery)に切り替えることで、メッセージテンプレートをBrazeダッシュボードで定義しつつ、送信はバックエンドからトリガーし続けることができます。 REST API経由でSMSメッセージを送信するには、BrazeダッシュボードでAPI キャンペーンを設定し、[`/messages/send`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages)エンドポイントを使用してメッセージを送信する必要があります。 ## 前提条件 {#prerequisites} このガイドを完了するには、以下が必要です: | 必要条件 | 説明 | | --- | --- | | Braze REST APIキー | `messages.send` 権限を持つキー。作成するには、**設定** > **APIキー** > **APIキー**に移動します。 | | SMSサブスクリプショングループ | Brazeワークスペースで設定されたSMSサブスクリプショングループ。 | | バックエンドサービス | Braze REST APIに対してHTTP POSTリクエストを送信できるバックエンドサービスまたはスクリプト環境。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="前提条件" } ## ステップ 1:API キャンペーンを作成する {#step-1-create-an-api-campaign} 1. Brazeダッシュボードで、**メッセージング** > **キャンペーン**に移動します。 2. **キャンペーンを作成**を選択し、次に**API キャンペーン**を選択します。 3. キャンペーンの名前と説明を入力します(例:「SMS通知」)。 4. 識別とトラッキングのために関連タグを追加します。 5. **メッセージングチャネルを追加**を選択し、次に**SMS**を選択します。 6. キャンペーンページに表示されている**キャンペーン ID**と**Message Variation ID**をメモしておきます。APIリクエストを構築する際に両方の値が必要です。 ## ステップ 2:APIを使ってSMSメッセージを送信する {#step-2-send-an-sms-message-using-the-api} [`/messages/send`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages)エンドポイントへのPOSTリクエストを構築します。リクエストペイロードにキャンペーン ID、受信者の外部ユーザーID、およびSMSコンテンツを含めます。 **Important:** `external_user_ids`で参照されている各受信者は、すでにBrazeに存在している必要があります。API経由のみの送信では、新しいユーザープロファイルは作成されません。送信の一部としてユーザーを作成する必要がある場合は、まず[`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)を使用するか、代わりに[APIトリガー型キャンペーン](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_triggered_campaigns)を使用してください。 ### リクエスト例 {#example-request} ``` POST YOUR_REST_ENDPOINT/messages/send Content-Type: application/json Authorization: Bearer YOUR_REST_API_KEY ``` `YOUR_REST_ENDPOINT`を、ワークスペースの[RESTエンドポイントURL](https://www.braze.com/docs/ja/ja/api/basics#endpoints)に置き換えます。 ```json { "campaign_id": "YOUR_CAMPAIGN_ID", "external_user_ids": ["user123"], "messages": { "sms": { "app_id": "YOUR_APP_ID", "subscription_group_id": "YOUR_SMS_SUBSCRIPTION_GROUP_ID", "message_variation_id": "YOUR_MESSAGE_VARIATION_ID", "body": "Hi }, you have a new message in your inbox. Check it out at https://yourwebsite.com/messages. Text STOP to opt out." } } } ``` プレースホルダーの値を実際のIDに置き換えます。`body`フィールドは[Liquidパーソナライゼーション](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize/liquid)をサポートしているため、メッセージの内容を各受信者に合わせて調整できます。SMSメッセージングオブジェクトがサポートするパラメーターの完全な一覧については、[SMSオブジェクト](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/sms_object)を参照してください。 リクエストを構築した後、バックエンドサービスからBraze REST APIへPOSTリクエストを送信します。 ## ステップ 3:統合を確認する {#step-3-verify-your-integration} 設定を完了したら、統合を確認します: 1. [ステップ 2](#step-2-send-an-sms-message-using-the-api)で説明した通りにAPIリクエストを送信します。その際、受信者として自身のユーザーIDを使用します。 2. SMSメッセージが自分の携帯電話に届いていることを確認します。 3. Brazeダッシュボードで、キャンペーンの結果ページに移動し、送信が記録されていることを確認します。 4. キャンペーンを拡大するにつれて、結果を注意深く監視します。 ## 考慮事項 {#considerations} - SMSキャンペーンが関連規制および通信事業者の要件に準拠していることを確認してください。すべてのメッセージにオプトアウトの手順(「STOPと送信してオプトアウト」など)を含めてください。詳細については、[SMSに関する法令](https://www.braze.com/docs/ja/ja/user_guide/channels/sms_mms_and_rcs/compliance_and_delivery/laws_and_regulations)および[オプトインとオプトアウトのキーワード](https://www.braze.com/docs/ja/ja/user_guide/channels/sms_mms_and_rcs/message_features_and_optimization/keyword_processing/optin_optout)を参照してください。 - Brazeの[パーソナライゼーション機能](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize)を使用して、ダイナミックなコンテンツやユーザー固有のデータを含め、SMSコンテンツをエンドユーザーに合わせてカスタマイズできます。 - Braze REST APIは、メッセージのスケジュール設定やキャンペーンのトリガーなどを行うための追加の[メッセージングエンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)を提供しています。 # REST APIを使用したメールメッセージの送信 Source: /docs/ja/developer_guide/rest_api/sending_email_messages/index.md # REST APIを使用したメールメッセージの送信 {#sending-email-messages-using-the-rest-api} > Braze REST APIを使用して、バックエンドからリアルタイムでトランザクションメールを送信できます。このアプローチにより、プログラムでメールを送信するサービスを構築しながら、Brazeダッシュボードで他のキャンペーンやキャンバスと一緒に配信分析を追跡できます。 これは、コンテンツがバックエンドシステムで定義されるトランザクションメッセージングに特に便利です。たとえば、消費者が別のユーザーからメッセージを受信したときに通知し、Webサイトにアクセスして受信トレイを確認するよう促すことができます。 このアプローチでは、以下のことが可能です。 - バックエンドからリアルタイムでメールをトリガーする。 - 開封、クリック数、バウンスなど、マーケティング所有のすべてのキャンペーンやキャンバスと一緒に分析を追跡する。 - メッセージインタラクションデータを使用して、フォローアップのリターゲティングなどの後続メッセージをトリガーする。 - メッセージ遅延やABテストなど、追加のBraze機能でユースケースを拡張する。 - オプションで、[APIトリガー配信](https://www.braze.com/docs/ja/ja/user_guide/messaging/campaigns/schedule_your_campaign/api_triggered_delivery)に切り替えて、Brazeダッシュボードでメールテンプレートを定義しながら、バックエンドから送信をトリガーする。 REST APIを通じてメールを送信するには、BrazeダッシュボードでAPI キャンペーンを設定し、[`/messages/send`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages)エンドポイントを使用してメッセージを送信する必要があります。 ## 前提条件 {#prerequisites} このガイドを完了するには、以下が必要です。 | 要件 | 説明 | | --- | --- | | Braze REST APIキー | `messages.send` 権限を持つキー。作成するには、**設定** > **APIキー** > **APIキー**に移動します。 | | BrazeアプリID | ワークスペース内のアプリの識別子。確認するには、**設定** > **APIキー**に移動し、**アプリ識別子**セクションを確認します。この値はメールメッセージングオブジェクトの `app_id` フィールドに必須です。詳細については、[アプリ識別子](https://www.braze.com/docs/ja/ja/api/identifier_types)を参照してください。 | | HTMLメールコンテンツ | 事前に準備したメールメッセージのHTML本文。 | | バックエンドサービス | Braze REST APIにHTTP POSTリクエストを送信できるバックエンドサービスまたはスクリプティング環境。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="前提条件" } ## ステップ 1: API キャンペーンを作成する {#step-1-create-an-api-campaign} 1. Brazeダッシュボードで、**メッセージング** > **キャンペーン**に移動します。 2. **キャンペーンを作成**を選択し、**API キャンペーン**を選択します。 3. キャンペーンの名前と説明を入力します(例:「メールメッセージ通知」)。 4. 識別と追跡のために関連するタグを追加します。 5. **メッセージングチャネルを追加**を選択し、**Email**を選択します。 6. キャンペーンページに表示される**キャンペーン ID**をメモします。APIリクエストを構築する際にこの値が必要です。オプションで、**Message Variation ID**もメモしてください。送信統計を特定のメッセージバリエーションに帰属させたい場合は、リクエストに含めます。 ## ステップ 2: APIを使用してメールを送信する {#step-2-send-an-email-using-the-api} [`/messages/send`](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_messages)エンドポイントへのPOSTリクエストを構築します。リクエストペイロードにキャンペーン ID、受信者の外部ユーザーID、およびメールコンテンツを含めます。 **Important:** `external_user_ids` で参照される各受信者は、Brazeにすでに存在している必要があります。APIのみの送信では、新しいユーザープロファイルは作成されません。送信の一部としてユーザーを作成する必要がある場合は、まず[`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)を使用するか、代わりに[APIトリガーキャンペーン](https://www.braze.com/docs/ja/ja/api/endpoints/messaging/send_messages/post_send_triggered_campaigns)を使用してください。 ### リクエスト例 {#example-request} ``` POST https://YOUR_REST_ENDPOINT/messages/send Content-Type: application/json Authorization: Bearer YOUR_REST_API_KEY ``` `YOUR_REST_ENDPOINT` をワークスペースの[RESTエンドポイントURL](https://www.braze.com/docs/ja/ja/api/basics#endpoints)に置き換えてください。 ```json { "campaign_id": "YOUR_CAMPAIGN_ID", "external_user_ids": ["user123"], "messages": { "email": { "app_id": "YOUR_APP_ID", "message_variation_id": "YOUR_MESSAGE_VARIATION_ID", "subject": "You have a new message!", "from": "Notifications ", "body": "

You have a new message!

Hi },

You received a new message in your inbox. Click the link below to read it:

View message

Thank you for using our service!

" } } } ``` プレースホルダーの値を実際のIDに置き換えてください。`from` フィールドは `"Display Name "` の形式を使用する必要があります。`body` フィールドは有効なHTMLを受け付け、[Liquidパーソナライゼーション](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize/liquid)をサポートしているため、各受信者に合わせてメールコンテンツをカスタマイズできます。メールメッセージングオブジェクトでサポートされるパラメーターの完全なリストについては、[メールオブジェクト](https://www.braze.com/docs/ja/ja/api/objects_filters/messaging/email_object)を参照してください。 リクエストを構築したら、バックエンドサービスからBraze REST APIにPOSTリクエストを送信します。 ## ステップ 3: インテグレーションを検証する {#step-3-verify-your-integration} 設定が完了したら、インテグレーションを検証します。 1. [ステップ 2](#step-2-send-an-email-using-the-api)の説明に従って、自分のユーザーIDを受信者としてAPIリクエストを送信します。 2. メールが受信トレイに配信されたことを確認します。 3. Brazeダッシュボードでキャンペーン結果ページに移動し、送信が記録されていることを確認します。 4. キャンペーンをスケールする際に、結果を注意深く監視します。 ## 考慮事項 {#considerations} - GDPRやCAN-SPAMなどの関連規制に準拠するために、必要なオプトアウトオプションとプライバシー通知を含めて、メールキャンペーンが準拠していることを確認してください。詳細については、[ユーザーサブスクリプションの管理](https://www.braze.com/docs/ja/ja/user_guide/channels/email/subscriptions)および[メールのベストプラクティス](https://www.braze.com/docs/ja/ja/user_guide/channels/email/best_practices)を参照してください。 - Brazeの[パーソナライゼーション機能](https://www.braze.com/docs/ja/ja/user_guide/messaging/design_and_edit/personalize)を使用して、ダイナミックなコンテンツやユーザー固有のデータを含め、エンドユーザーごとにメールコンテンツをカスタマイズできます。 - Braze REST APIは、メッセージのスケジュール設定、キャンペーンのトリガーなどのための追加の[メッセージングエンドポイント](https://www.braze.com/docs/ja/ja/api/endpoints/messaging)を提供しています。 # ユーザーに製品をおすすめする Source: /docs/ja/developer_guide/rest_api/recommending_products/index.md # ユーザーに製品をおすすめする {#recommending-products-to-users} > Braze REST APIを[カタログ](https://www.braze.com/docs/ja/ja/user_guide/data/activation/catalogs/create)や[コネクテッドコンテンツ](https://www.braze.com/docs/ja/ja/user_guide/personalization_and_dynamic_content/connected_content)と組み合わせて使用し、パーソナライズ済みの製品おすすめをメッセージに表示できます。このアプローチにより、独自のレコメンデーションエンジンをBrazeのメッセージングエコシステムに接続でき、技術者でないユーザーでも各おすすめに関するコンテンツやメッセージングを管理できます。 このアプローチでは、以下のことが可能です。 - REST APIを使用して、バックエンドからユーザープロファイルに製品おすすめを保存する。 - 送信時にカタログまたはコネクテッドコンテンツを使用して製品メタデータを取得する。 - メール、プッシュ、アプリ内メッセージなど、あらゆるメッセージングチャネルでパーソナライズ済みのおすすめを表示する。 ## 前提条件 {#prerequisites} このガイドを完了するには、以下が必要です。 | 要件 | 説明 | | --- | --- | | Braze REST APIキー | `users.track` 権限を持つキー。APIを経由してカタログを管理する場合は、関連するカタログ権限も必要です。作成するには、**設定** > **APIキー**に移動します。 | | Brazeカタログ | 製品メタデータ(名前、カテゴリ、価格、画像URLなど)を含むカタログ。作成するには、[カタログを作成する](https://www.braze.com/docs/ja/ja/user_guide/data/activation/catalogs/create)を参照してください。 | | Liquidの知識 | パーソナライズ済み変数のテンプレート化やコネクテッドコンテンツの使用に関する[Liquid](https://www.braze.com/docs/ja/ja/user_guide/personalization_and_dynamic_content/liquid)の中級レベルの知識。 | {: .reset-td-br-1 .reset-td-br-2 aria-label="前提条件" } ## ステップ 1: ユーザープロファイルにおすすめを保存する {#step-1-store-recommendations-on-user-profiles} まず、レコメンデーションエンジンが生成した製品おすすめを、カスタム属性としてBrazeユーザープロファイルに保存します。これにより、メッセージ送信時に各ユーザーのおすすめ製品を参照できます。 1. 保存するおすすめデータ(製品IDや好みのカテゴリなど)を決定します。 2. [`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)エンドポイントを使用して、おすすめをユーザープロファイルのカスタム属性として書き込みます。 ### リクエスト例 {#example-request} ```http POST YOUR_REST_ENDPOINT/users/track Content-Type: application/json Authorization: Bearer YOUR_REST_API_KEY ``` `YOUR_REST_ENDPOINT` をワークスペースの[RESTエンドポイントURL](https://www.braze.com/docs/ja/ja/api/basics#endpoints)に置き換えてください。 ```json { "attributes": [ { "external_id": "user123", "recommended_product_id": "1001" } ] } ``` 後でLiquidテンプレートで参照しやすいように、わかりやすい属性名(`recommended_product_id` など)を使用してください。レコメンデーションエンジンが新しい結果を生成するたびに定期的に更新し、おすすめの精度を維持してください。 ## ステップ 2: 製品メタデータを取得する {#step-2-retrieve-product-metadata} 各ユーザープロファイルにおすすめの識別子を保存した後、メッセージに含める完全な製品メタデータ(名前、価格、画像など)を取得する必要があります。2つのオプションがあります。 - **オプションA:** [Brazeカタログ](#option-a-braze-catalogs) — 製品情報をBrazeに直接保存し、高速な組み込みルックアップを行います。 - **オプションB:** [コネクテッドコンテンツ](#option-b-connected-content) — 送信時に外部APIから製品情報を取得します。 ### オプションA: Brazeカタログ {#option-a-braze-catalogs} 製品インベントリを含む[カタログ](https://www.braze.com/docs/ja/ja/user_guide/data/activation/catalogs/create)を作成済みの場合、Liquidを使用してメッセージ内で直接アイテムを検索できます。詳しい手順については、[カタログの使用](https://www.braze.com/docs/ja/ja/user_guide/data/activation/catalogs/use)を参照してください。 #### 特定のカタログアイテムをおすすめする {#recommend-a-specific-catalog-item} IDで特定の製品を参照するには、`catalog_items` Liquidタグを使用します。たとえば、`retail_products` という名前のカタログから製品 `1001` をおすすめするには: ```liquid We have a new item we think you'll like: Category: Name: Price: $ ``` #### 複数のカタログアイテムをおすすめする {#recommend-multiple-catalog-items} 1つのタグで複数のアイテムを参照することもできます。たとえば、3つの製品を紹介するには: ```liquid New items added in: - - - Visit our store to learn more! ``` #### ユーザーのおすすめを使用してアイテムをテンプレート化する {#template-items-using-a-users-recommendation} [ステップ 1](#step-1-store-recommendations-on-user-profiles)のカスタム属性とカタログルックアップを組み合わせて、各ユーザーに合わせたおすすめをパーソナライズします。 ```liquid Hi }, check out our pick for you: — $ ``` ### オプションB: コネクテッドコンテンツ {#option-b-connected-content} 製品メタデータがBrazeカタログではなく外部サービスにある場合は、[コネクテッドコンテンツ](https://www.braze.com/docs/ja/ja/user_guide/personalization_and_dynamic_content/connected_content/making_an_api_call)を使用して送信時に取得します。 たとえば、内部APIがIDで製品詳細を返す場合: ```liquid Hi }, we think you'll love: — $ ``` メッセージからのAPI呼び出しの詳細については、[API呼び出しを行う](https://www.braze.com/docs/ja/ja/user_guide/personalization_and_dynamic_content/connected_content/making_an_api_call)を参照してください。 **Warning:** コネクテッドコンテンツを使用して大量の製品リストを取得し、送信時にLiquidでそのリストを反復処理することは避けてください。大きなレスポンスペイロードは送信レイテンシーを増加させ、大規模な場合にメッセージのタイムアウトや配信失敗を引き起こす可能性があります。代わりに、ユーザーが必要とする特定の製品IDのみをプロファイルに保存し([ステップ 1](#step-1-store-recommendations-on-user-profiles)を参照)、それらの個別アイテムのメタデータを取得するか、高速なルックアップに最適化された[カタログ](#option-a-braze-catalogs)を使用してください。 ## ステップ 3: 統合を検証する {#step-3-verify-your-integration} セットアップが完了したら、統合を検証します。 1. [`/users/track`](https://www.braze.com/docs/ja/ja/api/endpoints/user_data/post_user_track)エンドポイントを使用して、自分のユーザープロファイルにテストおすすめを書き込みます。 2. カタログまたはコネクテッドコンテンツを使用しておすすめ製品を参照するテストメッセージを送信します。 3. 配信されたメッセージで製品詳細が正しく表示されることを確認します。 4. Brazeダッシュボードで、キャンペーンまたはキャンバスの結果ページに移動し、送信が記録されていることを確認します。 ## 考慮事項 {#considerations} - レコメンデーションエンジンが新しい結果を生成するたびにカスタム属性を定期的に更新し、おすすめデータの精度を維持してください。 - Brazeの[パーソナライゼーション機能](https://www.braze.com/docs/ja/ja/user_guide/personalization_and_dynamic_content)を使用して、製品詳細と合わせてユーザー固有のデータを組み込むなど、メッセージをさらにカスタマイズすることを検討してください。 - Brazeダッシュボードで定義されたテンプレートを使用してバックエンドからメッセージをトリガーするために、[APIトリガー配信](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/campaigns/building_campaigns/delivery_types/api_triggered_delivery)の使用を検討してください。 # ローカライゼーション Source: /docs/ja/developer_guide/localization/index.md # ローカライゼーション {#localization} > Braze SDKのローカライゼーションおよびサポートされている言語について説明します。これにより、世界中のユーザーとつながることができます。ローカライズされたメッセージの設定方法については、メッセージングの基本セクションの[ローカライゼーション](https://www.braze.com/docs/ja/ja/user_guide/messaging/messaging_fundamentals/localization)を参照してください。 ## ローカライゼーションについて {#about-localization} 英語に加えて、Brazeはアプリに表示されるSDKメッセージについて複数の言語をサポートしています。 ユーザーのスマートフォンの言語がサポートされている言語のいずれかに設定されている場合、メッセージングチャネルにデフォルトで含まれるSDKメッセージはその言語に翻訳されます。たとえば、アプリが接続の問題に関するメッセージを表示する場合、ユーザーが選択した言語に翻訳されます。 ## Supported language codes Braze supports most language codes in the [ISO-639-1](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) standard, with a few exceptions. Refer to the following table for the full list. | Language | Code | | -------- | ---- | | ENGLISH | `en` | | AFRIKAANS | `af` | | AGHEM | `agq` | | AKAN | `ak` | | ALBANIAN | `sq` | | AMHARIC | `am` | | ARABIC | `ar` | | ARMENIAN | `hy` | | ASSAMESE | `as` | | AYMARA | `ay` | | AZERBAIJANI | `az` | | BAFIA | `ksf` | | BASA | `bas` | | BASQUE | `eu` | | BELARUSIAN | `be` | | BEMBA | `bem` | | BENGALI | `bn` | | BENA | `bez` | | BOSNIAN | `bs` | | BRETON | `br` | | BULGARIAN | `bg` | | BURMESE | `my` | | CAMBODIAN | `km` | | CATALAN | `ca` | | CENTRAL ATLAS TAMAZIGHT | `tzm` | | CHEROKEE | `chr` | | CHIGA | `cgg` | | CHINESE | `zh` | | CONGO SWAHILI | `swc` | | CORNISH | `kw` | | CROATIAN | `hr` | | CZECH | `cs` | | DANISH | `da` | | DAWIDA | `dav` | | DOUALA | `dua` | | DUTCH | `nl` | | DZONGKHA | `dz` | | EKUGUSII | `guz` | | ESTONIAN | `et` | | ESPERANTO | `eo` | | EWONDO | `ewo` | | EWE | `ee` | | FAROESE | `fo` | | FARSI | `fa` | | FILIPINO | `fil` | | FINNISH | `fi` | | FRENCH | `fr` | | GALICIAN | `gl` | | GANDA | `lg` | | GEORGIAN | `ka` | | GERMAN | `de` | | GERMAN SWISS | `gsw` | | GREEK | `el` | | GREENLANDIC | `kl` | | GUARANI | `gn` | | GUJARATI | `gu` | | HAUSA | `ha` | | HAWAIIAN | `haw` | | HEBREW | `he` | | HINDI | `hi` | | HUNGARIAN | `hu` | | ICELANDIC | `is` | | IGBO | `ig` | | INDONESIAN | `id` | | INUKTITUT | `iu` | | IRISH | `ga` | | ITALIAN | `it` | | JAVANESE | `jv` | | JAPANESE | `ja` | | JOLA_FONYI | `dyo` | | KABYLE | `kab` | | KALENJIN | `kln` | | KAMBA | `kam` | | KANNADA | `kn` | | KASHMIRI | `ks` | | KAZAKH | `kk` | | KIEMBU | `ebu` | | KIKUYU | `ki` | | KINYARWANDA | `rw` | | KIRGHIZ | `ky` | | KOREAN | `ko` | | KURDISH | `ku` | | LAO | `lo` | | LATIN | `la` | | LATVIAN | `lv` | | LINGALA | `ln` | | LITHUANIAN | `lt` | | LUBA KATANGA | `lu` | | LUXEMBOURGISH | `lb` | | LUO | `luo` | | LUYIA | `luy` | | MACHAME | `jmc` | | MACEDONIAN | `mk` | | MALAGASY | `mg` | | MALAY | `ms` | | MALAYALAM | `ml` | | MALTESE | `mt` | | MANX | `gv` | | MARATHI | `mr` | | MASAI | `mas` | | MERU | `mer` | | MOLDAVIAN | `mo` | | MONGOLIAN | `mn` | | MORISYEN | `mfe` | | MUNDANG | `mua` | | NAM | `naq` | | NEPALI | `ne` | | NORTH NDEBELE | `nd` | | NORWEGIAN | `nb` | | NUER | `nus` | | NYANKOLE | `nyn` | | NYNORSK | `nn` | | OROMO | `om` | | PASHTO | `ps` | | PEUL | `ff` | | POLISH | `pl` | | PORTUGUESE | `pt` | | PUNJABI | `pa` | | QUECHUA | `qu` | | RAETO ROMANCE | `rm` | | ROMANIAN | `ro` | | ROMBO | `rof` | | RUSSIAN | `ru` | | RWA | `rwk` | | SAMBURU | `saq` | | SAMI | `se` | | SANGU | `sbp` | | SANSKRIT | `sa` | | SCOTTISH | `gd` | | SERBIAN | `sr` | | SENA | `seh` | | SHAMBALA | `ksb` | | SHONA | `sn` | | SICHUAN YI | `ii` | | SINDHI | `sd` | | SINHALESE | `si` | | SLOVAK | `sk` | | SLOVENIAN | `sl` | | SOMALI | `so` | | SPANISH | `es` | | SWAHILI | `sw` | | SWEDISH | `sv` | | TACHELHIT | `shi` | | TAGALOG | `tl` | | TAJIKI | `tg` | | TAMIL | `ta` | | TASAWAQ | `twq` | | TATAR | `tt` | | TELUGU | `te` | | TESO | `teo` | | THAI | `th` | | TIBETAN | `bo` | | TIGRINYA | `ti` | | TONGAN | `to` | | TURKISH | `tr` | | TURKMEN | `tk` | | UIGHUR | `ug` | | UKRAINIAN | `uk` | | URDU | `ur` | | UZBEK | `uz` | | VAI | `vai` | | VIETNAMESE | `vi` | | VUNJO | `vun` | | WELSH | `cy` | | XHOSA | `xh` | | YANGBEN | `yav` | | YIDDISH | `yi` | | YORUBA | `yo` | | ZARMA | `dje` | | ZULU | `zu` | {: .reset-td-br-1 .reset-td-br-2 aria-label="Supported language codes" } # ジオフェンス Source: /docs/ja/developer_guide/geofences/index.md # ジオフェンス {#geofences} > Braze SDKのジオフェンスの設定方法について説明します。[ジオフェンス](https://www.braze.com/docs/ja/ja/user_guide/engagement_tools/locations_and_geofences/#about-locations-and-geofences)とは、特定のグローバルな位置を中心に円を形成する仮想的な地理的領域のことで、緯度、経度、半径を組み合わせて表されます。 ## Prerequisites Before you can use this feature, you'll need to [integrate the Android Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android). ## Setting up geofences {#setting-up-geofences} ### Step 1: Enable in Braze You can enable geofences for your app in one of the following places: To enable geofences from the **Locations** page: 1. In Braze, go to **Audience** > **Locations**. 2. The number of apps in your workspace that have geofences enabled is listed under the map. For example, if geofences is only enabled for some of your apps, it may read: **2 of 5 Apps with Geofences enabled**. To enable additional apps, select the current count under the map. 3. Choose an app to enable geofences for, then select **Done.** ![The geofence options on the Braze locations page.](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-locations-page.png?4bf8451a2e59f1723b529fa8ff43b7f7) To enable geofences from the **App Settings** page: 1. In Braze, go to **Settings** > **App Settings**. 2. Select the app you'd like to enable geofences for. 3. Check **Geofences Enabled**, then select **Save.** ![The geofence checkbox located on the Braze settings pages.](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-app-settings-page.png?702b6b77bb33116e03d8ba576f4e62f9) ### Step 2: Update `build.gradle` Add `android-sdk-location` to your app-level `build.gradle`. Also, add the Google Play Services [location package](https://developers.google.com/android/reference/com/google/android/gms/location/package-summary) using the Google Play Services [setup guide](https://developers.google.com/android/guides/setup): ``` dependencies { implementation "com.braze:android-sdk-location:+" implementation "com.google.android.gms:play-services-location:${PLAY_SERVICES_VERSION}" } ``` ### Step 3: Update the manifest Add boot, fine location, and background location permissions to your `AndroidManifest.xml`: ```xml ``` **Important:** The background location access permission was added in Android 10 and is required for Geofences to work while the app is in the background for all Android 10+ devices. Add the Braze boot receiver to the `application` element of your `AndroidManifest.xml`: ```xml ``` ### Step 4: Enable Braze location collection If you have not yet enabled Braze location collection, update your `braze.xml` file to include `com_braze_enable_location_collection` and confirm its value is set to `true`: ```xml true ``` **Important:** Starting with Braze Android SDK version 3.6.0, Braze location collection is disabled by default. Braze geofences are enabled if Braze location collection is enabled. If you would like to opt-out of our default location collection but still want to use geofences, it can be enabled selectively by setting the value of key `com_braze_geofences_enabled` to `true` in `braze.xml`, independently of the value of `com_braze_enable_location_collection`: ```xml true ``` ### Step 5: Obtain location permissions from the end user For Android M and higher versions, you must request location permissions from the end user before gathering location information or registering geofences. Add the following call to notify Braze when a user grants the location permission to your app: ```java Braze.getInstance(context).requestLocationInitialization(); ``` ```kotlin Braze.getInstance(context).requestLocationInitialization() ``` This will cause the SDK to request geofences from Braze servers and initialize geofence tracking. See [`RuntimePermissionUtils.java`](https://github.com/braze-inc/braze-android-sdk/blob/master/droidboy/src/main/java/com/appboy/sample/util/RuntimePermissionUtils.kt) in our sample application for an example implementation. ```java public class RuntimePermissionUtils { private static final String TAG = BrazeLogger.getBrazeLogTag(RuntimePermissionUtils.class); public static final int DROIDBOY_PERMISSION_LOCATION = 40; public static void handleOnRequestPermissionsResult(Context context, int requestCode, int[] grantResults) { switch (requestCode) { case DROIDBOY_PERMISSION_LOCATION: // In Android Q, we require both FINE and BACKGROUND location permissions. Both // are requested simultaneously. if (areAllPermissionsGranted(grantResults)) { Log.i(TAG, "Required location permissions granted."); Toast.makeText(context, "Required location permissions granted.", Toast.LENGTH_SHORT).show(); Braze.getInstance(context).requestLocationInitialization(); } else { Log.i(TAG, "Required location permissions NOT granted."); Toast.makeText(context, "Required location permissions NOT granted.", Toast.LENGTH_SHORT).show(); } break; default: break; } } private static boolean areAllPermissionsGranted(int[] grantResults) { for (int grantResult : grantResults) { if (grantResult != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } } ``` ```kotlin object RuntimePermissionUtils { private val TAG = BrazeLogger.getBrazeLogTag(RuntimePermissionUtils::class.java!!) val DROIDBOY_PERMISSION_LOCATION = 40 fun handleOnRequestPermissionsResult(context: Context, requestCode: Int, grantResults: IntArray) { when (requestCode) { DROIDBOY_PERMISSION_LOCATION -> // In Android Q, we require both FINE and BACKGROUND location permissions. Both // are requested simultaneously. if (areAllPermissionsGranted(grantResults)) { Log.i(TAG, "Required location permissions granted.") Toast.makeText(context, "Required location permissions granted.", Toast.LENGTH_SHORT).show() Braze.getInstance(context).requestLocationInitialization() } else { Log.i(TAG, "Required location permissions NOT granted.") Toast.makeText(context, "Required location permissions NOT granted.", Toast.LENGTH_SHORT).show() } else -> { } } } private fun areAllPermissionsGranted(grantResults: IntArray): Boolean { for (grantResult in grantResults) { if (grantResult != PackageManager.PERMISSION_GRANTED) { return false } } return true } } ``` Using the preceding sample code is done via: ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { boolean hasAllPermissions = PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_BACKGROUND_LOCATION) && PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION); if (!hasAllPermissions) { // Request both BACKGROUND and FINE location permissions requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION}, RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION); } } else { if (!PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION)) { // Request only FINE location permission requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION); } } } ``` ```kotlin if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val hasAllPermissions = PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_BACKGROUND_LOCATION) && PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION) if (!hasAllPermissions) { // Request both BACKGROUND and FINE location permissions requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION) } } else { if (!PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)) { // Request only FINE location permission requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION) } } } ``` ### Step 6: Manually request geofence updates (optional) By default, Braze automatically retrieves the device's location and requests geofences based on that collected location. However, you can manually provide a GPS coordinate that will be used to retrieve proximal Braze geofences instead. To manually request Braze Geofences, you must disable automatic Braze geofence requests and provide a GPS coordinate for requests. #### Step 6.1: Disable automatic geofence requests Automatic Braze geofence requests can be disabled in your `braze.xml` file by setting `com_braze_automatic_geofence_requests_enabled` to `false`: ```xml false ``` This can additionally be done at runtime via: ```java BrazeConfig.Builder brazeConfigBuilder = new BrazeConfig.Builder() .setAutomaticGeofenceRequestsEnabled(false); Braze.configure(getApplicationContext(), brazeConfigBuilder.build()); ``` ```kotlin val brazeConfigBuilder = BrazeConfig.Builder() .setAutomaticGeofenceRequestsEnabled(false) Braze.configure(applicationContext, brazeConfigBuilder.build()) ``` #### Step 6.2: Manually request Braze geofence with GPS coordinate Braze Geofences are manually requested via the [`requestGeofences()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/request-geofences.html) method: ```java Braze.getInstance(getApplicationContext()).requestGeofences(latitude, longitude); ``` ```kotlin Braze.getInstance(applicationContext).requestGeofences(33.078947, -116.601356) ``` **Important:** Geofences can only be requested once per session, either automatically by the SDK or manually with this method. **Important:** As of iOS 14, geofences do not work reliably for users who choose to only give their approximate location permission. ## Prerequisites Before you can use this feature, you'll need to [integrate the Swift Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift). ## Setting up geofences {#setting-up-geofences} ### Step 1: Enable in Braze You can enable geofences for your app in one of the following places: To enable geofences from the **Locations** page: 1. In Braze, go to **Audience** > **Locations**. 2. The number of apps in your workspace that have geofences enabled is listed under the map. For example, if geofences is only enabled for some of your apps, it may read: **2 of 5 Apps with Geofences enabled**. To enable additional apps, select the current count under the map. 3. Choose an app to enable geofences for, then select **Done.** ![The geofence options on the Braze locations page.](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-locations-page.png?4bf8451a2e59f1723b529fa8ff43b7f7) To enable geofences from the **App Settings** page: 1. In Braze, go to **Settings** > **App Settings**. 2. Select the app you'd like to enable geofences for. 3. Check **Geofences Enabled**, then select **Save.** ![The geofence checkbox located on the Braze settings pages.](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-app-settings-page.png?702b6b77bb33116e03d8ba576f4e62f9) ### Step 2: Enable your app's location services By default, Braze location services are not enabled. To enable them in your app, complete the following steps. For a step-by-step tutorial, see [Tutorial: Braze Locations and Geofences](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/d1-brazelocation/). #### Step 2.1: Add the `BrazeLocation` module In Xcode, open the **General** tab. Under **Frameworks, Libraries, and Embedded Content**, add the `BrazeLocation` module. ![Add the BrazeLocation module in your Xcode project](https://www.braze.com/docs/ja/ja/assets/img/sdk_geofences/add-brazeLocation-module-xcode.png?a635e73143b5dee799072b76b29ffd5b) #### Step 2.2: Update your `Info.plist` In your `info.plist`, assign a `String` value to one of the following keys that describes why your application needs to track location. This string will be shown when your users are prompted for location services, so be sure to clearly explain the value of enabling this feature for your app. - `NSLocationAlwaysAndWhenInUseUsageDescription` - `NSLocationWhenInUseUsageDescription` ![Info.plist location strings in Xcode](https://www.braze.com/docs/ja/ja/assets/img/sdk_geofences/info-plist-location-strings.png?2a8b87c6d26af9f0b44e2a273d016f8c) **Important:** Apple has deprecated `NSLocationAlwaysUsageDescription`. For more information, see [Apple's developer documentation](https://developer.apple.com/documentation/bundleresources/information-property-list/nslocationalwaysusagedescription). ### Step 3: Enable geofences in your code In your app's code, enable geofences by setting `location.geofencesEnabled` to `true` on the `configuration` object that initializes the [`Braze`](https://braze-inc.github.io/braze-swift-sdk/tutorials/braze/d1-brazelocation/) instance. For other `location` configuration options, see [Braze Swift SDK reference](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/location-swift.class). ```swift let configuration = Braze.Configuration( apiKey: "", endpoint: "" ) configuration.location.brazeLocationProvider = BrazeLocationProvider() configuration.location.automaticLocationCollection = true configuration.location.geofencesEnabled = true configuration.location.automaticGeofenceRequests = true // Additional configuration customization... let braze = Braze(configuration: configuration) AppDelegate.braze = braze ``` ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:brazeApiKey endpoint:brazeEndpoint]; configuration.logger.level = BRZLoggerLevelInfo; configuration.location.brazeLocationProvider = [[BrazeLocationProvider alloc] init]; configuration.location.automaticLocationCollection = YES; configuration.location.geofencesEnabled = YES; configuration.location.automaticGeofenceRequests = YES; // Additional configuration customization... Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; AppDelegate.braze = braze; ``` #### Step 3.1: Enable background reporting (optional) By default, geofence events are only monitored if your app is in the foreground or has `Always` authorization, which monitors all application states. However, you can choose to also monitor geofence events if your app is in the background or has [`When In Use` authorization](#swift_request-authorization). To monitor these additional geofence events, open your Xcode project, then go to **Signing & Capabilities**. Under **Background Modes**, check **Location updates**. ![In Xcode, Background Mode > Location Updates](https://www.braze.com/docs/ja/ja/assets/img/sdk_geofences/xcode-background-modes-location-updates.png?7bfb02d003c77dedd1af7bf706959671) Next, enable `allowBackgroundGeofenceUpdates` in your app's code. This lets Braze extend your app's "When In Use" status by continuously monitoring location updates. This setting only works when your app is in the background. When the app re-opens, all existing background processes are paused and foreground processes are prioritized instead. ```swift let configuration = Braze.Configuration( apiKey: "", endpoint: "" ) // Additional configuration customization... // Enable background geofence reporting with `When In Use` authorization. configuration.location.allowBackgroundGeofenceUpdates = true // Determines the number of meters required to trigger a new location update. configuration.location.distanceFilter = 8000 let braze = Braze(configuration: configuration) AppDelegate.braze = braze ``` ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:brazeApiKey endpoint:brazeEndpoint]; // Additional configuration customization... // Enable background geofence reporting with `When In Use` authorization. configuration.location.allowBackgroundGeofenceUpdates = YES; // Determines the number of meters required to trigger a new location update. configuration.location.distanceFilter = 8000; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; AppDelegate.braze = braze; ``` **Important:** To prevent battery drain and rate limiting, configure `distanceFilter` to a value that meets your app's specific needs. Setting `distanceFilter` to a higher value prevents your app from requesting your user's location too frequently. ### Step 4: Request authorization {#request-authorization} When requesting authorization from a user, request either `When In Use` or `Always` authorization. To request `When In Use` authorization, use the `requestWhenInUseAuthorization()` method: ```swift var locationManager = CLLocationManager() locationManager.requestWhenInUseAuthorization() ``` ```objc CLLocationManager *locationManager = [[CLLocationManager alloc] init]; [locationManager requestWhenInUseAuthorization]; ``` By default, `requestAlwaysAuthorization()` only grants your app `When In Use` authorization and will re-prompt your user for `Always` authorization after some time has passed. However, you can choose to immediately prompt your user by first calling `requestWhenInUseAuthorization()` and then calling `requestAlwaysAuthorization()` after receiving your initial `When In Use` authorization. **Important:** You can only immediately prompt for `Always` authorization a single time. ```swift var locationManager = CLLocationManager() locationManager.requestAlwaysAuthorization() ``` ```objc CLLocationManager *locationManager = [[CLLocationManager alloc] init]; [locationManager requestAlwaysAuthorization]; ``` ## Manually request geofences {#manually-request-geofences} When the Braze SDK requests geofences from the backend, it reports the user's current location and receives geofences that are determined to be optimally relevant based on the location reported. To control the location that the SDK reports for the purposes of receiving the most relevant geofences, you can manually request geofences by providing the desired coordinates. ### Step 1: Set `automaticGeofenceRequests` to `false` You can disable automatic geofence requests in your `configuration` object passed to [`init(configuration)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/init(configuration:)). Set `automaticGeofenceRequests` to `false`. ```swift let configuration = Braze.Configuration( apiKey: "{BRAZE_API_KEY}", endpoint: "{BRAZE_ENDPOINT}" ) configuration.automaticGeofencesRequest = false let braze = Braze(configuration: configuration) AppDelegate.braze = braze ``` ```objc BRZConfiguration *configuration = [[BRZConfiguration alloc] initWithApiKey:{BRAZE_API_KEY} endpoint:{BRAZE_ENDPOINT}]; configuration.automaticGeofencesRequest = NO; Braze *braze = [[Braze alloc] initWithConfiguration:configuration]; AppDelegate.braze = braze; ``` ### Step 2: Call `requestGeofences` manually In your code, request geofences with the appropriate latitude and longitude. ```swift AppDelegate.braze?.requestGeofences(latitude: latitude, longitude: longitude) ``` ```objc [AppDelegate.braze requestGeofencesWithLatitude:latitude longitude:longitude]; ``` ## Frequently Asked Questions (FAQ) {#faq} #### Why am I not receiving geofences on my device? To confirm whether or not geofences are being received on your device, first use the [SDK Debugger tool](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/debugging#debugging-the-braze-sdk) to check SDK's logs. You will then be able to see if geofences are successfully being received from the server and if there are any notable errors. Below are other possible reasons geofences may not be received on your device: ##### iOS operating system limitations The iOS operating system only allows up to 20 geofences to be stored for a given app. With geofences enabled, Braze will use up some of these 20 available slots. To prevent accidental or unwanted disruption to other geofence-related functionality in your app, you must enable location geofences for individual apps on the dashboard. For our location services to work correctly, check that your app is not using all available geofence spots. ##### Rate limiting Braze has a limit of 1 geofence refresh per session to avoid unnecessary requests. #### How does it work if I am using both Braze and non-Braze geofence features? As mentioned above, iOS allows a single app to store a maximum of 20 geofences. This storage is shared by both Braze and non-Braze geofences and is managed by [CLLocationManager](https://developer.apple.com/documentation/corelocation/cllocationmanager). For instance, if your app contains 20 non-Braze geofences, there would be no storage to track any Braze geofences (or vice versa). In order to receive new geofences, you will need to use [Apple's location APIs](https://developer.apple.com/documentation/corelocation) to stop monitoring some of the existing geofences on the device. #### Can the Geofences feature be used while a device is offline? A device needs to be connected to the internet only when a refresh occurs. Once it has successfully received geofences from the server, it is possible to log a geofence entry or exit even if the device is offline. This is because a device's location operates separately from its internet connectivity. For example, say a device successfully received and registered geofences on session start and goes offline. If it then enters one of those registered geofences, it can trigger a Braze campaign. #### Why are geofences not monitored when my app is backgrounded/terminated? Without `Always` authorization, Apple restricts location services from running while an app is not in use. This is enforced by the operating system and is outside the control of the Braze SDK. While Braze offers separate configurations to run services while the app is in the background, there is no way to circumvent these restrictions for apps that are terminated without receiving explicit authorization from the user. ## Prerequisites Before you can use this feature, you'll need to [integrate the .NET MAUI Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=.net%20maui%20(xamarin)). ## Prerequisites This is the minimum SDK versions needed to start using geofences: ## Setting up geofences {#setting-up-geofences} ### Step 1: Enable in Braze You can enable geofences for your app in one of the following places: To enable geofences from the **Locations** page: 1. In Braze, go to **Audience** > **Locations**. 2. The number of apps in your workspace that have geofences enabled is listed under the map. For example, if geofences is only enabled for some of your apps, it may read: **2 of 5 Apps with Geofences enabled**. To enable additional apps, select the current count under the map. 3. Choose an app to enable geofences for, then select **Done.** ![The geofence options on the Braze locations page.](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-locations-page.png?4bf8451a2e59f1723b529fa8ff43b7f7) To enable geofences from the **App Settings** page: 1. In Braze, go to **Settings** > **App Settings**. 2. Select the app you'd like to enable geofences for. 3. Check **Geofences Enabled**, then select **Save.** ![The geofence checkbox located on the Braze settings pages.](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-app-settings-page.png?702b6b77bb33116e03d8ba576f4e62f9) --- Next, follow the platform-specific instructions below for either Android or iOS: ### Step 2: Add dependencies Add the following NuGet package reference to your project: - `BrazePlatform.BrazeAndroidLocationBinding` ### Step 3: Update your AndroidManifest.xml Add the following permissions to your `AndroidManifest.xml`: ```xml ``` **Important:** The background location access permission is required for geofences to work while the app is in the background on Android 10+ devices. ### Step 4: Configure Braze location collection Ensure that location collection is enabled in your Braze configuration. If you want to enable geofences without automatic location collection, set the following in your `Braze.xml`: ```xml true true ``` ### Step 5: Request location permissions at runtime You must request location permissions from the user before registering geofences. In your C# code, use the following pattern: ```csharp using AndroidX.Core.App; using AndroidX.Core.Content; private void RequestLocationPermission() { // ...existing code for checking and requesting permissions... } public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults) { // ...existing code for handling permission result... } ``` After permissions are granted, initialize Braze location collection: ```csharp Braze.GetInstance(this).RequestLocationInitialization(); ``` ### Step 6: Manually request geofence updates (optional) To manually request geofences for a specific location: ```csharp Braze.GetInstance(this).RequestGeofences(latitude, longitude); ``` **Important:** Geofences can only be requested once per session, either automatically by the SDK or manually with this method. ### Step 2: Add dependencies Add the following NuGet package reference to your project: - `Braze.iOS.BrazeLocation` ### Step 3: Configure location usage in Info.plist Add a usage description string for location services in your `Info.plist`: ```xml NSLocationAlwaysAndWhenInUseUsageDescription This app uses your location to enable geofences and location-based messaging. NSLocationWhenInUseUsageDescription This app uses your location to enable geofences and location-based messaging. ``` **Important:** Apple has deprecated `NSLocationAlwaysUsageDescription`. Use the keys above for iOS 14+. ### Step 4: Enable geofences in your Braze configuration In your app startup code (e.g., `App.xaml.cs`), configure Braze with geofences enabled: ```csharp using BrazeKit; using BrazeLocation; var configuration = new BRZConfiguration("", ""); configuration.Location.BrazeLocationProvider = new BrazeLocationProvider(); configuration.Location.AutomaticLocationCollection = true; configuration.Location.GeofencesEnabled = true; configuration.Location.AutomaticGeofenceRequests = true; // ...other configuration... var braze = new Braze(configuration); ``` ### Step 5: Enable background location updates (optional) To monitor geofences in the background, enable the **Location updates** background mode by adding the following configuration to your `Info.plist`: ```xml UIBackgroundModes location ``` Then, in your Braze configuration, set: ```csharp configuration.Location.AllowBackgroundGeofenceUpdates = true; configuration.Location.DistanceFilter = 8000; // meters ``` **Important:** Set `DistanceFilter` to a value that meets your app's needs to avoid battery drain. ### Step 6: Request location authorization Request either `When In Use` or `Always` authorization from the user: ```csharp using CoreLocation; var locationManager = new CLLocationManager(); locationManager.RequestWhenInUseAuthorization(); // or locationManager.RequestAlwaysAuthorization(); ``` **Important:** Without `Always` authorization, iOS restricts location services from running while the app is not in use. This is enforced by the operating system and cannot be bypassed by the Braze SDK. **Important:** Geofences are supported on **both iOS and Android** in the React Native SDK. The `requestLocationInitialization` method is Android-only and is not required for iOS. The `requestGeofences` method is available on both platforms. By default, the SDK can automatically request and monitor geofences when location is available; you can rely on this automatic configuration or call `requestGeofences` to request manually. ## Prerequisites Before you can use this feature, you'll need to [integrate the React Native Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=react%20native). ## Setting up geofences {#setting-up-geofences} ### Step 1: Enable in Braze You can enable geofences for your app in one of the following places: To enable geofences from the **Locations** page: 1. In Braze, go to **Audience** > **Locations**. 2. The number of apps in your workspace that have geofences enabled is listed under the map. For example, if geofences is only enabled for some of your apps, it may read: **2 of 5 Apps with Geofences enabled**. To enable additional apps, select the current count under the map. 3. Choose an app to enable geofences for, then select **Done.** ![The geofence options on the Braze locations page.](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-locations-page.png?4bf8451a2e59f1723b529fa8ff43b7f7) To enable geofences from the **App Settings** page: 1. In Braze, go to **Settings** > **App Settings**. 2. Select the app you'd like to enable geofences for. 3. Check **Geofences Enabled**, then select **Save.** ![The geofence checkbox located on the Braze settings pages.](https://www.braze.com/docs/ja/ja/assets/img_archive/enable-geofences-app-settings-page.png?702b6b77bb33116e03d8ba576f4e62f9) ### Step 2: Complete native Android setup Because the React Native SDK uses the native Braze Android SDK, complete the native Android geofence setup for your project. The iOS equivalent of these steps is covered in the native Swift SDK geofences guide ([steps 2.2 to 3.1](https://www.braze.com/docs/ja/ja/developer_guide/geofences/?sdktab=swift#swift_step-21-add-the-brazelocation-module)); step 2.1 (Add the BrazeLocation module) is not required for React Native because BrazeLocation is already included implicitly with the Braze React Native SDK. 1. **Update `build.gradle`:** Add `android-sdk-location` and Google Play Services location. See [Android geofences](https://www.braze.com/docs/ja/ja/developer_guide/geofences/?sdktab=android). 2. **Update the manifest:** Add location permissions and the Braze boot receiver. See [Android geofences](https://www.braze.com/docs/ja/ja/developer_guide/geofences/?sdktab=android). 3. **Enable Braze location collection:** Update your `braze.xml` file. See [Android geofences](https://www.braze.com/docs/ja/ja/developer_guide/geofences/?sdktab=android). ### Step 3: Complete native iOS setup Because the React Native SDK uses the native Braze iOS SDK, complete the native iOS geofence setup for your project by following the native Swift SDK instructions starting from step 2.2: update your `Info.plist` with location usage descriptions (step 2.2), and enable geofences in your Braze configuration including `automaticGeofenceRequests = true` (step 3); optionally enable background reporting (step 3.1). Step 2.1 (Add the BrazeLocation module) is not required—BrazeLocation is already included implicitly with the Braze React Native SDK. See [iOS geofences, steps 2.2 to 3.1](https://www.braze.com/docs/ja/ja/developer_guide/geofences/?sdktab=swift#swift_step-21-add-the-brazelocation-module). ### Step 4: Request geofences from JavaScript **On Android:** After the user grants location permissions, call `requestLocationInitialization()` to initialize Braze location features and request geofences from Braze servers. This method is not supported on iOS and is not required for iOS. **On iOS:** The equivalent is to enable the `automaticGeofenceRequests` configuration in your native Swift or Objective-C Braze configuration (see Step 3). With that enabled, the SDK automatically requests and monitors geofences when location is available; no JavaScript call equivalent to `requestLocationInitialization` is required. ```javascript import Braze from '@braze/react-native-sdk'; // Android only: call this after the user grants location permission Braze.requestLocationInitialization(); ``` ### Step 5: Manually request geofences (optional) On both iOS and Android, you can manually request a geofence update for a specific GPS coordinate using `requestGeofences`. By default, Braze automatically retrieves the device's location and requests geofences. To manually provide a coordinate instead: 1. Disable automatic geofence requests. On Android, set `com_braze_automatic_geofence_requests_enabled` to `false` in your `braze.xml`. On iOS, set `automaticGeofenceRequests` to `false` in your Braze configuration. 2. Call `requestGeofences` with the desired latitude and longitude: ```javascript import Braze from '@braze/react-native-sdk'; Braze.requestGeofences(33.078947, -116.601356); ``` **Important:** Geofences can only be requested once per session, either automatically by the SDK or manually with this method. # ストレージ Source: /docs/ja/developer_guide/storage/index.md # ストレージ {#storage} > Braze SDKによって保存されるさまざまなデバイスレベルのプロパティについて説明します。 ## デバイスのプロパティ {#device-properties} デフォルトでは、Brazeは以下のデバイスレベルプロパティを収集し、デバイス、言語、タイムゾーンベースのメッセージのパーソナライゼーションを可能にします。 - `BROWSER` - `BROWSER_VERSION` - `LANGUAGE` - `OS` - `RESOLUTION` - `TIME_ZONE` - `USER_AGENT` - `AD_TRACKING_ENABLED` - `ANDROID_VERSION` - `CARRIER` - `IS_BACKGROUND_RESTRICTED` - `LOCALE` - `MODEL` - `NOTIFICATION_ENABLED` - `RESOLUTION` - `TIMEZONE` **Note:** `AD_TRACKING_ENABLED`と`TIMEZONE`は`null`または空白の場合は収集されません。`GOOGLE_ADVERTISING_ID`はSDKによって自動的に収集されないため、[`setGoogleAdvertisingId`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-i-braze/set-google-advertising-id.html)経由で渡す必要があります。 - デバイスの通信事業者([`CTCarrier`非推奨](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/deviceproperty/carrier)に関する注記を参照) - デバイスのロケール - デバイスモデル - デバイスOSのバージョン - プッシュ許可ステータス - プッシュ表示オプション - プッシュ有効 - デバイスの解像度 - デバイスのタイムゾーン **Note:** Braze SDKはIDFAを自動的に収集しません。アプリはオプションで、以下のメソッドを直接実装することでIDFAをBrazeに渡すことができます。アプリはIDFAをBrazeに渡す前に、App Tracking Transparencyフレームワークを通じてエンドユーザーによるトラッキングへの明示的なオプトインを取得する必要があります。 1. 広告のトラッキング状態を設定するには、[`set(adTrackingEnabled:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/set(adtrackingenabled:)/)を使用します。 2. 広告主の識別子(IDFA)を設定するには、[`set(identifierForAdvertiser:)`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/set(identifierforadvertiser:)/)を使用します。 デフォルトでは、すべてのプロパティが有効になっています。ただし、手動で有効または無効にすることもできます。Braze SDKの機能の中には、特定のプロパティ(ローカルタイムゾーン配信やタイムゾーンなど)を必要とするものがあるため、本番環境にリリースする前に必ず設定をテストしてください。 例えば、許可リストに登録するデバイスの言語を指定できます。詳細については、[`InitializationOptions`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initializationoptions)の`devicePropertyAllowlist`オプションを参照してください。 ```javascript import * as braze from"@braze/web-sdk"; braze.initialize("API-KEY", { baseUrl: "BASE-URL", devicePropertyAllowlist: [ braze.DeviceProperties.LANGUAGE ] // list of `DeviceProperties` you want to collect }); ``` 例えば、許可リストに登録するAndroid OSバージョンとデバイスロケールを指定できます。詳細については、[`setDeviceObjectAllowlistEnabled()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-device-object-allowlist-enabled.html)と[`setDeviceObjectAllowlist()`](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze.configuration/-braze-config/-builder/set-device-object-allowlist.html)メソッドを参照してください。 ```java new BrazeConfig.Builder() .setDeviceObjectAllowlistEnabled(true) .setDeviceObjectAllowlist(EnumSet.of(DeviceKey.ANDROID_VERSION, DeviceKey.LOCALE)); ``` 例えば、許可リストに登録するタイムゾーンとロケールの収集を指定できます。詳細については、`configuration`オブジェクトの[`devicePropertyAllowList`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/devicepropertyallowlist)プロパティを参照してください。 ```swift configuration.devicePropertyAllowList = [.timeZone, .locale] ``` ```objc configuration.devicePropertyAllowList = @[ BRZDeviceProperty.timeZone, BRZDeviceProperty.locale ]; ``` **Tip:** 自動的に収集されるデバイスプロパティの詳細については、[SDKデータ収集](https://www.braze.com/docs/ja/ja/user_guide/data/unification/user_data/sdk_data_collection)を参照してください。 ## Cookieの保存(Webのみ) {#cookies} [Web Braze SDKを初期化](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initialize)すると、有効期限400日のCookieが作成および保存され、新しいセッションで自動的に更新されます。 以下のCookieが保存されます。 | Cookie | 説明 | サイズ | | --- | ---- | --- | | `ab.storage.userId.[your-api-key]` | 現在ログインしているユーザーが変更されたかどうかを判断し、イベントを現在のユーザーに関連付けるために使用されます。 | `changeUser`に渡された値のサイズに基づきます | | `ab.storage.sessionId.[your-api-key]` | メッセージを同期し、セッション分析を計算するために、ユーザーが新しいセッションを開始しているか既存のセッションを継続しているかを判断するために使用されるランダム生成文字列です。 | ~200バイト | | `ab.storage.deviceId.[your-api-key]` | 匿名ユーザーを識別し、ユーザーのデバイスを区別し、デバイスベースのメッセージングを可能にするために使用されるランダム生成文字列です。 | ~200バイト | | `ab.optOut` | `disableSDK`が呼び出されたときにユーザーのオプトアウト設定を格納するために使用されます。 | ~40バイト | | `ab._gd` | ルートレベルのCookieドメインを決定するために一時的に作成(その後削除)されます。これにより、サブドメイン間でSDKが適切に動作できるようになります。 | 該当なし | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 aria-label="Cookieの保存(Webのみ)" } ### Cookieの有効期限を変更する {#cookie-expiry} デフォルトでは、BrazeのCookieは400日後に期限切れになります。これを上書きするには、Web SDKを初期化する際に`cookieExpiryInDays`オプションを使用します。値は0より大きい必要があります。このオプションが省略された場合、または0以下に設定された場合は、400日のデフォルトが適用されます。このオプションにはWeb SDK 6.6.0以降が必要です。 ```javascript import * as braze from "@braze/web-sdk"; braze.initialize("API-KEY", { baseUrl: "BASE-URL", cookieExpiryInDays: 30 // expires after 30 days }); ``` ### Cookieを無効にする {#disable-cookies} すべてのCookieを無効にするには、Web SDKを初期化する際に[`noCookies`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initializationoptions)オプションを使用します。これにより、サブドメインをまたいで移動する匿名ユーザーを関連付けることができなくなり、各サブドメインで新しいユーザーが生成されます。 ```javascript import * as braze from "@braze/web-sdk"; braze.initialize("API-KEY", { baseUrl: "BASE-URL", noCookies: true }); ``` Brazeのトラッキング全般を停止したり、保存されたブラウザデータをすべて消去したりするには、それぞれ[`disableSDK`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#disableSDK)および[`wipeData`](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#wipedata) SDKメソッドを参照してください。これらの2つのメソッドは、ユーザーが同意を取り消した場合や、SDKの初期化後にBrazeのすべての機能を停止したい場合に役立ちます。 # Braze SDKのネットワーク設定 Source: /docs/ja/developer_guide/network/index.md # ネットワーク設定 {#network-settings} > Braze SDKのネットワーク設定を構成する方法について説明します。 ## Network offline mode [Network offline mode](https://braze-inc.github.io/braze-android-sdk/kdoc/braze-android-sdk/com.braze/-braze/-companion/outbound-network-requests-offline.html?query=var%20outboundNetworkRequestsOffline:%20Boolean) is an optional feature that pauses or resumes outbound network requests from the Braze SDK at any point during runtime. Events are not lost during the offline state. This reference article covers how to integrate this mode. To enable network offline mode in the Braze SDK, see the following example: ```java Braze.setOutboundNetworkRequestsOffline(true); ``` ```kotlin Braze.setOutboundNetworkRequestsOffline(true) ``` ## Network traffic control ### Requesting processing policies Braze allows the user the option to control network traffic using the following protocols: By default, the `RequestPolicy` enum value is set to `automatic`. When set, immediate server requests are performed when user-facing data is required for Braze features, such as in-app messages. The Braze SDK will automatically handle all server communication, including: - Flushing custom events and attributes data to Braze servers - Updating Content Cards and geofences - Requesting new in-app messages To minimize server load, Braze performs periodic flushes of new user data every few seconds. When the `RequestPolicy` enum value is `manual`, it performs the same as automatic request processing, except: - Custom attributes and custom event data are not automatically flushed to the server throughout the user session. - Braze will still perform automatic network requests for internal features, such as requesting in-app messages, Liquid templating in in-app messages, geofences, and location tracking. For more details, see the `Braze.Configuration.Api.RequestPolicy.manual` [documentation](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/api-swift.class/requestpolicy-swift.enum/manual). When these internal requests are made, Braze may flush locally stored custom attributes and custom event data to the Braze server, depending on the request type. ### Manually flushing user data Data can be manually flushed to Braze servers at any time using the following method: ```swift AppDelegate.braze?.requestImmediateDataFlush() ``` ```objc [AppDelegate.braze requestImmediateDataFlush]; ``` ### Setting the request processing policy These policies can be set at app startup time when you initialize the Braze configuration. In the `configuration` object, set the [`Braze.Configuration.Api.RequestPolicy`](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze/configuration-swift.class/api-swift.class/requestpolicy-swift.enum)) as shown in the following code snippet: ```swift configuration.api.requestPolicy = .automatic ``` ```objc configuration.api.requestPolicy = BRZRequestPolicyAutomatic; ``` # Braze SDK リファレンス、リポジトリ、サンプルアプリ Source: /docs/ja/developer_guide/references/index.md # リファレンス、リポジトリ、サンプルアプリ {#references-repositories-and-sample-apps} > これは、各 Braze SDKに属するリファレンスドキュメント、GitHubリポジトリ、サンプルアプリの一覧です。SDKのリファレンスドキュメントには、使用可能なクラス、型、関数、変数の詳細が記載されています。GitHubリポジトリは、SDKの関数や属性の宣言、コードの変更、バージョン管理に関するインサイトを提供します。各リポジトリには、Brazeの機能をテストしたり、独自のアプリケーションと併せて実装するために使用できる、完全にビルド可能なサンプルアプリケーションも含まれています。 ドキュメント内のミラーリングされたリポジトリREADMEコンテンツについては、[リポジトリガイド](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides)を参照してください。 ## リソース一覧 {#list-of-resources} **Note:** 現在、一部のSDKには専用のリファレンスドキュメントがありませんが、積極的に作成に取り組んでいます。 | プラットフォーム | リファレンス | リポジトリ | サンプルアプリ | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | Android SDK | [リファレンスドキュメント](https://braze-inc.github.io/braze-android-sdk/kdoc/index.html) | [GitHubリポジトリ](https://github.com/braze-inc/braze-android-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-android-sdk/tree/master/samples) | | Swift SDK | [リファレンスドキュメント](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/braze) | [GitHubリポジトリ](https://github.com/braze-inc/braze-swift-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-swift-sdk/tree/main/Examples) | | Web SDK | [リファレンスドキュメント](https://js.appboycdn.com/web-sdk/latest/doc/modules/braze.html#initialize) | [GitHubリポジトリ](https://github.com/braze-inc/braze-web-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-web-sdk/tree/master/sample-builds) | | Javascript SDK | [リファレンスドキュメント](https://braze-inc.github.io/braze-javascript-sdk/) | [GitHubリポジトリ](https://github.com/braze-inc/braze-javascript-sdk/tree/main) | N/A | | Cordova SDK | [宣言ファイル](https://github.com/braze-inc/braze-cordova-sdk/blob/master/www/BrazePlugin.js) | [GitHubリポジトリ](https://github.com/braze-inc/braze-cordova-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-cordova-sdk/tree/master/sample-project) | | Flutter SDK | [リファレンスドキュメント](https://pub.dev/documentation/braze_plugin/latest/braze_plugin/) | [GitHubリポジトリ](https://github.com/braze-inc/braze-flutter-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-flutter-sdk/tree/master/example) | | React Native SDK | [リファレンスドキュメント](https://braze-inc.github.io/braze-react-native-sdk/) | [GitHubリポジトリ](https://github.com/braze-inc/braze-react-native-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-react-native-sdk/tree/master/BrazeProject) | | Vega SDK | [リファレンスドキュメント](https://braze-inc.github.io/braze-vega-sdk/) | [GitHubリポジトリ](https://github.com/braze-inc/braze-vega-sdk) | N/A | | Roku SDK | N/A | [GitHubリポジトリ](https://github.com/braze-inc/braze-roku-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-roku-sdk/tree/main/torchietv) | | Unity SDK | [宣言ファイル](https://github.com/braze-inc/braze-unity-sdk/blob/master/Assets/Plugins/Appboy/BrazePlatform.cs) | [GitHubリポジトリ](https://github.com/braze-inc/braze-unity-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-unity-sdk/tree/master/unity-samples) | | .NET MAUI SDK(旧称 Xamarin) | N/A | [GitHubリポジトリ](https://github.com/braze-inc/braze-xamarin-sdk) | [サンプルアプリ](https://github.com/braze-inc/braze-xamarin-sdk/tree/master/appboy-component/samples) | {: .reset-td-br-1 .reset-td-br-2 .reset-td-br-3 .reset-td-br-4 aria-label="リソース一覧" } ## サンプルアプリのビルド {#building-a-sample-app} ### 「Droidboy」のビルド {#building-droidboy} [Android SDK GitHubリポジトリ](https://github.com/braze-inc/braze-android-sdk)内のテストアプリケーションはDroidboyと呼ばれます。以下の手順に従って、プロジェクトとともに完全に機能するDroidboyのコピーをビルドしてください。 1. 新しい[ワークスペース](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/app_group_configuration#app-group-configuration)を作成し、Braze API識別子キーを書き留めます。

2. FCM送信者IDとBraze API識別子キーを `/droidboy/res/values/braze.xml` 内の適切な場所(それぞれ `com_braze_push_fcm_sender_id` と `com_braze_api_key` という文字列のタグの間)にコピーします。

3. FCMサーバーキーとサーバーIDを**設定の管理**のワークスペース設定にコピーします。

4. Droidboy APKをアセンブルするには、SDKディレクトリ内で `./gradlew assemble` を実行します。Windowsでは `gradlew.bat` を使用してください。

5. Droidboy APKをテストデバイスに自動的にインストールするには、SDKディレクトリ内で `./gradlew installDebug` を実行します。 ### 「Hello Braze」のビルド {#building-hello-braze} Hello Brazeテストアプリケーションは、Braze SDKの最小限のユースケースを示すとともに、Braze SDKをGradleプロジェクトに簡単に統合する方法も示します。 1. **設定の管理**ページのAPI識別子キーを `res/values` フォルダーの `braze.xml` ファイルにコピーします。 ![「Hello Braze」のビルドに関連するスクリーンショット](https://www.braze.com/docs/ja/ja/assets/img_archive/hello_appboy.png?6a24a92e98dc23be7df4f1b6ce39eef5)

2. サンプルアプリをデバイスまたはエミュレーターにインストールするには、SDKディレクトリ内で次のコマンドを実行します。 ``` ./gradlew installDebug ``` `ANDROID_HOME` 変数が適切に設定されていない場合、または有効な `sdk.dir` フォルダーを含む `local.properties` フォルダーがない場合、このプラグインはベースSDKもインストールします。詳細については、[プラグインリポジトリ](https://github.com/JakeWharton/sdk-manager-plugin)を参照してください。 Android SDKビルドシステムの詳細については、[GitHubリポジトリのREADME](https://github.com/braze-inc/braze-android-sdk/blob/master/README.md)を参照してください。 ### Swiftテストアプリのビルド {#building-swift-test-apps} 以下の手順に従って、テストアプリケーションをビルドして実行してください。 1. 新しい[ワークスペース](https://www.braze.com/docs/ja/ja/developer_guide/platform_wide/app_group_configuration#creating-your-app-group-in-my-apps)を作成し、アプリ識別子APIキーとエンドポイントを書き留めます。 2. 統合方法(Swift Package Manager、CocoaPods、手動)に基づいて、適切な `xcodeproj` ファイルを選択して開きます。 3. `Credentials` ファイルの適切なフィールドにAPIキーとエンドポイントを入力します。 **Note:** SDKインテグレーションのQAを行う際は、[SDKデバッガー](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/debugging)を使用すれば、アプリの冗長ロギングをオンにすることなく問題のトラブルシューティングを行うことができます。 # リポジトリガイド Source: /docs/ja/developer_guide/sdk_repository_guides/index.md # リポジトリガイド {#repository-guides} > これらのページは、Braze SDKリポジトリのパブリックREADMEファイルをミラーリングしたものです。自動化により毎週同期され、各ページからサンプルプロジェクトや追加のコンテキストを含むソースリポジトリにリンクしています。 ## 利用可能なリポジトリガイド {#available-repository-guides} 以下のリポジトリガイドからプラットフォーム別にお選びください。 - [Web SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/web) - [Android SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/android) - [Swift SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/swift) - [JavaScript SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/javascript) - [Cordova SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/cordova) - [Flutter SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/flutter) - [React Native SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/react_native) - [Roku SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/roku) - [Unity SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/unity) - [.NET MAUI (Xamarin) SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_repository_guides/xamarin) # Web SDK リポジトリガイド Source: /docs/ja/developer_guide/sdk_repository_guides/web/index.md # Web SDK リポジトリガイド {#web-sdk-repository-guide} ## Braze Web SDKについて {#about-the-braze-web-sdk} Braze Web SDKを使用すると、BrazeのカスタマーエンゲージメントプラットフォームをWebアプリケーションに直接統合できます。TypeScriptで構築され、モダンなWeb開発向けに設計されたこのSDKは、ユーザー管理、メッセージング、分析、フィーチャーフラグのための包括的なツールを提供します。 ### できること {#what-you-can-do} - **ユーザー管理**: Webアプリケーション全体でユーザーのアイデンティティ、属性、動作を追跡・管理します - **アプリ内メッセージング**: ユーザーがサイトをアクティブに使用している間に、ターゲットを絞ったメッセージや通知を表示します - **Content Cards**: リアルタイムで更新されるパーソナライズされたコンテンツフィードやプロモーションカードを表示します - **バナー**: サイト内の特定のプレースメントにバナーメッセージを表示します - **プッシュ通知**: ユーザーがサイトにいないときでもWebプッシュ通知を送信してエンゲージメントを促進します - **フィーチャーフラグ**: サーバーサイドのフィーチャーフラグ管理で機能のロールアウトやABテストを制御します - **分析**: カスタムイベント、ユーザーインタラクション、コンバージョン指標を追跡します - **セッション管理**: ユーザーセッションとエンゲージメントパターンを監視します シングルページアプリケーション、ECサイト、コンテンツプラットフォームのいずれを構築する場合でも、Braze Web SDKは成長とリテンションを促進するパーソナライズされた魅力的なユーザー体験を作成するために必要なツールを提供します。 ## 前提条件 {#prerequisites} Braze Web SDKを統合する前に、以下が必要です。 - **Brazeアカウント**: APIアクセスが可能なBrazeアカウント - **APIキー**: BrazeダッシュボードからのアプリのAPIキー - **SDKエンドポイント**: BrazeのSDKエンドポイントURL(例: `sdk.iad-01.braze.com`) ### 認証情報の取得 {#getting-your-credentials} 1. **APIキー**: Brazeダッシュボードの**設定** > **APIキー**にあります 2. **SDKエンドポイント**: **設定** > **SDK認証** > **エンドポイント**にあります 3. **Service Worker**: プッシュ通知に必要です(プッシュ通知セクションを参照) ## インストール {#installation} ``` bash npm install --save @braze/web-sdk # or, using yarn: # yarn add @braze/web-sdk ``` ## クイックスタート {#quick-start} ``` typescript import * as braze from "@braze/web-sdk"; // Initialize the SDK braze.initialize('YOUR-API-KEY-HERE', { baseUrl: "YOUR-SDK-ENDPOINT-HERE", }); braze.changeUser('Jane Doe'); ``` ## 設定リファレンス {#configuration-reference} ### 初期化オプション {#initialization-options} `initialize`関数は、以下のプロパティを持つオプションオブジェクトを受け取ります。 | オプション | 型 | デフォルト | 説明 | |--------|------|---------|-------------| | `baseUrl` | `string` | **必須** | このオプションは、統合に適切なエンドポイントを使用するようBraze Web SDKを設定するために必須です。例: `braze.initialize('YOUR-API-KEY-HERE', { baseUrl: 'sdk.iad-03.braze.com' })` | | `enableLogging` | `boolean` | `false` | デフォルトでログを有効にするにはtrueに設定します。これによりBrazeがJavaScriptコンソールにログを出力するようになり、すべてのユーザーに表示されます。本番環境にリリースする前に、このオプションを削除するか、setLoggerで代替ロガーを提供してください。 | | `allowUserSuppliedJavascript` | `boolean` | `false` | デフォルトでは、Braze Web SDKはユーザー提供のJavaScriptクリックアクションを許可せず、HTMLアプリ内メッセージやバナーも有効にしません。これらはBrazeダッシュボードのユーザーがサイト上でJavaScriptを実行できるようにするためです。Brazeダッシュボードのユーザーが悪意のないJavaScriptクリックアクションを記述することを信頼する場合は、このプロパティをtrueに設定してください。 | | `doNotLoadFontAwesome` | `boolean` | `false` | Brazeはアプリ内メッセージのアイコンにFont Awesomeを使用しています。デフォルトでは、BrazeはFontAwesome CDNからFontAwesome 4.7.0を自動的に読み込みます。この動作を無効にするには(例えば、サイトでカスタマイズされたバージョンのFontAwesomeを使用している場合)、このオプションを`true`に設定してください。この場合、サイトでFontAwesomeが読み込まれていることを確認する責任はお客様にあります。そうしないと、アプリ内メッセージが正しくレンダリングされない場合があります。 | | `inAppMessageZIndex` | `number` | `999999` | デフォルトでは、Braze SDKはIn-App Messagesをz-index 999999で表示します。このオプションに値を指定すると、そのデフォルトを上書きできます。 | | `sessionTimeoutInSeconds` | `number` | `30` | デフォルトでは、セッションは30秒間操作がないとタイムアウトします。このオプションに値を指定すると、そのデフォルトを上書きできます。 | | `deviceId` | `string` | 自動生成 | デフォルトでは、BrazeはデバイスIDとしてランダムなGUIDを割り当てます。この設定オプションに値を指定すると、そのデフォルトを独自の値で上書きできます。 | | `appVersion` | `string` | `undefined` | このオプションに値を指定すると、Brazeに送信されるユーザーイベントが指定されたバージョンに関連付けられ、ユーザーセグメンテーションに使用できます。 | | `appVersionNumber` | `string` | `undefined` | ユーザーセグメンテーションに使用できる数値のアプリバージョン値です。この値は「1.2.3.4」のように4つのフィールドで送信する必要があり、そうでない場合は無視されます。注: `appVersion`も設定する必要があり、同じ値またはこのバージョンの一意の名前を使用してください。 | | `contentSecurityNonce` | `string` | `undefined` | このオプションに値を指定すると、Braze SDKはSDKが作成するすべての`