# SDK integration

*This guide assumes that you've already followed the* [*iOS*](/developer/sdk/ios/prerequisites.md) *and* [*Android*](/developer/sdk/android/prerequisites.md) *prerequisites.*

## Installation

*batch\_flutter requires Flutter 2.0 and Dart 2.15 or higher. Flutter 3 is supported.*

```shell
flutter pub add batch_flutter
```

## Setting up the plugin

Batch requires that the native projects are modified to configure the plugin.

This is required as Android and iOS might kill your applications process only to launch it at a later date to handle background tasks, such as displaying a notification. Integrating natively allows Batch to work even if the Flutter engine is not started.

Before proceeding, you will need your SDK API key. In the following documentation samples `YOUR_BATCH_API_KEY` should be replaced with your Batch SDK API key. You'll find it in Settings → General.

{% hint style="warning" %}
You should not use the same API key for iOS and Android.
{% endhint %}

### Android

***

#### Adding Firebase Cloud Messaging

Batch requires Firebase Cloud Messaging (FCM) for push to be enabled. It can be added using a Flutter plugin, or natively in the Android project by following [Firebase's native FCM documentation](https://firebase.google.com/docs/android/setup).

#### Adding Huawei Push (Optional)

Batch supports notifications using Huawei Mobile Services (HMS) for devices that don't support Play Services.\
If you require this, please follow the [native Android Huawei documentation](/developer/sdk/android/huawei.md).

#### Setting up a custom application class

If you already have a custom `android.app.Application` subclass registered, you can skip this step.

Open your project's Android folder in Android Studio.

First, create a new class that subclasses `android.app.Application`. It can be named however you want, but we will call it `ExampleApplication` for the sake of this example.\
Place it in your root package.

Then, add an `onCreate()` override. The class should look like this:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import android.app.Application

class ExampleApplication: Application() {
    override fun onCreate() {
        super.onCreate()
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
import android.app.Application;

public class ExampleApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
    }
}
```

{% endtab %}
{% endtabs %}

Finally, open your `AndroidManifest.xml` and find the `application` tag.\
In it, add an `android:name` attribute, and set the value to your class' name, prefixed by a dot (`.`).

{% code title="AndroidManifest.xml" %}

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.batch.batch_flutter_example">
   <application
        android:name=".ExampleApplication" >
   </application>
</manifest>
```

{% endcode %}

#### Enabling the plugin

In your `Application` subclass' `onCreate()` method, call `BatchFlutterPlugin.setup(this)`.

Example:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
import android.app.Application
import com.batch.batch_flutter.BatchFlutterPlugin

class ExampleApplication: Application() {
    override fun onCreate() {
        super.onCreate()
        // Configuration can also be provided as metadata in AndroidManifest.xml. This will be explained
        // in the documentation's next steps.
        BatchFlutterPlugin.getConfiguration(this)
                .setAPIKey("YOUR_API_KEY")
        BatchFlutterPlugin.setup(this)
    }
}
```

{% endtab %}

{% tab title="Java" %}

```java
import android.app.Application;
import com.batch.batch_flutter.BatchFlutterPlugin;

public class ExampleApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // Configuration can also be provided as metadata in AndroidManifest.xml. This will be explained
        // in the documentation's next steps.
        BatchFlutterPlugin.getConfiguration(this)
                .setAPIKey("YOUR_API_KEY");
        BatchFlutterPlugin.setup(this);
    }
}
```

{% endtab %}
{% endtabs %}

### iOS

***

Run `flutter build ios --no-codesign` after adding the plugin to your `pubspec` to initialize the native dependency.

#### Minimum iOS version

Default iOS Flutter projects can run on iOS 12.0 or higher. However, Batch requires iOS 15.\
This can lead to the following error when `flutter build ios` is ran:

```
Specs satisfying the `batch_flutter (from `.symlinks/plugins/batch_flutter/ios`)` 
dependency were found, but they required a higher minimum deployment target.
```

To fix this, you need to make your application require iOS 15 or higher:

* Open `ios/Podfile` and add `platform :ios, '15.0'` at the beginning of the file.\
  Make sure you do not have any other line starting with `platform :ios`.\
  If your app should require an higher iOS version, replace `15.0` with your minimum OS version.
* Update the iOS deployment target in the Xcode project.\
  This can be done later, as this will only produce a warning for now, but it must be fixed before submitting to the store.

#### Enable Push Capabilities

Open the `xcworkspace` in the `ios/` folder. In the project window:

* Select your project in the sidebar
* Go to `Signing & Capabilities`
* Press on `+ Capability`
* Add `Push Notifications`

#### Modifying the AppDelegate

Open `AppDelegate.swift` (or .m if you have an Objective-C plugin). In it:

* Import the `Batch` and `batch_flutter` modules.
* Inside of `didFinishLaunchingWithOptions`:
  * Add `BatchUNUserNotificationCenterDelegate.registerAsDelegate()` if you do not already have a custom `UNUserNotificationCenterDelegate`. If you do, please [follow this documentation](/developer/sdk/ios/advanced/intercepting-notifications.md).
  * Call `BatchFlutterPlugin.setup()`.
  * Call `BatchPush.refreshToken()`.

Here is an example Swift implementation of the AppDelegate:

{% code title="AppDelegate.swift" %}

```swift
import UIKit
import Flutter
import batch_flutter
import Batch

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GeneratedPluginRegistrant.register(with: self)
    
    // If you already have a UNUserNotificationCenterDelegate, please follow
    // https://doc.batch.com/ios/advanced/intercepting-notifications#ios-10
    // to integrate Batch in it.
    // Note that as a result, changing the value of`BatchPush.showsiOSForegroundNotifications`
    // won't have any effect.
    BatchUNUserNotificationCenterDelegate.registerAsDelegate()
    // API Key can also be configured in the Info.plist. This will be explained
    // in the documentation's next steps.
    BatchFlutterPlugin.configuration.APIKey = "YOUR_API_KEY"
    BatchFlutterPlugin.setup()
    BatchPush.refreshToken()
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

