Last active
January 3, 2024 16:18
-
-
Save xixilive/204e8a1bae02d6edc0f0d6337d8295c2 to your computer and use it in GitHub Desktop.
a expo config plugin for native-wechat
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fs from 'node:fs' | |
import path from 'node:path' | |
import { ExpoConfig } from '@expo/config-types' | |
import { | |
ConfigPlugin, createRunOncePlugin, IOSConfig, AndroidConfig, | |
withInfoPlist, withEntitlementsPlist, withXcodeProject, | |
withMainApplication, withAndroidManifest, AndroidManifest | |
} from 'expo/config-plugins' | |
export type NativeWechatPluginOptions = { | |
appid: string | |
} | |
type ManifestIntent = { | |
action: { | |
$: { | |
'android:name': string | |
} | |
} | |
data: { | |
$: { | |
'android:scheme': string | |
} | |
} | |
} | |
type ManifestWithQueries = AndroidManifest['manifest'] & { | |
queries?: Array<{ | |
package?: { | |
$: { | |
"android:name": string | |
} | |
}, | |
intend?: ManifestIntent[] | |
}> | |
} | |
const androidTemplates = { | |
WXEntryActivity: ` | |
package <PACKAGE_NAME>.wxapi; | |
import android.app.Activity; | |
import android.content.Intent; | |
import android.os.Bundle; | |
public class WXEntryActivity extends Activity { | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
try { | |
Intent intent = getIntent(); | |
Intent intentToBroadcast = new Intent(); | |
intentToBroadcast.setAction("com.hector.nativewechat.ACTION_REDIRECT_INTENT"); | |
intentToBroadcast.putExtra("intent", intent); | |
sendBroadcast(intentToBroadcast); | |
finish(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
`, | |
WXPayEntryActivity: ` | |
package <PACKAGE_NAME>.wxapi; | |
import android.app.Activity; | |
import android.os.Bundle; | |
public class WXPayEntryActivity extends Activity { | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
finish(); | |
} | |
} | |
` | |
} | |
const updateAppDelegateHeaderFile = (hFile: string) => { | |
let lines = fs.readFileSync(hFile, 'utf-8').split('\n') | |
const findInterfaceIndex = () => lines.findIndex(line => /^@interface\s+AppDelegate\s*:\s*EXAppDelegateWrapper/.test(line)) | |
let ifIndex = findInterfaceIndex() | |
if(ifIndex < 0) { | |
throw new Error('syntax error in AppDelegate.h') | |
} | |
const importIndex = lines.findIndex(line => /^#import\s+"WXApi.h"/.test(line)) | |
if(importIndex < 0) { | |
lines = lines.slice(0, ifIndex).concat(['', '#import "WXApi.h"', '']).concat(lines.slice(ifIndex)) | |
ifIndex = findInterfaceIndex() | |
const m = lines[ifIndex].match(/EXAppDelegateWrapper(<(.+)>)?/) | |
if(!m![1]) { | |
lines[ifIndex] = lines[ifIndex].replace('EXAppDelegateWrapper', 'EXAppDelegateWrapper<WXApiDelegate>') | |
} else { | |
const delegates = m![2].split(/,+/) | |
if(!delegates.includes('WXApiDelegate')) { | |
delegates.push('WXApiDelegate') | |
} | |
lines[ifIndex] = lines[ifIndex].replace('EXAppDelegateWrapper', `EXAppDelegateWrapper<${delegates.join(', ')}>`) | |
} | |
} | |
fs.writeFileSync(hFile, lines.join('\n'), 'utf-8') | |
} | |
const createWxApiActivityFiles = (baseDir: string, options: any = {}) => { | |
const destDir = path.resolve(baseDir, 'wxapi') | |
fs.mkdirSync(destDir, {recursive: true}) | |
fs.writeFileSync(path.resolve(destDir, 'WXEntryActivity.java'), androidTemplates.WXEntryActivity.replace('<PACKAGE_NAME>', options.package), 'utf-8') | |
fs.writeFileSync(path.resolve(destDir, 'WXPayEntryActivity.java'), androidTemplates.WXPayEntryActivity.replace('<PACKAGE_NAME>', options.package), 'utf-8') | |
} | |
const withIOSConfig = (config: ExpoConfig, options: NativeWechatPluginOptions) => { | |
if(!options?.appid) { | |
console.warn('wechat appid is missing from plugin options') | |
} | |
withXcodeProject(config, mod => { | |
updateAppDelegateHeaderFile(IOSConfig.Paths.getAppDelegateHeaderFilePath(mod.modRequest.projectRoot)) | |
return mod | |
}) | |
withEntitlementsPlist(config, (mod) => { | |
// associated domains | |
if(!Array.isArray(mod.modResults['com.apple.developer.associated-domains'])) { | |
mod.modResults['com.apple.developer.associated-domains'] = [] | |
} | |
const domains = mod.modResults['com.apple.developer.associated-domains'] | |
const items = ['applinks:app.magiilife.com'] | |
items.forEach(d => { | |
if(!domains.includes(d)) { | |
domains.push(d) | |
} | |
}) | |
return mod | |
}) | |
// add URL types and Queried URL schemas | |
withInfoPlist(config, (mod) => { | |
if(!Array.isArray(mod.modResults.CFBundleURLTypes)) { | |
mod.modResults.CFBundleURLTypes = [] | |
} | |
if(!Array.isArray(mod.modResults.LSApplicationQueriesSchemes)) { | |
mod.modResults.LSApplicationQueriesSchemes = [] | |
} | |
const schema = mod.modResults.CFBundleURLTypes.find(x => x.CFBundleURLName === 'weixin') | |
if(!schema) { | |
mod.modResults.CFBundleURLTypes.push({ | |
CFBundleURLName: 'weixin', CFBundleURLSchemes: [options.appid] | |
}) | |
} | |
const queriedUrlSchemas = ['weixin', 'wechat', 'weixinULAPI'] | |
queriedUrlSchemas.forEach(s => { | |
if(!mod.modResults.LSApplicationQueriesSchemes!.includes(s)) { | |
mod.modResults.LSApplicationQueriesSchemes!.push(s) | |
} | |
}) | |
return mod | |
}) | |
} | |
const withAndroidConfig = (config: ExpoConfig, options: NativeWechatPluginOptions) => { | |
// append wxapi activity files | |
withMainApplication(config, mod => { | |
createWxApiActivityFiles(path.dirname(mod.modResults.path), {package: config.android!.package}) | |
return mod | |
}) | |
withAndroidManifest(config, mod => { | |
const manifest = mod.modResults.manifest as ManifestWithQueries | |
const queryPkg = {$: {'android:name': 'com.tencent.mm'}} | |
if(!Array.isArray(manifest.queries)) { | |
manifest.queries = [] | |
} | |
if(manifest.queries.length === 0) { | |
manifest.queries.push({package: queryPkg}) | |
} else { | |
manifest.queries[0].package = {$: {'android:name': 'com.tencent.mm'}} | |
} | |
const application = manifest.application!.find(x => x.$['android:name'] === '.MainApplication')! | |
// WXEntryActivity | |
if(!application.activity!.find(x => x.$['android:name'] === '.wxapi.WXEntryActivity')) { | |
application.activity!.push({$: { | |
'android:name': '.wxapi.WXEntryActivity', | |
'android:exported': 'true', | |
'android:label': '@string/app_name', | |
'android:launchMode': 'singleTask', | |
'android:taskAffinity': config.android!.package, | |
'android:theme': '@android:style/Theme.Translucent.NoTitleBar' | |
}}) | |
} | |
// WXPayEntryActivity | |
if(!application.activity!.find(x => x.$['android:name'] === '.wxapi.WXPayEntryActivity')) { | |
application.activity!.push({$: { | |
'android:name': '.wxapi.WXPayEntryActivity', | |
'android:exported': 'true', | |
'android:label': '@string/app_name' | |
}}) | |
} | |
return mod | |
}) | |
} | |
const withNativeWechat: ConfigPlugin<NativeWechatPluginOptions> = (config, options) => { | |
withIOSConfig(config, options) | |
withAndroidConfig(config, options) | |
return config | |
} | |
export default createRunOncePlugin(withNativeWechat, 'native-wechat', '1.0.3') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment