react-native-mparticle 2.8.1 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +252 -94
  2. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  3. package/android/gradle/wrapper/gradle-wrapper.properties +6 -0
  4. package/android/gradle.properties +26 -0
  5. package/android/gradlew +160 -0
  6. package/android/gradlew.bat +90 -0
  7. package/android/libs/java-json.jar +0 -0
  8. package/android/src/main/java/com/mparticle/react/MParticleModule.kt +1 -1
  9. package/android/src/test/java/com/mparticle/react/IdentityApiTest.java +230 -0
  10. package/android/src/test/java/com/mparticle/react/MParticleUserTest.java +173 -0
  11. package/android/src/test/java/com/mparticle/react/testutils/MockMParticleUser.java +109 -0
  12. package/android/src/test/java/com/mparticle/react/testutils/MockMap.java +203 -0
  13. package/android/src/test/java/com/mparticle/react/testutils/MockReadableArray.java +68 -0
  14. package/android/src/test/java/com/mparticle/react/testutils/MockWritableMap.java +4 -0
  15. package/android/src/test/java/com/mparticle/react/testutils/Mutable.java +13 -0
  16. package/app.plugin.js +1 -0
  17. package/ios/RNMParticle/RNMPRokt.mm +93 -20
  18. package/ios/RNMParticle/RNMParticle.mm +2 -1
  19. package/ios/RNMParticle/RoktEventManager.m +24 -0
  20. package/js/codegenSpecs/NativeMParticle.ts +3 -4
  21. package/js/rokt/rokt-layout-view.android.tsx +2 -1
  22. package/lib/codegenSpecs/NativeMParticle.d.ts +3 -4
  23. package/lib/codegenSpecs/NativeMParticle.js.map +1 -1
  24. package/lib/rokt/rokt-layout-view.android.js +1 -0
  25. package/lib/rokt/rokt-layout-view.android.js.map +1 -1
  26. package/package.json +28 -4
  27. package/plugin/build/withMParticle.d.ts +60 -0
  28. package/plugin/build/withMParticle.js +30 -0
  29. package/plugin/build/withMParticleAndroid.d.ts +6 -0
  30. package/plugin/build/withMParticleAndroid.js +266 -0
  31. package/plugin/build/withMParticleIOS.d.ts +6 -0
  32. package/plugin/build/withMParticleIOS.js +362 -0
  33. package/plugin/src/withMParticle.ts +106 -0
  34. package/plugin/src/withMParticleAndroid.ts +359 -0
  35. package/plugin/src/withMParticleIOS.ts +459 -0
  36. package/plugin/tsconfig.json +8 -0
  37. package/react-native-mparticle.podspec +11 -0
  38. package/SECURITY.md +0 -9
