react-native-mparticle 2.8.0 → 2.9.0

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 (37) 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 +2 -2
  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 +25 -11
  18. package/ios/RNMParticle/RNMParticle.mm +38 -28
  19. package/js/codegenSpecs/NativeMParticle.ts +3 -4
  20. package/js/rokt/rokt-layout-view.android.tsx +2 -1
  21. package/lib/codegenSpecs/NativeMParticle.d.ts +3 -4
  22. package/lib/codegenSpecs/NativeMParticle.js.map +1 -1
  23. package/lib/rokt/rokt-layout-view.android.js +1 -0
  24. package/lib/rokt/rokt-layout-view.android.js.map +1 -1
  25. package/package.json +28 -4
  26. package/plugin/build/withMParticle.d.ts +60 -0
  27. package/plugin/build/withMParticle.js +30 -0
  28. package/plugin/build/withMParticleAndroid.d.ts +6 -0
  29. package/plugin/build/withMParticleAndroid.js +266 -0
  30. package/plugin/build/withMParticleIOS.d.ts +6 -0
  31. package/plugin/build/withMParticleIOS.js +362 -0
  32. package/plugin/src/withMParticle.ts +106 -0
  33. package/plugin/src/withMParticleAndroid.ts +359 -0
  34. package/plugin/src/withMParticleIOS.ts +459 -0
  35. package/plugin/tsconfig.json +8 -0
  36. package/react-native-mparticle.podspec +11 -0
  37. package/SECURITY.md +0 -9
