借鉴:http://www.cnblogs.com/shmilyGWT/p/8177961.html,这个有是否强制更新的选择,我简单的修改了一部分逻辑,看你的业务逻辑了,也就是增加一个参数来判断取消按钮是否显示,点击确认是否下载。
一、工具类
public class UpdateManager {
private Context mContext; //上下文
private String apkUrl; //apk下载地址
private List<String> list; //更新内容
private static final String savePath = "/sdcard/updateAPK/"; //apk保存到SD卡的路径
private static final String saveFileName = savePath + "app_feizufenqi.apk"; //完整路径名
private static final int DOWNLOADING = 1; //表示正在下载
private static final int DOWNLOADED = 2; //下载完毕
private static final int DOWNLOAD_FAILED = 3; //下载失败
private ProgressBar mProgress; //下载进度条控件
private int progress; //下载进度
private boolean cancelFlag = false; //取消下载标志位
private AlertDialog alertDialog1; //表示提示对话框、进度条对话框
/** 构造函数 */
public UpdateManager(Context context,String apkUrl, List list) {
this.mContext = context;
this.apkUrl = apkUrl;
this.list = list;
}
/** 显示更新对话框 */
public void showNoticeDialog(double serverVersion,double clientVersion) {
//如果版本最新,则不需要更新
if (serverVersion <= clientVersion)
return;
AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.softupdate_progress, null);
mProgress = view.findViewById(R.id.update_progress);
ListView lv = view.findViewById(R.id.lv);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext,R.layout.list_item,list);
lv.setAdapter(adapter);
view.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mProgress.setVisibility(View.VISIBLE);
//下载apk
downloadAPK();
}
});
dialog.setView(view);
alertDialog1 = dialog.create();
alertDialog1.setCancelable(false);
alertDialog1.show();
}
/** 下载apk的线程 */
public void downloadAPK() {
new Thread(new Runnable() {
@Override
public void run() {
try {
URL url = new URL(apkUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置连接主机超时时间
conn.setConnectTimeout(5 * 1000);
//设置从主机读取数据超时
conn.setReadTimeout(5 * 1000);
// 设置是否使用缓存 默认是true
// conn.setUseCaches(true);
// 设置为Post请求
conn.setRequestMethod("GET");
conn.connect();
if (conn.getResponseCode() == 200) {
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
File file = new File(savePath);
if (!file.exists()) {
file.mkdir();
}
String apkFile = saveFileName;
File ApkFile = new File(apkFile);
FileOutputStream fos = new FileOutputStream(ApkFile);
int count = 0;
byte buf[] = new byte[1024];
do {
int numread = is.read(buf);
count += numread;
progress = (int) (((float) count / length) * 100);
//更新进度
mHandler.sendEmptyMessage(DOWNLOADING);
if (numread <= 0) {
//下载完成通知安装
mHandler.sendEmptyMessage(DOWNLOADED);
break;
}
fos.write(buf, 0, numread);
} while (!cancelFlag); //点击取消就停止下载.
fos.close();
is.close();
}
} catch(Exception e) {
mHandler.sendEmptyMessage(DOWNLOAD_FAILED);
e.printStackTrace();
}
}
}).start();
}
/** 更新UI的handler */
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DOWNLOADING:
mProgress.setProgress(progress);
break;
case DOWNLOADED:
if (alertDialog1 != null)
alertDialog1.dismiss();
installAPK();
break;
case DOWNLOAD_FAILED:
Toast.makeText(mContext, "网络断开,请稍候再试", Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
};
/** 下载完成后自动安装apk */
public void installAPK() {
File apkFile = new File(saveFileName);
if (!apkFile.exists()) {
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
// 由于没有在Activity环境下启动Activity,设置下面的标签
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//版本在7.0以上是不能直接通过uri访问的
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致 参数3 共享的文件
Uri apkUri = FileProvider.getUriForFile(mContext, "com.example.myversionupdate.fileprovider", apkFile);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
Uri uri = Uri.fromFile(apkFile);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
}
mContext.startActivity(intent);
}
}
二、使用方法
UpdateManager() mUpdateManager = new UpdateManager(SplashActivity.this, "下载地址","更新内容集合");
mUpdateManager.showNoticeDialog("后台版本号", "本地版本号");
三、配置内容
1. 在res下创建一个名字为xml的文件夹,在此文件夹下创建一个名字为file_paths.xml的文件。内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<external-path
name="external_files"
path="." />
<root-path
name="root_path"
path="." />
</paths>
</resources>
2. 创建一个类MyFileProvider继承FileProvider。
3.在清单文件AndroidManifest中引用MyFileProvider。
<!-- 解决apk安装失败的问题 -->
<provider android:name=".MyFileProvider"
android:authorities="com.example.myversionupdate.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
四、注意事项
1. 在清单文件和工具类中的的authorities值一定是你的包名+fileprovider,不然下载失败。
2. 在使用前记得调用动态权限Manifest.permission.WRITE_EXTERNAL_STORAGE。