|
| 1 | +# Embedded Messaging — Iterable Android SDK |
| 2 | + |
| 3 | +Display persistent, native embedded messages within app screens using placements configured in Iterable. |
| 4 | + |
| 5 | +> **Prerequisites:** SDK must be initialized with `setEnableEmbeddedMessaging(true)` (see [integration-guide.md](integration-guide.md)). Dependency: `iterableapi-ui` for OOTB views. |
| 6 | +
|
| 7 | +--- |
| 8 | + |
| 9 | +## Business Context |
| 10 | + |
| 11 | +Embedded messages are persistent content blocks that live inside app screens — unlike in-app messages (which are overlays) or push (which is external). The marketing team creates campaigns and assigns them to **placements** in Iterable's dashboard. Each placement has an auto-generated numeric ID. |
| 12 | + |
| 13 | +The developer's role is to: |
| 14 | + |
| 15 | +1. Enable embedded messaging in the SDK config |
| 16 | +2. Get placement IDs from the marketing team (or Iterable dashboard) |
| 17 | +3. Register update listeners on screens that show embedded content |
| 18 | +4. Render the messages using OOTB views or custom UI |
| 19 | + |
| 20 | +--- |
| 21 | + |
| 22 | +## Decision Points |
| 23 | + |
| 24 | +| Decision | Tier | Default | Notes | |
| 25 | +|----------|------|---------|-------| |
| 26 | +| Enable embedded messaging | 🟠 Important | `false` | Only enable if the app uses embedded placements. Ask the developer. | |
| 27 | +| Placement IDs | 🔴 Critical | N/A | Auto-generated in Iterable dashboard. Must ask the developer — never assume a value. | |
| 28 | +| Which screens show embedded content | 🔴 Critical | N/A | App-specific. Ask the developer which screens should display embedded messages. | |
| 29 | +| OOTB view type (Banner, Card, Notification) vs custom UI | 🟡 Relevant | OOTB Card | Start with OOTB for speed. Go custom when the design system requires it. | |
| 30 | +| Which message to show when placement returns multiple | 🟡 Relevant | First in list | Confirm with the developer this is intentional. Marketing may expect priority-based selection. | |
| 31 | +| OOTB styling (colors, border, radius) | 🟢 Optional | SDK defaults | Customize via `IterableEmbeddedViewConfig` to match app theme. | |
| 32 | + |
| 33 | +--- |
| 34 | + |
| 35 | +## Step 1: Enable in Config |
| 36 | + |
| 37 | +```kotlin |
| 38 | +val config = IterableConfig.Builder() |
| 39 | + .setEnableEmbeddedMessaging(true) // 🟠 Only if using embedded messages |
| 40 | + .build() |
| 41 | +``` |
| 42 | + |
| 43 | +--- |
| 44 | + |
| 45 | +## Step 2: Register Update Listener |
| 46 | + |
| 47 | +> **Agent note:** Replace `PLACEMENT_ID` with the actual placement ID from the developer (🔴 Critical — never assume a value). |
| 48 | +
|
| 49 | +```kotlin |
| 50 | +import com.iterable.iterableapi.IterableEmbeddedUpdateHandler |
| 51 | + |
| 52 | +class YourFragment : Fragment(), IterableEmbeddedUpdateHandler { |
| 53 | + |
| 54 | + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 55 | + IterableApi.onSDKInitialized { |
| 56 | + IterableApi.getInstance().embeddedManager.addUpdateListener(this) |
| 57 | + activity?.runOnUiThread { displayEmbeddedMessages() } |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | + override fun onMessagesUpdated() { |
| 62 | + activity?.runOnUiThread { displayEmbeddedMessages() } |
| 63 | + } |
| 64 | + |
| 65 | + override fun onEmbeddedMessagingDisabled() { |
| 66 | + // Hide embedded UI — messaging was disabled server-side or due to auth issues |
| 67 | + } |
| 68 | + |
| 69 | + private fun displayEmbeddedMessages() { |
| 70 | + val messages = IterableApi.getInstance().embeddedManager.getMessages(PLACEMENT_ID) |
| 71 | + if (messages.isNullOrEmpty()) { |
| 72 | + // Hide embedded UI container |
| 73 | + return |
| 74 | + } |
| 75 | + val message = messages.first() |
| 76 | + // Render using OOTB view or custom UI (see below) |
| 77 | + } |
| 78 | + |
| 79 | + override fun onDestroyView() { |
| 80 | + try { IterableApi.getInstance().embeddedManager.removeUpdateListener(this) } |
| 81 | + catch (_: Exception) { } |
| 82 | + } |
| 83 | +} |
| 84 | +``` |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## Step 3a: OOTB Views |
| 89 | + |
| 90 | +The SDK provides three view types: `BANNER`, `CARD`, and `NOTIFICATION`. |
| 91 | + |
| 92 | +```kotlin |
| 93 | +// newInstance takes (viewType, message, config?) — NO context parameter |
| 94 | +val embeddedView = IterableEmbeddedView.newInstance( |
| 95 | + IterableEmbeddedViewType.CARD, // or BANNER, NOTIFICATION |
| 96 | + message, |
| 97 | + null // optional IterableEmbeddedViewConfig |
| 98 | +) |
| 99 | +yourContainer.addView(embeddedView) |
| 100 | +``` |
| 101 | + |
| 102 | +**Custom styling:** |
| 103 | + |
| 104 | +> **Agent note:** `IterableEmbeddedViewConfig` is a data class with NO default values on its parameters. You must provide ALL 10 fields — use `null` for any you don't want to customize. |
| 105 | +
|
| 106 | +```kotlin |
| 107 | +val config = IterableEmbeddedViewConfig( |
| 108 | + backgroundColor = Color.WHITE, |
| 109 | + borderColor = Color.LTGRAY, |
| 110 | + borderWidth = 1, |
| 111 | + borderCornerRadius = 8f, |
| 112 | + primaryBtnBackgroundColor = Color.BLUE, |
| 113 | + primaryBtnTextColor = Color.WHITE, |
| 114 | + secondaryBtnBackgroundColor = null, |
| 115 | + secondaryBtnTextColor = null, |
| 116 | + titleTextColor = null, |
| 117 | + bodyTextColor = null |
| 118 | +) |
| 119 | +``` |
| 120 | + |
| 121 | +> **Agent note:** OOTB views handle both `handleEmbeddedClick` (navigation) and `trackEmbeddedClick` (analytics) automatically on button and default action taps. |
| 122 | +
|
| 123 | +--- |
| 124 | + |
| 125 | +## Step 3b: Custom UI |
| 126 | + |
| 127 | +If the design requires a fully custom layout, use the message data model directly: |
| 128 | + |
| 129 | +```kotlin |
| 130 | +val title = message.elements?.title |
| 131 | +val body = message.elements?.body |
| 132 | +val imageUrl = message.elements?.mediaUrl |
| 133 | +val buttons = message.elements?.buttons // List<EmbeddedMessageElementsButton> |
| 134 | +val defaultAction = message.elements?.defaultAction |
| 135 | + |
| 136 | +// On button click — MUST call both: |
| 137 | +IterableApi.getInstance().embeddedManager.handleEmbeddedClick(message, button.id, clickedUrl) |
| 138 | +IterableApi.getInstance().trackEmbeddedClick(message, button.id, clickedUrl) |
| 139 | +``` |
| 140 | + |
| 141 | +> **Agent note:** `handleEmbeddedClick` does NOT call `trackEmbeddedClick` automatically. Custom UI must call both or clicks won't be tracked. The OOTB views handle this internally. |
| 142 | +
|
| 143 | +--- |
| 144 | + |
| 145 | +## Dashboard Setup |
| 146 | + |
| 147 | +- [ ] **Embedded placement** must be created in Iterable (auto-generated ID) |
| 148 | +- [ ] **Message Type** for Embedded channel must exist before creating templates |
| 149 | +- [ ] **Campaign** must be active and targeting the user |
| 150 | + |
| 151 | +--- |
| 152 | + |
| 153 | +## Gotchas |
| 154 | + |
| 155 | +- **Accessing `embeddedManager` before SDK init throws RuntimeException.** Always wrap in `onSDKInitialized`. |
| 156 | +- **Placement IDs are auto-generated** by Iterable — never hardcode `1` or any assumed value. Ask the developer for the actual ID from the dashboard. |
| 157 | +- **`getMessages()` returns `List?` (nullable).** Always use `isNullOrEmpty()`. |
| 158 | +- **Messages sync on foreground switch.** After creating a campaign, background and foreground the app to trigger a sync. |
| 159 | +- **`onEmbeddedMessagingDisabled` fires when messaging is disabled** server-side or due to subscription/auth issues. Hide the embedded UI when this is called. |
| 160 | +- **Create a Message Type for the Embedded channel** in the Iterable dashboard before creating templates. Without it, campaigns can't be created. |
0 commit comments