@@ -0,0 +1,459 @@
1
+ import {
2
+ ConfigPlugin,
3
+ withAppDelegate,
4
+ withDangerousMod,
5
+ } from '@expo/config-plugins';
6
+ import { mergeContents } from '@expo/config-plugins/build/utils/generateCode';
7
+ import { MParticlePluginProps } from './withMParticle';
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+
11
+ // Tag used for mergeContents to identify code blocks added by this plugin
12
+ const MPARTICLE_TAG = 'react-native-mparticle';
13
+
14
+ /**
15
+ * Get the mParticle log level for iOS (Swift syntax)
16
+ */
17
+ function getSwiftLogLevel(
18
+ logLevel?: MParticlePluginProps['logLevel']
19
+ ): string | null {
20
+ switch (logLevel) {
21
+ case 'none':
22
+ return '.none';
23
+ case 'error':
24
+ return '.error';
25
+ case 'warning':
26
+ return '.warning';
27
+ case 'debug':
28
+ return '.debug';
29
+ case 'verbose':
30
+ return '.verbose';
31
+ default:
32
+ return null;
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Get the mParticle environment for iOS (Swift syntax)
38
+ */
39
+ function getSwiftEnvironment(
40
+ environment?: MParticlePluginProps['environment']
41
+ ): string | null {
42
+ switch (environment) {
43
+ case 'development':
44
+ return '.development';
45
+ case 'production':
46
+ return '.production';
47
+ case 'autoDetect':
48
+ return '.autoDetect';
49
+ default:
50
+ return null;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Get the mParticle log level for iOS (Objective-C syntax)
56
+ */
57
+ function getObjcLogLevel(
58
+ logLevel?: MParticlePluginProps['logLevel']
59
+ ): string | null {
60
+ switch (logLevel) {
61
+ case 'none':
62
+ return 'MPILogLevelNone';
63
+ case 'error':
64
+ return 'MPILogLevelError';
65
+ case 'warning':
66
+ return 'MPILogLevelWarning';
67
+ case 'debug':
68
+ return 'MPILogLevelDebug';
69
+ case 'verbose':
70
+ return 'MPILogLevelVerbose';
71
+ default:
72
+ return null;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Get the mParticle environment for iOS (Objective-C syntax)
78
+ */
79
+ function getObjcEnvironment(
80
+ environment?: MParticlePluginProps['environment']
81
+ ): string | null {
82
+ switch (environment) {
83
+ case 'development':
84
+ return 'MPEnvironmentDevelopment';
85
+ case 'production':
86
+ return 'MPEnvironmentProduction';
87
+ case 'autoDetect':
88
+ return 'MPEnvironmentAutoDetect';
89
+ default:
90
+ return null;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Generate mParticle initialization code for Swift AppDelegate
96
+ */
97
+ function generateSwiftInitCode(props: MParticlePluginProps): string {
98
+ const {
99
+ iosApiKey,
100
+ iosApiSecret,
101
+ logLevel,
102
+ environment,
103
+ useEmptyIdentifyRequest = true,
104
+ dataPlanId,
105
+ dataPlanVersion,
106
+ } = props;
107
+
108
+ const lines: string[] = [
109
+ '// mParticle SDK initialization',
110
+ `let mParticleOptions = MParticleOptions(key: "${iosApiKey}", secret: "${iosApiSecret}")`,
111
+ ];
112
+
113
+ const swiftLogLevel = getSwiftLogLevel(logLevel);
114
+ if (swiftLogLevel) {
115
+ lines.push(`mParticleOptions.logLevel = ${swiftLogLevel}`);
116
+ }
117
+
118
+ const swiftEnvironment = getSwiftEnvironment(environment);
119
+ if (swiftEnvironment) {
120
+ lines.push(`mParticleOptions.environment = ${swiftEnvironment}`);
121
+ }
122
+
123
+ if (dataPlanId) {
124
+ lines.push(`mParticleOptions.dataPlanId = "${dataPlanId}"`);
125
+ if (dataPlanVersion) {
126
+ lines.push(
127
+ `mParticleOptions.dataPlanVersion = ${dataPlanVersion} as NSNumber`
128
+ );
129
+ }
130
+ }
131
+
132
+ if (useEmptyIdentifyRequest) {
133
+ lines.push('let identifyRequest = MPIdentityApiRequest.withEmptyUser()');
134
+ lines.push('mParticleOptions.identifyRequest = identifyRequest');
135
+ }
136
+
137
+ lines.push('MParticle.sharedInstance().start(with: mParticleOptions)');
138
+
139
+ return lines.join('\n ');
140
+ }
141
+
142
+ /**
143
+ * Generate mParticle initialization code for Objective-C AppDelegate
144
+ */
145
+ function generateObjcInitCode(props: MParticlePluginProps): string {
146
+ const {
147
+ iosApiKey,
148
+ iosApiSecret,
149
+ logLevel,
150
+ environment,
151
+ useEmptyIdentifyRequest = true,
152
+ dataPlanId,
153
+ dataPlanVersion,
154
+ } = props;
155
+
156
+ const lines: string[] = [
157
+ '// mParticle SDK initialization',
158
+ `MParticleOptions *mParticleOptions = [MParticleOptions optionsWithKey:@"${iosApiKey}"`,
159
+ ` secret:@"${iosApiSecret}"];`,
160
+ ];
161
+
162
+ const objcLogLevel = getObjcLogLevel(logLevel);
163
+ if (objcLogLevel) {
164
+ lines.push(`mParticleOptions.logLevel = ${objcLogLevel};`);
165
+ }
166
+
167
+ const objcEnvironment = getObjcEnvironment(environment);
168
+ if (objcEnvironment) {
169
+ lines.push(`mParticleOptions.environment = ${objcEnvironment};`);
170
+ }
171
+
172
+ if (dataPlanId) {
173
+ lines.push(`mParticleOptions.dataPlanId = @"${dataPlanId}";`);
174
+ if (dataPlanVersion) {
175
+ lines.push(`mParticleOptions.dataPlanVersion = @(${dataPlanVersion});`);
176
+ }
177
+ }
178
+
179
+ if (useEmptyIdentifyRequest) {
180
+ lines.push(
181
+ 'MPIdentityApiRequest *identifyRequest = [MPIdentityApiRequest requestWithEmptyUser];'
182
+ );
183
+ lines.push('mParticleOptions.identifyRequest = identifyRequest;');
184
+ }
185
+
186
+ lines.push('[[MParticle sharedInstance] startWithOptions:mParticleOptions];');
187
+
188
+ return lines.join('\n ');
189
+ }
190
+
191
+ /**
192
+ * Add mParticle configuration to AppDelegate
193
+ * Handles both Swift and Objective-C/Objective-C++
194
+ */
195
+ const withMParticleAppDelegate: ConfigPlugin<MParticlePluginProps> = (
196
+ config,
197
+ props
198
+ ) => {
199
+ return withAppDelegate(config, config => {
200
+ const { contents, language } = config.modResults;
201
+
202
+ // Check if mParticle is already initialized
203
+ if (
204
+ contents.includes('MParticleOptions') ||
205
+ contents.includes('mParticleOptions')
206
+ ) {
207
+ return config;
208
+ }
209
+
210
+ if (language === 'swift') {
211
+ config.modResults.contents = addMParticleToSwiftAppDelegate(
212
+ contents,
213
+ props
214
+ );
215
+ } else if (language === 'objc' || language === 'objcpp') {
216
+ config.modResults.contents = addMParticleToObjcAppDelegate(
217
+ contents,
218
+ props
219
+ );
220
+ } else {
221
+ console.warn(
222
+ `[react-native-mparticle] Unsupported AppDelegate language: ${language}. ` +
223
+ 'mParticle initialization must be added manually.'
224
+ );
225
+ }
226
+
227
+ return config;
228
+ });
229
+ };
230
+
231
+ /**
232
+ * Add mParticle import and initialization to Swift AppDelegate
233
+ */
234
+ function addMParticleToSwiftAppDelegate(
235
+ contents: string,
236
+ props: MParticlePluginProps
237
+ ): string {
238
+ // Add import statement
239
+ // Use mergeContents for safe, idempotent code injection
240
+ const withImport = mergeContents({
241
+ src: contents,
242
+ newSrc: 'import mParticle_Apple_SDK',
243
+ anchor: /import Expo/,
244
+ offset: 1, // Add after the anchor
245
+ tag: `${MPARTICLE_TAG}-import`,
246
+ comment: '//',
247
+ });
248
+
249
+ // Generate initialization code
250
+ const initCode = generateSwiftInitCode(props);
251
+
252
+ // Find the right place to add initialization code
253
+ // For Expo SDK 53+, it should be in didFinishLaunchingWithOptions before the return
254
+ // Look for the return super.application pattern
255
+ const withInit = mergeContents({
256
+ src: withImport.contents,
257
+ newSrc: `\n ${initCode}\n`,
258
+ anchor:
259
+ /return super\.application\(application, didFinishLaunchingWithOptions: launchOptions\)/,
260
+ offset: 0, // Add before the anchor
261
+ tag: `${MPARTICLE_TAG}-init`,
262
+ comment: '//',
263
+ });
264
+
265
+ return withInit.contents;
266
+ }
267
+
268
+ /**
269
+ * Add mParticle import and initialization to Objective-C AppDelegate
270
+ */
271
+ function addMParticleToObjcAppDelegate(
272
+ contents: string,
273
+ props: MParticlePluginProps
274
+ ): string {
275
+ // Add import statement after React import or first import
276
+ const withImport = mergeContents({
277
+ src: contents,
278
+ newSrc: '#import "mParticle.h"',
279
+ anchor: /#import <React\/RCTBundleURLProvider\.h>|#import "AppDelegate\.h"/,
280
+ offset: 1, // Add after the anchor
281
+ tag: `${MPARTICLE_TAG}-import`,
282
+ comment: '//',
283
+ });
284
+
285
+ // Generate initialization code
286
+ const initCode = generateObjcInitCode(props);
287
+
288
+ // Try different patterns for where to insert the init code
289
+ let result = withImport.contents;
290
+
291
+ // Pattern 1: Expo's return [super application...
292
+ if (
293
+ result.includes(
294
+ 'return [super application:application didFinishLaunchingWithOptions:launchOptions];'
295
+ )
296
+ ) {
297
+ const withInit = mergeContents({
298
+ src: result,
299
+ newSrc: `\n ${initCode}\n`,
300
+ anchor:
301
+ /return \[super application:application didFinishLaunchingWithOptions:launchOptions\];/,
302
+ offset: 0,
303
+ tag: `${MPARTICLE_TAG}-init`,
304
+ comment: '//',
305
+ });
306
+ result = withInit.contents;
307
+ }
308
+ // Pattern 2: self.initialProps = @{};
309
+ else if (result.includes('self.initialProps = @{};')) {
310
+ const withInit = mergeContents({
311
+ src: result,
312
+ newSrc: `\n ${initCode}\n`,
313
+ anchor: /self\.initialProps = @\{\};/,
314
+ offset: 1,
315
+ tag: `${MPARTICLE_TAG}-init`,
316
+ comment: '//',
317
+ });
318
+ result = withInit.contents;
319
+ }
320
+ // Pattern 3: return YES;
321
+ else if (result.includes('return YES;')) {
322
+ const withInit = mergeContents({
323
+ src: result,
324
+ newSrc: `\n ${initCode}\n`,
325
+ anchor: /return YES;/,
326
+ offset: 0,
327
+ tag: `${MPARTICLE_TAG}-init`,
328
+ comment: '//',
329
+ });
330
+ result = withInit.contents;
331
+ }
332
+
333
+ return result;
334
+ }
335
+
336
+ /**
337
+ * Known transitive dependencies that need dynamic linking for each kit
338
+ * These are dependencies of mParticle kits that must also be dynamic frameworks
339
+ */
340
+ const KIT_TRANSITIVE_DEPENDENCIES: Record<string, string[]> = {
341
+ 'mParticle-Rokt': ['Rokt-Widget'],
342
+ // Add other kit dependencies here as needed
343
+ // "mParticle-Amplitude": [],
344
+ // "mParticle-Braze": [],
345
+ };
346
+
347
+ /**
348
+ * Get all pods that need dynamic framework linking
349
+ */
350
+ function getDynamicFrameworkPods(iosKits?: string[]): string[] {
351
+ const pods = ['mParticle-Apple-SDK'];
352
+
353
+ if (iosKits) {
354
+ for (const kit of iosKits) {
355
+ pods.push(kit);
356
+ // Add transitive dependencies for this kit
357
+ const transitiveDeps = KIT_TRANSITIVE_DEPENDENCIES[kit];
358
+ if (transitiveDeps) {
359
+ pods.push(...transitiveDeps);
360
+ }
361
+ }
362
+ }
363
+
364
+ return [...new Set(pods)]; // Remove duplicates
365
+ }
366
+
367
+ /**
368
+ * Add kit pods and pre_install hook to Podfile
369
+ */
370
+ const withMParticlePodfile: ConfigPlugin<MParticlePluginProps> = (
371
+ config,
372
+ props
373
+ ) => {
374
+ return withDangerousMod(config, [
375
+ 'ios',
376
+ async config => {
377
+ const podfilePath = path.join(
378
+ config.modRequest.platformProjectRoot,
379
+ 'Podfile'
380
+ );
381
+
382
+ if (!fs.existsSync(podfilePath)) {
383
+ return config;
384
+ }
385
+
386
+ let podfileContent = fs.readFileSync(podfilePath, 'utf-8');
387
+
388
+ // Add pre_install hook for dynamic framework linking if not already present
389
+ if (!podfileContent.includes('mParticle-Apple-SDK')) {
390
+ // Get all pods that need dynamic linking (including transitive dependencies)
391
+ const dynamicPods = getDynamicFrameworkPods(props.iosKits);
392
+ const podConditions = dynamicPods
393
+ .map(pod => `pod.name == '${pod}'`)
394
+ .join(' || ');
395
+
396
+ const preInstallHook = `
397
+ # mParticle dynamic framework linking (added by react-native-mparticle expo plugin)
398
+ pre_install do |installer|
399
+ installer.pod_targets.each do |pod|
400
+ if ${podConditions}
401
+ def pod.build_type;
402
+ Pod::BuildType.new(:linkage => :dynamic, :packaging => :framework)
403
+ end
404
+ end
405
+ end
406
+ end
407
+ `;
408
+
409
+ // Add pre_install hook after platform declaration
410
+ const platformRegex = /platform :ios.*\n/;
411
+ if (platformRegex.test(podfileContent)) {
412
+ podfileContent = podfileContent.replace(
413
+ platformRegex,
414
+ `$&${preInstallHook}`
415
+ );
416
+ }
417
+ }
418
+
419
+ // Add kit pods if specified
420
+ if (props.iosKits && props.iosKits.length > 0) {
421
+ const kitPods = props.iosKits.map(kit => ` pod '${kit}'`).join('\n');
422
+
423
+ // Check if kits are already added
424
+ const kitsAlreadyAdded = props.iosKits.every(kit =>
425
+ podfileContent.includes(`pod '${kit}'`)
426
+ );
427
+
428
+ if (!kitsAlreadyAdded) {
429
+ // Add kit pods inside the main target block
430
+ // Look for use_react_native! and add after it
431
+ const useReactNativeRegex = /(use_react_native!\([^)]*\))/s;
432
+ if (useReactNativeRegex.test(podfileContent)) {
433
+ podfileContent = podfileContent.replace(
434
+ useReactNativeRegex,
435
+ `$1\n\n # mParticle kits (added by react-native-mparticle expo plugin)\n${kitPods}`
436
+ );
437
+ }
438
+ }
439
+ }
440
+
441
+ fs.writeFileSync(podfilePath, podfileContent);
442
+
443
+ return config;
444
+ },
445
+ ]);
446
+ };
447
+
448
+ /**
449
+ * Apply all iOS-specific mParticle configurations
450
+ */
451
+ export const withMParticleIOS: ConfigPlugin<MParticlePluginProps> = (
452
+ config,
453
+ props
454
+ ) => {
455
+ config = withMParticleAppDelegate(config, props);
456
+ config = withMParticlePodfile(config, props);
457
+
458
+ return config;
459
+ };
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "expo-module-scripts/tsconfig.plugin",
3
+ "compilerOptions": {
4
+ "outDir": "build",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["./src"]
8
+ }
@@ -25,5 +25,16 @@ Pod::Spec.new do |s|
25
25
  s.dependency "React-Core"
26
26
  end
27
27
 
28
+ # Primary: CocoaPods dependency (still works when SPM is not used)
28
29
  s.dependency 'mParticle-Apple-SDK', '~> 8.0'
30
+
31
+ # SPM bridge: registers mParticle-Apple-SDK as an SPM dependency alongside CocoaPods (RN 0.75+).
32
+ # See: https://github.com/facebook/react-native/pull/44627
33
+ if respond_to?(:spm_dependency, true)
34
+ spm_dependency(s,
35
+ url: 'https://github.com/mParticle/mparticle-apple-sdk.git',
36
+ requirement: { kind: 'upToNextMajorVersion', minimumVersion: '8.0.0' },
37
+ products: ['mParticle-Apple-SDK']
38
+ )
39
+ end
29
40
  end
package/SECURITY.md DELETED
@@ -1,9 +0,0 @@
1
- # Security Policy
2
-
3
- ## Reporting a vulnerability
4
-
5
- To avoid abuse by malicious actors please do not open GitHub issues or pull requests for any security related issue you may have spotted.
6
-
7
- The safest way to report any vulnerability or concern you may have is via our [dedicated submission form](https://www.rokt.com/vulnerability-disclosure/).
8
-
9
- For further information please refer to the [Rokt Vulnerability Disclosure Policy](https://www.rokt.com/vulnerability-disclosure/).