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

View file

@ -6,6 +6,7 @@
package com.aliucord.manager.installer.util package com.aliucord.manager.installer.util
import android.Manifest import android.Manifest
import android.os.Build
import pxb.android.axml.* import pxb.android.axml.*
object ManifestPatcher { object ManifestPatcher {
@ -67,10 +68,12 @@ object ManifestPatcher {
"uses-sdk" -> object : NodeVisitor(nv) { "uses-sdk" -> object : NodeVisitor(nv) {
override fun attr(ns: String?, name: String?, resourceId: Int, type: Int, value: Any?) { 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, 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.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import com.aliucord.manager.installer.service.InstallService import com.aliucord.manager.installer.service.InstallService
import kotlinx.coroutines.delay
import java.io.File import java.io.File
fun Application.installApks(vararg apks: File) = fun Application.installApks(silent: Boolean = false, vararg apks: File) {
packageManager.packageInstaller.installApks(this, *apks) 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) { if (silent) {
val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED)
val sessionId = createSession(params) }
val session = openSession(sessionId) }
}
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)
apks.forEach { apk -> apks.forEach { apk ->
session.openWrite(apk.name, 0, apk.length()).use { 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") @SuppressLint("UnspecifiedImmutableFlag")
val contentIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 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 { } else {
PendingIntent.getService(application, 0, callbackIntent, 0) PendingIntent.getService(this, 0, callbackIntent, 0)
} }
session.commit(contentIntent.intentSender) session.commit(contentIntent.intentSender)

View file

@ -409,12 +409,29 @@ class InstallViewModel(
} }
step(InstallStep.SIGN_APK) { 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) apks.forEach(Signer::signApk)
} }
step(InstallStep.INSTALL_APK) { step(InstallStep.INSTALL_APK) {
application.packageManager.packageInstaller application.installApks(silent = !preferences.devMode, *apks)
.installApks(application, *apks)
} }
patchedDir.deleteRecursively() patchedDir.deleteRecursively()
@ -595,12 +612,27 @@ class InstallViewModel(
} }
step(InstallStep.SIGN_APK) { 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) Signer.signApk(baseApkFile)
} }
step(InstallStep.INSTALL_APK) { step(InstallStep.INSTALL_APK) {
application.packageManager.packageInstaller application.installApks(silent = !preferences.devMode, baseApkFile)
.installApks(application, baseApkFile)
} }
patchedDir.deleteRecursively() patchedDir.deleteRecursively()

View file

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