In-app messages (Android)

Learn how to configure, customize, and test in-app messages in your Android app using the Blueshift SDK.

This guide explains how to display contextual in-app messages within your app.

Prerequisites

Before setting up in-app messages, ensure you have completed:


Set up in-app messages

Enable in-app messages

In your Application class's onCreate() method (e.g., MyApplication.kt), add these lines to your Configuration object before calling initialize():

val configuration = Configuration()
configuration.isInAppEnabled = true
// Enable JavaScript for HTML in-app messages
configuration.isJavaScriptForInAppWebViewEnabled = true
Configuration configuration = new Configuration();
configuration.setInAppEnabled(true);
// Enable JavaScript for HTML in-app messages
configuration.setJavaScriptForInAppWebViewEnabled(true);

Register activities for in-app display

In-app messages display on registered activities. Choose one of the following methods:

Method 1: Register individual activities

In each activity where you want to show in-app messages (e.g., MainActivity.kt, ProductActivity.kt), add this line inside the onCreate() method after setContentView():

// Add this line in your activity's onCreate() method after setContentView()
Blueshift.getInstance(this).registerForInAppMessages(this)
// Add this line in your activity's onCreate() method after setContentView()
Blueshift.getInstance(this).registerForInAppMessages(this);

The screen name will be the activity's fully qualified class name (e.g., com.example.app.MainActivity).

Method 2: Register with a custom screen name

Useful for fragments or custom naming. Add this line in your activity's onCreate() method after setContentView():

// Register with custom screen name
Blueshift.getInstance(this).registerForInAppMessages(this, "custom_screen_name")
// Register with custom screen name
Blueshift.getInstance(this).registerForInAppMessages(this, "custom_screen_name");

Replace the custom_screen_name with your desired screen identifier.

Method 3: Auto-register all activities

In your Application class (e.g., MyApplication.kt), implement ActivityLifecycleCallbacks to automatically register all activities. Add the following to your existing Application class:

import android.app.Application
import android.app.Activity
import android.os.Bundle
import com.blueshift.Blueshift
import com.blueshift.model.Configuration

class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
    
    override fun onCreate() {
        super.onCreate()
        
        // Your existing SDK initialization code
        val configuration = Configuration()
        configuration.setApiKey("YOUR_API_KEY")
        configuration.setAppIcon(R.mipmap.ic_launcher)
        configuration.isInAppEnabled = true
        Blueshift.getInstance(this).initialize(configuration)
        
        // Register lifecycle callbacks for automatic in-app registration
        registerActivityLifecycleCallbacks(this)
    }
    
    override fun onActivityStarted(activity: Activity) {
        Blueshift.getInstance(activity).registerForInAppMessages(activity)
    }
    
    override fun onActivityStopped(activity: Activity) {
        Blueshift.getInstance(activity).unregisterForInAppMessages(activity)
    }
    
    // Required empty implementations
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
    override fun onActivityResumed(activity: Activity) {}
    override fun onActivityPaused(activity: Activity) {}
    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
    override fun onActivityDestroyed(activity: Activity) {}
}
import android.app.Application;
import android.app.Activity;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.blueshift.Blueshift;
import com.blueshift.model.Configuration;

public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks {
    
    @Override
    public void onCreate() {
        super.onCreate();
        
        // Your existing SDK initialization code
        Configuration configuration = new Configuration();
        configuration.setApiKey("YOUR_API_KEY");
        configuration.setAppIcon(R.mipmap.ic_launcher);
        configuration.setInAppEnabled(true);
        Blueshift.getInstance(this).initialize(configuration);
        
        // Register lifecycle callbacks for automatic in-app registration
        registerActivityLifecycleCallbacks(this);
    }
    
    @Override
    public void onActivityStarted(@NonNull Activity activity) {
        Blueshift.getInstance(activity).registerForInAppMessages(activity);
    }
    
    @Override
    public void onActivityStopped(@NonNull Activity activity) {
        Blueshift.getInstance(activity).unregisterForInAppMessages(activity);
    }
    
    // Required empty implementations
    @Override
    public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {}
    @Override
    public void onActivityResumed(@NonNull Activity activity) {}
    @Override
    public void onActivityPaused(@NonNull Activity activity) {}
    @Override
    public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}
    @Override
    public void onActivityDestroyed(@NonNull Activity activity) {}
}

Unregister activities (optional)

If you need to stop displaying in-app messages on a specific activity, add the unregister line to that activity's onDestroy() method. For example, in MainActivity.kt or any other activity file where you registered for in-app messages:

override fun onDestroy() {
    // Unregister before destroying the activity
    Blueshift.getInstance(this).unregisterForInAppMessages(this)
    super.onDestroy()
}
@Override
protected void onDestroy() {
    // Unregister before destroying the activity
    Blueshift.getInstance(this).unregisterForInAppMessages(this);
    super.onDestroy();
}

