Skip to content

Commit a3cdfb7

Browse files
rmi22186claude
andcommitted
feat: Update Braze SDK to 41.1.1, AGP to 8.7.3, Gradle to 8.9
Update Braze Android SDK from 37.0.0 to 41.1.1. This requires upgrading AGP from 8.1.4 to 8.7.3 and Gradle from 8.0.2 to 8.9 because Braze 41 depends on androidx.datastore 1.1.x (a Kotlin Multiplatform library) which needs AGP 8.6+ for correct Android variant resolution. Also modernizes the example app with functional test UI for verifying event logging, purchases, user attributes, and identity. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent cf075ea commit a3cdfb7

File tree

9 files changed

+275
-79
lines changed

9 files changed

+275
-79
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ buildscript {
1010
mavenCentral()
1111
}
1212
dependencies {
13-
classpath 'com.android.tools.build:gradle:8.1.4'
13+
classpath 'com.android.tools.build:gradle:8.7.3'
1414
classpath 'com.mparticle:android-kit-plugin:' + project.version
1515
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1616
}
@@ -67,6 +67,6 @@ repositories {
6767

6868
dependencies {
6969
compileOnly 'com.google.firebase:firebase-messaging:[10.2.1, )'
70-
api 'com.braze:android-sdk-ui:41.0.0'
70+
api 'com.braze:android-sdk-ui:41.1.1'
7171
testImplementation files('libs/java-json.jar')
7272
}

example/build.gradle

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,69 @@
11
/**
22
*
3-
* Example app build.gradle for using mParticle + Braze + Firebase Cloud Messaging
4-
* Please see the inline comments below.
3+
* Example app for testing mParticle + Braze kit integration.
4+
*
5+
* Usage:
6+
* - Production (Maven): ./gradlew :example:installDebug -PuseLocalKit=false
7+
* - Local kit: ./gradlew :example:installDebug -PuseLocalKit=true
8+
*
9+
* By default, useLocalKit=false (pulls from Maven Central).
510
*
611
*/
712

8-
913
apply plugin: 'com.android.application'
1014

1115
android {
12-
compileSdk 31
16+
namespace 'com.mparticle.kits.braze.example'
17+
compileSdk 35
1318

1419
defaultConfig {
15-
applicationId "com.mparticle.com.mparticle.kits.braze.example"
16-
minSdk 16
17-
targetSdk 31
20+
applicationId "com.mparticle.kits.braze.example"
21+
minSdk 21
22+
targetSdk 34
1823
versionCode 1
1924
versionName "1.0"
20-
21-
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
22-
2325
}
2426

2527
buildTypes {
2628
release {
2729
minifyEnabled false
2830
}
2931
}
32+
33+
compileOptions {
34+
sourceCompatibility JavaVersion.VERSION_17
35+
targetCompatibility JavaVersion.VERSION_17
36+
}
3037
}
3138

3239
repositories {
3340
mavenCentral()
34-
maven { url "https://appboy.github.io/appboy-android-sdk/sdk" } //REQUIRED: Braze isn't available in jCenter or Maven Central - so you need to add their Maven Server
3541
google()
3642
}
3743

38-
buildscript {
39-
repositories {
40-
//REQUIRED: com.google.gms:google-services requires both jCenter and Google's Maven :rollseyes:
41-
mavenCentral()
42-
google()
43-
}
44-
dependencies {
45-
classpath 'com.google.gms:google-services:4.2.0' //REQUIRED for Firebase
46-
}
47-
}
44+
def useLocal = project.hasProperty('useLocalKit') ? project.property('useLocalKit').toBoolean() : false
45+
4846
dependencies {
49-
implementation 'com.android.support:appcompat-v7:28.0.0'
50-
implementation 'com.android.support:support-v4:28.0.0'
51-
implementation 'com.android.support:support-media-compat:28.0.0'
52-
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
47+
implementation 'androidx.appcompat:appcompat:1.6.1'
48+
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
49+
implementation 'com.google.android.material:material:1.11.0'
5350

54-
// REQUIRED: Add the Braze (formerly Appboy) kit here
55-
// this will also pull in mParticle's Core SDK (com.mparticle:android-core) as a transitive dependency
56-
implementation 'com.mparticle:android-appboy-kit:5.6.5'
51+
if (useLocal) {
52+
// Use the local kit module (includes local changes)
53+
implementation project(':')
54+
} else {
55+
// Use the latest production kit from Maven Central
56+
implementation 'com.mparticle:android-appboy-kit:+'
57+
}
5758

58-
// REQUIRED for Firebase
59-
implementation 'com.google.firebase:firebase-messaging:17.3.4'
59+
// Optional: Firebase for push testing
60+
// implementation 'com.google.firebase:firebase-messaging:23.4.0'
6061

61-
// Not strictly required but strongly recommended so that mParticle and Braze can query for the Android Advertising ID
62-
implementation 'com.google.android.gms:play-services-ads-identifier:16.0.0'
62+
// Required by Braze SDK v41+ for SharedPreferences -> DataStore migration
63+
// AGP 8.1.x resolves the -jvm KMP variant instead of -android, so we force the Android variants
64+
implementation 'androidx.datastore:datastore-android:1.1.7'
65+
implementation 'androidx.datastore:datastore-preferences-android:1.1.7'
6366

67+
// Optional: Google Advertising ID
68+
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
6469
}
65-
66-
apply plugin: 'com.google.gms.google-services' //REQUIRED for Firebase
Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
package="com.mparticle.kits.braze.example">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
43

54
<application
65
android:allowBackup="true"
@@ -9,35 +8,16 @@
98
android:roundIcon="@mipmap/ic_launcher_round"
109
android:supportsRtl="true"
1110
android:name=".ExampleApplication"
12-
android:theme="@style/AppTheme">
11+
android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
1312

14-
<!-- This Braze receiver is necessary to react to pending Intents within push notifications -->
15-
<receiver android:name="com.braze.push.BrazePushReceiver" />
16-
17-
<!-- This mParticle receiver is necessary to register for push notification tokens -->
18-
<receiver
19-
android:name="com.mparticle.MPReceiver"
20-
android:permission="com.google.android.c2dm.permission.SEND">
21-
<intent-filter>
22-
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
23-
24-
<!-- Use your package name as the category -->
25-
<category android:name="com.mparticle.kits.braze.example" />
26-
</intent-filter>
27-
</receiver>
28-
29-
<!-- This mParticle service is necessary to listen for token-updates -->
30-
<service android:name="com.mparticle.messaging.InstanceIdService" />
31-
32-
<!-- This is the service that takes care of forwarding push registrations, receipts, and opens to Braze -->
33-
<service android:name="com.mparticle.MPService" />
34-
35-
<activity android:name=".MainActivity">
13+
<activity
14+
android:name=".MainActivity"
15+
android:exported="true">
3616
<intent-filter>
3717
<action android:name="android.intent.action.MAIN" />
3818
<category android:name="android.intent.category.LAUNCHER" />
3919
</intent-filter>
4020
</activity>
4121
</application>
4222

43-
</manifest>
23+
</manifest>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.mparticle.kits.braze.example;
2+
3+
import android.app.Application;
4+
import android.util.Log;
5+
6+
import com.mparticle.MParticle;
7+
import com.mparticle.MParticleOptions;
8+
import com.mparticle.identity.BaseIdentityTask;
9+
import com.mparticle.identity.IdentityApiRequest;
10+
11+
public class ExampleApplication extends Application {
12+
13+
private static final String TAG = "BrazeExample";
14+
15+
@Override
16+
public void onCreate() {
17+
super.onCreate();
18+
19+
IdentityApiRequest identifyRequest = IdentityApiRequest.withEmptyUser()
20+
.email("test@example.com")
21+
.build();
22+
23+
// TODO: Replace with your mParticle API key and secret
24+
MParticleOptions options = MParticleOptions.builder(this)
25+
.credentials("YOUR_MP_API_KEY", "YOUR_MP_API_SECRET")
26+
.environment(MParticle.Environment.Development)
27+
.logLevel(MParticle.LogLevel.VERBOSE)
28+
.identify(identifyRequest)
29+
.identifyTask(new BaseIdentityTask()
30+
.addSuccessListener(result -> {
31+
Log.i(TAG, "Identify SUCCESS - MPID: " + result.getUser().getId());
32+
})
33+
.addFailureListener(result -> {
34+
Log.e(TAG, "Identify FAILED - " + result.toString());
35+
})
36+
)
37+
.build();
38+
39+
MParticle.start(options);
40+
Log.i(TAG, "mParticle initialized");
41+
}
42+
}
Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,130 @@
11
package com.mparticle.kits.braze.example;
22

3-
import android.support.v7.app.AppCompatActivity;
43
import android.os.Bundle;
4+
import android.util.Log;
5+
import android.widget.Button;
6+
import android.widget.TextView;
7+
import android.widget.Toast;
8+
9+
import androidx.appcompat.app.AppCompatActivity;
10+
11+
import com.mparticle.MParticle;
12+
import com.mparticle.MPEvent;
13+
import com.mparticle.MParticle.EventType;
14+
import com.mparticle.commerce.CommerceEvent;
15+
import com.mparticle.commerce.Product;
16+
import com.mparticle.commerce.TransactionAttributes;
17+
import com.mparticle.identity.MParticleUser;
18+
19+
import java.util.HashMap;
20+
import java.util.Map;
521

622
public class MainActivity extends AppCompatActivity {
723

24+
private static final String TAG = "BrazeExample";
25+
private TextView statusText;
26+
827
@Override
928
protected void onCreate(Bundle savedInstanceState) {
1029
super.onCreate(savedInstanceState);
1130
setContentView(R.layout.activity_main);
31+
32+
statusText = findViewById(R.id.status_text);
33+
updateStatus();
34+
35+
// Refresh MPID status on tap
36+
statusText.setOnClickListener(v -> updateStatus());
37+
38+
findViewById(R.id.btn_custom_event).setOnClickListener(v -> logCustomEvent());
39+
findViewById(R.id.btn_custom_event_attrs).setOnClickListener(v -> logCustomEventWithAttributes());
40+
findViewById(R.id.btn_purchase).setOnClickListener(v -> logPurchase());
41+
findViewById(R.id.btn_set_user_attr).setOnClickListener(v -> setUserAttributes());
42+
findViewById(R.id.btn_set_identity).setOnClickListener(v -> setUserIdentity());
43+
findViewById(R.id.btn_upload).setOnClickListener(v -> forceUpload());
44+
}
45+
46+
private void updateStatus() {
47+
MParticle instance = MParticle.getInstance();
48+
if (instance != null) {
49+
MParticleUser user = instance.Identity().getCurrentUser();
50+
String mpid = user != null ? String.valueOf(user.getId()) : "N/A";
51+
String email = "N/A";
52+
if (user != null) {
53+
String e = user.getUserIdentities().get(MParticle.IdentityType.Email);
54+
if (e != null) email = e;
55+
}
56+
statusText.setText("mParticle: Active | MPID: " + mpid + "\nEmail: " + email);
57+
} else {
58+
statusText.setText("mParticle: Not initialized");
59+
}
60+
}
61+
62+
private void logCustomEvent() {
63+
MPEvent event = new MPEvent.Builder("Test Event", EventType.Other).build();
64+
MParticle.getInstance().logEvent(event);
65+
toast("Logged: Test Event");
66+
}
67+
68+
private void logCustomEventWithAttributes() {
69+
Map<String, String> attrs = new HashMap<>();
70+
attrs.put("category", "testing");
71+
attrs.put("value", "42");
72+
73+
MPEvent event = new MPEvent.Builder("Test Event With Attrs", EventType.Other)
74+
.customAttributes(attrs)
75+
.build();
76+
MParticle.getInstance().logEvent(event);
77+
toast("Logged: Test Event With Attrs");
78+
}
79+
80+
private void logPurchase() {
81+
Product product = new Product.Builder("Test Product", "test-sku-123", 19.99)
82+
.quantity(1)
83+
.build();
84+
85+
TransactionAttributes transaction = new TransactionAttributes("txn-001")
86+
.setRevenue(19.99);
87+
88+
CommerceEvent event = new CommerceEvent.Builder(Product.PURCHASE, product)
89+
.transactionAttributes(transaction)
90+
.build();
91+
92+
MParticle.getInstance().logEvent(event);
93+
toast("Logged: Purchase ($19.99)");
94+
}
95+
96+
private void setUserAttributes() {
97+
MParticleUser user = MParticle.getInstance().Identity().getCurrentUser();
98+
if (user != null) {
99+
user.setUserAttribute("$FirstName", "Test");
100+
user.setUserAttribute("$LastName", "User");
101+
user.setUserAttribute("custom_attr", "hello_braze");
102+
toast("Set user attributes");
103+
} else {
104+
toast("No current user");
105+
}
106+
}
107+
108+
private void setUserIdentity() {
109+
MParticle.getInstance().Identity().getCurrentUser();
110+
com.mparticle.identity.IdentityApiRequest request =
111+
com.mparticle.identity.IdentityApiRequest.withEmptyUser()
112+
.email("test@example.com")
113+
.customerId("test-customer-123")
114+
.build();
115+
116+
MParticle.getInstance().Identity().modify(request);
117+
toast("Set email + customerId");
118+
updateStatus();
119+
}
120+
121+
private void forceUpload() {
122+
MParticle.getInstance().upload();
123+
toast("Upload triggered");
124+
}
125+
126+
private void toast(String msg) {
127+
Log.i(TAG, msg);
128+
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
12129
}
13130
}

0 commit comments

Comments
 (0)