Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

APK installation programmatically on Marshmallow

In one of my use case the application in the beginning contacts server and downloads the update of the same application.

For downloading I am using DownloadManager class of Android. Then using below code it tries to create app installer intent in onReceive() i.e. after the APK is downloaded successfully.

@Override
public void onReceive(Context context, Intent intent) {

    //check if the broadcast message is for our Enqueued download
    long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
    if (downloadReference == referenceId) {
        try {
            Log.v("", "Downloading of the new app version complete");

            String filepath = Environment.getExternalStorageDirectory() + "/" +
                    Environment.DIRECTORY_DOWNLOADS + "/" + mLatestVersionFileName;

            //start the installation of the latest version
            Uri uri = downloadManager.getUriForDownloadedFile(downloadReference);

            //downloadManager.getUriForDownloadedFile(downloadReference)
            Uri fileLoc = Uri.fromFile(new File(filepath));

            Intent promptInstall = new Intent(Intent.ACTION_VIEW);
            promptInstall.setDataAndType(uri, "application/vnd.android.package-archive");
            promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(promptInstall);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

The code works fine for Pre-Marshmallow devices and user gets the screen to install APK.

This does not works on Marshmallow device.

I am getting following exception on Marshmallow:

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=content://downloads/my_downloads/287 typ=application/vnd.android.package-archive flg=0x10000000 }

I have tried following things:

  1. Using the exact PackageInstaller of Marshmallow (com.google.android.packageinstaller/com.android.packageinstaller.PackageInstallerActivity) component name as part of Intent.
  2. Passing fileLoc instead of uri.
promptInstall.setDataAndType(uri, "application/vnd.android.package-archive");

This results in 'Parse error'.

Ideally intents are resolved by Android OS. I guess its not a big issue and I maybe missing something while creating Intent.

like image 894
Imran Solanki - GSLab Avatar asked May 16 '16 05:05

Imran Solanki - GSLab


2 Answers

Try this out

 public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
                    long downloadId = intent.getLongExtra(
                            DownloadManager.EXTRA_DOWNLOAD_ID, 0);
                    Query query = new Query();
                    query.setFilterById(enqueue);
                    Cursor c = dm.query(query);
                    if (c.moveToFirst()) {
                        int columnIndex = c
                                .getColumnIndex(DownloadManager.COLUMN_STATUS);
                        if (DownloadManager.STATUS_SUCCESSFUL == c
                                .getInt(columnIndex)) {

                            ImageView view = (ImageView) findViewById(R.id.imageView1);
                            String uriString = c
                                    .getString(c
                                            .getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));

                             //start the installation of the latest version
                            Uri uri = Uri.parse(uriString); 
                            Intent promptInstall = new Intent(Intent.ACTION_VIEW);
                            promptInstall.setDataAndType(uri, "application/vnd.android.package-archive");
                            promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            mContext.startActivity(promptInstall);
                        }
                    }
                }
            }
like image 143
Zeba Avatar answered Oct 19 '22 17:10

Zeba


Can you try this :

@Override
public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

        if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {

            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(yourDownloadID);
      DownloadManager dm = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);
            Cursor downloadResult = dm.query(query);

            if (downloadResult.moveToFirst()) {
                int statusColumnIndex = downloadResult.getColumnIndex(DownloadManager.COLUMN_STATUS);
                int status = downloadResult.getInt(statusColumnIndex);

                if (status == DownloadManager.STATUS_SUCCESSFUL) {
                    //download completed successfully
                    int localFileNameId = downloadResult.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);

                    String downloadPathFile = downloadResult.getString(localFileNameId);

       Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setDataAndType(Uri.fromFile(new File(downloadPathFile)), "application/vnd.android.package-archive");
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
}
like image 30
Vivek_Neel Avatar answered Oct 19 '22 17:10

Vivek_Neel