Android PackageInstaller, re-open the app after it updates itself

7.1k views Asked by At

I'm developing an app that runs as Device Owner, and I want to build an automatic updater inside it.

To do it I use the PackageInstaller, as I have the privileges to use it due to my Device owner position.

private void installPackage(InputStream inputStream)
        throws IOException {
    notifyLog("Inizio aggiornamento...");
    PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
    int sessionId = packageInstaller.createSession(new PackageInstaller
            .SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL));
    PackageInstaller.Session session = packageInstaller.openSession(sessionId);

    long sizeBytes = 0;

    OutputStream out = null;
    out = session.openWrite("my_app_session", 0, sizeBytes);

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

    session.commit(createIntentSender(sessionId));
}

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

The update goes right, but the problem is that it doesn't re-open the app itself after the update, even if I set an IntentSender to broadcast the action LauncherReceiver.START_INTENT to the new app instance (that will bring it on to start).

Here it is my Receiver:

public class LauncherReceiver extends BroadcastReceiver {

    public static final String START_INTENT = "com.aaa.aaa.action.START";

    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("CALL RECEIVER!!");
        Intent startIntent = new Intent(context, StartActivity.class);
        startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
        context.startActivity(startIntent);
    }
}

And it is registered in my manifest:

    <receiver android:name=".receivers.LauncherReceiver" android:enabled="true" android:exported="true">
        <intent-filter>
            <action android:name="com.aaa.aaa.action.START"></action>
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </receiver>

If I call it by CLI it works:

am broadcast -a com.package.appname.action.START 

So the receiver works but for some reason it doesn't work from the Package Installer session commit. The app close itself due to the upgrade but does't open again.

If I change the createIntentSender to this:

private IntentSender createIntentSender(int sessionId) {
    Intent intent = new Intent(Intent.ACTION_DIAL);
    intent.setData(Uri.parse("tel:0123456789"));
    PendingIntent pendingIntent = PendingIntent.getActivity(context,sessionId,intent,0);
    return pendingIntent.getIntentSender();
}

it actually opens the phone service. So I think the problem reside in the upgrade lifecycle, as the app is not ready when the broadcast action is spawned.

Moreover, I made another try and I created a side app that does nothing but call the broadcast action to my main app, so I can call this side app and with this "double step" it can actually re-open the just updated app. The problem is that I have to install two apps =/

Can anybody help me? Is there a way to re-open the just updated app?

1

There are 1 answers

5
David Wasser On BEST ANSWER

Starting from about Android 5 (I don't know the exact API level), Android will send a broadcast Intent with ACTION="android.intent.action.MY_PACKAGE_REPLACED" after your app is updated. Just add

        <intent-filter>
            <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
        </intent-filter>

to your <receiver> declaration and you should be able to listen for this and restart your app in onReceive().