# Flutter Android >[!IMPORTANT] >[Flutter Obfuscation issue](https://github.com/pendo-io/pendo-mobile-sdk/issues/196#issue-2605284796)

>Migration from the track-event solution to the low-code solution: > 1. Refer to [Step 2](#step-2-pendo-sdk-integration) in the installation guide, and verify the addition of the navigationObserver and clickListener. > 2. The migration process will take up to 24 hours to complete and be reflected in Pendo, during the processing time, you will not be able to tag Pages and Features. >[!IMPORTANT] >Requirements: >- Flutter: ">=3.16.0" >- SDK: ">=3.2.0 < 4.0.0" >- Android Gradle Plugin `8.0` or higher >- Kotlin version `1.9.0` or higher >- JAVA version `11` or higher >- minSdkVersion `21` or higher >- compileSDKVersion `35` or higher > >Supported Navigation Libraries: > >- GoRouter 13.0 or higher >- AutoRoute 7.0 or higher ## Step 1. Install Pendo SDK 1. In the **application folder**, run the following command: ```shell flutter pub add pendo_sdk ``` 2. In the application **android/build.gradle** file: - **Add the Pendo Repository to the repositories section under the allprojects section or to the settings.gradle if using dependencyResolutionManagement:** ```java allprojects { repositories { maven { url = uri("https://software.mobile.pendo.io/artifactory/androidx-release") } mavenCentral() } ``` - Minimum SDK Version: If applicable, set your app to be **minSdkVersion 21** or higher: ```java android { minSdkVersion 21 } ``` 3. In the application **AndroidManifest.xml** file: Add the following `` to the manifest in the `` tag: ```xml ``` 4. Using ProGuard / R8 - If you are using **ProGuard**, the rules that need to be added to ProGuard can be found here: [pendo-proguard.cfg](/android/pnddocs/pendo-proguard.cfg). - If you are using **ProGuard(D8/DX only)** to perform compile-time code optimization, and have `{Android SDK Location}/tools/proguard/proguard-android-optimize.txt`, add `!code/allocation/variable` to the `-optimizations` line in your `app/proguard-rules.pro` file. The optimizations line should look like this: `-optimizations *other optimizations*,!code/allocation/variable` ## Step 2. Integrate with the Pendo SDK >[!NOTE] >Find your API key in the Pendo UI under `Settings` > `Subscription settings` > select an app > `App Details`. 1. For optimal integration place the following code at the beginning of your app's execution: ```dart import 'package:pendo_sdk/pendo_sdk.dart'; var pendoKey = 'YOUR_API_KEY_HERE'; await PendoSDK.setup(pendoKey); ``` 2. Initialize Pendo where your visitor is being identified (e.g., login, register, etc.). ```dart import 'package:pendo_sdk/pendo_sdk.dart'; final String visitorId = 'VISITOR-UNIQUE-ID'; final String accountId = 'ACCOUNT-UNIQUE-ID'; final Map visitorData = {'Age': '25', 'Country': 'USA'}; final Map accountData = {'Tier': '1', 'Size': 'Enterprise'}; await PendoSDK.startSession(visitorId, accountId, visitorData, accountData); ``` **Notes:** **visitorId**: a user identifier (e.g., John Smith) **visitorData**: the user metadata (e.g., email, phone, country, etc.) **accountId**: an affiliation of the user to a specific company or group (e.g., Acme inc.) **accountData**: the account metadata (e.g., tier, level, ARR, etc.) >[!TIP] >To begin a session for an anonymous visitor, pass ```null``` or an empty string ```''``` as the Visitor ID. You can call the `startSession` API more than once and transition from an anonymous session to an identified session (or even switch between multiple identified sessions). 3. Add Navigation Observers
When using `Flutter Navigator API` add PendoNavigationObserver for each app Navigator: ```dart import 'package:pendo_sdk/pendo_sdk.dart'; // Observes the MaterialApp/CupertinoApp main Navigator return MaterialApp( ... navigatorObservers: [ PendoNavigationObserver() ],); // Observes the nested widget Navigator return Navigator( ... observers: [ PendoNavigationObserver() ],); ``` > [!TIP] > The Pendo SDK uses the `Route` name to uniquely identify each `Route`. Pendo highly recommends that you give a unique name to each route in the `RouteSettings`. The unique names must also be applied to the `showModalBottomSheet` api. **Navigation Types:**
* **_GoRouter_** When using `GoRouter`, change the `setup` API call to include the correct navigation library, like so: ```dart PendoSDK.setup(pendoKey, navigationLibrary: NavigationLibrary.GoRouter); ``` When using `GoRouter`, apply the `addPendoListenerToDelegate()` to your `GoRouter` instance.
Make sure to add it once (e.g., adding it in the build method will be less desired)
```dart import 'package:pendo_sdk/pendo_sdk.dart'; final GoRouter _router = GoRouter()..addPendoListenerToDelegate() class _AppState extends State { @override Widget build(BuildContext context) { return PendoActionListener( child: MaterialApp.router( routerConfig: _router, ), ); } } ``` > [!TIP] > Pendo SDK uses routerDelegate listener to track route change analytics, make sure your route is included in the GoRouter routes * **_AutoRoute_** When using `AutoRoute`, change the `setup` API call to include the correct navigation library, like so: ```dart PendoSDK.setup(pendoKey, navigationLibrary: NavigationLibrary.AutoRoute); ``` When using `AutoRoute`, apply the `addPendoListenerToDelegate()` to your `AutoRoute.config()` instance.
Make sure to add it once (e.g., adding it in the build method will be less desired)
```dart import 'package:pendo_sdk/pendo_sdk.dart'; @AutoRouterConfig() class AppRouter extends RootStackRouter { @override List get routes => []; } final AppRouter _router = AppRouter()..config().addPendoListenerToDelegate(); class _AppState extends State { @override Widget build(BuildContext context) { return PendoActionListener( child: MaterialApp.router( routerConfig: _router.config(), ), ); } } ``` > [!TIP] > Pendo SDK uses routerDelegate listener to track route change analytics, make sure your route is included in the AutoRoute routes. 4. Add a click listener
Wrap the main widget with a PendoActionListener in the root of the project: ```dart import 'package:pendo_sdk/pendo_sdk.dart'; Widget build(BuildContext context) { return PendoActionListener( // Use the PendoActionListener to track action clicks child: MaterialApp( title: 'Title', home: Provider( create: (context) => MyHomePageStore()..initList(), child: MyHomePage(title: Strings.appName), ), navigatorObservers: [PendoNavigationObserver()], // Use Pendo Observer to track the Navigator stack transitions ); ) } ``` >[!TIP] >You can use track events to programmatically notify Pendo of custom events of interest: ```dart import 'package:pendo_sdk/pendo_sdk.dart'; await PendoSDK.track('name', { 'firstProperty': 'firstPropertyValue', 'secondProperty': 'secondPropertyValue'}); ``` ## Step 3. Mobile device connectivity for testing >[!NOTE] >Find your scheme ID in the Pendo UI under `Settings` > `Subscription settings` > select an app > `App Details`. This step enables guide testing capabilities. Add the following **activity** to the application **AndroidManifest.xml** in the `` tag: ```xml ``` ## Step 4. Verify installation 1. Test using Android Studio: Run the app while attached to the Android Studio. Review the Android Studio logcat and look for the following message: `Pendo SDK was successfully integrated and connected to the server.` 2. In the Pendo UI, go to `Settings` > `Subscription Settings`. 3. Select your application from the list. 4. Select the `Install Settings tab` and follow the instructions under `Verify Your Installation` to ensure you have successfully integrated the Pendo SDK. 5. Confirm that you can see your app as `Integrated` under subscription settings. ## Using custom navigation widgets `With the release of version 3.6.2 custom navigation widget support was added.` To integrate custom navigation widgets (e.g., TabBar, BottomNavigationBar, PageView), follow these steps: 1. Implement `PendoCustomNavigationWidget` in your `StatefulWidget` class. 2. Implement `PendoNavigationState` in the corresponding state class. 3. Override `getPendoCustomNavigationInfo()` to provide details about the current navigation state. Example: ```dart class CUSTOM_STATEFULL_WIDGET extends StatefulWidget implements PendoCustomNavigationWidget { // Added for Pendo Support ... } class _CUSTOM_STATEFULL_WIDGET_STATE extends State implements PendoNavigationState { // Added for Pendo Support // Override this method to let Pendo get the info about the current selected state @override List getPendoCustomNavigationInfo() { List info = []; info.add(PendoCustomNavigationInfo( navigationWidgetType: PendoNavigationWidgetType.Top, // specifies widget location on the screen. this must be provided currentSelectedIndex: 1, // current selected index, optional numberOfIndexes: 5, // total number of indexes, optional currentSelectedTitle: 'first item', // unique title, optional selectedIconCode: 1234)); // unique number representing the image on the selected item, optional info.add(PendoCustomNavigationInfo( navigationWidgetType: PendoNavigationWidgetType.Middle, currentSelectedIndex: 2, numberOfIndexes: 3, currentSelectedTitle: 'second item', selectedIconCode: 2468)); info.add(PendoCustomNavigationInfo( navigationWidgetType: PendoNavigationWidgetType.Bottom, currentSelectedIndex: 3, numberOfIndexes: 6, currentSelectedTitle: 'third item', selectedIconCode: 1357)); return info; } } ``` ## Limitations - [Notes, Known Issues & Limitations](/other/flutter-notes-known-issues-limitations.md). - To support hybrid mode in Flutter, please open a ticket. ## Developer documentation - API documentation available [here](/api-documentation/flutter-apis.md). - See [Native application with Flutter components](/other/native-with-flutter-components.md) integration instructions. ## Troubleshooting - For technical issues, please [review open issues](https://github.com/pendo-io/pendo-mobile-sdk/issues) or [submit a new issue](https://github.com/pendo-io/pendo-mobile-sdk/issues). - See our [release notes](https://developers.pendo.io/category/mobile-sdk/). - For additional documentation, visit our [Help Center](https://support.pendo.io/hc/en-us/categories/23324531103771-Mobile-implementation).