@@ -0,0 +1,362 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.withMParticleIOS = void 0;
27
+ const config_plugins_1 = require("@expo/config-plugins");
28
+ const generateCode_1 = require("@expo/config-plugins/build/utils/generateCode");
29
+ const fs = __importStar(require("fs"));
30
+ const path = __importStar(require("path"));
31
+ // Tag used for mergeContents to identify code blocks added by this plugin
32
+ const MPARTICLE_TAG = 'react-native-mparticle';
33
+ /**
34
+ * Get the mParticle log level for iOS (Swift syntax)
35
+ */
36
+ function getSwiftLogLevel(logLevel) {
37
+ switch (logLevel) {
38
+ case 'none':
39
+ return '.none';
40
+ case 'error':
41
+ return '.error';
42
+ case 'warning':
43
+ return '.warning';
44
+ case 'debug':
45
+ return '.debug';
46
+ case 'verbose':
47
+ return '.verbose';
48
+ default:
49
+ return null;
50
+ }
51
+ }
52
+ /**
53
+ * Get the mParticle environment for iOS (Swift syntax)
54
+ */
55
+ function getSwiftEnvironment(environment) {
56
+ switch (environment) {
57
+ case 'development':
58
+ return '.development';
59
+ case 'production':
60
+ return '.production';
61
+ case 'autoDetect':
62
+ return '.autoDetect';
63
+ default:
64
+ return null;
65
+ }
66
+ }
67
+ /**
68
+ * Get the mParticle log level for iOS (Objective-C syntax)
69
+ */
70
+ function getObjcLogLevel(logLevel) {
71
+ switch (logLevel) {
72
+ case 'none':
73
+ return 'MPILogLevelNone';
74
+ case 'error':
75
+ return 'MPILogLevelError';
76
+ case 'warning':
77
+ return 'MPILogLevelWarning';
78
+ case 'debug':
79
+ return 'MPILogLevelDebug';
80
+ case 'verbose':
81
+ return 'MPILogLevelVerbose';
82
+ default:
83
+ return null;
84
+ }
85
+ }
86
+ /**
87
+ * Get the mParticle environment for iOS (Objective-C syntax)
88
+ */
89
+ function getObjcEnvironment(environment) {
90
+ switch (environment) {
91
+ case 'development':
92
+ return 'MPEnvironmentDevelopment';
93
+ case 'production':
94
+ return 'MPEnvironmentProduction';
95
+ case 'autoDetect':
96
+ return 'MPEnvironmentAutoDetect';
97
+ default:
98
+ return null;
99
+ }
100
+ }
101
+ /**
102
+ * Generate mParticle initialization code for Swift AppDelegate
103
+ */
104
+ function generateSwiftInitCode(props) {
105
+ const { iosApiKey, iosApiSecret, logLevel, environment, useEmptyIdentifyRequest = true, dataPlanId, dataPlanVersion, } = props;
106
+ const lines = [
107
+ '// mParticle SDK initialization',
108
+ `let mParticleOptions = MParticleOptions(key: "${iosApiKey}", secret: "${iosApiSecret}")`,
109
+ ];
110
+ const swiftLogLevel = getSwiftLogLevel(logLevel);
111
+ if (swiftLogLevel) {
112
+ lines.push(`mParticleOptions.logLevel = ${swiftLogLevel}`);
113
+ }
114
+ const swiftEnvironment = getSwiftEnvironment(environment);
115
+ if (swiftEnvironment) {
116
+ lines.push(`mParticleOptions.environment = ${swiftEnvironment}`);
117
+ }
118
+ if (dataPlanId) {
119
+ lines.push(`mParticleOptions.dataPlanId = "${dataPlanId}"`);
120
+ if (dataPlanVersion) {
121
+ lines.push(`mParticleOptions.dataPlanVersion = ${dataPlanVersion} as NSNumber`);
122
+ }
123
+ }
124
+ if (useEmptyIdentifyRequest) {
125
+ lines.push('let identifyRequest = MPIdentityApiRequest.withEmptyUser()');
126
+ lines.push('mParticleOptions.identifyRequest = identifyRequest');
127
+ }
128
+ lines.push('MParticle.sharedInstance().start(with: mParticleOptions)');
129
+ return lines.join('\n ');
130
+ }
131
+ /**
132
+ * Generate mParticle initialization code for Objective-C AppDelegate
133
+ */
134
+ function generateObjcInitCode(props) {
135
+ const { iosApiKey, iosApiSecret, logLevel, environment, useEmptyIdentifyRequest = true, dataPlanId, dataPlanVersion, } = props;
136
+ const lines = [
137
+ '// mParticle SDK initialization',
138
+ `MParticleOptions *mParticleOptions = [MParticleOptions optionsWithKey:@"${iosApiKey}"`,
139
+ ` secret:@"${iosApiSecret}"];`,
140
+ ];
141
+ const objcLogLevel = getObjcLogLevel(logLevel);
142
+ if (objcLogLevel) {
143
+ lines.push(`mParticleOptions.logLevel = ${objcLogLevel};`);
144
+ }
145
+ const objcEnvironment = getObjcEnvironment(environment);
146
+ if (objcEnvironment) {
147
+ lines.push(`mParticleOptions.environment = ${objcEnvironment};`);
148
+ }
149
+ if (dataPlanId) {
150
+ lines.push(`mParticleOptions.dataPlanId = @"${dataPlanId}";`);
151
+ if (dataPlanVersion) {
152
+ lines.push(`mParticleOptions.dataPlanVersion = @(${dataPlanVersion});`);
153
+ }
154
+ }
155
+ if (useEmptyIdentifyRequest) {
156
+ lines.push('MPIdentityApiRequest *identifyRequest = [MPIdentityApiRequest requestWithEmptyUser];');
157
+ lines.push('mParticleOptions.identifyRequest = identifyRequest;');
158
+ }
159
+ lines.push('[[MParticle sharedInstance] startWithOptions:mParticleOptions];');
160
+ return lines.join('\n ');
161
+ }
162
+ /**
163
+ * Add mParticle configuration to AppDelegate
164
+ * Handles both Swift and Objective-C/Objective-C++
165
+ */
166
+ const withMParticleAppDelegate = (config, props) => {
167
+ return (0, config_plugins_1.withAppDelegate)(config, config => {
168
+ const { contents, language } = config.modResults;
169
+ // Check if mParticle is already initialized
170
+ if (contents.includes('MParticleOptions') ||
171
+ contents.includes('mParticleOptions')) {
172
+ return config;
173
+ }
174
+ if (language === 'swift') {
175
+ config.modResults.contents = addMParticleToSwiftAppDelegate(contents, props);
176
+ }
177
+ else if (language === 'objc' || language === 'objcpp') {
178
+ config.modResults.contents = addMParticleToObjcAppDelegate(contents, props);
179
+ }
180
+ else {
181
+ console.warn(`[react-native-mparticle] Unsupported AppDelegate language: ${language}. ` +
182
+ 'mParticle initialization must be added manually.');
183
+ }
184
+ return config;
185
+ });
186
+ };
187
+ /**
188
+ * Add mParticle import and initialization to Swift AppDelegate
189
+ */
190
+ function addMParticleToSwiftAppDelegate(contents, props) {
191
+ // Add import statement
192
+ // Use mergeContents for safe, idempotent code injection
193
+ const withImport = (0, generateCode_1.mergeContents)({
194
+ src: contents,
195
+ newSrc: 'import mParticle_Apple_SDK',
196
+ anchor: /import Expo/,
197
+ offset: 1,
198
+ tag: `${MPARTICLE_TAG}-import`,
199
+ comment: '//',
200
+ });
201
+ // Generate initialization code
202
+ const initCode = generateSwiftInitCode(props);
203
+ // Find the right place to add initialization code
204
+ // For Expo SDK 53+, it should be in didFinishLaunchingWithOptions before the return
205
+ // Look for the return super.application pattern
206
+ const withInit = (0, generateCode_1.mergeContents)({
207
+ src: withImport.contents,
208
+ newSrc: `\n ${initCode}\n`,
209
+ anchor: /return super\.application\(application, didFinishLaunchingWithOptions: launchOptions\)/,
210
+ offset: 0,
211
+ tag: `${MPARTICLE_TAG}-init`,
212
+ comment: '//',
213
+ });
214
+ return withInit.contents;
215
+ }
216
+ /**
217
+ * Add mParticle import and initialization to Objective-C AppDelegate
218
+ */
219
+ function addMParticleToObjcAppDelegate(contents, props) {
220
+ // Add import statement after React import or first import
221
+ const withImport = (0, generateCode_1.mergeContents)({
222
+ src: contents,
223
+ newSrc: '#import "mParticle.h"',
224
+ anchor: /#import <React\/RCTBundleURLProvider\.h>|#import "AppDelegate\.h"/,
225
+ offset: 1,
226
+ tag: `${MPARTICLE_TAG}-import`,
227
+ comment: '//',
228
+ });
229
+ // Generate initialization code
230
+ const initCode = generateObjcInitCode(props);
231
+ // Try different patterns for where to insert the init code
232
+ let result = withImport.contents;
233
+ // Pattern 1: Expo's return [super application...
234
+ if (result.includes('return [super application:application didFinishLaunchingWithOptions:launchOptions];')) {
235
+ const withInit = (0, generateCode_1.mergeContents)({
236
+ src: result,
237
+ newSrc: `\n ${initCode}\n`,
238
+ anchor: /return \[super application:application didFinishLaunchingWithOptions:launchOptions\];/,
239
+ offset: 0,
240
+ tag: `${MPARTICLE_TAG}-init`,
241
+ comment: '//',
242
+ });
243
+ result = withInit.contents;
244
+ }
245
+ // Pattern 2: self.initialProps = @{};
246
+ else if (result.includes('self.initialProps = @{};')) {
247
+ const withInit = (0, generateCode_1.mergeContents)({
248
+ src: result,
249
+ newSrc: `\n ${initCode}\n`,
250
+ anchor: /self\.initialProps = @\{\};/,
251
+ offset: 1,
252
+ tag: `${MPARTICLE_TAG}-init`,
253
+ comment: '//',
254
+ });
255
+ result = withInit.contents;
256
+ }
257
+ // Pattern 3: return YES;
258
+ else if (result.includes('return YES;')) {
259
+ const withInit = (0, generateCode_1.mergeContents)({
260
+ src: result,
261
+ newSrc: `\n ${initCode}\n`,
262
+ anchor: /return YES;/,
263
+ offset: 0,
264
+ tag: `${MPARTICLE_TAG}-init`,
265
+ comment: '//',
266
+ });
267
+ result = withInit.contents;
268
+ }
269
+ return result;
270
+ }
271
+ /**
272
+ * Known transitive dependencies that need dynamic linking for each kit
273
+ * These are dependencies of mParticle kits that must also be dynamic frameworks
274
+ */
275
+ const KIT_TRANSITIVE_DEPENDENCIES = {
276
+ 'mParticle-Rokt': ['Rokt-Widget'],
277
+ // Add other kit dependencies here as needed
278
+ // "mParticle-Amplitude": [],
279
+ // "mParticle-Braze": [],
280
+ };
281
+ /**
282
+ * Get all pods that need dynamic framework linking
283
+ */
284
+ function getDynamicFrameworkPods(iosKits) {
285
+ const pods = ['mParticle-Apple-SDK'];
286
+ if (iosKits) {
287
+ for (const kit of iosKits) {
288
+ pods.push(kit);
289
+ // Add transitive dependencies for this kit
290
+ const transitiveDeps = KIT_TRANSITIVE_DEPENDENCIES[kit];
291
+ if (transitiveDeps) {
292
+ pods.push(...transitiveDeps);
293
+ }
294
+ }
295
+ }
296
+ return [...new Set(pods)]; // Remove duplicates
297
+ }
298
+ /**
299
+ * Add kit pods and pre_install hook to Podfile
300
+ */
301
+ const withMParticlePodfile = (config, props) => {
302
+ return (0, config_plugins_1.withDangerousMod)(config, [
303
+ 'ios',
304
+ async (config) => {
305
+ const podfilePath = path.join(config.modRequest.platformProjectRoot, 'Podfile');
306
+ if (!fs.existsSync(podfilePath)) {
307
+ return config;
308
+ }
309
+ let podfileContent = fs.readFileSync(podfilePath, 'utf-8');
310
+ // Add pre_install hook for dynamic framework linking if not already present
311
+ if (!podfileContent.includes('mParticle-Apple-SDK')) {
312
+ // Get all pods that need dynamic linking (including transitive dependencies)
313
+ const dynamicPods = getDynamicFrameworkPods(props.iosKits);
314
+ const podConditions = dynamicPods
315
+ .map(pod => `pod.name == '${pod}'`)
316
+ .join(' || ');
317
+ const preInstallHook = `
318
+ # mParticle dynamic framework linking (added by react-native-mparticle expo plugin)
319
+ pre_install do |installer|
320
+ installer.pod_targets.each do |pod|
321
+ if ${podConditions}
322
+ def pod.build_type;
323
+ Pod::BuildType.new(:linkage => :dynamic, :packaging => :framework)
324
+ end
325
+ end
326
+ end
327
+ end
328
+ `;
329
+ // Add pre_install hook after platform declaration
330
+ const platformRegex = /platform :ios.*\n/;
331
+ if (platformRegex.test(podfileContent)) {
332
+ podfileContent = podfileContent.replace(platformRegex, `$&${preInstallHook}`);
333
+ }
334
+ }
335
+ // Add kit pods if specified
336
+ if (props.iosKits && props.iosKits.length > 0) {
337
+ const kitPods = props.iosKits.map(kit => ` pod '${kit}'`).join('\n');
338
+ // Check if kits are already added
339
+ const kitsAlreadyAdded = props.iosKits.every(kit => podfileContent.includes(`pod '${kit}'`));
340
+ if (!kitsAlreadyAdded) {
341
+ // Add kit pods inside the main target block
342
+ // Look for use_react_native! and add after it
343
+ const useReactNativeRegex = /(use_react_native!\([^)]*\))/s;
344
+ if (useReactNativeRegex.test(podfileContent)) {
345
+ podfileContent = podfileContent.replace(useReactNativeRegex, `$1\n\n # mParticle kits (added by react-native-mparticle expo plugin)\n${kitPods}`);
346
+ }
347
+ }
348
+ }
349
+ fs.writeFileSync(podfilePath, podfileContent);
350
+ return config;
351
+ },
352
+ ]);
353
+ };
354
+ /**
355
+ * Apply all iOS-specific mParticle configurations
356
+ */
357
+ const withMParticleIOS = (config, props) => {
358
+ config = withMParticleAppDelegate(config, props);
359
+ config = withMParticlePodfile(config, props);
360
+ return config;
361
+ };
362
+ exports.withMParticleIOS = withMParticleIOS;
@@ -0,0 +1,106 @@
1
+ import { ConfigPlugin, createRunOncePlugin } from '@expo/config-plugins';
2
+ import { withMParticleIOS } from './withMParticleIOS';
3
+ import { withMParticleAndroid } from './withMParticleAndroid';
4
+
5
+ const pkg = require('../../package.json');
6
+
7
+ /**
8
+ * mParticle plugin configuration options
9
+ */
10
+ export interface MParticlePluginProps {
11
+ /**
12
+ * iOS API key from mParticle dashboard
13
+ */
14
+ iosApiKey: string;
15
+
16
+ /**
17
+ * iOS API secret from mParticle dashboard
18
+ */
19
+ iosApiSecret: string;
20
+
21
+ /**
22
+ * Android API key from mParticle dashboard
23
+ */
24
+ androidApiKey: string;
25
+
26
+ /**
27
+ * Android API secret from mParticle dashboard
28
+ */
29
+ androidApiSecret: string;
30
+
31
+ /**
32
+ * Log level for debugging
33
+ * @default 'none'
34
+ */
35
+ logLevel?: 'none' | 'error' | 'warning' | 'debug' | 'verbose';
36
+
37
+ /**
38
+ * mParticle environment
39
+ * @default 'autoDetect'
40
+ */
41
+ environment?: 'development' | 'production' | 'autoDetect';
42
+
43
+ /**
44
+ * Data plan ID for validation
45
+ */
46
+ dataPlanId?: string;
47
+
48
+ /**
49
+ * Data plan version for validation
50
+ */
51
+ dataPlanVersion?: number;
52
+
53
+ /**
54
+ * iOS kit pod names to include
55
+ * @example ['mParticle-Rokt', 'mParticle-Amplitude']
56
+ */
57
+ iosKits?: string[];
58
+
59
+ /**
60
+ * Android kit artifact names to include (version auto-detected from core SDK)
61
+ * @example ['android-rokt-kit', 'android-amplitude-kit']
62
+ */
63
+ androidKits?: string[];
64
+
65
+ /**
66
+ * Whether to use an empty identify request at initialization
67
+ * If true or omitted, uses requestWithEmptyUser/withEmptyUser()
68
+ * If false, no identify request is made at initialization
69
+ * Identity should be updated from React Native code after initialization
70
+ * @default true
71
+ */
72
+ useEmptyIdentifyRequest?: boolean;
73
+ }
74
+
75
+ /**
76
+ * Expo Config Plugin for mParticle React Native SDK
77
+ *
78
+ * This plugin configures your Expo project to use the mParticle SDK by:
79
+ * - Adding mParticle SDK initialization to iOS AppDelegate
80
+ * - Adding mParticle SDK initialization to Android MainApplication
81
+ * - Adding kit dependencies to iOS Podfile
82
+ * - Adding kit dependencies to Android build.gradle
83
+ */
84
+ const withMParticle: ConfigPlugin<MParticlePluginProps> = (config, props) => {
85
+ // Validate required props
86
+ if (!props.iosApiKey || !props.iosApiSecret) {
87
+ throw new Error(
88
+ 'react-native-mparticle plugin requires iosApiKey and iosApiSecret'
89
+ );
90
+ }
91
+ if (!props.androidApiKey || !props.androidApiSecret) {
92
+ throw new Error(
93
+ 'react-native-mparticle plugin requires androidApiKey and androidApiSecret'
94
+ );
95
+ }
96
+
97
+ // Apply iOS modifications
98
+ config = withMParticleIOS(config, props);
99
+
100
+ // Apply Android modifications
101
+ config = withMParticleAndroid(config, props);
102
+
103
+ return config;
104
+ };
105
+
106
+ export default createRunOncePlugin(withMParticle, pkg.name, pkg.version);