diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml index 73fa9af..a07a49a 100644 --- a/.gitea/workflows/build.yml +++ b/.gitea/workflows/build.yml @@ -41,7 +41,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: '25.6.1' - registry-url: 'https://registry.npmmirror.com' cache: 'npm' - name: Install dependencies @@ -106,7 +105,7 @@ jobs: NODE_OPTIONS: "--max-old-space-size=8192" NODE_ENV: "production" NDK_NUM_JOBS: "4" - CMAKE_BUILD_PARALLEL_LEVEL: "4" + CMAKE_BUILD_PARALLEL_LEVEL: "8" GRADLE_USER_HOME: /root/.gradle permissions: contents: read @@ -124,7 +123,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: '25.6.1' - registry-url: 'https://registry.npmmirror.com' cache: 'npm' - name: Install dependencies @@ -188,6 +186,7 @@ jobs: maven { url 'https://maven.aliyun.com/repository/public' } maven { url 'https://maven.aliyun.com/repository/central' } maven { url 'https://developer.huawei.com/repo/' } + maven { url 'https://developer.jiguang.cn/maven' } google() mavenCentral() gradlePluginPortal() @@ -210,6 +209,20 @@ jobs: includeBuild(expoPluginsPath) } + dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + repositories { + maven { url 'https://maven.aliyun.com/repository/google' } + maven { url 'https://maven.aliyun.com/repository/public' } + maven { url 'https://maven.aliyun.com/repository/central' } + maven { url 'https://developer.huawei.com/repo/' } + maven { url 'https://developer.jiguang.cn/maven' } + maven { url 'https://www.jitpack.io' } + google() + mavenCentral() + } + } + plugins { id("com.facebook.react.settings") id("expo-autolinking-settings") @@ -265,6 +278,7 @@ jobs: maven { url 'https://maven.aliyun.com/repository/central' } maven { url 'https://www.jitpack.io' } maven { url 'https://developer.huawei.com/repo/' } + maven { url 'https://developer.jiguang.cn/maven' } google() mavenCentral() } @@ -292,6 +306,8 @@ jobs: expo.webp.animated=false ndkVersion=27.1.12297006 expo.useLegacyPackaging=false + systemProp.org.gradle.internal.http.connectionTimeout=30000 + systemProp.org.gradle.internal.http.socketTimeout=30000 PROPS_EOF # Append signing properties (secrets appended, not cached) @@ -313,7 +329,7 @@ jobs: ./gradlew :app:assembleRelease -PreactNativeArchitectures=arm64-v8a --max-workers=4 --parallel - name: Upload APK artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: name: withyou-android-release-apk path: android/app/build/outputs/apk/release/app-release.apk @@ -396,8 +412,6 @@ jobs: labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64 provenance: false - cache-from: type=registry,ref=code.littlelan.cn/carrot_bbs/frontend-web:buildcache - cache-to: type=registry,ref=code.littlelan.cn/carrot_bbs/frontend-web:buildcache,mode=max - name: Show image tags run: | diff --git a/.npmrc b/.npmrc index 58fd2d6..9320736 100644 --- a/.npmrc +++ b/.npmrc @@ -1,5 +1 @@ -# Use China npm mirror for faster downloads in CI -registry=https://registry.npmmirror.com - -# Disable always-auth to avoid deprecation warnings always-auth=false diff --git a/app.json b/app.json index 5a85713..5aaca0c 100644 --- a/app.json +++ b/app.json @@ -66,6 +66,8 @@ "favicon": "./assets/favicon.png" }, "plugins": [ + "./plugins/withCmakeJobLimit", + "./plugins/withJcorePatch", "./plugins/withSigning", "./plugins/withMainActivityConfigChange", [ diff --git a/plugins/withCmakeJobLimit.js b/plugins/withCmakeJobLimit.js new file mode 100644 index 0000000..28f0131 --- /dev/null +++ b/plugins/withCmakeJobLimit.js @@ -0,0 +1,60 @@ +const { withDangerousMod } = require('@expo/config-plugins'); +const fs = require('fs'); +const path = require('path'); + +const MAX_JOBS = '8'; + +// React Native's hermes-engine build hardcodes +// Runtime.getRuntime().availableProcessors() +// for cmake --build -j, ignoring all env vars. +// On high-core CI runners this exhausts memory. +// This plugin patches hermes-engine/build.gradle.kts +// during prebuild to cap parallel jobs. +const withCmakeJobLimit = (config) => + withDangerousMod(config, [ + 'android', + async (config) => { + const root = config.modRequest.projectRoot; + + // 1. Patch hermes-engine: availableProcessors() -> "8" + const hermesPath = path.join( + root, + 'node_modules', + 'react-native', + 'ReactAndroid', + 'hermes-engine', + 'build.gradle.kts', + ); + if (fs.existsSync(hermesPath)) { + let content = fs.readFileSync(hermesPath, 'utf-8'); + content = content.replace( + /Runtime\.getRuntime\(\)\.availableProcessors\(\)\.toString\(\)/, + `"${MAX_JOBS}"`, + ); + fs.writeFileSync(hermesPath, content); + } + + // 2. Patch app/build.gradle: add cmake -j argument to externalNativeBuild + const appGradlePath = path.join( + config.modRequest.platformProjectRoot, + 'app', + 'build.gradle', + ); + if (fs.existsSync(appGradlePath)) { + let content = fs.readFileSync(appGradlePath, 'utf-8'); + // Insert externalNativeBuild cmake arguments block inside the android { } block + // We add it right after "ndkVersion rootProject.ext.ndkVersion" + if (!content.includes('CMAKE_BUILD_PARALLEL_LEVEL')) { + content = content.replace( + /(\s*ndkVersion rootProject\.ext\.ndkVersion)/, + `$1\n externalNativeBuild {\n cmake {\n arguments "-j${MAX_JOBS}"\n }\n }`, + ); + } + fs.writeFileSync(appGradlePath, content); + } + + return config; + }, + ]); + +module.exports = withCmakeJobLimit; diff --git a/plugins/withHuaweiPush.js b/plugins/withHuaweiPush.js index 92b7c2e..a4af2bd 100644 --- a/plugins/withHuaweiPush.js +++ b/plugins/withHuaweiPush.js @@ -22,6 +22,35 @@ const withHuaweiPush = (config, options = {}) => { // 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 jigLine = ` maven { url 'https://developer.jiguang.cn/maven' }`; + 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}\n ${jigLine}` + ); + } else if (hasPluginManagement) { + config.modResults.contents = contents.replace( + /(pluginManagement\s*\{)/, + `$1\n repositories {\n gradlePluginPortal()\n google()\n mavenCentral()\n ${repoLine}\n ${jigLine}\n }` + ); + } else { + config.modResults.contents = + `pluginManagement {\n repositories {\n ${repoLine}\n ${jigLine}\n }\n}\n\n` + + config.modResults.contents; + } + } + + // Add Jiguang Maven repo for dependency resolution (jcore/jpush SDK) + if (!contents.includes('developer.jiguang.cn/maven')) { + const depMgmtPattern = /dependencyResolutionManagement\s*\{[\s\S]*?repositories\s*\{/; + if (depMgmtPattern.test(config.modResults.contents)) { + config.modResults.contents = config.modResults.contents.replace( + depMgmtPattern, + ` 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); @@ -51,6 +80,9 @@ const withHuaweiPush = (config, options = {}) => { `$&\n maven { url 'https://developer.huawei.com/repo/' }` ); } + }\n maven { url 'https://developer.jiguang.cn/maven' }` + ); + } } return config; diff --git a/plugins/withJcorePatch.js b/plugins/withJcorePatch.js new file mode 100644 index 0000000..b81771c --- /dev/null +++ b/plugins/withJcorePatch.js @@ -0,0 +1,43 @@ +const { withDangerousMod } = require('@expo/config-plugins'); +const fs = require('fs'); +const path = require('path'); + +// Patch jcore-react-native's build.gradle to remove the legacy flatDir block +// and jniLibs.srcDirs. The 'libs' directory no longer exists in the package — +// dependencies are fetched from Maven — but the stale config causes Gradle +// warnings and can stall dependency resolution on newer Gradle versions. +const withJcorePatch = (config) => + withDangerousMod(config, [ + 'android', + async (config) => { + const root = config.modRequest.projectRoot; + const gradlePath = path.join( + root, + 'node_modules', + 'jcore-react-native', + 'android', + 'build.gradle', + ); + + if (!fs.existsSync(gradlePath)) return config; + + let content = fs.readFileSync(gradlePath, 'utf-8'); + + // Remove flatDir block + content = content.replace( + /repositories\s*\{\s*flatDir\s*\{\s*dirs\s+['"]libs['"]\s*\}\s*\}/, + '', + ); + + // Remove jniLibs.srcDirs line and its enclosing sourceSets block if it becomes empty + content = content.replace( + /\s*sourceSets\s*\{\s*main\s*\{\s*jniLibs\.srcDirs\s*=\s*\['libs'\]\s*\}\s*\}/, + '', + ); + + fs.writeFileSync(gradlePath, content); + return config; + }, + ]); + +module.exports = withJcorePatch;