Android SDK

SDK Setup


DownloadDownload


SDK Installation

Installation with Gradle

Please add the following repository under the allproject/repositores block in your project/build.gradle file

allprojects{
    ...
    repositories {
        ...
        maven { url "https://sdk-download.airbridge.io/maven" }
        ...
    }
    ...
}

Please add the following dependency under the dependencies block in your app/build.gradle file

dependencies {
    ...
    implementation "io.airbridge:sdk-android:2.+"
    ...
}

Direct Installation with an AAR File

The Airbridge SDK uses JetBrains' Kotlin and Coroutines libraries for better stability and productivity. Please add following dependency libraries in your project when setting up using an ARR file.

Library

Link

Airbridge SDK

Download

JetBrains Java Annotations

Download

Kotlin Standard Library

Download

Kotlinx Coroutines Core

Download

Kotlinx Coroutines Android

Download

πŸ“˜

Airbridge Android SDK requires Kotlin stdlib and Kotlinx coroutines library version 1.4 or higher.


Project Setup

Min SDKMin SDK

Add Permissions

Please add the following permissions in your AndroidManifest.xml file

<manifest ...>
  ...
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  ...
</manifest>

Initialization

Please add the following code under the onCreate method of the Application class file registered in the AndroidManifest.xml file.

@Override
public void onCreate() {
    super.onCreate();
    AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
        .build();
    Airbridge.init(this, config);
}
override fun onCreate() {
    super.onCreate()
    val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
        .build()
    Airbridge.init(this, config)
}

🚧

For proper operation, please make sure that the init method is called at the time of onCreate of the Application class.

You can find YOUR_APP_NAME and YOUR_APP_SDK_TOKEN in the "Airbridge Dashboard β†’ Settings β†’ Tokens" tab.

25202520

Testing the SDK

Once the basic installation and configuration of the Airbridge SDK is complete, you can test whether it has been correctly setup through the following methods.

Check in the Airbridge Dashboard

25202520
  1. Install and open the app on the device that you want to test
  2. Go to "Airbridge dashboard β†’ Raw Data β†’ App Real-time Logs"
  3. Enter Google Advertising ID of the device in the search box

πŸ“˜

Please re-check the guide above if you do not see any install event with your Google Advertising ID

πŸ“˜

You can find the Google Advertising ID of a device at Settings β†’ Google β†’ Ads β†’ Your advertising ID.

Check in LogCat

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

🚧

Since this method may expose user information, please make sure the method is executed only for the Build.DEBUG case.

// 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);
// Default log level = Log.INFO
val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setLogLevel(Log.DEBUG)
    .build()
Airbridge.init(this, config)
15321532



Deep Link Setup


Dashboard Setup

25202520

The following information must be registered at the "Airbridge dashboard β†’ Tracking Link β†’ Deep Link"

  • URI Scheme
  • sha256_cert_fingerprints

URI Scheme Setup

Enter the URI scheme that will be used, including ://, in the "Android URI Scheme" area as shown in the picture above. (e.g. example://, yoururischeme://)

🚧

Airbridge supports lowercase, numbers, and some special characters (-, +, .) for URI Schemes.

Register Fingerprint

Follow the below steps to obtain the sha256_cert_fingerprint.

  1. Prepare the keystore file that you used to register your app with Google Play Store.
  2. Execute the following command in Linux.
keytool -list -v -keystore my-release-key.keystore
  1. Copy the SHA256 value under the Certificate Fingerprints section and paste it under Android sha256_cert_fingerprints as shown in the picture above.
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

Project Setup

Intent Filter Setup

Follow these steps to setup the intent-filter

  1. Open AndroidManifest.xml
  2. Add the following intent-filter to the activity that will process the deep link.
