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

[MOB-2255] Integrate new Merchant Library into mParticle #1

Merged
merged 7 commits into from
Sep 12, 2018

Conversation

najmsheikh
Copy link

@najmsheikh najmsheikh commented Aug 15, 2018

Since we recently migrated merchant relevant functionality into the Button Merchant Library, our mParticle Kit needed to be updated to account for such changes.

Changes such as:

  • Removing the now outdated button internal package
  • Handling any pending post-install intents when the Kit is created.
  • Handling incoming third-party intents directly and not relying on Play Store (INSTALL_REFERRER) intents for attribution.
  • Using cart line item totals to create and track an Order only when a purchase is notified.
  • Discarding the current session and all persisted data on mParticle session conclusion.
  • Providing direct access to the Merchant Library API. (Edit: Attribution token only, for now)

@najmsheikh najmsheikh self-assigned this Aug 15, 2018
if (referrerValue == null) {
return;
@Override
public List<ReportingMessage> logEvent(CommerceEvent event) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything Button specific that we want to include in the ReportingMessage to mParticle?

build.gradle Outdated
@@ -16,3 +22,7 @@ android {
consumerProguardFiles 'consumer-proguard.pro'
}
}

dependencies {
api 'com.usebutton.merchant:button-merchant:1.0.0'
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using api instead of implementation allows the consumer of this Kit also have access to the Button Merchant Library. Is that something we want or do we want to completely abstract away the Merchant Library from the consumer?

Copy link

@Jon6193 Jon6193 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few comments but code looks good

}
ButtonMerchant.configure(ctx, applicationId);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend passing in the applicationContext instead of context to combat potential memory leaks

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This context (and any via the getContext() method) is managed by the mParticle Core SDK itself. I'd lean on the assumption that Core is handling 'lifecycle' properly. And since this isn't an Activity, the application context isn't available. Unless you meant to extract it from the passed context itself?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah extract it from the passed context itself getContext().getApplicationContext() This is definitely under the assumption that mParticle is handling the lifecycle properly but I think we should do our due diligence to not contribute to the issue if they are mis-managing the context they're passing to us

if (referrer.equals(mStorage.getReferrer())) return;
mStorage.setReferrer(referrer);
}
long orderTotal = Math.round(total * 100);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would only work for USD correct? @ecgreb thoughts on this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most countries are at hundredths place. The most notable exceptions would be the Japanese Yen or the South Korean Won -- both of which are base currency units.

logDebug("Beginning to track order %s", event.getTransactionAttributes().getId());

Order order = prepareOrder(event);
ButtonMerchant.trackOrder(getContext(), order, new UserActivityListener() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially add a getApplicationContext() method to replace getContext() methods so we can ensure that we aren't causing any memory leaks

build.gradle Outdated
@@ -16,3 +22,7 @@ android {
consumerProguardFiles 'consumer-proguard.pro'
}
}

