android版本更新及其异常问题处理
前⾔:基本上,⼤部分的App都要求做版本更新。以前没有具体负责过这⼀模块的开发,⼤概的原理是知道的,⼀直以为很简单,没怎么理。但最近⾃⼰在做这个模块的时候,还踩了不少坑。记录⼀下:
按照之前⾃⼰接触到的版本更新,总结⼀下其主要分为三⼤步骤:
1.检测版本更新:检测应⽤新版本,⼀般是进⼊应⽤时调取服务器接⼝,获取最新应⽤版 本信息,和当前应⽤版本信息进⾏⽐较,如果当前应⽤不是最新版本,则下载最新应⽤并⾃动跳转⾄系统⾃带的安装界⾯android最新版
2. 下载apk并且安装:下载apk可以调⽤android SDK ⾃带的DownloadManager进⾏下载,但是看⼀些帖⼦说使⽤DownloadManager 进⾏apk下载的时候,会有坑,有时候某些机型会出现“包解析错误”造成更新失败的问题,所以,⼀般会⾃定义下载apk并进⾏安装。
3. 调⽤系统安装:在android 7.0以前,可以使⽤下⾯的⽅法调起系统安装:
private void update_test(){
String mSavePath= ExternalStorageDirectory().getPath()+"/app-release.apk";
System.out.println("apk路径=====================》"+mSavePath);
File saveFile = new File(mSavePath);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(saveFile),"application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
其中,mSavePath表⽰的是apk下载之后在本地存储的路径。
但是从Android 7.0开始,为了提⾼私有⽂件的安全性,⾯向 Android 7.0 或更⾼版本的应⽤私有⽬录被限制访,传递软件包⽹域外的
file:// URI 可能给接收器留下⽆法访问的路径。因此,尝试传递 file:// URI 会触发 FileUriExposedException。分享私有⽂件内容的推荐⽅法是使⽤ FileProvider。
FileProvider的基本使⽤⽅法:
1.必须在l清单⽂件中注册provider:
其中,exported:要求必须为false,为true则会报安全异常。
grantUriPermissions:true,表⽰授予 URI 临时访问权限。
authorities 组件标识,按照android常⽤规则,都以包名开头,避免和其它应⽤发⽣冲突。
2.上⾯配置⽂件中 android:resource=”@xml/file_paths” 指的是当前组件引⽤ res/xml/l 这个⽂件。
我们需要在资源(res)⽬录下创建⼀个xml⽬录,然后创建⼀个名为“file_paths”(名字可以随便起,只要和在manifest注册的provider所引⽤的resource保持⼀致即可)的资源⽂件:
< external-path /> 代表的根⽬录:
如果是< files-path /> 代表的根⽬录: FilesDir()
如果是< cache-path /> 代表的根⽬录: getCacheDir()
上述代码中path=””,是有特殊意义的,它代码根⽬录,也就是说你可以向其它的应⽤共享根⽬录及其⼦⽬录下任何⼀个⽂件了。
3.使⽤FileProvider调⽤系统安装:
我们可以看到android 7.0以前的安装⽅式与7.0 以后的主要区别:
1)之前的Uri改成了有FileProvider创建⼀个content类型的Uri;
2)添加了intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) 来对⽬标应⽤临时授权该Uri所代表的⽂件。
同时,为了适配android 7.0之前与 7.0之后的机型,需要添加对Android版本判断的部分。
下⾯是从检查版本更新,到下载apk、调起系统安装的代码:
//从服务器获取apk版本与当前apk版本进⾏⽐较,若版本不⼀致,则提⽰更新
//从服务器获取apk版本与当前apk版本进⾏⽐较,若版本不⼀致,则提⽰更新private void updateUI(JSONObject jsonObject) {
if (View() != null) {
Button btn = View().findViewById(R.id.updateBtn);
try {
final String version = String("version");
String currentVersion = BuildConfig.VERSION_NAME;
final String url = String("url");
if (versionpareTo(currentVersion) <= 0) {
btn.setVisibility(View.INVISIBLE);
} else {
btn.setVisibility(View.VISIBLE);
btn.setText(getString(R.string.update_app, version));
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//upgradeApp(url);
//upgradeAppByBrowser(url);
promptUpdating(url,version);
}
});
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
//点击更新之后,弹出确认框,通过⽤户的选择取消或者确定进⾏版本的更新与否private void promptUpdating(final String url,String version){
String msg = getString(firm_update_app,version);
new IOSDialog.Builder(getContext())
.setMessage(msg)
.setPositiveButton(firm,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
upgradeApp(url);
}
})
.setNegativeButton(R.string.cancel, null).show();
}
//使⽤Okhttp进⾏apk的下载
private void upgradeApp(String url) {
int pos = url.lastIndexOf('/');
final String fileName = url.substring(pos + 1);
final KProgressHUD progressHUD = ate(getContext())
.setStyle(KProgressHUD.Style.PIE_DETERMINATE)
.setLabel(getString(R.string.downloading))
.setMaxProgress(100)
.setCancellable(false)
.show();
.
show();
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
final Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
progressHUD.dismiss();
Util.showIRToast(activity, false, String(R.stringwork_exception));
}
});
}
}
//apk下载的回调
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
long target = response.body().contentLength();
InputStream in = response.body().byteStream();
byte[] buff = new byte[1024 * 4];
long downloaded = 0;
File downloads = null;
//7.0
if ( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N){
downloads = new File(getActivity().getFilesDir(), "downloads");
downloads.mkdir();
}else{
downloads = ExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); }
//apk临时存储的本地位置
final File targetFile = new File(downloads, fileName);
if (ists()) {
targetFile.delete();
}
OutputStream output = new FileOutputStream(targetFile);
while (true) {
int readed = in.read(buff);
if (readed == -1) {
break;
break;
}
output.write(buff, 0, readed);
//write buff
downloaded += readed;
final int p = (int) (downloaded * 100 / target);
final Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
progressHUD.setProgress(p);
}
});
}
}
output.flush();
output.close();
Log.e("123","⽂件⼤⼩:"+targetFile.length());
final Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
progressHUD.dismiss();
launchInstallation(targetFile);
}
});
}
} else {
final Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
progressHUD.dismiss();
Util.showIRToast(activity, false, String(R.stringwork_exception));
}
});
}
}
}
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论