> ## Documentation Index
> Fetch the complete documentation index at: https://help.airbridge.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Android SDK (Deprecated)

![Maven metadata URL](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Fsdk-download.airbridge.io%2Fmaven%2Fio%2Fairbridge%2Fsdk-android%2Fmaven-metadata.xml\&versionPrefix=2\&label=Airbridge%20Android%20SDK)

## Install SDK

### Install Package

#### Install with Gradle

Add the following repository under the `allproject/repositores` block in your `project/build.gradle` file.

```groovy lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
allprojects {
    ...
    repositories {
        ...
        maven { url "https://sdk-download.airbridge.io/maven" }
        ...
    }
    ...
}
```

If you're using Android Studio Arctic Fox (2020.3.1) or a later version to create the project or [if the repository settings are set up within the settings.gradle file](https://developer.android.com/build/releases/gradle-plugin#settings-gradle), add the following code to the `project/settings.gradle` file under the `dependencyResolutionManagement/repositories` block.

```groovy lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
dependencyResolutionManagement {
    ...
    repositories {
        ...
        maven { url "https://sdk-download.airbridge.io/maven" }
        ...
    }
    ...
}
```

Add the following code to the `dependencies` block in your `app/build.gradle` file.

```groovy lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
dependencies {
    ...
    implementation "io.airbridge:sdk-android:2.+"
    ...
}
```

#### Install manually

The Airbridge SDK uses JetBrains' Kotlin and Coroutines libraries for enhanced stability and productivity.

If you install the SDK manually using an `.aar` file, add the following dependency libraries in your project.

