8

I am trying to create a mechanism for an app to update itself by downloading and installing a later APK from within the app.

I have an APK located on a server which installs fine if I simply navigate to the URI then open the .apk file. The problem comes when I try to install it programmatically. I get "Parse Error - There was a problem while parsing the package"

The target phone allows install from unknown sources and within AndroidManifest.xml I request these permissions:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.REQUEST_WRITE_PERMISSION"/>

The code to perform the update has been taken from another thread here on StackOverflow and changed slightly to suit my particular situation.

public class UpdateApp extends AsyncTask<String,Void,Void> {
    private Context context;
    public void setContext(Context contextf){
        context = contextf;
    }

    @Override
    protected Void doInBackground(String... arg0) {
        try {
            URL url = new URL(arg0[0]);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setDoOutput(true);
            conn.connect();

            File file = context.getCacheDir();
            file.mkdirs();
            File outputFile = new File(file, "update.apk");
            if(outputFile.exists()){
                outputFile.delete();
            }
            FileOutputStream fos = new FileOutputStream(outputFile);

            InputStream is = conn.getInputStream();

            byte[] buffer = new byte[1024];
            int len1 = 0;
            while ((len1 = is.read(buffer)) != -1) {
                fos.write(buffer, 0, len1);
            }
            fos.close();
            is.close();

            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);


        } catch (Throwable ex) {
            Toast.makeText(context, ex.toString(), Toast.LENGTH_LONG).show();
        }
        return null;
    }
}

What can I try in order to understand why the APK is generating an error when installed from within the code but installs without issue when downloaded from the server?

The app is being built for API 23 although it will be required to work with API 24 once complete.

İan Boddison
  • 357
  • 2
  • 11
  • how many times "UpdateApp" asynctask is running? Since the file name is same everytime, it might happen that the file is being downloaded multiple time and is not valid. Try appending `system.getcurrenttimemillis()` – Rahul Oct 09 '18 at 14:11
  • Thanks for the suggestion but that isn't the issue. "UpdateApp" only runs once per invocation of the app but, of course, there could have been previous files left over. I've changed the code to `File outputFile = new File(file, "update" + System.currentTimeMillis() + ".apk");` and that has not changed the behaviour. – İan Boddison Oct 09 '18 at 14:37

2 Answers2

6

You will have to make your cached apk file world-readable.

After is.close();

put

outputFile.setReadable(true, false);

Rahul
  • 4,699
  • 5
  • 26
  • 38
1

This works for me on Android 8

startActivity(Intent(Intent.ACTION_VIEW).apply {
    type = "application/vnd.android.package-archive"
    data = FileProvider.getUriForFile(applicationContext, "$packageName.fileprovider", file)
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
})
Vlad
  • 7,997
  • 3
  • 56
  • 43