Android7.0自动更新适配 包解析异常

作者:hexiuming12 时间:2022-02-13 11:21:00 

在Android7.0的手机上,自动更新的时候出现包解析异常,在其他的手机上没有这个问题。

原因:

Android7.0引入私有目录被限制访问和StrictMode API 。私有目录被限制访问是指在Android7.0中为了提高应用的安全性,在7.0上应用私有目录将被限制访问。StrictMode API是指禁止向你的应用外公开 file:// URI。 如果一项包含文件 file:// URI类型 的 Intent 离开你的应用,则会报出异常。

解决办法:

第一步:在AndroidManifest.xml中注册provider,provider可以向应用外提供数据。


<provider
 android:authorities="包名.fileprovider"
 android:name="android.support.v4.content.FileProvider"
 android:grantUriPermissions="true"//这是设置uri的权限
 android:exported="false">
 <meta-data
   android:name="android.support.FILE_PROVIDER_PATHS"
   android:resource="@xml/file_paths"/>//在第二步的时候会有介绍
</provider>

第二步:在res/xml中创建file_paths.xml文件。


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

第三步:贴出我的自动更新下载的代码


public class UpdateManager {
 private Context mContext;

private static String savePath ;
 private String saveFileName ;
 private ProgressBar mProgress; //下载进度条控件
 private static final int DOWNLOADING = 1; //表示正在下载
 private static final int DOWNLOADED = 2; //下载完毕
 private static final int DOWNLOAD_FAILED = 3; //下载失败
 private int progress; //下载进度
 private boolean cancelFlag = false; //取消下载标志位

private String serverVersion; //从服务器获取的版本号
 private String apkUrl;
//  private String apkUrl = "http://liuliu.lejuhuyu.com/AndroidApk/liuliu-dashou-app-1.0.2.apk";
 private String clientVersion; //客户端当前的版本号
 private String updateDescription = "请更新当前最新版本"; //更新内容描述信息
 private String forceUpdate; //是否强制更新
 private String update;
 private VersionBean mVersionBean;

private AlertDialog alertDialog1, alertDialog2; //表示提示对话框、进度条对话框
 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";
 }
 /** 显示更新对话框 */
 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 (serverVersion.equals(clientVersion))
     return;
   if (update.equals("2"))
     return;
   AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
   dialog.setTitle("发现新版本 :" + serverVersion);
   dialog.setMessage(updateDescription);
   dialog.setPositiveButton("现在更新", new DialogInterface.OnClickListener() {
     @Override
     public void onClick(DialogInterface arg0, int arg1) {
       // TODO Auto-generated method stub
       arg0.dismiss();
       showDownloadDialog();
     }
   });
   //是否强制更新
   if (forceUpdate.equals("2")) {
     dialog.setNegativeButton("待会更新", 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();
 }
 /** 显示进度条对话框 */
 public void showDownloadDialog() {
   AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
   dialog.setTitle("正在更新");
   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 (forceUpdate.equals("1")) {
//      dialog.setNegativeButton("取消", 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();

//下载apk
   downloadAPK();
 }
 DownloadManager manager;
 Cursor cursor;
 DownloadManager.Request down;
 DownloadManager.Query query;
 ContentObserver contentObserver;
 /** 下载apk的线程 */
 public void downloadAPK() {
   manager = (DownloadManager) LiuLiuApplication.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
   down = new DownloadManager.Request(Uri.parse(apkUrl));
   // 设置允许使用的网络类型,这里是移动网络和wifi都可以
   down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
       | DownloadManager.Request.NETWORK_WIFI);
   // 显示下载界面
   down.setVisibleInDownloadsUi(true);
   // 设置下载路径和文件名
   down.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "liuliu-dashou-app-"+mVersionBean.getLastVersion() + ".apk");
   down.setMimeType("application/vnd.android.package-archive");
   // 设置为可被媒体扫描器找到
   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);
 }

/** 更新UI的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,"网络断开,请稍候再试",false).show();
         break;
       default:
         break;
     }
   }
 };

/** 下载完成后自动安装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);
   }

}
}

来源:https://blog.csdn.net/hexiuming12/article/details/77839435

标签:Android,自动更新,包解析
0
投稿

猜你喜欢

  • 详解SpringBoot自定义配置与整合Druid

    2023-07-24 20:20:28
  • MyBatis-Plus通过version机制实现乐观锁的思路

    2023-09-16 06:58:27
  • C#开发微信公众号接口开发

    2023-10-14 11:49:01
  • RegexOptions.IgnoreCase正则表达式替换,忽略大小写

    2022-05-03 17:25:45
  • 浅谈Mybatis获取参数值的方式

    2022-09-22 07:56:21
  • Intelli IDEA安装Scala插件并安装Scala软件和配置环境变量的详细教程

    2023-02-16 23:49:01
  • Java并发框架:Executor API详解

    2021-10-31 14:30:28
  • java开源区块链jdchain入门

    2022-08-07 11:44:44
  • 带你了解Java数据结构和算法之队列

    2022-07-03 12:45:34
  • Mac OS下为Android Studio编译FFmpeg解码库的详细教程

    2023-06-30 02:37:54
  • Taro打包Android apk过程详解

    2022-01-31 02:55:27
  • C#读写xml文件方法总结(超详细!)

    2023-11-23 13:16:40
  • Java 用Prometheus搭建实时监控系统过程详解

    2023-09-06 12:07:40
  • java web中 HttpClient模拟浏览器登录后发起请求

    2022-10-27 23:07:05
  • Java按照List内存储的对象的某个字段进行排序的实例

    2023-12-11 11:58:35
  • C#中动态显示当前系统时间的实例方法

    2023-06-20 14:46:02
  • 基于Kubernetes实现前后端应用的金丝雀发布(两种方案)

    2023-01-07 02:32:27
  • Flutter 仿微信支付界面

    2023-08-30 01:31:53
  • C#使用xsd文件验证XML格式是否正确的实现方法

    2022-02-08 11:11:09
  • IntelliJ Plugin 开发之添加第三方jar的示例代码

    2021-11-27 13:35:52
  • asp之家 软件编程 m.aspxhome.com