| Library                    | Link                                                                                            |
| -------------------------- | ----------------------------------------------------------------------------------------------- |
| Airbridge SDK              | [Download](https://sdk-download.airbridge.io/maven/io/airbridge/sdk-android/index.html)         |
| JetBrains Java Annotations | [Download](https://mvnrepository.com/artifact/org.jetbrains/annotations)                        |
| Kotlin Standard Library    | [Download](https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib)               |
| Kotlinx Coroutines Core    | [Download](https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-core)    |
| Kotlinx Coroutines Android | [Download](https://mvnrepository.com/artifact/org.jetbrains.kotlinx/kotlinx-coroutines-android) |
| Play Services Appset       | [Download](https://mvnrepository.com/artifact/com.google.android.gms/play-services-appset)      |
| BillingClient              | [Download](https://mvnrepository.com/artifact/com.android.billingclient/billing/5.0.0)          |

<Info>
  **Note**

  Airbridge Android SDK requires Kotlin stdlib and Kotlinx coroutines library version 1.6 or later.
</Info>

<Note>
  Starting from Airbridge Android SDK version 2.24.2, the Play Services Appset library dependency for appSetId collection must be added.
</Note>

<Note>
  **Attention**

  Starting from Airbridge Android SDK version 2.26.1, the BillingClient library dependency for collecting In-App purchase details collection must be added.

  Please refer to the [BillingClient dependency](#billingclient-dependency) for troubleshooting
</Note>

### Set up project

[`Min SDK 16`](https://en.wikipedia.org/wiki/Android_Jelly_Bean)

#### Add permissions

Add the following permissions to your `AndroidManifest.xml` file.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
<manifest ...>
  ...
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  ...
</manifest>
```

#### Initialization

Add the following code under the `onCreate` method of the `Application` class file registered in the `AndroidManifest.xml` file.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  @Override
  public void onCreate() {
      super.onCreate();
      AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
          .build();
      Airbridge.init(this, config);
  }
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  override fun onCreate() {
      super.onCreate()
      val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
          .build()
      Airbridge.init(this, config)
  }
  ```
</CodeGroup>

<Danger>
  **Attention**

  To ensure initializeSDK works correctly, follow the conditions below.

  * Must be called in the `Application` class's `onCreate`.
  * Must be called on the `Main thread`.
</Danger>

The `YOUR_APP_NAME` and `YOUR_APP_SDK_TOKEN` can be found at **\[Settings]>\[Tokens]** in the Airbridge dashboard.

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/6CTRFgWYblklSTQJ/asset/image/app-sdk-token-settings.png?fit=max&auto=format&n=6CTRFgWYblklSTQJ&q=85&s=8ac768ed162169aa315cbd8e7255de92" alt="01-en-dev-android-sdk" width="1500" height="956" data-path="asset/image/app-sdk-token-settings.png" />
</Frame>

### SDK testing

After completing the Airbridge Android SDK setup, you can test whether it works properly by following the methods below.

#### Using the Airbridge Dashboard

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/6CTRFgWYblklSTQJ/asset/image/app-real-time-logs-sdk-events.png?fit=max&auto=format&n=6CTRFgWYblklSTQJ&q=85&s=8f2aeca7c1045a430c89eb8ca54acc2a" alt="02-en-dev-android-sdk" width="1500" height="956" data-path="asset/image/app-real-time-logs-sdk-events.png" />
</Frame>

1. Install and open the app on a test device.
2. Navigate to **\[Raw Data]>\[App Real-time Logs]** in the Airbridge dashboard.
3. Enter the [Google Advertising ID](https://developer.android.com/training/articles/ad-id) (GAID) of the test device into the search bar to find it in the logs.

It may take up to 5 minutes for the logs to be visible in the dashboard.

<Note>
  If you can't find the Install event in the Event Category column with the Google Advertising ID of the test device, check again whether the SDK is installed properly as instructed.
</Note>

<Note>
  The Google Advertising ID (GAID) of an Android device can be found at **\[Settings]>\[Google]>\[Ads]**.
</Note>

#### Using the LogCat

Use the following method if you want to use LogCat to see a more detailed log of the app.

<Danger>
  **Attention**

  As this method may expose user information, ensure it is only executed for cases of `Build.DEBUG`.
</Danger>

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default log level = Log.INFO
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setLogLevel(Log.DEBUG)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default log level = Log.INFO
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setLogLevel(Log.DEBUG)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/6CTRFgWYblklSTQJ/asset/image/android-sdk-logcat-event-requests.png?fit=max&auto=format&n=6CTRFgWYblklSTQJ&q=85&s=f6153310540c40859077afdf4d0c2ea8" alt="03-en-dev-android-sdk" width="1500" height="745" data-path="asset/image/android-sdk-logcat-event-requests.png" />
</Frame>

## Deep Linking

### Set up dashboard

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/JQTrije-Gw_sKnV9/asset/image/android-deep-link-settings.png?fit=max&auto=format&n=JQTrije-Gw_sKnV9&q=85&s=54b339d8ba0162352cdd57a73da140e1" alt="04-en-dev-android-sdk" width="1400" height="800" data-path="asset/image/android-deep-link-settings.png" />
</Frame>

The following information must be submitted to the **\[Tracking Link]>\[Deep Link]** page in the Airbridge dashboard.

* URI Scheme
* Package Name
* sha256\_cert\_fingerprints

#### Enter URI Scheme

Enter the Android URI scheme, including `://`, into the URI Scheme field. Only lowercase letters, numbers, `-`, and `+` are supported.

<Danger>
  **Attention**

  To redirect users as intended, submit the URI scheme differently for the production app and the development app.
</Danger>

#### Enter Package Name

The package name field of the production app that is already released on app stores will be automatically filled.

The package names field of the development app and production app that has not been released on app stores yet must be filled manually.

#### Enter Fingerprints

Follow the steps below to obtain the `sha256_cert_fingerprints`.

1. Prepare the `keystore` file that you used to register your app with the Google Play Store.
2. Execute the following command in the Terminal.

```bash Shell lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
keytool -list -v -keystore my-release-key.keystore
```

3. Copy the `SHA256` value under the `Certificate Fingerprints` section and paste it into the Android sha256\_cert\_fingerprints field in the Airbridge dashboard.

```bash Shell lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
Certificate fingerprints:
    MD5:  4C:65:04:52:F0:3F:F8:65:08:D3:71:86:FC:EF:C3:49
    SHA1: C8:BF:B7:B8:94:EA:5D:9D:38:59:FE:99:63:ED:47:B2:D9:5A:4E:CC
    SHA256: B5:EF:4D:F9:DC:95:E6:9B:F3:9A:5E:E9:D6:E0:D8:F6:7B:AB:79:C8:78:67:34:D9:A7:01:AB:6A:86:01:0E:99
```

<Note>
  Multiple `sha256_cert_fingerprints` can be entered by separating them with commas.
</Note>

### Set up project

#### Set up intent filter

If you are using the Airbridge Android SDK v2.21.1 or later, follow the steps below to set up the intent filter. If you are using the Airbridge Android SDK v2.21.0 or earlier, refer to this [section](/en/developers/deprecated-android-sdk-v2#deeplink-page) of this document.

1. Open the `AndroidManifest.xml` file.
2. Add the following `intent-filter` to the `activity` that will process deep links.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
<activity ...>
    ...
    <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="http" android:host="YOUR_APP_NAME.abr.ge" />
        <data android:scheme="https" android:host="YOUR_APP_NAME.abr.ge" />
    </intent-filter>
    <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="http" android:host="YOUR_APP_NAME.airbridge.io" />
        <data android:scheme="https" android:host="YOUR_APP_NAME.airbridge.io" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="YOUR_APP_URI_SCHEME" />
    </intent-filter>
    ...
</activity>
```

* `YOUR_APP_NAME.deeplink.page`: Airbridge [App Links](https://developer.android.com/training/app-links) Version 2
* `YOUR_APP_NAME.airbridge.io`: Airbridge [App Links](https://developer.android.com/training/app-links) Version 1
* `YOUR_APP_URI_SCHEME`: deep link using URI Scheme

#### Set up deep link callback

To process the deep link of the intent filter added to the `activity`, the following setup is required.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  @Override
  protected void onResume() {
      super.onResume();
      Airbridge.getDeeplink(getIntent(), new AirbridgeCallback<Uri>() {
          @Override
          public void onSuccess(Uri uri) {
              // Process deeplink data
          }

          @Override
          public void onFailure(Throwable throwable) {
              // Error
          }

          @Override
          public void onComplete() {
              // After process deeplink data
          }
      });
  }

  // The code below is required for proper deeplink processing
  @Override
  protected void onNewIntent(Intent intent) {
      super.onNewIntent(intent);
      setIntent(intent);
  }
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  override fun onResume() {
      super.onResume()
      Airbridge.getDeeplink(intent, object : AirbridgeCallback<Uri> {
          override fun onSuccess(uri: Uri) {
              // Process deeplink data
          }

          override fun onFailure(throwable: Throwable) {
              // Error
          }

          override fun onComplete() {
              // After process deeplink data
          }
      })
  }

  // The code below is required for proper deeplink processing
  override fun onNewIntent(intent: Intent?) {
      super.onNewIntent(intent)
      setIntent(intent)
  }
  ```
</CodeGroup>

#### Set up deferred deep link callback

To process a deferred deep link in the Airbridge SDK, the intent filter setup in the `AndroidManiest.xml` file automatically calls the corresponding `activity`. The process is the same as the deep link callback.

If you don't want the deferred deep link to automatically call the corresponding `activity` or want to handle a specific task with the information obtained through the deferred deep link, you can use the following method.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setOnDeferredDeeplinkReceiveListener(new OnDeferredDeeplinkReceiveListener() {
          @Override
          public boolean shouldLaunchReceivedDeferredDeeplink(Uri uri) {
              // If you want to open the target activity, please return true otherwise false
              // Default returning value = true
              return true;
          }
      })
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setOnDeferredDeeplinkReceiveListener(object : OnDeferredDeeplinkReceiveListener {
          override fun shouldLaunchReceivedDeferredDeeplink(uri: Uri): Boolean {
              // If you want to open the target activity, please return true otherwise false
              // Default returning value = true
              return true
          }
      })
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

### Deep link testing

Click on your URI scheme to test if your deep link has been properly set up in the Airbridge SDK.

* `YOUR_APP_URI_SCHEME://`

When the deep link setup is successful, you will see the Deeplink Open event on the **\[Raw Data]>\[App Real-time Log]** page in the Airbridge dashboard, like in the following image.

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/6CTRFgWYblklSTQJ/asset/image/app-real-time-logs-deep-link-event.png?fit=max&auto=format&n=6CTRFgWYblklSTQJ&q=85&s=dcdfd5780b41a7682b2d43975de94f25" alt="05-en-dev-android-sdk" width="1500" height="705" data-path="asset/image/app-real-time-logs-deep-link-event.png" />
</Frame>

### Set up Custom Domain

1. Please refer to the [user guide](/en/guides/custom-domain) and enter the custom domain in the dashboard.
2. Create the `res/values/airbridge.xml` file and add the custom domain as follows.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
    <string-array name="co_ab180_airbridge_custom_domains">
        <item>YOUR_APP_CUSTOM_DOMAIN</item>
    </string-array>
</resources>
```

3. Add the custom domain you configured earlier to the `Intent Filter` of the `Acitivty` that handles deep links, as shown below.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
<activity ...>
    ...
    <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="http" android:host="YOUR_APP_CUSTOM_DOMAIN" />
        <data android:scheme="https" android:host="YOUR_APP_CUSTOM_DOMAIN" />
    </intent-filter>
    ...
</activity>
```

<Danger>
  **Warning**

  The added domain should match the information listed on the Airbridge dashboard.
</Danger>

4. Complete your project setup by referring to the [Set up deep link callback](#set-up-deep-link-callback).

## User Data

### Set up user identifier

To measure ad performance across the web and app, Airbridge collects the following user identifiers.

* User Email: Email address
* User Phone: Phone number
* User ID: Unique User ID (The ID to identify a unique user must be the same in both web and mobile)
* User Alias: Identifiers that can represent users (e.g., loyalty program ID, integrated ID used across affiliate organizations, etc.)

<Note>
  The user email and phone number are automatically hashed (SHA256) when sent to servers.
</Note>

Follow the method below for the user identifier setup.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Automatically hashed on client side using SHA256
  // Can turn off hashing feature with special flag
  Airbridge.getCurrentUser().setEmail("testID@ab180.co");
  Airbridge.getCurrentUser().setPhone("821012341234");

  // Does not hash 
  Airbridge.getCurrentUser().setId("testID");
  Airbridge.getCurrentUser().setAlias("key", "value");

  // Clear user data
  Airbridge.expireUser()
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Automatically hashed on client side using SHA256
  // Can turn off hashing feature with special flag
  Airbridge.getCurrentUser().email = "testID@ab180.co"
  Airbridge.getCurrentUser().phone = "821012341234"

  // Does not hash 
  Airbridge.getCurrentUser().id = "testID"
  Airbridge.getCurrentUser().setAlias("key", "value")

  // Clear user data
  Airbridge.expireUser()
  ```
</CodeGroup>

| Identifier | Description       | Limitations                                                                                                                                                                                              |
| ---------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Email`    | User email        | Hashed by default<br />(SHA256, can be disabled)                                                                                                                                                         |
| `Phone`    | User phone number | Hashed by default<br />(SHA256, can be disabled)                                                                                                                                                         |
| `Id`       | User ID           | -                                                                                                                                                                                                        |
| `Alias`    | User alias        | - Maximum 10 aliases<br />- `"key"`type is string, maximum 128 characters supported<br />- `"key"`must satisfy `^[a-z_][a-z0-9_]*$`regex<br />-`"value"`type is string, maximum 128 characters supported |

Once the user identifier setup is complete, all events will be passed with the set identifier.

### Set up user attributes

Additional user attributes can be collected for a more accurate multi-touch attribution and in-depth data analysis.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.getCurrentUser().setAttribute("key", "value");
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.getCurrentUser().setAttribute("key", "value")
  ```
</CodeGroup>

| Name           | Description    | Limitations                                                                                                                                                                                                                                                                          |
| -------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `setAttribute` | User attribute | - Maximum 100 attributes supported<br />- "key" type is string, maximum 128 characters supported<br />- "key" must satisfy `^[a-z_][a-z0-9_]*$`regex<br />- "value" type is integer, float, long, boolean or string<br />- When "value" is string, Maximum 1024 characters supported |

### User data setup testing

The user information collected through the SDK can be found on the **\[Raw Data]>\[App Real-time Log]** page in the Airbridge dashboard.

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/6CTRFgWYblklSTQJ/asset/image/app-real-time-logs-user-details.png?fit=max&auto=format&n=6CTRFgWYblklSTQJ&q=85&s=4c1917b29aa2e20722f5aec384f9145c" alt="06-en-dev-android-sdk" width="1500" height="702" data-path="asset/image/app-real-time-logs-user-details.png" />
</Frame>

## Device Data

### Set up device alias

Setup the Airbridge SDK to collect device alias when collecting events. The alias won't be deleted even after the user closes the app unless the user deletes the app.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.setDeviceAlias("ADD_YOUR_KEY", "AND_YOUR_VALUE");
  Airbridge.removeDeviceAlias("DELETE_THIS_KEY");
  Airbridge.clearDeviceAlias();
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.setDeviceAlias("ADD_YOUR_KEY", "AND_YOUR_VALUE")
  Airbridge.removeDeviceAlias("DELETE_THIS_KEY")
  Airbridge.clearDeviceAlias()
  ```
</CodeGroup>

| Method                                       | Description                                                                                             |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `setDeviceAlias(key: String, value: String)` | Adds the key value pair to the device identifier.                                                       |
| `removeDeviceAlias(key: String)`             | Deletes the corresponding device alias. If there is no corresponding device alias, nothing is executed. |
| `clearDeviceAlias()`                         | Deletes all device aliases.                                                                             |

## In-app Events

All events called by the Airbridge SDK can be sent with the following field values.

| Name                 | Type                 | Description                           |
| -------------------- | -------------------- | ------------------------------------- |
| `EventCategory`      | String               | Name of the event<br />**\*Required** |
| `event_action`       | String               | Event attribute 1                     |
| `event_label`        | String               | Event attribute 2                     |
| `eventValue`         | Number               | Event attribute 3                     |
| `eventAttributes`    | Map\<String, Object> | Custom attributes                     |
| `semanticAttributes` | Map\<String, Object> | Semantic attributes                   |

### Send in-app events

You can use the following method to send events through the Airbridge SDK.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Number eventValue = 10;
  Map<String, Object> eventAttributes = new HashMap<String, Object>();
  SemanticAttributes semanticAttributes = new SemanticAttributes();
  semanticAttributes.put(SemanticAttributes.KEY_CURRENCY, "USD");
  Airbridge.trackEvent(StandardEventCategory.HOME_VIEW, "event_action", "event_label", eventValue, eventAttributes, semanticAttributes);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val eventValue = 10
  val eventAttributes = mutableMapOf<String, String>()
  val semanticAttributes = mutableMapOf<String, String>()
  semanticAttributes[SemanticAttributes.KEY_CURRENCY] = "USD"
  Airbridge.trackEvent(StandardEventCategory.HOME_VIEW, "event_action", "event_label", eventValue, eventAttributes, semanticAttributes)
  ```
</CodeGroup>

You can use the following method to send Custom Events other than the Airbridge Standard Events.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Number eventValue = 10;
  Map<String, String> eventAttributes = new HashMap<String, String>();
  Map<String, String> semanticAttributes = new HashMap<String, String>();
  semanticAttributes.put(SemanticAttributes.KEY_CURRENCY, "USD");
  Airbridge.trackEvent("event_category", "event_action", "event_label", eventValue, eventAttributes, semanticAttributes);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val eventValue = 10
  val eventAttributes = mutableMapOf<String, String>()
  val semanticAttributes = mutableMapOf<String, String>()
  semanticAttributes[SemanticAttributes.KEY_CURRENCY] = "USD"
  Airbridge.trackEvent("event_category", "event_action", "event_label", eventValue, eventAttributes, semanticAttributes)
  ```
</CodeGroup>

<Note>
  For more details about semantic attributes supported by the Airbridge SDK, refer to this [article](/en/guides/airbridge-event-elements#semantic-attributes).
</Note>

Alternatively, you can pre-define classes and use them to send Custom Events.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  class MyAppEvent extends Event {
      public MyAppEvent() {
          super("my_custom_category");
      }
  }
  ...
  Airbridge.trackEvent(new MyAppEvent());
  ...
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  class MyAppEvent : Event("my_custom_category")
  ...
  Airbridge.trackEvent(MyAppEvent())
  ...
  ```
</CodeGroup>

### Send Standard Events

#### Sign-up

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.getCurrentUser().setEmail("me@sample.com");
  Airbridge.getCurrentUser().setPhone("821012341234");
  Airbridge.getCurrentUser().setId("12345");
  Airbridge.getCurrentUser().setAlias("alias1", "value");
  Airbridge.getCurrentUser().setAttributes("attr1", 1234);
  Airbridge.trackEvent(StandardEventCategory.SIGN_UP);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.getCurrentUser().email = "testID@ab180.co"
  Airbridge.getCurrentUser().phone = "821012341234"
  Airbridge.getCurrentUser().id = "testID"
  Airbridge.getCurrentUser().setAlias("alias1", "value")
  Airbridge.getCurrentUser().setAttribute("attr1", 1234)
  Airbridge.trackEvent(StandardEventCategory.SIGN_UP)
  ```
</CodeGroup>

#### Sign-in

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.getCurrentUser().setEmail("me@sample.com");
  Airbridge.getCurrentUser().setPhone("821012341234");
  Airbridge.getCurrentUser().setId("12345");
  Airbridge.getCurrentUser().setAlias("alias1", "value");
  Airbridge.getCurrentUser().setAttributes("attr1", 1234);
  Airbridge.trackEvent(StandardEventCategory.SIGN_IN);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.getCurrentUser().email = "testID@ab180.co"
  Airbridge.getCurrentUser().phone = "821012341234"
  Airbridge.getCurrentUser().id = "testID"
  Airbridge.getCurrentUser().setAlias("alias1", "value")
  Airbridge.getCurrentUser().setAttribute("attr1", 1234)
  Airbridge.trackEvent(StandardEventCategory.SIGN_IN)
  ```
</CodeGroup>

#### **Sign-out**

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.trackEvent(StandardEventCategory.SIGN_OUT);
  Airbridge.expireUser();
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.trackEvent(StandardEventCategory.SIGN_OUT)
  Airbridge.expireUser()
  ```
</CodeGroup>

#### **View Home Screen**

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.trackEvent(StandardEventCategory.HOME_VIEW);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Airbridge.trackEvent(StandardEventCategory.HOME_VIEW)
  ```
</CodeGroup>

#### **View Search Results**

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  SemanticAttributes semanticAttributes = new SemanticAttributes();
  semanticAttributes.setQuery("Coca Cola");
  Airbridge.trackEvent(StandardEventCategory.SEARCH_RESULT_VIEW, null, null, null, null, semanticAttributes);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val semanticAttributes = SemanticAttributes()
  semanticAttributes.query = "Coca Cola"
  Airbridge.trackEvent(StandardEventCategory.SEARCH_RESULT_VIEW, null, null, null, null, semanticAttributes)
  ```
</CodeGroup>

#### **View Product List**

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Product fanta = new Product();
  fanta.setId("fanta_orange");
  fanta.setName("FANTA Orange");
  fanta.setQuantity(1);
  fanta.setCurrency("usd");
  fanta.setPrice(1.99);
  fanta.setPosition(0);

  Product cocacola = new Product();
  cocacola.setId("cocacola_low_sugar");
  cocacola.setName("Cocacola Low Sugar");
  cocacola.setQuantity(1);
  cocacola.setCurrency("usd");
  cocacola.setPrice(2.99);
  cocacola.setPosition(1);

  SemanticAttributes semanticAttributes = new SemanticAttributes();
  semanticAttributes.setProductListId("beverage_1");
  semanticAttributes.setCurrency("usd");
  semanticAttributes.setProducts(Arrays.asList(fanta, cocacola));
  Airbridge.trackEvent(StandardEventCategory.PRODUCT_LIST_VIEW, null, null, null, null, semanticAttributes);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val fanta = Product()
  fanta.id = "fanta_orange"
  fanta.name = "FANTA Orange"
  fanta.quantity = 1
  fanta.currency = "usd"
  fanta.price = 1.99
  fanta.position = 0

  val cocacola = Product()
  cocacola.id = "cocacola_low_sugar"
  cocacola.name = "Cocacola Low Sugar"
  cocacola.quantity = 1
  cocacola.currency = "usd"
  cocacola.price = 2.99
  cocacola.position = 1

  val semanticAttributes = SemanticAttributes()
  semanticAttributes.productListId = "beverage_1"
  semanticAttributes.currency = "usd"
  semanticAttributes.products = listOf(fanta, cocacola)
  Airbridge.trackEvent(
      category = StandardEventCategory.PRODUCT_LIST_VIEW,
      semanticAttributes = semanticAttributes
  )
  ```
</CodeGroup>

#### **View Product Details**

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Product fanta = new Product();
  fanta.setId("fanta_orange");
  fanta.setName("FANTA Orange");
  fanta.setQuantity(1);
  fanta.setCurrency("usd");
  fanta.setPrice(1.99);
  fanta.setPosition(0);

  Product cocacola = new Product();
  cocacola.setId("cocacola_low_sugar");
  cocacola.setName("Cocacola Low Sugar");
  cocacola.setQuantity(1);
  cocacola.setCurrency("usd");
  cocacola.setPrice(2.99);
  cocacola.setPosition(1);

  SemanticAttributes semanticAttributes = new SemanticAttributes();
  semanticAttributes.setCurrency("usd");
  semanticAttributes.setProducts(Arrays.asList(fanta, cocacola));
  Airbridge.trackEvent(StandardEventCategory.PRODUCT_DETAILS_VIEW, null, null, null, null, semanticAttributes);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val fanta = Product()
  fanta.id = "fanta_orange"
  fanta.name = "FANTA Orange"
  fanta.quantity = 1
  fanta.currency = "usd"
  fanta.price = 1.99
  fanta.position = 0

  val cocacola = Product()
  cocacola.id = "cocacola_low_sugar"
  cocacola.name = "Cocacola Low Sugar"
  cocacola.quantity = 1
  cocacola.currency = "usd"
  cocacola.price = 2.99
  cocacola.position = 1

  val semanticAttributes = SemanticAttributes()
  semanticAttributes.currency = "usd"
  semanticAttributes.products = listOf(fanta, cocacola)
  Airbridge.trackEvent(
      category = StandardEventCategory.PRODUCT_DETAILS_VIEW,
      semanticAttributes = semanticAttributes
  )
  ```
</CodeGroup>

#### **Add to Cart**

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Product fanta = new Product();
  fanta.setId("fanta_orange");
  fanta.setName("FANTA Orange");
  fanta.setQuantity(1);
  fanta.setCurrency("usd");
  fanta.setPrice(1.99);
  fanta.setPosition(0);

  Product cocacola = new Product();
  cocacola.setId("cocacola_low_sugar");
  cocacola.setName("Cocacola Low Sugar");
  cocacola.setQuantity(1);
  cocacola.setCurrency("usd");
  cocacola.setPrice(2.99);
  cocacola.setPosition(1);

  SemanticAttributes semanticAttributes = new SemanticAttributes();
  semanticAttributes.setCartId("cart_123");
  semanticAttributes.setProducts(Arrays.asList(fanta, cocacola));
  semanticAttributes.setCurrency("usd");

  Event event = new Event(StandardEventCategory.ADD_TO_CART);
  event.setValue(4.98);
  event.setSemanticAttributes(semanticAttributes);
  Airbridge.trackEvent(event);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val fanta = Product()
  fanta.id = "fanta_orange"
  fanta.name = "FANTA Orange"
  fanta.quantity = 1
  fanta.currency = "usd"
  fanta.price = 1.99
  fanta.position = 0

  val cocacola = Product()
  cocacola.id = "cocacola_low_sugar"
  cocacola.name = "Cocacola Low Sugar"
  cocacola.quantity = 1
  cocacola.currency = "usd"
  cocacola.price = 2.99
  cocacola.position = 1

  val event = Event(StandardEventCategory.ADD_TO_CART).apply {
      value = 4.98
      semanticAttributes = SemanticAttributes().apply {
          cartId = "cart_123"
          products = listOf(fanta, cocacola)
          currency = "usd"
      }
  }
  Airbridge.trackEvent(event)
  ```
</CodeGroup>

#### **Order Complete**

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  Product fanta = new Product();
  fanta.setId("fanta_orange");
  fanta.setName("FANTA Orange");
  fanta.setQuantity(1);
  fanta.setCurrency("usd");
  fanta.setPrice(1.99);
  fanta.setPosition(0);

  Product cocacola = new Product();
  cocacola.setId("cocacola_low_sugar");
  cocacola.setName("Cocacola Low Sugar");
  cocacola.setQuantity(1);
  cocacola.setCurrency("usd");
  cocacola.setPrice(2.99);
  cocacola.setPosition(1);

  SemanticAttributes semanticAttributes = new SemanticAttributes();
  semanticAttributes.setProducts(Arrays.asList(fanta, cocacola));
  semanticAttributes.setCurrency("usd");
  semanticAttributes.setInAppPurchased(true);

  Event event = new Event(StandardEventCategory.ORDER_COMPLETED);
  event.setValue(4.98);
  event.setSemanticAttributes(semanticAttributes);
  Airbridge.trackEvent(event);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val fanta = Product()
  fanta.id = "fanta_orange"
  fanta.name = "FANTA Orange"
  fanta.quantity = 1
  fanta.currency = "usd"
  fanta.price = 1.99
  fanta.position = 0

  val cocacola = Product()
  cocacola.id = "cocacola_low_sugar"
  cocacola.name = "Cocacola Low Sugar"
  cocacola.quantity = 1
  cocacola.currency = "usd"
  cocacola.price = 2.99
  cocacola.position = 1

  val event = Event(StandardEventCategory.ORDER_COMPLETED).apply {
      value = 4.98
      semanticAttributes = SemanticAttributes().apply {
          products = listOf(fanta, cocacola)
          currency = "usd"
          inAppPurchased = true
      }
  }
  Airbridge.trackEvent(event)
  ```
</CodeGroup>

### Event transmission testing

Send an event through the SDK and check whether the event is available in the Airbridge dashboard.

1. Send an event through the SDK.
2. Navigate to \[Raw Data]>\[App Real-time Logs] and search for the event.

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/6CTRFgWYblklSTQJ/asset/image/app-real-time-logs-event-list.png?fit=max&auto=format&n=6CTRFgWYblklSTQJ&q=85&s=4b82a73077ddc330be51a6fc826ddc09" alt="07-en-dev-android-sdk" width="1500" height="702" data-path="asset/image/app-real-time-logs-event-list.png" />
</Frame>

## Advanced Settings

### Install Restricted SDK

Depending on policies and environments, restrictions on collecting [device ID](/en/guides/identifiers)s like GAID and IDFA may be required. When installing the Restricted SDK version, the device IDs are not collected. The Restricted SDK is supported in v2.22.2 and later.

#### Install using Gradle

Add the following code within the `dependencies` block in the `app/build.gradle` file instead of the existing library.

```groovy lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
dependencies {
    ...
    implementation "io.airbridge:sdk-android-restricted:2.+"
    ...
}
```

#### Install manually

| Library                  | Link                                                                                               |
| ------------------------ | -------------------------------------------------------------------------------------------------- |
| Airbridge SDK restricted | [Download](https://sdk-download.airbridge.io/maven/io/airbridge/sdk-android-restricted/index.html) |

### Set up SDK Signature

With the SDK Signature, you can ensure SDK spoofing prevention and use verified events for ad performance measurement. Call the `setSDKSignatureSecret` function above the initialization code.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
          .setSDKSignatureSecret("YOUR_SDK_SIGNATURE_SECRET_ID", "YOUR_SDK_SIGNATURE_SECRET")
          .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setSDKSignatureSecret("YOUR_SDK_SIGNATURE_SECRET_ID", "YOUR_SDK_SIGNATURE_SECRET")
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

<Note>
  The SDK Signature Credentials are required for the SDK Signature setup. Refer to this [article](/en/guides/sdk-signature#configuring-the-sdk-signature-credentials) to learn how to create them.
</Note>

### Disable user identifier hashing

If you want to send user identifiers without hashing, use the following method to disable hashing.

<Danger>
  **Attention**

  Privacy measures must be in place as this option allows sensitive personal information, such as `User Email` and `User Phone`, to be accessed by third parties.
</Danger>

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default User Info Hash Enabled = true
  AirbridgeOption option = new AirbridgeOptionBuilder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setHashUserInformationEnabled(false)
      .build();
  Airbridge.initializeSDK(this, option);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default User Info Hash Enabled = true
  val option = AirbridgeOptionBuilder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setHashUserInformationEnabled(false)
      .build()
  Airbridge.initializeSDK(this, option)
  ```
</CodeGroup>

### Set up session timeout

You can use the following method to set the Airbridge SDK to not send an App Open event again if a user relaunches the app within a set session time.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Session Timeout = 5 minutes
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setSessionTimeoutSeconds(300)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Session Timeout = 5 minutes
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setSessionTimeoutSeconds(15)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

### Opt-in setup

The opt-in policy requires user consent before using user data.

Use the method below for collecting and transmitting data after obtaining consent for personal data tracking from users, especially when [GDPR](https://gdpr-info.eu/) or [CCPA](https://oag.ca.gov/privacy/ccpa) applies.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Auto Start Tracking Enabled = true
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setAutoStartTrackingEnabled(false)
      .build();
  Airbridge.init(this, config);

  ...

  // Set a variable like below
  if (properties.isGDPRAccepted) {
      Airbridge.startTracking();
  }
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Auto Start Tracking Enabled = true
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setAutoStartTrackingEnabled(false)
      .build()
  Airbridge.init(this, config)

  ...

  // Set a variable like below
  if (properties.isGDPRAccepted) {
      Airbridge.startTracking()
  }
  ```
</CodeGroup>

### Opt-out setup

<Note>
  **Attention**

  The instructions below are optional. Proceed only if necessary.
</Note>

The opt-out policy allows the use of user information until the user explicitly declines.

After setting the `setAutoStartTrackingEnabled` function to `true`, call the `stopTracking` function at a point where event data cannot be collected. From the moment the `stopTracking` function is called, the SDK will stop collecting events.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setAutoStartTrackingEnabled(true)
      .build();
  Airbridge.init(this, config);

  ...

  Airbridge.stopTracking();
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setAutoStartTrackingEnabled(true)
      .build()
  Airbridge.init(this, config)

  ...

  Airbridge.stopTracking()
  ```
</CodeGroup>

### Track Airbridge deep links only

It may be difficult to measure re-engagement if the Airbridge SDK collects all types of deep link events. The method below can be used to collect Airbridge deep link events only in the following cases:

* When the app is opened through an `airbridge.io` deep link
* When the app is opened through a `deeplink.page` deep link
* When the app is opened through an `abr.ge` deep link
* When the app is opened through a deep link with the [Custom Domain](/en/guides/custom-domain) that is set in the Airbridge dashboard
* When the app is opened through a deep link that contains the `airbridge_referrer` in the query

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Airbridge Link Only = false
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setTrackAirbridgeLinkOnly(true)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Airbridge Link Only = false
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setTrackAirbridgeLinkOnly(true)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

### Set up Meta deferred app links

Follow the steps below to use deferred deep linking in Meta ads. The Airbridge SDK collects the Meta deferred app links first above others. If there are no Meta deferred app links, Airbridge deferred deep links are collected.

Note that Meta ads' SKAN campaigns don't support Meta deferred app links. For more details, refer to the [Meta ads document](https://developers.facebook.com/docs/app-ads/deep-linking).

1. Add the following repository to the `project/build.gradle` file.

```groovy lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
allprojects {
    ...
    repositories {
        ...
        mavenCentral()
        ...
    }
    ...
}
```

2. Add the following code under the `dependencies` block of the `app/build.gradle` file.

```groovy lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
dependencies {
    ...
    implementation 'com.facebook.android:facebook-android-sdk:latest.release'
    ...
}
```

3. Add the following string in the `app/res/values/string.xml` file.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
...
<string name="facebook_app_id">FACEBOOK_APP_ID</string>
<string name="facebook_client_token">FACEBOOK_CLIENT_TOKEN</string>
...
```

4. Add the following `<meta-data>` under the `<application>` element in the `AndroidManifest.xml` file.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
...
<application android:label="@string/app_name" ...> 
    ...
    <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
    <meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>
    ...
</application>
...
```

5. Set the following option to `true`.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Facebook Deferred App Link Enabled = false
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setFacebookDeferredAppLinkEnabled(true)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Facebook Deferred App Link Enabled = false
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setFacebookDeferredAppLinkEnabled(true)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

### Set up Uninstall tracking

<Note>
  Uninstall tracking using Firebase Messaging is supported by the Airbridge Android SDK `v2.6.0` and later.
</Note>

Airbridge sends a silent push daily between 3:00 PM and 4:00 PM (UTC) to users whose app event has been collected at least once in the last 6 months to check for uninstalls. Uninstall events can be monitored through Airbridge reports and raw data export files.

Refer to the article below for the detailed setup instructions.

* [Uninstall Tracking](/en/developers/uninstall-tracking-deprecated-android-sdk-v2)

### Collect user location information

You can use the following method to collect the user location information through the Airbridge SDK.

<Danger>
  **Attention**

  The collection of location information should be for legitimate purposes, requiring caution in its use.
</Danger>

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
// Choose one
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
...
```

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Location Collection Enabled = false
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setLocationCollectionEnabled(true)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Location Collection Enabled = false
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setLocationCollectionEnabled(true)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

<Danger>
  **Attention**

  The Airbridge SDK collects the `LastKnownLocation` data. If the GPS information is not obtained, the value may not exist even if the corresponding permissions and settings are complete.
</Danger>

### Track installs by app stores

You can follow the methods below to track installs by different Android app stores, such as Google Play Store, One Store, Huawei Store, and Galaxy Store.

#### Using `AndroidManifest.xml`

Input the app store name (e.g., `playStore`, `oneStore`, `huaweiStore`, `galaxyStore`) for `andriod:value`.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
...
<application android:label="@string/app_name" ...> 
    ...
    <meta-data android:name="co.ab180.airbridge.app_market_identifier" android:value="playStore"/>
    ...
</application>
...
```

#### Using `AirbridgeConfig`

Input the app store name (e.g., `playStore`, `oneStore`, `huaweiStore`) for `setAppMarketIdentifier`.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setAppMarketIdentifier("playStore")
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setAppMarketIdentifier("playStore") // oneStore, huaweiStore ...
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

In the Actuals Report, select "Event Property" as a GroupBy to see the data by "App Market Identifier." Or you can go to the **\[App Raw Data]** menu and request raw data export by selecting "App Market Identifier" as Event Property to see the data in the export file.

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/0NLx_yaUdxu9z1c9/asset/image/app-real-time-logs-app-market-identifier.png?fit=max&auto=format&n=0NLx_yaUdxu9z1c9&q=85&s=0cb67883d56bb5f21d87150c603af31b" alt="08-en-dev-android-sdk" width="1474" height="548" data-path="asset/image/app-real-time-logs-app-market-identifier.png" />
</Frame>

<em>Installs by App Market Identifier</em>

### Collect error logs

When unintended errors occur in the internal operations of the SDK, the error log is sent to the Airbridge server to use the data for future improvements. If you want to disable this feature, you can use the method below to prevent sending the error logs to the Airbridge server.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Error Log Collection Enabled = true
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setErrorLogCollectionEnabled(false)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Error Log Collection Enabled = true
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setErrorLogCollectionEnabled(false)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

### Set up event buffer limit

When an event transmission failure occurs, the Airbridge SDK will store the event and retry at a later time. The following settings will allow you to limit the storage used for such events.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  int count = 10;
  long bytes = 1000000L;
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setEventMaximumBufferCount(count)
      .setEventMaximumBufferSize(bytes)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val count = 1_000
  val bytes = 1_000_000L
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setEventMaximumBufferCount(count)
      .setEventMaximumBufferSize(bytes)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

<Note>
  The storage size is slightly smaller than the actual data size due to metadata management and other factors.
</Note>

### Set up event transmission interval

Use the following method to set up event transmission intervals.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Event Transmit Interval = 0 millisecond
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setEventTransmitInterval(3000)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // Default Event Transmit Interval = 0 millisecond
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setEventTransmitInterval(3000)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

<Danger>
  **Attention**

  The `IllegalArgumentException` runtime error will occur if the `setEventTransmitInterval` is set to a negative number.
</Danger>

### Delete unprocessed events

Clear the device's internal database of unprocessed events that have not been sent to Airbridge.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setResetEventBufferEnabled(true)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setResetEventBufferEnabled(true)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

### Use tracking links within the app

<Danger>
  **Attention**

  When you set up the Airbridge Android SDK v2.18.0 or later to use tracking links within apps, every time a tracking link is used within the app, Deeplink Pageviews are aggregated, which are [Target Events](/en/guides/airbridge-attribution-model#target-events). The deep link performance may be affected when Deeplink Pageviews occur frequently right after Deeplink Opens.

  The attribution window for Deeplink Pageviews is set to 3 days by default. If you want to change the attribution window for Deeplink Pageviews, contact your Airbridge CSM. If you don't have a dedicated CSM, contact the [Airbridge Help Center](https://app.airbridge.io/supports).
</Danger>

You can use tracking links within the app. Note that custom domain tracking links with custom short IDs cannot don't function within the app. Use the method below to redirect users to specific in-app locations without sending them to an external browser.

```kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
Airbridge.click("https://abr.ge/~~~")
Airbridge.impression("https://abr.ge/~~~")
```

###### Click

When a user clicks on the tracking link within the app, the `Airbridge.click` function is called. A click event is collected, and the user is redirected to the configured app or web fallback path.

###### Impression

When a user engages with a tracking link within the app, the `Airbridge.click` function is called. An impression event is collected.

### Set up Meta Install Referrer collection

Meta Install Referrer (MIR) collection is supported by Airbridge Android SDK versions 2.22.3 or later. Follow the method below for the setup.

After the setup, you need to enter the decryption key into the Airbridge dashboard to view the decrypted Meta Install Referrer. Refer to this [user guide](/en/guides/meta-business-channel-integration#how-to-provide-the-app-id-and-the-decryption-key) to learn how to enter the decryption key.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setMetaInstallReferrer("YOUR_FACEBOOK_APP_ID")
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setMetaInstallReferrer("YOUR_FACEBOOK_APP_ID")
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

### Compliance with Google DMA

To comply with the Digital Markets Act (DMA), you must pass user consent data to Airbridge. For more information about the DMA and whether it applies to your service, see the [Airbridge user guide](/en/guides/supporting-the-updated-google-eu-user-consent-policy).

If you are in the European Economic Area (EEA), you must always pass User Response information to Airbridge.

1. Confirm whether the end user launched the app in the EEA. If the end user did launch the app in the EEA (`eea=1`), confirm whether the consent values have already been stored for the session. If there are consent values stored, continue to Step 3.

If the end user launched the app from outside the EEA, it is not necessary to collect user consent.

<Info>
  **Note**

  Airbridge cannot provide guidance on storing the user consent data and implementing the prompts. For assistance, consult legal professionals.
</Info>

2. If there are no consent values stored, proceed to obtain user consent, such as with a privacy prompt. You must collect the `adPersonalization` and `adUserData` values in this step.

<Accordion title="User consent data that must be passed to Airbridge SDK">
  | <span style={{ display: 'inline-block', minWidth: '80px' }}>Airbridge Field Name</span> | <span style={{ display: 'inline-block', minWidth: '80px' }}>Google Field Name</span> | <span style={{ display: 'inline-block', minWidth: '160px' }}>Description</span>                                                                          |
  | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `eea`<br />\<string>                                                                    | `eea`                                                                                | Data indicating whether the user location is within the EEA or not<br />- `0`: Non-EEA. DMA not applicable.<br />- `1`: EEA. DMA applicable.             |
  | `adPersonalization`<br />\<string>                                                      | `ad_personalization`                                                                 | Data indicating whether the user allowed data tracking for ad personalization<br />- `0`: User didn't allow tracking.<br />- `1`: User allowed tracking. |
  | `adUserData`<br />\<string>                                                             | `ad_user_data`                                                                       | Data indicating whether the user allowed data sharing with Google<br />- `0`: User didn't allow sharing.<br />- `1`: User allowed sharing.               |
</Accordion>

3. Initialize the Airbridge SDK and share the consent values with Airbridge before collecting the end user’s personal data.

<Danger>
  **Attention**

  Ensure to follow the instructions below.

  * Use the field names specified by Airbridge: `eea`, `adPersonalization`, `adUserData`
  * Input `0` or `1` following the consent data collected.
</Danger>

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // MainApplication.java
  @Override
  public void onCreate() {
      super.onCreate();
      // Initialize Airbridge SDK
      AirbridgeConfig config = new AirbridgeConfig.Builder("APP_NAME", "APP_TOKEN")
          // Make Airbridge SDK explicitly start tracking
          .setAutoStartTrackingEnabled(false)
          .build();
      Airbridge.init(this, config);
      
      // Set device alias into Airbridge SDK

      // Based on actual region
      Airbridge.setDeviceAlias("eea", "0" or "1");

      // Based on actual user consent
      Airbridge.setDeviceAlias("adPersonalization", "0" or "1");
      Airbridge.setDeviceAlias("adUserData", "0" or "1");

      // Explicitly start tracking
      Airbridge.startTracking();
  }
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  // MainApplication.kt
  override fun onCreate() {
      super.onCreate()
      // Initialize Airbridge SDK
      val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
          // Make Airbridge SDK explicitly start tracking
          .setAutoStartTrackingEnabled(false)
          .build()
      Airbridge.init(this, config)

      // Set device alias into Airbridge SDK
      // Based on actual region
      Airbridge.setDeviceAlias("eea", "0" or "1")

      // Based on actual user consent
      Airbridge.setDeviceAlias("adPersonalization", "0" or "1")
      Airbridge.setDeviceAlias("adUserData", "0" or "1")
      
      // Explicitly start tracking
      Airbridge.startTracking()
  ```
</CodeGroup>

### Set up attribution result callback

Follow the method below to get the attribution result data through the Airbridge SDK.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setOnAttributionResultReceiveListener(new OnAttributionResultReceiveListener() {
          @Override
          public void onAttributionResultReceived(@NonNull Map<String, String> result) {
              // Process attribution data
          }
      })
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setOnAttributionResultReceiveListener(object : OnAttributionResultReceiveListener {
          override fun onAttributionResultReceived(result: Map<String, String>) {
              // Process attribution data
          }
      })
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

The table below lists the data fields that will be retrieved through the callback.

| Field                      | Description                  |
| -------------------------- | ---------------------------- |
| attributedChannel          | Channel (String)             |
| attributedCampaign         | Campaign (String)            |
| attributedAdGroup          | Ad Group (String)            |
| attributedAdCreative       | Ad Creative (String)         |
| attributedContent          | Content (String)             |
| attributedTerm             | Keyword (String)             |
| attributedSubPublisher     | Sub Publisher (String)       |
| attributedSubSubPublisher1 | Sub-sub Publisher 1 (String) |
| attributedSubSubPublisher2 | Sub-sub Publisher 2 (String) |
| attributedSubSubPublisher3 | Sub-sub Publisher 3 (String) |

If an event is unattributed, meaning that there is no attribution result, you will get the following response.

```json lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
{
    "attributedChannel": "unattributed"
}
```

<Danger>
  **Guidelines for using attribution result data**

  ###### When the attribution data exists

  * Attribution data is forwarded within 40 seconds of SDK initialization.
  * If the app is closed and the attribution data cannot be received, the attribution data is forwarded within 40 seconds when the app is opened again.
  * On very rare occasions, it could take up to 5 minutes for the attribution data to be received.

  **When the attribution data does not exist**

  * The attribution data will be sent when the app is opened again after at least three hours have passed since the SDK was initialized.
  * Note that it is not recommended to use the attribution data for real-time processing.
</Danger>

### Deactivate Airbridge

All Airbridge functions can be turned off using the following method.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setSdkEnabled(false)
      .build();
  Airbridge.init(this, config);
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setSdkEnabled(false)
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

<Danger>
  **Attention**

  If `setResetEventBufferEnabled` is set to `true` and `setSdkEnabled` is set to `false`, the `setSdkEnabled` is prioritized and `setResetEventBufferEnabled` isn't processed.
</Danger>

## Hybrid App Setup

While basic events, such as Install, Open, Deeplink Open events can be automatically tracked by only installing the Android SDK in your hybrid app, in-app events, such as Sign-up, Purchase, etc., cannot be tracked as they are in-browser events that occur within a website of the WebView environment. Airbridge provides a simpler way to track in-app events by enabling the Android SDK to automatically pull all events from the Web SDK that is installed on the website of the WebView environment. This replaces the hassle of having to create bridge functions between native and WebView environments.

<Info>
  **Attention**

  Before proceeding with the hybrid app setup, install the [Android SDK](/en/developers/android-sdk-v4) and [Web SDK](/en/developers/web-sdk).
</Info>

### Sending events in WebView environments

* Reference - [Building Web Apps in WebView](https://developer.android.com/guide/webapps/webview)
* Reference - [Understanding Android WebView Javascript Interface ](https://stackoverflow.com/questions/36864811/understanding-android-webview-javascript-interface)

Call the `Airbridge::setJavascriptInterface` method in the target WebView as below.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  public class MainActivity extends Activity {
      
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);
          initWebView();
      }
      
      void initWebView() {
          webView = findViewById(R.id.webView);
          webView.getSettings().setJavaScriptEnabled(true);
          webView.getSettings().setDomStorageEnabled(true);

          Airbridge.setJavascriptInterface(webView, "YOUR_WEB_SDK_TOKEN");    
      
          webView.setWebChromeClient(new WebChromeClient());
          webView.setWebViewClient(new WebViewClient());
          webView.loadUrl("https://dev.blog.airbridge.io/websdk-web-app/");
      }
  }
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  class MainActivity : Activity() {
      
      override fun onCreate(savedInstanceState: Bundle) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)
          initWebView()
      }
      
      fun initWebView() {
          webView.settings.javaScriptEnabled = true
          webView.settings.domStorageEnabled = true
          
          Airbridge.setJavascriptInterface(webView, "YOUR_WEB_TOKEN")

          webView.webChromeClient = WebChromeClient()
          webView.webViewClient =  WebViewClient()
          webView.loadUrl("https://my_company.com/main")
      }
  }
  ```
</CodeGroup>

You can find the `YOUR_WEB_TOKEN` on the **\[Settings]>\[Tokens]** page in your Airbridge dashboard.

<Frame>
  <img src="https://mintcdn.com/airbridge-help-center/WgxACtbWtxE2BBF2/asset/image/web-sdk-token.png?fit=max&auto=format&n=WgxACtbWtxE2BBF2&q=85&s=b2f8bb4e8ba244d1497ce61351ae1dd5" alt="09-en-dev-android-sdk" width="1500" height="956" data-path="asset/image/web-sdk-token.png" />
</Frame>

Once the above setup is completed, initialize the Web SDK by following the [Web SDK guide](/en/developers/web-sdk).

### Handling Cases Where Tracking Links Open in WebView

* [Handling Cases Where Tracking Links Open in WebView](/en/developers/open-link-in-webview-deprecated-android-sdk-v2)

## Troubleshooting

### BillingClient Dependency

If you install the Airbridge SDK manually, you may encounter a compilation error due to a `BillingClient` dependency issue.

Starting from Airbridge SDK 2.26.1, a feature for collecting In-App purchase history has been added. To accommodate this, the SDK sets the In-App purchase library dependency as `compileOnly`, which does not cause issues during Gradle builds. However, when installed manually, a missing dependency may lead to compilation errors.

To resolve this issue, please refer to the following instructions.

```groovy lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
dependencies {
    api fileTree(dir: 'libs', include: ['billingClient.aar'])
}
```

### Ad ID permission

GAID is being collected as 00000000-0000-0000-0000-000000000000 even though LAT (Limited Ad Tracking) is deactivated.

1. Open the AndroidManifest.xml file.
2. Follow the method below to add the `com.google.android.gms.permission.AD_ID` permission.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
<manifest ...>
  ...
  <uses-permission android:name="com.google.android.gms.permission.AD_ID" />
  ...
</manifest>
```

For more details, refer to the [Google Play Services document](https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info#public-string-getid).

### Braze push notification

Deeplink Open events that occur through the push notifications generated by the Braze SDK are not collected by Airbridge. Instead, the App Open event is collected.

The Airbridge Android SDK uses the `dataString` in the `action` and `intent` of the `Activity` to distinguish between Deeplink Open events and App Open events.

When a user opens the app through a push notification using the Braze SDK, the app goes through an activity called `NotificationTrampolineActivity`. This activity handles push notifications, but the `dataString` is not included in its `action` and `intent`, preventing the SDK from determining if it's a Deeplink Open event or an App Open event.

The problem can be solved using the code snippet below for Airbridge Android SDK versions v2.21.5 and later.

<CodeGroup>
  ```java Java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setLifecycleIntegration(new AirbridgeLifecycleIntegration() {
      @Nullable
      @Override
      public String getDataString(@NotNull Activity activity) {
        if (activity.getClass().getName().equals("com.braze.push.NotificationTrampolineActivity")
            && activity.getIntent() != null
            && activity.getIntent().getExtras() != null) {
          return activity.getIntent().getExtras().getString("uri");
        }
        return null;
      }
    })
      .build();
  Airbridge.init(this, config)
  ```

  ```kotlin Kotlin lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
      .setLifecycleIntegration {
        it.takeIf { it.javaClass.name == "com.braze.push.NotificationTrampolineActivity" }
        ?.run { intent?.extras?.getString("uri") }
    }
      .build()
  Airbridge.init(this, config)
  ```
</CodeGroup>

### `deeplink.page`

Although the `deeplink.page` has been deprecated in the Airbridge Android SDK v.2.21.1, for Airbridge Android SDK v2.21.0 or earlier, you can set up the `intent-filter` by following the steps below.

1. Open the `AndroidManifest.xml` file.
2. Add the following `intent-filter` to the `activity` that will process deep links.

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
<activity ...>  
    ...  
    <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="http" android:host="YOUR_APP_NAME.deeplink.page" />
        <data android:scheme="https" android:host="YOUR_APP_NAME.deeplink.page" />
    </intent-filter>
    <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="http" android:host="YOUR_APP_NAME.airbridge.io" />
        <data android:scheme="https" android:host="YOUR_APP_NAME.airbridge.io" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="YOUR_APP_URI_SCHEME" />
    </intent-filter>
</activity>
```

### Dependencies

#### `java.lang.NoClassDefFoundError: kotlin/coroutines/AbstractCoroutineContextKey` Error

```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
<activity ...>  
    ...  
    <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="http" android:host="YOUR_APP_NAME.deeplink.page" />
        <data android:scheme="https" android:host="YOUR_APP_NAME.deeplink.page" />
    </intent-filter>
    <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="http" android:host="YOUR_APP_NAME.airbridge.io" />
        <data android:scheme="https" android:host="YOUR_APP_NAME.airbridge.io" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="YOUR_APP_URI_SCHEME" />
    </intent-filter>
</activity>
```

* Reference: [https://github.com/Kotlin/kotlinx.coroutines/issues/1879](https://github.com/Kotlin/kotlinx.coroutines/issues/1879)

According to [@qwwdfsad](https://github.com/Kotlin/kotlinx.coroutines/issues/1913#issuecomment-612916683), the use of kotlin-stdlib library v.1.3.70 and later is enforced when using kotlinx-coroutines-core library v1.3.5 and later.

Make sure that you use kotlin-stdlib library v1.3.70 and later if you're using kotlinx-coroutines-core library v.1.3.5 and later through the `gradlew dependencies` command.

### Auto Backup

* Reference - [https://developer.android.com/guide/topics/data/autobackup](https://developer.android.com/guide/topics/data/autobackup)

The Airbridge SDK's `AndroidManifest.xml` includes rules to opt out of backing up the Shared Preferences data. This is done to prevent keeping the same Airbridge settings during reinstallation, ensuring that new installations or reinstalls can be detected accurately.

To merge the Airbridge SDK backup rules with your app backup rules and prevent conflicts, refer to the following instructions.

Below are the opt-out rules defined in the Airbridge SDK.

<CodeGroup>
  ```xml Backup on Android 12 or later lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  <?xml version="1.0" encoding="utf-8"?>
  <data-extraction-rules>
      <cloud-backup>
          <exclude domain="sharedpref" path="airbridge-internal" />
          <exclude domain="sharedpref" path="airbridge-install" />
          <exclude domain="sharedpref" path="airbridge-user-info" />
          <exclude domain="sharedpref" path="airbridge-user-alias" />
          <exclude domain="sharedpref" path="airbridge-user-attributes" />
          <exclude domain="sharedpref" path="airbridge-device-alias" />
          <exclude domain="database" path="airbridge.db" />
      </cloud-backup>
      <device-transfer>
          <exclude domain="sharedpref" path="airbridge-internal" />
          <exclude domain="sharedpref" path="airbridge-install" />
          <exclude domain="sharedpref" path="airbridge-user-info" />
          <exclude domain="sharedpref" path="airbridge-user-alias" />
          <exclude domain="sharedpref" path="airbridge-user-attributes" />
          <exclude domain="sharedpref" path="airbridge-device-alias" />
          <exclude domain="database" path="airbridge.db" />
      </device-transfer>
  </data-extraction-rules>
  ```

  ```xml Backup on Android 11 and earlier lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
  <?xml version="1.0" encoding="utf-8"?>
  <full-backup-content>
      <exclude domain="sharedpref" path="airbridge-internal" />
      <exclude domain="sharedpref" path="airbridge-install" />
      <exclude domain="sharedpref" path="airbridge-user-info" />
      <exclude domain="sharedpref" path="airbridge-user-alias" />
      <exclude domain="sharedpref" path="airbridge-user-attributes" />
      <exclude domain="sharedpref" path="airbridge-device-alias" />
      <exclude domain="database" path="airbridge.db" />
  </full-backup-content>
  ```
</CodeGroup>

<AccordionGroup>
  <Accordion title="Fix confilict with fullBackupContent=&#x22;string&#x22;">
    If you add `android:fullBackupContent="string"` in the `AndroidManifest.xml`, you might get the following error:

    ```html Build Output lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    Manifest merger failed : Attribute application@fullBackupContent value=(string) from AndroidManifest.xml
    ```

    To fix this error, add `tools:replace="android:fullBackupContent"` in the `<application>` tag in the `AndroidManifest.xml` file.
  </Accordion>

  <Accordion title="Fix conflict with dataExtractionRules=&#x22;string resource&#x22;">
    If you add `android:dataExtractionRules="string resource"` in the `AndroidManifest.xml`, you might get the following error:

    ```html Build Output lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    Manifest merger failed : Attribute application@dataExtractionRules value=(string resource) from AndroidManifest.xml

    ```

    To fix this error, add `tools:replace="android:dataExtractionRules"` in the `<application>` tag in the `AndroidManifest.xml` file.
  </Accordion>

  <Accordion title="Fix conflict with allowBackup=&#x22;false&#x22;">
    If you add `android:allowBackup="false"` in the `AndroidManifest.xml`, you might get the following error:

    ```html Build Output lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    Manifest merger failed : Attribute application@allowBackup value=(false) from AndroidManifest.xml:32:9-36
        is also present at [:airbridge] AndroidManifest.xml:27:9-35 value=(true).
        Suggestion: add 'tools:replace="android:allowBackup"' to <application> element at AndroidManifest.xml:30:5-250:19 to override.
    ```

    To fix this error, add `tools:replace="android:allowBackup"` in the `<application>` tag in the `AndroidManifest.xml` file.
  </Accordion>

  <Accordion title="If compileSdkVersion is less than 31">
    Since the android:dataExtractionRules feature was added from API Level 31, you might get the following error if compileSdkVersion is less than 31:

    ```html Build Output lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    AndroidManifest.xml: AAPT: error: attribute android:dataExtractionRules not found.
    ```

    To fix this error, add `tools:remove="android:dataExtractionRules"` in the `<application>` tag in the `AndroidManifest.xml` file.
  </Accordion>
</AccordionGroup>

### Resolve Airbridge SDK backup rules merge conflict issue

If you are experiencing build errors caused by overlapping of the Airbridge SDK backup rules and third-party SDK backup rules, please refer to the workaround below.

e.g) If you have an Airbridge SDK backup rule and an Appsflyer SDK backup rule that overlap, you will see the build error below.

```html lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
Attribute application@fullBackupContent value=(@xml/appsflyer_backup_rules) from [com.appsflyer:af-android-sdk:6.6.1] AndroidManifest.xml:14:18-73
is also present at [io.airbridge:sdk-android:2.14.0] AndroidManifest.xml:27:18-78 value=(@xml/airbridge_auto_backup_rules).
Suggestion: add 'tools:replace="android:fullBackupContent"' to <application> element at AndroidManifest.xml:7:5-13:19 to override.
```

To resolve this issue, please set up as follows.

<AccordionGroup>
  <Accordion title="backup_rules.xml setup">
    1. Create a `src/main/res/xml` folder.
    2. Within the created xml folder, create a file (e.g. `custom_backup_rules.xml`).
    3. Add the data backup rules defined in the Airbridge SDK as follows.

    ```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    <?xml version="1.0" encoding="utf-8"?>
    <full-backup-content>
        <!-- Airbridge Backup Rules -->
        <exclude domain="sharedpref" path="airbridge-internal" />
        <exclude domain="sharedpref" path="airbridge-install" />
        <exclude domain="sharedpref" path="airbridge-user-info" />
        <exclude domain="sharedpref" path="airbridge-user-alias" />
        <exclude domain="sharedpref" path="airbridge-user-attributes" />
        <exclude domain="sharedpref" path="airbridge-device-alias" />
        <exclude domain="database" path="airbridge.db" />
      
        <!-- Appsflyer Backup Rules -->
        <exclude domain="sharedpref" path="appsflyer-data"/>

        <!-- Your Custom Backup Rules -->
    </full-backup-content>
    ```
  </Accordion>

  <Accordion title="data_extraction_rules.xml setup">
    <Info>
      **Note**

      The data\_extraction\_rules.xml setting is required for Airbridge Android SDK v2.27.1 and above.
    </Info>

    1. Within the created xml folder, create a file (e.g. `custom_data_extraction_rules.xml`).
    2. Add the data backup rules defined in the Airbridge SDK as follows.

    ```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    <?xml version="1.0" encoding="utf-8"?>
    <data-extraction-rules>
        <cloud-backup>
            <!-- Airbridge Backup Rules -->
            <exclude domain="sharedpref" path="airbridge-internal" />
            <exclude domain="sharedpref" path="airbridge-install" />
            <exclude domain="sharedpref" path="airbridge-user-info" />
            <exclude domain="sharedpref" path="airbridge-user-alias" />
            <exclude domain="sharedpref" path="airbridge-user-attributes" />
            <exclude domain="sharedpref" path="airbridge-device-alias" />
            <exclude domain="database" path="airbridge.db" />

            <!-- Appsflyer Backup Rules -->
            <exclude domain="sharedpref" path="appsflyer-data"/>

            <!-- Your Custom Backup Rules -->
        </cloud-backup>
        <device-transfer>
            <!-- Airbridge Backup Rules -->
            <exclude domain="sharedpref" path="airbridge-internal" />
            <exclude domain="sharedpref" path="airbridge-install" />
            <exclude domain="sharedpref" path="airbridge-user-info" />
            <exclude domain="sharedpref" path="airbridge-user-alias" />
            <exclude domain="sharedpref" path="airbridge-user-attributes" />
            <exclude domain="sharedpref" path="airbridge-device-alias" />
            <exclude domain="database" path="airbridge.db" />

            <!-- Appsflyer Backup Rules -->
            <exclude domain="sharedpref" path="appsflyer-data"/>

            <!-- Your Custom Backup Rules -->
        </device-transfer>
    </data-extraction-rules>
    ```
  </Accordion>

  <Accordion title="AndroidManifest.xml setup">
    ###### Airbridge Android SDK v2.27.1 or above

    ```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    <manifest
        ...
        xmlns:tools="http://schemas.android.com/tools">

        <application
            ...
            android:allowBackup="true"
            android:fullBackupContent="@xml/custom_backup_rules"
            android:dataExtractionRules="@xml/custom_data_extraction_rules"
            tools:replace="android:fullBackupContent,android:dataExtractionRules">
    ```

    ###### Airbridge Android SDK version less than v2.27.1

    ```xml lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
    <manifest
        ...
        xmlns:tools="http://schemas.android.com/tools">

        <application
            ...
            android:allowBackup="true"
            android:fullBackupContent="@xml/custom_backup_rules"
            tools:replace="android:fullBackupContent">
    ```
  </Accordion>
</AccordionGroup>

### Double brace initialization issue

```java lines theme={"theme":{"light":"github-dark-dimmed","dark":"github-dark-dimmed"}}
HashMap<String, Object> semanticAttributes = new HashMap();
semanticAttributes.put("products", Arrays.asList(
        // double brace initialization issue
        new HashMap<String, Object>() {{
            put("name", "MacBook Pro");
            put("price", 1548200);
            put("position", 1);
            put("brandID", 23);
            put("brandName", "apple");
        }},
        new HashMap<String, Object>() {{
            put("name", "MacBook Air");
            put("price", 1500000);
            put("position", 2);
            put("brandID", 23);
            put("brandName", "apple");
        }}
    )
);

HashMap<String, Object> customAttributes = new HashMap();
customAttributes.put("customKey", "customValue");

Airbridge.trackEvent(
    "purchase",
    "action",
    "label",
    3048200,
    customAttributes,
    semanticAttributes
);
```

The Android SDK uses Google's GSON library and there is a [known issue regarding the double brace initialization](https://github.com/google/gson/issues/346).  The product data may be missing when using double brace initialization for creating the product items as shown in the above Java code. Therefore, it is recommended to create the product items (e.g., [Order Complete ](#order-complete)event) manually.

## SDK Migration

When updating the SDK, consider the content regarding versions between the previous version and the later version or your updated version.

#### 2.24.0

For Airbridge Apps created after September 4, 2023, the issue in versions from v2.22.0 to v2.23.0 where the deep link URL provided in the deeplink callback was double-decoded from the content entered in the Airbridge dashboard has been resolved.

#### 2.21.2

An initialization option has been added to stop event transmission when the app goes to the background.

* You can stop event transmission when the app goes to the background using the `AirbridgeConfig#setTransmitEventOnBackgroundEnabled` function.
* The default value is `true`, and the remaining events are still transmitted in the background.

#### 2.21.1

`deeplink.page` has been deprecated. From v2.21.1 onwards, it is recommended to use `abr.ge` as the deep link domain when writing code.

* `deeplink.page` is still supported and functioning for backward compatibility.

#### 2.19.1

* The structure has been changed to not collect ORGANIC\_REOPEN and FOREGROUND events that occur within the session time by default.
* The BACKGROUND event has been removed.

#### 2.18.0

When the user moves to a different in-app location, the DeeplinkMovement event is collected only when the `Airbridge.click` is called.

<link rel="alternate" hrefLang="en" href="https://help.airbridge.io/en/developers/deprecated-android-sdk-v2" />

<link rel="alternate" hrefLang="ko" href="https://help.airbridge.io/ko/developers/deprecated-android-sdk-v2" />