<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>
  • YOUR_APP_NAME.deeplink.page : Airbridge App Links Version 2
  • YOUR_APP_NAME.airbridge.io : Airbridge App Links Version 1
  • YOUR_APP_URI_SCHEME : URI Scheme of the deep link (e.g. abc://)

Custom Domain Setup

The deeplink.page or abr.ge domains are available when creating a tracking link at the Airbridge dashboard. Customized URLs such as go.my_company.com/abcd can also be used as tracking links to improve the branding and CTR (Click Through Rate).

  1. Please follow this guide to setup custom domains.

  2. Create a /res/values/airbridge.xml file and edit it as below

<?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_CUSTOM_DOMAIN</item>
    </string-array>
</resources>
  1. Add the following intent-filter to the activity that will process the deep link.
<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_CUSTOM_DOMAIN" />
        <data android:scheme="https" android:host="YOUR_CUSTOM_DOMAIN" />
    </intent-filter>
    ...
</activity>

❗️

YOUR_CUSTOM_DOMAIN should match the information in the Airbridge dashboard

Deep Link Callback Setup

The edit below is needed to process the deep link as defined by the intent-filter above.

@Override
protected void onResume() {
    super.onResume();
    Airbridge.getDeeplink(getIntent(), new AirbridgeCallback<Uri>() {
        @Override
        public void onSuccess(Uri uri) {
            // Process deep link data
        }

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

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

// The code below is required for proper deep link processing
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
}
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)
}

Deferred Deep Link Callback Setup

In the general case of a deferred deep link in Airbridge SDK, the intent-filter automatically calls the corresponding activity and can be processed in the same way as a deep link callback.

πŸ“˜

When the corresponding activity is called through an Airbridge deferred deep link, the deferred=true query parameter is also passed on.

You can use the following method if you do not want the deferred deep link to automatically call an activity, or want to process a specific job with the information obtained through the deferred deep link.

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);
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)

Test Deep Link

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

  • YOUR_APP_URI_SCHEME://

The results will show on the "Airbridge dashboard β†’ Row Data β†’ App Real-time Log" tab if everything is working.

33603360



User Setup


User Identifier Setup

To measure the fragmented contributions of users between web and app, Airbridge collects the following user identifier information.

  • User Email: Email address
  • User Phone: Phone number
  • User ID: Unique User ID (The ID value that specifies the user must be the same in both web and mobile)
  • User Alias: Identifiers that can represent users (e.g. loyalty program ID, affiliate integrated ID, etc)

πŸ“˜

The user's email and phone numbers are hashed (SHA256) by default and then sent to servers.

You can set the user identifier as below for the SDK.

// Automatically hashed on client side using SHA256
// Can turn off hashing feature with special flag
Airbridge.getCurrentUser().setEmail("[email protected]e.io");
Airbridge.getCurrentUser().setPhone("1(123)123-1234");

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

// Clear user data
Airbridge.expireUser()
// Automatically hashed on client side using SHA256
// Can turn off hashing feature with special flag
Airbridge.getCurrentUser().email = "[email protected]"
Airbridge.getCurrentUser().phone = "(123)123-1234"

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

// Clear user data
Airbridge.expireUser()

Name

Description

Limitations

Email

User email

Hashed by default
(SHA256, can be disabled)

Phone

User phone number

Hashed by default
(SHA256, can be disabled)

Id

User ID

Alias

User alias

  • Maximum 10 aliases
  • "key" type is String, maximum 128 characters
  • "key" must satisfy ^[a-z_][a-z0-9_]*$ regex
  • "value" type is String, maximum 1024 characters

Once the user identifier has been setup, all events will be forwarded with the corresponding identity information.


User Attributes Setup

Additional user attributes can be used for more accurate Multi-Touch Attribution (MTA) analyses, additional internal data analysis, and linking third-party solutions.

Airbridge.getCurrentUser().setAttribute("key", "value");
Airbridge.getCurrentUser().setAttribute("key", "value")

Name

Description

Limitations

setAttribute

User attribute

  • Maximum 100 attributes
  • "key" type is string, maximum 128 characters
  • "key" must satisfy ^[a-z_][a-z0-9_]*$ regex
  • "value" type is primitive or string
  • Maximum 1024 characters when "value" is string

