-
Notifications
You must be signed in to change notification settings - Fork 28
feat: add Expo config plugin for mParticle integration and create Expo test app #270
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
base: main
Are you sure you want to change the base?
Conversation
…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.
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.
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.
| const kitDependencies = props.androidKits | ||
| .map(kit => ` implementation "com.mparticle:${kit}:+"`) |
Copilot
AI
Dec 2, 2025
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 "+" 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.
| 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 ''; | |
| }) |
| 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' | ||
| ); | ||
| } |
Copilot
AI
Dec 2, 2025
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.
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.
| "iosApiKey": "YOUR_IOS_API_KEY", | ||
| "iosApiSecret": "YOUR_IOS_API_SEC", | ||
| "androidApiKey": "YOUR_ANDROID_API_KEY", | ||
| "androidApiSecret": "YOUR_ANDROID_API_SEC", |
Copilot
AI
Dec 2, 2025
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.
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.
| "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", |
| "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", |
Copilot
AI
Dec 2, 2025
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 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"
| "prepare": "yarn clean && yarn build; yarn build:plugin", | |
| "prepare": "yarn clean && yarn build && yarn build:plugin", |
| const KIT_TRANSITIVE_DEPENDENCIES: Record<string, string[]> = { | ||
| 'mParticle-Rokt': ['Rokt-Widget'], | ||
| // Add other kit dependencies here as needed | ||
| // "mParticle-Amplitude": [], | ||
| // "mParticle-Braze": [], | ||
| }; |
Copilot
AI
Dec 2, 2025
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 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.
| ### 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`) | |
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.
@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.
| /** | ||
| * Apply all Android-specific mParticle configurations | ||
| */ | ||
| export const withMParticleAndroid: ConfigPlugin<MParticlePluginProps> = ( |
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.
@Mansi-mParticle please have a look and verify the Android code generation in this file.
| /** | ||
| * Apply all iOS-specific mParticle configurations | ||
| */ | ||
| export const withMParticleIOS: ConfigPlugin<MParticlePluginProps> = ( |
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.
@BrandonStalnaker please have a look and verify the iOS code generation in this file.
Summary
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