# Flutter

## Things to keep handy before starting your integration with Apxor

Please have the following handy before beginning the integration:

* **Application identifier** generated on the Apxor dashboard for your app\
  \
  ([Read more on how to fetch the application identifier from Apxor dashboard](https://guides.apxor.com/getting-started-with-apxor/adding-a-new-app))
* **App Bundle Id :** Every app has a unique application ID that looks like `com.example.myapp`. This id uniquely identifies the app on the device and also on the app store.\
  \
  [(Know more about bundle ids here)](https://developer.android.com/studio/build/configure-app-module)
* **The list of events** to setup triggers and track goals, user properties that allows to personalize messages and to target better.\
  \
  ([Read more on how you can setup here](https://guides.apxor.com/getting-started-with-apxor/api-guides/flutter))

## Getting Started

{% hint style="info" %}
**Prerequisites**

Flutter SDK supported version is >= 3.0.1.
{% endhint %}

### Set TAGs for Widgets

In order to display actions on Widgets, you can set tags for widgets using `ValueKey` with `String` as a value to it. It is highly recommended to set TAGs for Widgets which are Scrollable or contains multiple child widgets.

```dart
return TextButton(
  child: const Text('Sign In'),
  key: const ValueKey("Sign-in"), // Add ValueKey with String
  onPressed: () {
    // Sign in
  },
);
```

## Flutter Integration

### Step 1: Add Apxor SDK

Add `apxor_flutter` dependency in `pubspec.yaml`

```yaml
dependencies:
  apxor_flutter:
    git: https://github.com/apxor/apxor-flutter-sdk.git
```

### Step 2: Wrap Main Widget with Apxor Wrapper

```javascript
import 'package:apxor_flutter/apxor.dart';
import 'package:apxor_flutter/observer.dart';
@override
  Widget build(BuildContext context) {
	return ApxorFlutter.createWidget(MaterialApp(
              	…
        ),
);
}
```

### Step 3: Tracking Screens

<details>

<summary>If you are using Navigator in your Application</summary>

<pre class="language-javascript"><code class="lang-javascript">return Navigator(
      observers: [ApxNavigationObserver()],
<strong>      …
</strong>      );

</code></pre>

</details>

<details>

<summary>You are not using Navigator in your Application</summary>

add ApxNavigationObserver wherever routes are defined

```javascript
@override
  Widget build(BuildContext context) {
    return ApxorFlutter.createWidget(
      MaterialApp(
        navigatorObservers: [ApxNavigationObserver()],
	  routes: {
		…
		}
	  …
	),
    )
 }
```

</details>

#### **Passing Context for screen**

To avoid getting the elements from previous screens add the following in build method

```javascript
Widget build(BuildContext context) {
    ApxorFlutter.setContext("{Enter you route name here}", context);
}
```

### Step 4: Handle deeplink redirection

Use `setDeeplinkListener` to listen on deeplink redirection from Apxor SDK and handle redirection logic (including external redirection) within application logic as follows

```dart
ApxorFlutter.setDeeplinkListener((url) {
  // interpret the URL and handle redirection within the application
  _routeState.go(url!);

  // Or, to an external URL which will be opened in Browser
});
```

## Android Integration

### Step 0: Add Apxor Repository

Add Maven URL in project level `build.gradle` file.

**`Path: <project>/android/build.gradle`**:

```java

allprojects {
    repositories {
        // ...
        maven {
           url "https://repo.apxor.com/artifactory/list/libs-release-android/"
        }
        // ...
    }
}
```

### Step 1: Add Dependencies to your build.gradle file

**`Path: <project>/android/app/build.gradle`**:

```groovy
dependencies {
//...

    // Event tracking and a must-have dependency for other plugins
    implementation 'com.apxor.androidx:apxor-android-sdk-core:3.2.4@aar'


    // Add these for Realtime Actions and Surveys
    implementation 'com.apxor.androidx:apxor-android-sdk-qe:1.8.8@aar'
    implementation 'com.apxor.androidx:apxor-android-sdk-rtm:2.7.1@aar'
    implementation 'com.apxor.androidx:surveys:2.3.0@aar'


    // Helper plugin to create walkthroughs
    implementation 'com.apxor.androidx:wysiwyg:1.6.5@aar'
    
    // Add the below two dependencies to establish an SSE connection for WYSIWYG
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'com.launchdarkly:okhttp-eventsource:2.5.0'
    
//...
}
```

### Step 2: Plugins Integration

Create `plugins.json` file in `assets` folder.&#x20;

**`Path: android/app/src/main/assets/plugins.json`**

```json
{
  "plugins": [
    {
      "name": "rtm",
      "class": "com.apxor.androidsdk.plugins.realtimeui.ApxorRealtimeUIPlugin"
    },
    {
      "name": "push-v2",
      "class": "com.apxor.androidsdk.plugins.push.v2.PushPlugin"
    },
    {
      "name": "wysiwyg",
      "class": "com.apxor.androidsdk.plugins.wysiwyg.WYSIWYGPlugin"
    },
    {
      "name": "surveys",
      "class": "com.apxor.androidsdk.plugins.survey.SurveyPlugin"
    },
  ]
}
```

### Step 3: Initialize ApxorSDK

Add `meta-data` tag in `AndroidManifest.xml` file with your unique `APP_ID` as a value. You need to replace `YOUR_APP_ID` with your actual App Id. [Click here](https://guides.apxor.com/adding-a-new-app#step-5-copy-the-application-identifier) to know how to get app-id.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.apxor.flutter_example">
  <application ...>
      <meta-data android:name="APXOR_APP_ID" android:value="YOUR_APP_ID" />
    </application>
</manifest>
```

### Step 4: Add Proguard Rules

{% hint style="info" %}
**Note**

This is a mandatory step
{% endhint %}

If you do not have a `proguard-rules.pro` file in android folder then create one and configure the below rules in that `proguard-rules.pro` file. If you already have a `proguard-rules.pro` file in android folder then just configure the below rules in the existing file.

```java
-keep class com.apxor.** { *; }
-dontwarn com.apxor.**
```

Add the following in **`<project>/android/app/build.gradle`**

```gradle
buildTypes {
       release {
           signingConfig signingConfigs.release
           proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
       }
   }
```

### Step 5: Add exoplayer in your app (optional) <a href="#step-4-add-exoplayer-in-your-app-optional" id="step-4-add-exoplayer-in-your-app-optional"></a>

Exoplayer enables to configure Picture In Picture videos from Apxor dashboard and typically increases the app size by \~1Mb, if you are already using exoplayer in your app this step is not needed else add the following dependency in the application `build.gradle` file

**`Path: <project>/<app-module>/build.gradle`**:

<details>

<summary>com.apxor.androidx:apxor-android-sdk-rtm:2.3.6@aar version onwards</summary>

Copy

```
dependendies {
  //... 

  implementation 'androidx.media3:media3-exoplayer:1.1.1'
  implementation 'androidx.media3:media3-ui:1.1.1'


  //...
  }
```

</details>

<details>

<summary>com.apxor.androidx:apxor-android-sdk-rtm:2.3.5@aar and below</summary>

Copy

```
dependendies {
  //... 

  implementation 'com.google.android.exoplayer:exoplayer:2.14.0'

  //...
  }
```

</details>

<figure><img src="https://guides.apxor.com/~gitbook/image?url=https:%2F%2F300211688-files.gitbook.io%2F%7E%2Ffiles%2Fv0%2Fb%2Fgitbook-x-prod.appspot.com%2Fo%2Fspaces%252FQuYbJ9bg7CFtrBaVp9pB%252Fuploads%252FFVZvw6QsR1eWvpNnhqyP%252FInappVideo.png%3Falt=media%26token=43091ace-c788-43de-a3d1-a49f2b23523a&#x26;width=768&#x26;dpr=4&#x26;quality=100&#x26;sign=57b0a967195f1a2b6905d436f5d76ca5d2605d92cb8fc05e6fb18a243a76d660" alt=""><figcaption></figcaption></figure>

### Step 6: Disable Dexing Artifact Transformation \[optional]

This step is needed only if you use Apxor's Video InApp messages.

{% hint style="info" %}
**Note**

In the Android Gradle Plugin 3.5.0, we desugar & dex using Gradle artifact tranforms, which allow more parallelism and caching. This mechanism relies on libraries having the correct Maven information, because we use dependencies specified in POM files to set up the desugaring classpath. In cases we are unable to see all dependencies when desugaring a class it is required to disable parallel transformation to faciliate the process by adding the property as mentioned below.
{% endhint %}

Add the following in gradle.properties

**`Path: <project>/<app-module>/gradle.properties`**:

```java
android.enableDexingArtifactTransform = false
```

### Step 7: Ensuring ApxorSDK is initialised successfully

We have to verify for two things as follows :

**SDK Initialisation**

On running your android project lookout for the following log in logcat :

```java
ApxorSDK(v2**) successfully initialized for: APP_ID
```

<figure><img src="https://300211688-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQuYbJ9bg7CFtrBaVp9pB%2Fuploads%2FgTGeJikVUGsZAINqSkPV%2FSDKInitialisation.gif?alt=media&#x26;token=35ce4c10-dea5-4623-bb81-d89ee6002801" alt=""><figcaption></figcaption></figure>

**Plugin Initialisation**

By default, only error logs are enabled. To see debug logs for plugin initialisation and to confirm tracking event triggers, user properties. Please run the below command in terminal

```java
adb shell setprop log.tag.Apxor VERBOSE
```

<figure><img src="https://300211688-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQuYbJ9bg7CFtrBaVp9pB%2Fuploads%2F3KZ8EKIIV6NpmkWEwWVb%2FPluginInitialisation.gif?alt=media&#x26;token=5d98613c-6569-4e35-811f-35d6b557fb1e" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Apxor uploads data only when the app is minimized to the background. If you are running from Android Studio (emulators or devices), do not stop the app, just press on the "home" button in order for data to be uploaded.
{% endhint %}

### Step 8: Log data to set up triggers and measure goals

Now as we are done with basic integration, we can go ahead to setup event triggers, capture data for targeting and to personalize messaging.

[Click here for guides](https://guides.apxor.com/getting-started-with-apxor/api-guides/flutter) to log user properties, events and event properties.

## iOS Integration

### Step 1: Auto initialize SDK

To Auto initialize SDK (Recommended), add the following inside your application plist file.

Open your application's Info.plist as source code.Open Plist as Source Code

<figure><img src="https://300211688-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQuYbJ9bg7CFtrBaVp9pB%2Fuploads%2FGe4QC4GoIm6EL7U1kQ4X%2Finfo-plist.png?alt=media&#x26;token=acb558d4-5106-4a0b-809b-b0b9bb750d7f" alt=""><figcaption></figcaption></figure>

Copy paste the below piece of code, to create an entry for ApxorSDK.

```json
<key>Apxor</key>
<dict>
    <key>Core</key>
    <string>YOUR_APP_ID</string>
    <key>APXSurveyPlugin</key>
    <true/>
    <key>APXRTAPlugin</key>
    <true/>
    <key>APXPushPlugin</key>
    <true/>
    <key>APXWYSIWYGPlugin</key>
    <true/>
</dict>
```

{% hint style="info" %}
**Note**

* If you are unable to find our plugins in your pods after flutter run, then do<mark style="background-color:orange;">**`pod update`**</mark>
  {% endhint %}

### Step 2: Configuring Test Device

You need to configure your app to ensure there is a URL Scheme with your application's bundle identifier as the value.

If your app already has a URL Scheme with your application's bundle identifier as the value, you can skip this step.

#### Configuring URL Scheme

To configure URL scheme:

1. go to your project settings
2. select Targets
3. Click on the Info tab
4. Select the URL Types, and click on the + button to add a new URL Scheme
5. Add a new URL Scheme with your bundle identifier as the value

<figure><img src="https://300211688-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FQuYbJ9bg7CFtrBaVp9pB%2Fuploads%2Fyv6s59MsHEilVWT456JP%2FiOS-url-scheme.png?alt=media&#x26;token=8e1f2dac-ebdb-43d3-8306-aa1d6d2a37b2" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note**

Make sure the URL scheme has the value of your bundle identifier that was provided in the dashboard while registering with us. Also, the app must have the same bundle identifier.
{% endhint %}

### Step 3: Handling the deep link

Enable Apxor to handle Apxor specific deeplinks.

In your application's **AppDelegate** file, in the function application(\_:open:options:), add the following code at the beginning,

```objectivec
// ObjC
NSString *urlStr = url.absoluteString;
if ([urlStr containsString:@"add-test-device"]) {
  [ApxorSDK handleDeeplink:url];
}
```

```swift
// Swift
let urlStr = url.absoluteString
if (urlStr.contains("add-test-device")) {
    ApxorSDK.handleDeeplink(url)
}
```

### Step 4: Log data to set up triggers and measure goals

Now as we are done with basic integration, we can go ahead to setup event triggers, capture data for targeting and to personalize messaging.

[Click here for guides](https://guides.apxor.com/getting-started-with-apxor/api-guides/flutter) to log user properties, events and event properties.

### Embed Slot

{% hint style="info" %}
**Note**

For using Apxor Embedded Cards the versions of the following plugins should be greater than or equal the ones mentioned below

**Core: 2.10.26**

**RTA: 1.09.26**

**CE: 1.05.16**

**WYSIWYG: 1.02.67**
{% endhint %}

In all areas of the app where you may want to show an in-line widget, insert the following code

```
const ApxorEmbedWidget(valueKey: <Tag>)
```

Rename <mark style="color:blue;">\<Tag></mark> to any unique ID (any positive Integer). Ensure that you keep the ID unique across different IDs and across different ApxorEmbedWidget instances.

### Story Slot

{% hint style="info" %}
**Note**

For using Apxor Stories the versions of the following plugins should be greater than or equal the ones mentioned below

**Core: 2.10.26**

**RTA: 1.09.26**

**CE: 1.05.16**

**WYSIWYG: 1.02.67**
{% endhint %}

In all areas of the app where you may want to show stories, insert the following code

```
const ApxorStoryWidget(id: <ID>)
```

Replace <mark style="color:blue;">\<ID></mark> with any unique integer(any positive Integer). Ensure that you keep the ID unique across different ApxorStoryWidget instances.

## Web Integration

### Step 1: Add integration scripts and Initialize Apxor&#x20;

Add the following integration scripts to your **index.html** file in the **head tag**(project/web/index.html)

Add your <mark style="background-color:purple;">**site ID**</mark> and <mark style="background-color:purple;">**app version**</mark> in the code below&#x20;

```html
<!-- Start of Integrating APXOR Web SDK -->

<!-- Initializing Apxor Core -->
<script type="text/javascript" defer src="https://unpkg.com/apxor"></script>

<!-- Initializing Apxor QE -->
<script
  type="text/javascript"
  defer
  src="https://unpkg.com/apxor-qe"
> 
</script>
<!-- Initializing Apxor RTM -->
<script
  type="text/javascript"
  defer
  src="https://unpkg.com/apxor-rtm"
>
</script>

<!-- Initialization step -->
<script>
 
  const _d = new Date();
  (function (a, p, x, o, r) {
    Apxor = a.Apxor || { _q: [], _st: _d };
    [
      "init",
      "setUserId",
      "setUserProperties",
      "setSessionProperties",
      "logPageView",
      "logEvent",
      "logClientEvent",
      "setAppVersion",
      "getClientId",
      "getSessionId",
      "startNewSession",
      "endSession",
      "flattenJSON",
      "setRedirectionHandler",
      "setIsFlutter",
      "registerApxorFlutterHelper",
      "setWYSIWYGCookieForFlutter"
    ].forEach(function (m) {
      Apxor[m] = function () {
        this._q.push({ m: m, args: arguments });
      };
    });
   })(window, document, "script");
   
   Apxor.init(
      "YOUR_SITE_ID",
      {
        idle_time_out: 1800,
        plugins: ["ApxorRTM"],
        Version: <Your_App_Version>,
      },
      
      function success(data) {
        console.log("APXOR SDK Initialized");
      },
      function error() {
        console.log("APXOR SDK not initialized");
      });
      
</script>
```