Test User Information Setup

Check your user information settings at "Airbridge Dashboard β†’ Raw Data β†’ App Real-time Log".

33603360



Event Setup


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

Name

Type

Description

EventCategory

String

Name of the event
Required

event_action

String

Event attribute 1

event_label

String

Event attribute 2

eventValue

Number

Event attribute value

eventAttributes

Map<String, Object>

Custom attributes

semanticAttributes

Semantic attributes class

Semantic attributes

Below is an example of how you can send a standard event using the Airbridge SDK.

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);
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)

If your application has specific needs that are not covered by a standard event category, you can log custom events as below.

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);
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)

πŸ“˜

Please refer to guide for more details on semantic attributes supported by the Airbridge SDK.

Alternatively, you can pre-define classes and inherit them depending on the event your app needs.

class MyAppEvent extends Event {
    public MyAppEvent() {
        super("my_custom_category");
    }
}
...
Airbridge.trackEvent(new MyAppEvent());
...

Sending Standard Events

User Sign up

Airbridge.getCurrentUser().setEmail("[email protected]");
Airbridge.getCurrentUser().setPhone("1(123)123-1234");
Airbridge.getCurrentUser().setId("personID");
Airbridge.getCurrentUser().setAlias("alias1", "value");
Airbridge.getCurrentUser().setAttributes("attr1", 1234);
Airbridge.trackEvent(StandardEventCategory.SIGN_UP);
Airbridge.getCurrentUser().setEmail("[email protected]")
Airbridge.getCurrentUser().setPhone("(123)123-1234")
Airbridge.getCurrentUser().setId("personID")
Airbridge.getCurrentUser().setAlias("alias1", "value")
Airbridge.getCurrentUser().setAttributes("attr1", 1234)
Airbridge.trackEvent(StandardEventCategory.SIGN_UP)

User Sign in

Airbridge.getCurrentUser().setEmail("[email protected]");
Airbridge.getCurrentUser().setPhone("1(123)123-1234");
Airbridge.getCurrentUser().setId("personID");
Airbridge.getCurrentUser().setAlias("alias1", "value");
Airbridge.getCurrentUser().setAttributes("attr1", 1234);
Airbridge.trackEvent(StandardEventCategory.SIGN_IN);
Airbridge.getCurrentUser().setEmail("[email protected]")
Airbridge.getCurrentUser().setPhone("(123)123-1234")
Airbridge.getCurrentUser().setId("personID")
Airbridge.getCurrentUser().setAlias("alias1", "value")
Airbridge.getCurrentUser().setAttributes("attr1", 1234)
Airbridge.trackEvent(StandardEventCategory.SIGN_IN)

User Sign out

Airbridge.trackEvent(StandardEventCategory.SIGN_OUT);
Airbridge.expireUser();
Airbridge.trackEvent(StandardEventCategory.SIGN_OUT)
Airbridge.expireUser()

View Home Screen

Airbridge.trackEvent(StandardEventCategory.HOME_VIEW);
Airbridge.trackEvent(StandardEventCategory.HOME_VIEW)

View Search Results

SemanticAttributes semanticAttributes = new SemanticAttributes();
semanticAttributes.setQuery("Coca Cola");
Airbridge.trackEvent(StandardEventCategory.SEARCH_RESULT_VIEW, null, null, null, null, semanticAttributes.toMap());
val semanticAttributes = SemanticAttributes()
semanticAttributes.query = "Coca Cola"
Airbridge.trackEvent(StandardEventCategory.SEARCH_RESULT_VIEW, null, null, null, null, semanticAttributes.toMap())

View Product List

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.setProducts(Arrays.asList(fanta, cocacola));
Airbridge.trackEvent(StandardEventCategory.PRODUCT_LIST_VIEW, null, null, null, null, semanticAttributes.toMap());
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.products = listOf(fanta, cocacola)
Airbridge.trackEvent(StandardEventCategory.PRODUCT_LIST_VIEW, null, null, null, null, semanticAttributes.toMap())

