Skip to content

Writing Integrations

Brennan Gamwell edited this page Sep 25, 2017 · 11 revisions

We're huge fans of open-source, and we absolutely love getting good contributions to analytics-android! Integrations are available to thousands of Segment customers and we have hundreds of integrations already in our queue, so it's important that you do the following before writing a new integration.

Agree to the Segment Platform Partners Agreement which is necessary to make contributions to Segment Integrations.

Apply to be a Segment partner: https://segment.com/partners/.

We'll review your application and contact you with more information on whether you've been approved, on building out your integration library, and with a few more forms to fill out.

Getting Setup

Android integrations are written as Android Libraries. If you have your own SDK, this would be the same.

Since the integrations are decoupled from our library, you are free to use whatever IDE, build system, folder structure you wish. The only requirement is that integrations be uploaded to Maven Central or jCenter to make it easier for mutual customers to add your integration.

You can see an example for the partner-built Leanplum android integration. Feel free to clone the repository, and replace references to Leanplum with your own SDK.

You'll need to use your own namespace for your library package - not Leanplum's, nor Segment's. :)

Dependencies

To access the Segment Packaged API, you’ll need to declare a dependency on our library.

provided 'com.segment.analytics.android:analytics:4.0.0'

We’ll notify partners when there are changes to our integration API. We won’t make any incompatible changes, but we may add new features.

For testing your integration, we also have a few utility classes in the test artifact.

    testCompile 'com.segment.analytics.android:analytics-tests:4.0.0-SNAPSHOT'

    // Note: If you're using a beta version of Segment's library, the package API will be released as a snapshot, so you’ll need to add the snapshot repository.
    repositories {
      mavenCentral()
      maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
    }

You can find examples of SDK tests in any of Segment's Android repositories. These are all open source at https://github.com/segment-integrations.

Integration API

There are three important classes when it comes to writing an integration.

  1. The Analytics class
  2. The Integration class
  3. The Integration.Factory class

The Analytics class is our public facing API for customers. For integrations, it contains a few key things:

  1. The application Context object
  2. A Logger implementation that can be specifically used by your integration.

The Logger is where you should log all transformations made by our SDK (in verbose mode), so that users can clearly see what’s going on under the covers.

The Integration.Factory class is a class that lets the Segment SDK create an object of your Integration class.

    interface Integration.Factory {
      // Attempts to create an integration with {@code settings}.
      Integration<?> create(ValueMap settings, Analytics analytics);
      
      // Return the key for which this factory can create an integration.
      String key();
    }

All integrations extend from an abstract class called Integration.

    public abstract class Integration<T> {
      // These are the same as http://developer.android.com/reference/android/app/Application.ActivityLifecycleCallbacks.html.
      public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
      }
    
      public void onActivityStarted(Activity activity) {
      }
    
      public void onActivityResumed(Activity activity) {
      }
    
      public void onActivityPaused(Activity activity) {
      }
    
      public void onActivityStopped(Activity activity) {
      }
    
      public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
      }
    
      public void onActivityDestroyed(Activity activity) {
      }
    
      // These are messages in the format of the Segment API.
      // You can refer to the Javadocs for each payload in more detail.
      // Semantically, they are the same as documented in our spec:
      // https://segment.com/docs/spec/.
      public void identify(IdentifyPayload identify) {
      }
    
      public void group(GroupPayload group) {
      }
    
      public void track(TrackPayload track) {
      }
    
      public void alias(AliasPayload alias) {
      }
    
      public void screen(ScreenPayload screen) {
      }
    
      // These methods are specific to client side libraries.
      // Flush is when you should try to upload queued events to your server.
      public void flush() {
      }
    
      // Reset is when you clear out any local user data.
      public void reset() {
      }
      
      // This should return the same object your users would have to use if 
      // they were to integrate natively.
      // e.g. Localytics would return `null`, but Mixpanel would return an instance
      // of a MixpanelAPI object.
      public T getUnderlyingInstance() {
        return null;
      }
    }

Our SDK calls methods on these integrations with whatever data our users have provided. You should override the methods you are interested in.

You can feel free to not include unused methods in your Android library. For example, here’s an SDK that only cares about the identify method.

    public class ExampleIntegration extends Integration {
      public static final Integration.Factory FACTORY = new Integration.Factory() {
        @Override
        Integration<?> create(ValueMap settings, Analytics analytics) {
          String apiKey = settings.getString("apiKey");
          Context context = analytics.getApplication();
          return new ExampleIntegration(apiKey, context);
        }
        
        @Override
        String key() {
          return "example"
        }
      };
      
      @Override public void identify(IdentifyPayload identify) {
        ExampleSDK.identify(identify.userId(), identify.traits);
      }
    }

For a user, the way they install your library is by declaring a dependency on your integration and by registering the factory class in their builder.

compile ‘example:segment-integration:1.2.0’

    Analytics.Builder builder = new Analytics.Builder(this, ANALYTICS_WRITE_KEY);
    builder.use(ExampleIntegration.FACTORY);

ValueMap

Android doesn’t have a native JSON data type. The closest is JSONObject, but there are significant limitations in using it.

We’ve written an easier implementation, called ValueMap. It’s main advantage is that it implements the java Map interface, so you can choose to work with the APIs you’re already used to.

When reading from a ValueMap, it offers a few additional conveniences to work with.

  • getString(key)

  • getInt(key, default)

  • getBoolean(key, default)

They handle parsing from JSON to java primitives, and falling back gracefully to your default value if one is not available.

Recommendations

As we mentioned, there aren’t too many hard and fast rules, integrations are very flexible. Similarly, there aren’t any rules for naming classes, but we have a few recommendations.

  1. Name your integration class {YOUR_SERVICE}Integration.java; e.g. MixpanelIntegration.java or FlurryIntegration.java.
  2. Expose a public static final field for your Factory class.
  3. Follow the structure in the sample repo.

One hard-and-fast rule we do adhere to is the requirement that your app's settings should be set up to be served via Segment's CDN. This allows customers to update their implementations on the fly without having to redeploy their application. Unless there is a significant technical reason that would impact the user experience more than not having their settings in the Segment UI, we don't approve apps structured to require hard-coded settings - this would go against our core product value of making turning on new integrations easy and code free.

Finally, conduct your own code review before submitting your app to us! This will reduce our reply time and help get your integration released more quickly.

By following these recommendations, you’ll make it easier for both customers to pull in your integration, and for you to update your integration. We have some internal tooling that will allow us to make PRs to your repositories whenever we release and update to our core SDK.

Publishing

The integrations should be published to Maven Central. If you aren’t familiar with the process, the following resources should guide you:

  1. http://www.sonatype.org/nexus/2015/04/28/how-to-publish-your-open-source-library-to-maven-central/

  2. http://inthecheesefactory.com/blog/how-to-upload-library-to-jcenter-maven-central-as-dependency/en

  3. http://felipecsl.com/blog/2013/12/06/publishing-an-android-library-to-maven-central/

Clone this wiki locally