# Quick start

> Install and configure the Grovs Flutter SDK in your app.

Source: https://docs.grovs.io/docs/sdk/flutter/quick-start

Install the plugin, add the native configuration and open your first link on a device. Takes about fifteen minutes.

**Using an AI coding agent?**

Copy one prompt into Claude Code, Cursor or Copilot and it does these steps in your project.

```text
Add Grovs deep linking to this Flutter app (example app: Medly).

1. Add grovs_flutter_plugin: ^3.1.1 to pubspec.yaml and run flutter pub get. It needs Flutter 3.38.0 or later.
2. Android: in AndroidManifest.xml, add the grovs_api_key and grovs_use_test_environment meta-data inside the application element. Add intent filters to the launcher activity: the custom URL scheme and autoVerify App Links for the production and test hosts. Add flutter_deeplinking_enabled=false meta-data to that activity.
3. iOS: in Info.plist, add GrovsApiKey, GrovsUseTestEnvironment, FlutterDeepLinkingEnabled=false and the URL scheme from the Grovs dashboard. Add the Associated Domains capability with applinks: entries for the production and test hosts.
4. Read the API key from the existing secrets setup (env GROVS_API_KEY); don't commit it. Use the test environment only in debug builds.
5. Subscribe to Grovs().onDeeplinkReceived in the root widget and route DeeplinkDetails.data to the existing navigation.
6. Build both platforms, then list what you changed.

Docs: https://docs.grovs.io/docs/sdk/flutter/quick-start.md
```