```

{% endcode %}

#### Rich notifications

Rich notifications require setting up a Notification Service Extension. Please follow the native [Rich notifications setup documentation](/developer/sdk/ios/sdk-integration/rich-notifications-setup.md).

{% hint style="info" %}
Due to a [Flutter bug](https://github.com/flutter/flutter/issues/76868), we advise using CocoaPods to add `BatchExtension` rather than SPM. If you're getting an error saying "Packages are not supported when using legacy build locations, but the current project has them enabled", this might be the underlying issue.
{% endhint %}

## Configuring the plugin

As shown by the examples earlier, the plugin needs to be configured with the API Key.\
There are two ways to do so:

* Code configuration, in your `Application` subclass on Android, `AppDelegate` on iOS.
* Static configuration, using `AndroidManifest.xml` on Android, `Info.plist` on iOS.

{% hint style="warning" %}
Not configuring an API key will result in any `batch_flutter` dart method call to throw an exception
{% endhint %}

### Android

***

Code based configuration should be done in your `Application` subclass, right before `BatchFlutterPlugin.setup`: configuration changes made after calling this method will not be applied.

Call `BatchFlutterPlugin.getConfiguration(this)` to get the configuration object, which can be used as a builder. Changes will automatically be saved.

Example:

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
BatchFlutterPlugin.getConfiguration(this).setAPIKey("YOUR_API_KEY")
```

{% endtab %}

{% tab title="Java" %}

```java
BatchFlutterPlugin.getConfiguration(this).setAPIKey("YOUR_API_KEY");
```

{% endtab %}
{% endtabs %}

The following methods are available:

