feat(push): add OPPO and vivo push plugins, bump JPush to 6.1.0
- Add withOppoPush.js and withVivoPush.js config plugins - Register new plugins in app.json - Bump JPush version from 5.8.0 to 6.1.0 in Honor/Huawei/Xiaomi plugins
This commit is contained in:
2
app.json
2
app.json
@@ -157,6 +157,8 @@
|
|||||||
"./plugins/withHuaweiPush",
|
"./plugins/withHuaweiPush",
|
||||||
"./plugins/withXiaomiPush",
|
"./plugins/withXiaomiPush",
|
||||||
"./plugins/withHonorPush",
|
"./plugins/withHonorPush",
|
||||||
|
"./plugins/withVivoPush",
|
||||||
|
"./plugins/withOppoPush",
|
||||||
"expo-callkit-telecom",
|
"expo-callkit-telecom",
|
||||||
[
|
[
|
||||||
"expo-splash-screen",
|
"expo-splash-screen",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const path = require('path');
|
|||||||
// 没有这个问题。
|
// 没有这个问题。
|
||||||
const withHonorPush = (config, options = {}) => {
|
const withHonorPush = (config, options = {}) => {
|
||||||
const {
|
const {
|
||||||
jpushVersion = '5.8.0',
|
jpushVersion = '6.1.0',
|
||||||
appId = '104562917',
|
appId = '104562917',
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const fs = require('fs');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const withHuaweiPush = (config, options = {}) => {
|
const withHuaweiPush = (config, options = {}) => {
|
||||||
const { jpushVersion = '5.8.0' } = options;
|
const { jpushVersion = '6.1.0' } = options;
|
||||||
|
|
||||||
config = withSettingsGradle(config, (config) => {
|
config = withSettingsGradle(config, (config) => {
|
||||||
const contents = config.modResults.contents;
|
const contents = config.modResults.contents;
|
||||||
|
|||||||
144
plugins/withOppoPush.js
Normal file
144
plugins/withOppoPush.js
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
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.0,5.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;
|
||||||
141
plugins/withVivoPush.js
Normal file
141
plugins/withVivoPush.js
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
const { withDangerousMod } = require('@expo/config-plugins');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
// vivo 厂商推送通道的 Expo config plugin.
|
||||||
|
//
|
||||||
|
// 客户端职责(依据极光官方文档 https://docs.jiguang.cn/jpush/client/Android/android_3rd_guide):
|
||||||
|
// 1) 添加 cn.jiguang.sdk.plugin:vivo 依赖
|
||||||
|
// 2) 注入 manifestPlaceholders: VIVO_APPKEY / VIVO_APPID(AAR 自带 vivo Receiver)
|
||||||
|
// 3) 添加 Proguard 规则 (com.vivo.push.** + com.vivo.vms.** 保留)
|
||||||
|
//
|
||||||
|
// 注意事项:
|
||||||
|
// - 极光 JPUSH_CHANNEL 是「APK 分发渠道」统计字段,不是厂商通道开关,**不应覆盖**。
|
||||||
|
// - 客户端仅需要 VIVO_APPKEY / VIVO_APPID 两个占位符。
|
||||||
|
// VIVO_APP_SECRET 只在极光控制台「集成设置」页面填写,客户端不需要。
|
||||||
|
// - vivo AAR 已发布到 Maven Central,不需要额外 Maven 仓库。
|
||||||
|
// - vivo 平台限制:若应用未上架 vivo 商店,测试推送时需在 vivo 推送平台添加测试设备,
|
||||||
|
// 且需通过 API 指定 push_mode=1(测试推送)下发。
|
||||||
|
//
|
||||||
|
// 实现说明:用 withDangerousMod 直接读写磁盘文件。
|
||||||
|
// 原因:Expo SDK 56+ 的 withAppBuildGradle hook 链中,第二个以后的 plugin 写回
|
||||||
|
// modResults.contents 会被静默忽略,导致多个 vendor plugin 只能写入第一个的修改。
|
||||||
|
// withDangerousMod 走文件系统,串行、可靠,幂等检查保证可重复执行 prebuild。
|
||||||
|
const withVivoPush = (config, options = {}) => {
|
||||||
|
const {
|
||||||
|
jpushVersion = '6.1.0',
|
||||||
|
appId = '106100295',
|
||||||
|
appKey = '2110cb5f6dc5bd7abea82c38f8d0a1ec',
|
||||||
|
} = 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:vivo')) {
|
||||||
|
const depsPattern = /dependencies\s*\{/;
|
||||||
|
if (depsPattern.test(gradle)) {
|
||||||
|
gradle = gradle.replace(
|
||||||
|
depsPattern,
|
||||||
|
`dependencies {\n implementation 'cn.jiguang.sdk.plugin:vivo:${jpushVersion}'`
|
||||||
|
);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1b. 注入 manifestPlaceholders
|
||||||
|
const manifestPlaceholderRegex = /manifestPlaceholders\s*=\s*\[([\s\S]*?)\]/;
|
||||||
|
const match = gradle.match(manifestPlaceholderRegex);
|
||||||
|
|
||||||
|
const requiredPlaceholders = {
|
||||||
|
VIVO_APPKEY: appKey,
|
||||||
|
VIVO_APPID: appId,
|
||||||
|
};
|
||||||
|
|
||||||
|
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('[withVivoPush] 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.vivo.push.**')) {
|
||||||
|
const vivoRules = `
|
||||||
|
# JPush vivo vendor channel — keep rules (https://docs.jiguang.cn/jpush/client/Android/android_3rd_guide)
|
||||||
|
-dontwarn com.vivo.push.**
|
||||||
|
-keep class com.vivo.push.** { *; }
|
||||||
|
-keep class com.vivo.vms.** { *; }
|
||||||
|
`;
|
||||||
|
fs.writeFileSync(proguardFilePath, proguard + vivoRules);
|
||||||
|
console.log('[withVivoPush] appended vivo Proguard rules to proguard-rules.pro');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = withVivoPush;
|
||||||
@@ -16,7 +16,7 @@ const path = require('path');
|
|||||||
// 串行、可靠,幂等检查保证可重复执行 prebuild。
|
// 串行、可靠,幂等检查保证可重复执行 prebuild。
|
||||||
const withXiaomiPush = (config, options = {}) => {
|
const withXiaomiPush = (config, options = {}) => {
|
||||||
const {
|
const {
|
||||||
jpushVersion = '5.8.0',
|
jpushVersion = '6.1.0',
|
||||||
appId = '2882303761520539252',
|
appId = '2882303761520539252',
|
||||||
appKey = '5792053978252',
|
appKey = '5792053978252',
|
||||||
} = options;
|
} = options;
|
||||||
|
|||||||
Reference in New Issue
Block a user