customerio-expo-plugin 2.0.0 → 2.0.2

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 (25) hide show
  1. package/package.json +8 -8
  2. package/plugin/lib/commonjs/ios/withAppDelegateModifications.js +5 -3
  3. package/plugin/lib/commonjs/ios/withAppDelegateModifications.js.map +1 -1
  4. package/plugin/lib/commonjs/ios/withCIOIos.js +48 -5
  5. package/plugin/lib/commonjs/ios/withCIOIos.js.map +1 -1
  6. package/plugin/lib/commonjs/ios/withNotificationsXcodeProject.js +39 -23
  7. package/plugin/lib/commonjs/ios/withNotificationsXcodeProject.js.map +1 -1
  8. package/plugin/lib/commonjs/ios/withXcodeProject.js +2 -13
  9. package/plugin/lib/commonjs/ios/withXcodeProject.js.map +1 -1
  10. package/plugin/lib/commonjs/types/cio-types.js.map +1 -1
  11. package/plugin/lib/module/ios/withAppDelegateModifications.js +5 -3
  12. package/plugin/lib/module/ios/withAppDelegateModifications.js.map +1 -1
  13. package/plugin/lib/module/ios/withCIOIos.js +48 -5
  14. package/plugin/lib/module/ios/withCIOIos.js.map +1 -1
  15. package/plugin/lib/module/ios/withNotificationsXcodeProject.js +39 -23
  16. package/plugin/lib/module/ios/withNotificationsXcodeProject.js.map +1 -1
  17. package/plugin/lib/module/ios/withXcodeProject.js +2 -13
  18. package/plugin/lib/module/ios/withXcodeProject.js.map +1 -1
  19. package/plugin/lib/module/types/cio-types.js.map +1 -1
  20. package/plugin/lib/typescript/types/cio-types.d.ts +37 -12
  21. package/plugin/src/ios/withAppDelegateModifications.ts +5 -10
  22. package/plugin/src/ios/withCIOIos.ts +57 -6
  23. package/plugin/src/ios/withNotificationsXcodeProject.ts +53 -45
  24. package/plugin/src/ios/withXcodeProject.ts +2 -10
  25. package/plugin/src/types/cio-types.ts +47 -12
@@ -1,6 +1,6 @@
1
1
  import type { ExpoConfig } from '@expo/config-types';
2
2
 
3
- import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
3
+ import type { CustomerIOPluginOptionsIOS, CustomerIOPluginPushNotificationOptions } from '../types/cio-types';
4
4
  import { withAppDelegateModifications } from './withAppDelegateModifications';
5
5
  import { withCioNotificationsXcodeProject } from './withNotificationsXcodeProject';
6
6
  import { withCioXcodeProject } from './withXcodeProject';