* `setAPIKey`: Batch API Key.
* `setInitialDoNotDisturbState`: Enables [Do Not Disturb](/developer/sdk/flutter/messaging.md#controlling-the-display-using-do-not-disturb-mode) by default. Default: false.
* `setProfileCustomIdMigrationEnabled`: Enables profile custom id migration. See [profile data migration](/developer/sdk/flutter/profile-data/data-migration.md) for more info. Default: true.
* `setProfileCustomDataMigrationEnabled`: Enables profile custom data migration. See [profile data migration](/developer/sdk/flutter/profile-data/data-migration.md) for more info. Default: true.

{% hint style="info" %}
If you call `getConfiguration` and have also configured the plugin using the manifest, the object's default values will mirror your manifest values.
{% endhint %}

Manifest configuration automatically looks for the following keys:

* `com.batch.flutter.apikey`: Batch API Key.
* `com.batch.flutter.do_not_disturb_initial_state`: Enables [Do Not Disturb](/developer/sdk/flutter/messaging.md#controlling-the-display-using-do-not-disturb-mode) by default. Default: false.
* `com.batch.flutter.profile_custom_id_migration_enabled`: Enables profile custom id migration. See [profile data migration](/developer/sdk/flutter/profile-data/data-migration.md) for more info. Default: true.
* `com.batch.flutter.profile_custom_data_migration_enabled`: Enables profile custom data migration. See [profile data migration](/developer/sdk/flutter/profile-data/data-migration.md) for more info. Default: true.

Boolean keys should be set as `"true"`/`"false"`.

### iOS

***

Code based configuration should be done in your application delegate class, right before `BatchFlutterPlugin.setup`: configuration changes made after calling this method will not be applied.

Call `BatchFlutterPlugin.configuration` to get the configuration object. Changes will automatically be saved.

Example:

```swift
BatchFlutterPlugin.configuration.APIKey = "YOUR_API_KEY"
```

The following properties can be used to configure the plugin:

* `APIKey` (string): Batch API Key.
* `initialDoNotDisturbState` (boolean): Enables [Do Not Disturb](/developer/sdk/flutter/messaging.md#controlling-the-display-using-do-not-disturb-mode) by default. Default: false.
* `profileCustomIdMigrationEnabled` (boolean): Enables profile custom id migration. See [profile data migration](/developer/sdk/flutter/profile-data/data-migration.md) for more info. Default: true.
* `profileCustomDataMigrationEnabled` (boolean): Enables profile custom data migration. See [profile data migration](/developer/sdk/flutter/profile-data/data-migration.md) for more info. Default: true.

{% hint style="info" %}
If you call `configuration` and have also configured the plugin using the Info.plist, the object's default values will mirror your manifest values.
{% endhint %}

`Info.plist`-based configuration looks for the following keys:

* `BatchFlutterAPIKey` (string): Batch API Key.
* `BatchFlutterDoNotDisturbInitialState` (boolean): Enables [Do Not Disturb](/developer/sdk/flutter/messaging.md#controlling-the-display-using-do-not-disturb-mode) by default. Default: false.
* `BatchFlutterProfileCustomIdMigrationEnabled` (boolean): Enables profile custom id migration. See [profile data migration](/developer/sdk/flutter/profile-data/data-migration.md) for more info. Default: true.
* `BatchFlutterProfileCustomDataMigrationEnabled` (boolean): Enables profile custom data migration. See [profile data migration](/developer/sdk/flutter/profile-data/data-migration.md) for more info. Default: true.

## Asking for the permission to display notifications

On iOS and Android (13+), your app needs to request for the permission to display notifications.\
This is done on the Flutter side of the app, as it can be asked as a step of an onboarding.\
Once the user consents, the push token will automatically be fetched by the SDK.

This can be done using `BatchPush.instance.requestNotificationAuthorization()`  or the async variant `BatchPush.instance.requestNotificationAuthorizationAsync()` :

```dart
import 'package:batch_flutter/batch_push.dart';

@override
Widget build(BuildContext context) {
  return ElevatedButton(
        child: Text("Request notification permission"),
        onPressed: () =>
            BatchPush.instance.requestNotificationAuthorization(),
      )
}
// Or use the async variant
// final granted = await BatchPush.instance.requestNotificationAuthorizationAsync();
```

## Your first notification

You can now build and launch your application! Batch should automatically start.\
We can now display a test push notification.

#### 1. Obtaining Your Device Token on iOS

You can find your device's token using the [debug tool](https://doc.batch.com/guides-and-best-practices/profiles/how-to-see-the-data-attached-to-your-install-or-custom-user-id) or locating the token Batch posts to the Xcode console:

```objc
Installation ID: <Installation ID>
Push token (Apple Push Production): <push token>
```

Based on your *Provisioning Profile*, the token shown in the console will be **Development** *("Sandbox/Development")* or **Production** *("Production")*.

If you're not running your Flutter application using Xcode, you can find the logs in macOS' Console app. Filter using the `com.batch.ios` subsystem.

![macOS Console filtering](/files/ojgn04wOlIUI1pIYSG0q)

{% hint style="info" %}
Flutter will show Batch's logs in your IDE, but might miss early logs (such as the Installation ID).
{% endhint %}

#### 2. Obtaining Your Device Token on Android

You can find your device's token using the [debug tool](https://doc.batch.com/guides-and-best-practices/profiles/how-to-see-the-data-attached-to-your-install-or-custom-user-id) or locating the token Batch posts to the logcat *(*[*see here*](https://developer.android.com/tools/debugging/debugging-studio) *to know more)*:

```
Batch   : Installation ID: <Installation ID>
Batch.Push: Registration ID/Push Token (FCM): <your device token>
```

#### 3. Sending A Test Push

You can send test notifications to your device with a push token. In the push notification creation form, click the ⚙️ and copy your push token in the corresponding field. Hit "Send a test".

![Test push](/files/3dM5GdwqahOxWwnsVJLY)

#### What's next

*Congratulations on finishing the integration of Batch Push!*

Here are a couple of extra steps you can take before releasing your app:

* **Small icon / Accent color**: Make sure the small icon you are using is opaque white. We also recommend you use an accent color. You will find more information [here](/developer/sdk/android/advanced/customizing-notifications.md).
* **Analytics**: Add an [event dispatcher](/developer/sdk/flutter/advanced/event-dispatchers.md) to automatically track your campaigns in your third-party analytics tool.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://doc.batch.com/developer/sdk/flutter/sdk-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
