SimpleInstaller
Overview
SimpleInstaller is an Android library which provides easy to use abstraction over Android packages install and uninstall functionality leveraging Kotlin coroutines.
It supports Android versions starting from 4.1 Jelly Bean. Package installer provides a Kotlin SharedFlow property which can be collected for installation progress updates. Split packages installation is also supported (note that this is only available on Android versions starting from 5.0 Lollipop).
SimpleInstaller was developed with background execution in mind. You can launch an install or uninstall session from background, for example, while foreground service is running and your application was removed from recents. The way it works is that the user is shown a high-priority notification which launches a standard Android confirmation by clicking on it, or full-screen intent with confirmation (depends on firmware).
Gradle dependencies
All versions are available here.
implementation("io.github.solrudev:simpleinstaller:x.y.z")
Replace "x.y.z" with the latest version.
Usage
First, you need to initialize SimpleInstaller. To do this, add the following line to your Application class' onCreate()
method:
SimpleInstaller.initialize(this)
Optionally, you can provide an icon for SimpleInstaller notifications:
SimpleInstaller.initialize(this, R.drawable.your_notification_icon)
Installation
There are two methods for installation, each of them receives either Uri
, AssetFileDescriptor
, File
or custom ApkSource
. URIs must have file:
or content:
scheme.
suspend fun PackageInstaller.installPackage(apkFile): InstallResult
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
suspend fun PackageInstaller.installSplitPackage(vararg apkFiles): InstallResult
These methods return an InstallResult
object, which can be either Success
or Failure
. Failure
object may contain a cause of failure in its cause
property.
They also have non-suspend variants which accept PackageInstallerCallback
callback as a second parameter.
fun PackageInstaller.installPackage(apkFile, callback: PackageInstallerCallback)
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun PackageInstaller.installSplitPackage(vararg apkFiles, callback: PackageInstallerCallback)
Install permission
On Oreo and higher PackageInstaller
sets an install reason PackageManager.INSTALL_REASON_USER
, so on first install there should be a prompt from Android to allow installation. But relying on this is not recommended, because your app will be restarted if user chooses Always allow, so the result and progress won't be received anymore (this is the case for MIUI). There's InstallPermissionContract
in activityresult
package which you should use to request user to turn on install from unknown sources for your app.
In your Activity:
val requestInstallPermissionLauncher = registerForActivityResult(InstallPermissionContract()) { booleanResult ->
if (booleanResult) { /* do something */ }
}
...
requestInstallPermissionLauncher.launch(Unit)
ApkSource
SimpleInstaller provides an abstract ApkSource
class with the following public interface:
val progress: SharedFlow<ProgressData>
abstract val length: Long
abstract fun openInputStream(): InputStream?
abstract suspend fun getUri(): Uri
open fun clearTempFiles()
SimpleInstaller has implementations for Uri
, AssetFileDescriptor
and File
. You can provide your own implementation and pass it to PackageInstaller.installPackage
or PackageInstaller.installSplitPackage
.
Uninstallation
suspend fun PackageUninstaller.uninstallPackage(packageName: String): Boolean
Returns true if uninstall succeeded, false otherwise.
This method also has non-suspend variant which accepts PackageUninstallerCallback
callback as a second parameter.
fun PackageUninstaller.uninstallPackage(packageName: String, callback: PackageUninstallerCallback)
Java interoperability
SimpleInstaller.initialize()
is available statically and has a separate overload with notification icon resource ID as a parameter.
There are static methods in PackageInstaller
and PackageUninstaller
which accept callbacks as a second parameter. They are wrappers around Kotlin suspend functions. Callbacks have the following interfaces:
interface PackageInstallerCallback {
fun onSuccess()
fun onFailure(cause: InstallFailureCause?)
fun onException(exception: Throwable)
fun onCanceled()
fun onProgressChanged(progress: ProgressData)
}
interface PackageUninstallerCallback {
fun onFinished(success: Boolean)
fun onException(exception: Throwable)
fun onCanceled()
}
hasActiveSession
property can be accessed statically:
PackageInstaller.getHasActiveSession()
PackageUninstaller.getHasActiveSession()
Current install/uninstall session can be canceled through a static cancel()
method.
Sample app
There's a simple sample app available. It can install chosen APK file and uninstall an application selected from the installed apps list. Go here to see sources.