From d4169538c97e08fab11e57ade00cf481aa4255ce Mon Sep 17 00:00:00 2001 From: LukeMackin Date: Sun, 19 Jul 2026 15:42:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20manifest=E6=94=BE=E5=9B=9E=E4=BB=93?= =?UTF-8?q?=E5=BA=93=E6=BA=90=E7=A0=81=20+=20APK=E6=8C=89=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=8F=B7=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - manifest.json/beta/nightly 从Release Assets移到源码仓库 - APK命名: gca-v0.1.0 → v0.1.0-dav-android-debug.apk - Release #7: 仅含APK(prerelease), manifest从raw URL拉取 - 三渠道manifest: manifest.json / manifest-beta.json / manifest-nightly.json --- .../executionHistory/executionHistory.bin | Bin 804154 -> 956985 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .../.gradle/8.10.2/fileHashes/fileHashes.bin | Bin 43847 -> 43997 bytes .../.gradle/8.10.2/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../8.10.2/fileHashes/resourceHashesCache.bin | Bin 18803 -> 18871 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../android/.gradle/file-system.probe | Bin 8 -> 8 bytes .../client-android/android/app/build.gradle | 2 +- .../main/java/dev/yuzu/gca/MainActivity.kt | 133 +++++++++++++----- packages/client-android/manifest-beta.json | 1 + packages/client-android/manifest-nightly.json | 1 + packages/client-android/manifest.json | 5 +- 12 files changed, 100 insertions(+), 42 deletions(-) create mode 100644 packages/client-android/manifest-beta.json create mode 100644 packages/client-android/manifest-nightly.json diff --git a/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.bin b/packages/client-android/android/.gradle/8.10.2/executionHistory/executionHistory.bin index 244c4b241bfd520f2bd66d8c28390f1f817f60c8..2675db3a5f37b585b907cebb9ab697affc846e44 100644 GIT binary patch delta 4321 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 delta 1683 zcmZXU3s6*57{~Xa46sg!3&TrgQ4!%TEX%WW3swZdO;IBz6fCT4%$$jsMra5D9R*?7 z;A2@H!md-AtO3D=l7UGmo{<@hfZ`BgB&kVkpz;`^^O}b2&g?z^d%yqp`_B39*)uXE z>KYV%8Q>^f-~%0-HuDxCCxv`PXsQMH?7S;1EpSWW)sfz6u}b`aPs%wc6suMO+&HH| zV=)MGJH#qUGxX%5XNfl~kg*NC^U$;PMR*;Ll2$0lQ%F!;fG=U98;oU0UAybQGv>58 zkB5%F(YN4p2L%kNipmqjBe1vO7xPvLWs!|P{l3R<+tZd?f32M^%KezQRGb5K<<>yv zA*t)y4BHFYrEW9Z(vMB%Hy@=QuVCtN>W8s+r2B&SiK})RL8rSmMp{!@`Crc}HS+rS zqnjuCx#8dHm~Y?O@^mQI+*sW`C9-)*&oY8g5MA;HP^L+t)no_v^8Lgrc|4ePXsz-% zG&;kJ#r8{zE`U-K< z0h|Qa3J{3PCQ$eU>oY`mFii@eIQDuH?@3S>pnUEu<)D#qL@ExZbS^+K?aMIjbe>!% zv7Rl&W!k`ir-9y)>2Mt+whr*R#3VPGXaUigOyg2K(IVpi4Qp-@76C6w$d)F=F~=uO zUZc_R&j;KeOief!(OX3O!A%librDW{K=dfn7;dY>?;l}+tTXESU(J@>3y=M;8P$I# z*)hNbYiJg{sY4Cr{$MM3NM=MEI*h=0b+B zXPkNxo5nHu3XqhcnA{yP@VJ4n=q}vAcA-1*KPt1AsN}A+M}lCs={8a(%EL`QRgRfb z!e}Jgmgotl>8@S_%Jb-7Ew^E;!(fh=Li%|-lxu}Kj_qrH2>g6*?np*g;_8Vyb3fbh zJ27lmT4vr3ti%s(k-xE-X{ z)J@ko|Jat^;POyt*6dUKTMJEO*Vpf9EJKnXhwF2Afg&g}odv^aElJ1!Yn{*q`bSw9 zlpjoAwW=ML9A+62tWV*PSmfd$O7pukmXZI(;4fy?Zby!KywZ91N|R8g(++eVQa{Yf zk^ZRF%sjV5qP}jkw5G#p==)6Sz+2Vp&#ZUiO6_C+j_S+Do|Koj7l0wvS!V3LZoT4q z!@I^PeOS`PX4GbMK&pJ_C}2xBJAkB+YTPUPsBn){%fQB0hK_&Zku@8~PAk9d)V%dH zf8Us58RcSMtqoV+nJ-K#+!|xIxr!nK(AkSGA)wncJwGOyn~mu4y)@$Um7;(C=NXm( zrYc{tDqs*ss?c^rqm3yMjgydUQiy$BYEhfe*=0i8$V&}|D@23Em35mulUlPqT!Sv} W)^3Vk+25mKyc=W!O64g$gMR?Ns#8}0 diff --git a/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.lock b/packages/client-android/android/.gradle/8.10.2/fileHashes/fileHashes.lock index 76da75c92d0bdcef55e763d1e625b556a3cd193c..d108fdd1f4bf1402050baaa0c04dde6cde9194c9 100644 GIT binary patch literal 17 VcmZP;cbNQT33F5g0~j#p0{|$*1FZl6 literal 17 VcmZP;cbNQT33F5g0~jz}001c?1PuTH diff --git a/packages/client-android/android/.gradle/8.10.2/fileHashes/resourceHashesCache.bin b/packages/client-android/android/.gradle/8.10.2/fileHashes/resourceHashesCache.bin index 844cabd1dfff28a35050b3f02d81df01e60a4271..3dc1a59fe0298760843b14ad011e26527d2b542b 100644 GIT binary patch delta 160 zcmex7iE;a6#tkMCn%phvvS*#6nZ7cBfv5g|DClAoShV`;H#Mku@nlzt1_8m(Yv%3c z4{U%6PMy40B8rJoa--r8@r4HBn;kuj7+s8kl9E6y2*Ls-dCHO{cmB$$tDR^&5@z!O cC@6=jLU8> "$base/manifest-beta.json" + "nightly" -> "$base/manifest-nightly.json" + else -> "$base/manifest.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 { - val manifestJson = httpGet("https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-6/manifest.json") - appendLog(" manifest: ${manifestJson.take(200)}...") + manifestJson = httpGet(url) + appendLog(" ✅ 获取成功 (${manifestJson.length}B)") } catch (e: Exception) { - appendLog(" ⚠️ 网络不可用: ${e.message}") - appendLog(" 代码逻辑已验证(版本解析/SHA256/PackageInstaller)") - appendLog("=== OTA 测试完成(离线模式) ===") + appendLog(" ❌ 获取失败: ${e.message}") + appendLog("=== 测试中止 ===") return@withContext } - appendLog("[2/4] 解析 manifest JSON...") + // 2. 解析 + appendLog("[2/4] 解析 manifest...") var manifestSha256 = "" var manifestApkUrl = "" + var manifestTag = "" try { - val manifestJson = httpGet("https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-6/manifest.json") - // 简易 JSON 解析(不用 Gson,直接字符串提取) - val sha256Field = "\"sha256\": \"" - val sha256Start = manifestJson.indexOf(sha256Field) + sha256Field.length - val sha256End = manifestJson.indexOf("\"", sha256Start) - manifestSha256 = manifestJson.substring(sha256Start, sha256End) - - val urlField = "\"url\": \"" - val urlStart = manifestJson.indexOf(urlField) + urlField.length - val urlEnd = manifestJson.indexOf("\"", urlStart) - manifestApkUrl = manifestJson.substring(urlStart, urlEnd) - + fun extractJson(key: String): String { + val field = "\"$key\": \"" + val start = manifestJson.indexOf(field) + field.length + val end = manifestJson.indexOf("\"", start) + return manifestJson.substring(start, end) + } + manifestSha256 = extractJson("sha256") + manifestApkUrl = extractJson("url") + manifestTag = extractJson("tag") + appendLog(" 渠道: $channel 版本: $manifestTag") appendLog(" SHA256: ${manifestSha256.take(16)}...") - appendLog(" APK URL: ${manifestApkUrl.take(50)}...") - appendLog(" 需要更新 ✅") } catch (e: Exception) { - appendLog(" ⚠️ manifest 解析失败: ${e.message}") - appendLog("=== OTA 测试中止 ===") + appendLog(" ❌ 解析失败: ${e.message}") return@withContext } - appendLog("[3/4] 下载 APK: ${manifestApkUrl.take(40)}...") - val apkFile = File(cacheDir, "test-update.apk") + // 3. 下载 + appendLog("[3/4] 下载 APK...") + val apkFile = File(cacheDir, "update-$channel.apk") try { downloadFile(manifestApkUrl, apkFile) - appendLog(" 下载完成: ${apkFile.length()} bytes ✅") + 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 校验通过!") - appendLog(" ${actualSha256.take(32)}...") } else { appendLog(" ❌ SHA256 校验失败!") - appendLog(" 期望: ${manifestSha256.take(32)}...") - appendLog(" 实际: ${actualSha256.take(32)}...") + appendLog(" expected: ${manifestSha256.take(32)}") + appendLog(" actual: ${actualSha256.take(32)}") } - appendLog("=== OTA 测试完成 ===") + appendLog("=== $channel 渠道测试完成 ===") } private fun httpGet(url: String): String { diff --git a/packages/client-android/manifest-beta.json b/packages/client-android/manifest-beta.json new file mode 100644 index 0000000..b238a9a --- /dev/null +++ b/packages/client-android/manifest-beta.json @@ -0,0 +1 @@ +{"version":"0.1.0","builds":{"android":{"type":"apk","tag":"v0.1.0-dav-android-7-beta","url":"https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-7/v0.1.0-dav-android-debug.apk","sha256":"6cd6bbfe07e8b86b06bc328b7b08138dfb00defc71c8bcc98fbb256b2153aba6","size":3223411,"channel":"beta"}}} \ No newline at end of file diff --git a/packages/client-android/manifest-nightly.json b/packages/client-android/manifest-nightly.json new file mode 100644 index 0000000..a6dd7c4 --- /dev/null +++ b/packages/client-android/manifest-nightly.json @@ -0,0 +1 @@ +{"version":"0.1.0","builds":{"android":{"type":"apk","tag":"v0.1.0-dav-android-7-nightly","url":"https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-7/v0.1.0-dav-android-debug.apk","sha256":"6cd6bbfe07e8b86b06bc328b7b08138dfb00defc71c8bcc98fbb256b2153aba6","size":3223411,"channel":"nightly"}}} \ No newline at end of file diff --git a/packages/client-android/manifest.json b/packages/client-android/manifest.json index 1c24a26..a6f38e8 100644 --- a/packages/client-android/manifest.json +++ b/packages/client-android/manifest.json @@ -3,10 +3,11 @@ "builds": { "android": { "type": "apk", - "tag": "v0.1.0-dav-android-6", - "url": "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-6/gca-v0.1.0.apk", + "tag": "v0.1.0-dav-android-7", + "url": "https://git.childish-ghost.com/LukeMackin/Yuzu-GCA/releases/download/v0.1.0-dav-android-7/v0.1.0-dav-android-debug.apk", "sha256": "6cd6bbfe07e8b86b06bc328b7b08138dfb00defc71c8bcc98fbb256b2153aba6", "size": 3223411, + "channel": "stable", "minVersion": "0.1.0" } }