feat: silent updating (#51)

Co-authored-by: Diamond <33725716+DiamondMiner88@users.noreply.github.com>
This commit is contained in:
rushii 2023-01-08 10:59:11 -08:00 • committed by GitHub
parent f44cae2311
commit c18ffbabea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 26 deletions

View file

@ -4,6 +4,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
@ -25,8 +26,8 @@
android:name=".ManagerApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
tools:ignore="AllowBackup">
<service android:name=".installer.service.InstallService" />

View file

@ -6,6 +6,7 @@
package com.aliucord.manager.installer.util
import android.Manifest
import android.os.Build
import pxb.android.axml.*
object ManifestPatcher {
@ -67,10 +68,12 @@ object ManifestPatcher {
"uses-sdk" -> object : NodeVisitor(nv) {
override fun attr(ns: String?, name: String?, resourceId: Int, type: Int, value: Any?) {
if (name != "targetSdkVersion")
if (name == "targetSdkVersion") {
val version = if (Build.VERSION.SDK_INT >= 31) 30 else 28
super.attr(ns, name, resourceId, type, version)
} else {
super.attr(ns, name, resourceId, type, value)
super.attr(ns, name, resourceId, type, 28)
}
}
}

View file

@ -6,18 +6,28 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import com.aliucord.manager.installer.service.InstallService
import kotlinx.coroutines.delay
import java.io.File
fun Application.installApks(vararg apks: File) =
packageManager.packageInstaller.installApks(this, *apks)
fun Application.installApks(silent: Boolean = false, vararg apks: File) {
val packageInstaller = packageManager.packageInstaller
val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
if (Build.VERSION.SDK_INT >= 31) {
setInstallScenario(PackageManager.INSTALL_SCENARIO_FAST)
fun PackageInstaller.installApks(application: Application, vararg apks: File) {
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId = createSession(params)
val session = openSession(sessionId)
if (silent) {
setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED)
}
}
}
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)
apks.forEach { apk ->
session.openWrite(apk.name, 0, apk.length()).use {
@ -26,13 +36,13 @@ fun PackageInstaller.installApks(application: Application, vararg apks: File) {
}
}
val callbackIntent = Intent(application, InstallService::class.java)
val callbackIntent = Intent(this, InstallService::class.java)
@SuppressLint("UnspecifiedImmutableFlag")
val contentIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.getService(application, 0, callbackIntent, PendingIntent.FLAG_MUTABLE)
PendingIntent.getService(this, 0, callbackIntent, PendingIntent.FLAG_MUTABLE)
} else {
PendingIntent.getService(application, 0, callbackIntent, 0)
PendingIntent.getService(this, 0, callbackIntent, 0)
}
session.commit(contentIntent.intentSender)

View file

@ -409,12 +409,29 @@ class InstallViewModel(
}
step(InstallStep.SIGN_APK) {
// Align resources.arsc due to targeting api 30 for silent install
if (Build.VERSION.SDK_INT >= 31) {
for (file in apks) {
val bytes = ZipReader(file).use {
if (it.entryNames.contains("resources.arsc")) {
it.openEntry("resources.arsc")?.read()
} else {
null
}
} ?: continue
ZipWriter(file, true).use {
it.deleteEntry("resources.arsc", true)
it.writeEntry("resources.arsc", bytes, ZipCompression.NONE, 4096)
}
}
}
apks.forEach(Signer::signApk)
}
step(InstallStep.INSTALL_APK) {
application.packageManager.packageInstaller
.installApks(application, *apks)
application.installApks(silent = !preferences.devMode, *apks)
}
patchedDir.deleteRecursively()
@ -595,12 +612,27 @@ class InstallViewModel(
}
step(InstallStep.SIGN_APK) {
// Align resources.arsc due to targeting api 30 for silent install
if (Build.VERSION.SDK_INT >= 31) {
val bytes = ZipReader(baseApkFile).use {
if (it.entryNames.contains("resources.arsc")) {
it.openEntry("resources.arsc")?.read()
} else {
null
}
}
ZipWriter(baseApkFile, true).use {
it.deleteEntry("resources.arsc", true)
it.writeEntry("resources.arsc", bytes, ZipCompression.NONE, 4096)
}
}
Signer.signApk(baseApkFile)
}
step(InstallStep.INSTALL_APK) {
application.packageManager.packageInstaller
.installApks(application, baseApkFile)
application.installApks(silent = !preferences.devMode, baseApkFile)
}
patchedDir.deleteRecursively()

View file

@ -41,18 +41,14 @@ class UpdaterViewModel(
viewModelScope.launch {
isWorking = true
application.externalCacheDir!!.resolve("manager.apk").apply {
delete()
application.externalCacheDir!!.resolve("manager.apk").also {
it.delete()
downloadManager.download(url, this)
application.installApks(this)
delay(10000)
downloadManager.download(url, it)
application.installApks(silent = true, it)
showDialog = false
delete()
it.delete()
}
isWorking = false
}
}