> **Note:** Upgrading from 3.0? See the [3.1 upgrade guide](https://docs.grovs.io/docs/upgrade-guides/flutter-3-2). From 1.x, start with the [3.0 upgrade guide](https://docs.grovs.io/docs/upgrade-guides/flutter-3-0).

## Requirements

- Flutter 3.38.0+, Dart 3.9.2+
- iOS 13.0+
- Android 7.0 (API 24)+. The launcher activity can extend `FlutterActivity` (the default) or `FlutterFragmentActivity`.
- Your bundle ID, package name and SHA-256 signing fingerprint registered in the Grovs dashboard. See [How to Get the Package Name](https://docs.grovs.io/docs/how-to-guides/android/package-name) and [How to Get the SHA-256 Fingerprint](https://docs.grovs.io/docs/how-to-guides/android/sha256-fingerprint)

## Installation

Add to `pubspec.yaml`:

```yaml
dependencies:
  grovs_flutter_plugin: ^3.1.1
```

```bash
flutter pub get
```

The plugin pulls in the native SDKs (`Grovs` from 3.1.0 on iOS, `io.grovs:Grovs:3.1.0` on Android). Don't add them to your app separately. On iOS it builds with Swift Package Manager when Flutter's SPM support is on, and with CocoaPods (`Grovs ~> 3.1`) otherwise.

## Configuration

There's no `configure` call in Dart. The plugin reads native config files and configures the SDK at launch, before any Dart runs.

| Info.plist key                            | AndroidManifest.xml `meta-data` name               | Default     | Description                                                                                                                                                                                                   |
| ----------------------------------------- | -------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GrovsApiKey` (String)                    | `grovs_api_key` (string)                           | required    | Project API key from the Grovs dashboard. If missing, iOS doesn't configure the SDK at all; Android passes an empty string.                                                                                   |
| `GrovsUseTestEnvironment` (Boolean)       | `grovs_use_test_environment` (boolean)             | `false`     | `true` targets the test environment, `false` production. Match your API key's environment.                                                                                                                    |
| `GrovsBaseURL` (String)                   | `grovs_base_url` (string)                          | Grovs cloud | Domain of a [self-hosted backend](https://docs.grovs.io/docs/self-hosting/configure/sdk-configuration), for example `https://sdk.example.com`.                                                                |
| `GrovsClipboardDomains` (Array of String) | `grovs_clipboard_domains` (comma-separated string) | none        | Extra link hosts accepted by [clipboard-assisted deferred deep linking](https://docs.grovs.io/docs/sdk/flutter/deep-linking#clipboard-assisted-deferred-deep-linking). Grovs-owned hosts are always accepted. |
| `GrovsEnabled` (Boolean)                  | `grovs_enabled` (boolean)                          | `true`      | Whether the SDK may collect and send anything this launch. Set `false` and call `setSDK(true)` after consent. See [Privacy & Consent](https://docs.grovs.io/docs/sdk/flutter/privacy).                        |

The plugin always turns native automatic screen tracking off. Screen views come from `Grovs.navigatorObserver`; see [Events & Screen Tracking](https://docs.grovs.io/docs/sdk/flutter/analytics#automatic-screen-tracking).

## Android setup

### 1. Add configuration to AndroidManifest.xml

Inside `<application>` in `android/app/src/main/AndroidManifest.xml`:

```xml
<application>
    <meta-data
        android:name="grovs_api_key"
        android:value="YOUR_API_KEY" />
    <meta-data
        android:name="grovs_use_test_environment"
        android:value="true" />

    <!-- Optional: custom base URL for self-hosted backends -->
    <meta-data
        android:name="grovs_base_url"
        android:value="https://sdk.example.com" />

    <!-- Optional: start disabled until the user gives consent (default true) -->
    <meta-data
        android:name="grovs_enabled"
        android:value="false" />

    <!-- Optional: extra hosts accepted for clipboard deferred deep linking -->
    <meta-data
        android:name="grovs_clipboard_domains"
        android:value="links.example.com,promo.example.com" />
</application>
```

The plugin configures the SDK once per process when the first Flutter engine attaches. It follows the host activity's own lifecycle to call `Grovs.onStart`, and forwards `onNewIntent` from the engine's activity. `MainActivity` needs no changes.

### 2. Add intent filters

Add these to your launcher activity:

```xml
<activity android:name=".MainActivity">
    <!-- Custom URL scheme -->
    <intent-filter>
        <data android:scheme="your_app_scheme" android:host="open" />
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
    </intent-filter>

    <!-- App links (production) -->
    <intent-filter android:autoVerify="true">
        <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" android:host="your_app_host" />
    </intent-filter>

    <!-- App links (test) -->
    <intent-filter android:autoVerify="true">
        <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" android:host="your_app_test_host" />
    </intent-filter>
</activity>
```

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

The plugin hands every link to the SDK and leaves it for other plugins too, so Flutter's own deep linking would also open Grovs links as routes. Add this inside the launcher activity:

```xml
<meta-data android:name="flutter_deeplinking_enabled" android:value="false" />
```

## iOS setup

### 1. Add configuration to Info.plist

Add to `ios/Runner/Info.plist`:

```xml
<key>GrovsApiKey</key>
<string>YOUR_API_KEY</string>
<key>GrovsUseTestEnvironment</key>
<true/>

<!-- Optional: custom base URL for self-hosted backends -->
<key>GrovsBaseURL</key>
<string>https://sdk.example.com</string>

<!-- Optional: start disabled until the user gives consent (default true) -->
<key>GrovsEnabled</key>
<false/>

<!-- Optional: extra hosts accepted for clipboard deferred deep linking -->
<key>GrovsClipboardDomains</key>
<array>
    <string>links.example.com</string>
    <string>promo.example.com</string>
</array>
```

The plugin registers as an application delegate and a scene delegate, so launches, universal links and URL opens reach the SDK with no `AppDelegate.swift` or `SceneDelegate` changes. It never claims a link, so other plugins (login callbacks, say) still receive theirs. It also sets itself as `Grovs.delegate` and `Grovs.inAppDelegate`. Don't assign your own delegates natively, or deep links and in-app events stop reaching Dart.

### 2. Configure URL schemes

Add your URL scheme to `Info.plist`:

```xml
<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>your_app_scheme</string>
        </array>
    </dict>
</array>
```

### 3. Configure Associated Domains

1. Open `ios/Runner.xcworkspace` in Xcode.
2. Select the **Runner** target, then **Signing & Capabilities**.
3. Click **+ Capability** and add **Associated Domains**.
4. Add `applinks:your_app_host` and `applinks:your_app_test_host`.

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

Without this, Flutter's own deep linking also opens Grovs links as routes and can send links that have no matching route to Safari. Add to `Info.plist`:

```xml
<key>FlutterDeepLinkingEnabled</key>
<false/>
```

### 5. App lifecycle

Nothing to add. The plugin works with the UIScene lifecycle (`FlutterSceneDelegate`, the default for new Flutter apps) and with AppDelegate-only apps. If you wrote scene delegate code that calls `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.

For push campaigns, set the notification center delegate in `AppDelegate.swift`. See [Push notifications](https://docs.grovs.io/docs/sdk/flutter/push-notifications#ios).

## Basic usage

```dart
import 'package:grovs_flutter_plugin/grovs.dart';

final grovs = Grovs();

// Optional: verbose logging while integrating ('info' or 'error')
await grovs.setDebugLevel('info');

// Optional: identify the user
await grovs.setUserIdentifier('user-123');
await grovs.setUserAttributes({
  'name': 'Jane Doe',
  'plan': 'premium',
});
```

Every method returns a `Future` and throws `GrovsException` when the native call fails. Only `getPlatformVersion` lets a raw `PlatformException` through. `grovs.dart` also exports the in-app message types. The link and error models (`GenerateLinkParams`, `DeeplinkDetails`, `GrovsLinkDetails`, `GrovsException` and the rest) need a second import:

```dart
import 'package:grovs_flutter_plugin/models/grovs_link.dart';
```

## Next steps

- [Handle incoming deep links →](https://docs.grovs.io/docs/sdk/flutter/deep-linking)
- [Generate smart links →](https://docs.grovs.io/docs/sdk/flutter/link-creation)
- [Receive push campaigns →](https://docs.grovs.io/docs/sdk/flutter/push-notifications)
- [Control in-app messages →](https://docs.grovs.io/docs/sdk/flutter/in-app-messages)
- [Track events and screens →](https://docs.grovs.io/docs/sdk/flutter/analytics)
- [Gate collection on user consent →](https://docs.grovs.io/docs/sdk/flutter/privacy)

## See also

- [Integrating a pub.dev Package](https://docs.grovs.io/docs/how-to-guides/flutter/pub-dev): add the package from pub.dev
- [How to Add an Associated Domain](https://docs.grovs.io/docs/how-to-guides/ios/associated-domain): Xcode steps in detail
- [How to Add a New Intent Filter](https://docs.grovs.io/docs/how-to-guides/android/intent-filter): Android intent filters in detail
- [How to Get the SHA-256 Fingerprint](https://docs.grovs.io/docs/how-to-guides/android/sha256-fingerprint): fingerprints for App Links verification
- [Deep link not opening the app](https://docs.grovs.io/docs/troubleshooting/deep-link-not-opening-app): links open the browser instead of the app
- [SDK configuration issues](https://docs.grovs.io/docs/troubleshooting/sdk-configuration-issues): common setup and initialization problems
