Reputation: 1329
I am building AOSP for Android version 8.1 and I want to implement my own app store and hence need to install apks onto the system.
The only way I've seen so far is using something like the following:
val intent = Intent(Intent.ACTION_VIEW)
val file = File(Environment.getExternalStorageDirectory().toString() + "/APKs/" + "spotify.apk")
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
However, this requests confirmation before each package is installed from the user. Is there any other way to achieve this without user confirmation if the app is a system app built into the image? Also what is the installation effectively doing in the background? Just moving the APK file to /data/app
or what exactly happens?
Upvotes: 1
Views: 2186
Reputation: 1329
I solved it like so:
Prerequisite:
Your APK needs to be signed by system as correctly pointed out earlier. One way to achieve that is building the AOSP image yourself and adding the source code into the build.
Code:
Once installed as a system app, you can use the package manager methods to install and uninstall an APK as following:
Install:
public boolean install(final String apkPath, final Context context) {
Log.d(TAG, "Installing apk at " + apkPath);
try {
final Uri apkUri = Uri.fromFile(new File(apkPath));
final String installerPackageName = "MyInstaller";
context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
Uninstall:
public boolean uninstall(final String packageName, final Context context) {
Log.d(TAG, "Uninstalling package " + packageName);
try {
context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
To have a callback once your APK is installed/uninstalled you can use this:
/**
* Callback after a package was installed be it success or failure.
*/
private class InstallObserver implements IPackageInstallObserver {
@Override
public void packageInstalled(String packageName, int returnCode) throws RemoteException {
if (packageName != null) {
Log.d(TAG, "Successfully installed package " + packageName);
callback.onAppInstalled(true, packageName);
} else {
Log.e(TAG, "Failed to install package.");
callback.onAppInstalled(false, null);
}
}
@Override
public IBinder asBinder() {
return null;
}
}
/**
* Callback after a package was deleted be it success or failure.
*/
private class DeleteObserver implements IPackageDeleteObserver {
@Override
public void packageDeleted(String packageName, int returnCode) throws RemoteException {
if (packageName != null) {
Log.d(TAG, "Successfully uninstalled package " + packageName);
callback.onAppUninstalled(true, packageName);
} else {
Log.e(TAG, "Failed to uninstall package.");
callback.onAppUninstalled(false, null);
}
}
@Override
public IBinder asBinder() {
return null;
}
}
/**
* Callback to give the flow back to the calling class.
*/
public interface InstallerCallback {
void onAppInstalled(final boolean success, final String packageName);
void onAppUninstalled(final boolean success, final String packageName);
}
Upvotes: 1
Reputation: 2795
Take a look runInstall()
method
Required permission:
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
Upvotes: 1