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 plugin resolution if (!contents.includes('developer.huawei.com/repo')) { if (contents.includes('pluginManagement')) { config.modResults.contents = contents.replace( /(pluginManagement\s*\{[\s\S]*?repositories\s*\{)/, `$1\n maven { url 'https://developer.huawei.com/repo/' }` ); } else { // No pluginManagement block at all — create one with the Huawei repo config.modResults.contents = `pluginManagement {\n repositories {\n maven { url 'https://developer.huawei.com/repo/' }\n }\n}\n\n` + config.modResults.contents; } } // Map the plugin ID to its Maven artifact via resolutionStrategy. // AGConnect is not published as a standard Gradle plugin marker, so Gradle 9+ // cannot resolve it by plugin ID alone. This mapping tells Gradle where to find it. if (!config.modResults.contents.includes('com.huawei.agconnect:agcp')) { const pmMatch = config.modResults.contents.match(/pluginManagement\s*\{/); if (pmMatch) { config.modResults.contents = config.modResults.contents.replace( /(pluginManagement\s*\{)/, `$1\n resolutionStrategy {\n eachPlugin {\n if (requested.id.id == 'com.huawei.agconnect') {\n useModule('com.huawei.agconnect:agcp:1.9.1.301')\n }\n }\n }` ); } } // Ensure Huawei Maven repo also appears 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/' }` ); } } // Declare the plugin in a top-level plugins {} block (outside pluginManagement). // In Gradle 9+, plugins declared with `apply false` in settings.gradle are // available to all subprojects via `apply plugin:` or the plugins DSL. if (!config.modResults.contents.includes("id 'com.huawei.agconnect'")) { const pluginsBlockPattern = /^plugins\s*\{/m; if (pluginsBlockPattern.test(config.modResults.contents)) { // Add to existing top-level plugins block config.modResults.contents = config.modResults.contents.replace( /^plugins\s*\{/m, `plugins {\n id 'com.huawei.agconnect' version '1.9.1.301' apply false` ); } else { // Insert a top-level plugins block after pluginManagement closing brace, // or at the very beginning if no pluginManagement block exists. const pmClosePattern = /\n\}\n/; if (pmClosePattern.test(config.modResults.contents)) { const firstClosing = config.modResults.contents.indexOf('}', config.modResults.contents.indexOf('pluginManagement')) + 1; if (firstClosing > 0) { const insertPos = firstClosing; config.modResults.contents = config.modResults.contents.slice(0, insertPos) + `\n\nplugins {\n id 'com.huawei.agconnect' version '1.9.1.301' apply false\n}` + config.modResults.contents.slice(insertPos); } } else { // Fallback: prepend after pluginManagement block config.modResults.contents = config.modResults.contents.replace( /(pluginManagement\s*\{[\s\S]*?\})/, `$1\n\nplugins {\n id 'com.huawei.agconnect' version '1.9.1.301' apply false\n}` ); } } } 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; 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'` ); } } } 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'); } return config; }, ]); config = withAndroidManifest(config, (config) => { return config; }); return config; }; module.exports = withHuaweiPush;