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 ')) { newContents = newContents.replace( /(#import "AppDelegate.h")/, `$1\n#import ` ); } if (!newContents.includes('#import ')) { newContents = newContents.replace( /(#import "AppDelegate.h")/, `$1\n#import ` ); } 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;