customerio-expo-plugin 3.3.0 → 3.5.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.
- package/package.json +8 -1
- package/plugin/lib/commonjs/android/withAndroidManifestUpdates.js +64 -59
- package/plugin/lib/commonjs/android/withAndroidManifestUpdates.js.map +1 -1
- package/plugin/lib/commonjs/android/withAppGoogleServices.js +10 -7
- package/plugin/lib/commonjs/android/withAppGoogleServices.js.map +1 -1
- package/plugin/lib/commonjs/android/withGoogleServicesJSON.js +18 -21
- package/plugin/lib/commonjs/android/withGoogleServicesJSON.js.map +1 -1
- package/plugin/lib/commonjs/android/withLocationGradleProperties.js +16 -12
- package/plugin/lib/commonjs/android/withLocationGradleProperties.js.map +1 -1
- package/plugin/lib/commonjs/android/withMainApplicationModifications.js +19 -12
- package/plugin/lib/commonjs/android/withMainApplicationModifications.js.map +1 -1
- package/plugin/lib/commonjs/android/withNotificationChannelMetadata.js +2 -1
- package/plugin/lib/commonjs/android/withNotificationChannelMetadata.js.map +1 -1
- package/plugin/lib/commonjs/android/withProjectBuildGradle.js +29 -25
- package/plugin/lib/commonjs/android/withProjectBuildGradle.js.map +1 -1
- package/plugin/lib/commonjs/android/withProjectGoogleServices.js +9 -5
- package/plugin/lib/commonjs/android/withProjectGoogleServices.js.map +1 -1
- package/plugin/lib/commonjs/helpers/constants/ios.js +76 -8
- package/plugin/lib/commonjs/helpers/constants/ios.js.map +1 -1
- package/plugin/lib/commonjs/helpers/utils/injectCIOPodfileCode.js +76 -31
- package/plugin/lib/commonjs/helpers/utils/injectCIOPodfileCode.js.map +1 -1
- package/plugin/lib/commonjs/index.js +7 -0
- package/plugin/lib/commonjs/index.js.map +1 -1
- package/plugin/lib/commonjs/ios/withAppDelegateModifications.js +47 -33
- package/plugin/lib/commonjs/ios/withAppDelegateModifications.js.map +1 -1
- package/plugin/lib/commonjs/ios/withCIOIosSwift.js +44 -54
- package/plugin/lib/commonjs/ios/withCIOIosSwift.js.map +1 -1
- package/plugin/lib/commonjs/ios/withGoogleServicesJsonFile.js +46 -30
- package/plugin/lib/commonjs/ios/withGoogleServicesJsonFile.js.map +1 -1
- package/plugin/lib/commonjs/ios/withNotificationsXcodeProject.js +192 -122
- package/plugin/lib/commonjs/ios/withNotificationsXcodeProject.js.map +1 -1
- package/plugin/lib/commonjs/postInstallHelper.js +58 -11
- package/plugin/lib/commonjs/postInstallHelper.js.map +1 -1
- package/plugin/lib/commonjs/utils/resolveRNSDK.js +97 -0
- package/plugin/lib/commonjs/utils/resolveRNSDK.js.map +1 -0
- package/plugin/lib/commonjs/utils/writeExpoVersion.js +56 -0
- package/plugin/lib/commonjs/utils/writeExpoVersion.js.map +1 -0
- package/plugin/lib/module/android/withAndroidManifestUpdates.js +61 -58
- package/plugin/lib/module/android/withAndroidManifestUpdates.js.map +1 -1
- package/plugin/lib/module/android/withAppGoogleServices.js +9 -7
- package/plugin/lib/module/android/withAppGoogleServices.js.map +1 -1
- package/plugin/lib/module/android/withGoogleServicesJSON.js +17 -21
- package/plugin/lib/module/android/withGoogleServicesJSON.js.map +1 -1
- package/plugin/lib/module/android/withLocationGradleProperties.js +15 -12
- package/plugin/lib/module/android/withLocationGradleProperties.js.map +1 -1
- package/plugin/lib/module/android/withMainApplicationModifications.js +18 -12
- package/plugin/lib/module/android/withMainApplicationModifications.js.map +1 -1
- package/plugin/lib/module/android/withNotificationChannelMetadata.js +1 -1
- package/plugin/lib/module/android/withNotificationChannelMetadata.js.map +1 -1
- package/plugin/lib/module/android/withProjectBuildGradle.js +28 -25
- package/plugin/lib/module/android/withProjectBuildGradle.js.map +1 -1
- package/plugin/lib/module/android/withProjectGoogleServices.js +8 -5
- package/plugin/lib/module/android/withProjectGoogleServices.js.map +1 -1
- package/plugin/lib/module/helpers/constants/ios.js +75 -8
- package/plugin/lib/module/helpers/constants/ios.js.map +1 -1
- package/plugin/lib/module/helpers/utils/injectCIOPodfileCode.js +74 -31
- package/plugin/lib/module/helpers/utils/injectCIOPodfileCode.js.map +1 -1
- package/plugin/lib/module/index.js +7 -0
- package/plugin/lib/module/index.js.map +1 -1
- package/plugin/lib/module/ios/withAppDelegateModifications.js +45 -33
- package/plugin/lib/module/ios/withAppDelegateModifications.js.map +1 -1
- package/plugin/lib/module/ios/withCIOIosSwift.js +42 -54
- package/plugin/lib/module/ios/withCIOIosSwift.js.map +1 -1
- package/plugin/lib/module/ios/withGoogleServicesJsonFile.js +45 -30
- package/plugin/lib/module/ios/withGoogleServicesJsonFile.js.map +1 -1
- package/plugin/lib/module/ios/withNotificationsXcodeProject.js +187 -122
- package/plugin/lib/module/ios/withNotificationsXcodeProject.js.map +1 -1
- package/plugin/lib/module/postInstallHelper.js +58 -11
- package/plugin/lib/module/postInstallHelper.js.map +1 -1
- package/plugin/lib/module/utils/resolveRNSDK.js +88 -0
- package/plugin/lib/module/utils/resolveRNSDK.js.map +1 -0
- package/plugin/lib/module/utils/writeExpoVersion.js +48 -0
- package/plugin/lib/module/utils/writeExpoVersion.js.map +1 -0
- package/plugin/lib/typescript/android/withAndroidManifestUpdates.d.ts +2 -0
- package/plugin/lib/typescript/android/withAppGoogleServices.d.ts +1 -0
- package/plugin/lib/typescript/android/withGoogleServicesJSON.d.ts +1 -0
- package/plugin/lib/typescript/android/withLocationGradleProperties.d.ts +2 -0
- package/plugin/lib/typescript/android/withMainApplicationModifications.d.ts +6 -0
- package/plugin/lib/typescript/android/withNotificationChannelMetadata.d.ts +5 -0
- package/plugin/lib/typescript/android/withProjectBuildGradle.d.ts +9 -0
- package/plugin/lib/typescript/android/withProjectGoogleServices.d.ts +1 -0
- package/plugin/lib/typescript/helpers/constants/ios.d.ts +18 -0
- package/plugin/lib/typescript/helpers/utils/injectCIOPodfileCode.d.ts +25 -1
- package/plugin/lib/typescript/ios/withAppDelegateModifications.d.ts +13 -0
- package/plugin/lib/typescript/ios/withCIOIosSwift.d.ts +11 -0
- package/plugin/lib/typescript/ios/withGoogleServicesJsonFile.d.ts +14 -1
- package/plugin/lib/typescript/ios/withNotificationsXcodeProject.d.ts +53 -2
- package/plugin/lib/typescript/utils/resolveRNSDK.d.ts +7 -0
- package/plugin/lib/typescript/utils/writeExpoVersion.d.ts +3 -0
- package/plugin/src/android/withAndroidManifestUpdates.ts +83 -73
- package/plugin/src/android/withAppGoogleServices.ts +13 -11
- package/plugin/src/android/withGoogleServicesJSON.ts +30 -28
- package/plugin/src/android/withLocationGradleProperties.ts +23 -17
- package/plugin/src/android/withMainApplicationModifications.ts +25 -15
- package/plugin/src/android/withNotificationChannelMetadata.ts +1 -1
- package/plugin/src/android/withProjectBuildGradle.ts +37 -27
- package/plugin/src/android/withProjectGoogleServices.ts +14 -9
- package/plugin/src/helpers/constants/ios.ts +87 -8
- package/plugin/src/helpers/utils/injectCIOPodfileCode.ts +97 -50
- package/plugin/src/index.ts +7 -0
- package/plugin/src/ios/withAppDelegateModifications.ts +61 -48
- package/plugin/src/ios/withCIOIosSwift.ts +58 -62
- package/plugin/src/ios/withGoogleServicesJsonFile.ts +66 -48
- package/plugin/src/ios/withNotificationsXcodeProject.ts +257 -207
- package/plugin/src/postInstallHelper.js +75 -17
- package/plugin/src/utils/resolveRNSDK.ts +118 -0
- package/plugin/src/utils/writeExpoVersion.ts +62 -0
|
@@ -1,3 +1,16 @@
|
|
|
1
|
-
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
1
|
+
import type { ConfigPlugin, XcodeProject } from '@expo/config-plugins';
|
|
2
2
|
import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
|
|
3
|
+
export type CopyGoogleServicePlistOptions = {
|
|
4
|
+
iosPath: string;
|
|
5
|
+
appName: string | undefined;
|
|
6
|
+
googleServicesFile: string | undefined;
|
|
7
|
+
expoIosGoogleServicesFileSet: boolean;
|
|
8
|
+
xcodeProject: XcodeProject;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Copies the FCM GoogleService-Info.plist into the iOS project (when needed) and registers it
|
|
12
|
+
* in the Xcode project's Resources group. Idempotent — no-ops if a plist is already present
|
|
13
|
+
* at either of the two well-known locations Expo / RN Firebase use.
|
|
14
|
+
*/
|
|
15
|
+
export declare function copyGoogleServicePlistFile({ iosPath, appName, googleServicesFile, expoIosGoogleServicesFileSet, xcodeProject, }: CopyGoogleServicePlistOptions): void;
|
|
3
16
|
export declare const withGoogleServicesJsonFile: ConfigPlugin<CustomerIOPluginOptionsIOS>;
|
|
@@ -1,3 +1,54 @@
|
|
|
1
|
-
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
-
import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
|
|
1
|
+
import type { ConfigPlugin, XcodeProject } from '@expo/config-plugins';
|
|
2
|
+
import type { CustomerIOPluginOptionsIOS, RichPushConfig } from '../types/cio-types';
|
|
3
3
|
export declare const withCioNotificationsXcodeProject: ConfigPlugin<CustomerIOPluginOptionsIOS>;
|
|
4
|
+
export type AddNseTargetToXcodeProjectOptions = {
|
|
5
|
+
appleTeamId?: string;
|
|
6
|
+
bundleIdentifier?: string;
|
|
7
|
+
iosDeploymentTarget?: string;
|
|
8
|
+
appGroupId?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Mutates the parsed XcodeProject to register the rich-push NotificationService
|
|
12
|
+
* extension target: creates a PBXGroup for its files, registers the group under
|
|
13
|
+
* the project's top-level group, adds the app_extension target, wires three
|
|
14
|
+
* build phases (Sources, Resources, Frameworks), configures the target's build
|
|
15
|
+
* settings (DEVELOPMENT_TEAM, IPHONEOS_DEPLOYMENT_TARGET, code-sign style,
|
|
16
|
+
* Swift version, and CODE_SIGN_ENTITLEMENTS when `appGroupId` is set), and
|
|
17
|
+
* stamps the development team attribute on both the new target and the
|
|
18
|
+
* project's main target attributes.
|
|
19
|
+
*
|
|
20
|
+
* Idempotent — returns the project unchanged if a target named
|
|
21
|
+
* `CIO_NOTIFICATION_TARGET_NAME` is already present.
|
|
22
|
+
*/
|
|
23
|
+
export declare function addNotificationServiceExtensionToXcodeProject(xcodeProject: XcodeProject, options: AddNseTargetToXcodeProjectOptions): XcodeProject;
|
|
24
|
+
/**
|
|
25
|
+
* Pure string transform: substitutes the `{{BUNDLE_VERSION}}` and
|
|
26
|
+
* `{{BUNDLE_SHORT_VERSION}}` placeholders in the NSE Info.plist template.
|
|
27
|
+
* Either or both may be provided; missing values leave the corresponding
|
|
28
|
+
* placeholder untouched.
|
|
29
|
+
*/
|
|
30
|
+
export declare function applyBundleVersionToNsePlist(content: string, payload: {
|
|
31
|
+
bundleVersion?: string;
|
|
32
|
+
bundleShortVersion?: string;
|
|
33
|
+
}): string;
|
|
34
|
+
/**
|
|
35
|
+
* Pure string transform: substitutes the `{{APP_GROUP_ID_BUILDER_LINE}}`
|
|
36
|
+
* placeholder in NotificationService.swift with either the configured
|
|
37
|
+
* appGroupId builder line or an empty string.
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyAppGroupIdToNotificationService(content: string, appGroupId?: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Pure string transform: substitutes the `{{CDP_API_KEY}}` and `{{REGION}}`
|
|
42
|
+
* placeholders in the NSE Env.swift template. Missing or invalid region
|
|
43
|
+
* falls back to `Region.US` and logs a warning.
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyRichPushConfigToEnv(content: string, richPushConfig?: RichPushConfig): string;
|
|
46
|
+
/**
|
|
47
|
+
* Pure string transform: substitutes every PushService.swift placeholder
|
|
48
|
+
* (`{{REGISTER_SNIPPET}}`, `{{CDP_API_KEY}}`, `{{REGION}}`,
|
|
49
|
+
* `{{AUTO_TRACK_PUSH_EVENTS}}`, `{{AUTO_FETCH_DEVICE_TOKEN}}`,
|
|
50
|
+
* `{{SHOW_PUSH_APP_IN_FOREGROUND}}`, `{{APP_GROUP_ID_BUILDER_LINE}}`) using
|
|
51
|
+
* the configured push-notification options. Validation of the rich-push
|
|
52
|
+
* config (cdpApiKey/region required) is the wrapper's responsibility.
|
|
53
|
+
*/
|
|
54
|
+
export declare function applyConfigToPushFile(content: string, options: CustomerIOPluginOptionsIOS): string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type ResolvedRNSDK = {
|
|
2
|
+
packageDir: string;
|
|
3
|
+
packageJsonPath: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function tryReadRNVersion(fromDir: string): string | null;
|
|
6
|
+
export declare function tryResolveRNSDK(fromDir: string): ResolvedRNSDK | null;
|
|
7
|
+
export declare function resolveRNSDK(fromDir: string): ResolvedRNSDK;
|
|
@@ -9,92 +9,102 @@ import { logger } from '../utils/logger';
|
|
|
9
9
|
export const DEFAULT_LOW_PRIORITY = -10;
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const customerIOMessagingpush =
|
|
19
|
-
'io.customer.messagingpush.CustomerIOFirebaseMessagingService';
|
|
12
|
+
export function modifyAndroidManifestApplication(
|
|
13
|
+
application: ManifestApplication[],
|
|
14
|
+
options: CustomerIOPluginOptionsAndroid
|
|
15
|
+
): ManifestApplication[] {
|
|
16
|
+
const customerIOMessagingpush =
|
|
17
|
+
'io.customer.messagingpush.CustomerIOFirebaseMessagingService';
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
if (!application[0].service) {
|
|
20
|
+
application[0].service = [];
|
|
21
|
+
}
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
const existingServiceIndex = application[0].service.findIndex(
|
|
24
|
+
(service) => service.$['android:name'] === customerIOMessagingpush
|
|
25
|
+
);
|
|
28
26
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
27
|
+
if (existingServiceIndex === -1) {
|
|
28
|
+
// Intent filter structure for Firebase messaging service
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
const intentFilter: any = {
|
|
31
|
+
action: [
|
|
32
|
+
{
|
|
33
|
+
$: {
|
|
34
|
+
'android:name': 'com.google.firebase.MESSAGING_EVENT',
|
|
38
35
|
},
|
|
39
|
-
],
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
// Handle priority based on setHighPriorityPushHandler value
|
|
43
|
-
if (options.setHighPriorityPushHandler === true) {
|
|
44
|
-
// High priority - no priority attribute means default high priority
|
|
45
|
-
logger.info(
|
|
46
|
-
'Successfully set CustomerIO push handler as high priority in AndroidManifest.xml'
|
|
47
|
-
);
|
|
48
|
-
} else if (options.setHighPriorityPushHandler === false) {
|
|
49
|
-
// Low priority - set fixed priority
|
|
50
|
-
intentFilter.$ = {
|
|
51
|
-
'android:priority': DEFAULT_LOW_PRIORITY.toString(),
|
|
52
|
-
};
|
|
53
|
-
logger.info(
|
|
54
|
-
`Successfully set CustomerIO push handler as low priority (${DEFAULT_LOW_PRIORITY}) in AndroidManifest.xml`
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
application[0].service.push({
|
|
59
|
-
'$': {
|
|
60
|
-
'android:name': customerIOMessagingpush,
|
|
61
|
-
'android:exported': 'false',
|
|
62
36
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
} else if (options.setHighPriorityPushHandler === true) {
|
|
66
|
-
// Service exists, need to ensure it becomes high priority (remove priority attribute)
|
|
67
|
-
const existingService = application[0].service[existingServiceIndex];
|
|
37
|
+
],
|
|
38
|
+
};
|
|
68
39
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'Successfully updated existing CustomerIO push handler to high priority in AndroidManifest.xml'
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
40
|
+
// Handle priority based on setHighPriorityPushHandler value
|
|
41
|
+
if (options.setHighPriorityPushHandler === true) {
|
|
42
|
+
// High priority - no priority attribute means default high priority
|
|
43
|
+
logger.info(
|
|
44
|
+
'Successfully set CustomerIO push handler as high priority in AndroidManifest.xml'
|
|
45
|
+
);
|
|
79
46
|
} else if (options.setHighPriorityPushHandler === false) {
|
|
80
|
-
//
|
|
81
|
-
|
|
47
|
+
// Low priority - set fixed priority
|
|
48
|
+
intentFilter.$ = {
|
|
49
|
+
'android:priority': DEFAULT_LOW_PRIORITY.toString(),
|
|
50
|
+
};
|
|
51
|
+
logger.info(
|
|
52
|
+
`Successfully set CustomerIO push handler as low priority (${DEFAULT_LOW_PRIORITY}) in AndroidManifest.xml`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
82
55
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
56
|
+
application[0].service.push({
|
|
57
|
+
'$': {
|
|
58
|
+
'android:name': customerIOMessagingpush,
|
|
59
|
+
'android:exported': 'false',
|
|
60
|
+
},
|
|
61
|
+
'intent-filter': [intentFilter],
|
|
62
|
+
});
|
|
63
|
+
} else if (options.setHighPriorityPushHandler === true) {
|
|
64
|
+
// Service exists, need to ensure it becomes high priority (remove priority attribute)
|
|
65
|
+
const existingService = application[0].service[existingServiceIndex];
|
|
66
|
+
|
|
67
|
+
if (existingService['intent-filter'] && existingService['intent-filter'].length > 0) {
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
69
|
+
const intentFilter = existingService['intent-filter'][0] as any;
|
|
70
|
+
if (intentFilter.$ && intentFilter.$['android:priority']) {
|
|
71
|
+
delete intentFilter.$['android:priority'];
|
|
91
72
|
logger.info(
|
|
92
|
-
|
|
73
|
+
'Successfully updated existing CustomerIO push handler to high priority in AndroidManifest.xml'
|
|
93
74
|
);
|
|
94
75
|
}
|
|
95
76
|
}
|
|
77
|
+
} else if (options.setHighPriorityPushHandler === false) {
|
|
78
|
+
// Service exists, update to low priority
|
|
79
|
+
const existingService = application[0].service[existingServiceIndex];
|
|
80
|
+
|
|
81
|
+
// Update existing service intent-filter with fixed priority
|
|
82
|
+
if (existingService['intent-filter'] && existingService['intent-filter'].length > 0) {
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
+
const intentFilter = existingService['intent-filter'][0] as any;
|
|
85
|
+
if (!intentFilter.$) {
|
|
86
|
+
intentFilter.$ = {};
|
|
87
|
+
}
|
|
88
|
+
intentFilter.$['android:priority'] = DEFAULT_LOW_PRIORITY.toString();
|
|
89
|
+
logger.info(
|
|
90
|
+
`Successfully updated existing CustomerIO push handler to low priority (${DEFAULT_LOW_PRIORITY}) in AndroidManifest.xml`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
96
94
|
|
|
97
|
-
|
|
95
|
+
return application;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export const withAndroidManifestUpdates: ConfigPlugin<
|
|
99
|
+
CustomerIOPluginOptionsAndroid
|
|
100
|
+
> = (configOuter, options) => {
|
|
101
|
+
return withAndroidManifest(configOuter, (props) => {
|
|
102
|
+
const application = props.modResults.manifest
|
|
103
|
+
.application as ManifestApplication[];
|
|
104
|
+
props.modResults.manifest.application = modifyAndroidManifestApplication(
|
|
105
|
+
application,
|
|
106
|
+
options
|
|
107
|
+
);
|
|
98
108
|
return props;
|
|
99
109
|
});
|
|
100
110
|
};
|
|
@@ -8,21 +8,23 @@ import {
|
|
|
8
8
|
import type { CustomerIOPluginOptionsAndroid } from '../types/cio-types';
|
|
9
9
|
import { logger } from '../utils/logger';
|
|
10
10
|
|
|
11
|
+
export function modifyAppBuildGradle(contents: string): string {
|
|
12
|
+
const regex = new RegExp(CIO_APP_GOOGLE_SNIPPET);
|
|
13
|
+
if (regex.test(contents)) {
|
|
14
|
+
logger.info('app/build.gradle snippet already exists. Skipping...');
|
|
15
|
+
return contents;
|
|
16
|
+
}
|
|
17
|
+
return contents.replace(
|
|
18
|
+
CIO_APP_APPLY_REGEX,
|
|
19
|
+
`$1\n${CIO_APP_GOOGLE_SNIPPET}`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
11
23
|
export const withAppGoogleServices: ConfigPlugin<
|
|
12
24
|
CustomerIOPluginOptionsAndroid
|
|
13
25
|
> = (configOuter) => {
|
|
14
26
|
return withAppBuildGradle(configOuter, (props) => {
|
|
15
|
-
|
|
16
|
-
const match = props.modResults.contents.match(regex);
|
|
17
|
-
if (!match) {
|
|
18
|
-
props.modResults.contents = props.modResults.contents.replace(
|
|
19
|
-
CIO_APP_APPLY_REGEX,
|
|
20
|
-
`$1\n${CIO_APP_GOOGLE_SNIPPET}`
|
|
21
|
-
);
|
|
22
|
-
} else {
|
|
23
|
-
logger.info('app/build.gradle snippet already exists. Skipping...');
|
|
24
|
-
}
|
|
25
|
-
|
|
27
|
+
props.modResults.contents = modifyAppBuildGradle(props.modResults.contents);
|
|
26
28
|
return props;
|
|
27
29
|
});
|
|
28
30
|
};
|
|
@@ -5,38 +5,40 @@ import { logger } from '../utils/logger';
|
|
|
5
5
|
import { FileManagement } from './../helpers/utils/fileManagement';
|
|
6
6
|
import type { CustomerIOPluginOptionsAndroid } from './../types/cio-types';
|
|
7
7
|
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
);
|
|
24
|
-
} catch {
|
|
25
|
-
logger.info(
|
|
26
|
-
`There was an error copying your google-services.json file. You can copy it manually into ${androidPath}/app/google-services.json`
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
} else {
|
|
30
|
-
logger.info(
|
|
31
|
-
`The Google Services file provided in ${googleServicesFile} doesn't seem to exist. You can copy it manually into ${androidPath}/app/google-services.json`
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
} else {
|
|
8
|
+
export function copyGoogleServicesFile(
|
|
9
|
+
androidPath: string,
|
|
10
|
+
googleServicesFile: string | undefined
|
|
11
|
+
): void {
|
|
12
|
+
const destination = `${androidPath}/app/google-services.json`;
|
|
13
|
+
|
|
14
|
+
if (FileManagement.exists(destination)) {
|
|
15
|
+
logger.info(`File already exists: ${destination}. Skipping...`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (googleServicesFile && FileManagement.exists(googleServicesFile)) {
|
|
20
|
+
try {
|
|
21
|
+
FileManagement.copyFile(googleServicesFile, destination);
|
|
22
|
+
} catch {
|
|
35
23
|
logger.info(
|
|
36
|
-
`
|
|
24
|
+
`There was an error copying your google-services.json file. You can copy it manually into ${destination}`
|
|
37
25
|
);
|
|
38
26
|
}
|
|
27
|
+
} else {
|
|
28
|
+
logger.info(
|
|
29
|
+
`The Google Services file provided in ${googleServicesFile} doesn't seem to exist. You can copy it manually into ${destination}`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
39
33
|
|
|
34
|
+
export const withGoogleServicesJSON: ConfigPlugin<
|
|
35
|
+
CustomerIOPluginOptionsAndroid
|
|
36
|
+
> = (configOuter, cioProps) => {
|
|
37
|
+
return withProjectBuildGradle(configOuter, (props) => {
|
|
38
|
+
copyGoogleServicesFile(
|
|
39
|
+
props.modRequest.platformProjectRoot,
|
|
40
|
+
cioProps?.googleServicesFile
|
|
41
|
+
);
|
|
40
42
|
return props;
|
|
41
43
|
});
|
|
42
44
|
};
|
|
@@ -6,6 +6,28 @@ import type { CustomerIOPluginLocationOptions } from '../types/cio-types';
|
|
|
6
6
|
|
|
7
7
|
const CUSTOMERIO_LOCATION_ENABLED_KEY = 'customerio_location_enabled';
|
|
8
8
|
|
|
9
|
+
export function modifyGradleProperties(
|
|
10
|
+
items: PropertiesItem[]
|
|
11
|
+
): PropertiesItem[] {
|
|
12
|
+
const existingIndex = items.findIndex(
|
|
13
|
+
(item) => item.type === 'property' && item.key === CUSTOMERIO_LOCATION_ENABLED_KEY
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const newItem: PropertiesItem = {
|
|
17
|
+
type: 'property',
|
|
18
|
+
key: CUSTOMERIO_LOCATION_ENABLED_KEY,
|
|
19
|
+
value: 'true',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (existingIndex >= 0) {
|
|
23
|
+
items[existingIndex] = newItem;
|
|
24
|
+
} else {
|
|
25
|
+
items.push(newItem);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return items;
|
|
29
|
+
}
|
|
30
|
+
|
|
9
31
|
/**
|
|
10
32
|
* Adds or updates customerio_location_enabled in android/gradle.properties when location.enabled is true.
|
|
11
33
|
* The Customer.io React Native SDK reads this to enable the location native module.
|
|
@@ -19,23 +41,7 @@ export const withLocationGradleProperties: ConfigPlugin<{
|
|
|
19
41
|
|
|
20
42
|
return withGradleProperties(config, (config) => {
|
|
21
43
|
const items = config.modResults as PropertiesItem[];
|
|
22
|
-
|
|
23
|
-
(item) => item.type === 'property' && item.key === CUSTOMERIO_LOCATION_ENABLED_KEY
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
const newItem: PropertiesItem = {
|
|
27
|
-
type: 'property',
|
|
28
|
-
key: CUSTOMERIO_LOCATION_ENABLED_KEY,
|
|
29
|
-
value: 'true',
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
if (existingIndex >= 0) {
|
|
33
|
-
items[existingIndex] = newItem;
|
|
34
|
-
} else {
|
|
35
|
-
items.push(newItem);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
config.modResults = items;
|
|
44
|
+
config.modResults = modifyGradleProperties(items);
|
|
39
45
|
return config;
|
|
40
46
|
});
|
|
41
47
|
};
|
|
@@ -36,6 +36,30 @@ const getLocationInitOptions = (
|
|
|
36
36
|
trackingMode: sdkConfig?.location?.trackingMode,
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
+
const SDK_INITIALIZER_CLASS = 'CustomerIOSDKInitializer';
|
|
40
|
+
const SDK_INITIALIZER_PACKAGE = 'io.customer.sdk.expo';
|
|
41
|
+
const SDK_INITIALIZER_FILE = `${SDK_INITIALIZER_CLASS}.kt`;
|
|
42
|
+
const SDK_INITIALIZER_IMPORT = `import ${SDK_INITIALIZER_PACKAGE}.${SDK_INITIALIZER_CLASS}`;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Pure string transform: given the existing MainApplication contents, returns the contents
|
|
46
|
+
* with the CustomerIOSDKInitializer import and onCreate call injected (idempotent — if the
|
|
47
|
+
* initialize call is already present, the call-injection step is skipped).
|
|
48
|
+
*/
|
|
49
|
+
export function injectCustomerIOInitializerIntoMainApplication(
|
|
50
|
+
contents: string
|
|
51
|
+
): string {
|
|
52
|
+
let next = addImportToFile(contents, SDK_INITIALIZER_IMPORT);
|
|
53
|
+
if (!next.includes(CIO_NATIVE_SDK_INITIALIZE_CALL)) {
|
|
54
|
+
next = addCodeToMethod(
|
|
55
|
+
next,
|
|
56
|
+
CIO_MAINAPPLICATION_ONCREATE_REGEX,
|
|
57
|
+
CIO_NATIVE_SDK_INITIALIZE_SNIPPET
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return next;
|
|
61
|
+
}
|
|
62
|
+
|
|
39
63
|
/**
|
|
40
64
|
* Setup CustomerIOSDKInitializer for Android auto initialization
|
|
41
65
|
*/
|
|
@@ -44,30 +68,16 @@ const setupCustomerIOSDKInitializer = (
|
|
|
44
68
|
sdkConfig: NativeSDKConfig,
|
|
45
69
|
location?: CustomerIOPluginLocationOptions,
|
|
46
70
|
): string => {
|
|
47
|
-
const SDK_INITIALIZER_CLASS = 'CustomerIOSDKInitializer';
|
|
48
|
-
const SDK_INITIALIZER_PACKAGE = 'io.customer.sdk.expo';
|
|
49
|
-
|
|
50
|
-
const SDK_INITIALIZER_FILE = `${SDK_INITIALIZER_CLASS}.kt`;
|
|
51
|
-
const SDK_INITIALIZER_IMPORT = `import ${SDK_INITIALIZER_PACKAGE}.${SDK_INITIALIZER_CLASS}`;
|
|
52
|
-
|
|
53
71
|
const locationOptions = getLocationInitOptions(location, sdkConfig);
|
|
54
|
-
let content = config.modResults.contents;
|
|
55
72
|
|
|
56
73
|
try {
|
|
57
74
|
// Always regenerate the CustomerIOSDKInitializer file to reflect config changes
|
|
58
75
|
copyTemplateFile(config, SDK_INITIALIZER_FILE, SDK_INITIALIZER_PACKAGE, (content) =>
|
|
59
76
|
patchNativeSDKInitializer(content, PLATFORM.ANDROID, sdkConfig, locationOptions)
|
|
60
77
|
);
|
|
61
|
-
|
|
62
|
-
content = addImportToFile(content, SDK_INITIALIZER_IMPORT);
|
|
63
|
-
// Add initialization code to onCreate if not already present
|
|
64
|
-
if (!content.includes(CIO_NATIVE_SDK_INITIALIZE_CALL)) {
|
|
65
|
-
content = addCodeToMethod(content, CIO_MAINAPPLICATION_ONCREATE_REGEX, CIO_NATIVE_SDK_INITIALIZE_SNIPPET);
|
|
66
|
-
}
|
|
78
|
+
return injectCustomerIOInitializerIntoMainApplication(config.modResults.contents);
|
|
67
79
|
} catch (error) {
|
|
68
80
|
logger.warn(`Could not setup ${SDK_INITIALIZER_CLASS}:`, error);
|
|
69
81
|
return config.modResults.contents;
|
|
70
82
|
}
|
|
71
|
-
|
|
72
|
-
return content;
|
|
73
83
|
};
|
|
@@ -7,7 +7,7 @@ import type { CustomerIOPluginOptionsAndroid } from '../types/cio-types';
|
|
|
7
7
|
/**
|
|
8
8
|
* Adds a metadata entry to the Android manifest if it doesn't already exist
|
|
9
9
|
*/
|
|
10
|
-
const addMetadataIfNotExists = (
|
|
10
|
+
export const addMetadataIfNotExists = (
|
|
11
11
|
application: ManifestApplication,
|
|
12
12
|
name: string,
|
|
13
13
|
value: string
|
|
@@ -23,6 +23,40 @@ function shouldDisableAndroid16Support(
|
|
|
23
23
|
return isExpoVersion53OrLower(config);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Pure string transform: injects an androidx resolution-strategy block into the
|
|
28
|
+
* project-level build.gradle's `allprojects { ... }` section when
|
|
29
|
+
* `disableAndroid16Support` is true. Idempotent — returns input unchanged if the
|
|
30
|
+
* snippet is already present, or if the flag is false.
|
|
31
|
+
*/
|
|
32
|
+
export function modifyProjectBuildGradleAndroid16Support(
|
|
33
|
+
contents: string,
|
|
34
|
+
options: { disableAndroid16Support: boolean }
|
|
35
|
+
): string {
|
|
36
|
+
if (!options.disableAndroid16Support) {
|
|
37
|
+
return contents;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (contents.includes('androidx.core:core-ktx:1.13.1')) {
|
|
41
|
+
return contents;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const resolutionStrategy = `
|
|
45
|
+
configurations.all {
|
|
46
|
+
resolutionStrategy {
|
|
47
|
+
// Disable Android 16 support by forcing older androidx versions
|
|
48
|
+
// Compatible with API 35 and AGP 8.8.2 (prevents API 36/AGP 8.9.1+ requirement)
|
|
49
|
+
force 'androidx.core:core-ktx:1.13.1'
|
|
50
|
+
force 'androidx.lifecycle:lifecycle-process:2.8.7'
|
|
51
|
+
}
|
|
52
|
+
}`;
|
|
53
|
+
|
|
54
|
+
return contents.replace(
|
|
55
|
+
/allprojects\s*\{/,
|
|
56
|
+
`allprojects {${resolutionStrategy}`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
26
60
|
/**
|
|
27
61
|
* Adds dependency resolution strategy to force specific androidx versions.
|
|
28
62
|
* This disables Android 16 support for apps using Expo SDK 53 or older gradle versions.
|
|
@@ -38,34 +72,10 @@ export function withProjectBuildGradle(
|
|
|
38
72
|
androidOptions?: CustomerIOPluginOptionsAndroid
|
|
39
73
|
): ExpoConfig {
|
|
40
74
|
return withExpoProjectBuildGradle(config, (config) => {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!shouldDisableAndroid16Support(config, androidOptions)) {
|
|
45
|
-
return config;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Skip if already applied
|
|
49
|
-
if (modResults.contents.includes('androidx.core:core-ktx:1.13.1')) {
|
|
50
|
-
return config;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const resolutionStrategy = `
|
|
54
|
-
configurations.all {
|
|
55
|
-
resolutionStrategy {
|
|
56
|
-
// Disable Android 16 support by forcing older androidx versions
|
|
57
|
-
// Compatible with API 35 and AGP 8.8.2 (prevents API 36/AGP 8.9.1+ requirement)
|
|
58
|
-
force 'androidx.core:core-ktx:1.13.1'
|
|
59
|
-
force 'androidx.lifecycle:lifecycle-process:2.8.7'
|
|
60
|
-
}
|
|
61
|
-
}`;
|
|
62
|
-
|
|
63
|
-
// Add resolution strategy inside allprojects block
|
|
64
|
-
modResults.contents = modResults.contents.replace(
|
|
65
|
-
/allprojects\s*\{/,
|
|
66
|
-
`allprojects {${resolutionStrategy}`
|
|
75
|
+
config.modResults.contents = modifyProjectBuildGradleAndroid16Support(
|
|
76
|
+
config.modResults.contents,
|
|
77
|
+
{ disableAndroid16Support: shouldDisableAndroid16Support(config, androidOptions) }
|
|
67
78
|
);
|
|
68
|
-
|
|
69
79
|
return config;
|
|
70
80
|
});
|
|
71
81
|
}
|
|
@@ -7,19 +7,24 @@ import {
|
|
|
7
7
|
} from './../helpers/constants/android';
|
|
8
8
|
import type { CustomerIOPluginOptionsAndroid } from './../types/cio-types';
|
|
9
9
|
|
|
10
|
+
export function modifyProjectBuildGradleForGoogleServices(contents: string): string {
|
|
11
|
+
const regex = new RegExp(CIO_PROJECT_GOOGLE_SNIPPET);
|
|
12
|
+
if (regex.test(contents)) {
|
|
13
|
+
return contents;
|
|
14
|
+
}
|
|
15
|
+
return contents.replace(
|
|
16
|
+
CIO_PROJECT_BUILDSCRIPTS_REGEX,
|
|
17
|
+
`$1\n${CIO_PROJECT_GOOGLE_SNIPPET}`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
export const withProjectGoogleServices: ConfigPlugin<
|
|
11
22
|
CustomerIOPluginOptionsAndroid
|
|
12
23
|
> = (configOuter) => {
|
|
13
24
|
return withProjectBuildGradle(configOuter, (props) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
props.modResults.contents = props.modResults.contents.replace(
|
|
18
|
-
CIO_PROJECT_BUILDSCRIPTS_REGEX,
|
|
19
|
-
`$1\n${CIO_PROJECT_GOOGLE_SNIPPET}`
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
25
|
+
props.modResults.contents = modifyProjectBuildGradleForGoogleServices(
|
|
26
|
+
props.modResults.contents
|
|
27
|
+
);
|
|
23
28
|
return props;
|
|
24
29
|
});
|
|
25
30
|
};
|