Handle deep links

In-app messages can contain deep links to navigate users within your app. The SDK triggers a VIEW intent with the deep link URL. You can use either HTTPS deep links (Android App Links) or custom URL schemes, depending on your app's requirements.

Configure deep link handling

Step 1: Add intent filter to AndroidManifest.xml

Add this intent filter inside the <activity> tag of the activity that should handle deep links (typically your main activity or a dedicated deep link activity):

<activity
    android:name=".MainActivity"
    android:exported="true">
    
    <!-- Your existing intent filters -->
    
    <!-- Deep link intent filter for in-app messages -->
    <intent-filter
        android:autoVerify="true"
        tools:targetApi="m">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        
        <data android:scheme="https" />
        <data android:host="yourapp.com" />
    </intent-filter>
</activity>

Replace yourapp.com with your actual domain.

Step 2: Handle deep link in activity

In the activity specified in Step 1 (e.g., MainActivity.kt), add this code in the onCreate() method to handle the deep link:

import android.net.Uri

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    // Handle deep link from in-app message
    val uri: Uri? = intent.data
    if (uri != null) {
        // Navigate to the appropriate screen based on the URI
        // Example: if (uri.path == "/product") { openProductScreen() }
    }
}
import android.net.Uri;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // Handle deep link from in-app message
    Uri uri = getIntent().getData();
    if (uri != null) {
        // Navigate to the appropriate screen based on the URI
        // Example: if (uri.getPath().equals("/product")) { openProductScreen(); }
    }
}

Advanced

Manual trigger control

To manually control when to fetch and display in-app messages, enable manual mode in your Application class's onCreate() method during SDK initialization:

Enable manual mode:

val configuration = Configuration()
configuration.setApiKey("YOUR_API_KEY")
configuration.setAppIcon(R.mipmap.ic_launcher)
configuration.isInAppEnabled = true
// Enable manual trigger mode
configuration.isInAppManualTriggerEnabled = true

Blueshift.getInstance(this).initialize(configuration)
Configuration configuration = new Configuration();
configuration.setApiKey("YOUR_API_KEY");
configuration.setAppIcon(R.mipmap.ic_launcher);
configuration.setInAppEnabled(true);
// Enable manual trigger mode
configuration.setInAppManualTriggerEnabled(true);

Blueshift.getInstance(this).initialize(configuration);

When manual mode is enabled:

  • SDK will not fetch messages on app start
  • SDK will not automatically display messages
  • Messages are fetched only when a silent push is received
  • Messages display only when manually triggered

Manually fetch messages:

Call this method from your activity or fragment when you want to fetch in-app messages:

import com.blueshift.Blueshift
import com.blueshift.inappmessage.InAppApiCallback
import android.util.Log

Blueshift.getInstance(this).fetchInAppMessages(object : InAppApiCallback {
    override fun onSuccess() {
        Log.d("InApp", "Fetch success")
    }
    
    override fun onFailure(errorCode: Int, errorMessage: String) {
        Log.d("InApp", "Fetch failed: $errorMessage")
    }
})
import com.blueshift.Blueshift;
import com.blueshift.inappmessage.InAppApiCallback;
import android.util.Log;

Blueshift.getInstance(this).fetchInAppMessages(new InAppApiCallback() {
    @Override
    public void onSuccess() {
        Log.d("InApp", "Fetch success");
    }
    
    @Override
    public void onFailure(int errorCode, String errorMessage) {
        Log.d("InApp", "Fetch failed: " + errorMessage);
    }
});

Manually display messages:

Call this method from your activity when you want to display the fetched in-app messages:

Blueshift.getInstance(this).displayInAppMessages()
Blueshift.getInstance(this).displayInAppMessages();

Background fetch control

Control automatic fetching via silent push (available from SDK v3.1.1+) in your Application class's onCreate() method during SDK initialization:

val configuration = Configuration()
configuration.setApiKey("YOUR_API_KEY")
configuration.setAppIcon(R.mipmap.ic_launcher)
configuration.isInAppEnabled = true
// Control background fetch
configuration.isInAppBackgroundFetchEnabled = true

Blueshift.getInstance(this).initialize(configuration)
Configuration configuration = new Configuration();
configuration.setApiKey("YOUR_API_KEY");
configuration.setAppIcon(R.mipmap.ic_launcher);
configuration.setInAppEnabled(true);
// Control background fetch
configuration.setInAppBackgroundFetchEnabled(true);

Blueshift.getInstance(this).initialize(configuration);

Set to false to disable automatic fetching via silent push.

Display interval

Control time between consecutive in-app displays on the same screen (default: 60 seconds) in your Application class's onCreate() method during SDK initialization:

val configuration = Configuration()
configuration.setApiKey("YOUR_API_KEY")
configuration.setAppIcon(R.mipmap.ic_launcher)
configuration.isInAppEnabled = true
// Set display interval
configuration.inAppInterval = 120 // seconds

