customerio-expo-plugin 3.1.0 → 3.2.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 +3 -2
- package/plugin/lib/commonjs/android/withCIOAndroid.js +13 -2
- package/plugin/lib/commonjs/android/withCIOAndroid.js.map +1 -1
- package/plugin/lib/commonjs/android/withLocationGradleProperties.js +37 -0
- package/plugin/lib/commonjs/android/withLocationGradleProperties.js.map +1 -0
- package/plugin/lib/commonjs/android/withMainApplicationModifications.js +21 -5
- package/plugin/lib/commonjs/android/withMainApplicationModifications.js.map +1 -1
- package/plugin/lib/commonjs/helpers/native-files/android/CustomerIOSDKInitializer.kt +2 -0
- package/plugin/lib/commonjs/helpers/native-files/ios/CustomerIOSDKInitializer.swift +2 -0
- package/plugin/lib/commonjs/helpers/utils/injectCIOPodfileCode.js +19 -2
- package/plugin/lib/commonjs/helpers/utils/injectCIOPodfileCode.js.map +1 -1
- package/plugin/lib/commonjs/helpers/utils/patchLocationCode.js +50 -0
- package/plugin/lib/commonjs/helpers/utils/patchLocationCode.js.map +1 -0
- package/plugin/lib/commonjs/helpers/utils/patchPluginNativeCode.js +3 -1
- package/plugin/lib/commonjs/helpers/utils/patchPluginNativeCode.js.map +1 -1
- package/plugin/lib/commonjs/index.js +2 -2
- package/plugin/lib/commonjs/index.js.map +1 -1
- package/plugin/lib/commonjs/ios/withCIOIos.js +29 -4
- package/plugin/lib/commonjs/ios/withCIOIos.js.map +1 -1
- package/plugin/lib/commonjs/ios/withCIOIosSwift.js +19 -9
- package/plugin/lib/commonjs/ios/withCIOIosSwift.js.map +1 -1
- package/plugin/lib/commonjs/ios/withXcodeProject.js +4 -1
- package/plugin/lib/commonjs/ios/withXcodeProject.js.map +1 -1
- package/plugin/lib/commonjs/types/cio-types.js.map +1 -1
- package/plugin/lib/module/android/withCIOAndroid.js +13 -2
- package/plugin/lib/module/android/withCIOAndroid.js.map +1 -1
- package/plugin/lib/module/android/withLocationGradleProperties.js +30 -0
- package/plugin/lib/module/android/withLocationGradleProperties.js.map +1 -0
- package/plugin/lib/module/android/withMainApplicationModifications.js +20 -4
- package/plugin/lib/module/android/withMainApplicationModifications.js.map +1 -1
- package/plugin/lib/module/helpers/native-files/android/CustomerIOSDKInitializer.kt +2 -0
- package/plugin/lib/module/helpers/native-files/ios/CustomerIOSDKInitializer.swift +2 -0
- package/plugin/lib/module/helpers/utils/injectCIOPodfileCode.js +18 -2
- package/plugin/lib/module/helpers/utils/injectCIOPodfileCode.js.map +1 -1
- package/plugin/lib/module/helpers/utils/patchLocationCode.js +44 -0
- package/plugin/lib/module/helpers/utils/patchLocationCode.js.map +1 -0
- package/plugin/lib/module/helpers/utils/patchPluginNativeCode.js +3 -2
- package/plugin/lib/module/helpers/utils/patchPluginNativeCode.js.map +1 -1
- package/plugin/lib/module/index.js +2 -2
- package/plugin/lib/module/index.js.map +1 -1
- package/plugin/lib/module/ios/withCIOIos.js +29 -4
- package/plugin/lib/module/ios/withCIOIos.js.map +1 -1
- package/plugin/lib/module/ios/withCIOIosSwift.js +19 -9
- package/plugin/lib/module/ios/withCIOIosSwift.js.map +1 -1
- package/plugin/lib/module/ios/withXcodeProject.js +5 -1
- package/plugin/lib/module/ios/withXcodeProject.js.map +1 -1
- package/plugin/lib/module/types/cio-types.js.map +1 -1
- package/plugin/lib/typescript/android/withCIOAndroid.d.ts +2 -2
- package/plugin/lib/typescript/android/withLocationGradleProperties.d.ts +9 -0
- package/plugin/lib/typescript/android/withMainApplicationModifications.d.ts +7 -2
- package/plugin/lib/typescript/helpers/utils/injectCIOPodfileCode.d.ts +9 -1
- package/plugin/lib/typescript/helpers/utils/patchLocationCode.d.ts +12 -0
- package/plugin/lib/typescript/helpers/utils/patchPluginNativeCode.d.ts +3 -1
- package/plugin/lib/typescript/index.d.ts +2 -1
- package/plugin/lib/typescript/ios/withCIOIos.d.ts +2 -2
- package/plugin/lib/typescript/ios/withCIOIosSwift.d.ts +2 -2
- package/plugin/lib/typescript/ios/withXcodeProject.d.ts +8 -1
- package/plugin/lib/typescript/types/cio-types.d.ts +28 -0
- package/plugin/src/android/withCIOAndroid.ts +13 -2
- package/plugin/src/android/withLocationGradleProperties.ts +41 -0
- package/plugin/src/android/withMainApplicationModifications.ts +26 -4
- package/plugin/src/helpers/native-files/android/CustomerIOSDKInitializer.kt +2 -0
- package/plugin/src/helpers/native-files/ios/CustomerIOSDKInitializer.swift +2 -0
- package/plugin/src/helpers/utils/injectCIOPodfileCode.ts +35 -3
- package/plugin/src/helpers/utils/patchLocationCode.ts +80 -0
- package/plugin/src/helpers/utils/patchPluginNativeCode.ts +10 -1
- package/plugin/src/index.ts +9 -3
- package/plugin/src/ios/withCIOIos.ts +24 -3
- package/plugin/src/ios/withCIOIosSwift.ts +20 -4
- package/plugin/src/ios/withXcodeProject.ts +20 -3
- package/plugin/src/types/cio-types.ts +30 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExpoConfig } from '@expo/config-types';
|
|
2
|
-
import type { CustomerIOPluginOptions } from './types/cio-types';
|
|
2
|
+
import type { CustomerIOPluginOptions, LocationTrackingMode, NativeSDKConfig } from './types/cio-types';
|
|
3
|
+
export type { LocationTrackingMode, NativeSDKConfig };
|
|
3
4
|
declare function withCustomerIOPlugin(config: ExpoConfig, props: CustomerIOPluginOptions): ExpoConfig;
|
|
4
5
|
export default withCustomerIOPlugin;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ExpoConfig } from '@expo/config-types';
|
|
2
|
-
import type { CustomerIOPluginOptionsIOS, NativeSDKConfig } from '../types/cio-types';
|
|
3
|
-
export declare function withCIOIos(config: ExpoConfig, sdkConfig?: NativeSDKConfig, props?: CustomerIOPluginOptionsIOS): ExpoConfig;
|
|
2
|
+
import type { CustomerIOPluginOptionsIOS, CustomerIOPluginLocationOptions, NativeSDKConfig } from '../types/cio-types';
|
|
3
|
+
export declare function withCIOIos(config: ExpoConfig, sdkConfig?: NativeSDKConfig, props?: CustomerIOPluginOptionsIOS, location?: CustomerIOPluginLocationOptions): ExpoConfig;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { ExpoConfig } from '@expo/config-types';
|
|
2
|
-
import type { CustomerIOPluginOptionsIOS, NativeSDKConfig } from '../types/cio-types';
|
|
3
|
-
export declare const withCIOIosSwift: (configOuter: ExpoConfig, sdkConfig?: NativeSDKConfig, props?: CustomerIOPluginOptionsIOS) => ExpoConfig;
|
|
2
|
+
import type { CustomerIOPluginOptionsIOS, CustomerIOPluginLocationOptions, NativeSDKConfig } from '../types/cio-types';
|
|
3
|
+
export declare const withCIOIosSwift: (configOuter: ExpoConfig, sdkConfig?: NativeSDKConfig, props?: CustomerIOPluginOptionsIOS, location?: CustomerIOPluginLocationOptions) => ExpoConfig;
|
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
import { type InjectCIOPodfileOptions } from '../helpers/utils/injectCIOPodfileCode';
|
|
2
3
|
import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
|
|
3
|
-
export
|
|
4
|
+
export type WithCioXcodeProjectOptions = {
|
|
5
|
+
/** Options for Podfile host app snippet (location subspec, etc.) */
|
|
6
|
+
podfileOptions?: InjectCIOPodfileOptions;
|
|
7
|
+
};
|
|
8
|
+
/** Props for the CIO Xcode project mod; push options are optional when only location is enabled. */
|
|
9
|
+
export type WithCioXcodeProjectProps = Partial<CustomerIOPluginOptionsIOS> & WithCioXcodeProjectOptions;
|
|
10
|
+
export declare const withCioXcodeProject: ConfigPlugin<WithCioXcodeProjectProps>;
|
|
@@ -76,6 +76,12 @@ export type CustomerIOPluginOptionsAndroid = {
|
|
|
76
76
|
*/
|
|
77
77
|
disableAndroid16Support?: boolean;
|
|
78
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Location tracking mode for the Customer.io SDK location module.
|
|
81
|
+
* Location is off by default. Only used when location is enabled (plugin option location.enabled: true).
|
|
82
|
+
* @public
|
|
83
|
+
*/
|
|
84
|
+
export type LocationTrackingMode = 'OFF' | 'MANUAL' | 'ON_APP_START';
|
|
79
85
|
/**
|
|
80
86
|
* SDK configuration options for auto initialization
|
|
81
87
|
* @public
|
|
@@ -89,6 +95,23 @@ export type NativeSDKConfig = {
|
|
|
89
95
|
logLevel?: 'none' | 'error' | 'info' | 'debug';
|
|
90
96
|
siteId?: string;
|
|
91
97
|
migrationSiteId?: string;
|
|
98
|
+
/**
|
|
99
|
+
* Location module config. Location is off by default; only applied when plugin option location.enabled is true.
|
|
100
|
+
* trackingMode: 'MANUAL' (host app controls when location is captured, default),
|
|
101
|
+
* 'ON_APP_START' (SDK captures once per launch when app becomes active), or 'OFF'.
|
|
102
|
+
*/
|
|
103
|
+
location?: {
|
|
104
|
+
trackingMode?: LocationTrackingMode;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Location is off by default. When true, enables the Customer.io SDK location native module (iOS Podfile location subspec,
|
|
109
|
+
* Android gradle.properties flag). Permissions and privacy keys (Info.plist, AndroidManifest)
|
|
110
|
+
* remain the host app's responsibility.
|
|
111
|
+
* @public
|
|
112
|
+
*/
|
|
113
|
+
export type CustomerIOPluginLocationOptions = {
|
|
114
|
+
enabled?: boolean;
|
|
92
115
|
};
|
|
93
116
|
/**
|
|
94
117
|
* Combined plugin options for both iOS and Android platforms
|
|
@@ -98,6 +121,11 @@ export type CustomerIOPluginOptions = {
|
|
|
98
121
|
config?: NativeSDKConfig;
|
|
99
122
|
android: CustomerIOPluginOptionsAndroid;
|
|
100
123
|
ios: CustomerIOPluginOptionsIOS;
|
|
124
|
+
/**
|
|
125
|
+
* Location is off by default. When location.enabled is true, the plugin adds SDK build-time setup (Podfile location subspec,
|
|
126
|
+
* gradle.properties). Host apps must add their own location permissions and privacy usage strings.
|
|
127
|
+
*/
|
|
128
|
+
location?: CustomerIOPluginLocationOptions;
|
|
101
129
|
};
|
|
102
130
|
/**
|
|
103
131
|
* Rich push configuration used to initialize Notification Service Extension (NSE) on the native side
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { ExpoConfig } from '@expo/config-types';
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
CustomerIOPluginOptionsAndroid,
|
|
5
|
+
CustomerIOPluginLocationOptions,
|
|
6
|
+
NativeSDKConfig,
|
|
7
|
+
} from '../types/cio-types';
|
|
4
8
|
import { withAndroidManifestUpdates } from './withAndroidManifestUpdates';
|
|
5
9
|
import { withAppGoogleServices } from './withAppGoogleServices';
|
|
6
10
|
import { withGoogleServicesJSON } from './withGoogleServicesJSON';
|
|
11
|
+
import { withLocationGradleProperties } from './withLocationGradleProperties';
|
|
7
12
|
import { withMainApplicationModifications } from './withMainApplicationModifications';
|
|
8
13
|
import { withNotificationChannelMetadata } from './withNotificationChannelMetadata';
|
|
9
14
|
import { withProjectBuildGradle } from './withProjectBuildGradle';
|
|
@@ -14,6 +19,7 @@ export function withCIOAndroid(
|
|
|
14
19
|
config: ExpoConfig,
|
|
15
20
|
sdkConfig?: NativeSDKConfig,
|
|
16
21
|
props?: CustomerIOPluginOptionsAndroid,
|
|
22
|
+
location?: CustomerIOPluginLocationOptions,
|
|
17
23
|
): ExpoConfig {
|
|
18
24
|
// Only run notification setup if props are provided
|
|
19
25
|
if (props) {
|
|
@@ -30,7 +36,7 @@ export function withCIOAndroid(
|
|
|
30
36
|
|
|
31
37
|
// Add auto initialization if sdkConfig is provided
|
|
32
38
|
if (sdkConfig) {
|
|
33
|
-
config = withMainApplicationModifications(config, sdkConfig);
|
|
39
|
+
config = withMainApplicationModifications(config, { sdkConfig, location });
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
// Update project strings for user agent metadata
|
|
@@ -40,5 +46,10 @@ export function withCIOAndroid(
|
|
|
40
46
|
// This prevents androidx versions that require API 36 from being pulled in
|
|
41
47
|
config = withProjectBuildGradle(config, props);
|
|
42
48
|
|
|
49
|
+
// Enable SDK location module when location.enabled is true
|
|
50
|
+
if (location?.enabled === true) {
|
|
51
|
+
config = withLocationGradleProperties(config, { location });
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
return config;
|
|
44
55
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
import { withGradleProperties } from '@expo/config-plugins';
|
|
3
|
+
import type { PropertiesItem } from '@expo/config-plugins/build/android/Properties';
|
|
4
|
+
|
|
5
|
+
import type { CustomerIOPluginLocationOptions } from '../types/cio-types';
|
|
6
|
+
|
|
7
|
+
const CUSTOMERIO_LOCATION_ENABLED_KEY = 'customerio_location_enabled';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Adds or updates customerio_location_enabled in android/gradle.properties when location.enabled is true.
|
|
11
|
+
* The Customer.io React Native SDK reads this to enable the location native module.
|
|
12
|
+
*/
|
|
13
|
+
export const withLocationGradleProperties: ConfigPlugin<{
|
|
14
|
+
location?: CustomerIOPluginLocationOptions;
|
|
15
|
+
}> = (config, props) => {
|
|
16
|
+
if (props?.location?.enabled !== true) {
|
|
17
|
+
return config;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return withGradleProperties(config, (config) => {
|
|
21
|
+
const items = config.modResults as PropertiesItem[];
|
|
22
|
+
const existingIndex = items.findIndex(
|
|
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;
|
|
39
|
+
return config;
|
|
40
|
+
});
|
|
41
|
+
};
|
|
@@ -4,24 +4,45 @@ import type { ApplicationProjectFile } from '@expo/config-plugins/build/android/
|
|
|
4
4
|
import { CIO_MAINAPPLICATION_ONCREATE_REGEX, CIO_NATIVE_SDK_INITIALIZE_CALL, CIO_NATIVE_SDK_INITIALIZE_SNIPPET } from '../helpers/constants/android';
|
|
5
5
|
import { PLATFORM } from '../helpers/constants/common';
|
|
6
6
|
import { patchNativeSDKInitializer } from '../helpers/utils/patchPluginNativeCode';
|
|
7
|
-
import type {
|
|
7
|
+
import type {
|
|
8
|
+
CustomerIOPluginLocationOptions,
|
|
9
|
+
NativeSDKConfig,
|
|
10
|
+
} from '../types/cio-types';
|
|
8
11
|
import { addCodeToMethod, addImportToFile, copyTemplateFile } from '../utils/android';
|
|
9
12
|
import { logger } from '../utils/logger';
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
type MainApplicationModParams = {
|
|
15
|
+
sdkConfig: NativeSDKConfig;
|
|
16
|
+
location?: CustomerIOPluginLocationOptions;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const withMainApplicationModifications: ConfigPlugin<MainApplicationModParams> = (configOuter, { sdkConfig, location }) => {
|
|
12
20
|
return withMainApplication(configOuter, async (config) => {
|
|
13
|
-
const content = setupCustomerIOSDKInitializer(config, sdkConfig);
|
|
21
|
+
const content = setupCustomerIOSDKInitializer(config, sdkConfig, location);
|
|
14
22
|
config.modResults.contents = content;
|
|
15
23
|
return config;
|
|
16
24
|
});
|
|
17
25
|
};
|
|
18
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Build location options for native initializer from plugin config.
|
|
29
|
+
* trackingMode comes from config.location.trackingMode (only used when location.enabled is true).
|
|
30
|
+
*/
|
|
31
|
+
const getLocationInitOptions = (
|
|
32
|
+
location?: CustomerIOPluginLocationOptions,
|
|
33
|
+
sdkConfig?: NativeSDKConfig
|
|
34
|
+
) => ({
|
|
35
|
+
enabled: location?.enabled === true,
|
|
36
|
+
trackingMode: sdkConfig?.location?.trackingMode,
|
|
37
|
+
});
|
|
38
|
+
|
|
19
39
|
/**
|
|
20
40
|
* Setup CustomerIOSDKInitializer for Android auto initialization
|
|
21
41
|
*/
|
|
22
42
|
const setupCustomerIOSDKInitializer = (
|
|
23
43
|
config: ExportedConfigWithProps<ApplicationProjectFile>,
|
|
24
44
|
sdkConfig: NativeSDKConfig,
|
|
45
|
+
location?: CustomerIOPluginLocationOptions,
|
|
25
46
|
): string => {
|
|
26
47
|
const SDK_INITIALIZER_CLASS = 'CustomerIOSDKInitializer';
|
|
27
48
|
const SDK_INITIALIZER_PACKAGE = 'io.customer.sdk.expo';
|
|
@@ -29,12 +50,13 @@ const setupCustomerIOSDKInitializer = (
|
|
|
29
50
|
const SDK_INITIALIZER_FILE = `${SDK_INITIALIZER_CLASS}.kt`;
|
|
30
51
|
const SDK_INITIALIZER_IMPORT = `import ${SDK_INITIALIZER_PACKAGE}.${SDK_INITIALIZER_CLASS}`;
|
|
31
52
|
|
|
53
|
+
const locationOptions = getLocationInitOptions(location, sdkConfig);
|
|
32
54
|
let content = config.modResults.contents;
|
|
33
55
|
|
|
34
56
|
try {
|
|
35
57
|
// Always regenerate the CustomerIOSDKInitializer file to reflect config changes
|
|
36
58
|
copyTemplateFile(config, SDK_INITIALIZER_FILE, SDK_INITIALIZER_PACKAGE, (content) =>
|
|
37
|
-
patchNativeSDKInitializer(content, PLATFORM.ANDROID, sdkConfig)
|
|
59
|
+
patchNativeSDKInitializer(content, PLATFORM.ANDROID, sdkConfig, locationOptions)
|
|
38
60
|
);
|
|
39
61
|
// Add import if not already present
|
|
40
62
|
content = addImportToFile(content, SDK_INITIALIZER_IMPORT);
|
|
@@ -7,6 +7,7 @@ import io.customer.messaginginapp.ModuleMessagingInApp
|
|
|
7
7
|
import io.customer.messagingpush.MessagingPushModuleConfig
|
|
8
8
|
import io.customer.messagingpush.ModuleMessagingPushFCM
|
|
9
9
|
import io.customer.reactnative.sdk.messaginginapp.ReactInAppEventListener
|
|
10
|
+
{{LOCATION_MODULE_IMPORT}}
|
|
10
11
|
import io.customer.sdk.CustomerIOBuilder
|
|
11
12
|
import io.customer.sdk.core.util.CioLogLevel
|
|
12
13
|
import io.customer.sdk.data.model.Region
|
|
@@ -41,6 +42,7 @@ object CustomerIOSDKInitializer {
|
|
|
41
42
|
MessagingPushModuleConfig.Builder().build()
|
|
42
43
|
)
|
|
43
44
|
)
|
|
45
|
+
{{LOCATION_MODULE_INIT}}
|
|
44
46
|
|
|
45
47
|
build()
|
|
46
48
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import CioDataPipelines
|
|
2
2
|
import CioInternalCommon
|
|
3
3
|
import CioMessagingInApp
|
|
4
|
+
{{LOCATION_MODULE_IMPORT}}
|
|
4
5
|
|
|
5
6
|
class CustomerIOSDKInitializer {
|
|
6
7
|
static func initialize() {
|
|
@@ -23,6 +24,7 @@ class CustomerIOSDKInitializer {
|
|
|
23
24
|
setIfDefined(value: {{SCREEN_VIEW_USE}}, thenPassItTo: builder.screenViewUse) { ScreenView.getScreenView($0) }
|
|
24
25
|
setIfDefined(value: {{MIGRATION_SITE_ID}}, thenPassItTo: builder.migrationSiteId)
|
|
25
26
|
|
|
27
|
+
{{LOCATION_MODULE_INIT}}
|
|
26
28
|
CustomerIO.initialize(withConfig: builder.build())
|
|
27
29
|
|
|
28
30
|
if let siteId = siteId {
|
|
@@ -4,9 +4,40 @@ import { getRelativePathToRNSDK } from '../constants/ios';
|
|
|
4
4
|
import { injectCodeByRegex } from './codeInjection';
|
|
5
5
|
import { FileManagement } from './fileManagement';
|
|
6
6
|
|
|
7
|
+
export type InjectCIOPodfileOptions = {
|
|
8
|
+
/** When true, add the location subspec. When false/omit, use single push subspec only. */
|
|
9
|
+
locationEnabled?: boolean;
|
|
10
|
+
/** When false and locationEnabled, inject only :subspecs => ['location']. When true, use push + location. */
|
|
11
|
+
hasPush?: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** Builds the host app pod line for the Podfile (single subspec or :subspecs with location). Exported for tests. */
|
|
15
|
+
export function buildHostAppPodSnippet(
|
|
16
|
+
iosPath: string,
|
|
17
|
+
isFcmPushProvider: boolean,
|
|
18
|
+
options?: InjectCIOPodfileOptions
|
|
19
|
+
): string {
|
|
20
|
+
const path = getRelativePathToRNSDK(iosPath);
|
|
21
|
+
const locationEnabled = options?.locationEnabled === true;
|
|
22
|
+
const hasPush = options?.hasPush !== false;
|
|
23
|
+
|
|
24
|
+
if (!locationEnabled) {
|
|
25
|
+
const subspec = isFcmPushProvider ? 'fcm' : 'apn';
|
|
26
|
+
return `pod 'customerio-reactnative/${subspec}', :path => '${path}'`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!hasPush) {
|
|
30
|
+
return `pod 'customerio-reactnative', :subspecs => ['location'], :path => '${path}'`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const pushSubspec = isFcmPushProvider ? 'fcm' : 'apn';
|
|
34
|
+
return `pod 'customerio-reactnative', :subspecs => ['${pushSubspec}', 'location'], :path => '${path}'`;
|
|
35
|
+
}
|
|
36
|
+
|
|
7
37
|
export async function injectCIOPodfileCode(
|
|
8
38
|
iosPath: string,
|
|
9
|
-
isFcmPushProvider: boolean
|
|
39
|
+
isFcmPushProvider: boolean,
|
|
40
|
+
options?: InjectCIOPodfileOptions
|
|
10
41
|
) {
|
|
11
42
|
const blockStart = '# --- CustomerIO Host App START ---';
|
|
12
43
|
const blockEnd = '# --- CustomerIO Host App END ---';
|
|
@@ -21,10 +52,11 @@ export async function injectCIOPodfileCode(
|
|
|
21
52
|
// Find that line in the Podfile and then we will insert our code above that line.
|
|
22
53
|
const lineInPodfileToInjectSnippetBefore = /post_install do \|installer\|/;
|
|
23
54
|
|
|
55
|
+
const podLine = buildHostAppPodSnippet(iosPath, isFcmPushProvider, options);
|
|
56
|
+
|
|
24
57
|
const snippetToInjectInPodfile = `
|
|
25
58
|
${blockStart}
|
|
26
|
-
|
|
27
|
-
}', :path => '${getRelativePathToRNSDK(iosPath)}'
|
|
59
|
+
${podLine}
|
|
28
60
|
${blockEnd}
|
|
29
61
|
`.trim();
|
|
30
62
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { LocationTrackingMode } from '../../types/cio-types';
|
|
2
|
+
import { PLATFORM, type Platform } from '../constants/common';
|
|
3
|
+
|
|
4
|
+
const VALID_TRACKING_MODES: LocationTrackingMode[] = ['OFF', 'MANUAL', 'ON_APP_START'];
|
|
5
|
+
|
|
6
|
+
/** Options for location module in generated native initializer */
|
|
7
|
+
export type LocationInitOptions = {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
trackingMode?: LocationTrackingMode;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function normalizeTrackingMode(
|
|
13
|
+
rawMode: string | undefined
|
|
14
|
+
): LocationTrackingMode {
|
|
15
|
+
const upper = rawMode?.toUpperCase();
|
|
16
|
+
return upper && VALID_TRACKING_MODES.includes(upper as LocationTrackingMode)
|
|
17
|
+
? (upper as LocationTrackingMode)
|
|
18
|
+
: 'MANUAL';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Replaces {{LOCATION_MODULE_IMPORT}} and {{LOCATION_MODULE_INIT}} placeholders
|
|
23
|
+
* in SDK initializer template content for the given platform.
|
|
24
|
+
*/
|
|
25
|
+
export function patchLocationPlaceholders(
|
|
26
|
+
content: string,
|
|
27
|
+
platform: Platform,
|
|
28
|
+
locationOptions?: LocationInitOptions
|
|
29
|
+
): string {
|
|
30
|
+
const locationEnabled = locationOptions?.enabled === true;
|
|
31
|
+
const trackingMode = normalizeTrackingMode(locationOptions?.trackingMode);
|
|
32
|
+
|
|
33
|
+
if (platform === PLATFORM.ANDROID) {
|
|
34
|
+
if (locationEnabled) {
|
|
35
|
+
return content
|
|
36
|
+
.replace(
|
|
37
|
+
/\{\{LOCATION_MODULE_IMPORT\}\}/g,
|
|
38
|
+
`import io.customer.location.LocationModuleConfig
|
|
39
|
+
import io.customer.location.LocationTrackingMode
|
|
40
|
+
import io.customer.location.ModuleLocation
|
|
41
|
+
`
|
|
42
|
+
)
|
|
43
|
+
.replace(
|
|
44
|
+
/\{\{LOCATION_MODULE_INIT\}\}/g,
|
|
45
|
+
`if (io.customer.reactnative.sdk.BuildConfig.CIO_LOCATION_ENABLED) {
|
|
46
|
+
addCustomerIOModule(
|
|
47
|
+
ModuleLocation(
|
|
48
|
+
LocationModuleConfig.Builder()
|
|
49
|
+
.setLocationTrackingMode(LocationTrackingMode.${trackingMode})
|
|
50
|
+
.build()
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return content
|
|
58
|
+
.replace(/\n\{\{LOCATION_MODULE_IMPORT\}\}\n/g, '\n')
|
|
59
|
+
.replace(/\n\s*\{\{LOCATION_MODULE_INIT\}\}\n/g, '\n');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// iOS
|
|
63
|
+
if (locationEnabled) {
|
|
64
|
+
const modeSwift =
|
|
65
|
+
trackingMode === 'OFF'
|
|
66
|
+
? '.off'
|
|
67
|
+
: trackingMode === 'ON_APP_START'
|
|
68
|
+
? '.onAppStart'
|
|
69
|
+
: '.manual';
|
|
70
|
+
return content
|
|
71
|
+
.replace(/\{\{LOCATION_MODULE_IMPORT\}\}/g, 'import CioLocation\n')
|
|
72
|
+
.replace(
|
|
73
|
+
/\{\{LOCATION_MODULE_INIT\}\}/g,
|
|
74
|
+
`_ = builder.addModule(LocationModule(config: LocationConfig(mode: ${modeSwift})))`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return content
|
|
78
|
+
.replace(/\n\{\{LOCATION_MODULE_IMPORT\}\}\n/g, '\n')
|
|
79
|
+
.replace(/\n\s*\{\{LOCATION_MODULE_INIT\}\}\n/g, '\n\n');
|
|
80
|
+
}
|
|
@@ -2,6 +2,12 @@ import type { NativeSDKConfig } from '../../types/cio-types';
|
|
|
2
2
|
import { getPluginVersion } from '../../utils/plugin';
|
|
3
3
|
import { validateNativeSDKConfig } from '../../utils/validation';
|
|
4
4
|
import { PLATFORM, type Platform } from '../constants/common';
|
|
5
|
+
import {
|
|
6
|
+
type LocationInitOptions,
|
|
7
|
+
patchLocationPlaceholders,
|
|
8
|
+
} from './patchLocationCode';
|
|
9
|
+
|
|
10
|
+
export type { LocationInitOptions };
|
|
5
11
|
|
|
6
12
|
/**
|
|
7
13
|
* Shared utility function to perform common SDK config replacements
|
|
@@ -10,7 +16,8 @@ import { PLATFORM, type Platform } from '../constants/common';
|
|
|
10
16
|
export function patchNativeSDKInitializer(
|
|
11
17
|
rawContent: string,
|
|
12
18
|
platform: Platform,
|
|
13
|
-
sdkConfig: NativeSDKConfig
|
|
19
|
+
sdkConfig: NativeSDKConfig,
|
|
20
|
+
locationOptions?: LocationInitOptions
|
|
14
21
|
): string {
|
|
15
22
|
// Validate SDK configuration to ensure all fields are present and
|
|
16
23
|
// correct at the time of patching in prebuild
|
|
@@ -98,5 +105,7 @@ export function patchNativeSDKInitializer(
|
|
|
98
105
|
(configValue) => `"${configValue}"`
|
|
99
106
|
);
|
|
100
107
|
|
|
108
|
+
content = patchLocationPlaceholders(content, platform, locationOptions);
|
|
109
|
+
|
|
101
110
|
return content;
|
|
102
111
|
}
|
package/plugin/src/index.ts
CHANGED
|
@@ -3,7 +3,13 @@ import type { ExpoConfig } from '@expo/config-types';
|
|
|
3
3
|
import { withCIOAndroid } from './android/withCIOAndroid';
|
|
4
4
|
import { isExpoVersion53OrHigher } from './ios/utils';
|
|
5
5
|
import { withCIOIos } from './ios/withCIOIos';
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
CustomerIOPluginOptions,
|
|
8
|
+
LocationTrackingMode,
|
|
9
|
+
NativeSDKConfig,
|
|
10
|
+
} from './types/cio-types';
|
|
11
|
+
|
|
12
|
+
export type { LocationTrackingMode, NativeSDKConfig };
|
|
7
13
|
|
|
8
14
|
// Entry point for config plugin
|
|
9
15
|
function withCustomerIOPlugin(
|
|
@@ -20,8 +26,8 @@ function withCustomerIOPlugin(
|
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
// Apply platform specific modifications
|
|
23
|
-
config = withCIOIos(config, props.config, props.ios);
|
|
24
|
-
config = withCIOAndroid(config, props.config, props.android);
|
|
29
|
+
config = withCIOIos(config, props.config, props.ios, props.location);
|
|
30
|
+
config = withCIOAndroid(config, props.config, props.android, props.location);
|
|
25
31
|
|
|
26
32
|
return config;
|
|
27
33
|
}
|
|
@@ -2,6 +2,7 @@ import type { ExpoConfig } from '@expo/config-types';
|
|
|
2
2
|
import type {
|
|
3
3
|
CustomerIOPluginOptionsIOS,
|
|
4
4
|
CustomerIOPluginPushNotificationOptions,
|
|
5
|
+
CustomerIOPluginLocationOptions,
|
|
5
6
|
NativeSDKConfig,
|
|
6
7
|
} from '../types/cio-types';
|
|
7
8
|
import { mergeConfigWithEnvValues } from '../utils/config';
|
|
@@ -17,13 +18,15 @@ export function withCIOIos(
|
|
|
17
18
|
config: ExpoConfig,
|
|
18
19
|
sdkConfig?: NativeSDKConfig,
|
|
19
20
|
props?: CustomerIOPluginOptionsIOS,
|
|
21
|
+
location?: CustomerIOPluginLocationOptions,
|
|
20
22
|
) {
|
|
21
23
|
const isSwiftProject = isExpoVersion53OrHigher(config);
|
|
22
24
|
const platformConfig = mergeDeprecatedPropertiesAndLogWarnings(props);
|
|
25
|
+
const locationEnabled = location?.enabled === true;
|
|
23
26
|
|
|
24
27
|
if (platformConfig?.pushNotification) {
|
|
25
28
|
if (isSwiftProject) {
|
|
26
|
-
config = withCIOIosSwift(config, sdkConfig, platformConfig);
|
|
29
|
+
config = withCIOIosSwift(config, sdkConfig, platformConfig, location);
|
|
27
30
|
} else {
|
|
28
31
|
// Auto initialization is only supported in Swift projects (Expo SDK 53+)
|
|
29
32
|
// Legacy Objective-C projects only support push notifications
|
|
@@ -33,10 +36,28 @@ export function withCIOIos(
|
|
|
33
36
|
platformConfig.pushNotification.env = platformConfig.pushNotification.env
|
|
34
37
|
|| mergeConfigWithEnvValues(platformConfig, sdkConfig);
|
|
35
38
|
config = withCioNotificationsXcodeProject(config, platformConfig);
|
|
36
|
-
config = withCioXcodeProject(config,
|
|
39
|
+
config = withCioXcodeProject(config, {
|
|
40
|
+
...platformConfig,
|
|
41
|
+
podfileOptions: {
|
|
42
|
+
locationEnabled,
|
|
43
|
+
hasPush: true,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
37
46
|
config = withGoogleServicesJsonFile(config, platformConfig);
|
|
38
47
|
} else if (sdkConfig && isSwiftProject) {
|
|
39
|
-
config = withCIOIosSwift(config, sdkConfig, platformConfig);
|
|
48
|
+
config = withCIOIosSwift(config, sdkConfig, platformConfig, location);
|
|
49
|
+
if (locationEnabled) {
|
|
50
|
+
config = withCioXcodeProject(config, {
|
|
51
|
+
...platformConfig,
|
|
52
|
+
podfileOptions: { locationEnabled: true, hasPush: false },
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
} else if (locationEnabled) {
|
|
56
|
+
// Location-only: no push, no config. Still add Podfile location subspec so CIO_LOCATION_ENABLED is set and native location code is included.
|
|
57
|
+
config = withCioXcodeProject(config, {
|
|
58
|
+
...platformConfig,
|
|
59
|
+
podfileOptions: { locationEnabled: true, hasPush: false },
|
|
60
|
+
});
|
|
40
61
|
}
|
|
41
62
|
|
|
42
63
|
return config;
|
|
@@ -17,7 +17,11 @@ import {
|
|
|
17
17
|
import { replaceCodeByRegex } from '../helpers/utils/codeInjection';
|
|
18
18
|
import { FileManagement } from '../helpers/utils/fileManagement';
|
|
19
19
|
import { patchNativeSDKInitializer } from '../helpers/utils/patchPluginNativeCode';
|
|
20
|
-
import type {
|
|
20
|
+
import type {
|
|
21
|
+
CustomerIOPluginOptionsIOS,
|
|
22
|
+
CustomerIOPluginLocationOptions,
|
|
23
|
+
NativeSDKConfig,
|
|
24
|
+
} from '../types/cio-types';
|
|
21
25
|
import { logger } from '../utils/logger';
|
|
22
26
|
import { getIosNativeFilesPath } from '../utils/plugin';
|
|
23
27
|
import { copyFileToXcode, getOrCreateCustomerIOGroup } from '../utils/xcode';
|
|
@@ -34,6 +38,7 @@ const copyAndConfigureAppDelegateHandler = (
|
|
|
34
38
|
config: ExportedConfigWithProps<XcodeProject>,
|
|
35
39
|
sdkConfig?: NativeSDKConfig,
|
|
36
40
|
props?: CustomerIOPluginOptionsIOS,
|
|
41
|
+
location?: CustomerIOPluginLocationOptions,
|
|
37
42
|
): ExportedConfigWithProps<XcodeProject> => {
|
|
38
43
|
// Destination path in the iOS project
|
|
39
44
|
const projectName = config.modRequest.projectName || '';
|
|
@@ -59,6 +64,7 @@ const copyAndConfigureAppDelegateHandler = (
|
|
|
59
64
|
projectName,
|
|
60
65
|
sdkConfig,
|
|
61
66
|
props,
|
|
67
|
+
location,
|
|
62
68
|
});
|
|
63
69
|
} else if (sdkConfig) {
|
|
64
70
|
// Copy only CustomerIOSDKInitializer.swift for auto-init without push notifications
|
|
@@ -68,6 +74,7 @@ const copyAndConfigureAppDelegateHandler = (
|
|
|
68
74
|
iosProjectRoot,
|
|
69
75
|
projectName,
|
|
70
76
|
sdkConfig,
|
|
77
|
+
location,
|
|
71
78
|
});
|
|
72
79
|
}
|
|
73
80
|
|
|
@@ -81,6 +88,7 @@ const copyAndConfigurePushAppDelegateHandler = ({
|
|
|
81
88
|
projectName,
|
|
82
89
|
sdkConfig,
|
|
83
90
|
props,
|
|
91
|
+
location,
|
|
84
92
|
}: {
|
|
85
93
|
xcodeProject: XcodeProject;
|
|
86
94
|
group: XcodeProject['pbxCreateGroup'];
|
|
@@ -88,6 +96,7 @@ const copyAndConfigurePushAppDelegateHandler = ({
|
|
|
88
96
|
projectName: string;
|
|
89
97
|
sdkConfig: NativeSDKConfig | undefined;
|
|
90
98
|
props: CustomerIOPluginOptionsIOS;
|
|
99
|
+
location?: CustomerIOPluginLocationOptions;
|
|
91
100
|
}) => {
|
|
92
101
|
const useFcm = isFcmPushProvider(props);
|
|
93
102
|
|
|
@@ -156,7 +165,7 @@ const copyAndConfigurePushAppDelegateHandler = ({
|
|
|
156
165
|
// Add auto initialization if sdkConfig is provided
|
|
157
166
|
if (sdkConfig) {
|
|
158
167
|
// Also copy CustomerIOSDKInitializer.swift for auto-initialization
|
|
159
|
-
copyAndConfigureNativeSDKInitializer({ xcodeProject, group, iosProjectRoot, projectName, sdkConfig });
|
|
168
|
+
copyAndConfigureNativeSDKInitializer({ xcodeProject, group, iosProjectRoot, projectName, sdkConfig, location });
|
|
160
169
|
|
|
161
170
|
// Inject auto initialization call before MessagingPush initialization
|
|
162
171
|
handlerFileContent = handlerFileContent.replace(CIO_MESSAGING_PUSH_APP_DELEGATE_INIT_REGEX, CIO_NATIVE_SDK_INITIALIZE_SNIPPET + '$1');
|
|
@@ -171,13 +180,18 @@ const copyAndConfigureNativeSDKInitializer = ({
|
|
|
171
180
|
iosProjectRoot,
|
|
172
181
|
projectName,
|
|
173
182
|
sdkConfig,
|
|
183
|
+
location,
|
|
174
184
|
}: {
|
|
175
185
|
xcodeProject: XcodeProject;
|
|
176
186
|
group: XcodeProject['pbxCreateGroup'];
|
|
177
187
|
iosProjectRoot: string;
|
|
178
188
|
projectName: string;
|
|
179
189
|
sdkConfig: NativeSDKConfig;
|
|
190
|
+
location?: CustomerIOPluginLocationOptions;
|
|
180
191
|
}) => {
|
|
192
|
+
const locationOptions = location
|
|
193
|
+
? { enabled: location.enabled === true, trackingMode: sdkConfig?.location?.trackingMode }
|
|
194
|
+
: undefined;
|
|
181
195
|
const filename = 'CustomerIOSDKInitializer.swift';
|
|
182
196
|
const sourcePath = path.join(getIosNativeFilesPath(), filename);
|
|
183
197
|
// Add the CustomerIOSDKInitializer.swift file to the same Xcode group as CioSdkAppDelegateHandler
|
|
@@ -187,7 +201,8 @@ const copyAndConfigureNativeSDKInitializer = ({
|
|
|
187
201
|
projectName,
|
|
188
202
|
sourceFilePath: sourcePath,
|
|
189
203
|
targetFileName: filename,
|
|
190
|
-
transform: (content) =>
|
|
204
|
+
transform: (content) =>
|
|
205
|
+
patchNativeSDKInitializer(content, PLATFORM.IOS, sdkConfig, locationOptions),
|
|
191
206
|
customerIOGroup: group,
|
|
192
207
|
});
|
|
193
208
|
};
|
|
@@ -196,10 +211,11 @@ export const withCIOIosSwift = (
|
|
|
196
211
|
configOuter: ExpoConfig,
|
|
197
212
|
sdkConfig?: NativeSDKConfig,
|
|
198
213
|
props?: CustomerIOPluginOptionsIOS,
|
|
214
|
+
location?: CustomerIOPluginLocationOptions,
|
|
199
215
|
) => {
|
|
200
216
|
// First, copy required swift files to iOS folder and add it to Xcode project
|
|
201
217
|
configOuter = withXcodeProject(configOuter, async (config) => {
|
|
202
|
-
return copyAndConfigureAppDelegateHandler(config, sdkConfig, props);
|
|
218
|
+
return copyAndConfigureAppDelegateHandler(config, sdkConfig, props, location);
|
|
203
219
|
});
|
|
204
220
|
|
|
205
221
|
// Modify the AppDelegate based on configuration
|
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
2
|
import { withXcodeProject } from '@expo/config-plugins';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
injectCIOPodfileCode,
|
|
6
|
+
type InjectCIOPodfileOptions,
|
|
7
|
+
} from '../helpers/utils/injectCIOPodfileCode';
|
|
5
8
|
import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
|
|
6
9
|
import { isFcmPushProvider } from './utils';
|
|
7
10
|
|
|
8
|
-
export
|
|
11
|
+
export type WithCioXcodeProjectOptions = {
|
|
12
|
+
/** Options for Podfile host app snippet (location subspec, etc.) */
|
|
13
|
+
podfileOptions?: InjectCIOPodfileOptions;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** Props for the CIO Xcode project mod; push options are optional when only location is enabled. */
|
|
17
|
+
export type WithCioXcodeProjectProps = Partial<CustomerIOPluginOptionsIOS> &
|
|
18
|
+
WithCioXcodeProjectOptions;
|
|
19
|
+
|
|
20
|
+
export const withCioXcodeProject: ConfigPlugin<WithCioXcodeProjectProps> = (
|
|
9
21
|
config,
|
|
10
22
|
cioProps
|
|
11
23
|
) => {
|
|
12
24
|
return withXcodeProject(config, async (props) => {
|
|
13
25
|
const iosPath = props.modRequest.platformProjectRoot;
|
|
26
|
+
const podfileOptions = cioProps?.podfileOptions;
|
|
14
27
|
|
|
15
|
-
await injectCIOPodfileCode(
|
|
28
|
+
await injectCIOPodfileCode(
|
|
29
|
+
iosPath,
|
|
30
|
+
isFcmPushProvider(cioProps as CustomerIOPluginOptionsIOS | undefined),
|
|
31
|
+
podfileOptions
|
|
32
|
+
);
|
|
16
33
|
|
|
17
34
|
return props;
|
|
18
35
|
});
|