View Product Details

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));
Airbridge.trackEvent(StandardEventCategory.PRODUCT_DETAILS_VIEW, null, null, null, null, semanticAttributes.toMap());
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.products = listOf(fanta, cocacola)
Airbridge.trackEvent(StandardEventCategory.PRODUCT_DETAILS_VIEW, null, null, null, null, semanticAttributes.toMap())

Add to Cart

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");
semanticAttributes.setTotalValue(4.98);
Airbridge.trackEvent(StandardEventCategory.ADD_TO_CART, null, null, null, null, semanticAttributes.toMap());
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.cartId = "cart_123"
semanticAttributes.products = listOf(fanta, cocacola)
semanticAttributes.currency = "USD"
semanticAttributes.totalValue = 4.98
Airbridge.trackEvent(StandardEventCategory.ADD_TO_CART, null, null, null, null, semanticAttributes.toMap())

Order Complete

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.setTotalValue(4.98);
semanticAttributes.setInAppPurchased(true);
Airbridge.trackEvent(StandardEventCategory.ORDER_COMPLETED, null, null, null, null, semanticAttributes.toMap());
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.products = listOf(fanta, cocacola)
semanticAttributes.currency = "USD"
semanticAttributes.totalValue = 4.98
semanticAttributes.inAppPurchased = true
Airbridge.trackEvent(StandardEventCategory.ORDER_COMPLETED, null, null, null, null, semanticAttributes.toMap())

Verify Event Transmission

Event information sent from the Airbridge SDK should be seen in the "Airbridge dashboard β†’ Raw Data β†’ App Real-time Log" tab.

33603360



Advanced Setup


User Identifier Hash Setup

If you want to send user identity information without hashing it for internal data analysis, you can disable hashing by turning off the following option.

❗️

Other security measures must be taken internally when sensitive personal information such as "User Email" and "User Phone" is being handled.

// Default User Info Hash Enabled = true
AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setUserInfoHashEnabled(false)
    .build();
Airbridge.init(this, config);
// Default User Info Hash Enabled = true
val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setUserInfoHashEnabled(false)
    .build()
Airbridge.init(this, config)

Session Timeout Settings

Airbridge SDK does not resend an app open event if the user relaunches the app within the set session time. It will only send an app open event when the user opens the app after the set session time.

// Default Session Timeout = 5 minutes
AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setSessionTimeoutSeconds(15)
    .build();
Airbridge.init(this, config);
// Default Session Timeout = 5 minutes
val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setSessionTimeoutSeconds(15)
    .build()
Airbridge.init(this, config)

Privacy Protection

Use this function if privacy laws apply, and data should only be collected and transferred with consent. (e.g GDPR, CCPA)

// 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();
}
// 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()
}

Track Airbridge Links Only

It may be difficult to see the re-engagement performance through Airbridge if there are too many deep link actions within the advertiser's app. The following option can be used to receive deep link events for Airbridge deep links only.

This option will measure deep links only if the following requirements are met.

  • The app is opened through a airbridge.io link
  • The app is opened through a deeplink.page link
  • The app is opened through a Custom Domain Setup that is registered on the Airbridge dashboard
  • The app is opened through a link that contains airbridge_referrer information in the query
// Default Airbridge Link Only = false
AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setTrackAirbridgeLinkOnly(true)
    .build();
Airbridge.init(this, config);
// Default Airbridge Link Only = false
val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setTrackAirbridgeLinkOnly(true)
    .build()
Airbridge.init(this, config)

Deferred App Link Settings for Facebook

The settings below will allow Airbridge SDK to utilize Facebook's deferred app link information.

Reference - https://developers.facebook.com/docs/app-events/getting-started-app-events-android
Reference - https://developers.facebook.com/docs/app-ads/deep-linking

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

