feat: silent updating (#51)
Co-authored-by: Diamond <33725716+DiamondMiner88@users.noreply.github.com>
This commit is contained in:
parent
f44cae2311
commit
c18ffbabea
5 changed files with 68 additions and 26 deletions
|
|
@ -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" />
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue