# Flutter SDK 3.2

> What changes when you move the Grovs Flutter plugin from 3.0 to 3.1 and 3.2.

Source: https://docs.grovs.io/docs/upgrade-guides/flutter-3-2

This guide covers both 3.1.0 and 3.2.0 of `grovs_flutter_plugin`. 3.1.0 adds Swift Package Manager support and `handleUrl`, stops the plugin claiming incoming links on iOS and fixes launch links in UIScene apps. 3.2.0 adds [push campaigns](https://docs.grovs.io/docs/sdk/flutter/push-notifications), [in-app messages](https://docs.grovs.io/docs/sdk/flutter/in-app-messages) and `linkDetails`, and moves to the native 3.1 SDKs. No Dart signature changes; existing Dart code still compiles.

Already on 3.1? Skip the steps marked **3.1**.

Requirements: **Flutter 3.38.0** or later (new in 3.1), Dart 3.9.2, iOS 13.0, Android 7.0 (API 24).

## Checklist

1. [Bump the dependency](#1-bump-the-version) to 3.2.0.
2. **3.1** [Turn off Flutter's built-in deep linking](#2-turn-off-flutters-built-in-deep-linking) on both platforms.
3. **3.1** [Remove SceneDelegate link forwarding](#3-remove-scenedelegate-link-forwarding) on iOS, if you added any.
4. **3.2** [Set the notification center delegate](#4-set-the-notification-center-delegate) on iOS.
5. **3.2** [Check your push setup](#5-check-your-push-setup): token code and `firebase_messaging` on Android.
6. **3.2** [Remove the messages inbox](#6-remove-the-messages-inbox) and rename reserved event names.
7. Optional: [control in-app messages](https://docs.grovs.io/docs/sdk/flutter/in-app-messages) and [handle push taps](https://docs.grovs.io/docs/sdk/flutter/push-notifications).

## 1. Bump the version

In `pubspec.yaml`:

```yaml
dependencies:
  grovs_flutter_plugin: ^3.2.0
```

Then run `flutter pub get`. The plugin now pulls in `Grovs` 3.1 on iOS and `io.grovs:Grovs:3.1.0` on Android.

On iOS the plugin builds with Swift Package Manager when Flutter's SPM support is on, and with CocoaPods otherwise. With CocoaPods, if `Grovs ~> 3.1` can't be found, refresh the specs:

```bash
cd ios && pod install --repo-update
```

## 2. Turn off Flutter's built-in deep linking

**3.1.** On iOS the plugin no longer claims incoming links, the same as on Android, so other plugins (login callbacks, say) always receive theirs. Flutter's own deep linking would then also open Grovs links as routes and can send them to Safari. Turn it off.

```xml
<!-- ios/Runner/Info.plist -->
<key>FlutterDeepLinkingEnabled</key>
<false/>
```

```xml
<!-- android/app/src/main/AndroidManifest.xml, inside the launcher <activity> -->
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
```

## 3. Remove SceneDelegate link forwarding

**3.1.** Apps on the UIScene lifecycle lost the link that launched the app from a closed state. That includes new Flutter apps and apps that Flutter 3.41 or later migrated automatically. The plugin now receives scene events itself.

If you added SceneDelegate code that forwards links to Grovs (`Grovs.handleSceneDelegate`), remove it, or every link is delivered twice. If your scene delegate doesn't extend `FlutterSceneDelegate`, follow Flutter's [UIScene migration guide](https://flutter.dev/to/uiscene-migration) so Flutter passes scene events to plugins.

## 4. Set the notification center delegate

**3.2.** On iOS the plugin passes the APNs token to Grovs, counts taps on Grovs pushes and shows them while the app is open. For taps and foreground display, set the delegate in `ios/Runner/AppDelegate.swift`:

```swift
import UserNotifications

// In application(_:didFinishLaunchingWithOptions:), before returning
UNUserNotificationCenter.current().delegate = self
```

If you also call `handleNotificationOpen` from Dart on iOS, remove one of the two, or each tap counts twice.

## 5. Check your push setup

**3.2.**

- **iOS token.** Remove the code that read the APNs token in Dart and passed it to `setPushToken`. The plugin does it. Leaving it in works, with one extra attributes update.
- **Android token.** The plugin fetches the first FCM token when Firebase is present. Keep your `onTokenRefresh` listener that calls `setPushToken`.
- **Android with `firebase_messaging`.** The Grovs messaging service now has priority -1, so `firebase_messaging` handles messages first. Grovs no longer draws pushes while the app is open; draw them in your `onMessage` handler, use `isGrovsNotification` to spot Grovs pushes, and call `handleNotificationOpen` from the tap handler. See [Foreground pushes](https://docs.grovs.io/docs/sdk/flutter/push-notifications#3-foreground-pushes).
- **iOS with `firebase_messaging` 16.x.** It answers every notification before Grovs can, so Grovs pushes don't show in the foreground. Upgrade to 17 or call `setForegroundNotificationPresentationOptions`. See [iOS foreground pushes](https://docs.grovs.io/docs/sdk/flutter/push-notifications#foreground-pushes).
- **Taps reach `onDeeplinkReceived`.** A tapped Grovs push now arrives on the deep link stream. `link` is `null` when the push has no link, so don't assume it's set.

## 6. Remove the messages inbox

**3.2.** The messages inbox is gone from the native SDKs and the backend. The plugin's hidden iOS inbox handlers were removed. Remove any inbox buttons or unread badges in native code. Campaigns built under **Engage** in the dashboard show on their own as in-app messages.

The native 3.1 SDKs also refuse custom event names Grovs uses for reporting. Rename any `track` call that uses one: `in_app_viewed`, `in_app_clicked`, `in_app_dismissed`, `in_app_answered`, `in_app_commented`, `in_app_held`, `push_open`, `push_delivered`, `push_held`, `journey_entered`, `journey_held`, `journey_path`.

## What's new

Nothing here is required.

- **[`handleUrl`](https://docs.grovs.io/docs/sdk/flutter/deep-linking#links-tapped-inside-your-app)** (3.1): resolves a Grovs link tapped inside your own app, which would otherwise open in a browser.
- **[`linkDetails`](https://docs.grovs.io/docs/sdk/flutter/link-creation#link-details)** (3.2): gets a link's details by path, as `GrovsLinkDetails`.
- **[In-app messages](https://docs.grovs.io/docs/sdk/flutter/in-app-messages)** (3.2): campaigns show with no code. `pauseInAppMessages`, `resumeInAppMessages`, `discardInAppMessages`, `setInAppExcludedScreens`, `setInAppDebugLogging` and the `onInAppMessage` stream.
- **[Push campaigns](https://docs.grovs.io/docs/sdk/flutter/push-notifications)** (3.2): tap counting, links followed on tap, `isGrovsNotification` and `handleNotificationOpen`, and campaign images through `GrovsNotificationService` on iOS.
- **Privacy manifest** (3.1): the plugin's iOS privacy manifest is now included in CocoaPods builds.

## Verifying the upgrade

1. Open a Grovs link from a closed app on iOS and Android. It arrives on `onDeeplinkReceived` once, and the app doesn't open Safari or push a route of its own.
2. Call `handleUrl` with one of your links from inside the app. It arrives on `onDeeplinkReceived`.
3. In the dashboard, create an in-app campaign triggered on app open, call `setUserIdentifier` with your own ID, use **Send test**, and bring the app to the foreground.
4. If you use push, send a campaign to your own user ID and tap it. The open shows in the campaign report and the push arrives on `onDeeplinkReceived`.

## See also

- [iOS SDK 3.1](https://docs.grovs.io/docs/upgrade-guides/ios-3-1): what changed in the native iOS SDK underneath
- [Flutter SDK 3.0](https://docs.grovs.io/docs/upgrade-guides/flutter-3-0): upgrading from 1.x
- [API Reference](https://docs.grovs.io/docs/sdk/flutter/api-reference): every property, method and type
- [Flutter CHANGELOG](https://pub.dev/packages/grovs_flutter_plugin/changelog)
