# 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)の学習パスなどのガイド付きコースをチェックすることもできます。
**Tip:**
開発者や実装担当者がBrazeのカスタムコンテンツを作成する際には、マーケターと部門を超えたコラボレーションを行う機会があります。例えば、新しいUIや特定のコンポーネントの新機能を開発する場合、新しい動作とバックエンドとの統合方法を文書化することで、チームを成功に導くことができます。
# Braze SDK チュートリアル
Source: /docs/ja/developer_guide/tutorials/index.md
# Braze SDKを統合する
Source: /docs/ja/developer_guide/sdk_integration/index.md
# {: 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**.
{: style="max-width:95%;"}
### Step 2: Add the initialization tag template
In the template gallery, search for `braze-inc`, then select **Braze Initialization Tag**.
{: style="max-width:80%;"}
Select **Add to workspace** > **Add**.
{: style="max-width:70%;"}
### Step 3: Configure the tag
From the **Templates** section, select your newly added template.
{: style="max-width:95%;"}
Select the pencil icon to open the **Tag Configuration** dropdown.

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.
{: 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_KEYYOUR_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**.

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.

**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**.

#### 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.

#### 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.

#### 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`.

#### 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).

**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_KEYYOUR_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_KEYYOUR_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:
```
```
### Step 3: Configure
Within `main.brs`, set the Braze configuration on the global node:
```brightscript
globalNode = screen.getGlobalNode()
config = {}
config_fields = BrazeConstants().BRAZE_CONFIG_FIELDS
config[config_fields.API_KEY] = {YOUR_API_KEY}
' example endpoint: "https://sdk.iad-01.braze.com/"
config[config_fields.ENDPOINT] = {YOUR_ENDPOINT}
config[config_fields.HEARTBEAT_FREQ_IN_SECONDS] = 5
globalNode.addFields({brazeConfig: config})
```
You can find your [SDK endpoint](https://www.braze.com/docs/ja/ja/user_guide/administrative/access_braze/sdk_endpoints/) and API key within the Braze dashboard.
### Step 4: Initialize Braze
Initialize the Braze instance:
```brightscript
m.BrazeTask = createObject("roSGNode", "BrazeTask")
m.Braze = getBrazeInstance(m.BrazeTask)
```
## Optional configurations
### Logging
To debug your Braze integration, you can view the Roku debug console for Braze logs. Refer to [Debugging code](https://developer.roku.com/docs/developer-program/debugging/debugging-channels.md) from Roku Developers to learn more.
## About the Unity Braze SDK
For a full list of types, functions, variables, and more, see [Unity Declaration File](https://github.com/braze-inc/braze-unity-sdk/blob/master/Assets/Plugins/Appboy/BrazePlatform.cs). Additionally, if you've already integrated Unity manually for iOS, you can [switch to an automated integration](#unity_automated-integration) instead.
## Integrating the Unity SDK
### Prerequisites
Before you start, verify your environment is supported by the [latest Braze Unity SDK version](https://github.com/braze-inc/braze-unity-sdk/releases).
### Step 1: Choose your Braze Unity package
The Braze [`.unitypackage`](https://docs.unity3d.com/Manual/AssetPackages.html) bundles native bindings for the Android and iOS platforms, along with a C# interface.
There are several Braze Unity packages available for download on the [Braze Unity releases page](https://github.com/Appboy/appboy-unity-sdk/releases):
- `Appboy.unitypackage`
- This package bundles the Braze Android and iOS SDKs and the [SDWebImage](https://github.com/SDWebImage/SDWebImage) dependency for the iOS SDK, which is required for the proper functionality of Braze in-app messaging, and Content Cards features on iOS. The SDWebImage framework is used for downloading and displaying images, including GIFs. If you intend on utilizing full Braze functionality, download and import this package.
- `Appboy-nodeps.unitypackage`
- This package is similar to `Appboy.unitypackage` except for the [SDWebImage](https://github.com/SDWebImage/SDWebImage) framework is not present. This package is useful if you do not want the SDWebImage framework present in your iOS app.
**Note:**
As of Unity 2.6.0, the bundled Braze Android SDK artifact requires [AndroidX](https://developer.android.com/jetpack/androidx) dependencies. If you were previously using a `jetified` unitypackage, you can safely transition to the corresponding `unitypackage`.
If Android builds fail with "This project uses AndroidX dependencies, but the 'android.useAndroidX' property is not enabled", enable [Custom Gradle Properties Template](https://docs.unity3d.com/Manual/class-PlayerSettingsAndroid.html#Publishing) in your Unity Publishing Settings. Then open `Assets/Plugins/Android/gradleTemplate.properties` and set `android.useAndroidX=true`. For a working template, see the [Braze Unity sample app](https://github.com/braze-inc/braze-unity-sdk/tree/master/unity-samples) and its [`gradleTemplate.properties`](https://github.com/braze-inc/braze-unity-sdk/blob/master/unity-samples/Assets/Plugins/Android/gradleTemplate.properties) file.
The Braze [`.unitypackage`](https://docs.unity3d.com/Manual/AssetPackages.html) bundles native bindings for the Android and iOS platforms, along with a C# interface.
The Braze Unity package is available for download on the [Braze Unity releases page](https://github.com/Appboy/appboy-unity-sdk/releases) with two integration options:
1. `Appboy.unitypackage` only
- This package bundles the Braze Android and iOS SDKs without any additional dependencies. With this integration method, there will not be proper functionality of Braze in-app messaging, and Content Cards features on iOS. If you intend on utilizing full Braze functionality without custom code, use the option below instead.
- To use this integration option, ensure that the box next to `Import SDWebImage dependency` is *unchecked* in the Unity UI under "Braze Configuration".
2. `Appboy.unitypackage` with `SDWebImage`
- This integration option bundles the Braze Android and iOS SDKs and the [SDWebImage](https://github.com/SDWebImage/SDWebImage) dependency for the iOS SDK, which is required for the proper functionality of Braze in-app messaging, and Content Cards features on iOS. The `SDWebImage` framework is used for downloading and displaying images, including GIFs. If you intend on utilizing full Braze functionality, download and import this package.
- To automatically import `SDWebImage`, be sure to *check* the box next to `Import SDWebImage dependency` in the Unity UI under "Braze Configuration".
**Note:**
To see if you require the [SDWebImage](https://github.com/SDWebImage/SDWebImage) dependency for your iOS project, visit the [iOS in-app message documentation](https://www.braze.com/docs/ja/ja/developer_guide/platform_integration_guides/swift/in-app_messaging/overview/).
### Step 2: Import the package
In the Unity Editor, import the package into your Unity project by navigating to **Assets > Import Package > Custom Package**. Next, click **Import**.
Alternatively, follow the [Unity asset package import](https://docs.unity3d.com/Manual/AssetPackages.html) instructions for a more detailed guide on importing custom Unity packages.
**Note:**
If you only wish to import the iOS or Android plugin, deselect the `Plugins/Android` or `Plugins/iOS` subdirectory when importing the Braze `.unitypackage`.
In the Unity Editor, import the package into your Unity project by navigating to **Assets > Import Package > Custom Package**. Next, click **Import**.
Alternatively, follow the [Unity asset package import](https://docs.unity3d.com/Manual/AssetPackages.html) instructions for a more detailed guide on importing custom Unity packages.
**Note:**
If you only wish to import the iOS or Android plugin, deselect the `Plugins/Android` or `Plugins/iOS` subdirectory when importing the Braze `.unitypackage`.
### Step 3: Configure the SDK
#### Step 3.1: Configure `AndroidManifest.xml`
Configure [`AndroidManifest.xml`](https://docs.unity3d.com/Manual/android-manifest.html) so the Braze SDK can function. 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`.
1. Go to the `Assets/Plugins/Android/` directory and open your `AndroidManifest.xml` file. This is the [default location in the Unity editor](https://docs.unity3d.com/Manual/android-manifest.html).
2. In your `AndroidManifest.xml`, add the required permissions and activities from in the following template.
3. When you're finished, your `AndroidManifest.xml` should only contain a single Activity with `"android.intent.category.LAUNCHER"` present.
```xml
```
**Important:**
All Activity classes registered in your `AndroidManifest.xml` file should be fully integrated with the Braze Android SDK, otherwise your analytics won't be collected. If you add your own Activity class, be sure you [extend the Braze Unity player](#unity_extend-unity-player) so you can prevent this.
#### Step 3.2: Update `AndroidManifest.xml` with your package name
To find your package name, click **File > Build Settings > Player Settings > Android Tab**.

In your `AndroidManifest.xml`, all instances of `REPLACE_WITH_YOUR_PACKAGE_NAME` should be replaced with your `Package Name` from the previous step.
#### Step 3.3: Add gradle dependencies
To add gradle dependencies to your Unity project, first enable ["Custom Main Gradle Template"](https://docs.unity3d.com/Manual/class-PlayerSettingsAndroid.html#Publishing) in your Publishing Settings. This will create a template gradle file that your project will use. A gradle file handles setting dependencies and other build-time project settings. For more information, check out the Braze Unity sample app's [mainTemplate.gradle](https://github.com/braze-inc/braze-unity-sdk/blob/master/unity-samples/Assets/Plugins/Android/mainTemplate.gradle).
The following dependencies are required:
```groovy
implementation 'com.google.firebase:firebase-messaging:22.0.0'
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.6.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"
implementation 'androidx.core:core:1.6.0'
```
You may also set these dependencies using the [External Dependency Manager](https://github.com/googlesamples/unity-jar-resolver).
#### Step 3.4: Automate the Unity Android integration
Braze provides a native Unity solution for automating the Unity Android integration.
1. In the Unity Editor, open the Braze Configuration Settings by navigating to **Braze > Braze Configuration**.
2. Check the **Automate Unity Android Integration** box.
3. In the **Braze API Key** field, input your application's API key found in **Manage Settings** from the Braze dashboard.
**Note:**
This automatic integration should not be used with a manually created `braze.xml` file since the configuration values may conflict during project building. If you require a manual `braze.xml`, disable the automatic integration.
#### Step 3.1: Set your API key
Braze provides a native Unity solution for automating the Unity iOS integration. This solution modifies the built Xcode project using Unity's [`PostProcessBuildAttribute`](http://docs.unity3d.com/ScriptReference/Callbacks.PostProcessBuildAttribute.html) and subclasses the `UnityAppController` using the `IMPL_APP_CONTROLLER_SUBCLASS` macro.
1. In the Unity Editor, open the Braze Configuration Settings by navigating to **Braze > Braze Configuration**.
2. Check the **Automate Unity iOS Integration** box.
3. In the **Braze API Key** field, input your application's API key found in **Manage Settings**.

If your application is already using another `UnityAppController` subclass, you will need to merge your subclass implementation with `AppboyAppDelegate.mm`.
## Customizing the Unity package
### Step 1: Clone the repository
In your terminal, clone the [Braze Unity SDK GitHub repository](https://github.com/braze-inc/braze-unity-sdk), then navigate to that folder:
```bash
git clone git@github.com:braze-inc/braze-unity-sdk.git
cd ~/PATH/TO/DIRECTORY/braze-unity-sdk
```
```powershell
git clone git@github.com:braze-inc/braze-unity-sdk.git
cd C:\PATH\TO\DIRECTORY\braze-unity-sdk
```
### Step 2: Export package from repository
First, launch Unity and keep it running in the background. Then, in the repository root, run the following command to export the package to `braze-unity-sdk/unity-package/`.
```bash
/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode -nographics -projectPath "$(pwd)" -executeMethod Appboy.Editor.Build.ExportAllPackages -quit
```
```powershell
"%UNITY_PATH%" -batchmode -nographics -projectPath "%PROJECT_ROOT%" -executeMethod Appboy.Editor.Build.ExportAllPackages -quit
```
**Tip:**
If you experience any issues after running these commands, refer to [Unity: Command Line Arguments](https://docs.unity3d.com/2017.2/Documentation/Manual/CommandLineArguments.html).
### Step 3: Import package into Unity
1. In Unity, import the desired package into your Unity project by navigating to **Assets** > **Import Package** > **Custom Package**.
2. If there's any files you don't want want to import, deselect them now.
3. Customize the exported Unity package located in `Assets/Editor/Build.cs`.
## Switch to an automated integration (Swift only) {#automated-integration}
To take advantage of the automated iOS integration offered in the Braze Unity SDK, follow these steps on transitioning from a manual to an automated integration.
1. Remove all Braze-related code from your Xcode project's `UnityAppController` subclass.
2. Remove Braze iOS libraries from your Unity or Xcode project (such as `Appboy_iOS_SDK.framework` and `SDWebImage.framework`).
3. Import the Braze Unity package into your project again. For a full walkthrough, see [Step 2: Import the package](#unity_step-2-import-the-package).
4. Set your API key again. For a full walkthrough, see [Step 3.1: Set your API key](#unity_step-31-set-your-api-key).
## Optional configurations
### Verbose logging
To enable verbose logging in the Unity Editor, do the following:
1. Open the Braze Configuration Settings by navigating to **Braze** > **Braze Configuration**.
2. Click the **Show Braze Android Settings** dropdown.
3. In the **SDK Log Level** field, input the value "0".
### Prime 31 compatibility
To use the Braze Unity plugin with Prime31 plugins, edit your project's `AndroidManifest.xml` to use the Prime31 compatible Activity classes. Change all references of
`com.braze.unity.BrazeUnityPlayerActivity` to `com.braze.unity.prime31compatible.BrazeUnityPlayerActivity`
### Amazon Device Messaging (ADM)
Braze supports integrating [ADM push](https://developer.amazon.com/public/apis/engage/device-messaging) into Unity apps. If you want to integrate ADM push, create a file called `api_key.txt` containing your ADM API key and place it in the `Plugins/Android/assets/` folder. For more information on integrating ADM with Braze, visit our [ADM push integration instructions](https://www.braze.com/docs/ja/ja/developer_guide/push_notifications/?sdktab=unity).
### Extending the Braze Unity player (Android only) {#extend-unity-player}
The example `AndroidManifest.xml` file provided has one Activity class registered, [`BrazeUnityPlayerActivity`](https://github.com/braze-inc/braze-android-sdk/blob/e804cb3a10ae68364b354b52abf1bef8a0d1a9dc/android-sdk-unity/src/main/java/com/braze/unity/BrazeUnityPlayerActivity.kt). This class is integrated with the Braze SDK and extends `UnityPlayerActivity` with session handling, in-app message registration, push notification analytics logging, and more. See [Unity](https://docs.unity3d.com/Manual/AndroidUnityPlayerActivity.html) for more information on extending the `UnityPlayerActivity` class.
If you are creating your own custom `UnityPlayerActivity` in a library or plugin project, you will need to extend our `BrazeUnityPlayerActivity` to integrate your custom functionality with Braze. Before beginning work on extending `BrazeUnityPlayerActivity`, follow our instructions for integrating Braze into your Unity project.
1. Add the Braze Android SDK as a dependency to your library or plugin project as described in the [Braze Android SDK integration instructions](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android).
2. Integrate our Unity `.aar`, which contains our Unity-specific functionality, to your Android library project you are building for Unity. The `appboy-unity.aar` is available from our [public repo](https://github.com/braze-inc/braze-unity-sdk/tree/master/Assets/Plugins/Android). After our Unity library is successfully integrated, modify your `UnityPlayerActivity` to extend `BrazeUnityPlayerActivity`.
3. Export your library or plugin project and drop it into `//Assets/Plugins/Android` as normal. Do not include any Braze source code in your library or plugin as they will already be present in `//Assets/Plugins/Android`.
4. Edit your `//Assets/Plugins/Android/AndroidManifest.xml` to specify your `BrazeUnityPlayerActivity` subclass as the main activity.
You should now be able to package an `.apk` from the Unity IDE that is fully integrated with Braze and contains your custom `UnityPlayerActivity` functionality.
## Troubleshooting
### Error: "File could not be read"
Errors resembling the following may be safely ignored. Apple software uses a proprietary PNG extension called CgBI, which Unity does not recognize. These errors will not affect your iOS build or the proper display of the associated images in the Braze bundle.
```
Could not create texture from Assets/Plugins/iOS/AppboyKit/Appboy.bundle/...png: File could not be read
```
## Integrating the .NET MAUI SDK
Integrating the Braze .NET MAUI (formerly Xamarin) SDK will provide you with basic analytics functionality as well as working in-app messages with which you can engage your users.
### Prerequisites
Before you can integrate the .NET MAUI Braze SDK, be sure you meet the following requirements:
- Starting in `version 3.0.0`, this SDK requires using .NET 6+ and removes support for projects using the Xamarin framework.
- Starting in `version 4.0.0`, this SDK dropped support for Xamarin & Xamarin.Forms and added support for .NET MAUI. See [Microsoft's policy](https://dotnet.microsoft.com/en-us/platform/support/policy/xamarin) around the end of support for Xamarin.
### Step 1: Get the .NET MAUI binding
A .NET MAUI binding is a way to use native libraries in .NET MAUI apps. The implementation of a binding consists of building a C# interface to the library, and then using that interface in your application. See the [.NET MAUI documentation](http://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/binding_a_java_library_%28.jar%29/). There are two ways to include the Braze SDK binding: using NuGet or compiling from source.
The simplest integration method involves getting the Braze SDK from the [NuGet.org](https://www.nuget.org/) central repository. In the Visual Studio sidebar, right click `Packages` folder and click `Add Packages...`. Search for 'Braze' and install the [`BrazePlatform.BrazeAndroidBinding`](https://www.nuget.org/packages/BrazePlatform.BrazeAndroidBinding/) package into your project.
To use Braze location services and geofences, also install the [`BrazePlatform.BrazeAndroidLocationBinding`](https://www.nuget.org/packages/BrazePlatform.BrazeAndroidLocationBinding/) package.
The second integration method is to include the [binding source](https://github.com/braze-inc/braze-xamarin-sdk). Under [`appboy-component/src/androidnet6`](https://github.com/braze-inc/braze-xamarin-sdk/tree/master/appboy-component/src/androidnet6/BrazeAndroidNet6Binding) you will find our binding source code; adding a project reference to the ```BrazeAndroidBinding.csproj``` in your .NET MAUI application will cause the binding to be built with your project and provide you access to the Braze Android SDK.
To use Braze location services and geofences, also add a project reference to the ```BrazeAndroidLocationBinding.csproj``` found under [`appboy-component/src/androidnet6/BrazeAndroidLocationBinding`](https://github.com/braze-inc/braze-xamarin-sdk/tree/master/appboy-component/src/androidnet6/BrazeAndroidLocationBinding).
**Important:**
The iOS bindings for .NET MAUI SDK version 4.0.0 and later use the [Braze Swift SDK](https://github.com/braze-inc/braze-swift-sdk/), while previous versions use the [legacy AppboyKit SDK](https://github.com/Appboy/Appboy-ios-sdk).
A .NET MAUI binding is a way to use native libraries in .NET MAUI apps. The implementation of a binding consists of building a C# interface to the library and then using that interface in your application. There are two ways to include the Braze SDK binding: using NuGet or compiling from source.
The simplest integration method involves getting the Braze SDK from the [NuGet.org](https://www.nuget.org/) central repository. In the Visual Studio sidebar, right-click `Packages` folder and click `Add Packages...`. Search for 'Braze' and install the latest .NET MAUI iOS NuGet packages: [Braze.iOS.BrazeKit](https://www.nuget.org/packages/Braze.iOS.BrazeKit), [Braze.iOS.BrazeUI](https://www.nuget.org/packages/Braze.iOS.BrazeUI), and [Braze.iOS.BrazeLocation](https://www.nuget.org/packages/Braze.iOS.BrazeLocation) into your project.
We also provide the compatibility libraries packages: [Braze.iOS.BrazeKitCompat](https://www.nuget.org/packages/Braze.iOS.BrazeKitCompat) and [Braze.iOS.BrazeUICompat](https://www.nuget.org/packages/Braze.iOS.BrazeUICompat), to help make your migration to .NET MAUI easier.
The second integration method is to include the [binding source](https://github.com/braze-inc/braze-xamarin-sdk). Under [`appboy-component/src/iosnet6`](https://github.com/braze-inc/braze-xamarin-sdk/tree/master/appboy-component/src/iosnet6/BrazeiOSNet6Binding) you will find our binding source code; adding a project reference to the ```BrazeiOSBinding.csproj``` in your .NET MAUI application will cause the binding to be built with your project and provide you access to the Braze iOS SDK. Make sure `BrazeiOSBinding.csproj` is showing in your project's "Reference" folder.
### Step 2: Configure your Braze instance
#### Step 2.1: Configure the Braze SDK in Braze.xml
Now that the libraries have been integrated, you have to create an `Braze.xml` file in your project's `Resources/values` folder. The contents of that file should resemble the following code snippet:
**Note:**
Be sure to substitute `YOUR_API_KEY` with the API key located at **Settings** > **API Keys** in the Braze dashboard.
```xml
YOUR_API_KEYYOUR_CUSTOM_ENDPOINT_OR_CLUSTERXAMARINNUGET
```
If you are including the binding source manually, remove `NUGET` from your code.
**Tip:**
To see an example `Braze.xml`, check out our [Android MAUI sample app](https://github.com/braze-inc/braze-xamarin-sdk/blob/master/appboy-component/samples/android-net-maui/BrazeAndroidMauiSampleApp/BrazeAndroidMauiSampleApp/Resources/values/Braze.xml).
#### Step 2.2: Add required permissions to Android manifest
Now that you've added your API key, you need to add the following permissions to your `AndroidManifest.xml` file:
```xml
```
For an example of your `AndroidManifest.xml`, see the [Android MAUI](https://github.com/braze-inc/braze-xamarin-sdk/blob/master/appboy-component/samples/android-net-maui/BrazeAndroidMauiSampleApp/BrazeAndroidMauiSampleApp/AndroidManifest.xml) sample application.
#### Step 2.3: Track user sessions and registering for in-app messages
To enable user session tracking and register your app for in-app messages, add the following call to the `OnCreate()` lifecycle method of the `Application` class in your app:
```kotlin
RegisterActivityLifecycleCallbacks(new BrazeActivityLifecycleCallbackListener());
```
When setting up your Braze instance, add the following snippet to configure your instance:
**Note:**
Be sure to substitute `YOUR_API_KEY` with the API key located at **Settings** > **API Keys** in the Braze dashboard.
```csharp
var configuration = new BRZConfiguration("YOUR_API_KEY", "YOUR_ENDPOINT");
configuration.Api.AddSDKMetadata(new[] { BRZSDKMetadata.Xamarin });
braze = new Braze(configuration);
```
See the `App.xaml.cs` file in the [iOS MAUI](https://github.com/braze-inc/braze-xamarin-sdk/blob/master/appboy-component/samples/ios-net-maui/BrazeiOSMauiSampleApp/BrazeiOSMauiSampleApp/App.xaml.cs) sample application.
### Step 3: Test the integration
Now you can launch your application and see sessions being logged to the Braze dashboard (along with device information and other analytics). For a more in-depth discussion of best practices for the basic SDK integration, consult the [Android integration instructions](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=android).
Now you can launch your application and see sessions being logged to the Braze dashboard. For a more in-depth discussion of best practices for the basic SDK integration, consult the [iOS integration instructions](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?sdktab=swift).
**Important:**
Our current public .NET MAUI binding for the iOS SDK does not connect to the iOS Facebook SDK (linking social data) and does not include sending the IDFA to Braze.
# 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).
## About the Braze Vega SDK
The Braze Vega SDK lets you collect analytics and display rich in-app messages to your users. Most methods in the Braze Vega SDK are asynchronous and return promises that should be awaited or resolved.
## Integrating the Braze Vega SDK
### Step 1: Install the Braze library
Install the Braze Vega SDK using your preferred package manager.
If your project uses NPM, you can add the Braze Vega SDK as a dependency.
```bash
npm install @braze/vega-sdk --save
```
After installation, you can import the methods you need:
```javascript
import { initialize, changeUser, openSession } from "@braze/vega-sdk";
```
If your project uses Yarn, you can add the Braze Vega SDK as a dependency.
```bash
yarn add @braze/vega-sdk
```
After installation, you can import the methods you need:
```javascript
import { initialize, changeUser, openSession } from "@braze/vega-sdk";
```
### Step 2: Initialize the SDK
After the Braze Vega SDK is added to your project, 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.
**Important:**
You must await or resolve the `changeUser` promise before calling other Braze methods, or events and attributes may be set on the incorrect user.
```javascript
import { useEffect } from "react-native";
import {
initialize,
changeUser,
logCustomEvent,
openSession,
setCustomUserAttribute,
setUserCountry
} from "@braze/vega-sdk";
const App = () => {
useEffect(() => {
const initBraze = async () => {
// Initialize the SDK
await initialize("YOUR-API-KEY", "YOUR-SDK-ENDPOINT", {
sessionTimeoutInSeconds: 60,
appVersionNumber: "1.2.3.4",
enableLogging: true, // set to `true` for debugging
});
// Change user
await changeUser("user-id-123");
// Start a session
await openSession();
// Log custom events and set user attributes
logCustomEvent("visited-page", { pageName: "home" });
setCustomUserAttribute("my-attribute", "my-attribute-value");
setUserCountry("USA");
};
initBraze();
}, []);
return (
// Your app components
);
};
```
**Important:**
Anonymous users 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.
## Optional configurations
### Logging
You can enable SDK logging to help with debugging and troubleshooting. There are multiple ways to enable logging.
#### Enable logging during initialization
Pass `enableLogging: true` to `initialize()` to log debugging messages to the console:
```javascript
initialize("YOUR-API-KEY", "YOUR-SDK-ENDPOINT", {
enableLogging: true
});
```
**Important:**
Basic logs are visible to all users, so consider disabling logging before releasing your code to production.
#### Enable logging after initialization
Use `toggleLogging()` to enable or disable SDK logging after initialization:
```javascript
import { toggleLogging } from "@braze/vega-sdk";
// Enable logging
toggleLogging();
```
#### Custom logging
Use `setLogger()` to provide a custom logger function for more control over how SDK logs are handled:
```javascript
import { setLogger } from "@braze/vega-sdk";
setLogger((message) => {
console.log("Braze Custom Logger: " + message);
// Add your custom logging logic here
});
```
### Configuration options
You can pass additional configuration options to `initialize()` to customize the SDK behavior:
```javascript
await initialize("YOUR-API-KEY", "YOUR-SDK-ENDPOINT", {
sessionTimeoutInSeconds: 60, // Configure session timeout (default is 1800 seconds)
appVersionNumber: "1.2.3.4", // Set your app version
enableLogging: true, // Enable SDK logging
});
```
## Upgrading the SDK
When you reference the Braze Vega SDK from NPM or Yarn, you can upgrade to the latest version by updating your package dependency:
```bash
npm update @braze/vega-sdk
# or, using yarn:
yarn upgrade @braze/vega-sdk
```
## Testing your integration
To verify your SDK integration is working correctly:
1. Initialize the SDK with `enableLogging: true` to see debug messages in the console
2. Ensure you `await changeUser()` before calling other SDK methods
3. Call `await openSession()` to start a session
4. Check your Braze dashboard under **Overview** to verify that session data is being recorded
5. Test logging a custom event and verify it appears in your dashboard
**Note:**
SDK統合のQAを行う際は、[SDKデバッガー](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/debugging)を使用すると、アプリの詳細ログを有効にすることなく問題をトラブルシューティングできます。
# Google Tag ManagerとBraze SDK
Source: /docs/ja/developer_guide/sdk_integration/google_tag_manager/index.md
# Google Tag ManagerとBraze SDK {#google-tag-manager-with-the-braze-sdk}
> [Google Tag Manager(GTM)](https://developers.google.com/tag-platform/tag-manager)をBraze SDKと連携することで、コード変更やアプリの新バージョンリリースを必要とせずに、Brazeのイベントトラッキングやユーザー属性の更新をリモートでコントロールできます。
## About Google Tag Manager for Web {#google-tag-manager}
Google Tag Manager (GTM) lets you remotely add, remove, and edit tags on your website without requiring a production code release or engineering resources. Braze offers the following templates for the Web SDK:
|Tag Type|Use Case|
|--------|--------|
| Initialization tag | This tag lets you [integrate the Web Braze SDK](https://www.braze.com/docs/ja/ja/developer_guide/sdk_integration/?tab=google%20tag%20manager&sdktab=web) without needing to modify your site’s code.|
| Action tag | This tag lets you [create Content Cards](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/?sdktab=web#web_using-google-tag-manager), [set user attributes](https://www.braze.com/docs/ja/ja/developer_guide/analytics/setting_user_attributes/?tab=google%20tag%20manager&sdktab=web), and [manage data collection](https://www.braze.com/docs/ja/ja/developer_guide/analytics/managing_data_collection/?tab=google%20tag%20manager&sdktab=web).|
{: .reset-td-br-1 .reset-td-br-2 aria-label="About Google Tag Manager for Web #google-tag-manager" }
## Tag sequencing for Braze action tags
Custom events and other Braze action tags can fail when they fire before the **Braze Initialization** tag finishes loading the Web SDK. In Google Tag Manager, open the action tag, go to **Advanced Settings** > **Tag Sequencing**, select **A tag that fires before [this tag] is fired**, and choose your Braze Initialization tag.
For more detail, see [Verify tag sequencing for custom events](https://www.braze.com/docs/ja/ja/developer_guide/content_cards/?sdktab=web#tag-sequencing).
## Log purchases with GTM
In Braze action tags and Custom HTML tags, call `braze.logPurchase()` to record revenue. The legacy `appboy.logPurchase()` namespace is not supported in current Web SDK integrations.
## Logging custom events with GTM
You can log custom events using a **Custom HTML** tag in GTM. This approach uses the GTM [data layer](https://developers.google.com/tag-platform/tag-manager/datalayer) to pass event data from your site to a GTM tag that calls the Braze Web SDK.
### Step 1: Push the event to the data layer
In your site's code, push an event to the data layer wherever you want to trigger the custom event. For example, to log a custom event when a button is clicked:
```html
```
### Step 2: Create a trigger in GTM
1. In your GTM container, go to **Triggers** and create a new trigger.
2. Set the **Trigger Type** to **Custom Event**.
3. Set the **Event Name** to the same value you pushed to the data layer (for example, `my_custom_event`).
4. Choose when the trigger should fire (for example, **All Custom Events**).
### Step 3: Create a Custom HTML tag
1. In GTM, go to **Tags** and create a new tag.
2. Set the **Tag Type** to **Custom HTML**.
3. In the HTML field, add the following:
```html
```
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`

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.

**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.

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`.

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.

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.

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)から利用可能です:
**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をインストールすると、基本的な分析機能(セッション処理)と基本的なアプリ内メッセージが提供されます。追加のチャネルと機能のために統合をさらにカスタマイズする必要があります。
{#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 秒です。
## セッショントラッキングをテストする
ユーザーを介してセッションを検出するには、ダッシュボードでユーザーを見つけ、ユーザープロファイルの [**アプリの利用状況**] に移動します。「セッション」指標が想定どおりに増加していることを確認することで、セッショントラッキングが機能していることを確認できます。

# 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**を選択します。
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
CFBundleURLTypesCFBundleURLName{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
LSApplicationQueriesSchemesmyappfacebooktwitter
```
詳細については、`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
}
```

# ユニバーサルリンク {#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
NSAppTransportSecurityNSAllowsArbitraryLoadsNSExceptionDomainsexample.comNSExceptionAllowsInsecureHTTPLoadsNSIncludesSubdomains
```
詳細については、[アプリトランスポートセキュリティのキー](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
NSAppTransportSecurityNSAllowsArbitraryLoads
```
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}

### 設定ページからジオフェンスを有効にする {#enable-geofences-from-the-settings-page}

## 自動ジオフェンスリクエストを無効にする {#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` である「イベント名」を検索するトリガーを作成します。

次に、新しいタグ(「Function Call」とも呼ばれます)を作成し、この記事で後述する[カスタムタグプロバイダー](#adding-ios-google-tag-provider)のクラスパスを入力します。
このタグは、先ほど作成した `played song` イベントをロギングするとトリガーされます。
サンプルタグのカスタムパラメーター(キーと値のペア)では、`eventName` を `played song` に設定しました。これが、Brazeにロギングされるカスタムイベント名になります。
**Important:**
カスタムイベントの送信時に、`actionType` を `logEvent` に設定し、次の例のように `eventName` の値を設定します。
この例のカスタムタグプロバイダーは、これらのキーを使用して、Google Tag Managerからデータを受信した際に実行するアクションとBrazeに送信するイベント名を決定します。

また、追加のキーと値のペア引数をタグに含めることもできます。この引数は、カスタムイベントプロパティとしてBrazeに送信されます。`eventName` および `actionType` は、カスタムイベントプロパティでは無視されません。次のサンプルタグでは、`genre` を渡します。これは、Google Tag Managerでタグ変数を使用して定義されており、アプリでロギングしたカスタムイベントから取得されます。
`genre` イベントプロパティは、「Firebase - Event Parameter」変数としてGoogle Tag Managerに送信されます。Google Tag Manager for iOSでは、Firebaseがデータレイヤーとして使用されるためです。

最後に、ユーザーがアプリで曲を再生すると、タグのトリガー名 `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 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.
Adds Braze.LiveActivities.UpdateEvent, a new enum covering activity and token lifecycle events (e.g. started, active, dismissed, stale, ended, contentUpdated, pushTokenUpdated) as well as Braze SDK operation events (trackingStarted, trackingResumed, pushTokenFlushed).
Adds Braze.LiveActivities.ErrorEvent, a new enum covering observation failures, token registration failures (with isTransient for retry logic), activityNotFound, and invalidPushTokenTag.
Adds subscribeToStateUpdates(_:) and subscribeToErrors(_:) methods on Braze.LiveActivities to register callbacks for the above events. Both return a Braze.Cancellable to remove the subscription.
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.
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
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 BrazeKitCompatABKContentCard.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.
Adds dSYM files to the dynamic and mergeable variants of the Braze SDK XCFrameworks.
This addresses an App Store submission validation warning when using Xcode 16.0 or later.
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.
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.
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
extensionAppDelegate:@preconcurrencyUNUserNotificationCenterDelegate{// 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.
Adds additional safeguards to Braze.Notifications.subscribeToUpdates to ensure the same Push notification can’t trigger the update closure multiple times.
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
Adds support for delayed SDK initialization, allowing you to create the Braze instance outside of application(_:didFinishLaunchingWithOptions:).
The SDK can now be initialized asynchronously, while conserving the ability to process incoming Braze push notifications.
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:
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).
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.
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.
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:
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 the following methods to the liveActivities module:
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:
Sessions now properly start as expected.
The click behavior Open Web URL Inside App now properly opens the URL in a modal web view. Previously, the URL would always be opened using the default web browser.
[BrazeDelegate.braze(:willPresentModalWithContext:)](https://braze-inc.github.io/braze-swift-sdk/documentation/brazekit/brazedelegate/braze(:willpresentmodalwithcontext:)-1fj41) now has a default implementation.
Handling network requests and persisting data properly extend the lifetime of the application for processing.
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.
Follow the manual integration guide to add the SDWebImage.bundle to your project for static XCFrameworks.
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.
Additionally, when presented as a part of In-App Messages or Content Cards, those URLs will be fetched using the URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData caching policy, which always requests a fresh version from the source and ignores any cached versions.
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.
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.
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.
Adds the Braze.Configuration.forwardUniversalLinks configuration. When enabled, the SDK will redirect universal links from Braze campaigns to the appropriate system methods.
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
Adds a new SDKMetadata option .reactnativenewarch for the React Native New Architecture.
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.
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.
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
The in-app message data models sent to BrazeInAppMessagePresenter.present(message:) now contain remote asset URLs. Previously, these data models would contain local asset URLs.
This change is only breaking in two situations:
When implementing a custom BrazeInAppMessagePresenter.
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.
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.
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:
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.:
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
Adds two Example schemes:
InAppMessage-Custom-UI:
Demonstrates how to implement your own custom In-App Message UI.
Available on iOS and tvOS.
ContentCards-Custom-UI:
Demonstrates how to implement your own custom Content Card UI.
。
# 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 変更ログ
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.
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!
Class level API methods have changed to instance methods to make subclassing easier, however getNavigationContentCardsViewController and getNavigationFeedViewController are left in as class methods for backwards compatibility.
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.
This removes the need for integrators to exclude the arm64 architecture when building for the simulator. Please undo any of the changes that may have been made when upgrading to 3.27.0 (Integrators will now be required to exclude …).
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.
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
...
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.
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.
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.
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.
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
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:
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:
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.
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:
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.
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.
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.
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.
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.
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:
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.
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.
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 ワークスペースを使用してください。

### ステップ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.

## 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**.

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].

### ステップ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バージョンは以下の通りです。
### カスタムプロパティにアクセスする {#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.
{: 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.

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.

### 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).

### 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/).

## 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バージョンが必要です:
## 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
```

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.

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

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).

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.

#### 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.

#### 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**.

[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**.
{: 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.
{: 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**を選択します。すぐにデバイスでコンテンツカードを起動できます。

## コンテンツカードの配置 {#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に割り当て、その値に基づいて、ランタイム時にカードの動作、外観、または機能をダイナミックに調整します。
{: 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レイヤーからインポートされます。そこから、カードのスタイルの特定の部分、カードが表示される順序、フィードがユーザーに表示される方法を調整できます。

**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の作成時、マーケターはカードを固定するオプションを選択できます。固定されたカードはユーザーのフィードの上部に表示され、ユーザーはそれを閉じることができません。カードスタイルをカスタマイズする際に、固定アイコンの見た目を変更できます。
{: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の下部には、カードが閲覧されたかどうかを示す青い線が表示されます。

カードの未読インジケーターの色を変更するには、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}
{: 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`はセットアップ時に把握しておく必要があります。
{: style="max-width:60%;"}
## インタラクティブコンテンツとしてのContent Cards {#content-cards-as-interactive-content}
{: 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)を参照してください。
{: style="max-width:80%;"}
## Content Cardsバッジ {#content-card-badges}
{: 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は「更新はありません。後で再度確認してください。」という「空のフィード」エラーメッセージを表示します。この「空のフィード」エラーメッセージは、次のようにカスタマイズできます。

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
CFBundleURLTypesCFBundleURLNameYOUR.SCHEMECFBundleURLSchemesYOUR.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
LSApplicationQueriesSchemesmyappfbtwitter
```
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
NSAppTransportSecurityNSAllowsArbitraryLoadsNSExceptionDomainsexample.comNSExceptionAllowsInsecureHTTPLoadsNSIncludesSubdomains
```
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
NSAppTransportSecurityNSAllowsArbitraryLoads
```
## 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.
{: 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.
{: 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
{: 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:

## 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).
{: 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.
{: 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.

[`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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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:

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).
{: 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.
{: 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.

[`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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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:

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).
{: 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.
{: 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.

[`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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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:

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).
{: 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.
{: 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.

[`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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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:

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).
{: 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.
{: 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.

[`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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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:

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**.
{: 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.
{: 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).
{: 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.
{: 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.

[`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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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:

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).
{: 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.
{: 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.

[`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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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.
{: 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:

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.

**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)を作成します。

プッシュキャンペーンにはキーと値のペアエクストラを含める必要があります。これは、このプッシュキャンペーンがSDKカスタムイベントを記録するために送信されることを示します。このイベントはアプリ内メッセージをトリガーするために使用されます。
{: style="max-width:70%;" }
前出のプッシュコールバックサンプルコードは、キーと値のペアを認識して、適切なSDKカスタムイベントをログに記録します。
「アプリ内メッセージトリガー」イベントに添付するイベントプロパティを含めるには、プッシュペイロードのキーと値のペアでプロパティを渡します。この例では、後続のアプリ内メッセージのキャンペーン名が含められています。カスタムプッシュコールバックは、カスタムイベントをログに記録するときに、イベントプロパティのパラメーターとして値を渡すことができます。
#### ステップ3: アプリ内メッセージキャンペーンを作成する {#step-3-create-an-in-app-message-campaign}
Brazeダッシュボードで、ユーザーに表示されるアプリ内メッセージキャンペーンを作成します。このキャンペーンにはアクションベースの配信が必要であり、カスタムプッシュコールバック内から記録されたカスタムイベントからトリガーされる必要があります。
以下の例では、イベントプロパティを最初のサイレントプッシュの一部として送信することで、トリガーされる特定のアプリ内メッセージが設定されています。

アプリがフォアグラウンドにないときにサーバー送信イベントがログに記録されると、イベントはログに記録されますが、アプリ内メッセージは表示されません。アプリケーションがフォアグラウンドになるまでイベントを遅延させたい場合は、カスタムプッシュレシーバーにチェックを含めて、アプリがフォアグラウンドになるまでイベントを無視または遅延させる必要があります。
#### ステップ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)を作成します。

プッシュキャンペーンにはキーと値のペアエクストラを含める必要があります。これは、このプッシュキャンペーンがSDKカスタムイベントを記録するために送信されることを示します。このイベントはアプリ内メッセージをトリガーするために使用されます。

`application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`メソッド内のコードはキー`IS_SERVER_EVENT`をチェックし、存在する場合はSDKカスタムイベントをログに記録します。
プッシュペイロードのキーと値のペアエクストラ内で目的の値を送信することで、イベント名またはイベントプロパティのいずれかを変更できます。カスタムイベントを記録する場合、これらのエクストラはイベント名のパラメーターまたはイベントプロパティとして使用できます。
#### ステップ3: アプリ内メッセージキャンペーンを作成する
Brazeダッシュボードで、ユーザーに表示されるアプリ内メッセージキャンペーンを作成します。このキャンペーンにはアクションベースの配信があり、`application(_:didReceiveRemoteNotification:fetchCompletionHandler:)`メソッド内から記録されたカスタムイベントからトリガーされる必要があります。
以下の例では、イベントプロパティを最初のサイレントプッシュの一部として送信することで、トリガーされる特定のアプリ内メッセージが設定されています。

**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
```
## 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
CFBundleURLTypesCFBundleURLNameYOUR.SCHEMECFBundleURLSchemesYOUR.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
LSApplicationQueriesSchemesmyappfbtwitter
```
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
NSAppTransportSecurityNSAllowsArbitraryLoadsNSExceptionDomainsexample.comNSExceptionAllowsInsecureHTTPLoadsNSIncludesSubdomains
```
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
NSAppTransportSecurityNSAllowsArbitraryLoads
```
## 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.

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.

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.

**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.

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.

**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. レスポンスデータに正しいアプリ内メッセージが表示されていることを確認します。

##### メッセージがリクエストされない場合のトラブルシューティング {#troubleshoot-messages-not-being-requested}
アプリ内メッセージがリクエストされていない場合、アプリがセッションを正しくトラッキングしていない可能性があります。アプリ内メッセージはセッション開始時に更新されます。セッションタイムアウトのセマンティクスに基づいて、アプリがセッションを開始していることを確認してください。

##### メッセージが返されない場合のトラブルシューティング {#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)を参照してください。
- **インプレッションが以前より少ない:** セグメントとキャンペーンの変更ログを確認してください。より優先度の高いキャンペーンで同じトリガーイベントを再利用していないか確認してください。

デリゲートまたはカスタムハンドラーを使用してアプリ内メッセージを手動で表示している場合は、インプレッションとクリックを自分でログに記録する必要があります。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).
{: 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**.

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**.

### 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**.

Select **Add Key** > **Create new key**.

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.
{: 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**.

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**.

**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**.

Select **Cloud Messaging**, then under **Firebase Cloud Messaging API (V1)**, copy the number in the **Sender ID** field.

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
trueFIREBASE_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-HIJK456789LMtrue603679405392
```
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
truecom.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:

### 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_ICONREPLACE_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.

#### 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
trueyour.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 nameYour 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.

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
{: 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.

### 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
{: 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**.

Select **Cloud Messaging**, then under **Firebase Cloud Messaging API (V1)**, copy the **Sender ID** to your clipboard.

#### 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
trueFIREBASE_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`.

### 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.
{: 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`.

### 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.

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.

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.

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**.

Select **Cloud Messaging**, then under **Firebase Cloud Messaging API (V1)**, copy the **Sender ID** to your clipboard.

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.

## 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.
{: 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.
{: 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: 
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.

#### 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.

#### 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.

#### 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.

### 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.

```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`.

#### 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:

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.

```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
trueFIREBASE_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.
{: style="max-width:40%;"}
This example is rendered with the following HTML:
```html
MultiColorPush
testmessage
```
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.
{: 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.

## 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.

### 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.
{: style="max-width:65%;"}
The summary text will display under the body of the message in the expanded view.
{: 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:

### 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.

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`.
{: 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:

### 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`.

### 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.

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.

### 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.

### 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.
{: style="max-width:65%;"}
The summary text will display under the body of the message in the expanded view.
{: 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:

### 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.

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
CFBundleURLTypesCFBundleURLNameYOUR.SCHEMECFBundleURLSchemesYOUR.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
LSApplicationQueriesSchemesmyappfbtwitter
```
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
NSAppTransportSecurityNSAllowsArbitraryLoadsNSExceptionDomainsexample.comNSExceptionAllowsInsecureHTTPLoadsNSIncludesSubdomains
```
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
NSAppTransportSecurityNSAllowsArbitraryLoads
```
## 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`.

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.

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).

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**.
{: 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.

2. Select the "BrazeNotificationService" framework.

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/).

#### 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.

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.

#### 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`:


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`.

**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:

### 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**をオンにしてください。

### ステップ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.

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.

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.

**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.

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.

**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
{: 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.

## 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:

### 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.

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.
{: 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:
{: 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.

## 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:

### 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}
{: 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:**
ライブアクティビティとプッシュ通知は似ていますが、システム権限は別個のものです。デフォルトでは、すべてのライブアクティビティ機能が有効になっていますが、ユーザーはアプリごとにこの機能を無効にすることができます。