diff --git a/core/mogo-core-utils/src/main/AndroidManifest.xml b/core/mogo-core-utils/src/main/AndroidManifest.xml
index 6f47c81c15..7e643df2d9 100644
--- a/core/mogo-core-utils/src/main/AndroidManifest.xml
+++ b/core/mogo-core-utils/src/main/AndroidManifest.xml
@@ -37,11 +37,14 @@
-
+
+
-
+
\ No newline at end of file
diff --git a/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/util/ApkInstaller.kt b/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/util/ApkInstaller.kt
index b4ba64e395..d962921066 100644
--- a/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/util/ApkInstaller.kt
+++ b/core/mogo-core-utils/src/main/java/com/mogo/eagle/core/utilcode/util/ApkInstaller.kt
@@ -1,32 +1,20 @@
package com.mogo.eagle.core.utilcode.util
-import android.annotation.*
-import android.app.PendingIntent
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentSender
-import android.content.pm.PackageInstaller
-import android.content.pm.PackageInstaller.Session
-import android.content.pm.PackageInstaller.SessionCallback
-import android.content.pm.PackageInstaller.SessionParams
+import android.app.*
+import android.content.*
+import android.content.pm.PackageInstaller.*
import android.os.*
-import android.util.Log
-import androidx.lifecycle.ProcessLifecycleOwner
-import androidx.lifecycle.lifecycleScope
-import kotlinx.coroutines.*
-import java.io.File
-import java.io.FileInputStream
-import java.io.InputStream
-import java.lang.ref.WeakReference
-import java.util.concurrent.ConcurrentHashMap
+import android.util.*
+import android.widget.*
+import androidx.appcompat.app.*
+import com.mogo.eagle.core.utilcode.util.ApkInstaller.Companion.INSTALL_CODE_INVALID
+import java.io.*
+
class ApkInstaller {
companion object {
- private const val TAG = "ApkInstaller"
-
const val INSTALL_CODE_INVALID = -2
@JvmStatic
@@ -46,118 +34,133 @@ class ApkInstaller {
block?.invoke(INSTALL_CODE_INVALID, msg)
return
}
- installApp(context, FileInputStream(apkFile), block)
- }
-
- @JvmStatic
- fun installApp(context: Context, input: InputStream, block: ((Int, String) -> Unit)?) {
- ProcessLifecycleOwner.get().lifecycleScope.launch(Dispatchers.IO) {
- var session: Session? = null
- try {
- val installer = context.packageManager.packageInstaller
- installer.registerSessionCallback(object : SessionCallback() {
- override fun onCreated(sessionId: Int) {
- Log.d(TAG, "onCreate: sessionId -> $sessionId")
- }
- override fun onBadgingChanged(sessionId: Int) {
- Log.d(TAG, "onBadgingChanged: sessionId -> $sessionId")
- }
-
- override fun onActiveChanged(sessionId: Int, active: Boolean) {
- Log.d(TAG, "onActiveChanged: sessionId -> $sessionId, active: $active")
- }
-
- override fun onProgressChanged(sessionId: Int, progress: Float) {
- Log.d(TAG, "onProgressChanged: sessionId -> $sessionId, process: $progress")
- }
-
- override fun onFinished(sessionId: Int, success: Boolean) {
- Log.d(TAG, "onFinished: sessionId -> $sessionId, success: $success")
- }
- }, Handler(Looper.getMainLooper()))
- val params = SessionParams(SessionParams.MODE_FULL_INSTALL)
- val sessionId = installer.createSession(params)
- session = installer.openSession(sessionId)
- val output = session.openWrite("install.apk", 0, -1)
- output.use { o ->
- input.copyTo(o)
- }
- withContext(Dispatchers.Main) {
- session.commit(createIntent(context, sessionId))
- }
- block?.also {
- AppInstallReceiver.listeners[sessionId] = WeakReference(it)
- }
- } catch (t: Throwable) {
- block?.invoke(-2, t.message ?: "未知异常")
- session?.close()
- }
- }
- }
-
- @SuppressLint("UnspecifiedImmutableFlag")
- private fun createIntent(context: Context, sessionId: Int): IntentSender {
- val intent = Intent(context, AppInstallReceiver::class.java)
- intent.action = AppInstallReceiver.INTENT_ACTION_SESSION_INSTALL
- intent.putExtra(AppInstallReceiver.INTENT_EXTRA_SESSION_ID, sessionId)
- return PendingIntent.getBroadcast(context, sessionId, intent, PendingIntent.FLAG_UPDATE_CURRENT).intentSender
+ val intent = Intent(context, InstallApkSessionApi::class.java)
+ intent.putExtra("APK_FILE_PATH", apkFile.absolutePath)
+ block?.also { InstallApkSessionApi.listener = it }
+ context.startActivity(intent)
}
}
}
-class AppInstallReceiver: BroadcastReceiver() {
+
+class InstallApkSessionApi: AppCompatActivity() {
companion object {
const val TAG = "AppInstallReceiver"
const val INTENT_ACTION_SESSION_INSTALL = "com.mogo.launcher.f.action.SESSION_API_PACKAGE_INSTALLED"
- const val INTENT_EXTRA_SESSION_ID = "intent.extra.session_id"
- val listeners by lazy { ConcurrentHashMap Unit)>>() }
+ @Volatile
+ var listener: ((Int, String) -> Unit)? = null
}
- override fun onReceive(context: Context?, intent: Intent?) {
- val c = context ?: return
- val i = intent ?: return
- val a = i.action ?: return
- if (a == INTENT_ACTION_SESSION_INSTALL) {
- val e = i.extras ?: return
- val sessionId = e.getInt(INTENT_EXTRA_SESSION_ID, 0)
- Log.d(TAG, "action -> $a, sessionId: $sessionId")
- when(val status = e.getInt(PackageInstaller.EXTRA_STATUS)) {
- PackageInstaller.STATUS_PENDING_USER_ACTION -> {
- val confirm = e.get(Intent.EXTRA_INTENT) as? Intent
- if (confirm != null) {
- Log.d(TAG, "confirm -> status:$status, sessionID: $sessionId")
- val activityInfo = c.packageManager.resolveActivity(confirm, 0)?.activityInfo
- if (activityInfo != null) {
- c.startActivity(confirm)
- } else {
- notifyListeners(status, "action: ${confirm.action} 不存在")
- }
- } else {
- notifyListeners(status, "需要用户确认的应用程序不存在")
- }
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ Log.d(TAG, "--- InstallApkSessionApi -- onCreate --")
+ val apkPath = intent.extras?.getString("APK_FILE_PATH")
+ if (apkPath.isNullOrEmpty()) {
+ Log.e(TAG, "--- InstallApkSessionApi --:apk path is null or empty.")
+ finish()
+ return
+ }
+ val file = File(apkPath)
+ if (!file.exists()) {
+ Log.e(TAG, "--- InstallApkSessionApi --:apk is not exist.")
+ finish()
+ return
+ }
+ var session: Session? = null
+ val input = FileInputStream(file)
+ try {
+ val installer = packageManager.packageInstaller
+ installer.registerSessionCallback(object : SessionCallback() {
+ override fun onCreated(sessionId: Int) {
+ Log.d(TAG, "onCreate: sessionId -> $sessionId")
}
- PackageInstaller.STATUS_FAILURE_ABORTED,
- PackageInstaller.STATUS_FAILURE,
- PackageInstaller.STATUS_FAILURE_BLOCKED,
- PackageInstaller.STATUS_FAILURE_CONFLICT,
- PackageInstaller.STATUS_FAILURE_INCOMPATIBLE,
- PackageInstaller.STATUS_FAILURE_INVALID,
- PackageInstaller.STATUS_FAILURE_STORAGE -> {
- Log.d(TAG, "failed -> status:$status, sessionID: $sessionId")
- notifyListeners(status, "安装失败: $status")
+ override fun onBadgingChanged(sessionId: Int) {
+ Log.d(TAG, "onBadgingChanged: sessionId -> $sessionId")
+ }
+
+ override fun onActiveChanged(sessionId: Int, active: Boolean) {
+ Log.d(TAG, "onActiveChanged: sessionId -> $sessionId, active: $active")
+ }
+
+ override fun onProgressChanged(sessionId: Int, progress: Float) {
+ Log.d(TAG, "onProgressChanged: sessionId -> $sessionId, process: $progress")
+ }
+
+ override fun onFinished(sessionId: Int, success: Boolean) {
+ Log.d(TAG, "onFinished: sessionId -> $sessionId, success: $success")
+ }
+ }, Handler(Looper.getMainLooper()))
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL)
+ val sessionId = installer.createSession(params)
+ session = installer.openSession(sessionId)
+ val output = session.openWrite("install.apk", 0, -1)
+ output.use { o ->
+ input.copyTo(o)
+ }
+ val intent = Intent(this, InstallApkSessionApi::class.java)
+ intent.action = INTENT_ACTION_SESSION_INSTALL
+ val pendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
+ session.commit(pendingIntent.intentSender)
+ } catch (t: IOException) {
+ Log.e(TAG, "--- InstallApkSessionApi --:exception 1:${t.message}")
+ listener?.invoke(INSTALL_CODE_INVALID, t.message ?: "未知异常")
+ session?.close()
+ } catch (t: RuntimeException) {
+ Log.e(TAG, "--- InstallApkSessionApi --:exception 2:${t.message}")
+ listener?.invoke(INSTALL_CODE_INVALID, t.message ?: "未知异常2")
+ session?.abandon()
+ } finally {
+ try {
+ input.close()
+ } catch (t: Throwable) {
+ t.printStackTrace()
+ }
+ }
+ }
+ override fun onNewIntent(intent: Intent?) {
+ super.onNewIntent(intent)
+ Log.i(TAG, "--- InstallApkSessionApi -- onNewIntent --")
+ val i = intent ?: return
+ val extras = i.extras
+ if (INTENT_ACTION_SESSION_INSTALL == i.action) {
+ Log.i(TAG, "--- InstallApkSessionApi -- action: ${ i.action } --")
+ val status = extras?.getInt(EXTRA_STATUS)
+ Log.i(TAG, "--- InstallApkSessionApi -- action: ${ i.action } - status: $status --")
+ val message = extras?.getString(EXTRA_STATUS_MESSAGE)
+ when (status) {
+ STATUS_PENDING_USER_ACTION -> {
+ Log.i(TAG, "--- InstallApkSessionApi -- confirm --")
+ // This test app isn't privileged, so the user has to confirm the install.
+ val confirmIntent = extras[Intent.EXTRA_INTENT] as? Intent
+ startActivity(confirmIntent)
+ }
+ STATUS_SUCCESS -> {
+ Log.i(TAG, "--- InstallApkSessionApi -- install success --")
+ Toast.makeText(this, "Install succeeded!", Toast.LENGTH_SHORT).show()
+ listener?.invoke(STATUS_SUCCESS, "安装成功")
+ finish()
+ listener = null
+ }
+ STATUS_FAILURE,
+ STATUS_FAILURE_ABORTED,
+ STATUS_FAILURE_BLOCKED,
+ STATUS_FAILURE_CONFLICT,
+ STATUS_FAILURE_INCOMPATIBLE,
+ STATUS_FAILURE_INVALID,
+ STATUS_FAILURE_STORAGE -> {
+ Toast.makeText(this, "Install failed! $status, $message", Toast.LENGTH_SHORT).show()
+ listener?.invoke(status, "安装失败")
+ finish()
+ listener = null
}
else -> {
- Log.d(TAG, "other status:$status, sessionID: $sessionId")
- notifyListeners(status, "未知状态")
+ status?.also { listener?.invoke(it, "未知状态") }
+ Toast.makeText(this, "Unrecognized status received from installer: $status", Toast.LENGTH_SHORT).show()
+ finish()
+ listener = null
}
}
}
}
-
- private fun notifyListeners(code: Int, reason: String) {
- listeners.values.forEach {
- it.get()?.invoke(code, reason)
- }
- }
-}
\ No newline at end of file
+}