特别注意: 两个更新前后的apk,必须保证签名和包名完全一致,才可以覆盖安装,否则安装会失败!!!
工具类代码如下:
1.下载更新APK的工具
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 callBack 安装界面成功调起的回调
*/
public static void installAPK(Context context, String filePath, InstallCallBack callBack) {
try {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
File apkFile = new File(filePath);
Uri apkUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String authority = context.getPackageName() + ".updateFileProvider";
apkUri = FileProvider.getUriForFile(context, authority, apkFile);
// 授予目录临时共享权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
apkUri = Uri.fromFile(apkFile);
}
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
context.startActivity(intent);
if (callBack != null) {
callBack.onSuccess();
}
//关闭当前
android.os.Process.killProcess(android.os.Process.myPid());
} catch (Exception e) {
if (callBack != null) {
callBack.onFail(e);
}
}
}
/**
* 通过浏览器下载APK更新安装
*
* @param context 上下文
* @param httpUrlApk APK下载地址
*/
public static void installAPKWithBrower(Context context, String httpUrlApk) {
Uri uri = Uri.parse(httpUrlApk);
Intent viewIntent = new Intent(Intent.ACTION_VIEW, uri);
context.startActivity(viewIntent);
}
/**
* 获取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();
}
}
}
使用方式:
public static final String APK_URL = "http://static.portport.cn/tools/app/GangGang_release-1.0.apk";
public void download2(View view) {
//通过浏览器去下载APK
InstallUtils.installAPKWithBrower(this, APK_URL);
}
自个去试试吧!挺好用的!希望能帮到现在正在做app升级的你!!!