allprojects{
    ...
    repositories {
        ...
        mavenCentral()
        ...
    }
    ...
}

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

dependencies {
    ...
    implementation 'com.facebook.android:facebook-android-sdk:latest.release'
    ...
}

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

...
<string name="facebook_app_id">FACEBOOK_APP_ID</string>
...

Add the following meta-data under the application element in the AndroidManifest.xml file.

...
<application android:label="@string/app_name" ...> 
    ...
    <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
    ...
</application>
...

Set the below option to true.

// 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);
// 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)

Device Identifier Setup

Use the following method to setup device identifier information for the Airbridge SDK.

Airbridge.getDeviceInfo().setAlias("key", "value");
Airbridge.getDeviceInfo().setAlias("key", "value")

Name

Description

Limitations

Alias

Device alias

  • Maximum 10 aliases
  • "key" type is NSString, maximum 128 characters
  • "key" must satisfy ^[a-z_][a-z0-9_]*$ regex
  • "value" type is NSString, maximum 1024 characters

App Uninstallation Tracking

πŸ“˜

App uninstallation tracking through Firebase Messaging is supported by Airbridge Android SDK v2.6.0 and above.

Please refer to this page for more information on app uninstallation tracking.


User Location Information Collection

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

❗️

Location information must be collected for legal purposes through legal methods.

// Choose one
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
...
// Default Location Collection Enabled = false
AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setLocationCollectionEnabled(true)
    .build();
Airbridge.init(this, config);
// Default Location Collection Enabled = false
val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setLocationCollectionEnabled(true)
    .build()
Airbridge.init(this, config)

🚧

Airbridge SDK collects LastKnownLocation information. If the GPS information is not obtained, the value may not exist even if the corresponding permissions and settings are complete.


Inflow Measurement Per App Market

If advertisers need to analyze their application inflow performance for each market separately(e.g. Google Play Store, One Store, Huawei Store), you can set identifiers for each application and it will be reflected on the Airbridge dashboard.

Setup via AndroidManifest.xml

Insert the app market's name(e.g. playStore, oneStore, huaweiStore) at andriod:value.

...
<application android:label="@string/app_name" ...> 
    ...
    <meta-data android:name="co.ab180.airbridge.app_market_identifier" android:value="playStore"/>
    ...
</application>
...

Setup via AirbridgeConfig

Insert the app market's name(e.g. playStore, oneStore, huaweiStore) at setAppMarketIdentifier.

AirbridgeConfig config = new AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setAppMarketIdentifier("playStore") // oneStore, huaweiStore ...
    .build();
Airbridge.init(this, config);
val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setAppMarketIdentifier("playStore") // oneStore, huaweiStore ...
    .build()
Airbridge.init(this, config)

The data can be utilized at the Airbridge dashboard through "Reports β†’ Actuals β†’ GroupBy β†’ Event Property β†’ App Market Identifier" and "Raw Data β†’ App Raw Data β†’ Export Raw Data β†’ Select Property β†’ App Market Identifier".

14741474

Installations per App Market


Error Log Collection

Error logs of the SDK are sent to the Airbridge server to improve the quality of the Airbridge SDK. These error logs only include the SDK's internal operations. You can disable this by turning off the following option.

// 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);
// Default Error Log Collection Enabled = true
val config = AirbridgeConfig.Builder("YOUR_APP_NAME", "YOUR_APP_SDK_TOKEN")
    .setErrorLogCollectionEnabled(false)
    .build()
Airbridge.init(this, config)

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.

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);
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)

πŸ“˜

Event buffer size is slightly smaller than the actual size of the data due to metadata management.



Hybrid App Setup


While basic events (e.g. "install", "open", "deep link open") can be automatically tracked by only installing the Android SDK in your hybrid app, in-app events (e.g. sign-up, purchase, etc.) cannot be tracked as they are actually 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.

❗️

Please note that in order to utilize this feature, both SDKs must be installed; Android SDK on the mobile native environment and web SDK on the website of the WebView environment.