Blueshift.getInstance(this).initialize(configuration)
Configuration configuration = new Configuration();
configuration.setApiKey("YOUR_API_KEY");
configuration.setAppIcon(R.mipmap.ic_launcher);
configuration.setInAppEnabled(true);
// Set display interval
configuration.setInAppInterval(120); // seconds

Blueshift.getInstance(this).initialize(configuration);

Listen to in-app lifecycle events

Track delivery, open, and click events (available from SDK v3.1.9+). Add this listener to your Application class's onCreate() method after SDK initialization:

import com.blueshift.Blueshift
import com.blueshift.BlueshiftInAppListener
import android.util.Log

Blueshift.setBlueshiftInAppListener(object : BlueshiftInAppListener {
    override fun onInAppDelivered(inappMap: Map<String, Any>) {
        Log.d("InApp", "Delivered")
    }
    
    override fun onInAppOpened(inappMap: Map<String, Any>) {
        Log.d("InApp", "Opened")
    }
    
    override fun onInAppClicked(inappMap: Map<String, Any>) {
        Log.d("InApp", "Clicked")
    }
})
import com.blueshift.Blueshift;
import com.blueshift.BlueshiftInAppListener;
import android.util.Log;

Blueshift.setBlueshiftInAppListener(new BlueshiftInAppListener() {
    @Override
    public void onInAppDelivered(Map<String, Object> inappMap) {
        Log.d("InApp", "Delivered");
    }
    
    @Override
    public void onInAppOpened(Map<String, Object> inappMap) {
        Log.d("InApp", "Opened");
    }
    
    @Override
    public void onInAppClicked(Map<String, Object> inappMap) {
        Log.d("InApp", "Clicked");
    }
});

Test in-app messages

Get device ID

In MainActivity, add this code inside the onCreate() method:

import android.util.Log
import com.blueshift.util.DeviceUtils

val deviceId = DeviceUtils.getDeviceId(this)
Log.d("InAppTest", "Device ID: $deviceId")
import android.util.Log;
import com.blueshift.util.DeviceUtils;

String deviceId = DeviceUtils.getDeviceId(this);
Log.d("InAppTest", "Device ID: " + deviceId);

Run your app and search for InAppTest in Logcat. You'll see something like the following:

D/InAppTest: Device ID: eEzgZKd6QE-M0P5oHL-mWS:com.example.blueshiftsdktest

Copy the Device ID.

Send a test in-app message from Blueshift

  • Go to In-App Studio in the Blueshift dashboard
  • Create a new in-app notification or open an existing one
  • Click the Test Send tab
  • Enter the Device ID in the Device ID field
  • Select the adapter from the App dropdown
  • Click Send

Verify message display

The in-app message should appear on the registered activity. If you added the in-app listener in your Application class during setup, check Logcat for InAppTest:

D/InAppTest: Message delivered
D/InAppTest: Message opened

If the message doesn't appear:

  • Check push notifications are configured (silent push required for triggering)
  • Verify activity is registered for in-app messages
  • Check device targeting in the dashboard
  • Verify event name matches trigger condition
  • Confirm notification permission granted (required for silent push on Android 13+)

Test deep links

Step 1: Add intent filter to AndroidManifest.xml

Add this inside your MainActivity's <activity> tag:

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    
    <data android:scheme="yourapp" />
      </intent-filter>

Replace yourapp with your app's custom scheme.

Step 2: Add deep link handling to MainActivity

Add this in MainActivity's onCreate() method:

import android.net.Uri
import android.util.Log

val uri = intent.data
if (uri != null) {
    Log.d("InAppTest", "Deep link: $uri")
    Log.d("InAppTest", "Scheme: ${uri.scheme}")
    Log.d("InAppTest", "Host: ${uri.host}")
    Log.d("InAppTest", "Path: ${uri.path}")
}
import android.net.Uri;
import android.util.Log;

Uri uri = getIntent().getData();
if (uri != null) {
    Log.d("InAppTest", "Deep link: " + uri);
    Log.d("InAppTest", "Scheme: " + uri.getScheme());
    Log.d("InAppTest", "Host: " + uri.getHost());
    Log.d("InAppTest", "Path: " + uri.getPath());
}

Step 3: Add a deep link to the in-app message

In your in-app message template, add a link or button with your custom scheme (example: yourapp://product/123)

Step 4: Send test message

Use the Test Send tab to send the message to your device

Step 5: Tap the link

When the message appears, tap the link or button

Step 6: Check Logcat

Search for InAppTest in Logcat. You should see:

D/InAppTest: Deep link: yourapp://product/123
D/InAppTest: Scheme: yourapp
D/InAppTest: Host: product
D/InAppTest: Path: /123

If you see the deep link in the logs, your deep link handling is working correctly.

Reference documentation

For more information about in-app messages: