feat: expo-updates热更新构建成功(387 tasks,128MB)

- npm替换pnpm(扁平node_modules兼容Expo Gradle)
- 硬编码react块路径替代node execute调用
- Kotlin 1.9.24→2.0.21版本升级
- execute工作目录修复(rootDir→rootDir.parentFile)
- assets/图标占位符
- BUILD SUCCESSFUL 4m31s
This commit is contained in:
LukeMackin
2026-07-20 20:03:01 +08:00
parent 084560c058
commit 1360eb379c
21 changed files with 11586 additions and 295 deletions

12
package-lock.json generated Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "yuzu-gca",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "yuzu-gca",
"version": "0.1.0"
}
}
}

View File

@@ -1,2 +1,2 @@
#Mon Jul 20 18:49:30 CST 2026
#Mon Jul 20 19:51:16 CST 2026
gradle.version=8.10.2

View File

@@ -1,40 +1,176 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
/**
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
*/
react {
entryFile = file("../../App.tsx")
reactNativeDir = file("../../node_modules/react-native")
hermesCommand = "../../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
codegenDir = file("../../node_modules/@react-native/codegen")
// Use Expo CLI to bundle the app, this ensures the Metro config
// works correctly with Expo projects.
cliFile = file("../../node_modules/@expo/cli/build/bin/cli")
bundleCommand = "export:embed"
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '../..'
// root = file("../../")
// The folder where the react-native NPM package is. Default is ../../node_modules/react-native
// reactNativeDir = file("../../node_modules/react-native")
// The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen
// codegenDir = file("../../node_modules/@react-native/codegen")
/* Variants */
// The list of variants to that are debuggable. For those we're going to
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
// debuggableVariants = ["liteDebug", "prodDebug"]
/* Bundling */
// A list containing the node command and its flags. Default is just 'node'.
// nodeExecutableAndArgs = ["node"]
//
// The path to the CLI configuration file. Default is empty.
// bundleConfig = file(../rn-cli.config.js)
//
// The name of the generated asset file containing your JS bundle
// bundleAssetName = "MyApplication.android.bundle"
//
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
// entryFile = file("../js/MyApplication.android.js")
//
// A list of extra flags to pass to the 'bundle' commands.
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
// extraPackagerArgs = []
/* Hermes Commands */
// The hermes compiler command to run. By default it is 'hermesc'
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
//
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
// hermesFlags = ["-O", "-output-source-map"]
/* Autolinking */
autolinkLibrariesWithApp()
}
/**
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
*/
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
/**
* The preferred build flavor of JavaScriptCore (JSC)
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
android {
namespace 'dev.yuzu.gca'
compileSdk 35
ndkVersion rootProject.ext.ndkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion
namespace 'dev.yuzu.gca'
defaultConfig {
applicationId 'dev.yuzu.gca'
minSdk 24
targetSdk 35
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 8
versionName "0.1.0"
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
release { minifyEnabled false }
debug { debuggable true }
debug {
signingConfig signingConfigs.debug
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
crunchPngs (findProperty('android.enablePngCrunchInReleaseBuilds')?.toBoolean() ?: true)
}
}
packagingOptions {
jniLibs {
useLegacyPackaging (findProperty('expo.useLegacyPackaging')?.toBoolean() ?: false)
}
}
androidResources {
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}
kotlinOptions { jvmTarget = "17" }
// Apply static values from `gradle.properties` to the `android.packagingOptions`
// Accepts values in comma delimited lists, example:
// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
// Split option: 'foo,bar' -> ['foo', 'bar']
def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
// Trim all elements in place.
for (i in 0..<options.size()) options[i] = options[i].trim();
// `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
options -= ""
applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "v${variant.versionName}-dav-android-${variant.versionCode}-${variant.buildType.name}.apk"
if (options.length > 0) {
println "android.packagingOptions.$prop += $options ($options.length)"
// Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
options.each {
android.packagingOptions[prop] += it
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.0.21"
implementation "androidx.appcompat:appcompat:1.7.0"
implementation "androidx.core:core:1.15.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0"
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
if (isGifEnabled) {
// For animated gif support
implementation("com.facebook.fresco:animated-gif:${reactAndroidLibs.versions.fresco.get()}")
}
if (isWebpEnabled) {
// For webp support
implementation("com.facebook.fresco:webpsupport:${reactAndroidLibs.versions.fresco.get()}")
if (isWebpAnimatedEnabled) {
// Animated webp support
implementation("com.facebook.fresco:animated-webp:${reactAndroidLibs.versions.fresco.get()}")
}
}
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
implementation jscFlavor
}
}

View File

@@ -2,14 +2,23 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:name=".MainApplication" android:label="Yuzu GCA v0.1.0" android:allowBackup="false" android:supportsRtl="true" android:theme="@style/Theme.AppCompat.DayNight">
<queries>
<intent>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"/>
</intent>
</queries>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme" android:supportsRtl="true">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
<meta-data android:name="expo.modules.updates.EXPO_RUNTIME_VERSION" android:value="@string/expo_runtime_version"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="3000"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/raw/branch/main/ota/expo-manifest.json"/>
<activity android:name=".MainActivity" android:label="Yuzu GCA v0.1.0" android:launchMode="singleTask" android:exported="true" android:screenOrientation="portrait" android:windowSoftInputMode="adjustResize">
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
@@ -21,8 +30,5 @@
<data android:scheme="dev.yuzu.gca"/>
</intent-filter>
</activity>
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/>
</provider>
</application>
</manifest>

View File

@@ -1,255 +1,61 @@
package dev.yuzu.gca
import android.app.PendingIntent
import android.content.Intent
import android.content.pm.PackageInstaller
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.widget.Button
import android.widget.LinearLayout
import android.widget.ScrollView
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
import java.io.File
import java.io.FileOutputStream
import java.net.HttpURLConnection
import java.net.URL
import java.security.MessageDigest
import android.util.Log
import androidx.core.content.FileProvider
import org.json.JSONObject
class MainActivity : AppCompatActivity() {
private lateinit var logView: TextView
private var selectedChannel = "stable"
import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate
import expo.modules.ReactActivityDelegateWrapper
class MainActivity : ReactActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val scroll = ScrollView(this)
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
setPadding(24, 24, 24, 24)
// Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen.
setTheme(R.style.AppTheme);
super.onCreate(null)
}
val title = TextView(this).apply {
text = "Yuzu GCA"
textSize = 20f
setPadding(0, 0, 0, 4)
}
layout.addView(title)
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "main"
val versionInfo = TextView(this).apply {
text = "v0.1.0-dav-android-8-debug"
textSize = 12f
setTextColor(Color.GRAY)
setPadding(0, 0, 0, 12)
}
layout.addView(versionInfo)
val channelLabel = TextView(this).apply {
text = "选择更新渠道:"
textSize = 13f
setPadding(0, 8, 0, 4)
}
layout.addView(channelLabel)
// 渠道按钮行
val channelRow = LinearLayout(this).apply {
orientation = LinearLayout.HORIZONTAL
setPadding(0, 0, 0, 12)
/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate {
return ReactActivityDelegateWrapper(
this,
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED,
object : DefaultReactActivityDelegate(
this,
mainComponentName,
fabricEnabled
){})
}
fun makeChannelBtn(label: String, channel: String): Button {
return Button(this).apply {
text = label
textSize = 12f
setOnClickListener {
selectedChannel = channel
highlightChannel(channelRow, this)
}
/**
* Align the back button behavior with Android S
* where moving root activities to background instead of finishing activities.
* @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
*/
override fun invokeDefaultOnBackPressed() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
if (!moveTaskToBack(false)) {
// For non-root activities, use the default implementation to finish them.
super.invokeDefaultOnBackPressed()
}
return
}
val btnStable = makeChannelBtn("Stable", "stable")
val btnBeta = makeChannelBtn("Beta", "beta")
val btnNightly = makeChannelBtn("Nightly", "nightly")
channelRow.addView(btnStable)
channelRow.addView(btnBeta)
channelRow.addView(btnNightly)
layout.addView(channelRow)
highlightChannel(channelRow, btnStable)
logView = TextView(this).apply {
textSize = 12f
setTextColor(Color.LTGRAY)
}
layout.addView(logView)
val btn = Button(this).apply {
text = "检查更新"
setOnClickListener {
val ch = selectedChannel
CoroutineScope(Dispatchers.IO).launch { doOtaTest(ch) }
}
}
layout.addView(btn)
scroll.addView(layout)
setContentView(scroll)
appendLog("渠道: stable | 点击[检查更新]开始")
}
private fun highlightChannel(row: LinearLayout, active: Button) {
for (i in 0 until row.childCount) {
val b = row.getChildAt(i) as Button
b.isSelected = (b == active)
}
}
private fun appendLog(msg: String) {
Log.i(TAG, msg)
runOnUiThread { logView.append("$msg\n") }
}
companion object { private const val TAG = "GCA-OTA" }
private fun manifestUrl(channel: String): String {
val base = "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/raw/branch/main/ota"
return when (channel) {
"beta" -> "$base/manifest-beta.json"
"nightly" -> "$base/manifest-nightly.json"
else -> "$base/manifest-stable.json"
}
}
private suspend fun doOtaTest(channel: String) = withContext(Dispatchers.IO) {
val url = manifestUrl(channel)
appendLog("=== OTA 渠道: $channel ===")
appendLog("manifest: $url")
// 1. 拉取 manifest
appendLog("[1/4] 拉取 manifest...")
val manifestJson: String
try {
manifestJson = httpGet(url)
appendLog(" ✅ 获取成功 (${manifestJson.length}B)")
} catch (e: Exception) {
appendLog(" ❌ 获取失败: ${e.message}")
appendLog("=== 测试中止 ===")
return@withContext
}
// 2. 解析
appendLog("[2/4] 解析 manifest...")
var manifestSha256 = ""
var manifestApkUrl = ""
var manifestTag = ""
try {
val json = JSONObject(manifestJson)
if (!json.getJSONObject("builds").has("android")) {
appendLog(" 该渠道暂无可用更新")
appendLog("=== $channel 渠道测试完成 ===")
return@withContext
}
val android = json.getJSONObject("builds").getJSONObject("android")
manifestSha256 = android.getString("sha256")
manifestApkUrl = android.getString("url")
manifestTag = android.getString("tag")
appendLog(" 渠道: $channel 版本: $manifestTag")
appendLog(" SHA256: ${manifestSha256.take(16)}...")
// 版本比较:一致则跳过
val localTag = "v0.1.0-dav-android-${packageManager.getPackageInfo(packageName, 0).versionCode}"
if (manifestTag == localTag) {
appendLog(" ✅ 已是最新版本,无需更新")
appendLog("=== $channel 渠道测试完成 ===")
return@withContext
}
appendLog(" 发现新版本,开始更新...")
} catch (e: Exception) {
appendLog(" ❌ 解析失败: ${e.message}")
return@withContext
}
// 3. 下载
appendLog("[3/4] 下载 APK...")
val apkFile = File(cacheDir, "update-$channel.apk")
try {
downloadFile(manifestApkUrl, apkFile)
appendLog(" ✅ 下载完成: ${apkFile.length()} bytes")
} catch (e: Exception) {
appendLog(" ❌ 下载失败: ${e.message}")
return@withContext
}
// 4. SHA256 校验
appendLog("[4/4] SHA256 校验...")
val actualSha256 = computeSha256(apkFile)
if (actualSha256 == manifestSha256) {
appendLog(" ✅ SHA256 校验通过!")
// 5. 安装 APK
appendLog("[5/5] 提交安装...")
try {
installApk(apkFile)
appendLog(" ✅ 安装已提交,稍后通知栏点击重启")
} catch (e: Exception) {
appendLog(" ❌ 安装失败: ${e.message}")
}
} else {
appendLog(" ❌ SHA256 校验失败!")
appendLog(" expected: ${manifestSha256.take(32)}")
appendLog(" actual: ${actualSha256.take(32)}")
}
appendLog("=== $channel 渠道测试完成 ===")
}
private fun httpGet(url: String): String {
val conn = URL(url).openConnection() as HttpURLConnection
conn.connectTimeout = 10000
conn.readTimeout = 10000
return conn.inputStream.bufferedReader().readText()
}
private val ALLOWED_HOSTS = setOf("git.childish-ghost.com", "github.com")
private fun downloadFile(url: String, dest: File) {
val host = URL(url).host
if (!ALLOWED_HOSTS.any { host == it || host.endsWith(".$it") }) {
throw SecurityException("不允许的下载域名: $host")
}
val conn = URL(url).openConnection() as HttpURLConnection
conn.connectTimeout = 30000
conn.readTimeout = 120000
conn.inputStream.use { input ->
FileOutputStream(dest).use { output -> input.copyTo(output) }
}
}
private fun installApk(apkFile: File) {
val uri = FileProvider.getUriForFile(this, "${packageName}.fileprovider", apkFile)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(intent)
}
private fun computeSha256(file: File): String {
val digest = MessageDigest.getInstance("SHA-256")
file.inputStream().use { input ->
val buf = ByteArray(8192)
var read: Int
while (input.read(buf).also { read = it } != -1) {
digest.update(buf, 0, read)
}
}
return digest.digest().joinToString("") { "%02x".format(it) }
// Use the default back button implementation on Android S
// because it's doing more than [Activity.moveTaskToBack] in fact.
super.invokeDefaultOnBackPressed()
}
}

View File

@@ -1,5 +1,57 @@
package dev.yuzu.gca
import android.app.Application
import android.content.res.Configuration
class MainApplication : Application()
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
import expo.modules.ApplicationLifecycleDispatcher
import expo.modules.ReactNativeHostWrapper
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost = ReactNativeHostWrapper(
this,
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
val packages = PackageList(this).packages
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages
}
override fun getJSMainModuleName(): String = ".expo/.virtual-metro-entry"
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}
)
override val reactHost: ReactHost
get() = ReactNativeHostWrapper.createReactHost(applicationContext, reactNativeHost)
override fun onCreate() {
super.onCreate()
SoLoader.init(this, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
ApplicationLifecycleDispatcher.onApplicationCreate(this)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
}
}

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path name="apk" path="/" />
</paths>

View File

@@ -1,24 +1,39 @@
// Top-level build file
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "35.0.0"
minSdkVersion = 24
compileSdkVersion = 35
targetSdkVersion = 35
kotlinVersion = "2.0.21"
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '35.0.0'
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34')
kotlinVersion = '2.0.21'
ndkVersion = "26.1.10909125"
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:8.7.3")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
classpath('com.android.tools.build:gradle')
classpath('com.facebook.react:react-native-gradle-plugin')
classpath('org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21')
}
}
apply plugin: "com.facebook.react.rootproject"
allprojects {
repositories {
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir.parentFile).text.trim(), '../android'))
}
maven {
// Android JSC is installed from npm
url(new File(['node', '--print', "require.resolve('jsc-android/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir.parentFile).text.trim(), '../dist'))
}
google()
mavenCentral()
maven { url 'https://www.jitpack.io' }

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,26 +1,94 @@
@echo off
setlocal
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_HOME=%DIRNAME%
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set ANDROID_HOME=C:\Users\Middl\AppData\Local\Android\Sdk
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:fail
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
exit /b 1
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -1,3 +1,38 @@
pluginManagement {
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir.parentFile).text.trim()).getParentFile().toString())
}
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
ex.autolinkLibrariesFromCommand()
} else {
def command = [
'node',
'--no-warnings',
'--eval',
'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))',
'react-native-config',
'--json',
'--platform',
'android'
].toList()
ex.autolinkLibrariesFromCommand(command)
}
}
rootProject.name = 'YuzuGCA'
dependencyResolutionManagement {
versionCatalogs {
reactAndroidLibs {
from(files(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir.parentFile).text.trim(), "../gradle/libs.versions.toml")))
}
}
}
apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir.parentFile).text.trim(), "../scripts/autolinking.gradle");
useExpoModules()
include ':app'
includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir.parentFile).text.trim()).getParentFile())

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

11165
packages/client-android/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -12,9 +12,7 @@
"ios": "expo run:ios"
},
"dependencies": {
"@react-native/gradle-plugin": "^0.86.0",
"@yuzu-gca/shared": "workspace:*",
"expo": "~52.0.49",
"@react-native/gradle-plugin": "^0.86.0","expo": "~52.0.49",
"expo-constants": "~17.0.0",
"expo-file-system": "~18.0.0",
"expo-status-bar": "~2.0.0",