dependencies {
api 'com.usebutton.merchant:button-merchant:1.0.0'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use implementation @ecgreb let me know what you think about this

Copy link
Author

@najmsheikh najmsheikh Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The consumer would need to do twice the setup (e.g. mParticle ButtonKit retrieves the app ID from the mParticle dashboard while the merchant library retrieves it directly) if plan on using the Merchant Library directly.

I do wonder if it'll use the ButtonMerchant instance configured from mParticle or not. Could be a race condition too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ecgreb Thoughts on this?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we would want partners calling configure() again on a separate instance but it could still be powerful to give them access to the underlying instance that is powering the integration. Is there any way to do this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we don't provide direct access to the instance, we have wrapper methods that allow access to key merchant library API.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On another note, would we want to use a wildcard versioning for only 1.x of the Merchant Library dependency? Since we only make API breaking changes on major versions. This'll allow the mParticle ButtonKit to get the latest of bug fixes for free without manually having to increment the version upon every Merchant Library update.

if (intent.getData() != null && intent.getData().getQueryParameter("btn_ref") != null) {
logDebug("Tracking incoming intent as %s", intent.toString());
ButtonMerchant.trackIncomingIntent(getContext(), intent);
if (intent.getExtras() != null && intent.hasExtra("referrer")) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this line needed? The merchant library should handle all of this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The library does not have a check for this. Is there a scenario where the intent would be valid without a referrer?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this line should be removed completely and there should only be a null check on the intent

new ButtonMerchant.AttributionTokenListener() {
@Override
public void onAttributionTokenChanged(@NonNull String s) {
public void onAttributionTokenChanged(@NonNull final String s) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is final still needed?

@ecgreb
Copy link

ecgreb commented Aug 23, 2018

@najmsheikh I updated master to include the latest changes from upstream so this branch can now be rebased.

}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
throw new IllegalArgumentException(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should silently disable and log an error rather that throwing an exception here since this could crash the merchant app.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is mParticle's prescribed way of notifying the core SDK that our Kit cannot be initialized. I would have thrown a different exception but the parent class only seems to "support" this one.

} else if (throwable != null) {
logError("Error checking post install intent", throwable);
} else {
logError("Neither an Intent nor a Throwable is available post-install");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not an error state but expected if the request successfully completes and no post install deep link was found.

public void setInstallReferrer(Intent intent) {
if (intent != null) {
logDebug("Tracking incoming intent from %s", intent.toString());
ButtonMerchant.trackIncomingIntent(getApplicationContext(), intent);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Install referrer intent comes from the play store and does not contain the attribution token. This functionality has been removed and no longer needs to be tracked.

@najmsheikh najmsheikh force-pushed the najm/MOB-2255-integrate-merchant-library-mparticle branch from 197a2fe to f2d86a0 Compare August 23, 2018 21:03
Copy link

@ecgreb ecgreb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @najmsheikh :) I added a few comments below but overall implementation looks good.

I realize there were no existing tests for this project, however it seems like we would be doing ourselves a disservice if we didn't add at least basic unit test coverage for the logic in the ButtonKit class.

build.gradle Outdated
@@ -16,3 +22,7 @@ android {
consumerProguardFiles 'consumer-proguard.pro'
}
}

dependencies {
api 'com.usebutton.merchant:button-merchant:1.0.0'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we would want partners calling configure() again on a separate instance but it could still be powerful to give them access to the underlying instance that is powering the integration. Is there any way to do this?


private static void logError(String message) {
if (MParticle.getInstance().getEnvironment() == MParticle.Environment.Development) {
Logger.error("ButtonKit: " + message);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it makes sense to only log debug messages in Development, shouldn't we also log errors in production?


@Override
public List<ReportingMessage> onActivityDestroyed(final Activity activity) { return null; }
public List<ReportingMessage> onActivityStarted(Activity activity) {
return null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should call trackIncomingIntent() in both onActivityCreated() and onActivityStarted() to account for the case where the merchant app is open but in the background and a new deep link is sent from the publisher app.

najmsheikh and others added 5 commits August 30, 2018 15:25
This commit attempts to maintain feature parity with previous ButtonKit
version by interacting with the `KitManager` in the same way on
attribution token changes and on post-install deep links.

* Attribution token changes invoke `setIntegrationAttributes()` on kit
* Post-install deep links no longer start the activity
* Post-install deep links sets `AttributionResult` on kit manager
* No post-install deep link sets `AttributionError` on kit manager
* Debug logging check removed since handled by `Logger.setMinLogLevel()`
* Adds tests for kit manager interactions
Copy link
Author

@najmsheikh najmsheikh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really glad we got testing sorted out! Just some questions/comments but looks good. We should now update the O'Christmas Tree app and run through the merchant library tests

build.gradle Outdated
@@ -9,18 +9,16 @@ buildscript {
}
}

allprojects {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project does not compile for me without the google repo

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-added

PackageManager pm = applicationContext.getPackageManager();
if (intent != null && intent.resolveActivity(pm) != null) {
logDebug("Handling post-install intent for %s", intent.toString());
AttributionResult result = new AttributionResult()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does seem to be the intended way of forwarding intent data. mParticle has a feature branch that they committed to (but didn't merge) about a month ago. Looking at that, do you think we should add parameters that house the referrer?

Another implementation

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find on that commit. I think this is something we can address when we submit the PR to mParticle. For now, I'm going to keep the kit communication as it was.

public void onAttributionTokenChanged(@NonNull String token) {
final Map<String, String> attributes = getIntegrationAttributes();
attributes.put(ATTRIBUTE_REFERRER, token);
setIntegrationAttributes(attributes);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that this in parity with the old code but where in the dashboard do these attributes reside? Is it per user, per application, per session? The javadoc wasn't quite clear on this.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea

when(context.getApplicationContext()).thenReturn(context);
when(mParticleWrapper.isDebuggingEnvironment()).thenReturn(true);
MParticle.setInstance(new TestMParticle());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏽

@NonNull
@Override
public IdentityApi Identity() {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is why we should try not to have static methods/singletons in the constructor 😬

* Declare minSdkVersion 15
* Re-add google repository for merchant library transitive dependencies
* Switch from `implementation` to `api` for merchant lib dependency
* Update "error" message when no post-install deep link is found
* Report error when post-install deep link check returns throwable
* Remove unused imports
build.gradle Outdated
@@ -9,18 +9,16 @@ buildscript {
}
}

allprojects {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-added

PackageManager pm = applicationContext.getPackageManager();
if (intent != null && intent.resolveActivity(pm) != null) {
logDebug("Handling post-install intent for %s", intent.toString());
AttributionResult result = new AttributionResult()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find on that commit. I think this is something we can address when we submit the PR to mParticle. For now, I'm going to keep the kit communication as it was.

public void onAttributionTokenChanged(@NonNull String token) {
final Map<String, String> attributes = getIntegrationAttributes();
attributes.put(ATTRIBUTE_REFERRER, token);
setIntegrationAttributes(attributes);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea

Copy link

@Jon6193 Jon6193 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ecgreb ecgreb merged commit f45f721 into master Sep 12, 2018
@ecgreb ecgreb deleted the najm/MOB-2255-integrate-merchant-library-mparticle branch September 12, 2018 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants