-
Notifications
You must be signed in to change notification settings - Fork 0
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
[MOB-2255] Integrate new Merchant Library into mParticle #1
Conversation
if (referrerValue == null) { | ||
return; | ||
@Override | ||
public List<ReportingMessage> logEvent(CommerceEvent event) { |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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?
There was a problem hiding this 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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ecgreb Thoughts on this?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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")) { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is final still needed?
@najmsheikh I updated |
} | ||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { | ||
throw new IllegalArgumentException( |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
197a2fe
to
f2d86a0
Compare
There was a problem hiding this 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' |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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.
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
There was a problem hiding this 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 { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No idea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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:
button
internal packageINSTALL_REFERRER
) intents for attribution.Using cart line item totals to create and track anOrder
only when a purchase is notified.Discarding the current session and all persisted data on mParticle session conclusion.