feat: OTA校验通过后调用PackageInstaller真正安装APK
- SHA256通过→installApk()→PackageInstaller Session API - 安装完成后通知栏提示重启 - 权限检查: canRequestPackageInstalls()
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,8 @@
|
|||||||
package dev.yuzu.gca
|
package dev.yuzu.gca
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageInstaller
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
@@ -161,6 +164,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val actualSha256 = computeSha256(apkFile)
|
val actualSha256 = computeSha256(apkFile)
|
||||||
if (actualSha256 == manifestSha256) {
|
if (actualSha256 == manifestSha256) {
|
||||||
appendLog(" ✅ SHA256 校验通过!")
|
appendLog(" ✅ SHA256 校验通过!")
|
||||||
|
// 5. 安装 APK
|
||||||
|
appendLog("[5/5] 提交安装...")
|
||||||
|
try {
|
||||||
|
installApk(apkFile)
|
||||||
|
appendLog(" ✅ 安装已提交,稍后通知栏点击重启")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
appendLog(" ❌ 安装失败: ${e.message}")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
appendLog(" ❌ SHA256 校验失败!")
|
appendLog(" ❌ SHA256 校验失败!")
|
||||||
appendLog(" expected: ${manifestSha256.take(32)}")
|
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 {
|
private fun computeSha256(file: File): String {
|
||||||
val digest = MessageDigest.getInstance("SHA-256")
|
val digest = MessageDigest.getInstance("SHA-256")
|
||||||
file.inputStream().use { input ->
|
file.inputStream().use { input ->
|
||||||
|
|||||||
Reference in New Issue
Block a user