customerio-expo-plugin 2.0.2 → 2.1.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 +10 -10
- package/plugin/lib/commonjs/android/withAndroidManifestUpdates.js.map +1 -1
- package/plugin/lib/commonjs/android/withAppGoogleServices.js.map +1 -1
- package/plugin/lib/commonjs/android/withGistMavenRepository.js.map +1 -1
- package/plugin/lib/commonjs/android/withGoogleServicesJSON.js.map +1 -1
- package/plugin/lib/commonjs/android/withProjectGoogleServices.js.map +1 -1
- package/plugin/lib/commonjs/android/withProjectStrings.js.map +1 -1
- package/plugin/lib/commonjs/helpers/constants/ios.js +27 -1
- package/plugin/lib/commonjs/helpers/constants/ios.js.map +1 -1
- package/plugin/lib/commonjs/helpers/native-files/ios/apn/CioSdkAppDelegateHandler.swift +52 -0
- package/plugin/lib/commonjs/helpers/native-files/ios/fcm/CioSdkAppDelegateHandler.swift +74 -0
- package/plugin/lib/commonjs/helpers/utils/fileManagement.js.map +1 -1
- package/plugin/lib/commonjs/ios/utils.js +17 -2
- package/plugin/lib/commonjs/ios/utils.js.map +1 -1
- package/plugin/lib/commonjs/ios/withAppDelegateModifications.js.map +1 -1
- package/plugin/lib/commonjs/ios/withCIOIos.js +8 -1
- package/plugin/lib/commonjs/ios/withCIOIos.js.map +1 -1
- package/plugin/lib/commonjs/ios/withCIOIosSwift.js +269 -0
- package/plugin/lib/commonjs/ios/withCIOIosSwift.js.map +1 -0
- package/plugin/lib/commonjs/ios/withGoogleServicesJsonFile.js.map +1 -1
- package/plugin/lib/commonjs/ios/withNotificationsXcodeProject.js +4 -3
- package/plugin/lib/commonjs/ios/withNotificationsXcodeProject.js.map +1 -1
- package/plugin/lib/commonjs/ios/withXcodeProject.js.map +1 -1
- package/plugin/lib/module/android/withAndroidManifestUpdates.js.map +1 -1
- package/plugin/lib/module/android/withAppGoogleServices.js.map +1 -1
- package/plugin/lib/module/android/withGistMavenRepository.js.map +1 -1
- package/plugin/lib/module/android/withGoogleServicesJSON.js.map +1 -1
- package/plugin/lib/module/android/withProjectGoogleServices.js.map +1 -1
- package/plugin/lib/module/android/withProjectStrings.js.map +1 -1
- package/plugin/lib/module/helpers/constants/ios.js +26 -0
- package/plugin/lib/module/helpers/constants/ios.js.map +1 -1
- package/plugin/lib/module/helpers/native-files/ios/apn/CioSdkAppDelegateHandler.swift +52 -0
- package/plugin/lib/module/helpers/native-files/ios/fcm/CioSdkAppDelegateHandler.swift +74 -0
- package/plugin/lib/module/helpers/utils/fileManagement.js.map +1 -1
- package/plugin/lib/module/ios/utils.js +15 -1
- package/plugin/lib/module/ios/utils.js.map +1 -1
- package/plugin/lib/module/ios/withAppDelegateModifications.js.map +1 -1
- package/plugin/lib/module/ios/withCIOIos.js +8 -1
- package/plugin/lib/module/ios/withCIOIos.js.map +1 -1
- package/plugin/lib/module/ios/withCIOIosSwift.js +262 -0
- package/plugin/lib/module/ios/withCIOIosSwift.js.map +1 -0
- package/plugin/lib/module/ios/withGoogleServicesJsonFile.js.map +1 -1
- package/plugin/lib/module/ios/withNotificationsXcodeProject.js +5 -4
- package/plugin/lib/module/ios/withNotificationsXcodeProject.js.map +1 -1
- package/plugin/lib/module/ios/withXcodeProject.js.map +1 -1
- package/plugin/lib/typescript/android/withAndroidManifestUpdates.d.ts +1 -1
- package/plugin/lib/typescript/android/withAppGoogleServices.d.ts +1 -1
- package/plugin/lib/typescript/android/withGistMavenRepository.d.ts +1 -1
- package/plugin/lib/typescript/android/withGoogleServicesJSON.d.ts +1 -1
- package/plugin/lib/typescript/android/withProjectGoogleServices.d.ts +1 -1
- package/plugin/lib/typescript/android/withProjectStrings.d.ts +1 -1
- package/plugin/lib/typescript/helpers/constants/ios.d.ts +3 -0
- package/plugin/lib/typescript/helpers/utils/fileManagement.d.ts +1 -2
- package/plugin/lib/typescript/ios/utils.d.ts +2 -0
- package/plugin/lib/typescript/ios/withAppDelegateModifications.d.ts +1 -1
- package/plugin/lib/typescript/ios/withCIOIosSwift.d.ts +3 -0
- package/plugin/lib/typescript/ios/withGoogleServicesJsonFile.d.ts +1 -1
- package/plugin/lib/typescript/ios/withNotificationsXcodeProject.d.ts +1 -1
- package/plugin/lib/typescript/ios/withXcodeProject.d.ts +1 -1
- package/plugin/src/android/withAndroidManifestUpdates.ts +2 -1
- package/plugin/src/android/withAppGoogleServices.ts +2 -1
- package/plugin/src/android/withGistMavenRepository.ts +2 -1
- package/plugin/src/android/withGoogleServicesJSON.ts +2 -1
- package/plugin/src/android/withProjectGoogleServices.ts +2 -1
- package/plugin/src/android/withProjectStrings.ts +2 -1
- package/plugin/src/helpers/constants/ios.ts +29 -0
- package/plugin/src/helpers/native-files/ios/apn/CioSdkAppDelegateHandler.swift +52 -0
- package/plugin/src/helpers/native-files/ios/fcm/CioSdkAppDelegateHandler.swift +74 -0
- package/plugin/src/helpers/utils/fileManagement.ts +1 -1
- package/plugin/src/ios/utils.ts +20 -3
- package/plugin/src/ios/withAppDelegateModifications.ts +2 -1
- package/plugin/src/ios/withCIOIos.ts +15 -2
- package/plugin/src/ios/withCIOIosSwift.ts +384 -0
- package/plugin/src/ios/withGoogleServicesJsonFile.ts +1 -1
- package/plugin/src/ios/withNotificationsXcodeProject.ts +9 -9
- package/plugin/src/ios/withXcodeProject.ts +2 -1
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
import {
|
|
3
|
+
withAppDelegate,
|
|
4
|
+
withXcodeProject,
|
|
5
|
+
} from '@expo/config-plugins';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
|
|
8
|
+
import { FileManagement } from '../helpers/utils/fileManagement';
|
|
9
|
+
import {
|
|
10
|
+
LOCAL_PATH_TO_CIO_NSE_FILES,
|
|
11
|
+
CIO_REGISTER_PUSHNOTIFICATION_SNIPPET_v2,
|
|
12
|
+
CIO_REGISTER_PUSH_NOTIFICATION_PLACEHOLDER,
|
|
13
|
+
CIO_CONFIGUREDEEPLINK_KILLEDSTATE_SWIFT_SNIPPET,
|
|
14
|
+
} from '../helpers/constants/ios';
|
|
15
|
+
import { replaceCodeByRegex } from '../helpers/utils/codeInjection';
|
|
16
|
+
import { isFcmPushProvider } from './utils';
|
|
17
|
+
|
|
18
|
+
// Constants
|
|
19
|
+
const CIO_SDK_APP_DELEGATE_HANDLER_CLASS = 'CioSdkAppDelegateHandler';
|
|
20
|
+
const CIO_SDK_APP_DELEGATE_HANDLER_FILENAME = `${CIO_SDK_APP_DELEGATE_HANDLER_CLASS}.swift`;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Copy and configure the CioSdkAppDelegateHandler.swift file
|
|
24
|
+
*/
|
|
25
|
+
const copyAndConfigureAppDelegateHandler = (
|
|
26
|
+
config: any,
|
|
27
|
+
props: CustomerIOPluginOptionsIOS
|
|
28
|
+
): any => {
|
|
29
|
+
const projectRoot = config.modRequest.projectRoot;
|
|
30
|
+
const iosProjectRoot = path.join(projectRoot, 'ios');
|
|
31
|
+
const useFcm = isFcmPushProvider(props);
|
|
32
|
+
|
|
33
|
+
// Source path for the handler file
|
|
34
|
+
const handlerSourcePath = path.join(
|
|
35
|
+
LOCAL_PATH_TO_CIO_NSE_FILES,
|
|
36
|
+
useFcm ? 'fcm' : 'apn',
|
|
37
|
+
CIO_SDK_APP_DELEGATE_HANDLER_FILENAME
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Destination path in the iOS project
|
|
41
|
+
const projectName = config.modRequest.projectName || '';
|
|
42
|
+
if (!projectName) {
|
|
43
|
+
console.warn(
|
|
44
|
+
'Project name is undefined, cannot copy CioSdkAppDelegateHandler.swift'
|
|
45
|
+
);
|
|
46
|
+
return config;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const handlerDestPath = path.join(
|
|
50
|
+
iosProjectRoot,
|
|
51
|
+
projectName,
|
|
52
|
+
CIO_SDK_APP_DELEGATE_HANDLER_FILENAME
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
FileManagement.copyFile(handlerSourcePath, handlerDestPath);
|
|
56
|
+
|
|
57
|
+
// Add the file to the Xcode project
|
|
58
|
+
const xcodeProject = config.modResults;
|
|
59
|
+
|
|
60
|
+
// Create a group for CustomerIO files if it doesn't exist
|
|
61
|
+
let group;
|
|
62
|
+
const existingGroup = xcodeProject.pbxGroupByName('CustomerIO');
|
|
63
|
+
if (existingGroup) {
|
|
64
|
+
group = existingGroup;
|
|
65
|
+
} else {
|
|
66
|
+
group = xcodeProject.pbxCreateGroup('CustomerIO');
|
|
67
|
+
const classesKey = xcodeProject.findPBXGroupKey({ name: projectName });
|
|
68
|
+
xcodeProject.addToPbxGroup(group, classesKey);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Add the file to the Xcode project
|
|
72
|
+
xcodeProject.addSourceFile(
|
|
73
|
+
`${projectName}/${CIO_SDK_APP_DELEGATE_HANDLER_FILENAME}`,
|
|
74
|
+
null,
|
|
75
|
+
group
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
let handlerFileContent = FileManagement.readFile(handlerDestPath);
|
|
79
|
+
|
|
80
|
+
const disableNotificationRegistration =
|
|
81
|
+
props.pushNotification?.disableNotificationRegistration;
|
|
82
|
+
let snippet = '';
|
|
83
|
+
// unless this property is explicity set to true, push notification
|
|
84
|
+
// registration will be added to the AppDelegate
|
|
85
|
+
if (disableNotificationRegistration !== true) {
|
|
86
|
+
snippet = CIO_REGISTER_PUSHNOTIFICATION_SNIPPET_v2;
|
|
87
|
+
}
|
|
88
|
+
handlerFileContent = replaceCodeByRegex(
|
|
89
|
+
handlerFileContent,
|
|
90
|
+
CIO_REGISTER_PUSH_NOTIFICATION_PLACEHOLDER,
|
|
91
|
+
snippet
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const autoTrackPushEvents =
|
|
95
|
+
props.pushNotification?.autoTrackPushEvents !== false;
|
|
96
|
+
handlerFileContent = replaceCodeByRegex(
|
|
97
|
+
handlerFileContent,
|
|
98
|
+
/\{\{AUTO_TRACK_PUSH_EVENTS\}\}/,
|
|
99
|
+
autoTrackPushEvents.toString()
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const autoFetchDeviceToken =
|
|
103
|
+
props.pushNotification?.autoFetchDeviceToken !== false;
|
|
104
|
+
handlerFileContent = replaceCodeByRegex(
|
|
105
|
+
handlerFileContent,
|
|
106
|
+
/\{\{AUTO_FETCH_DEVICE_TOKEN\}\}/,
|
|
107
|
+
autoFetchDeviceToken.toString()
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const showPushAppInForeground =
|
|
111
|
+
props.pushNotification?.showPushAppInForeground !== false;
|
|
112
|
+
handlerFileContent = replaceCodeByRegex(
|
|
113
|
+
handlerFileContent,
|
|
114
|
+
/\{\{SHOW_PUSH_APP_IN_FOREGROUND\}\}/,
|
|
115
|
+
showPushAppInForeground.toString()
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
FileManagement.writeFile(handlerDestPath, handlerFileContent);
|
|
119
|
+
|
|
120
|
+
return config;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const withCIOIosSwift: ConfigPlugin<CustomerIOPluginOptionsIOS> = (
|
|
124
|
+
configOuter,
|
|
125
|
+
props
|
|
126
|
+
) => {
|
|
127
|
+
// First, copy the CioSdkAppDelegateHandler.swift file to the iOS project and add it to Xcode project
|
|
128
|
+
configOuter = withXcodeProject(configOuter, async (config) => {
|
|
129
|
+
return copyAndConfigureAppDelegateHandler(config, props);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// Then modify the AppDelegate
|
|
133
|
+
return withAppDelegate(configOuter, async (config) => {
|
|
134
|
+
return modifyAppDelegate(config, props);
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Modify the AppDelegate to integrate with Customer.io SDK
|
|
140
|
+
*/
|
|
141
|
+
const modifyAppDelegate = (
|
|
142
|
+
config: any,
|
|
143
|
+
props: CustomerIOPluginOptionsIOS
|
|
144
|
+
): any => {
|
|
145
|
+
const appDelegateContent = config.modResults.contents;
|
|
146
|
+
|
|
147
|
+
// Check if modifications have already been applied
|
|
148
|
+
if (appDelegateContent.includes(CIO_SDK_APP_DELEGATE_HANDLER_CLASS)) {
|
|
149
|
+
console.log(
|
|
150
|
+
'CustomerIO Swift AppDelegate changes already exist. Skipping...'
|
|
151
|
+
);
|
|
152
|
+
return config;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Add the handler property declaration
|
|
156
|
+
let modifiedContent = addHandlerPropertyDeclaration(appDelegateContent);
|
|
157
|
+
|
|
158
|
+
// Modify didFinishLaunchingWithOptions to initialize and call the handler
|
|
159
|
+
modifiedContent = modifyDidFinishLaunchingWithOptions(modifiedContent);
|
|
160
|
+
|
|
161
|
+
// Add didRegisterForRemoteNotificationsWithDeviceToken implementation
|
|
162
|
+
modifiedContent =
|
|
163
|
+
addDidRegisterForRemoteNotificationsWithDeviceToken(modifiedContent);
|
|
164
|
+
|
|
165
|
+
// Add didFailToRegisterForRemoteNotificationsWithError implementation
|
|
166
|
+
modifiedContent =
|
|
167
|
+
addDidFailToRegisterForRemoteNotificationsWithError(modifiedContent);
|
|
168
|
+
|
|
169
|
+
// Add deep link handling for killed state if enabled
|
|
170
|
+
if (props.pushNotification?.handleDeeplinkInKilledState === true) {
|
|
171
|
+
modifiedContent = addHandleDeeplinkInKilledState(modifiedContent);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
config.modResults.contents = modifiedContent;
|
|
175
|
+
return config;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Check if a method exists in the AppDelegate content
|
|
180
|
+
* @param content The AppDelegate content
|
|
181
|
+
* @param methodSignature The method signature to check for
|
|
182
|
+
* @returns true if the method exists, false otherwise
|
|
183
|
+
*/
|
|
184
|
+
const methodExistsInAppDelegate = (
|
|
185
|
+
content: string,
|
|
186
|
+
methodSignature: string
|
|
187
|
+
): boolean => {
|
|
188
|
+
return content.includes(methodSignature);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Add handler property declaration to the AppDelegate class
|
|
193
|
+
* This adds the line: let cioSdkHandler = CioSdkAppDelegateHandler()
|
|
194
|
+
* to the AppDelegate class
|
|
195
|
+
*/
|
|
196
|
+
const addHandlerPropertyDeclaration = (content: string): string => {
|
|
197
|
+
// Look for the AppDelegate class declaration
|
|
198
|
+
const classDeclarationRegex = /class\s+AppDelegate\s*:\s*.*\s*{/;
|
|
199
|
+
const match = content.match(classDeclarationRegex);
|
|
200
|
+
|
|
201
|
+
if (!match) {
|
|
202
|
+
console.warn('Could not find AppDelegate class declaration');
|
|
203
|
+
return content;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const position = match.index! + match[0].length;
|
|
207
|
+
return (
|
|
208
|
+
content.substring(0, position) +
|
|
209
|
+
`\n let cioSdkHandler = ${CIO_SDK_APP_DELEGATE_HANDLER_CLASS}()\n` +
|
|
210
|
+
content.substring(position)
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Modify didFinishLaunchingWithOptions to call the handler
|
|
216
|
+
* This adds the handler call before the return statement in didFinishLaunchingWithOptions
|
|
217
|
+
*/
|
|
218
|
+
const modifyDidFinishLaunchingWithOptions = (content: string): string => {
|
|
219
|
+
// Find the return statement in didFinishLaunchingWithOptions
|
|
220
|
+
// Always look for launchOptions since modifiedLaunchOptions is only set later
|
|
221
|
+
const returnStatementRegex = /return\s+super\.application\s*\(\s*application\s*,\s*didFinishLaunchingWithOptions\s*:\s*launchOptions\s*\)/;
|
|
222
|
+
|
|
223
|
+
const returnStatementMatch = content.match(returnStatementRegex);
|
|
224
|
+
|
|
225
|
+
if (!returnStatementMatch) {
|
|
226
|
+
console.warn(
|
|
227
|
+
'Could not find return statement with super.application in didFinishLaunchingWithOptions'
|
|
228
|
+
);
|
|
229
|
+
return content;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Add handler call before the return statement
|
|
233
|
+
const insertPosition = returnStatementMatch.index!;
|
|
234
|
+
const handlerCallCode = ` cioSdkHandler.application(application, didFinishLaunchingWithOptions: launchOptions)\n\n `;
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
content.substring(0, insertPosition) +
|
|
238
|
+
handlerCallCode +
|
|
239
|
+
content.substring(insertPosition)
|
|
240
|
+
);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Add or modify didRegisterForRemoteNotificationsWithDeviceToken implementation
|
|
245
|
+
* If the method already exists, it adds the handler call to the existing method
|
|
246
|
+
* If the method doesn't exist, it adds a new method implementation
|
|
247
|
+
*/
|
|
248
|
+
const addDidRegisterForRemoteNotificationsWithDeviceToken = (
|
|
249
|
+
content: string
|
|
250
|
+
): string => {
|
|
251
|
+
const methodSignature = 'func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken:';
|
|
252
|
+
|
|
253
|
+
// Check if method already exists
|
|
254
|
+
if (methodExistsInAppDelegate(content, methodSignature)) {
|
|
255
|
+
// Method exists, modify it to call our handler
|
|
256
|
+
const methodRegex =
|
|
257
|
+
/func\s+application\s*\(\s*_\s+application\s*:\s*UIApplication\s*,\s*didRegisterForRemoteNotificationsWithDeviceToken\s+deviceToken\s*:\s*Data\s*\)\s*{[\s\S]*?}/;
|
|
258
|
+
const match = content.match(methodRegex);
|
|
259
|
+
|
|
260
|
+
if (match) {
|
|
261
|
+
// Add our handler call to the existing method
|
|
262
|
+
const methodContent = match[0];
|
|
263
|
+
const openBraceIndex = methodContent.indexOf('{') + 1;
|
|
264
|
+
const modifiedMethod =
|
|
265
|
+
methodContent.substring(0, openBraceIndex) +
|
|
266
|
+
'\n // Call CustomerIO SDK handler\n' +
|
|
267
|
+
' cioSdkHandler.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)\n' +
|
|
268
|
+
methodContent.substring(openBraceIndex);
|
|
269
|
+
|
|
270
|
+
return content.replace(methodRegex, modifiedMethod);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return content;
|
|
274
|
+
} else {
|
|
275
|
+
// Method doesn't exist, add it inside the AppDelegate class
|
|
276
|
+
// Find the end of the AppDelegate class
|
|
277
|
+
const classEndRegex = /^}(\s*$|\s*\/\/)/m;
|
|
278
|
+
const classEndMatch = content.match(classEndRegex);
|
|
279
|
+
|
|
280
|
+
if (!classEndMatch) {
|
|
281
|
+
console.warn('Could not find end of AppDelegate class');
|
|
282
|
+
return content;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Insert the method inside the class
|
|
286
|
+
const position = classEndMatch.index!;
|
|
287
|
+
return (
|
|
288
|
+
content.substring(0, position) +
|
|
289
|
+
'\n // Handle device token registration\n' +
|
|
290
|
+
' public override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {\n' +
|
|
291
|
+
' // Call CustomerIO SDK handler\n' +
|
|
292
|
+
' cioSdkHandler.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)\n' +
|
|
293
|
+
' super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)\n' +
|
|
294
|
+
' }\n' +
|
|
295
|
+
content.substring(position)
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Add or modify didFailToRegisterForRemoteNotificationsWithError implementation
|
|
302
|
+
* If the method already exists, it adds the handler call to the existing method
|
|
303
|
+
* If the method doesn't exist, it adds a new method implementation
|
|
304
|
+
*/
|
|
305
|
+
const addDidFailToRegisterForRemoteNotificationsWithError = (
|
|
306
|
+
content: string
|
|
307
|
+
): string => {
|
|
308
|
+
const methodSignature = 'func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error:';
|
|
309
|
+
|
|
310
|
+
// Check if method already exists
|
|
311
|
+
if (methodExistsInAppDelegate(content, methodSignature)) {
|
|
312
|
+
// Method exists, modify it to call our handler
|
|
313
|
+
const methodRegex =
|
|
314
|
+
/func\s+application\s*\(\s*_\s+application\s*:\s*UIApplication\s*,\s*didFailToRegisterForRemoteNotificationsWithError\s+error\s*:\s*Error\s*\)\s*{[\s\S]*?}/;
|
|
315
|
+
const match = content.match(methodRegex);
|
|
316
|
+
|
|
317
|
+
if (match) {
|
|
318
|
+
// Add our handler call to the existing method
|
|
319
|
+
const methodContent = match[0];
|
|
320
|
+
const openBraceIndex = methodContent.indexOf('{') + 1;
|
|
321
|
+
const modifiedMethod =
|
|
322
|
+
methodContent.substring(0, openBraceIndex) +
|
|
323
|
+
'\n // Call CustomerIO SDK handler\n' +
|
|
324
|
+
' cioSdkHandler.application(application, didFailToRegisterForRemoteNotificationsWithError: error)\n' +
|
|
325
|
+
methodContent.substring(openBraceIndex);
|
|
326
|
+
|
|
327
|
+
return content.replace(methodRegex, modifiedMethod);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return content;
|
|
331
|
+
} else {
|
|
332
|
+
// Method doesn't exist, add it inside the AppDelegate class
|
|
333
|
+
// Find the end of the AppDelegate class
|
|
334
|
+
const classEndRegex = /^}(\s*$|\s*\/\/)/m;
|
|
335
|
+
const classEndMatch = content.match(classEndRegex);
|
|
336
|
+
|
|
337
|
+
if (!classEndMatch) {
|
|
338
|
+
console.warn('Could not find end of AppDelegate class');
|
|
339
|
+
return content;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Insert the method inside the class
|
|
343
|
+
const position = classEndMatch.index!;
|
|
344
|
+
return (
|
|
345
|
+
content.substring(0, position) +
|
|
346
|
+
'\n // Handle remote notification registration errors\n' +
|
|
347
|
+
' public override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {\n' +
|
|
348
|
+
' // Call CustomerIO SDK handler\n' +
|
|
349
|
+
' cioSdkHandler.application(application, didFailToRegisterForRemoteNotificationsWithError: error)\n' +
|
|
350
|
+
' super.application(application, didFailToRegisterForRemoteNotificationsWithError: error)\n' +
|
|
351
|
+
' }\n' +
|
|
352
|
+
content.substring(position)
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Add deep link handling for killed state
|
|
359
|
+
* This replaces the return statement with deep link handling code
|
|
360
|
+
* and a modified return statement that uses modifiedLaunchOptions
|
|
361
|
+
*/
|
|
362
|
+
const addHandleDeeplinkInKilledState = (content: string): string => {
|
|
363
|
+
// Check if deep link code snippet is already present
|
|
364
|
+
const deepLinkMarker = "Deep link workaround for app killed state start";
|
|
365
|
+
if (content.includes(deepLinkMarker)) {
|
|
366
|
+
return content;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Find the return statement with launchOptions
|
|
370
|
+
const returnStatementRegex = /return\s+super\.application\s*\(\s*application\s*,\s*didFinishLaunchingWithOptions\s*:\s*launchOptions\s*\)/;
|
|
371
|
+
const returnStatementMatch = content.match(returnStatementRegex);
|
|
372
|
+
|
|
373
|
+
if (!returnStatementMatch) {
|
|
374
|
+
console.warn("Could not find return statement with launchOptions");
|
|
375
|
+
return content;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Create the replacement code with deep link handling and modified return statement
|
|
379
|
+
const modifiedReturnStatement = "return super.application(application, didFinishLaunchingWithOptions: modifiedLaunchOptions)";
|
|
380
|
+
const replacementCode = CIO_CONFIGUREDEEPLINK_KILLEDSTATE_SWIFT_SNIPPET + "\n\n " + modifiedReturnStatement;
|
|
381
|
+
|
|
382
|
+
// Replace the return statement with deep link handling code and modified return statement
|
|
383
|
+
return content.replace(returnStatementRegex, replacementCode);
|
|
384
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
withXcodeProject,
|
|
3
3
|
IOSConfig,
|
|
4
|
-
ConfigPlugin,
|
|
5
4
|
} from '@expo/config-plugins';
|
|
5
|
+
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
6
6
|
|
|
7
7
|
import { FileManagement } from './../helpers/utils/fileManagement';
|
|
8
8
|
import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
XcodeProject,
|
|
4
|
-
withXcodeProject,
|
|
5
|
-
} from '@expo/config-plugins';
|
|
1
|
+
import type { ConfigPlugin, XcodeProject } from '@expo/config-plugins';
|
|
2
|
+
import { withXcodeProject } from '@expo/config-plugins';
|
|
6
3
|
|
|
7
4
|
import {
|
|
8
5
|
CIO_NOTIFICATION_TARGET_NAME,
|
|
@@ -14,7 +11,7 @@ import { replaceCodeByRegex } from '../helpers/utils/codeInjection';
|
|
|
14
11
|
import { injectCIONotificationPodfileCode } from '../helpers/utils/injectCIOPodfileCode';
|
|
15
12
|
import type { CustomerIOPluginOptionsIOS } from '../types/cio-types';
|
|
16
13
|
import { FileManagement } from './../helpers/utils/fileManagement';
|
|
17
|
-
import { isFcmPushProvider } from './utils';
|
|
14
|
+
import { isExpoVersion53OrHigher, isFcmPushProvider } from './utils';
|
|
18
15
|
|
|
19
16
|
const PLIST_FILENAME = `${CIO_NOTIFICATION_TARGET_NAME}-Info.plist`;
|
|
20
17
|
const ENV_FILENAME = 'Env.swift';
|
|
@@ -23,10 +20,12 @@ const TARGETED_DEVICE_FAMILY = `"1,2"`;
|
|
|
23
20
|
|
|
24
21
|
const addNotificationServiceExtension = async (
|
|
25
22
|
options: CustomerIOPluginOptionsIOS,
|
|
26
|
-
xcodeProject: XcodeProject
|
|
23
|
+
xcodeProject: XcodeProject,
|
|
24
|
+
isExpoVersion53OrHigher: boolean
|
|
27
25
|
) => {
|
|
28
26
|
try {
|
|
29
|
-
|
|
27
|
+
// PushService file is only needed for pre-Expo 53 code generation
|
|
28
|
+
if (options.pushNotification && !isExpoVersion53OrHigher) {
|
|
30
29
|
await addPushNotificationFile(options, xcodeProject);
|
|
31
30
|
}
|
|
32
31
|
|
|
@@ -88,7 +87,8 @@ export const withCioNotificationsXcodeProject: ConfigPlugin<
|
|
|
88
87
|
|
|
89
88
|
const modifiedProjectFile = await addNotificationServiceExtension(
|
|
90
89
|
options,
|
|
91
|
-
config.modResults
|
|
90
|
+
config.modResults,
|
|
91
|
+
isExpoVersion53OrHigher(configOuter)
|
|
92
92
|
);
|
|
93
93
|
|
|
94
94
|
if (modifiedProjectFile) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ConfigPlugin
|
|
1
|
+
import type { ConfigPlugin } from '@expo/config-plugins';
|
|
2
|
+
import { withXcodeProject } from '@expo/config-plugins';
|
|
2
3
|
|
|
3
4
|
import { isFcmPushProvider } from './utils';
|
|
4
5
|
import { injectCIOPodfileCode } from '../helpers/utils/injectCIOPodfileCode';
|