您的位置:首页 > 移动开发 > Android开发

Android 7.0 版本更新

2017-12-06 14:56 603 查看
好久不写博客了,这段日子项目时而忙时而松,慢慢的不知道时间都在指缝中溜走了,项目基本完成,慢慢写点在项目中用到的东西,记录下来便于以后查找。

言归正传,现在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);

以后还有更优的方法继续补充….
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: