Merge branch 'dev' of https://code.littlelan.cn/carrot_bbs/frontend into dev
This commit is contained in:
@@ -95,7 +95,116 @@ const withJPush = (config, options = {}) => {
|
||||
config = withAppDelegate(config, (config) => {
|
||||
const { contents } = config.modResults;
|
||||
|
||||
if (!contents.includes('JPush')) {
|
||||
if (contents.includes('JPush') || contents.includes('JCoreModule')) {
|
||||
return config;
|
||||
}
|
||||
|
||||
const isSwift = contents.includes('class AppDelegate') || contents.includes('@main');
|
||||
|
||||
if (isSwift) {
|
||||
let newContents = contents;
|
||||
|
||||
if (!newContents.includes('import JPushRN')) {
|
||||
if (newContents.includes('import UIKit')) {
|
||||
newContents = newContents.replace(
|
||||
/(import UIKit\n)/,
|
||||
`$1import UserNotifications\n`
|
||||
);
|
||||
} else {
|
||||
newContents = newContents.replace(
|
||||
/(internal import Expo\n)/,
|
||||
`$1import UserNotifications\n`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Swift: Add JPush init in application(_:didFinishLaunchingWithOptions:)
|
||||
// Match various Swift signatures
|
||||
const swiftDidFinishPatterns = [
|
||||
/public override func application\(\s*_ application: UIApplication,\s*didFinishLaunchingWithOptions launchOptions: \[UIApplication\.LaunchOptionsKey: Any\]\? = nil\s*\) -> Bool \{/,
|
||||
/func application\(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: \[UIApplication\.LaunchOptionsKey: Any\]\?\?\) -> Bool \{/,
|
||||
];
|
||||
|
||||
let didInsertInit = false;
|
||||
for (const pattern of swiftDidFinishPatterns) {
|
||||
if (pattern.test(newContents)) {
|
||||
newContents = newContents.replace(
|
||||
pattern,
|
||||
`$&\n // JPush initialization\n #if DEBUG\n JCoreModule.setup(withOption: launchOptions, appKey: "${appKey}", channel: "${channel}", apsForProduction: false)\n #else\n JCoreModule.setup(withOption: launchOptions, appKey: "${appKey}", channel: "${channel}", apsForProduction: true)\n #endif`
|
||||
);
|
||||
didInsertInit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: find the didFinishLaunchingWithOptions method start and insert after the opening brace
|
||||
if (!didInsertInit && newContents.includes('didFinishLaunchingWithOptions')) {
|
||||
const lines = newContents.split('\n');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i].includes('didFinishLaunchingWithOptions') && lines[i].includes('{')) {
|
||||
lines.splice(i + 1, 0,
|
||||
' // JPush initialization',
|
||||
' #if DEBUG',
|
||||
` JPUSHService.setup(withOption: launchOptions, appKey: "${appKey}", channel: "${channel}", apsForProduction: false)`,
|
||||
' #else',
|
||||
` JPUSHService.setup(withOption: launchOptions, appKey: "${appKey}", channel: "${channel}", apsForProduction: true)`,
|
||||
' #endif',
|
||||
' UNUserNotificationCenter.current().delegate = self'
|
||||
);
|
||||
newContents = lines.join('\n');
|
||||
didInsertInit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also add delegate = self after regex-based insertion if not already present
|
||||
if (didInsertInit && !newContents.includes('UNUserNotificationCenter.current().delegate')) {
|
||||
newContents = newContents.replace(
|
||||
/(#endif\n)(\s+let delegate)/,
|
||||
`$1 UNUserNotificationCenter.current().delegate = self\n$2`
|
||||
);
|
||||
}
|
||||
|
||||
// Swift: Add delegate methods before the closing brace of the class
|
||||
const jpushSwiftMethods = `
|
||||
// JPush: Register for remote notifications
|
||||
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
||||
JPUSHService.registerDeviceToken(deviceToken)
|
||||
}
|
||||
|
||||
override func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
||||
NSLog("did fail to register for remote notifications with error: %@", error.localizedDescription)
|
||||
}
|
||||
|
||||
// JPush: Handle remote notification
|
||||
override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
|
||||
JPUSHService.handleRemoteNotification(userInfo)
|
||||
completionHandler(.newData)
|
||||
}
|
||||
|
||||
// UNUserNotificationCenter delegate: foreground notification display
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
|
||||
completionHandler([.alert, .badge, .sound])
|
||||
}
|
||||
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
|
||||
JPUSHService.handleRemoteNotification(response.notification.request.content.userInfo)
|
||||
completionHandler()
|
||||
}
|
||||
`;
|
||||
|
||||
if (!newContents.includes('JPUSHService.registerDeviceToken')) {
|
||||
// Find the closing brace of the AppDelegate class
|
||||
const lastBraceIndex = newContents.lastIndexOf('}');
|
||||
if (lastBraceIndex !== -1) {
|
||||
newContents = newContents.slice(0, lastBraceIndex) + jpushSwiftMethods + '\n' + newContents.slice(lastBraceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
config.modResults.contents = newContents;
|
||||
} else {
|
||||
// ObjC AppDelegate
|
||||
let newContents = contents;
|
||||
|
||||
if (!newContents.includes('#import <UserNotifications/UserNotifications.h>')) {
|
||||
@@ -116,7 +225,7 @@ const withJPush = (config, options = {}) => {
|
||||
if (didFinishLaunchPattern.test(newContents)) {
|
||||
newContents = newContents.replace(
|
||||
didFinishLaunchPattern,
|
||||
`$1\n // JPush initialization\n [JCoreModule setupWithOption:launchOptions appKey:@"${appKey}" channel:@"${channel}" apsForProduction:NO];\n`
|
||||
`$1\n // JPush initialization\n #if DEBUG\n [JCoreModule setupWithOption:launchOptions appKey:@"${appKey}" channel:@"${channel}" apsForProduction:NO];\n #else\n [JCoreModule setupWithOption:launchOptions appKey:@"${appKey}" channel:@"${channel}" apsForProduction:YES];\n #endif\n`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -160,7 +269,26 @@ const withJPush = (config, options = {}) => {
|
||||
return config;
|
||||
});
|
||||
|
||||
// 4. iOS: Add required capabilities and permissions to Info.plist
|
||||
// 4. iOS: Add bridging header for Swift if needed
|
||||
config = withDangerousMod(config, [
|
||||
'ios',
|
||||
async (config) => {
|
||||
const appDelegatePath = path.join(config.modRequest.platformProjectRoot, 'app', 'AppDelegate.swift');
|
||||
if (fs.existsSync(appDelegatePath)) {
|
||||
const bridgingHeaderSearch = path.join(config.modRequest.platformProjectRoot, 'app', 'app-Bridging-Header.h');
|
||||
if (fs.existsSync(bridgingHeaderSearch)) {
|
||||
let bridgingContent = fs.readFileSync(bridgingHeaderSearch, 'utf-8');
|
||||
if (!bridgingContent.includes('JCoreModule')) {
|
||||
bridgingContent += '\n#import "JPUSHService.h"\n#import <UserNotifications/UserNotifications.h>\n';
|
||||
fs.writeFileSync(bridgingHeaderSearch, bridgingContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
]);
|
||||
|
||||
// 5. 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')) {
|
||||
|
||||
41
plugins/withSigning.js
Normal file
41
plugins/withSigning.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const { withDangerousMod } = require('@expo/config-plugins');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const withSigning = (config, options = {}) => {
|
||||
const { teamId = 'X3964MGXHG' } = options;
|
||||
|
||||
config = withDangerousMod(config, [
|
||||
'ios',
|
||||
async (config) => {
|
||||
const platformRoot = config.modRequest.platformProjectRoot;
|
||||
|
||||
// 1. Inject CODE_SIGN_STYLE and DEVELOPMENT_TEAM into pbxproj
|
||||
const pbxprojPath = path.join(platformRoot, 'app.xcodeproj', 'project.pbxproj');
|
||||
if (fs.existsSync(pbxprojPath)) {
|
||||
let contents = fs.readFileSync(pbxprojPath, 'utf-8');
|
||||
const entitlementsLine = 'CODE_SIGN_ENTITLEMENTS = app/app.entitlements;';
|
||||
const signingBlock = `${entitlementsLine}\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = ${teamId};`;
|
||||
contents = contents.replaceAll(entitlementsLine, signingBlock);
|
||||
fs.writeFileSync(pbxprojPath, contents);
|
||||
}
|
||||
|
||||
// 2. Set aps-environment to production in entitlements
|
||||
const entitlementsPath = path.join(platformRoot, 'app', 'app.entitlements');
|
||||
if (fs.existsSync(entitlementsPath)) {
|
||||
let entitlements = fs.readFileSync(entitlementsPath, 'utf-8');
|
||||
entitlements = entitlements.replace(
|
||||
/<key>aps-environment<\/key>\s*<string>development<\/string>/,
|
||||
'<key>aps-environment</key>\n\t<string>production</string>'
|
||||
);
|
||||
fs.writeFileSync(entitlementsPath, entitlements);
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
]);
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
module.exports = withSigning;
|
||||
Reference in New Issue
Block a user