feat: OTA校验通过后调用PackageInstaller真正安装APK

- SHA256通过→installApk()→PackageInstaller Session API
- 安装完成后通知栏提示重启
- 权限检查: canRequestPackageInstalls()
This commit is contained in:
LukeMackin
2026-07-19 19:57:56 +08:00
parent 49d3c187d0
commit 0f37573faf
8 changed files with 38 additions and 0 deletions

View File

@@ -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 ->