Files
frontend/plugins/withOppoPush.js

145 lines
5.5 KiB
JavaScript
Raw Permalink Normal View History

const { withDangerousMod } = require('@expo/config-plugins');
const fs = require('fs');
const path = require('path');
// OPPO 厂商推送通道的 Expo config plugin.
//
// 客户端职责(依据极光官方文档 https://docs.jiguang.cn/jpush/client/Android/android_3rd_guide
// 1) 添加 cn.jiguang.sdk.plugin:oppo 依赖5.9.0+ 自动包含 heytap 官方 aar
// 2) 注入 manifestPlaceholders: OPPO_APPKEY / OPPO_APPID / OPPO_APPSECRET带 OP- 前缀)
// 3) 添加 Proguard 规则 (coloros.mcsdk / heytap / mcs 三个包保留)
//
// 注意事项:
// - 极光 JPUSH_CHANNEL 是「APK 分发渠道」统计字段,不是厂商通道开关,**不应覆盖**。
// - OPPO 与小米/vivo/荣耀不同:客户端需要 3 个占位符(含 AppSecret且必须带 `OP-` 前缀。
// - OPPO AAR 在 JPush 5.9.0+ 通过 maven 自动拉取,不需要手动下载 aar 文件。
// - OPPO SDK 3.1.0+ 依赖 gson 2.6.2 和 androidx.annotation 1.1.05.9.0 maven 已自动包含。
//
// 实现说明:用 withDangerousMod 直接读写磁盘文件。
// 原因Expo SDK 56+ 的 withAppBuildGradle hook 链中,第二个以后的 plugin 写回
// modResults.contents 会被静默忽略,导致多个 vendor plugin 只能写入第一个的修改。
const withOppoPush = (config, options = {}) => {
const {
jpushVersion = '6.1.0',
appId = '37219099',
appKey = '4eb532fcddd147c0bf7c356a149b2058',
appSecret = '9a0c290b2b8049e1893246ed7b9367d0',
} = options;
config = withDangerousMod(config, [
'android',
async (config) => {
const appBuildGradlePath = path.join(
config.modRequest.platformProjectRoot,
'app',
'build.gradle'
);
const proguardFilePath = path.join(
config.modRequest.platformProjectRoot,
'app',
'proguard-rules.pro'
);
// --- 1. 处理 build.gradle ---
if (fs.existsSync(appBuildGradlePath)) {
let gradle = fs.readFileSync(appBuildGradlePath, 'utf-8');
let changed = false;
// 1a. 注入 AAR 依赖
if (!gradle.includes('cn.jiguang.sdk.plugin:oppo')) {
const depsPattern = /dependencies\s*\{/;
if (depsPattern.test(gradle)) {
gradle = gradle.replace(
depsPattern,
`dependencies {\n implementation 'cn.jiguang.sdk.plugin:oppo:${jpushVersion}'`
);
changed = true;
}
}
// 1b. 注入 manifestPlaceholders带 OP- 前缀)
const manifestPlaceholderRegex = /manifestPlaceholders\s*=\s*\[([\s\S]*?)\]/;
const match = gradle.match(manifestPlaceholderRegex);
// OPPO 官方要求占位符值必须以 "OP-" 前缀开头
const requiredPlaceholders = {
OPPO_APPKEY: `OP-${appKey}`,
OPPO_APPID: `OP-${appId}`,
OPPO_APPSECRET: `OP-${appSecret}`,
};
if (match) {
const existingBlock = match[1];
const existingEntries = {};
const entryRegex = /(\w+)\s*:\s*"([^"]*)"/g;
let entryMatch;
while ((entryMatch = entryRegex.exec(existingBlock)) !== null) {
existingEntries[entryMatch[1]] = entryMatch[2];
}
let placeholdersChanged = false;
for (const [key, value] of Object.entries(requiredPlaceholders)) {
if (existingEntries[key] !== value) {
existingEntries[key] = value;
placeholdersChanged = true;
}
}
if (placeholdersChanged) {
const entriesStr = Object.entries(existingEntries)
.map(([k, v]) => `${k}: "${v}"`)
.join(',\n ');
const newBlock = `\n manifestPlaceholders = [\n ${entriesStr}\n ]`;
gradle = gradle.replace(manifestPlaceholderRegex, newBlock.trim());
changed = true;
}
} else if (gradle.includes('REACT_NATIVE_RELEASE_LEVEL')) {
// 没有 manifestPlaceholders block 时新建
const entriesStr = Object.entries(requiredPlaceholders)
.map(([k, v]) => `${k}: "${v}"`)
.join(',\n ');
const block = `\n manifestPlaceholders = [\n ${entriesStr}\n ]\n`;
const lines = gradle.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;
}
}
gradle = lines.join('\n');
changed = true;
}
if (changed) {
fs.writeFileSync(appBuildGradlePath, gradle);
console.log('[withOppoPush] updated app/build.gradle (AAR + manifestPlaceholders)');
}
}
// --- 2. 处理 proguard-rules.pro ---
if (fs.existsSync(proguardFilePath)) {
let proguard = fs.readFileSync(proguardFilePath, 'utf-8');
if (!proguard.includes('-keep class com.heytap.**')) {
const oppoRules = `
# JPush OPPO vendor channel keep rules (https://docs.jiguang.cn/jpush/client/Android/android_3rd_guide)
-dontwarn com.coloros.mcsdk.**
-dontwarn com.heytap.**
-dontwarn com.mcs.**
-keep class com.coloros.mcsdk.** { *; }
-keep class com.heytap.** { *; }
-keep class com.mcs.** { *; }
`;
fs.writeFileSync(proguardFilePath, proguard + oppoRules);
console.log('[withOppoPush] appended OPPO Proguard rules to proguard-rules.pro');
}
}
return config;
},
]);
return config;
};
module.exports = withOppoPush;