Migrating from Android’s BroadcastReceiver to Google Play Install Referrer API with Adobe Analytics

Adobe Analytics can track not only websites, but mobile apps just the same. This is achieved by using the Adobe Experience Platform Mobile SKDs for native iOS and Android apps.

One very interesting part of tracking mobile apps is known as acquisition tracking, which looks at how users found the tracked app. To help with this, Adobe exposes some functionality in their SDKs to listen for the events that the mobile operating system is using to tell apps about the way they have been installed. This happens “automagically” on iOS but needs some custom implementation on Android.

BroadcastReciever and Install Referrer API on Android

Adobe requires to use a very old implementation method called BroadcastReceiver. That method relies on the Google Play Store App sending a message (a broadcast) to the app that has just been installed, telling it about the details of the install (like which marketing campaign has been used). This is a very old method on Android and has a successor called Install Referrer API since 2017. Because of this Google announced to retire the old method by March 1, 2020 back in November 2019 and started sending out reminder emails.

By this date the Google Play Store App will stop sending out the broadcasts the Adobe SKDs rely on. This will only happen in newer versions of the Play Store App. As long as the user does not update that app, broadcasts will still be sent. If the old versions of the Play Store remain functional users could still install apps and the Play Store will send the broadcasts.

That portion of users will decrease with updates over time but leaves marketeers with a scenario where both old and new methods will be used. However, the good message is that there is no harm in still having the old code in your app, since it will only listen for a broadcast it will never receive.

As a migration strategy, app maintainers could implement both methods. But this is not a good idea, since it would leave us with two events for the same install. Because the new method has been around since 2017, we can expect a high adoption by now. Therefore, we should only focus on the state-of-the-art method.

New Adobe methods for Install Referrer

Adobe announced in the Experience Cloud Release Notes that a new version of the Mobile Services and Mobile SDKs will be released on January 16, 2020. The notes say:

  • Acquisition – Added a new API, Analytics.processGooglePlayInstallReferrerUrl(final String url) , to support Google Play Install Referrer APIs.

At time of writing, those new versions are not available for download via Mobile Services or GitHub. There is no documentation as well, so we need to make an educated guess at what we need to do.

The parameter of that new API gives us a hint. “final String url” looks like the string we would get when using the getInstallReferrer() method with the Install Referrer API. Given that information, let’s implement the new method with our Adobe SDKs!

Implementing Play Install Referrer with Mobile Services

The general method of implementing the new API is described in detail in the Android Developer Documentation. It involves connecting to Google Play to get the desired information and handling the response.

But there is one caveat: The information about the install method remains available for 90 days after the installation. Because of this, we need to implement a different broadcast receiver (there it is again!) to only send the referrer on the first app launch. Since I am no Android developer, I will rely on Martin Zeitler’s post on stackoverflow about how to implement this in conjunction with the old documentation.

To use the new Play API, we need to add the dependency to our build.gradle:

implementation 'com.android.installreferrer:installreferrer:1.1'

The next step is similar to the old broadcast receiver. In our AndroidManifest.xml, we replace the old intent receiver

... action android:name="com.android.vending.INSTALL_REFERRER" ...

with

... action android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" ...

to get a notification about the first launch of our app.

Next, in our Java-file, we listen for that notification and pass it to the new Mobile Services API (might have missed some imports):

import com.adobe.mobile.*;
import android.content.BroadcastReceiver;
import com.android.installreferrer.api.InstallReferrerClient;
import com.android.installreferrer.api.InstallReferrerStateListener;
import com.android.installreferrer.api.ReferrerDetails;
import android.content.Context;
import android.content.Intent;
public class PackageStatusReceiver extends BroadcastReceiver implements InstallReferrerStateListener {
    protected static final String LOG_TAG = PackageStatusReceiver.class.getSimpleName();
    private InstallReferrerClient referrerClient;
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction() != null) {
            if(intent.getAction().equals(Intent.ACTION_PACKAGE_FIRST_LAUNCH)) {
                this.referrerClient = InstallReferrerClient.newBuilder(context).build();
                this.referrerClient.startConnection(this);
            }
        }
    }
    @Override
    public void onInstallReferrerSetupFinished(int responseCode) {
        switch (responseCode) {
            case InstallReferrerClient.InstallReferrerResponse.OK:
                Log.d(LOG_TAG, "InstallReferrer Response.OK");
                try {
                    ReferrerDetails response = referrerClient.getInstallReferrer();
                    String referrer = response.getInstallReferrer();
                    com.adobe.mobile.Analytics.processGooglePlayInstallReferrerUrl(referrer);
                    Log.d(LOG_TAG, "InstallReferrer " + referrer);
                    referrerClient.endConnection();
                } catch (RemoteException e) {
                    Log.e(LOG_TAG, "" + e.getMessage());
                }
                break;
            case InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED:
                Log.w(LOG_TAG, "InstallReferrer Response.FEATURE_NOT_SUPPORTED");
                break;
            case InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE:
                Log.w(LOG_TAG, "InstallReferrer Response.SERVICE_UNAVAILABLE");
                break;
            case InstallReferrerClient.InstallReferrerResponse.SERVICE_DISCONNECTED:
                Log.w(LOG_TAG, "InstallReferrer Response.SERVICE_DISCONNECTED");
                break;
            case InstallReferrerClient.InstallReferrerResponse.DEVELOPER_ERROR:
                Log.w(LOG_TAG, "InstallReferrer Response.DEVELOPER_ERROR");
                break;
        }
    }
    @Override
    public void onInstallReferrerServiceDisconnected() {
        Log.w(LOG_TAG, "InstallReferrer onInstallReferrerServiceDisconnected()");
    }
}

Now, Mobile Services should receive the data, since we called com.adobe.mobile.Analytics.processGooglePlayInstallReferrerUrl(referrer) with our referrer-string.