Android7.0 Automatic Update Adaptation Package Parsing Exception

  • 2021-09-12 02:09:12
  • OfStack

On Android 7.0 phones, packet parsing anomalies occur during automatic updates, but not on other phones.

Reason:

Android 7.0 introduces private directory restricted access and StrictMode API. Restricted access to private directories means that in order to improve the security of applications in Android 7.0, private directories will be restricted in 7.0. StrictMode API means that it is forbidden to expose file://URI to your application. If an Intent containing file file://URI leaves your application, an exception will be reported.

Solution:

Step 1: Register provider in AndroidManifest. xml, and provider can provide data outside the application.


<provider
  android:authorities=" Package name .fileprovider"
  android:name="android.support.v4.content.FileProvider"
  android:grantUriPermissions="true"// This is the setting uri Permissions of 
  android:exported="false">
  <meta-data
    android:name="android.support.FILE_PROVIDER_PATHS"
    android:resource="@xml/file_paths"/>// In the first 2 There will be an introduction when you step 
</provider>

Step 2: Create the file_paths. xml file in res/xml.


<?xml version="1.0" encoding="utf-8"?>
<resources>
  <paths>
    <external-path path="" name="download" />
  </paths>
</resources>

Step 3: Post my automatic update downloaded code


public class UpdateManager {
  private Context mContext;

  private static String savePath ;
  private String saveFileName ;
  private ProgressBar mProgress; // Download the progress bar control 
  private static final int DOWNLOADING = 1; // Indicates that you are downloading 
  private static final int DOWNLOADED = 2; // Download finished 
  private static final int DOWNLOAD_FAILED = 3; // Download failed 
  private int progress; // Download progress 
  private boolean cancelFlag = false; // Cancel download flag bit 

  private String serverVersion; // The version number obtained from the server 
  private String apkUrl;
//  private String apkUrl = "http://liuliu.lejuhuyu.com/AndroidApk/liuliu-dashou-app-1.0.2.apk";
  private String clientVersion; // The current version number of the client 
  private String updateDescription = " Please update the latest version "; // Update content description information 
  private String forceUpdate; // Whether to force updates 
  private String update;
  private VersionBean mVersionBean;

  private AlertDialog alertDialog1, alertDialog2; // Represents prompt dialog box, progress bar dialog box 
  public UpdateManager(Context context,VersionBean versionBean) {
    this.mContext = context;
    this.mVersionBean = versionBean;
    apkUrl = "http://liuliu.lejuhuyu.com/AndroidApk/liuliu-dashou-app-"+versionBean.getLastVersion()+".apk";
    savePath = Environment.DIRECTORY_DOWNLOADS;
    saveFileName = savePath + "/liuliu-dashou-app-"+versionBean.getLastVersion()+".apk";
  }
  /**  Show the update dialog box  */
  public void showNoticeDialog() {
    serverVersion = mVersionBean.getLastVersion();
    clientVersion = mVersionBean.getVersion();
    L.e("apkUrl="+apkUrl);
    L.e("savePath="+savePath);
    L.e("saveFileName="+saveFileName);
//    forceUpdate = StringUtils.getVersion();
//    forceUpdate = "1";
    forceUpdate = mVersionBean.getImportant();
    update = mVersionBean.getUpdate();
    // If the version is up to date, no update is required 
    if (serverVersion.equals(clientVersion))
      return;
    if (update.equals("2"))
      return;
    AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
    dialog.setTitle(" Discover a new version   : " + serverVersion);
    dialog.setMessage(updateDescription);
    dialog.setPositiveButton(" Update now ", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface arg0, int arg1) {
        // TODO Auto-generated method stub
        arg0.dismiss();
        showDownloadDialog();
      }
    });
    // Whether to force updates 
    if (forceUpdate.equals("2")) {
      dialog.setNegativeButton(" Update later ", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface arg0, int arg1) {
          // TODO Auto-generated method stub
          arg0.dismiss();
        }
      });
    }
    alertDialog1 = dialog.create();
    alertDialog1.setCancelable(false);
    alertDialog1.show();
  }
  /**  Show progress bar dialog box  */
  public void showDownloadDialog() {
    AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
    dialog.setTitle(" Updating ");
    final LayoutInflater inflater = LayoutInflater.from(mContext);
    View v = inflater.inflate(R.layout.softupdate_progress, null);
    mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
    dialog.setView(v);
    // If it is a forced update, the Cancel button is not displayed 
//    if (forceUpdate.equals("1")) {
//      dialog.setNegativeButton(" Cancel ", new DialogInterface.OnClickListener() {
//        @Override
//        public void onClick(DialogInterface arg0, int arg1) {
//          // TODO Auto-generated method stub
//          arg0.dismiss();
//          cancelFlag = false;
//        }
//      });
//    }
    alertDialog2 = dialog.create();
    alertDialog2.setCancelable(false);
    alertDialog2.show();

    // Download apk
    downloadAPK();
  }
  DownloadManager manager;
  Cursor cursor;
  DownloadManager.Request down;
  DownloadManager.Query query;
  ContentObserver contentObserver;
  /**  Download apk Threads of  */
  public void downloadAPK() {
    manager = (DownloadManager) LiuLiuApplication.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
    down = new DownloadManager.Request(Uri.parse(apkUrl));
    //  Set the types of networks allowed, in this case mobile networks and wifi All right 
    down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
        | DownloadManager.Request.NETWORK_WIFI);
    //  Display the download interface 
    down.setVisibleInDownloadsUi(true);
    //  Set the download path and file name 
    down.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "liuliu-dashou-app-"+mVersionBean.getLastVersion() + ".apk");
    down.setMimeType("application/vnd.android.package-archive");
    //  Set to be found by the media scanner 
    down.allowScanningByMediaScanner();
    down.setAllowedOverRoaming(false);
