Migrate from @react-navigation/native to expo-router navigation hooks across all screens. Add polyfills module and apply LiveKit VideoView optional loading for Expo Go compatibility. Improve background sync to skip when user is not logged in. Enhance fetchUnreadCount to return typed totalUnread and systemUnread values.
201 lines
8.0 KiB
JavaScript
201 lines
8.0 KiB
JavaScript
const {
|
|
withAppBuildGradle,
|
|
withProjectBuildGradle,
|
|
withSettingsGradle,
|
|
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 = withSettingsGradle(config, (config) => {
|
|
const contents = config.modResults.contents;
|
|
|
|
// Add Huawei Maven repo to pluginManagement.repositories for buildscript resolution.
|
|
// NOTE: We intentionally do NOT add `plugins { id 'com.huawei.agconnect' ... }` here.
|
|
// The Huawei agcp plugin transitively depends on agconnect-apms-plugin:1.6.2.300,
|
|
// which depends on AGP 4.0.1. That old AGP references BuildCompletionListener (removed
|
|
// from Gradle 8.x+), causing NoClassDefFoundError at build time. Instead, the plugin
|
|
// is applied via buildscript classpath in build.gradle with the apms-plugin excluded.
|
|
if (!contents.includes('developer.huawei.com/repo')) {
|
|
const repoLine = ` maven { url 'https://developer.huawei.com/repo/' }`;
|
|
const hasPluginManagement = contents.includes('pluginManagement');
|
|
const hasRepositoriesInPM = /pluginManagement\s*\{[\s\S]*?repositories\s*\{/.test(contents);
|
|
|
|
if (hasRepositoriesInPM) {
|
|
config.modResults.contents = contents.replace(
|
|
/(pluginManagement\s*\{[\s\S]*?repositories\s*\{)/,
|
|
`$1\n ${repoLine}`
|
|
);
|
|
} else if (hasPluginManagement) {
|
|
config.modResults.contents = contents.replace(
|
|
/(pluginManagement\s*\{)/,
|
|
`$1\n repositories {\n gradlePluginPortal()\n google()\n mavenCentral()\n ${repoLine}\n }`
|
|
);
|
|
} else {
|
|
config.modResults.contents =
|
|
`pluginManagement {\n repositories {\n ${repoLine}\n }\n}\n\n` +
|
|
config.modResults.contents;
|
|
}
|
|
}
|
|
|
|
// Ensure Huawei Maven repo in dependencyResolutionManagement (Gradle 9+)
|
|
if (!config.modResults.contents.match(/dependencyResolutionManagement[\s\S]*developer\.huawei\.com\/repo/)) {
|
|
const depMgmtPattern = /dependencyResolutionManagement\s*\{[\s\S]*?repositories\s*\{/;
|
|
if (depMgmtPattern.test(config.modResults.contents)) {
|
|
config.modResults.contents = config.modResults.contents.replace(
|
|
depMgmtPattern,
|
|
`$&\n maven { url 'https://developer.huawei.com/repo/' }`
|
|
);
|
|
}
|
|
}
|
|
|
|
return config;
|
|
});
|
|
|
|
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;
|
|
|
|
// Add Huawei AGConnect classpath with apms-plugin excluded.
|
|
// The apms-plugin transitively depends on AGP 4.0.1 which is incompatible
|
|
// with Gradle 8.14+ (references removed BuildCompletionListener class).
|
|
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') {\n exclude group: 'com.huawei.agconnect', module: 'agconnect-apms-plugin'\n }`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set explicit AGP version (needed by Huawei plugin validation)
|
|
if (!contents.includes('com.android.tools.build:gradle:8.12.0')) {
|
|
config.modResults.contents = config.modResults.contents.replace(
|
|
/classpath\(['"]com\.android\.tools\.build:gradle['"]\)/,
|
|
"classpath('com.android.tools.build:gradle:8.12.0')"
|
|
);
|
|
}
|
|
|
|
if (!config.modResults.contents.includes('developer.huawei.com/repo')) {
|
|
const bsRepoPattern = /(buildscript\s*\{[\s\S]*?repositories\s*\{)/;
|
|
if (bsRepoPattern.test(config.modResults.contents)) {
|
|
config.modResults.contents = config.modResults.contents.replace(
|
|
bsRepoPattern,
|
|
`$1\n maven { url 'https://developer.huawei.com/repo/' }`
|
|
);
|
|
}
|
|
}
|
|
|
|
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');
|
|
}
|
|
|
|
// RN 0.85.3 ships Gradle 9.3.1 in its template, but Kotlin 2.1.20 is incompatible
|
|
// with Gradle 9.x (CompilerEnvironment ClassNotFoundException). Downgrade to 8.14.5.
|
|
const wrapperFile = path.join(config.modRequest.platformProjectRoot, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
|
if (fs.existsSync(wrapperFile)) {
|
|
let wrapper = fs.readFileSync(wrapperFile, 'utf8');
|
|
if (wrapper.includes('gradle-9.')) {
|
|
wrapper = wrapper.replace(/gradle-[\d.]+-bin\.zip/, 'gradle-8.14.5-bin.zip');
|
|
fs.writeFileSync(wrapperFile, wrapper);
|
|
console.log('[withHuaweiPush] downgraded Gradle to 8.14.5 for Kotlin 2.1.20 compatibility');
|
|
}
|
|
}
|
|
|
|
// Ensure local.properties with SDK path exists (gets cleared on prebuild --clean)
|
|
const localPropsFile = path.join(config.modRequest.platformProjectRoot, 'local.properties');
|
|
if (!fs.existsSync(localPropsFile)) {
|
|
const homeDir = process.env.USERPROFILE || process.env.HOME || '';
|
|
const sdkPath = path.join(homeDir, 'AppData', 'Local', 'Android', 'Sdk');
|
|
if (fs.existsSync(sdkPath)) {
|
|
fs.writeFileSync(localPropsFile, `sdk.dir=${sdkPath.replace(/\\/g, '\\\\')}\n`);
|
|
console.log('[withHuaweiPush] created local.properties with SDK path');
|
|
}
|
|
}
|
|
|
|
return config;
|
|
},
|
|
]);
|
|
|
|
config = withAndroidManifest(config, (config) => {
|
|
return config;
|
|
});
|
|
|
|
return config;
|
|
};
|
|
|
|
module.exports = withHuaweiPush;
|