Replace expo-notifications with JPush for push notifications across the app. This includes adding JPush native module dependencies, configuring the JPush plugin in app.json, implementing jpushService wrapper, and updating notification services to use JPush APIs. Also adds device registration on token refresh for both mobile and web platforms. BREAKING CHANGE: expo-notifications removed in favor of JPush for push notifications
155 lines
5.3 KiB
JavaScript
155 lines
5.3 KiB
JavaScript
const {
|
|
withAndroidManifest,
|
|
withDangerousMod,
|
|
withAppDelegate,
|
|
withInfoPlist,
|
|
withAppBuildGradle,
|
|
} = require('@expo/config-plugins');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const withJPush = (config, options = {}) => {
|
|
const { appKey, channel = 'developer-default' } = options;
|
|
|
|
if (!appKey) {
|
|
throw new Error('JPush appKey is required in plugin options');
|
|
}
|
|
|
|
// 1. Android: Inject manifestPlaceholders into app/build.gradle
|
|
config = withAppBuildGradle(config, (config) => {
|
|
const block = '\n manifestPlaceholders = [\n' +
|
|
' JPUSH_APPKEY: "' + appKey + '",\n' +
|
|
' JPUSH_CHANNEL: "' + channel + '"\n' +
|
|
' ]';
|
|
|
|
const contents = config.modResults.contents;
|
|
|
|
if (contents.includes('manifestPlaceholders')) {
|
|
config.modResults.contents = contents.replace(
|
|
/manifestPlaceholders\s*=\s*\[[\s\S]*?\]/,
|
|
block.trim()
|
|
);
|
|
} else if (contents.includes('REACT_NATIVE_RELEASE_LEVEL')) {
|
|
const lines = contents.split('\n');
|
|
for (let i = 0; i < lines.length; i++) {
|
|
if (lines[i].includes('REACT_NATIVE_RELEASE_LEVEL')) {
|
|
lines.splice(i + 1, 0, block);
|
|
break;
|
|
}
|
|
}
|
|
config.modResults.contents = lines.join('\n');
|
|
}
|
|
|
|
return config;
|
|
});
|
|
|
|
// 2. Android: Add JPush metadata and permissions to AndroidManifest
|
|
config = withAndroidManifest(config, (config) => {
|
|
const manifest = config.modResults;
|
|
|
|
if (!manifest.manifest['uses-permission']) {
|
|
manifest.manifest['uses-permission'] = [];
|
|
}
|
|
|
|
const requiredPermissions = [
|
|
'android.permission.RECEIVE_USER_PRESENT',
|
|
'android.permission.POST_NOTIFICATIONS',
|
|
];
|
|
|
|
requiredPermissions.forEach((permission) => {
|
|
const exists = manifest.manifest['uses-permission'].find(
|
|
(p) => p.$['android:name'] === permission
|
|
);
|
|
if (!exists) {
|
|
manifest.manifest['uses-permission'].push({
|
|
$: { 'android:name': permission },
|
|
});
|
|
}
|
|
});
|
|
|
|
return config;
|
|
});
|
|
|
|
// 3. iOS: Add JPush initialization to AppDelegate
|
|
config = withAppDelegate(config, (config) => {
|
|
const { contents } = config.modResults;
|
|
|
|
if (!contents.includes('JPush')) {
|
|
let newContents = contents;
|
|
|
|
if (!newContents.includes('#import <UserNotifications/UserNotifications.h>')) {
|
|
newContents = newContents.replace(
|
|
/(#import "AppDelegate.h")/,
|
|
`$1\n#import <UserNotifications/UserNotifications.h>`
|
|
);
|
|
}
|
|
|
|
if (!newContents.includes('#import <jcore-react-native/JCoreModule.h>')) {
|
|
newContents = newContents.replace(
|
|
/(#import "AppDelegate.h")/,
|
|
`$1\n#import <jcore-react-native/JCoreModule.h>`
|
|
);
|
|
}
|
|
|
|
const didFinishLaunchPattern = /(- \(BOOL\)application:\(UIApplication \*\)application didFinishLaunchingWithOptions:\(NSDictionary \*\)launchOptions\s*\{)/;
|
|
if (didFinishLaunchPattern.test(newContents)) {
|
|
newContents = newContents.replace(
|
|
didFinishLaunchPattern,
|
|
`$1\n // JPush initialization\n [JCoreModule setupWithOption:launchOptions appKey:@"${appKey}" channel:@"${channel}" apsForProduction:NO];\n`
|
|
);
|
|
}
|
|
|
|
const jpushMethods = `
|
|
// JPush: Register for remote notifications
|
|
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
|
|
[JCoreModule registerDeviceToken:deviceToken];
|
|
}
|
|
|
|
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
|
|
NSLog(@"did fail to register for remote notifications with error: %@", error);
|
|
}
|
|
|
|
// JPush: Handle remote notification
|
|
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
|
[JCoreModule didReceiveRemoteNotification:userInfo];
|
|
completionHandler(UIBackgroundFetchResultNewData);
|
|
}
|
|
|
|
// UNUserNotificationCenter delegate
|
|
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
|
|
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound);
|
|
}
|
|
|
|
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
|
|
[JCoreModule didReceiveRemoteNotification:response.notification.request.content.userInfo];
|
|
completionHandler();
|
|
}
|
|
`;
|
|
|
|
if (!newContents.includes('JCoreModule registerDeviceToken')) {
|
|
newContents = newContents.replace(
|
|
/@end\s*$/,
|
|
`${jpushMethods}\n@end\n`
|
|
);
|
|
}
|
|
|
|
config.modResults.contents = newContents;
|
|
}
|
|
|
|
return config;
|
|
});
|
|
|
|
// 4. iOS: Add required capabilities and permissions to Info.plist
|
|
config = withInfoPlist(config, (config) => {
|
|
config.modResults.UIBackgroundModes = config.modResults.UIBackgroundModes || [];
|
|
if (!config.modResults.UIBackgroundModes.includes('remote-notification')) {
|
|
config.modResults.UIBackgroundModes.push('remote-notification');
|
|
}
|
|
|
|
return config;
|
|
});
|
|
|
|
return config;
|
|
};
|
|
|
|
module.exports = withJPush; |