Android 7.0 版本更新
2017-12-06 14:56
603 查看
好久不写博客了,这段日子项目时而忙时而松,慢慢的不知道时间都在指缝中溜走了,项目基本完成,慢慢写点在项目中用到的东西,记录下来便于以后查找。
言归正传,现在Android已经升级到8.0了对于8.0的适配还没有遇到过多的问题,但是7.0更加强了安全性,禁止向应用外公开file://URI,如果一项包含file://URI类型的intent离开你的应用,应用失败并出现FileUriExposedException异常,如调用【系统相机拍照】、【裁切照片】、【版本更新】等
现在我将适配了Android7.0的版本更新代码呈上:
注意:context.getPackageName() + “.fileProvider” 中和Manifest中的authorities中一致,其中context.getPackageName() 获取到的是程序的applicationId不是packageName。
注意如果是你下载更新安装成功后缺没有直接打开程序而是退到主界面了,原因是在Android4.0以后你没有设置intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
以后还有更优的方法继续补充….
言归正传,现在Android已经升级到8.0了对于8.0的适配还没有遇到过多的问题,但是7.0更加强了安全性,禁止向应用外公开file://URI,如果一项包含file://URI类型的intent离开你的应用,应用失败并出现FileUriExposedException异常,如调用【系统相机拍照】、【裁切照片】、【版本更新】等
现在我将适配了Android7.0的版本更新代码呈上:
/** * date: 2017/12/4 16:44 * autour: HelenChen * description: 更新界面 */ private void upDateDialog(AppSettingsBean appSettingsBean) { final AlertDialog dialots = new AlertDialog.Builder(SplashActivity.this).create(); View deview = View.inflate(UIUtils.getContext(), R.layout.dialog_splash_update, null); TextView tv_title = (TextView) deview.findViewById(R.id.tv_diolog_title); ImageView iv_dialog_cancel = (ImageView) deview.findViewById(R.id.iv_dialog_cancel); LinearLayout ll_close = (LinearLayout) deview.findViewById(R.id.ll_close); Button bt_dialog_ok = (Button) deview.findViewById(R.id.bt_dialog_ok); TextView tv_dess = (TextView) deview.findViewById(R.id.tv_showdialog_text); NumberProgressBar down_progress = (NumberProgressBar) deview.findViewById(R.id.down_progress); tv_title.setText("是否升级到版本 " + appSettingsBean.getAppVersion() + "?"); tv_dess.setText(appSettingsBean.getAppContent()); dialots.show(); Window windows = dialots.getWindow(); windows.setBackgroundDrawableResource(android.R.color.transparent); windows.setContentView(deview); ll_close.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialots.dismiss(); finish(); } }); bt_dialog_ok.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String appPath = appSettingsBean.getAppPath(); String downApkUrl = UrlManager.GetConfigAPKUrl(appPath); //下载更新 MyUpdateUtils.downLoad(downApkUrl, down_progress, context); } }); }
public class MyUpdateUtils { /** * date: 2017/12/5 14:42 * autour: HelenChen * description: 下载更新 */ public static void downLoad(String downApkUrl, NumberProgressBar down_progress, Context context) { try { //下载后的APK的命名 String APK_NAME = "fxt"; down_progress.setProgressTextColor(Color.parseColor("#4967eb")); down_progress.setReachedBarColor(Color.parseColor("#4967eb")); new InstallUtils(context, downApkUrl, APK_NAME, new InstallUtils.DownloadCallBack() { @Override public void onStart() { LogUtils.i("下载" + "InstallUtils---onStart"); // tv_down_progress.setText("0%"); down_progress.setVisibility(View.VISIBLE); } @Override public void onComplete(String path) { LogUtils.i("下载" + "InstallUtils---onComplete:" + path); /** * 安装APK工具类 * @param context 上下文 * @param filePath 文件路径 * @param authorities ---------Manifest中配置provider的authorities字段--------- * @param callBack 安装界面成功调起的回调 */ String url1 = context.getPackageName() + ".fileProvider"; LogUtils.i("安装111 " + url1); InstallUtils.installAPK(context, path, context.getPackageName() + ".fileProvider", new InstallUtils.InstallCallBack() { @Override public void onSuccess() { Toast.makeText(context, "正在安装程序", Toast.LENGTH_SHORT).show(); } @Override public void onFail(Exception e) { Toast.makeText(context, "安装失败:" + e.toString(), Toast.LENGTH_SHORT).show(); } }); // tv_down_progress.setText("100%"); down_progress.setMax(100); } @Override public void onLoading(long total, long current) { LogUtils.i("下载" + "InstallUtils----onLoading:-----total:" + total + ",current:" + current); // tv_down_progress.setText((int) (current * 100 / total) + "%"); down_progress.setProgress((int) (current * 100 / total)); down_progress.setMax(100); } @Override public void onFail(Exception e) { LogUtils.i("下载" + "InstallUtils---onFail:" + e.getMessage()); } }).downloadAPK(); } catch (Exception e) { e.printStackTrace(); } } }
注意:context.getPackageName() + “.fileProvider” 中和Manifest中的authorities中一致,其中context.getPackageName() 获取到的是程序的applicationId不是packageName。
package com.example.administrator.im_demo.versionupdate; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.support.v4.content.FileProvider; import android.text.TextUtils; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.Timer; import java.util.TimerTask; /** * date: 2017/12/5 17:06 * autour: HelenChen * description: 下载更新APK的工具 * version: V1.0 * @Copyright: */ public class InstallUtils { //任务定时器 private Timer mTimer; //定时任务 private TimerTask mTask; //文件总大小 private int fileLength = 1; //下载的文件大小 private int fileCurrentLength; private Context context; private String httpUrl; private String savePath; private String saveName; private DownloadCallBack downloadCallBack; private static File saveFile; private boolean isComplete = false; public interface DownloadCallBack { void onStart(); void onComplete(String path); void onLoading(long total, long current); void onFail(Exception e); } public interface InstallCallBack { void onSuccess(); void onFail(Exception e); } public InstallUtils(Context context, String httpUrl, String saveName, DownloadCallBack downloadCallBack) { this.context = context; this.httpUrl = httpUrl; this.saveName = saveName; this.downloadCallBack = downloadCallBack; this.savePath = getCachePath(this.context); } public void downloadAPK() { if (TextUtils.isEmpty(httpUrl)) { return; } saveFile = new File(savePath); if (!saveFile.exists()) { boolean isMK = saveFile.mkdirs(); if (!isMK) { //创建失败 return; } } saveFile = new File(savePath + File.separator + saveName + ".apk"); if (downloadCallBack != null) { //下载开始 downloadCallBack.onStart(); } new Thread(new Runnable() { @Override public void run() { InputStream inputStream = null; FileOutputStream outputStream = null; HttpURLConnection connection = null; try { URL url = new URL(httpUrl); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(10 * 1000); connection.setReadTimeout(10 * 1000); connection.connect(); inputStream = connection.getInputStream(); outputStream = new FileOutputStream(saveFile); fileLength = connection.getContentLength(); //判断fileLength大小 if (fileLength <= 0) { //失败的地址 ((Activity) context).runOnUiThread(new Runnable() { @Override public void run() { if (downloadCallBack != null) { downloadCallBack.onFail(new Exception("下载地址异常")); downloadCallBack = null; } } }); return; } //计时器 initTimer(); byte[] buffer = new byte[1024]; int current = 0; int len; while ((len = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, len); current += len; if (fileLength > 0) { fileCurrentLength = current; } } isComplete = true; //下载完成 ((Activity) context).runOnUiThread(new Runnable() { @Override public void run() { //解决某些低版本安装失败的问题 changeApkFileMode(saveFile); if (downloadCallBack != null) { downloadCallBack.onComplete(saveFile.getPath()); downloadCallBack = null; } } }); } catch (final Exception e) { e.printStackTrace(); ((Activity) context).runOnUiThread(new Runnable() { @Override public void run() { if (downloadCallBack != null) { downloadCallBack.onFail(e); downloadCallBack = null; } } }); } finally { try { if (inputStream != null) inputStream.close(); if (outputStream != null) outputStream.close(); if (connection != null) connection.disconnect(); } catch (IOException e) { } //销毁Timer destroyTimer(); } } }).start(); } private void initTimer() { mTimer = new Timer(); mTask = new TimerTask() {//在run方法中执行定时的任务 @Override public void run() { ((Activity) context).runOnUiThread(new Runnable() { @Override public void run() { if (downloadCallBack != null) { if (!isComplete) { downloadCallBack.onLoading(fileLength, fileCurrentLength); } } } }); } }; //任务定时器一定要启动 mTimer.schedule(mTask, 0, 200); } private void destroyTimer() { if (mTimer != null && mTask != null) { mTask.cancel(); mTimer.cancel(); mTask = null; mTimer = null; } } /** * 安装APK工具类 * * @param context 上下文 * @param filePath 文件路径 * @param authorities Manifest中配置provider的authorities字段 * @param callBack 安装界面成功调起的回调 */ public static void installAPK(Context context, String filePath, String authorities, InstallCallBack callBack) { try { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); File apkFile = new File(filePath); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); Uri contentUri = FileProvider.getUriForFile(context, authorities, apkFile); intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); } else { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); } context.startActivity(intent); if (callBack != null) { callBack.onSuccess(); } } catch (Exception e) { if (callBack != null) { callBack.onFail(e); } } } /** * 获取app缓存路径 SDCard/Android/data/你的应用的包名/cache * * @param context * @return */ public String getCachePath(Context context) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { //外部存储可用 cachePath = context.getExternalCacheDir().getPath(); } else { //外部存储不可用 cachePath = context.getCacheDir().getPath(); } return cachePath; } //参照:APK放到data/data/下面提示解析失败 (http://blog.csdn.net/lonely_fireworks/article/details/27693073) private void changeApkFileMode(File file) { try { //apk放在缓存目录时,低版本安装提示权限错误,需要对父级目录和apk文件添加权限 String cmd1 = "chmod 777 " + file.getParent(); Runtime.getRuntime().exec(cmd1); String cmd = "chmod 777 " + file.getAbsolutePath(); Runtime.getRuntime().exec(cmd); } catch (IOException e) { e.printStackTrace(); } } }
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileProvider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_provider"/> </provider>
<?xml version="1.0" encoding="utf-8"?> <paths> <!--升级--> <external-cache-path name="mn_update_external_cache" path="" /> <cache-path name="mn_update_cache" path="" /> </paths>
注意如果是你下载更新安装成功后缺没有直接打开程序而是退到主界面了,原因是在Android4.0以后你没有设置intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
以后还有更优的方法继续补充….
相关文章推荐
- Android 版本更新工具 兼容7.0
- Android 版本更新下载自动安装APK,并解决Android6.0,7.0安装失败的问题
- 直接拿来用的版本更新(Android 兼容7.0)
- Android版本更新-----兼容android7.0
- Android 版本更新(非热更新) 适配7.0更新 以及三星 note系列读取内存相关目录无权限问题
- Android使用DownloadMange进行版本更新(兼容7.0)
- Android版本更新(适用于6.0/7.0)
- android 7.0 apk版本更新,下载之后自动安装
- android版本更新适配7.0,解决7.0手机无法更新安装apk
- 使用七牛云存储实现Android版本更新
- 安卓(Android)应用版本更新方法
- Android提示版本更新+notification显示下载进度
- Android提示版本更新的实现
- Android 版本更新的实现
- android SDK manager 无法获取更新版本,连线包下载大全【转】
- Android应用更新之自动检测版本及自动升级
- Android版本更新
- android 版本更新 静默安装及自启动
- Android版本检测\自动更新
- Android检测版本更新(读取apk配置文件中的版本信息)