# モバイルIn-AppメッセージングのiOS SDK連携

プレビュー版Engage Mobile SDKを使用すると、iOSアプリをEngage StudioのモバイルIn-Appメッセージングに接続できます。アプリが`trackImmediately`でトリガーイベントを送ると、SDKがRealtime Personalizationからオファーを取得し、対応するメッセージを表示します。

プレビュー
ネイティブSDK連携はプレビューです。一般提供前に、API、パッケージの配布方法、メッセージペイロード、表示動作が変更される場合があります。Treasure AIが提供するリリースごとのSDK配布手順に従ってください。

## SDKが担当する処理

SDKはThin Clientとして動作します。Realtime Personalizationが返すかどうかを決定し、SDKは返された判定を実行します。

| 責務 | 担当 |
|  --- | --- |
| オーディエンスの適格性と配信判定 | Realtime Personalization |
| トリガーイベントとアプリのライフサイクルタイミング | お客様のアプリ |
| レスポンスからのメッセージ選択 | SDK |
| ModalとBannerのWebView表示 | SDK |
| Hosted Pages URLの表示 | SDK |
| アプリ固有のDeep Link処理 | お客様のアプリ |
| アプリ固有のカスタムアクション | お客様のアプリ |
| キャンペーンのImpression、Click、Dismiss計測 | SDK |


## 事前準備

次の値を用意してください。

- Treasure AIアカウント用の書き込み専用APIキー。
- アカウントリージョンのRecordsエンドポイント。
- Personalizationエンドポイント。
- Personalizationトークン。
- トリガーイベント用のデータベースとテーブル。
- メッセージを表示する画面や操作を識別するイベントスキーマ。


SDKパッケージはiOS 12以降をサポートします。アプリをビルドする前に、提供されたプレビュー版アーティファクトでサポートされるOS範囲を確認してください。

## SDKモジュールの導入

プレビュー版パッケージは次の2つのモジュールを提供します。

- `TreasureData` — イベント収集、バッファリング、アップロード。
- `TreasureDataEngage` — Mobile In-AppメッセージとHosted Pagesの表示に使用するiOS向けWebKitレンダリングレイヤー。


プレビュー版パッケージの配布方法は、公開インストール手順としては確定していません。プレビューへのアクセスと使用するパッケージバージョンについては、Treasure AIの担当者に確認してください。

## クイックスタート

アプリ起動時に両方のモジュールをインポートし、SDKを一度設定します。

```swift
import TreasureData
import TreasureDataEngage

TreasureData.initializeWithApiKey(
    "<WRITE_ONLY_API_KEY>",
    apiEndpoint: "https://<region>.records.in.treasuredata.com"
)

let td = TreasureData.sharedInstance()
td.defaultDatabase = "<DATABASE>"
td.defaultTable = "<EVENT_TABLE>"
td.personalizationEndpoint =
    "https://p13n-api.treasuredata.com"
td.personalizationToken = "<PERSONALIZATION_TOKEN>"

// 計測データをインストール単位に関連付けるために使用します。
td.enableAutoAppendUniqId()

// メッセージコンテンツからwindow.TDContextとして読み取れる任意の値です。
td.profileContext = [
    "member_tier": "gold"
]

// iOSで表示するために必要です。
TDEngage.install()
```

メッセージをトリガーできる画面またはイベントで、`trackImmediately`を呼び出します。

```swift
td.trackImmediately([
    "event": "pageview",
    "screen_name": "home"
])
```

コールバックのオーバーロードを使用すると、SDKがメッセージを表示したかどうかを確認できます。

```swift
td.trackImmediately([
    "event": "pageview",
    "screen_name": "campaign"
], table: "<EVENT_TABLE>") { shown in
    print("In-App message shown: \(shown)")
}
```

`addEvent`と`uploadEvents`は通常のイベント送信に引き続き使用できます。これらのAPIはMobile In-Appメッセージをトリガーしません。

## Core APIの設定

