diff --git a/platformtools/appmanager/src/androidMain/AndroidManifest.xml b/platformtools/appmanager/src/androidMain/AndroidManifest.xml
index 0e482ce..00622ed 100644
--- a/platformtools/appmanager/src/androidMain/AndroidManifest.xml
+++ b/platformtools/appmanager/src/androidMain/AndroidManifest.xml
@@ -5,7 +5,9 @@
-
+
Unit,
@@ -60,47 +68,119 @@ class ApkInstallerAndroid : AppInstaller {
if (!canRequestInstallPackages()) {
// 2) Request permission if necessary
requestInstallPackagesPermission()
+
+ // Optional: Wait for the user to grant permission
+ // You can implement logic to wait or inform the user
+ // and return or suspend until the permission is granted.
+ // For simplicity, we continue here.
}
- // 3) Recheck after the request: if still not allowed, exit
+ // 3) Re-check after the request: if still not allowed, exit
if (!canRequestInstallPackages()) {
onResult(false, "Installation from unknown sources is not allowed.")
return
}
- // 4) If permission is granted, proceed with the installation
try {
- val intent = Intent(Intent.ACTION_VIEW).apply {
- // Open the APK installer in a new task
- flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ // Use a suspended coroutine to wait for the installation result
+ suspendCancellableCoroutine { continuation ->
+ val packageManager = context.packageManager
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- // From Nougat (API 24), a FileProvider must be used
- // and permissions must be granted to read the URI
- val apkUri: Uri = FileProvider.getUriForFile(
- context, "${context.packageName}.fileprovider", appFile
- )
- setDataAndType(apkUri, "application/vnd.android.package-archive")
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- } else {
- // Before Nougat, Uri.fromFile can still be used
- setDataAndType(Uri.fromFile(appFile), "application/vnd.android.package-archive")
+ // Extract the package name from the APK file
+ val packageInfo = packageManager.getPackageArchiveInfo(appFile.absolutePath, 0)
+ val targetPackageName = packageInfo?.packageName
+
+ if (targetPackageName == null) {
+ onResult(false, "Failed to extract package name from APK file.")
+ continuation.resume(Unit)
+ return@suspendCancellableCoroutine
}
- }
- // Launch the intent
- context.startActivity(intent)
+ // Retrieve current package information for the target package before installation
+ val currentPackageInfo = try {
+ packageManager.getPackageInfo(targetPackageName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ null
+ }
+
+ // Retrieve the current versionCode or installation date
+ val currentVersionCode = currentPackageInfo?.versionCode ?: -1
+ val currentInstallTime = currentPackageInfo?.firstInstallTime ?: -1
+
+ // Create the intent to launch the APK installation
+ val installIntent = Intent(Intent.ACTION_VIEW).apply {
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ // From Nougat (API 24) onwards, use FileProvider
+ val apkUri: Uri = FileProvider.getUriForFile(
+ context, "${context.packageName}.fileprovider", appFile
+ )
+ setDataAndType(apkUri, "application/vnd.android.package-archive")
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ } else {
+ // Before Nougat, use Uri.fromFile
+ setDataAndType(Uri.fromFile(appFile), "application/vnd.android.package-archive")
+ }
+ }
+
+ try {
+ // Launch the installation intent
+ context.startActivity(installIntent)
- // Inform the caller that the installation has started
- onResult(true, "Installation started.")
+ // Wait for a short moment to allow the installation to start
+ Handler(Looper.getMainLooper()).postDelayed({
+ // Check if the app has been installed or updated
+ val updatedPackageInfo = try {
+ packageManager.getPackageInfo(targetPackageName, 0)
+ } catch (e: PackageManager.NameNotFoundException) {
+ null
+ }
+
+ if (updatedPackageInfo != null) {
+ // Compare the versionCode or installation date
+ val isUpdated = when {
+ // If the versionCode has increased, it's a successful update
+ updatedPackageInfo.versionCode > currentVersionCode -> true
+ // If the installation date has changed, it's a successful update
+ updatedPackageInfo.firstInstallTime > currentInstallTime -> true
+ // Otherwise, the installation/update failed
+ else -> false
+ }
+
+ if (isUpdated) {
+ onResult(true, "Installation/update successful.")
+ } else {
+ onResult(false, "The application was not updated.")
+ }
+ } else {
+ onResult(false, "The application was not installed.")
+ }
+
+ // Resume the coroutine
+ continuation.resume(Unit)
+ }, 5000) // Wait 5 seconds before checking
+
+ } catch (e: Exception) {
+ // Handle errors during the installation intent launch
+ onResult(false, "Failed to start installation: ${e.message}")
+ continuation.resumeWithException(e)
+ }
+
+ // Handle coroutine cancellation
+ continuation.invokeOnCancellation {
+ // Clean up if necessary
+ }
+ }
} catch (e: Exception) {
- // In case of an unexpected error
e.printStackTrace()
- onResult(false, "Failed to start installation: ${e.message}")
+ onResult(false, "Installation failed: ${e.message}")
}
}
+
+
/**
* Installs an APK file silently without user interaction.
*