@@ -10,12 +10,63 @@ export function withCIOIos(
10
10
  config: ExpoConfig,
11
11
  props: CustomerIOPluginOptionsIOS
12
12
  ) {
13
- if (props.pushNotification) {
14
- config = withAppDelegateModifications(config, props);
15
- config = withCioNotificationsXcodeProject(config, props);
16
- config = withCioXcodeProject(config, props);
17
- config = withGoogleServicesJsonFile(config, props);
13
+ const cioProps = mergeDeprecatedPropertiesAndLogWarnings(props);
14
+ if (cioProps.pushNotification) {
15
+ config = withAppDelegateModifications(config, cioProps);
16
+ config = withCioNotificationsXcodeProject(config, cioProps);
17
+ config = withCioXcodeProject(config, cioProps);
18
+ config = withGoogleServicesJsonFile(config, cioProps);
18
19
  }
19
20
 
20
21
  return config;
21
22
  }
23
+
24
+ /** The basic purpose of this function is to centralize where we handle the deprecation
25
+ by merging the deprecated properties into the new ios.pushNotification.* properties
26
+ and logging a warning if they are set. This way, we can remove the deprecated properties
27
+ from the top level of the ios object in the future, and update this function
28
+ while the rest of the plugin code remains unchanged.
29
+ */
30
+ const mergeDeprecatedPropertiesAndLogWarnings = (
31
+ props: CustomerIOPluginOptionsIOS
32
+ ) => {
33
+ // The deprecatedTopLevelProperties maps the top level properties
34
+ // that are deprecated to the new ios.pushNotification.* properties
35
+ // that should be used instead. The deprecated properties are
36
+ // still available for backwards compatibility, but they will
37
+ // be removed in the future.
38
+
39
+ const deprecatedTopLevelProperties = {
40
+ showPushAppInForeground: props.showPushAppInForeground,
41
+ autoTrackPushEvents: props.autoTrackPushEvents,
42
+ handleDeeplinkInKilledState: props.handleDeeplinkInKilledState,
43
+ disableNotificationRegistration: props.disableNotificationRegistration,
44
+ autoFetchDeviceToken: props.autoFetchDeviceToken,
45
+ };
46
+
47
+ // loop over all the deprecated properties and log a warning if they are set
48
+ Object.entries(deprecatedTopLevelProperties).forEach(([key, value]) => {
49
+ if (value !== undefined) {
50
+ console.warn(
51
+ `The ios.${key} property is deprecated. Please use ios.pushNotification.${key} instead.`
52
+ );
53
+
54
+ if (props.pushNotification === undefined) {
55
+ props.pushNotification = {} as CustomerIOPluginPushNotificationOptions;
56
+ }
57
+ const propKey = key as keyof CustomerIOPluginPushNotificationOptions;
58
+ if (props.pushNotification[propKey] === undefined) {
59
+ props.pushNotification = {
60
+ ...props.pushNotification,
61
+ [propKey]: value,
62
+ };
63
+ } else {
64
+ console.warn(
65
+ `The ios.${key} property is deprecated. Since the value of ios.pushNotification.${key} is set, it will be used.`
66
+ );
67
+ }
68
+ }
69
+ });
70
+
71
+ return props;
72
+ };
@@ -30,7 +30,7 @@ const addNotificationServiceExtension = async (
30
30
  await addPushNotificationFile(options, xcodeProject);
31
31
  }
32
32
 
33
- if (options.pushNotification?.useRichPush) {
33
+ if (options.pushNotification?.useRichPush === true) {
34
34
  await addRichPushXcodeProj(options, xcodeProject);
35
35
  }
36
36
  return xcodeProject;
@@ -45,12 +45,7 @@ export const withCioNotificationsXcodeProject: ConfigPlugin<
45
45
  > = (configOuter, props) => {
46
46
  return withXcodeProject(configOuter, async (config) => {
47
47
  const { modRequest, ios, version: bundleShortVersion } = config;
48
- const {
49
- appleTeamId,
50
- iosDeploymentTarget,
51
- pushNotification,
52
- useFrameworks,
53
- } = props;
48
+ const { appleTeamId, iosDeploymentTarget, useFrameworks } = props;
54
49
 
55
50
  if (ios === undefined)
56
51
  throw new Error(
@@ -89,8 +84,7 @@ export const withCioNotificationsXcodeProject: ConfigPlugin<
89
84
  appName: projectName,
90
85
  useFrameworks,
91
86
  iosDeploymentTarget,
92
- pushNotification,
93
- };
87
+ } satisfies CustomerIOPluginOptionsIOS;
94
88
 
95
89
  const modifiedProjectFile = await addNotificationServiceExtension(
96
90
  options,
@@ -137,9 +131,7 @@ const addRichPushXcodeProj = async (
137
131
  recursive: true,
138
132
  });
139
133
 
140
- const platformSpecificFiles = [
141
- 'NotificationService.swift',
142
- ];
134
+ const platformSpecificFiles = ['NotificationService.swift'];
143
135
 
144
136
  const commonFiles = [
145
137
  PLIST_FILENAME,
@@ -153,13 +145,15 @@ const addRichPushXcodeProj = async (
153
145
  platformSpecificFiles.forEach((filename) => {
154
146
  const targetFile = getTargetFile(filename);
155
147
  FileManagement.copyFile(
156
- `${LOCAL_PATH_TO_CIO_NSE_FILES}/${isFcmProvider ? "fcm" : "apn"}/${filename}`,
148
+ `${LOCAL_PATH_TO_CIO_NSE_FILES}/${
149
+ isFcmProvider ? 'fcm' : 'apn'
150
+ }/${filename}`,
157
151
  targetFile
158
152
  );
159
153
  });
160
154
 
161
- // Copy common files
162
- commonFiles.forEach((filename) => {
155
+ // Copy common files
156
+ commonFiles.forEach((filename) => {
163
157
  const targetFile = getTargetFile(filename);
164
158
  FileManagement.copyFile(
165
159
  `${LOCAL_PATH_TO_CIO_NSE_FILES}/common/${filename}`,
@@ -298,25 +292,31 @@ const updateNseEnv = (
298
292
  const REGION_RE = /\{\{REGION\}\}/;
299
293
 
300
294
  let envFileContent = FileManagement.readFile(envFileName);
301
-
302
- if (options.pushNotification?.env?.cdpApiKey) {
303
- envFileContent = replaceCodeByRegex(
304
- envFileContent,
305
- CDP_API_KEY_RE,
306
- options.pushNotification?.env?.cdpApiKey
295
+ const { cdpApiKey, region } = options.pushNotification?.env || {
296
+ cdpApiKey: undefined,
297
+ region: undefined,
298
+ };
299
+
300
+ if (!cdpApiKey) {
301
+ throw new Error(
302
+ 'Adding NotificationServiceExtension failed: ios.pushNotification.env.cdpApiKey is missing from app.config.js or app.json.'
307
303
  );
308
304
  }
305
+ envFileContent = replaceCodeByRegex(
306
+ envFileContent,
307
+ CDP_API_KEY_RE,
308
+ cdpApiKey
309
+ );
309
310
 
310
- if (options.pushNotification?.env?.region) {
311
+ if (region) {
311
312
  const regionMap = {
312
313
  us: 'Region.US',
313
314
  eu: 'Region.EU',
314
315
  };
315
- const region = options.pushNotification?.env?.region?.toLowerCase();
316
- const mappedRegion = (regionMap as any)[region] || '';
316
+ const mappedRegion = (regionMap as any)[region.toLowerCase()] || '';
317
317
  if (!mappedRegion) {
318
318
  console.warn(
319
- `${options.pushNotification?.env?.region} is an invalid region. Please use the values from the docs: https://customer.io/docs/sdk/expo/getting-started/#configure-the-plugin`
319
+ `${region} is an invalid region. Please use the values from the docs: https://customer.io/docs/sdk/expo/getting-started/#configure-the-plugin`
320
320
  );
321
321
  } else {
322
322
  envFileContent = replaceCodeByRegex(
@@ -338,7 +338,7 @@ async function addPushNotificationFile(
338
338
  const { iosPath, appName } = options;
339
339
  const isFcmProvider = isFcmPushProvider(options);
340
340
  // PushService.swift is platform-specific and always lives in the platform folder
341
- const sourceFile = `${isFcmProvider ? "fcm" : "apn"}/PushService.swift`;
341
+ const sourceFile = `${isFcmProvider ? 'fcm' : 'apn'}/PushService.swift`;
342
342
  const targetFileName = 'PushService.swift';
343
343
  const appPath = `${iosPath}/${appName}`;
344
344
  const getTargetFile = (filename: string) => `${appPath}/${filename}`;
@@ -376,50 +376,58 @@ const updatePushFile = (
376
376
  const REGISTER_RE = /\{\{REGISTER_SNIPPET\}\}/;
377
377
 
378
378
  let envFileContent = FileManagement.readFile(envFileName);
379
+ const disableNotificationRegistration =
380
+ options.pushNotification?.disableNotificationRegistration;
381
+ const { cdpApiKey, region } = options.pushNotification?.env || {
382
+ cdpApiKey: undefined,
383
+ region: undefined,
384
+ };
385
+ if (!cdpApiKey) {
386
+ throw new Error(
387
+ 'Adding NotificationServiceExtension failed: ios.pushNotification.env.cdpApiKey is missing from app.config.js or app.json.'
388
+ );
389
+ }
379
390
 
380
391
  let snippet = '';
381
- if (
382
- options.disableNotificationRegistration !== undefined &&
383
- options.disableNotificationRegistration === false
384
- ) {
392
+ // unless this property is explicity set to true, push notification
393
+ // registration will be added to the AppDelegate
394
+ if (disableNotificationRegistration !== true) {
385
395
  snippet = CIO_REGISTER_PUSHNOTIFICATION_SNIPPET;
386
396
  }
387
397
  envFileContent = replaceCodeByRegex(envFileContent, REGISTER_RE, snippet);
388
398
 
389
- if (options.pushNotification) {
390
- envFileContent = replaceCodeByRegex(
391
- envFileContent,
392
- /\{\{CDP_API_KEY\}\}/,
393
- options.pushNotification.env.cdpApiKey
394
- );
399
+ envFileContent = replaceCodeByRegex(
400
+ envFileContent,
401
+ /\{\{CDP_API_KEY\}\}/,
402
+ cdpApiKey
403
+ );
404
+
405
+ if (region) {
395
406
  envFileContent = replaceCodeByRegex(
396
407
  envFileContent,
397
408
  /\{\{REGION\}\}/,
398
- options.pushNotification.env.region.toUpperCase()
409
+ region.toUpperCase()
399
410
  );
400
411
  }
401
412
 
402
413
  const autoTrackPushEvents =
403
- options.autoTrackPushEvents === undefined ||
404
- options.autoTrackPushEvents === true;
414
+ options.pushNotification?.autoTrackPushEvents !== false;
405
415
  envFileContent = replaceCodeByRegex(
406
416
  envFileContent,
407
417
  /\{\{AUTO_TRACK_PUSH_EVENTS\}\}/,
408
418
  autoTrackPushEvents.toString()
409
419
  );
410
420
 
411
- const autoFetchDeviceToken =
412
- options.autoFetchDeviceToken === undefined ||
413
- options.autoFetchDeviceToken === true;
421
+ const autoFetchDeviceToken =
422
+ options.pushNotification?.autoFetchDeviceToken !== false;
414
423
  envFileContent = replaceCodeByRegex(
415
424
  envFileContent,
416
425
  /\{\{AUTO_FETCH_DEVICE_TOKEN\}\}/,
417
426
  autoFetchDeviceToken.toString()
418
427
  );
419
-
428
+
420
429
  const showPushAppInForeground =
421
- options.showPushAppInForeground === undefined ||
422
- options.showPushAppInForeground === true;
430
+ options.pushNotification?.showPushAppInForeground !== false;
423
431
  envFileContent = replaceCodeByRegex(
424
432
  envFileContent,
425
433
  /\{\{SHOW_PUSH_APP_IN_FOREGROUND\}\}/,
@@ -1,23 +1,15 @@
1
1
  import { ConfigPlugin, withXcodeProject } from '@expo/config-plugins';
2
2
 
3
+ import { isFcmPushProvider } from './utils';
3
4
  import { injectCIOPodfileCode } from '../helpers/utils/injectCIOPodfileCode';
4
5
  import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
5
- import { isFcmPushProvider } from './utils';
6
6
 
7
7
  export const withCioXcodeProject: ConfigPlugin<CustomerIOPluginOptionsIOS> = (
8
8
  config,
9
9
  cioProps
10
10
  ) => {
11
11
  return withXcodeProject(config, async (props) => {
12
- const options: CustomerIOPluginOptionsIOS = {
13
- iosPath: props.modRequest.platformProjectRoot,
14
- bundleIdentifier: props.ios?.bundleIdentifier,
15
- devTeam: cioProps?.devTeam,
16
- bundleVersion: props.ios?.buildNumber,
17
- bundleShortVersion: props?.version,
18
- iosDeploymentTarget: cioProps?.iosDeploymentTarget,
19
- };
20
- const { iosPath } = options;
12
+ const iosPath = props.modRequest.platformProjectRoot;
21
13
 
22
14
  await injectCIOPodfileCode(iosPath, isFcmPushProvider(cioProps));
23
15
 
@@ -15,25 +15,40 @@ export type CustomerIOPluginOptionsIOS = {
15
15
  iosDeploymentTarget?: string;
16
16
  appleTeamId?: string;
17
17
  appName?: string;
18
- disableNotificationRegistration?: boolean;
18
+
19
+ useFrameworks?: 'static' | 'dynamic';
20
+
21
+ pushNotification?: CustomerIOPluginPushNotificationOptions;
22
+
19
23
  /**
20
24
  * @deprecated No longer has any effect. Use autoTrackPushEvents to control if push metrics should be automatically tracked by SDK.
21
25
  */
22
26
  handleNotificationClick?: boolean;
27
+
28
+ /**
29
+ * @deprecated Property will be removed in the future. Use ios.pushNotification.autoFetchDeviceToken instead
30
+ */
31
+ autoFetchDeviceToken?: boolean;
32
+
33
+ /**
34
+ * @deprecated Property will be removed in the future. Use ios.pushNotification.showPushAppInForeground instead
35
+ */
23
36
  showPushAppInForeground?: boolean;
37
+
38
+ /**
39
+ * @deprecated Property will be removed in the future. Use ios.pushNotification.autoTrackPushEvents instead
40
+ */
24
41
  autoTrackPushEvents?: boolean;
25
- autoFetchDeviceToken?: boolean;
42
+
43
+ /**
44
+ * @deprecated Property will be removed in the future. Use ios.pushNotification.handleDeeplinkInKilledState instead
45
+ */
26
46
  handleDeeplinkInKilledState?: boolean;
27
- useFrameworks?: 'static' | 'dynamic';
28
- pushNotification?: {
29
- provider?: 'apn' | 'fcm';
30
- googleServicesFile?: string;
31
- useRichPush: boolean;
32
- env: {
33
- cdpApiKey: string;
34
- region: string;
35
- };
36
- };
47
+
48
+ /**
49
+ * @deprecated Property will be removed in the future. Use ios.pushNotification.disableNotificationRegistration instead
50
+ */
51
+ disableNotificationRegistration?: boolean;
37
52
  };
38
53
 
39
54
  export type CustomerIOPluginOptionsAndroid = {
@@ -46,3 +61,23 @@ export type CustomerIOPluginOptions = {
46
61
  android: CustomerIOPluginOptionsAndroid;
47
62
  ios: CustomerIOPluginOptionsIOS;
48
63
  };
64
+
65
+ export type CustomerIOPluginPushNotificationOptions = {
66
+ provider?: 'apn' | 'fcm';
67
+ googleServicesFile?: string;
68
+ useRichPush?: boolean;
69
+ autoFetchDeviceToken?: boolean;
70
+ autoTrackPushEvents?: boolean;
71
+ showPushAppInForeground?: boolean;
72
+ disableNotificationRegistration?: boolean;
73
+ handleDeeplinkInKilledState?: boolean;
74
+
75
+ /**
76
+ * These values will be used to initialize the Notification Service Extension (NSE) on the native side.
77
+ * They should match the values you use to initialize the SDK in your app
78
+ */
79
+ env: {
80
+ cdpApiKey: string;
81
+ region: string;
82
+ };
83
+ };