From 0f37573faf338e05dd347d3336b0ccaa5a6f3f7b Mon Sep 17 00:00:00 2001 From: LukeMackin Date: Sun, 19 Jul 2026 19:57:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20OTA=E6=A0=A1=E9=AA=8C=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E5=90=8E=E8=B0=83=E7=94=A8PackageInstaller=E7=9C=9F=E6=AD=A3?= =?UTF-8?q?=E5=AE=89=E8=A3=85APK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SHA256通过→installApk()→PackageInstaller Session API - 安装完成后通知栏提示重启 - 权限检查: canRequestPackageInstalls() --- .../executionHistory/executionHistory.bin | Bin 956985 -> 956985 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes .../.gradle/8.10.2/fileHashes/fileHashes.bin | Bin 44097 -> 44097 bytes .../.gradle/8.10.2/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../8.10.2/fileHashes/resourceHashesCache.bin | Bin 18973 -> 19007 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../android/.gradle/file-system.probe | Bin 8 -> 8 bytes .../main/java/dev/yuzu/gca/MainActivity.kt | 38 ++++++++++++++++++ 8 files changed, 38 insertions(+) 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 748738be6da09f5623aec4246e67da104ddd8bb8..08032007b7618f03cf9a8c5fccdec8bf19c8e62b 100644 GIT binary patch delta 2565 zcmaJ?c{r497oTSg<{38)Gw+y?DBdC_OHDpn6iKBluNEa+WH+)@N)lu2LbxMKvP`x@ zY7mu5Zz(ZUL@5brS}c(kZ{IWXecwORclF0}UHA1n=XdUNe&?L~X{a-9s56daBWyfd zf=yscvZdJ4b;QEkrtN1v+*t-5tAaxh1nm#@@;BJ;72*~cu+q@g&!7BrHf)S?Yft5{ zf=ofIoE@zT{RQF;-X?}iDU@BdrYxKOW6nf!P4>+lj@?Kl)PF!!f?L{%@-U~37(+HN zF@NM|?@iH|q#LQE9!i7D9}r6wF8fIJz6iJznQ-#fwIZk1rN}uUZ~oPX#A1Z(Zb~an zU_?1obW@$h-nVvQ0g{e(W~*b7T4;GA2Caalj;qX%6L3;}(PJ?|*D#3RP=R-zxl)x;Q9ooY-QS5p%4kY{`dJtjw9$NXAM1NDjL+SxhN@e2vORyI0MM*fjic1fvi zL|U_KNsvSCUrjGzS`=yz)lyIy-n(A356@FQjmAq$3%(0A%Y*hqD5O?iIyU0`um)!L z#MVjhmR{y!M)-3GT@1s|q7IAGGe&9ZD&qq6ywDNc_QU|JYU_J{dglEwy$fMabe1uk$+UE2|(rA4vIs22%SW zIuE9@&{75Q89{1<9=dREJDNon9}|c?LNnyW`#b{&JBb@%2cM|VQ|UmH@H*lhnf)S^ z`15&Txk`Tjq+7nzJ5elgqQF<{Knwg3g0_*xn-zPp3&lPX?_!tCnV=1;ez%{wqm+V^ zX(r)mi%j*X%PgO~-b@yUaE(yi6s5vQ5?1#)3jlb$jbLWAf)_vMsLDOIk51Sw?dDij zMI=wOc(6ALn8~M{(2wXpygu1Xf2?fJ=KN3Bp=}gcqd@-uxco0TydMqj>u_+x-<#Y! zNWq-yEggkE4(S4+7RjA>ObeNqr8W~*@|j$Jy<^r_b)4W!Jn9KGV}Jo&{3#iGE2Iq@ zLRJjWqKH2u@7_+qiWs15C;pO*ifARLh01fcDK=ZS?7TKRaQPLbl&OnB1@o4J4A#I^ z`r}vI*n(`~Vx!VNvekklT-%bVGc#;vIaK6;l@gz^3#>Un>DSjNj066rzF)cE>`}EI zbZ5U)Ma62RHT_tTu*Cvp!h~3mqZDnoz<32=Pg45E^K$%GCd>Oo8qARq2oJ^q8uYYA z72tt5u$~;Z@vGptgo|C^YLyo4FVzglivyaJ9rCQmsKS_LE-2U+*DIj-T^R(~tHxoz3DlziG z1n@!0zg<#kab1C2xR%jQhBh;}LPTzmK=R@G1fZO?6&o0CB5|Ghj`+kHS+>X*o78n%!al0I9nHw1DO8Ev zn~8An6gWz`v(&R9eY0w8xlt|R>Z9`W0+vTWDyX4bWbb0_*86Muc|yXI(;HOxaYeL3 z1m>(DErJedz>>P4baf*2qfLIGOKa_cQbO5JwM?SvT`=viAGkdxU^f z^p3uAQG^!=9JfU^U|BjavH9jBvt(_%(WMpdTd%0-(%9IXjS04vF^q$1eZ1=!%b1EP zxHvx+%QrMI7)jpG3JnPH2nuF|xVquU$keo}H(hXHYeboKdH=L)gYfnOJM<4~Pjwbe zYq&g9;Opgh_xoOYi_mg|Nz#MKr$L-z%IibJ_~MbU!85k~kKXDU-W27v8K$fvX+WC{ zu!UOX|Ez&q^8P9(dx~WknqP857=UaIkYKUGCn#lNtgb( z#7y(4Fb_r+SVWyol-sMhE2ebVsaSdUNoM;Kp`~yKN~7}Kq9&B=Ui$M>a>~PupYX9@ ze3+62RMw6^K5U{#GvB0jBsQsJ)^_NzD4$jif~5SnU;oRzd%{7HRbqYtUmX2_Z5GV! z5ynt9CTX9Dz4Nv0iy;wf`lmgAN4~HNyh zobq!G4$*ZB_4adTxOoTQ$m=Uc2iAwzFB|!qLQp0I4vdTmw@d-!S{`AODeex-zq?Jo mt$suFARsuLojGc0;q+Q`v^K=y@kO!e5MZAyFCEHp@&5+9l%7)n delta 2555 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 w5k!dWKAE0RSk~1HAwM literal 17 VcmZP;cbNQT33F5g0~oM)0RSkW1Bn0t 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 7accf6956e65416c03bdf6c055a8aed0e8d38da8..2b5186019c9f3258bf3b81b43b429d3e1e49e167 100644 GIT binary patch delta 87 zcmbO`g>nBB#tkMCjQo>LB@zVY?Dh}fww=Ju00v&Nn|mdg85t`#D*h1PXs|$Rv!lly iMkQmQq$Cgvg0Miw#aUG{Ct9*}D#Nw*w#$hF1?2!EH5Uc| delta 34 scmV+-0Nww;lmVTT0kAX}0S=Qj7+{mF82bTXu_5>uu`sw6vq4DQ0pTPKFaQ7m diff --git a/packages/client-android/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/packages/client-android/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 922e025e9c61c170db623f4ce4bb8fda5c76ec06..fade1c2f517be5e83e2e1fca8bb06acb340eb474 100644 GIT binary patch literal 17 VcmZQhQ5D(E8h+WD0SuTg0{|jv1DpT= literal 17 UcmZQhQ5D(E8h+WD0SuVK0U_-JAOHXW diff --git a/packages/client-android/android/.gradle/file-system.probe b/packages/client-android/android/.gradle/file-system.probe index 4b43214a3d9479423e2207ae0fe6d0cca0b3aeb0..a519afb4a27f573283f3125c79637da4ac1fca26 100644 GIT binary patch literal 8 PcmZQzV4PoNbM_Me2vGwT literal 8 PcmZQzV4PoNpw0*Y1@HlL diff --git a/packages/client-android/android/app/src/main/java/dev/yuzu/gca/MainActivity.kt b/packages/client-android/android/app/src/main/java/dev/yuzu/gca/MainActivity.kt index 08d3816..1fbd110 100644 --- a/packages/client-android/android/app/src/main/java/dev/yuzu/gca/MainActivity.kt +++ b/packages/client-android/android/app/src/main/java/dev/yuzu/gca/MainActivity.kt @@ -1,5 +1,8 @@ package dev.yuzu.gca +import android.app.PendingIntent +import android.content.Intent +import android.content.pm.PackageInstaller import android.graphics.Color import android.os.Bundle import android.widget.Button @@ -161,6 +164,14 @@ class MainActivity : AppCompatActivity() { 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)}") @@ -192,6 +203,33 @@ class MainActivity : AppCompatActivity() { } } + private fun installApk(apkFile: File) { + if (!packageManager.canRequestPackageInstalls()) { + throw SecurityException("需要允许安装未知应用权限") + } + val packageInstaller = packageManager.packageInstaller + val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) + val sessionId = packageInstaller.createSession(params) + val session = packageInstaller.openSession(sessionId) + try { + apkFile.inputStream().use { input -> + session.openWrite("package", 0, apkFile.length()).use { output -> + input.copyTo(output) + session.fsync(output) + } + } + val launchIntent = packageManager.getLaunchIntentForPackage(packageName) + ?: throw Exception("无法获取启动Intent") + val pendingIntent = PendingIntent.getActivity( + this, 0, launchIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + session.commit(pendingIntent.intentSender) + } finally { + session.close() + } + } + private fun computeSha256(file: File): String { val digest = MessageDigest.getInstance("SHA-256") file.inputStream().use { input ->