Install Android system app, silent update without

2020-06-22 08:22发布

问题:

I am trying to get my app to download an update from an ftp site, in the form of a new version of the apk. After download the apk should be installed silently, without any confirmation from a user. I have the download part under control. I can also do this with confirmation from the user. The problem is the silent update part.

From what I can tell the only way to do this is by installing the app as a system app. This is where I need some help.

I have tried alot of things. The most success I have had is the following:

  1. Rooting the device.
  2. Adding *android:sharedUserId="android.uid.system" to the manifest.
  3. Adding the following permissions to the manifest:

    android.permission.ACCESS_SUPERUSER and android.permission.INSTALL_PACKAGES

  4. Signing the apk with Android Studio->Build->Generate Signed APK... using a signature generated like this:

    ./keytool-importkeypair -k google_certificate.keystore -p android -pk8 platform.pk8 -cert platform.x509.pem -alias platform

where I got the pk8 and pem files from the Android source mirror on GitHub.

  1. Moving the signed apk to system/app on the device and clicking install on it.

The first thing I get is a huge list of permissions that the app is requesting which I never did. So I guess this is the permissions a system app has, so far so good :)

The immediately after I get the message:

App not installed.

Google could not tell why this error occures, so I am asking here.

Am I on the right path?

Why was the app not installed?

回答1:

So after a couple of years I got to that problem again, and I managed to solve it. So the most important part is rooting the phone properly: This was done with the SuperSU app.

After downloading the .apk file, a method similar to the following is used to install the update:

private Boolean Install(String path)
{
    File file = new File(path);
    if(file.exists()){
        try {
            Process proc = Runtime.getRuntime().exec(new String[]{"su","-c","pm install -r -d " + path});
            proc.waitFor();
            BufferedReader input = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
            String line;
            Boolean hasError = false;
            while ((line = input.readLine()) != null) {
                if(line.contains("Failure")){
                    hasError = true;
                }
            }
            if(proc.exitValue() != 0 || hasError){
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    return false;
}


回答2:

If you device is rooted you can execute this command:

pm install com.example.myapp

How to execute this command?
There are two ways:

Way #1:
Use RootTools library:

Command command = new Command(0, "pm install com.example.myapp") {
            @Override
            public void commandCompleted(int arg0, int arg1) {
                Log.i(TAG, "App installation is completed");
            }

            @Override
            public void commandOutput(int arg0, String line) {

            }

            @Override
            public void commandTerminated(int arg0, String arg1) {

            }
}
RootTools.getShell(true).add(command);

Way #2:
This way not requires libraries, but it's harder than first way.

//Start a new process with root privileges
Process process = Runtime.getRuntime().exec("su");
//Get OutputStream of su to write commands to su process
OutputStream out = process.getOutputStream();
//Your command
String cmd = "pm install com.example.myapp";
//Write the command to su process
out.write(cmd.getBytes());
//Flush the OutputStream
out.flush();
//Close the OutputStream
out.close();
//Wait until command
process.waitFor();
Log.i(TAG, "App installation is completed");