# Android SDK 3.1

> What changes when you move the Grovs Android SDK from 3.0 to 3.1.

Source: https://docs.grovs.io/docs/upgrade-guides/android-3-1

3.1.0 adds [push campaigns](https://docs.grovs.io/docs/sdk/android/push-notifications) and [in-app messages](https://docs.grovs.io/docs/sdk/android/in-app-messages), and removes the messages inbox along with the dependencies it brought in. Most apps bump the version, add back any dependency they relied on, and fix what the compiler flags.

Requirements are unchanged: **Android 5.0 (API 21)**, Kotlin 1.8 or later.

## Checklist

1. [Bump the dependency](#1-bump-the-version) to 3.1.0.
2. [Declare the libraries the SDK no longer brings in](#2-declare-libraries-the-sdk-no-longer-brings-in), if your app uses them.
3. [Remove the messages inbox](#3-remove-the-messages-inbox) from your UI.
4. [Update your own messaging service](#4-update-your-own-messaging-service), if you have one.
5. [Check how you handle push taps](#5-check-how-you-handle-push-taps).
6. [Rename custom events that use a reserved name](#6-rename-reserved-event-names).
7. [Check the other behavior changes](#7-other-behavior-changes).
8. Optional: [set up push campaigns](https://docs.grovs.io/docs/sdk/android/push-notifications), [react to in-app messages](https://docs.grovs.io/docs/sdk/android/in-app-messages#react-to-messages) and [enable app ratings](https://docs.grovs.io/docs/sdk/android/in-app-messages#app-ratings).

## 1. Bump the version

In your app-level `build.gradle`:

```groovy
dependencies {
    implementation("io.grovs:Grovs:3.1.0")
}
```

The SDK now depends on `androidx.webkit:webkit`, for HTML in-app messages.

## 2. Declare libraries the SDK no longer brings in

The SDK used these only for the inbox screens. If your app uses any of them, declare them yourself, or the build fails with missing classes or resources:

- `com.google.android.material:material`
- `androidx.constraintlayout:constraintlayout`
- `androidx.navigation:navigation-fragment-ktx`
- `androidx.navigation:navigation-ui-ktx`

The SDK now depends on `androidx.navigation:navigation-runtime-ktx` instead, so `trackNavigation` still works.

## 3. Remove the messages inbox

The inbox is gone on the device and the backend. In-app messages replace it.

- `Grovs.displayMessagesFragment(onDismissed)` is deprecated and shows nothing. It calls `onDismissed` once on the main thread.
- Both `Grovs.numberOfUnreadMessages` forms are deprecated and always yield `0`, the callback once on the main thread. They used to yield `null` when the SDK wasn't configured, was disabled or was offline.
- `Grovs.setOnAutomaticNotificationsListener` and `GrovsNotificationsListener` are deprecated. The listener is never called.
- The SDK no longer displays dashboard messages automatically or calls the inbox endpoints.

Remove inbox buttons and unread badges. Campaigns built under **Engage** in the dashboard show on their own once the SDK is configured.

These were public and are now removed. Code that referenced them won't compile:

- `io.grovs.handlers.NotificationsManager`, and everything in `io.grovs.fragments`, `io.grovs.viewmodels`, `io.grovs.adapters` and `io.grovs.model.notifications`.
- The generated `io.grovs.databinding` classes.
- The extensions `Fragment.applySystemBarInsets`, `showProgressBar`, `hideProgressBar` and `NavController.safeNavigate`.
- `ActivityProvider.requireNotificationsListener`.
- The instance methods `displayMessagesFragment`, `numberOfUnreadMessages`, `setOnAutomaticNotificationsListener` and `requireNotificationsListener` on `Grovs` instances. The companion methods `Grovs.displayMessagesFragment` and the others stay.
- The four inbox methods on `IGrovsService`.

The inbox resources are removed too. If your app overrode or referenced them, delete those references:

- The `Grovs*` text and button styles, except `GrovsInAppWindow`.
- The strings `grovs_messages` and `grovs_messages_empty`.
- The `grovs_*` colors, except `grovs_push_notification_icon_tint`.
- The inbox layouts, navigation graph, slide animations and icons.

## 4. Update your own messaging service

If your app declares its own `FirebaseMessagingService`, replace `handleGrovsNotification`, now deprecated, with `GrovsMessaging.handleMessage`. In 3.0 it only handled inbox pushes; `handleMessage` handles push campaigns.

```kotlin
// 3.0
override fun onMessageReceived(message: RemoteMessage) {
    if (handleGrovsNotification(message)) return
    // your own messages
}

override fun onNewToken(token: String) {
    super.onNewToken(token)
    Grovs.pushToken = token
}

// 3.1
override fun onMessageReceived(message: RemoteMessage) {
    if (GrovsMessaging.handleMessage(this, message)) return
    // your own messages
}

override fun onNewToken(token: String) {
    GrovsMessaging.onNewToken(token)
}
```

You can also extend `io.grovs.handlers.MessagingService` instead. Either way, remove the SDK's service declaration from your merged manifest with `tools:node="remove"`. See [If your app has its own FirebaseMessagingService](https://docs.grovs.io/docs/sdk/android/push-notifications#if-your-app-has-its-own-firebasemessagingservice).

## 5. Check how you handle push taps

In 3.0 the SDK ignored Grovs push campaigns: Android showed background pushes, nothing showed foreground ones, and your app read the `grovs_*` intent extras itself. In 3.1:

- **Taps reach your deep link listener.** The SDK reports the open and calls `GrovsDeeplinkListener` with the push data, merged over its link's data. If your app also routes from the intent extras, it routes twice. Remove your own routing for Grovs pushes.
- **Foreground pushes are shown.** The SDK's messaging service, or `GrovsMessaging.handleMessage`, now shows Grovs pushes while the app is open, with their image. If your app showed them itself, remove that code, or set `GrovsMessaging.showForegroundNotifications = false`.
- **Splash screens.** If your launcher starts another activity without its extras, call `Grovs.handleNotificationOpen(intent)` where the tap lands.

A push is a Grovs push when its data has a non-blank `grovs_campaign_id`. A blank or whitespace-only ID is no longer treated as one.

## 6. Rename reserved event names

`track` now refuses every name the backend reserves. Rename any custom event that uses one of these, newly refused in 3.1:

`push_open`, `push_delivered`, `push_held`, `in_app_held`, `journey_entered`, `journey_held`, `journey_path`.

## 7. Other behavior changes

- **In-app messages show without code.** Once your project has live in-app campaigns, they show in the app. Use [`pauseInAppMessages`](https://docs.grovs.io/docs/sdk/android/in-app-messages#hold-messages-back) or [`setInAppExcludedScreens`](https://docs.grovs.io/docs/sdk/android/in-app-messages#hold-messages-back) to keep them off flows like checkout.
- **Notification permission.** The SDK doesn't declare `POST_NOTIFICATIONS`. On Android 13 and later, in-app campaigns with an "Ask for push permission" button aren't shown unless your app declares it.
- **App ratings.** "Rate the app" campaigns need `com.google.android.play:review-ktx` in your app. Without it they're skipped.
- **Values set before `configure`.** `identifier`, `attributes` and `pushToken` set before `configure` are kept and sent once the SDK authenticates. They used to be lost. `identifier` and `attributes` set this way still win over the values the server holds.
- **Push token.** A token set before authentication no longer clears the user identifier and attributes on the server. Token refreshes reach Grovs without app code.
- **Small icon meta-data.** `io.grovs.NotificationIconSmall` accepts `android:resource` as well as a drawable name in `android:value`.
- **Screen tracking.** Screens whose class is named `NotificationsMainFragment`, `NotificationsListFragment`, `NotificationDetailsFragment` or `AutoDisplayedNotificationFragment` are now tracked like any other screen.
- **Event properties.** Whole numbers in custom event properties are sent as whole numbers (`4`, not `4.0`).
- **Custom service implementations.** `BatchEventsResponse` has a new `inApp` field, so its constructor and `copy` changed, and `IGrovsService` has new `inAppSync` and `pushOpen(campaignId, sessionId)` methods. This only affects code that constructs or implements these types.
- **Data safety.** Push opens and in-app message interactions are now reported. Check your Google Play Data safety form against [what the SDK collects](https://docs.grovs.io/docs/sdk/android/privacy#what-the-sdk-collects).

## Verify the upgrade

1. Build with no missing-class or missing-resource errors.
2. Open a Grovs link and check that your `GrovsDeeplinkListener` still receives it.
3. In the dashboard, create an in-app campaign triggered on app open, use **Send test** with your own user identifier, and bring the app to the foreground. The message shows at the next sync.
4. If you use push, send a campaign to your own user identifier and tap it, once with the app in the background and once with it open. The open shows in the campaign report, and the listener gets the push data once per tap.

Full list of changes: [Android CHANGELOG](https://github.com/grovs-io/grovs-Android/blob/main/CHANGELOG.md).
