ci(android): add Android NDK caching and installation to build workflow
This commit is contained in:
@@ -209,6 +209,23 @@ jobs:
|
||||
sed -i '/always-auth/d' ~/.npmrc
|
||||
fi
|
||||
|
||||
- name: Cache Android NDK
|
||||
uses: actions/cache@v4
|
||||
id: cache-ndk
|
||||
with:
|
||||
path: /opt/android/ndk/27.0.12077973
|
||||
key: ndk-27.0.12077973-v1
|
||||
|
||||
- name: Install Android NDK
|
||||
if: steps.cache-ndk.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
echo "Existing NDK versions:"
|
||||
ls /opt/android/ndk/ 2>/dev/null || echo "No NDK dir"
|
||||
echo "Installing NDK 27.0.12077973..."
|
||||
yes | sdkmanager --install "ndk;27.0.12077973"
|
||||
echo "NDK after install:"
|
||||
ls /opt/android/ndk/
|
||||
|
||||
- name: Cache Gradle
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@@ -360,6 +377,7 @@ jobs:
|
||||
expo.gif.enabled=true
|
||||
expo.webp.enabled=true
|
||||
expo.webp.animated=false
|
||||
ndkVersion=27.1.12297006
|
||||
expo.useLegacyPackaging=false
|
||||
PROPS_EOF
|
||||
|
||||
|
||||
3
app.json
3
app.json
@@ -151,7 +151,8 @@
|
||||
"appKey": "2cbe4da12e2c24aa3dca4610",
|
||||
"channel": "developer-default"
|
||||
}
|
||||
]
|
||||
],
|
||||
"./plugins/withHuaweiPush"
|
||||
],
|
||||
"extra": {
|
||||
"eas": {
|
||||
|
||||
1
plugins/agconnect-services.json
Normal file
1
plugins/agconnect-services.json
Normal file
@@ -0,0 +1 @@
|
||||
{"agcgw":{"url":"connect-drcn.dbankcloud.cn","backurl":"connect-drcn.hispace.hicloud.com","websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn","websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com"},"agcgw_all":{"SG":"connect-dra.dbankcloud.cn","SG_back":"connect-dra.hispace.hicloud.com","CN":"connect-drcn.dbankcloud.cn","CN_back":"connect-drcn.hispace.hicloud.com","RU":"connect-drru.hispace.dbankcloud.ru","RU_back":"connect-drru.hispace.dbankcloud.cn","DE":"connect-dre.dbankcloud.cn","DE_back":"connect-dre.hispace.hicloud.com"},"websocketgw_all":{"SG":"connect-ws-dra.hispace.dbankcloud.cn","SG_back":"connect-ws-dra.hispace.dbankcloud.com","CN":"connect-ws-drcn.hispace.dbankcloud.cn","CN_back":"connect-ws-drcn.hispace.dbankcloud.com","RU":"connect-ws-drru.hispace.dbankcloud.ru","RU_back":"connect-ws-drru.hispace.dbankcloud.cn","DE":"connect-ws-dre.hispace.dbankcloud.cn","DE_back":"connect-ws-dre.hispace.dbankcloud.com"},"client":{"cp_id":"30086000618737115","product_id":"101653523864112478","client_id":"1949443370896080512","client_secret":"CA50EF8C69075FAEFECF2D9F0F3ED101DC3264E0BFE1CC5E5B0272E7FF8215A1","project_id":"101653523864112478","app_id":"117704941","api_key":"DgEDAIkxmMyXBT6vYYW8ZWWXBMJweDbdmmKLYo5MvgH2lV8jPSIZt5WVpjd0/nZ0dk9gAwHf+dWIySILr3QQd7W80H8NNvuCUAQPig==","package_name":"cn.qczlit.withyou"},"oauth_client":{"client_id":"117704941","client_type":1},"app_info":{"app_id":"117704941","package_name":"cn.qczlit.withyou"},"service":{"analytics":{"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn","collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn","collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn","collector_url_ru":"datacollector-drru.dt.dbankcloud.ru,datacollector-drru.dt.hicloud.com","collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn","resource_id":"p1","channel_id":""},"ml":{"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"},"cloudstorage":{"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn","storage_url_ru":"https://agc-storage-drru.cloud.huawei.ru","storage_url_sg":"https://ops-dra.agcstorage.link","storage_url_de":"https://ops-dre.agcstorage.link","storage_url_cn":"https://agc-storage-drcn.platform.dbankcloud.cn","storage_url_ru_back":"https://agc-storage-drru.cloud.huawei.ru","storage_url_sg_back":"https://agc-storage-dra.cloud.huawei.asia","storage_url_de_back":"https://agc-storage-dre.cloud.huawei.eu","storage_url_cn_back":"https://agc-storage-drcn.cloud.huawei.com.cn"},"search":{"url":"https://search-drcn.cloud.huawei.com"},"edukit":{"edu_url":"edukit.cloud.huawei.com.cn","dh_url":"edukit.cloud.huawei.com.cn"}},"region":"CN","configuration_version":"3.0","appInfos":[{"package_name":"cn.qczlit.withyou","client":{"app_id":"117704941"},"oauth_client":{"client_id":"117704941","client_type":1},"app_info":{"app_id":"117704941","package_name":"cn.qczlit.withyou"}}]}
|
||||
110
plugins/withHuaweiPush.js
Normal file
110
plugins/withHuaweiPush.js
Normal file
@@ -0,0 +1,110 @@
|
||||
const {
|
||||
withAppBuildGradle,
|
||||
withProjectBuildGradle,
|
||||
withDangerousMod,
|
||||
withAndroidManifest,
|
||||
} = require('@expo/config-plugins');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const withHuaweiPush = (config, options = {}) => {
|
||||
const { jpushVersion = '5.8.0' } = options;
|
||||
|
||||
config = withProjectBuildGradle(config, (config) => {
|
||||
const contents = config.modResults.contents;
|
||||
|
||||
if (!contents.includes('developer.huawei.com/repo')) {
|
||||
config.modResults.contents = contents.replace(
|
||||
/(repositories\s*\{)/g,
|
||||
(match) => {
|
||||
return match + `\n maven { url 'https://developer.huawei.com/repo/' }`;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
config = withProjectBuildGradle(config, (config) => {
|
||||
const contents = config.modResults.contents;
|
||||
|
||||
if (!contents.includes('com.huawei.agconnect:agcp')) {
|
||||
if (contents.includes('buildscript')) {
|
||||
const depsPattern = /(buildscript\s*\{[\s\S]*?dependencies\s*\{)/;
|
||||
if (depsPattern.test(contents)) {
|
||||
config.modResults.contents = contents.replace(
|
||||
depsPattern,
|
||||
`$1\n classpath 'com.huawei.agconnect:agcp:1.9.1.301'`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
config = withAppBuildGradle(config, (config) => {
|
||||
const contents = config.modResults.contents;
|
||||
|
||||
if (!contents.includes('com.huawei.agconnect')) {
|
||||
const applyPluginPattern = /apply plugin:\s*['"]com\.google\.gms\.google-services['"]/;
|
||||
if (applyPluginPattern.test(contents)) {
|
||||
config.modResults.contents = contents.replace(
|
||||
applyPluginPattern,
|
||||
`apply plugin: 'com.google.gms.google-services'\napply plugin: 'com.huawei.agconnect'`
|
||||
);
|
||||
} else {
|
||||
const lastApplyPlugin = /apply plugin:[^\n]*(?:\n)/g;
|
||||
const matches = contents.match(lastApplyPlugin);
|
||||
if (matches && matches.length > 0) {
|
||||
const lastMatch = matches[matches.length - 1];
|
||||
const lastIndex = contents.lastIndexOf(lastMatch);
|
||||
config.modResults.contents =
|
||||
contents.slice(0, lastIndex + lastMatch.length) +
|
||||
"apply plugin: 'com.huawei.agconnect'\n" +
|
||||
contents.slice(lastIndex + lastMatch.length);
|
||||
} else {
|
||||
config.modResults.contents = contents + "\napply plugin: 'com.huawei.agconnect'\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!contents.includes('cn.jiguang.sdk.plugin:huawei')) {
|
||||
const depsPattern = /dependencies\s*\{/;
|
||||
if (depsPattern.test(config.modResults.contents)) {
|
||||
config.modResults.contents = config.modResults.contents.replace(
|
||||
depsPattern,
|
||||
`dependencies {\n implementation 'cn.jiguang.sdk.plugin:huawei:${jpushVersion}'`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
config = withDangerousMod(config, [
|
||||
'android',
|
||||
async (config) => {
|
||||
const appDir = path.join(config.modRequest.platformProjectRoot, 'app');
|
||||
const srcFile = path.join(config.modRequest.projectRoot, 'plugins', 'agconnect-services.json');
|
||||
const destFile = path.join(appDir, 'agconnect-services.json');
|
||||
|
||||
if (fs.existsSync(srcFile)) {
|
||||
fs.copyFileSync(srcFile, destFile);
|
||||
console.log('[withHuaweiPush] copied agconnect-services.json to android/app/');
|
||||
} else {
|
||||
console.warn('[withHuaweiPush] agconnect-services.json not found at project root');
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
]);
|
||||
|
||||
config = withAndroidManifest(config, (config) => {
|
||||
return config;
|
||||
});
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
module.exports = withHuaweiPush;
|
||||
@@ -17,19 +17,40 @@ const withJPush = (config, 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()
|
||||
);
|
||||
const requiredPlaceholders = {
|
||||
JPUSH_APPKEY: appKey,
|
||||
JPUSH_CHANNEL: channel,
|
||||
};
|
||||
|
||||
const manifestPlaceholderRegex = /manifestPlaceholders\s*=\s*\[([\s\S]*?)\]/;
|
||||
const match = contents.match(manifestPlaceholderRegex);
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(requiredPlaceholders)) {
|
||||
existingEntries[key] = value;
|
||||
}
|
||||
|
||||
const entriesStr = Object.entries(existingEntries)
|
||||
.map(([k, v]) => `${k}: "${v}"`)
|
||||
.join(',\n ');
|
||||
const newBlock = `\n manifestPlaceholders = [\n ${entriesStr}\n ]`;
|
||||
|
||||
config.modResults.contents = contents.replace(manifestPlaceholderRegex, newBlock.trim());
|
||||
} else if (contents.includes('REACT_NATIVE_RELEASE_LEVEL')) {
|
||||
const entriesStr = Object.entries(requiredPlaceholders)
|
||||
.map(([k, v]) => `${k}: "${v}"`)
|
||||
.join(',\n ');
|
||||
const block = '\n manifestPlaceholders = [\n ' + entriesStr + '\n ]';
|
||||
const lines = contents.split('\n');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (lines[i].includes('REACT_NATIVE_RELEASE_LEVEL')) {
|
||||
|
||||
Reference in New Issue
Block a user