Skip to content

Conversation

@thomson-t
Copy link
Contributor

Summary

  • Introduced a new Expo config plugin to facilitate mParticle SDK integration for both iOS and Android.
  • Created an Expo test app to demonstrate the usage of the mParticle SDK, including event logging and Rokt placements.
  • Updated onboarding documentation to include instructions for using the new plugin and test app.

Testing Plan

Tested locally
iOS

Simulator.Screen.Recording.-.iPhone.17.Pro.-.2025-12-02.at.10.30.56.mov

Android

Screen_recording_20251202_110907.webm

Master Issue

Closes ticket

…o test app

- Introduced a new Expo config plugin to facilitate mParticle SDK integration for both iOS and Android.
- Created an Expo test app to demonstrate the usage of the mParticle SDK, including event logging and Rokt placements.
- Updated onboarding documentation to include instructions for using the new plugin and test app.
@thomson-t thomson-t requested a review from a team as a code owner December 2, 2025 17:56
Copilot AI review requested due to automatic review settings December 2, 2025 17:56
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an Expo config plugin for the mParticle React Native SDK, enabling automated native configuration for Expo projects. The implementation supports both iOS and Android platforms with automatic code injection for SDK initialization, kit dependencies, and platform-specific build configurations.

Key Changes:

  • Expo config plugin with platform-specific modules for iOS (Swift/Objective-C) and Android (Kotlin/Java) code generation
  • ExpoTestApp demonstrating plugin usage with mParticle SDK features and Rokt placements
  • Comprehensive documentation updates including plugin configuration options and integration guides

Reviewed changes