//    down.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    long id = manager.enqueue(down);
    query = new DownloadManager.Query().setFilterById(id);
    contentObserver = new ContentObserver(mHandler) {
      @Override
      public void onChange(boolean selfChange) {
//        super.onChange(selfChange);
        boolean downloading = true;
        while(downloading){
          cursor = manager.query(query);
          try {
            if (cursor != null && cursor.moveToFirst()) {
              int bytes_downloaded = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
              int bytes_total = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
              progress = (int) ((bytes_downloaded * 100) / bytes_total);
              mHandler.sendEmptyMessage(DOWNLOADING);
              if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))==DownloadManager.STATUS_SUCCESSFUL) {
                mHandler.sendEmptyMessage(DOWNLOADED);
              }else if (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))==DownloadManager.STATUS_FAILED){
                mHandler.sendEmptyMessage(DOWNLOAD_FAILED);
              }
            }
          }catch (Exception e){
            e.printStackTrace();
            mHandler.sendEmptyMessage(DOWNLOAD_FAILED);
          }finally {
            if (cursor != null){
              downloading = false;
              cursor.close();
            }
          }
        }
      }
    };
    mContext.getContentResolver().registerContentObserver(Uri.parse("content://downloads/"),true,contentObserver);
  }

  /**  Update UI Adj. handler */
  private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      // TODO Auto-generated method stub
      switch (msg.what) {
        case DOWNLOADING:
          mProgress.setProgress(progress);
          break;
        case DOWNLOADED:
          if (alertDialog2 != null)
            alertDialog2.dismiss();
          installAPK();
          break;
        case DOWNLOAD_FAILED:
          ToastUtil.getInstance(mContext," The network is disconnected, please try again later ",false).show();
          break;
        default:
          break;
      }
    }
  };

  /**  Automatic installation after download apk */
  public void installAPK() {
    File apkFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"liuliu-dashou-app-"+mVersionBean.getLastVersion() + ".apk");

    if (!apkFile.exists()) {
      return;
    }
    if (Build.VERSION.SDK_INT>=24){
     
      Uri apkUri = FileProvider.getUriForFile(mContext, LiuLiuApplication.getContext().getPackageName()+".fileprovider", apkFile);
      Intent install = new Intent(Intent.ACTION_VIEW);
      install.addCategory(Intent.CATEGORY_DEFAULT);
      install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      install.setDataAndType(apkUri, "application/vnd.android.package-archive");
      mContext.startActivity(install);
    } else {
      Intent intent = new Intent();
      intent.setAction(Intent.ACTION_VIEW);
      intent.addCategory(Intent.CATEGORY_DEFAULT);
      intent.setType("application/vnd.android.package-archive");
      intent.setData(Uri.fromFile(apkFile));
      intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      mContext.startActivity(intent);
    }

  }
}

Related articles: