# In-App Messaging

In-App Campaigns allow you to trigger messages when users open your app or perform a specific action. This is great to communicate with users who have turned off push notifications or to show contextual messages while your users are browsing your app _(e.g. special offers, update reminder, etc)_.

![In-App formats](https://38998153-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCL8wF0y1T2vLnm3yR2MW%2Fuploads%2Fqp99NdkZNILOt23tWk3k%2Fios_inapp_format.jpg?alt=media\&token=7cf2643f-616c-4386-9bb8-cc0227f4f026)

### Requirements

In-App Messaging takes full advantage of [mobile landings](mobile-landings): If they are already working in your app, In-App Messaging should work out of the box.

Multiple formats are available:

* Fullscreen
* Banner
* Image
* Modal
* WebView (Batch SDK 1.17.+)

### Displaying In-App messages

#### Fully automatic mode

There is no code required to make In-App Messages work in automatic mode. Create some campaigns on your dashboard, and they will start coming up in your app.\
If they don't, please head over to the [troubleshooting](#Troubleshooting) section.

{% hint style="info" %}
The automatic mode will only work properly if Batch is well integrated into **ALL** of your activities.
{% endhint %}

#### Controlling the display using "Do Not Disturb mode"

You can also get more control on when messages are displayed without giving up on the automatic mode, by using the "Do Not Disturb" (DnD) mode.\
It allows you to tell Batch to hold on an in-app message for you, rather than display it without using the fully manual mode.\
For example, if launching your app results in a splash screen or a fullscreen ad, you might find it undesirable to have Batch display something on top of it.

Turning on "Do Not Disturb" mode will make Batch enqueue the latest message, rather than display it.

**Toggling DnD**

Now, when you don't want Batch to automatically display, turn on Do Not Disturb:

{% tabs %}
{% tab title="Kotlin" %}
```kotlin
Batch.Messaging.setDoNotDisturbEnabled(true)
```
{% endtab %}

{% tab title="Java" %}
```java
Batch.Messaging.setDoNotDisturbEnabled(true);
```
{% endtab %}
{% endtabs %}

Once you want to start showing messages automatically, call the method with `false` to turn it off.

{% hint style="info" %}
Disabling Do Not Disturb mode does NOT make Batch show the enqueued message
{% endhint %}

**Displaying pending mobile landings**

After coming back from DnD mode, you might want to show the enqueued message, as Batch will not do that automatically. Batch exposes two methods for managing the queue:

* `Batch.Messaging.hasPendingMessage()` , allowing you to peek into the queue.
* `Batch.Messaging.popPendingMessage()` , allowing you to fetch the pending message (if any). Since calling this makes Batch delete its reference to it to save memory, further calls might return `null`.

Here is a quick example of how they can be used:

{% tabs %}
{% tab title="Kotlin" %}
```kotlin
fun splashScreenDismissed(context: Context) {
    Batch.Messaging.setDoNotDisturbEnabled(false)
    val message = Batch.Messaging.popPendingMessage()
    message?.let {
        Batch.Messaging.show(context, it)
    }
}
```
{% endtab %}

{% tab title="Java" %}
```java
public void splashScreenDismissed(Context context) {
    Batch.Messaging.setDoNotDisturbEnabled(false);
    BatchMessage msg = Batch.Messaging.popPendingMessage();
    if (msg != null) {
        Batch.Messaging.show(context, msg);
    }
}
```
{% endtab %}
{% endtabs %}

{% hint style="info" %}
Only the latest message is queued: if a mobile landing arrives while one is still pending, it will overwrite the previous one.
{% endhint %}

#### Excluding activities

If your application shows a temporary activity before your main one (such as a trampoline or splash screen activity), it is possible to mark it as excluded from Batch's lifecycle handling. Batch will handle storing intent information and will delay its start:

* Any mobile landing will automatically be enqueued and displayed over the next activity.
* In-App messages will not be triggered on the excluded activity.
* Direct open tracking will also wait for the next activity.

To do so, add the following meta-data your `AndroidManifest.xml` :

```xml
<activity android:name=".SplashActivity">
     ...
    <meta-data 
      android:name="com.batch.android.EXCLUDE_FROM_LIFECYCLE" 
      android:value="true" />
</activity>
```

This feature shouldn't be used for activities shown during user navigation, such as ads or a critical path. Do Not Disturb is the way to go for these use cases.

#### Manual mode

Like Mobile Landings, you may want to take full control over how in-app messaging behaves. Batch allows you to disable automatic displaying, and handle that yourself. For compatibility reasons, `Batch.Messaging.setAutomaticMode(false)` does not control this behavior like it does on mobile landings.

In order to handle messages yourself, you will have to set an implementation of the `Batch.Messaging.InAppInterceptor` interface.

You'll then have the option to handle the message yourself, or let Batch continue processing it as if it was in automatic mode.

\
Here is an example:

{% tabs %}
{% tab title="Kotlin" %}
```kotlin
class SampleApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // [...]
        Batch.Messaging.setInAppInterceptor(InAppAwareListener())
    }
}

class InAppAwareListener : InAppInterceptor {
    // ...InAppInterceptor interface method implementations...
    
    override fun onBatchInAppMessageReady(message: BatchInAppMessage): Boolean {
        // Sample implementation that prevents messages from being displayed if the logged in user isn't the right one
        // "getLoggedInUsername()" is an hypothetical method that returns the logged in username as a string, if logged in
        if (message.customPayload.optString("username", "") == getLoggedInUsername()) {
            // Returning false tells Batch that we didn't want to handle the message.
            // Batch will then display it
            return false
        }
        return true
    }
}
```
{% endtab %}

{% tab title="Java" %}
```java
public class SampleApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Batch.Messaging.setLifecycleListener(new InAppAwareListener());
    }
}

public class InAppAwareListener implements Batch.Messaging.InAppInterceptor {
    // ...InAppInterceptor interface method implementations...
  
    public boolean onBatchInAppMessageReady(@NonNull BatchInAppMessage message) {
        // Sample implementation that prevents messages from being displayed if the logged in user isn't the right one
        // "getLoggedInUsername()" is an hypothetical method that returns the logged in username as a string, if logged in
        if (message.getCustomPayload().optString("username", "").equals(getLoggedInUsername())) {
          // Returning false tells Batch that we didn't want to handle the message.
          // Batch will then display it
          return false;
        }
        return true;
    }
}
```
{% endtab %}
{% endtabs %}

### Troubleshooting

#### In-App messages fail to show

This can come from multiple things:

* Batch might not be able to display the message: make sure all of the prerequisites are satisfied by your app.\
  If proguard is enabled, try disabling it temporarily.
* The In-App campaign might not have been synchronized yet. Try to kill and restart your app: backgrounding it might not be enough.
* If the trigger is "next session", you might just not have triggered a new session yet. Try force killing and restarting the app, or wait 5 minutes with the app in the background.\
  Restarting the app might be needed twice: once to sync the campaigns, and once to trigger the "new session" event.

If that does not fix the problem, please check the logs using logcat and see if Batch outputs anything.\
If not, you can always contact our [support team](https://batch.com/support) with information about your problem.
