26

We are writing an Android app that shows ads on large screens. We have a backend where advertisers can select the ads, so they are updated almost instantly. Because there will be a lot of Android boxes running (plugged into HDMI screens), we should be able to update our software remotely.

This is the case:

Main app is running continuously (unless turned off) and the users never see anything Android related. We need an updater app that listens for updates and deletes the main apk, installs a new apk. While updating we will show an activity with "Updating, please wait", until the new main apk is installed and showing.

What we need:

We need help on how to implement the update mechanism without prompting the user on ROOTED DEVICE.

What we have:

The updater app is hooked into the boot received event, where a service starts (this service will listen for updates, which will be implemented by a colleague soon). The service can start an activity which will prompt the update info while updating.

In the updater activity

 try {
            Process proc = Runtime.getRuntime().exec(new String[]{"su", "pm install -r /mnt/sdcard/MYFOLDER/testAPK.apk"});
            stringBuilder.append(String.valueOf(proc.waitFor()));
            stringBuilder.append("\n");
        } catch (Exception e) {
            if (e instanceof IOException) {
                Log.d(TAG, "IOException");
            } else if (e instanceof InterruptedException) {
                Log.d(TAG, "InterruptedException");
            } else {
                e.printStackTrace();
            }
        }

The StringBuilder prints 11, but does the same if I give random unexisting command..

In the Manifest

<!-- Permission to start UpdaterService on boot -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

<!-- Install/delete permissions, only granted to system apps -->
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

The Install packages and delete packages are useless if I don't install my app as system app, am I correct?

Long story short, no installation of my test APK, and I have no idea how to solve this. Any help would be appreciated!

TomCB
  • 3,983
  • 9
  • 40
  • 66
  • 1
    if you do have the root access, put the updater app in /system/app/ and you will get the INSTALL_PACKAGES and DELETE_PACKAGES permission – nandeesh Nov 14 '14 at 09:05

2 Answers2

32

You can simply use adb install command to install/update APK silently. Sample code is below

public static void InstallAPK(String filename){
    File file = new File(filename); 
    if(file.exists()){
        try {   
            String command;
            command = "adb install -r " + filename;
            Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
            proc.waitFor();
        } catch (Exception e) {
        e.printStackTrace();
        }
     }
  }

OR

Please check http://paulononaka.wordpress.com/2011/07/02/how-to-install-a-application-in-background-on-android/

Palak
  • 2,165
  • 2
  • 21
  • 31
  • Where do you get the StringUtil class? – TomCB Nov 14 '14 at 09:12
  • 9
    It works, I used "pm install" instead of "adb install"! Thanks! – TomCB Nov 14 '14 at 10:02
  • 8
    Rooted Device Needed! Working like a charm, su commands need rooted device – Naveed Ahmad Oct 28 '16 at 09:50
  • But in production build tablet, How can i achieve this process? – DineshkumarBalan Dec 26 '16 at 07:00
  • @Palak Hey may I check with you regarding upon successfully installed, how can I access the version number of the apk? Also, how can I know if the latest apk has been installed for the application to perform an upgrade? –  Jun 08 '18 at 03:52
  • @user7691120adb: Answer for access the version of the apk "shell dumpsys package my.package | grep versionName" Regarding, how can I know if the latest apk has been installed for the application to perform an upgrade? - Please elaborate this – Palak Aug 11 '18 at 13:00
  • @Palak, I get the following error `"Cannot run program \"su\": error=13, Permission denied"`. – Zdravko Donev Feb 16 '19 at 09:22
  • @Zdravko Donev: First of all sorry for late response, please let me know about AndroidManifest.xml permission – Palak Feb 24 '19 at 19:23
  • So is it not possible to update an app without being rooted and without the install prompt – Ismail Iqbal Oct 08 '19 at 05:34
1
public void InstallAPK(String filename){

    Process process = Runtime.getRuntime().exec("su");
    OutputStream out = process.getOutputStream();
    String reinstall = "pm install -r " + filename + "\n";
    String am = "am start -a android.intent.action.MAIN -n yourPackage/.MainActivity";
    String cmd = reinstall + am + " &";
    out.write(cmd.getBytes());
    out.flush();
    out.close();
    process.waitFor();

}
  • Installation works but app do not get restated again.... Can you please tell me about this. the path to MainActivity is correct... – asad.qazi Mar 29 '22 at 11:21