### Full Custom Inbox Implementation Example Source: https://github.com/iterable/iterable-sdk-skill/blob/main/polished/android/customizing-mobile-inbox-on-android.polished.md A comprehensive example showing how to implement a fully customized inbox experience. ```kotlin class FullCustomInboxActivity : IterableInboxActivity() { private lateinit var recyclerView: RecyclerView override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_custom_inbox) recyclerView = findViewById(R.id.inbox_recycler_view) setupAdapter() } private fun setupAdapter() { val messages = IterableApi.sharedInstance.inboxManager.messages val adapter = MyCustomAdapter(messages) recyclerView.adapter = adapter } } ``` ```java public class FullCustomInboxActivity extends IterableInboxActivity { private RecyclerView recyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_inbox); recyclerView = findViewById(R.id.inbox_recycler_view); setupAdapter(); } private void setupAdapter() { List messages = IterableApi.sharedInstance.getInboxManager().getMessages(); MyCustomAdapter adapter = new MyCustomAdapter(messages); recyclerView.setAdapter(adapter); } } ``` -------------------------------- ### Install Context7 MCP Server Source: https://github.com/iterable/iterable-sdk-skill/blob/main/README.md Deep link URL to install the Context7 MCP server for Cursor. ```text cursor://anysphere.cursor-deeplink/mcp/install?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0= ``` -------------------------------- ### Install Claude Code Plugin Source: https://github.com/iterable/iterable-sdk-skill/blob/main/README.md Commands to install the Iterable skill plugin for Claude Code. ```text /plugin marketplace add Iterable/iterable-sdk-skill /plugin install iterable-sdk@iterable ``` -------------------------------- ### Install Cursor Plugin via CLI Source: https://github.com/iterable/iterable-sdk-skill/blob/main/README.md Commands to clone the repository and symlink the plugin for local development in Cursor. ```bash git clone --depth 1 https://github.com/Iterable/iterable-sdk-skill.git ~/iterable-skills ln -s ~/iterable-skills ~/.cursor/plugins/local/iterable-sdk ``` -------------------------------- ### Initialize SDK with Auth Handler Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-sdk.md Example implementation of the auth handler passed into the IterableConfig builder during SDK initialization. ```java IterableConfig config = new IterableConfig.Builder() // ... other configuration options ... .setAuthHandler(new IterableAuthHandler() { @Override public String onAuthTokenRequested() { // Fetch a JWT token for the signed-in user, from your server, and // return it to the SDK. return ""; } @Override public void onTokenRegistrationSuccessful(String authToken) { // The SDK has retrieved a non-null JWT token for the signed-in user. // However, the SDK does not validate the token before calling this // method. } @Override public void onAuthFailure(AuthFailure authFailure) { // Inspect the authFailure enum constant and take any necessary action. For // example, you can pause auth retries (see section 5.5.3, below). } }).build(); IterableApi.initialize(_context, "", config); ``` -------------------------------- ### Full Custom Inbox Implementation Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/customizing-mobile-inbox-on-android.md A comprehensive example showing a custom inbox implementation with a custom adapter. ```kotlin class MyCustomInboxFragment : Fragment() { private lateinit var recyclerView: RecyclerView private lateinit var adapter: MyInboxAdapter override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_my_inbox, container, false) recyclerView = view.findViewById(R.id.recycler_view) adapter = MyInboxAdapter(IterableApi.sharedInstance.inboxMessages) recyclerView.adapter = adapter return view } override fun onResume() { super.onResume() IterableApi.sharedInstance.addInboxUpdatedListener { adapter.updateMessages(IterableApi.sharedInstance.inboxMessages) } } override fun onPause() { super.onPause() IterableApi.sharedInstance.removeInboxUpdatedListener { } } } ``` ```java public class MyCustomInboxFragment extends Fragment { private RecyclerView recyclerView; private MyInboxAdapter adapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_my_inbox, container, false); recyclerView = view.findViewById(R.id.recycler_view); adapter = new MyInboxAdapter(IterableApi.sharedInstance.getInboxMessages()); recyclerView.setAdapter(adapter); return view; } @Override public void onResume() { super.onResume(); IterableApi.sharedInstance.addInboxUpdatedListener(() -> { adapter.updateMessages(IterableApi.sharedInstance.getInboxMessages()); }); } @Override public void onPause() { super.onPause(); IterableApi.sharedInstance.removeInboxUpdatedListener(() -> {}); } } ``` -------------------------------- ### Implement Custom Inbox Activity Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/customizing-mobile-inbox-on-android.md Example implementation of a custom activity for the Mobile Inbox. ```kotlin class MyInboxActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_my_inbox) val fragment = IterableInboxFragment() supportFragmentManager.beginTransaction() .replace(R.id.inbox_container, fragment) .commit() } } ``` ```java public class MyInboxActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_inbox); IterableInboxFragment fragment = new IterableInboxFragment(); getSupportFragmentManager().beginTransaction() .replace(R.id.inbox_container, fragment) .commit(); } } ``` -------------------------------- ### Implement IterableUrlHandler Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Example implementation of the URL handler to process specific custom URL schemes. ```kotlin override fun handleIterableURL(uri: Uri, actionContext: IterableActionContext): Boolean { val urlString = uri.toString() // For example, urlString might be: "mycompany://profile" if (urlString.contains("mycompany://profile")) { // Navigate the user to the profile page ... return true } return false } ``` -------------------------------- ### Convert Anonymous User to Known User Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/updating-user-profiles.md Examples demonstrating how to update a user's email and profile data, including handling potential failures when the user already exists. ```swift let email = "newEmail@example.com" // The IterableAPI.updateUser(...) can be added to any method within your code. `yourUserIsNowKnownFunction` is just an example func yourUserIsNowKnownFunction() { IterableAPI.updateEmail(email, onSuccess: myUserUpdateSuccessHandler, onFailure: myUserUpdateFailureHandler) } func myUserUpdateSuccessHandler(data: [AnyHashable: Any]?) -> () { print("Successfully sent user update request to Iterable") } func myUserUpdateFailureHandler(reason: String?, data: Data?) -> () { print("Failure sending user update request to Iterable") IterableAPI.email = email IterableAPI.updateUser(dataField, mergeNestedObjects: false) } ``` ```objectivec @import IterableSDK; typedef void (^successHandler)(NSDictionary * _Nullable); typedef void (^failureHandler)(NSString * _Nullable, NSData * _Nullable); NSString *email = @"newEmail@example.com"; // The [IterableAPI updateUser:...] can be added to any method within your code. `yourUserIsNowKnownFunction` is just an example - (void)yourUserIsNowKnownFunction { [IterableAPI updateEmail:email onSuccess:myUserUpdateSuccessHandler onFailure:myUserUpdateFailureHandler]; } successHandler myUserUpdateSuccessHandler = ^(NSDictionary * _Nullable data) { NSLog(@"Successfully sent user update request to Iterable"); }; failureHandler myUserUpdateFailureHandler = ^(NSString * _Nullable reason, NSData * _Nullable data) { NSLog(@"Failure sending user update request to Iterable"); IterableAPI.email = email; [IterableAPI updateUser:dataField mergeNestedObjects:false]; }; ``` ```java final String email = "newEmail@example.com"; IterableApi.getInstance().updateEmail(email, new IterableHelper.SuccessHandler() { @Override public void onSuccess(JSONObject data) { System.out.println("sent to Iterable success"); } }, new IterableHelper.FailureHandler() { @Override public void onFailure(String reason, JSONObject data) { System.out.println("sent to Iterable failure"); IterableApi.getInstance().setEmail(email); //This assumes your saving your user profile fields in the datafield object locally IterableApi.getInstance().updateUser(datafields); } }); ``` -------------------------------- ### JSON Data Payloads Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/updating-user-profiles.md Examples of JSON structures for user profile updates. ```json { "firstName": "John", "isRegistered": true, "totalPurchases": 15 } ``` ```json { "email": "john@example.com", "dataFields": { "firstName": "John" } } ``` ```json { "email": "john@example.com", "dataFields": { "firstName": "John" } } ``` ```json { "email": "john@example.com", "dataFields": { "favoriteColors": ["blue", "green"] } } ``` -------------------------------- ### Update User Profile via SDK Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/updating-user-profiles.md Examples of updating user profile fields using Swift, Objective-C, and Java. ```swift // The IterableAPI.updateUser(...) can be called anywhere the SDK is accessible // myFunc() demonstrates this usage import IterableSDK func myFunc() { let dataField: [String: Any] = [ "Address": [ "Street1": "123 Main St", "Street2": "Apt 1", "City": "Iter-a-ville", "State": "CA", "Zip": "90210" ] ] IterableAPI.updateUser(dataField, mergeNestedObjects: false, onSuccess: myUserUpdateSuccessHandler, onFailure: myUserUpdateFailureHandler) } func myUserUpdateSuccessHandler(data: [AnyHashable: Any]?) -> () { print("Successfully sent user update request to Iterable") } func myUserUpdateFailureHandler(reason: String?, data: Data?) -> () { print("Failure sending user update request to Iterable") } ``` ```objectivec // The [IterableAPI updateUser:...] can be called anywhere the SDK is accessible // myFunc demonstrates this usage @import IterableSDK; typedef void (^successHandler)(NSDictionary * _Nullable); typedef void (^failureHandler)(NSString * _Nullable, NSData * _Nullable); - (void)myFunc { NSDictionary *data = @{ @"Address": @{ @"Street1": @"123 Main St", @"Street2": @"Apt 1", @"City": @"Iter-a-ville", @"State": @"CA", @"Zip": @"90210" } }; [IterableAPI updateUser:data mergeNestedObjects:NO onSuccess:myUserUpdateSuccessHandler onFailure:myUserUpdateFailureHandler]; } successHandler myUserUpdateSuccessHandler = ^(NSDictionary * _Nullable data) { NSLog(@"Successfully sent user update request to Iterable"); }; failureHandler myUserUpdateFailureHandler = ^(NSString * _Nullable reason, NSData * _Nullable data) { NSLog(@"Failure sending user update request to Iterable"); }; ``` ```java JSONObject address = new JSONObject(); JSONObject datafields = new JSONObject(); try { address.put("Street1", "123 Main St"); address.put("Street2", "Apt 1"); address.put("City", "Iter-a-ville"); address.put("State", "CA"); address.put("Zip", "90210"); datafields.put("dataFields", address); } catch (JSONException e) { e.printStackTrace(); } IterableApi.getInstance().updateUser(datafields); ``` -------------------------------- ### startSession() Source: https://github.com/iterable/iterable-sdk-skill/blob/main/sources/android/embedded-messages-with-iterables-android-sdk.md Starts a new embedded message session when a user navigates to a screen or page that displays embedded messages. ```APIDOC ## startSession() ### Description Starts a session when the screen that displays your embedded message is displayed or comes to the foreground. ### Method `IterableApi.getInstance().embeddedManager.getEmbeddedSessionManager().startSession()` ``` -------------------------------- ### Implement Custom Inbox Message View Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/customizing-mobile-inbox-on-android.md Example implementation of a custom view for individual inbox messages. ```kotlin class MyInboxMessageView : IterableInboxMessageView { override fun getLayoutId(): Int { return R.layout.my_inbox_message_layout } override fun bind(message: IterableInAppMessage, view: View) { val titleView = view.findViewById(R.id.title) titleView.text = message.content.title } } ``` ```java public class MyInboxMessageView implements IterableInboxMessageView { @Override public int getLayoutId() { return R.layout.my_inbox_message_layout; } @Override public void bind(IterableInAppMessage message, View view) { TextView titleView = view.findViewById(R.id.title); titleView.setText(message.getContent().getTitle()); } } ``` -------------------------------- ### Start an Embedded Message Session Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Call this when the screen displaying embedded messages comes to the foreground. ```kotlin // When the screen that displays your embedded message is displayed or comes to // the foreground IterableApi .getInstance() .embeddedManager .getEmbeddedSessionManager() .startSession() ``` -------------------------------- ### Implement a custom action handler in Kotlin Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Example implementation of a custom action handler that processes specific action types. ```kotlin override fun handleIterableCustomAction( action: IterableAction, actionContext: IterableActionContext ): Boolean { // The custom action's type is stored in action.type if (action.type?.contains("joinClass")) // Sign the user up for a class ... return true } return false } ``` -------------------------------- ### Define placeholder layout Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Example XML layout containing a FrameLayout placeholder for the embedded message view. ```xml ``` -------------------------------- ### Wrapping SDK calls in onSDKInitialized Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/PITFALLS.md Ensures SDK calls are executed only after initialization is complete, preventing IllegalStateException during cold starts. ```kotlin IterableApi.onSDKInitialized { ... } ``` -------------------------------- ### Implement IterableEmbeddedUpdateHandler Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Example implementation of the update handler methods to manage message display, sync status, and error handling. ```kotlin override fun onMessagesUpdated() { // Fetch messages for the placement associated with the current view val messages = embeddedManager.getMessages(placementId) // Show or hide messages... // ... } override fun onEmbeddedMessagingDisabled() { // Hide embedded UI or show default content // showFallbackContent() } override fun onEmbeddedMessagingSyncSucceeded() { // Stop loading indicators, confirm latest content is shown // hideLoadingSpinner() } override fun onEmbeddedMessagingSyncFailed(reason: String?) { // Log or surface a non-sensitive error state // Log.d("Embedded", "Sync failed: ${reason ?: "Unknown error"}") // showEmbeddedErrorState() } ``` -------------------------------- ### Initialize SDK and implement callbacks Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/configure-the-android-sdk.md Initialize the SDK within your Activity and implement the required interfaces for JWT authentication and unknown user management. ```kotlin // // This example creates the IterableConfig in the main activity, but you can create it in // another place that's convenient for your app's architecture, if necessary. // class MainActivity : AppCompatActivity(), IterableUnknownUserHandler, IterableAuthHandler { override fun onCreate(savedInstanceState: Bundle?) { config = IterableConfig.Builder() .setAuthHandler(this) .setEnableUnknownUserActivation(true) .setUnknownUserHandler(this) .setEventThresholdLimit(100) .setIdentityResolution(IterableIdentityResolution(true, true)) .build() IterableApi.initialize(this, , config) } // // Fetch a new JWT token for the current or unknown user, from your server. // Then, return it as a string. // override fun onAuthTokenRequested(): String { // ... return "" } // // Handle failures that occur when fetching JWT tokens. // override fun onAuthFailure(authFailure: AuthFailure?) { // ... } // // The SDK calls onTokenRegistrationSuccessful after onAuthTokenRequested // returns a non-null JWT token. However, other than a null check, the SDK does not // validate the token before calling this method. You can leave this method empty. // override fun onTokenRegistrationSuccessful(authToken: String?) { } // // Callback for the SDK to invoke after it creates a userId for an unknown user. // If necessary, use this method to pass the new userId to your server. // override fun onUnknownUserCreated(userId: String) { // ... } } ``` -------------------------------- ### Subscribe to SDK Initialization Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-sdk.md Use this to listen for initialization completion from multiple locations in your app. ```kotlin IterableApi.onSDKInitialized { // This callback will be invoked when initialization completes // If already initialized, it's called immediately } ``` -------------------------------- ### Get In-App Messages Source: https://github.com/iterable/iterable-sdk-skill/blob/main/polished/android/android-sdk.polished.md Retrieve currently available in-app messages. ```java List messages = IterableApi.getInstance().getInAppMessages(); ``` -------------------------------- ### Initialize SDK Asynchronously Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-sdk.md Use this method in Application.onCreate() to prevent ANR errors during startup. ```kotlin // In Application.onCreate() IterableApi.initializeInBackground(this, "", config) { // SDK is ready - this callback is optional } ``` -------------------------------- ### Application Class Integration Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/SKILL.md Invoke the initialization helper within the Application class onCreate method to ensure the SDK is configured at app startup. ```kotlin // In the app's Application class (e.g. MyApplication.onCreate()): override fun onCreate() { super.onCreate() // ...existing setup... IterableTracker.initialize( this, BuildConfig.ITERABLE_API_KEY, IterableTracker.stableUserId(this), ) } ``` -------------------------------- ### Get Last Push Payload Source: https://github.com/iterable/iterable-sdk-skill/blob/main/polished/android/android-sdk.polished.md Retrieve the last received push payload. ```java Bundle payload = IterableApi.getInstance().getLastPushPayload(); ``` -------------------------------- ### Register EmbeddedMessageDelegate Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Register the delegate with the Iterable API to start receiving updates. ```kotlin IterableApi.getInstance().embeddedManager.delegate = MyEmbeddedMessageDelegate() ``` -------------------------------- ### Embedded Message View XML Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Example layout XML for an embedded message container. ```xml ``` -------------------------------- ### Correct initializeInBackground Usage Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/PITFALLS.md Always use the 4-argument overload to ensure the configuration object is correctly passed to the SDK. ```kotlin IterableApi.initializeInBackground(context, apiKey, config) { // init complete (this trailing lambda is the 4th arg) } ``` -------------------------------- ### Initialize Iterable SDK Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-sdk.md Initialize the SDK in your Application class. ```java IterableApi.initialize(this, "YOUR_API_KEY"); IterableApi.getInstance().setEmail("user@example.com"); ``` -------------------------------- ### Merge Nested Objects Examples Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/updating-user-profiles.md JSON representations of profile data before and after applying mergeNestedObjects settings. ```json "address": { "street": "123 Main St", "city": "San Francisco" } ``` ```json "address": { "state": "CA", "zipCode": "94105" } ``` ```json "address": { "state": "CA", "zipCode": "94105" } ``` ```json "address": { "street": "123 Main St", "city": "San Francisco", "state": "CA", "zipCode": "94105" } ``` -------------------------------- ### Initialize the SDK in the background Source: https://github.com/iterable/iterable-sdk-skill/blob/main/sources/android/android-sdk.md Use background initialization to prevent ANR errors during app startup. ```kotlin // In Application.onCreate() IterableApi.initializeInBackground(this, "", config) { // SDK is ready - this callback is optional } ``` ```kotlin IterableApi.onSDKInitialized { // This callback will be invoked when initialization completes // If already initialized, it's called immediately } ``` -------------------------------- ### Initialize Iterable SDK Source: https://github.com/iterable/iterable-sdk-skill/blob/main/eval/transcripts/android/push-basic.baseline.sample.md Configure and initialize the Iterable SDK within your Application class to enable push registration. ```kotlin class MyApp : Application() { override fun onCreate() { super.onCreate() val config = IterableConfig.Builder() .setAutoPushRegistration(true) .build() IterableApi.initializeInBackground(this, "YOUR_API_KEY", config) // Register the device for push IterableApi.getInstance().registerForPush() } } ``` -------------------------------- ### Canonical SDK Initialization Helper Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/SKILL.md A singleton object pattern for initializing the SDK and managing user identity. Ensure setUserId is called within onSDKInitialized to guarantee the SDK is ready. ```kotlin // IterableTracker.kt — minimal, single source of init + identity. object IterableTracker { fun initialize(context: Context, apiKey: String, userId: String) { val config = IterableConfig.Builder() .setLogLevel(Log.VERBOSE) // android.util.Log int — NOT an SDK enum (pitfall: setLogLevel takes an int) .setAutoPushRegistration(true) // default; do NOT also call registerForPush() (pitfall #6) // .setDataRegion(IterableDataRegion.EU) // uncomment for EU projects (pitfall #8) // .setAllowedProtocols(arrayOf("yourscheme")) // only if you handle custom-scheme deep links (rule 5) // .setAuthHandler(authHandler) // REQUIRED if the key is JWT-protected (rule 1) .build() // 4-arg overload: config + trailing-lambda callback (pitfall #18). // The callback runs BEFORE the SDK is ready — keep it empty. IterableApi.initializeInBackground(context, apiKey, config) { // init complete; do NOT identify here (pitfall #2) } // onSDKInitialized runs AFTER init (immediately if already ready). // Identify here. Read identity fresh — don't capture at startup (pitfall #3). IterableApi.onSDKInitialized { IterableApi.getInstance().setUserId(userId) // or setEmail(...) — pick ONE mode (rule 7, pitfall #12) } } // Account-less / local-first apps (common; the UUA doc is for // anonymous→identified *upgrades*, not this): generate a stable per-install // UUID once and persist it. Each reinstall = a new Iterable user — confirm // that's acceptable with the developer. fun stableUserId(context: Context): String { val prefs = context.getSharedPreferences("iterable", Context.MODE_PRIVATE) return prefs.getString("user_id", null) ?: java.util.UUID.randomUUID().toString() .also { prefs.edit().putString("user_id", it).apply() } } } ``` -------------------------------- ### Initialize the Iterable SDK Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-sdk.md Initialize the SDK in your Application class's onCreate method using an IterableConfig object and your API key. ```java IterableConfig config = new IterableConfig.Builder().build(); IterableApi.initialize(context, "", config); ``` -------------------------------- ### Configure Iterable SDK Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Initializes the SDK with custom URL and action handlers, enables embedded messaging, and identifies the user. ```kotlin val config = IterableConfig.Builder() .setUrlHandler(this) .setCustomActionHandler(this) .setEnableEmbeddedMessaging(true) // Specify the URL schemes you're expecting to receive in the campaigns you // send with Iterable. The SDK passes URLs with these URL schemes to your URL // handler, which can then handle them as necessary. For example, if you // indicate that "mycompany" is an allowed protocol, the SDK will pass URLs // such as "mycompany://profile" to your URL handler, which can respond as // needed. For example, for "mycompany://profile", it might deep link to // the app's user profile screen. .setAllowedProtocols(arrayOf("mycompany")) .build() IterableApi.initialize(this, apiKey, config) IterableApi.getInstance().setEmail(email) // IterableApi.getInstance().setUserId(userId) ``` -------------------------------- ### Initialize Iterable SDK for Deep Linking Source: https://github.com/iterable/iterable-sdk-skill/blob/main/polished/android/android-app-links.polished.md Ensure the Iterable SDK is initialized in your Application class to support deep link tracking. ```java IterableApi.initialize(this, "YOUR_API_KEY"); IterableApi.getInstance().setDeepLinkHandler(new IterableDeepLinkHandler() { @Override public void handleDeepLink(Uri uri) { // Handle the deep link } }); ``` -------------------------------- ### Iterable initializeInBackground Overloads Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/PITFALLS.md The 3-argument overload accepts a callback, not a configuration object. Using it with a config object will cause the config to be ignored. ```java initializeInBackground(Context, String, IterableInitializationCallback) initializeInBackground(Context, String, IterableConfig, IterableInitializationCallback) ``` -------------------------------- ### Generate Evaluation Prompts Source: https://github.com/iterable/iterable-sdk-skill/blob/main/eval/README.md Command to generate prompt files for the baseline and skill-enabled arms. ```bash pnpm eval:prompts android # writes eval/prompts/android/..md ``` -------------------------------- ### Manage Listener Lifecycle in Activity or Fragment Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Example of adding and removing an embedded update listener within the onResume and onPause lifecycle methods. ```kotlin override fun onResume() { super.onResume() IterableApi.getInstance().embeddedManager.addUpdateListener(this) // ... } override fun onPause() { super.onPause() IterableApi.getInstance().embeddedManager.removeUpdateListener(this) // ... } ``` -------------------------------- ### Run Evaluation and Reporting Commands Source: https://github.com/iterable/iterable-sdk-skill/blob/main/eval/README.md Commands to execute the evaluation pipeline and generate the final report. ```bash pnpm eval:run android # score transcripts → eval/results/android.json pnpm eval:report android # render → eval/report/android.md ← the slide ``` -------------------------------- ### Configure ProGuard Rules Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-sdk.md Add this rule to your ProGuard configuration to ensure SDK features function correctly. ```text -keep class org.json.** { *; } ``` -------------------------------- ### Repository Structure Overview Source: https://github.com/iterable/iterable-sdk-skill/blob/main/README.md Directory layout of the project repository. ```text iterable-android/ the installable skill (SKILL.md + PITFALLS.md + snapshot/) polished/ the docs in agent-ready form (what gets published to Context7) pipeline/ tooling that builds polished/ from sources/, CI-gated sources/ raw Iterable docs, fetched at pinned commits context7.json Context7 manifest .claude-plugin/ Claude Code plugin + marketplace manifests .cursor-plugin/ Cursor plugin + marketplace manifests mcp.json Context7 MCP server (Cursor plugin auto-discovery) .mcp.json same config (Claude Code auto-discovery; kept in sync by CI) ``` -------------------------------- ### Project Directory Structure Source: https://github.com/iterable/iterable-sdk-skill/blob/main/eval/README.md Overview of the evaluation directory layout. ```text eval/ ├── scenarios/android.yml # the 8 asks + their checks (committed) ├── transcripts/android/ # agent replies, one per scenario × arm │ └── *.sample.md # illustrative samples shipped so this runs today ├── prompts/ # generated: prompt files to feed each arm (gitignored) ├── results/android.json # generated: scored output (gitignored) └── report/android.md # generated: the before/after slide (gitignored) ``` -------------------------------- ### Refresh snapshots and run validation gates Source: https://github.com/iterable/iterable-sdk-skill/blob/main/REVIEW.md Commands to synchronize the snapshot directory and execute all automated verification checks. Ensure all checks pass before pushing changes. ```bash git checkout cd pipeline pnpm snapshot:refresh # mirror polished/ → iterable-android/snapshot/ pnpm check:all # MUST be green before you push ``` -------------------------------- ### Manual Push Registration Configuration Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/identifying-the-user.md Notes on manual push registration for Android when automatic registration is disabled. ```java // Iterable SDK automatically registers the push token with Iterable // whenever setEmail or setUserId is called. // If you want to trigger token registration manually, first disable automatic // registration by calling setAutoPushRegistration(false) on IterableConfig.Builder when initializing the SDK. // Then call registerForPush whenever you want to register the token: // Only use this line if you want to register push manually. // IterableApi.getInstance().registerForPush(); ``` -------------------------------- ### Avoid post-construction mutation of CommerceItem Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/PITFALLS.md Do not use .apply to set properties on CommerceItem after initialization, as these fields are write-once and will cause runtime crashes. ```kotlin // WRONG — compiles, throws at runtime on the assignment CommerceItem(id, name, price, quantity).apply { categories = arrayOf(product.category) } ``` ```kotlin CommerceItem( id, name, price, quantity, sku, description, url, imageUrl, arrayOf(product.category), // categories — set here, never reassigned ) ``` -------------------------------- ### Initialize Iterable SDK for Embedded Messaging Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/embedded-messages-with-iterables-android-sdk.md Configure the Iterable SDK to enable embedded messaging during initialization. ```kotlin val config = IterableConfig.Builder() .setEmbeddedMessagingEnabled(true) .build() IterableApi.initialize(applicationContext, "YOUR_API_KEY", config) ``` ```java IterableConfig config = new IterableConfig.Builder() .setEmbeddedMessagingEnabled(true) .build(); IterableApi.initialize(applicationContext, "YOUR_API_KEY", config); ``` -------------------------------- ### Create Inbox Fragment with Custom Layout Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/customizing-mobile-inbox-on-android.md Use the newInstance method to initialize an IterableInboxFragment with a specific custom layout resource. ```kotlin val inboxFragment = IterableInboxFragment.newInstance(InboxMode.POPUP, R.layout.custom_inbox_item) ``` ```java IterableInboxFragment inboxFragment = IterableInboxFragment.newInstance(InboxMode.POPUP, R.layout.custom_inbox_item); ``` -------------------------------- ### Launch InboxActivity on Button Tap Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/setting-up-mobile-inbox-on-android.md Use the provided activity wrapper to open the mobile inbox in response to user interaction. ```kotlin startActivity(Intent(context, IterableInboxActivity::class.java)) ``` ```java startActivity(new Intent(getContext(), IterableInboxActivity.class)); ``` -------------------------------- ### Initialize Iterable with Auth Handler Source: https://github.com/iterable/iterable-sdk-skill/blob/main/eval/transcripts/android/jwt-auth.skill.sample.md Configure the SDK with an IterableAuthHandler to fetch fresh JWTs from your server. Ensure the token is fetched dynamically within the lambda to handle refreshes correctly. ```kotlin class MyApp : Application() { override fun onCreate() { super.onCreate() val config = IterableConfig.Builder() .setAuthHandler(object : IterableAuthHandler { override fun onAuthTokenRequested(): String? { // Block-fetch a server-minted JWT for whoever is logged in NOW. val email = sessionStore.currentEmail() ?: return null return backend.fetchIterableJwt(email) // calls your /token endpoint } override fun onTokenRegistrationSuccessful(authToken: String) {} override fun onAuthFailure(failure: AuthFailure) { Log.w("Iterable", "auth failed: ${failure.failureReason}") } }) .build() // Do NOT call setEmail here — the init callback runs before the auth // manager is ready and burns the retry budget permanently. IterableApi.initializeInBackground(this, "YOUR_API_KEY", config) } } ``` -------------------------------- ### Configure Java 8 Compatibility Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-sdk.md Add these settings to your app's build.gradle file if upgrading to version 3.3.1+ causes build failures or crashes. ```groovy android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } ... } ``` -------------------------------- ### Authenticate with JWT Source: https://github.com/iterable/iterable-sdk-skill/blob/main/eval/transcripts/android/jwt-auth.baseline.sample.md Generate a JWT token and associate it with the user email to authenticate requests. ```kotlin val jwt = Jwts.builder() .setSubject(currentUser.email) .signWith(SignatureAlgorithm.HS256, "YOUR_JWT_SECRET".toByteArray()) .compact() IterableApi.getInstance().setEmail(currentUser.email, jwt) ``` -------------------------------- ### Configure Auto-Registration Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/PITFALLS.md Use this configuration to enable automatic push token registration during user identification. ```java IterableConfig.Builder().setAutoPushRegistration(true) ``` -------------------------------- ### Configure Android App Links in AndroidManifest.xml Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-app-links.md Add the intent filter to your activity to handle deep links. Ensure the host matches your website domain. ```xml ``` -------------------------------- ### Securely Loading API Keys from local.properties Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/PITFALLS.md Use this helper method to read keys from local.properties instead of hardcoding them. Ensure the default value is an empty string to prevent accidental commits of sensitive keys. ```groovy def getSecret(property, defaultValue) { def f = rootProject.file("local.properties") if (f.exists()) { def props = new Properties() f.withInputStream { props.load(it) } def v = props.getProperty(property) if (v != null) return v } return defaultValue // empty string — NEVER a literal key } // ... buildConfigField "String", "ITERABLE_API_KEY", "\"" + getSecret('ITERABLE_API_KEY', "") + "\"" ``` -------------------------------- ### startImpression() and pauseImpression() Source: https://github.com/iterable/iterable-sdk-skill/blob/main/sources/android/embedded-messages-with-iterables-android-sdk.md Tracks the appearance and disappearance of embedded messages within an active session. ```APIDOC ## startImpression(messageId, placementId) ### Description Starts tracking an impression for a specific message when it appears on screen. ### Parameters - **messageId** (String) - Required - The unique identifier of the message. - **placementId** (String) - Required - The identifier of the placement where the message appears. ## pauseImpression(messageId) ### Description Pauses the tracking of an impression when a message disappears from the screen. ### Parameters - **messageId** (String) - Required - The unique identifier of the message. ``` -------------------------------- ### Configure WebView Base URL Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-sdk.md Sets a base URL for the WebView to resolve CORS issues when loading external resources. ```java IterableConfig config = new IterableConfig.Builder() // ... other configuration options ... .setWebViewBaseUrl("https://app.iterable.com") // Use https://app.eu.iterable.com for EU .build(); IterableApi.initialize(context, "", config); ``` -------------------------------- ### Set Custom Inbox UI Configuration Source: https://github.com/iterable/iterable-sdk-skill/blob/main/polished/android/customizing-mobile-inbox-on-android.polished.md Configure the visual appearance of the Mobile Inbox by setting a custom configuration object. ```kotlin val config = IterableInboxCustomizationObject() config.navTitle = "My Inbox" IterableApi.sharedInstance.inboxCustomizationObject = config ``` ```java IterableInboxCustomizationObject config = new IterableInboxCustomizationObject(); config.navTitle = "My Inbox"; IterableApi.sharedInstance.setInboxCustomizationObject(config); ``` -------------------------------- ### Handle App Links in MainActivity Source: https://github.com/iterable/iterable-sdk-skill/blob/main/iterable-android/snapshot/android-app-links.md Use this implementation in your activity to process incoming deep links via the Iterable SDK and prevent redundant intent handling. ```java // MainActivity.java @Override public void onCreate() { super.onCreate(); ... handleIntent(getIntent()); } @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); if (intent != null) { handleIntent(intent); } } private void handleIntent(Intent intent) { if (Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() != null) { IterableApi.getInstance().handleAppLink(intent.getDataString()); // Overwrite the intent to make sure we don't open the deep link // again when the user opens our app later from the task manager setIntent(new Intent(Intent.ACTION_MAIN)); } } ```