Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moving MParticle-specific messaging logic into a router for reusability #8

Merged
merged 5 commits into from
Jun 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 70 additions & 94 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,117 +2,89 @@

## Android SDK

Hello! This is the public repo of the mParticle Android SDK. Right now, it contains the "kit" implementations and maintains a dependency on the mParticle Core library.
[![Maven Central Status](https://maven-badges.herokuapp.com/maven-central/com.mparticle/android-core/badge.svg?style=flat-square)](https://search.maven.org/#search%7Cga%7C1%7Cmparticle)

We originally built the [mParticle platform](https://www.mparticle.com) to help simplify the approach to SDKs and improve app performance. We've found that having a bunch of SDKs in an app bloats its size and is no-good for your users' battery. So, we built client-side APIs for you to collect all of your data, and a server platform that lets you send your data where you want it to go.
Hello! This is the public repo of the mParticle Android SDK. mParticle's mission is straightforward: make it really easy to use all of the great services in the app ecosystem. Our SDKs and platform are designed to be your abstraction layer and data hub, and we do the work of integrating with each individual app service so you don't have to.

From that original goal the platform has grown to support 50+ services and SDKs, including developer tools, analytics, attribution, messaging, and advertising services. mParticle is designed to serve as the connector between all of these services - check out [our site](https://www.mparticle.com), or hit us at dev@mparticle.com to learn more.
The platform has grown to support 80+ partners in the ecosystem, including developer tools, analytics, attribution, marketing automation, and advertising services. We also have a powerful audience engine that sits atop our platform to let you action on all of your data - [learn more here](https://www.mparticle.com)!

## Get the SDK
### Core SDK

The SDK is composed of the Core library and a series of "kit" libraries that depend on Core. Though most of mParticle's integrations are on the server-side, some of these services need to be integrated on the client side - and that's where *kits* come in. The Core SDK takes care of initializing the kits depending on what you've configured in [your app's dashboard](https://app.mparticle.com), so you just have to decide which kits you *may* use prior to submission to Google Play. You can easily include all of the kits, none of the kits, or individual kits - the choice is yours.
mParticle's Android integration is powered by a Core library, which supports mParticle's server-side integrations and audience platform.

### Gradle Setup
You can grab the Core SDK via Maven Central. Please reference the badge above and follow the [releases page](https://github.com/mParticle/mparticle-android-sdk/releases) to stay up to date with the latest version.

[![Maven Central Status](https://maven-badges.herokuapp.com/maven-central/com.mparticle/android-core/badge.svg?style=flat-square)](https://search.maven.org/#search%7Cga%7C1%7Cmparticle)
```groovy
dependencies {
compile 'com.mparticle:android-core:4.+'
}
```

mParticle deploys all artifacts to Maven Central - determine the correct artifact(s) to include in your project from the following options:
### Kits

**Option 1:** Include *only* the Core library (`com.mparticle:android-core`). This means that you'll only be using *server-based* integrations.
**Option 2:** Pick the Kits (`com.mparticle:android-XXX-kit`) that you'd like to use, and include only those. A Kit will only be instantiated if you configure it in the mParticle services dashboard.
**Option 3:** Include all the Kits with the `com.mparticle:android-sdk` artifact.
Several integrations require additional client-side add-on libraries called "kits." Some kits embed other SDKs, others just contain a bit of additional functionality. Kits are designed to feel just like server-side integrations; you enable, disable, filter, sample, and otherwise tweak kits completely from the mParticle platform UI. The Core SDK will detect kits at runtime, but you need to add them as dependencies to your build:

```groovy
dependencies {
// Option 1:
// Just the Core library - only use server-side integrations
compile 'com.mparticle:android-core:4.+'

// Option 2:
// Pick the individual kits you want
// This will automatically incorporate android-core
compile (
'com.mparticle:android-adjust-kit:4.+',
'com.mparticle:android-appboy-kit:4.+',
'com.mparticle:android-branch-kit:4.+'
'com.mparticle:android-example-kit:4.+',
'com.mparticle:android-another-kit:4.+',
)

// Option 3:
// Use this to include ALL kits
// This will automatically incorporate android-core
compile "com.mparticle:android-sdk:4.+"

//Required for many attribution services
compile "com.google.android.gms:play-services-ads:7.8.0"

//Optional - for Push notification support
compile "com.google.android.gms:play-services-gcm:7.8.0"
}
```

Here's the full list of currently supported kits:

- `com.mparticle:android-adjust-kit:4.+`
- `com.mparticle:android-appsflyer-kit:4.+`
- `com.mparticle:android-appboy-kit:4.+`
- `com.mparticle:android-branch-kit:4.+`
- `com.mparticle:android-comscore-kit:4.+`
- `com.mparticle:android-crittercism-kit:4.+`
- `com.mparticle:android-flurry-kit:4.+`
- `com.mparticle:android-foresee-kit:4.+`
- `com.mparticle:android-kahuna-kit:4.+`
- `com.mparticle:android-kochava-kit:4.+`
- `com.mparticle:android-localytics-kit:4.+`
- `com.mparticle:android-wootric-kit:4.+`
- `com.mparticle:android-tune-kit:4.+`

## Proguard

Proguard is a minification/optimization/obfuscation tool that's extremely useful, and it can also cause some sticky bugs. The mParticle SDK is already minified so there's no need to...double-minify it. With Proguard you can specify a set of exclusion rules - reference the sample below and edit your app's rules file to avoid processing mParticle, Google Play Services, and the various Kit SDK classes.

```ini
# mParticle (required)
-keep class com.mparticle.** { *; }

# Google Play Services (required)
-keep class com.google.android.gms.common.** { *; }
-keep class com.google.android.gms.ads.identifier.** { *; }

# Appboy Kit
-dontwarn com.amazon.device.messaging.**
-dontwarn bo.app.**
-keep class bo.app.** { *; }
-keep class com.appboy.** { *; }

# Kahuna Kit
-keep class kahuna.sdk.** { *; }

# Kochava Kit
-keep class kochava.android.** { *; }

# Comscore Kit
-keep class com.comscore.** { *; }
-dontwarn com.comscore.**

# Flurry Kit
-keep class com.flurry.** { *; }
-dontwarn com.flurry.**

# Localytics Kit
-keep class com.localytics.android.** { *; }
-keepattributes JavascriptInterface

# Wootric Kit
-keep class com.wootric.** { *; }
-keep class retrofit.** { *; }
-keepclassmembernames interface * {
@retrofit.http.* <methods>;
}
Kits are deployed as individual artifacts in Maven Central, and each has a dedicated repository if you'd like to view the source code. Review the table below to see if you need to include any kits:

Kit | Maven Artifact
----|---------
[Adjust](https://github.com/mparticle-integrations/mparticle-android-integration-adjust) | [`android-adjust-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-adjust-kit%22)
[Appboy](https://github.com/mparticle-integrations/mparticle-android-integration-appboy) | [`android-appboy-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-appboy-kit%22)
[AppsFlyer](https://github.com/mparticle-integrations/mparticle-android-integration-appsflyer) | [`android-appsflyer-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-appsflyer-kit%22)
[Apptentive](https://github.com/mparticle-integrations/mparticle-android-integration-apptentive) | [`android-apptentive-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-apptentive-kit%22)
[Apteligent](https://github.com/mparticle-integrations/mparticle-android-integration-apteligent) | [`android-apteligent-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-apteligent-kit%22)
[Branch Metrics](https://github.com/mparticle-integrations/mparticle-android-integration-branchmetrics) | [`android-branch-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-branch-kit%22)
[comScore](https://github.com/mparticle-integrations/mparticle-android-integration-comscore) | [`android-comscore-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-comscore-kit%22)
[Flurry](https://github.com/mparticle-integrations/mparticle-android-integration-flurry) | [`android-flurry-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-flurry-kit%22)
[Kahuna](https://github.com/mparticle-integrations/mparticle-android-integration-kahuna) | [`android-kahuna-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-kahuna-kit%22)
[Kochava](https://github.com/mparticle-integrations/mparticle-android-integration-kochava) | [`android-kochava-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-kochava-kit%22)
[Localytics](https://github.com/mparticle-integrations/mparticle-android-integration-localytics) | [`android-localytics-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-localytics-kit%22)
[Tune](https://github.com/mparticle-integrations/mparticle-android-integration-tune) | [`android-tune-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-tune-kit%22)
[Wootric](https://github.com/mparticle-integrations/mparticle-android-integration-wootric) | [`android-wootric-kit`](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mparticle%22%20AND%20a%3A%22android-wootric-kit%22)


### Optional Dependencies

##### Google Play Services Ads

The Google Play Services Ads framework is necessary to collect the Android Advertisting ID. AAID collection is required by all attribution and audience integrations, and many other integrations. Include the `-ads` artifact, a subset of [Google Play Services](https://developers.google.com/android/guides/setup):

```groovy
compile 'com.google.android.gms:play-services-ads:9.0.0'
```

##### Google Cloud Messaging

mParticle supports several marketing automation and push messaging integrations. These require that mParticle register for an instance id (formely known as a push registration token) using the Google Play Services Cloud Messaging framework. Include the `-gcm` artifact, a subset of [Google Play Services](https://developers.google.com/android/guides/setup):

```groovy
compile 'com.google.android.gms:play-services-gcm:9.0.0'
```

### Install Referrer

In order for attribution, deep linking, and many other integrations to work properly, add the mParticle `ReferrerReceiver` to your manifest file within the `<application>` tag:

```xml
<receiver android:name="com.mparticle.ReferrerReceiver" android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER"/>
</intent-filter>
</receiver>
```

## Show me the code

OK OK, slow down. Grab your mParticle key and secret from [your app's dashboard](https://app.mparticle.com/apps) and add them as `string` resources in your app:
Grab your mParticle key and secret from [your app's dashboard](https://app.mparticle.com/apps) and add them as `string` resources in your app:

```xml
<?xml version="1.0" encoding="utf-8" ?>
Expand All @@ -122,10 +94,11 @@ OK OK, slow down. Grab your mParticle key and secret from [your app's dashboard]
<string name="mp_secret">APP SECRET</string>
</resources>
```
> You can also pass your key/secret programmatically in the method below.

#### Initialize the SDK

Call `start` from the `onCreate` method of your app's `Application` class. If you don't already have an `Application` class, create it and then specify its fully-qualified name in the `<application>` tag of your app's `AndroidManifest.xml`.
Call `start` from the `onCreate` method of your app's `Application` class. It's crucial that the SDK be started here for proper session management. If you don't already have an `Application` class, create it and then specify its fully-qualified name in the `<application>` tag of your app's `AndroidManifest.xml`.

```java
package com.example.myapp;
Expand All @@ -142,7 +115,11 @@ public class MyApplication extends Application {
}
```

**Note:** It's not advisable to log events in your `Application.onCreate()`. Android may instantiate your `Application` class for a lot of reasons, in the background, while the user isn't even using their device.
> **Warning:** It's generally not a good idea to log events in your `Application.onCreate()`. Android may instantiate your `Application` class for a lot of reasons, in the background, while the user isn't even using their device.

#### Proguard

Proguard is a minification/optimization/obfuscation tool that's extremely useful, and it can also cause some sticky bugs. The mParticle SDK is already minified so there's no need to...double-minify it. If you're using Gradle there's nothing to do - we include a `consumer-proguard` rules file inside our `AAR` which Gradle will automatically include in your build. If you're not using Gradle, please add those same rules manually - [see here for the latest](https://github.com/mParticle/mparticle-android-sdk/blob/master/android-core/consumer-proguard.pro).

## Read More

Expand All @@ -154,4 +131,3 @@ Just by initializing the SDK you'll be set up to track user installs, engagement
## License

[Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)

Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ public class KitFrameworkWrapper implements KitManager {
private final ConfigManager mConfigManager;
private final ReportingManager mReportingManager;
private KitManager mKitManager;
private volatile boolean loadAttempted;
private volatile boolean frameworkLoadAttempted = false;
private volatile boolean kitsLoaded = false;

private boolean shouldCheckForDeepLink = false;
private Queue queuedEvents;
private boolean queueEvents = true;
private boolean registerForPush = false;
private Queue eventQueue;
private volatile boolean registerForPush = false;
private volatile boolean shouldCheckForDeepLink = false;

public KitFrameworkWrapper(Context context, ReportingManager reportingManager, ConfigManager configManager, AppStateManager appStateManager) {
this.mContext = context;
Expand All @@ -41,13 +41,12 @@ public KitFrameworkWrapper(Context context, ReportingManager reportingManager, C
}

public void loadKitLibrary() {
if (!loadAttempted) {
if (!frameworkLoadAttempted) {
ConfigManager.log(MParticle.LogLevel.DEBUG, "Loading Kit Framework.");
loadAttempted = true;
frameworkLoadAttempted = true;
try {
Class clazz = Class.forName("com.mparticle.kits.KitManagerImpl");
Constructor<KitFrameworkWrapper> constructor = clazz.getConstructor(Context.class, ReportingManager.class, ConfigManager.class, AppStateManager.class);
constructor.setAccessible(true);
mKitManager = constructor.newInstance(mContext, mReportingManager, mConfigManager, mAppStateManager);
JSONArray configuration = mConfigManager.getLatestKitConfiguration();
ConfigManager.log(MParticle.LogLevel.DEBUG, "Kit Framework loaded.");
Expand All @@ -62,16 +61,35 @@ public void loadKitLibrary() {
}
}

private void disableQueuing() {
queueEvents = false;
if (queuedEvents != null) {
queuedEvents.clear();
queuedEvents = null;
boolean getFrameworkLoadAttempted() {
return frameworkLoadAttempted;
}

Queue getEventQueue() {
return eventQueue;
}

void setKitManager(KitManager manager) {
mKitManager = manager;
}
boolean getKitsLoaded() {
return kitsLoaded;
}

void setKitsLoaded(boolean kitsLoaded) {
this.kitsLoaded = kitsLoaded;
}

void disableQueuing() {
setKitsLoaded(true);
if (eventQueue != null) {
eventQueue.clear();
eventQueue = null;
ConfigManager.log(MParticle.LogLevel.DEBUG, "Kit initialization complete. Disabling event queueing.");
}
}

private void replayEvents() {
void replayEvents() {
if (mKitManager == null) {
return;
}
Expand All @@ -87,12 +105,12 @@ private void replayEvents() {
mKitManager.checkForDeepLink();
}

if (queuedEvents == null || queuedEvents.size() == 0) {
if (eventQueue == null || eventQueue.size() == 0) {
return;
}

ConfigManager.log(MParticle.LogLevel.DEBUG, "Replaying events after receiving first kit configuration.");
for (Object event : queuedEvents) {
for (Object event : eventQueue) {
if (event instanceof MPEvent) {
MPEvent mpEvent = (MPEvent) event;
if (mpEvent.isScreenEvent()) {
Expand All @@ -107,23 +125,24 @@ private void replayEvents() {
}

public void replayAndDisableQueue() {
setKitsLoaded(true);
replayEvents();
disableQueuing();
}

private boolean queueEvent(Object event) {
if (!queueEvents) {
boolean queueEvent(Object event) {
if (getKitsLoaded()) {
return false;
}

if (queuedEvents == null) {
queuedEvents = new ConcurrentLinkedQueue<Object>();
if (eventQueue == null) {
eventQueue = new ConcurrentLinkedQueue<Object>();
}
//it's an edge case to even need this, so 10
//should be enough.
if (queuedEvents.size() <= 10) {
if (eventQueue.size() < 10) {
ConfigManager.log(MParticle.LogLevel.DEBUG, "Queuing Kit event while waiting for initial configuration.");
queuedEvents.add(event);
eventQueue.add(event);
}
return true;
}
Expand All @@ -149,7 +168,7 @@ public void logCommerceEvent(CommerceEvent event) {
@Override
public void logScreen(MPEvent screenEvent) {
if (!queueEvent(screenEvent) && mKitManager != null) {
mKitManager.logEvent(screenEvent);
mKitManager.logScreen(screenEvent);
}
}

Expand All @@ -176,13 +195,17 @@ public void logNetworkPerformance(String url, long startTime, String method, lon

@Override
public void checkForDeepLink() {
if (mKitManager != null) {
if (mKitManager != null && getKitsLoaded()) {
mKitManager.checkForDeepLink();
} else {
shouldCheckForDeepLink = true;
}
}

boolean getShouldCheckForDeepLink() {
return shouldCheckForDeepLink;
}

@Override
public void logException(Exception exception, Map<String, String> eventData, String message) {
if (mKitManager != null) {
Expand Down Expand Up @@ -257,7 +280,7 @@ public boolean onMessageReceived(Context context, Intent intent) {

@Override
public boolean onPushRegistration(String instanceId, String senderId) {
if (!queueEvents && mKitManager != null) {
if (getKitsLoaded() && mKitManager != null) {
mKitManager.onPushRegistration(instanceId, senderId);
}else {
registerForPush = true;
Expand Down
Loading