| APIまたはプロパティ | 用途 |
|  --- | --- |
| `personalizationEndpoint` | メッセージオファーを取得するエンドポイント。 |
| `personalizationToken` | Personalizationの読み取りに使用する認証情報。書き込み用APIキーとは分けて管理します。 |
| `defaultDatabase` / `defaultTable` | トリガーリクエストと通常イベントのデフォルト送信先。 |
| `trackImmediately(_:table:onResult:)` | トリガーイベントを送信し、メッセージを取得します。 |
| `profileContext` | メッセージコンテンツへ`window.TDContext`として渡すJSON化可能な値。 |
| `TDEngage.install()` | iOSのレンダリングレイヤーをCore SDKに登録します。 |
| `linkHandler` | アプリがURLやCustom Schemeを処理するためのフック。 |
| `bridgeDelegate` | メッセージコンテンツからのアプリ固有の`invoke`呼び出しを受け取ります。 |
| `openUrl(_:context:)` | アプリがすでに持っているURLを表示します。プッシュ通知のペイロードからURLを受け取る場合などに使用します。 |


## メッセージ配信フロー

1. アプリが`trackImmediately(event)`を呼び出します。
2. Treasure Data iOS SDKがPersonalizationへトリガーイベントを送信します。
3. Realtime Personalizationがオファーまたは該当なしを返します。
4. `TreasureDataEngage`が表示可能なメッセージを1件選択します。
5. SDKが同時表示ガードを確認します。
6. SDKがModal、Banner、またはHosted Pagesを表示します。
7. アプリとメッセージコンテンツが結果の操作を処理します。


キャンペーンに一致しなければ、SDKは何も表示しません。これはエラーではなく、通常の結果です。

SDKはレスポンスから表示可能なメッセージを1件だけ選択します。別のメッセージが表示中の場合、新しいメッセージは表示されません。

## Hosted Pages

Hosted Pagesは、URLからコンテンツを読み込むキャンペーンメッセージです。SDKはURLをフルスクリーンWebViewで表示し、設定されたプロフィールコンテキストを注入します。

次のような用途に使用できます。

- クーポンページ
- スタンプカード
- 抽選やインタラクティブなプロモーション
- アンケートやフォーム
- パーソナライズされたキャンペーンページ


Hosted PagesにはModalやBannerの表示設定は適用されません。ホストされたページ側で、エクスペリエンスを終了するための導線を提供してください。

### キャンペーン配信のHosted Pages

アプリが`trackImmediately`を呼び出し、Realtime PersonalizationがHosted Pagesオファーを返した場合、SDKはキャンペーン計測に必要なキャンペーンIDを持って表示します。

### URLを直接表示する場合

アプリがすでにURLを持っている場合は、`openUrl`を呼び出します。

```swift
let url = URL(string: "https://example.com/coupon")!
TreasureData.sharedInstance().openUrl(
    url,
    context: ["coupon_id": "abc123"]
)
```

これはPush通知のタップ後の処理に使用できます。URLはSDKのWebViewに表示されますが、キャンペーンオファーを経由していないため、キャンペーンの`impression`、`click`、`dismiss`は記録されません。

## リンク処理

アプリがCustom Schemeを処理する場合は、`linkHandler`を使用します。

```swift
td.linkHandler = { url in
    guard url.scheme == "engage-demo" else {
        return false
    }

    AppRouter.shared.open(url)
    return true
}
```

アプリがURLを処理した場合だけ`true`を返してください。未設定または`false`の場合、SDKは対応するWeb URLに対してデフォルト動作を行います。アプリ側で別のブラウザーを開いてから`false`を返さないでください。

ハンドラーはメインスレッドで同期的に呼び出されます。ハンドラー自体は短く保ち、URLを受け取った後に必要な処理をアプリのサービスへ渡してください。

## カスタムアクション

メッセージコンテンツは、SDKのブリッジを介してアプリ固有の処理を要求できます。アプリは`TDEngageBridgeDelegate`で要求を受け取ります。