Copilot reviewed 17 out of 21 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
plugin/tsconfig.json TypeScript configuration for the Expo plugin
plugin/src/withMParticle.ts Main plugin entry point with configuration interface and validation
plugin/src/withMParticleIOS.ts iOS-specific configuration including AppDelegate modification and Podfile updates
plugin/src/withMParticleAndroid.ts Android-specific configuration including MainApplication and build.gradle modification
app.plugin.js Plugin export module for Expo integration
package.json Added plugin build scripts, files list, and Expo dependencies
README.md Added comprehensive Expo setup instructions and plugin configuration documentation
ONBOARDING.md Added ExpoTestApp setup and development workflow documentation
ExpoTestApp/* Complete Expo test application with mParticle and Rokt integration examples
js/rokt/rokt-layout-view.android.tsx Type casting fix for React compatibility

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +329 to +330
const kitDependencies = props.androidKits
.map(kit => ` implementation "com.mparticle:${kit}:+"`)
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

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

Using "+" as the version specifier for kit dependencies could lead to unexpected behavior if kits release breaking changes. Consider documenting this choice or allowing users to specify versions explicitly through the plugin configuration.

Suggested change
const kitDependencies = props.androidKits
.map(kit => ` implementation "com.mparticle:${kit}:+"`)
// Allow users to specify kit versions explicitly via plugin configuration.
// Each entry in androidKits can be either a string (kit name, uses '+') or an object { name, version }.
const kitDependencies = props.androidKits
.map(kit => {
if (typeof kit === 'string') {
// Default to '+' for backward compatibility, but document the risk.
return ` implementation "com.mparticle:${kit}:+" // Consider specifying a version to avoid breaking changes`;
} else if (kit && typeof kit === 'object' && kit.name) {
const version = kit.version || '+';
return ` implementation "com.mparticle:${kit.name}:${version}"${version === '+' ? ' // Consider specifying a version to avoid breaking changes' : ''}`;
}
return '';
})

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +95
const withMParticle: ConfigPlugin<MParticlePluginProps> = (config, props) => {
// Validate required props
if (!props.iosApiKey || !props.iosApiSecret) {
throw new Error(
'react-native-mparticle plugin requires iosApiKey and iosApiSecret'
);
}
if (!props.androidApiKey || !props.androidApiSecret) {
throw new Error(
'react-native-mparticle plugin requires androidApiKey and androidApiSecret'
);
}
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

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

API keys and secrets are directly embedded in generated native code without obfuscation. This is documented behavior, but consider adding a warning in the README that these credentials will be visible in the app binary and version control (in generated native projects). Developers should use workspace-specific keys, not production keys.

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +36
"iosApiKey": "YOUR_IOS_API_KEY",
"iosApiSecret": "YOUR_IOS_API_SEC",
"androidApiKey": "YOUR_ANDROID_API_KEY",
"androidApiSecret": "YOUR_ANDROID_API_SEC",
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

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

Placeholder API credentials should not be committed to the repository. Consider using environment variables or a template file (e.g., app.json.example) with dummy values, and document that developers need to replace these with their actual credentials.

Suggested change
"iosApiKey": "YOUR_IOS_API_KEY",
"iosApiSecret": "YOUR_IOS_API_SEC",
"androidApiKey": "YOUR_ANDROID_API_KEY",
"androidApiSecret": "YOUR_ANDROID_API_SEC",
"iosApiKey": "REPLACE_ME",
"iosApiSecret": "REPLACE_ME",
"androidApiKey": "REPLACE_ME",
"androidApiSecret": "REPLACE_ME",

Copilot uses AI. Check for mistakes.
"prepare": "yarn clean && yarn build",
"dev:pack": "yarn build && yarn pack --filename react-native-mparticle-latest.tgz",
"clean:plugin": "rm -rf plugin/build",
"prepare": "yarn clean && yarn build; yarn build:plugin",
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

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

The prepare script uses a semicolon instead of && to chain commands. This means if the first build fails, the plugin build will still execute. Use && for proper error propagation: "prepare": "yarn clean && yarn build && yarn build:plugin"

Suggested change
"prepare": "yarn clean && yarn build; yarn build:plugin",
"prepare": "yarn clean && yarn build && yarn build:plugin",

Copilot uses AI. Check for mistakes.
Comment on lines +340 to +345
const KIT_TRANSITIVE_DEPENDENCIES: Record<string, string[]> = {
'mParticle-Rokt': ['Rokt-Widget'],
// Add other kit dependencies here as needed
// "mParticle-Amplitude": [],
// "mParticle-Braze": [],
};
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

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

The KIT_TRANSITIVE_DEPENDENCIES mapping should be documented or moved to configuration. If new kits are added in the future, this hardcoded mapping needs to be updated. Consider adding a comment explaining how developers can extend this if they encounter dependency issues with other kits.

Copilot uses AI. Check for mistakes.
Comment on lines +72 to +86
### Plugin Configuration Options

| Option | Type | Required | Description |
| ------------------------- | -------- | -------- | ------------------------------------------------------------------- |
| `iosApiKey` | string | Yes | iOS API key from mParticle dashboard |
| `iosApiSecret` | string | Yes | iOS API secret from mParticle dashboard |
| `androidApiKey` | string | Yes | Android API key from mParticle dashboard |
| `androidApiSecret` | string | Yes | Android API secret from mParticle dashboard |
| `logLevel` | string | No | Log level: `'none'`, `'error'`, `'warning'`, `'debug'`, `'verbose'` |
| `environment` | string | No | Environment: `'development'`, `'production'`, `'autoDetect'` |
| `dataPlanId` | string | No | Data plan ID for validation |
| `dataPlanVersion` | number | No | Data plan version |
| `iosKits` | string[] | No | iOS kit pod names (e.g., `['mParticle-Rokt']`) |
| `androidKits` | string[] | No | Android kit artifact names (e.g., `['android-rokt-kit']`) |
| `useEmptyIdentifyRequest` | boolean | No | Use empty user identify request at init (default: `true`) |
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rmi22186 these are the plugin configurations that I added for now. Please have a look and let me know if this makes sense and if we need to add/remove anything.

Comment on lines +348 to +351
/**
* Apply all Android-specific mParticle configurations
*/
export const withMParticleAndroid: ConfigPlugin<MParticlePluginProps> = (
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Mansi-mParticle please have a look and verify the Android code generation in this file.

Comment on lines +448 to +451
/**
* Apply all iOS-specific mParticle configurations
*/
export const withMParticleIOS: ConfigPlugin<MParticlePluginProps> = (
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@BrandonStalnaker please have a look and verify the iOS code generation in this file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants