24

PackageInstaller (https://developer.android.com/reference/android/content/pm/PackageInstaller.html) seems to have been added starting in API 21 (Lollipop), however I have not found any solid code examples on how to install an APK via this API. Any code help would be appreciated.

I’m investigating COSU/Kiosk apps for Android M Preview and was trying to implement the new feature "Silent install and uninstall of apps by Device Owner” (https://developer.android.com/preview/api-overview.html#afw) via the PackageInstaller API.

Found these, but not helpful: How to install/update/remove APK using "PackageInstaller" class in Android L? What's "PackageInstaller" class on Lollipop, and how to use it?

Did not find any Android sample apps either.

Thanks in advance.

Community
  • 1
  • 1
ken604
  • 281
  • 1
  • 2
  • 7
  • possible duplicate of [How to install/update/remove APK using "PackageInstaller" class in Android L?](http://stackoverflow.com/questions/26884956/how-to-install-update-remove-apk-using-packageinstaller-class-in-android-l) – Kenneth Sep 09 '15 at 07:19
  • As @Kenneth mentions, it seems an [answer](http://stackoverflow.com/a/27520814/2050) provides the searched sample code. – Eric Platon Mar 16 '16 at 01:49

2 Answers2

13

This is possible from Android 6.0 and up.

  • Make your app the Device owner.

Once your app gets the Device owner permission, we can install, uninstall and update silently without any user intervention.

public static boolean installPackage(Context context, InputStream in, String packageName)
        throws IOException {
    PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
    PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
            PackageInstaller.SessionParams.MODE_FULL_INSTALL);
    params.setAppPackageName(packageName);
    // set params
    int sessionId = packageInstaller.createSession(params);
    PackageInstaller.Session session = packageInstaller.openSession(sessionId);
    OutputStream out = session.openWrite("COSU", 0, -1);
    byte[] buffer = new byte[65536];
    int c;
    while ((c = in.read(buffer)) != -1) {
        out.write(buffer, 0, c);
    }
    session.fsync(out);
    in.close();
    out.close();

    session.commit(createIntentSender(context, sessionId));
    return true;
}


private static IntentSender createIntentSender(Context context, int sessionId) {
        PendingIntent pendingIntent = PendingIntent.getBroadcast(
                context,
                sessionId,
                new Intent(ACTION_INSTALL_COMPLETE),
                0);
        return pendingIntent.getIntentSender();
    }

Uninstall:

String appPackage = "com.your.app.package";
Intent intent = new Intent(getActivity(), getActivity().getClass());
PendingIntent sender = PendingIntent.getActivity(getActivity(), 0, intent, 0);
PackageInstaller mPackageInstaller = getActivity().getPackageManager().getPackageInstaller();
mPackageInstaller.uninstall(appPackage, sender.getIntentSender());

Complete device owner demo app in this repo.

amalBit
  • 12,041
  • 6
  • 77
  • 94
4

Figured it out, here's the code:

    try
    {
        PackageInstaller pi = app.getPackageManager().getPackageInstaller();
        int sessId          = pi.createSession(new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));

        PackageInstaller.Session session = pi.openSession(sessId);

        // .. write updated APK file to out


        long sizeBytes = 0;
        final File file = new File(filepathApk);
        if (file.isFile())
        {
            sizeBytes = file.length();
        }

        InputStream in = null;
        OutputStream out = null;

        in = new FileInputStream(filepathApk);
        out = session.openWrite("my_app_session", 0, sizeBytes);

        int total = 0;
        byte[] buffer = new byte[65536];
        int c;
        while ((c = in.read(buffer)) != -1)
        {
            total += c;
            out.write(buffer, 0, c);
        }
        session.fsync(out);
        in.close();
        out.close();

        System.out.println("InstallApkViaPackageInstaller - Success: streamed apk " + total + " bytes");

        // fake intent
        Context app = this;
        Intent intent = new Intent(app, AlarmReceiver.class);
        PendingIntent alarmtest = PendingIntent.getBroadcast(app,
                1337111117, intent, PendingIntent.FLAG_UPDATE_CURRENT);

        session.commit(alarmtest.getIntentSender());
        session.close();

    }
    catch (Exception ex)
    {
        ex.printStackTrace();
    }
prototyp
  • 570
  • 6
  • 20
ken604
  • 281
  • 1
  • 2
  • 7