Sending Events in WebView Environments

Reference - Building Web Apps in WebView

Reference - Understanding Android WebView Javascript Interface

Please call the Airbridge::setJavascriptInterface method in the target WebView as below.

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("http://dev.blog.airbridge.io/websdk-web-app/");
    }
}
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("http://my_company.com/main")
    }
}

You can find YOUR_WEB_TOKEN in the "Airbridge dashboard β†’ Settings β†’ Tokens" tab

25202520

Reload the web SDK at the web page you'll be using.

(function(a_,i_,r_,_b,_r,_i,_d,_g,_e){if(!a_[_b]||!a_[_b].queue){_g=i_.getElementsByTagName(r_)[0];a_[_b]={queue:[]};_d={};for(_i=0;_i<_r.length;_d={$jscomp$loop$prop$m$2:_d.$jscomp$loop$prop$m$2},_i++)_d.$jscomp$loop$prop$m$2=_r[_i],~_d.$jscomp$loop$prop$m$2.indexOf(".")&&(_e=_d.$jscomp$loop$prop$m$2.split(".")[0],a_[_b][_e]=a_[_b][_e]||{},a_[_b][_e][_d.$jscomp$loop$prop$m$2.split(".")[1]]=function(_d){return function(){a_[_b].queue.push([_d.$jscomp$loop$prop$m$2,arguments])}}(_d)),a_[_b][_d.$jscomp$loop$prop$m$2]=function(_d){return function(){a_[_b].queue.push([_d.$jscomp$loop$prop$m$2,arguments])}}(_d);_d=i_.createElement(r_);_d.async=1;_d.src="//static.airbridge.io/sdk/latest/airbridge.min.js";_g.parentNode.insertBefore(_d,_g)}})(window,document,"script","airbridge","init setBanner setDownload setDeeplinks sendSMS sendWeb setUserAgent setUserAlias addUserAlias setMobileAppData setUserId setUserEmail setUserPhone setUserAttributes setDeviceIFV setDeviceIFA setDeviceGAID events.send events.signIn events.signUp events.signOut events.purchased events.addedToCart events.productDetailsViewEvent events.homeViewEvent events.productListViewEvent events.searchResultViewEvent".split(" "));

airbridge.init({
    app: 'YOUR_APP_NAME',
    webToken: 'YOUR_WEB_SDK_TOKEN'
});



Troubleshooting


Dependencies

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

java.lang.NoClassDefFoundError: kotlin/coroutines/AbstractCoroutineContextKey
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
  ...

Reference - https://github.com/Kotlin/kotlinx.coroutines/issues/1879

According to @qwwdfsad, the use of "kotlin-stdlib 1.3.70" and above is enforced when using "kotlinx-coroutines-core 1.3.5" and above.

Make sure that you're using "kotlin-stdlib 1.3.70" and above if you're using "kotlinx-coroutines-core 1.3.5" and above through the gradlew dependencies command.


Auto Backup

Reference - https://developer.android.com/guide/topics/data/autobackup

Airbridge SDK defines airbridge_auto_backup_rules.xml in AndroidManifest.xml to prevent automatic replication of internal data. If you need Auto Backup for your Android app, you have to merge with airbridge_auto_backup_rules.xml file yourself

When errors like Manifest merger failed : Attribute [email protected] value=(true) occur, please add the following rules in your backup_rules.xml file and add tools:replace="android:fullBackupContent" inside application element

Airbridge SDK defines airbridge_auto_backup_rules.xml in AndroidManifest.xml to prevent automatic replication of internal data. You may have to configure your auto backup rules if your app uses auto backup, which in turn might cause conflicts such as Manifest merger failed : Attribute [email protected] value=(true).

If such errors occur, you will need to set tools:replace="android:fullBackupContent" under the application element and merge the following rules to your backup_rules.xml file.

Below are the auto backup rules defined in the Airbridge SDK.

<?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>