Android update app across app restarts using DownloadManager (avoid downloading multiple times)

656 views Asked by At

Iam trying to update my app by downloading the apk using download manager. I have registered broadcast receiver to listen to DownloadManager.ACTION_DOWNLOAD_COMPLETE in MainActivity and open the apk in onReceive method. Following is the code:

public class MainActivity extends CordovaActivity {
private long downloadReference;
private DownloadManager downloadManager;
private IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    registerReceiver(downloadReceiver, intentFilter);

}

public void updateApp(String url) {
    //start downloading the file using the download manager
    downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    Uri Download_Uri = Uri.parse(url);
    DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
    request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
    request.setAllowedOverRoaming(false);
    request.setDestinationInExternalFilesDir(MainActivity.this, Environment.DIRECTORY_DOWNLOADS, "myapk.apk");
    downloadReference = downloadManager.enqueue(request);
}


@Override
public void onDestroy() {
    //unregister your receivers
    this.unregisterReceiver(downloadReceiver);
    super.onDestroy();
}

private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {

    @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) {

            //start the installation of the latest version
                    Intent installIntent = new Intent(Intent.ACTION_VIEW);
                installIntent.setDataAndType(downloadManager.getUriForDownloadedFile(downloadReference),
                        "application/vnd.android.package-archive");
                installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(installIntent);

        }

    }

};

}

updateApp(url) is called on click of a button in UI. Now after clicking the button, the download starts. Lets say the app is closed (receiver is unregistered) after initiating the download, I have problem with two scenarios when the app is started again.

  1. The previous download completes after my app is restarted -
    downloadReference is lost and when my receiver receives the broadcast, the referenceId wont be same as downloadReference, so installIntent is never started. So I have to click on Update button again and initiate the download. Is there a way to avoid this problem?

  2. The previous download completes before my app is restarted - There is no way of knowing that my previous download is complete in the newly started activity. Again I have to click the button and reinitiate the download. Is there a way to enable sticky broadcast for download manager?

1

There are 1 answers

0
bpr10 On

For this, you have to store the download reference in your preference. Then you can query the DownloadManager using DownloadManager.Query() which will return a cursor holding all the download requests posted to DownloadManager by your app. Then you can match the downloadReference id and then check the status of your download. If it's complete then you can get the path from DownloadManager.COLUMN_LOCAL_FILENAME.

private void updateDownloadStatus(long downloadReference) {      
  DownloadManager.Query query = new DownloadManager.Query();

  // if you have stored the downloadReference. Else you have to loop through the cursor.
  query.setFilterById(downloadReference); 

  Cursor cursor = null;

  try {
    cursor = DOWNLOAD_MANAGER.query(query);
    if (cursor == null || !cursor.moveToFirst()) {
      // restart download
      return;
    }
    float bytesDownloaded =
        cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
    float bytesTotal =
        cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
    int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
    int downloadStatus = cursor.getInt(columnIndex);
    int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
    int failureStatus = cursor.getInt(columnReason);
    int filePathInt = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
    String filePath = cursor.getString(filePathInt);

    switch (downloadStatus) {
      case DownloadManager.STATUS_FAILED:
      case DownloadManager.ERROR_FILE_ERROR:
        // restart download
        break;

      case DownloadManager.STATUS_SUCCESSFUL:
        if (filePath != null) {
          //got the file 
        } else {
          //restart
        }
        break;

      case DownloadManager.STATUS_PENDING:
      case DownloadManager.STATUS_RUNNING:
      case DownloadManager.STATUS_PAUSED:
        /// wait till download finishes
        break;
    }
  } catch (Exception e) {
    Log.e("Error","message" + e.getMessage(), e);
  } finally {
    if (cursor != null) {
      cursor.close();
    }
  }
}