```swift
final class EngageClient: NSObject, TDEngageBridgeDelegate {
    func handleTDBridgeInvoke(
        name: String,
        params: [String: Any]
    ) {
        switch name {
        case "grantPoints":
            // 認証、認可、パラメーターの上限を確認します。
            break
        default:
            break
        }
    }
}

td.bridgeDelegate = engageClient
```

SDKはアクション名を解釈せず、要求を認可もしません。メッセージコンテンツとすべてのパラメーターを信頼できない入力として扱ってください。Delegateはweak参照のため、短命なView Controllerではなく、アプリのライフサイクル中存続するオブジェクトを割り当てます。

## メッセージコンテンツへプロフィールコンテキストを渡す

`profileContext`は、Modal、Banner、Hosted Pagesのコンテンツへ`window.TDContext`として注入されます。

```swift
td.profileContext = [
    "member_tier": "gold",
    "points": 1200
]
```

コンテンツ側では、ページの準備後に値を読み取れます。

```javascript
const tier = window.TDContext?.member_tier;
```

次のルールに従ってください。

- JSON化できる値だけを使用します。
- SDKはコンテキストを永続化しないため、アプリ起動ごとに設定します。
- サインイン中のユーザーが変わったら、値をクリアまたは置き換えます。
- APIキー、トークン、パスワード、ホストされたHosted Pagesページに見せるべきでない値を含めないでください。
- JavaScriptの数値精度の問題を避けるため、大きな数値のIDは文字列で渡します。


## 画面遷移を処理する

Personalizationリクエストは非同期です。レスポンスが到着する前に、ユーザーがトリガー元の画面を離れる場合があります。プレビューSDKでは、表示を抑制するためのゲートと、コールバック形式から返される実行中タスクを使用して、古いリクエストを抑制またはキャンセルできます。

トリガー元の画面にいる場合だけ表示したい場合は、次のようにします。

```swift
let task = td.trackImmediately([
    "event": "pageview",
    "screen_name": "checkout"
], table: "<EVENT_TABLE>") { shown in
    // 必要に応じてアプリの診断情報を更新します。
}

// トリガー元の画面が無効になったらキャンセルします。
task?.cancel()
```

表示ゲートの正確なAPIはプレビュー契約の一部であり、一般提供前に変更される場合があります。

## 計測

プレビューSDKの連携では、キャンペーン配信されたメッセージの計測を自動的に記録します。

- `impression` — エクスペリエンスが表示されたとき。
- `click` — 対応するリンクまたはブリッジアクションを使用したとき。
- `dismiss` — エクスペリエンスが閉じられたとき。


計測データをインストールに関連付ける場合、`enableAutoAppendUniqId()`が実質的に必要です。計測先とスキーマは一般提供前に変更される場合があります。

トラブルシューティングについては、[モバイルIn-Appのトラブルシューティング](/ja/products/marketing-cloud/engage-studio/channels/mobile-inapp/troubleshooting)を参照してください。

## 最小連携チェックリスト

サンプルアプリのリポジトリを使用せずに、プレビューSDKを連携できます。

- 付属する配布手順に従って、プレビュー版`TreasureData`と`TreasureDataEngage`モジュールを追加します。
- アプリ起動時にCore SDKを一度初期化します。
- Personalizationエンドポイント、トークン、データベース、イベントテーブルを設定します。
- Core SDK初期化後に`TDEngage.install()`を呼び出します。
- コンテンツで必要な場合だけ`profileContext`、`linkHandler`、`bridgeDelegate`を設定します。
- 対象画面またはイベントで`trackImmediately`を呼び出します。
- 対応するiOSデバイスでModal、Banner、Hosted Pagesをテストします。
- Mobile Pushを使用する場合は、Pushトークンを別途登録します。
- リリース前にImpression、Click、Dismiss、Deep Link、Hosted Pagesを確認します。


プレビューSDKのパッケージ名、バージョン、配布URLはリリースごとに異なります。ソースリポジトリURLではなく、アーティファクトに付属するインストール手順を使用してください。