APP版本更新,监听下载进度兼容6.0、7.0、8.0
重要提醒:
https://www.jianshu.com/p/bb4cde6e88c6?tdsourcetag=s_pcqq_aiomsg
更新主要分为以下几步:
1.获取APP下载路径
2.开启服务
3.开启下载任务
4.监听下载进度
5.下载完成后注册并发送通知
6.接收到通知安装APP
1.此处是下载路径
public class VersionUpdate {
/**
* 请求服务器,检查版本是否可以更新
*
* @param versionUpdate
*/
public static void checkVersion(final VersionUpdateImpl versionUpdate) {
//从网络请求获取到的APK下载路径,此处是随便找的链接
versionUpdate.bindService("download url");
}
}
public interface VersionUpdateImpl {
/**
*绑定版本更新下载服务
*
* @param apkUrl apk下载路径
*/
void bindService(String apkUrl);
}
2.主页面的操作
//前面的判断自己添加
removeOldApk();//在检查版本之前首先要删除以前存在的APK
VersionUpdate.checkVersion(MainActivity.this);//检查更新版本
@Override
public void bindService(String apkUrl) {
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra(DownloadService.BUNDLE_KEY_DOWNLOAD_URL, apkUrl);
isBindService = bindService(intent, conn, BIND_AUTO_CREATE);
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
DownloadService.DownloadBinder binder = (DownloadService.DownloadBinder) service;
DownloadService downloadService = binder.getService();
downloadService.setTargetActivity(MainActivity.this);
//接口回调,下载进度
downloadService.setOnProgressListener(new DownloadService.OnProgressListener() {
@Override
public void onProgress(float fraction) {
bnp.setProgress((int) (fraction * 100));
//判断是否真的下载完成进行安装了,以及是否注册绑定过服务
if (fraction == DownloadService.UNBIND_SERVICE && isBindService) {
unbindService(conn);
isBindService = false;
}
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
/**
* 删除上次更新存储在本地的apk
*/
private void removeOldApk() {
//获取老APK的存储路径
// 这里在下载APK完成后会把路径保存起来
File fileName = new File(SPUtil.getString(Constant.SP_DOWNLOAD_PATH, ""));
Log.e("老APK的存储路径","老APK的存储路径 =" + SPUtil.getString(Constant.SP_DOWNLOAD_PATH, ""));
if (fileName != null && fileName.exists() && fileName.isFile()) {
fileName.delete();
Log.e("进行删除操作","存储器内存在老APK,进行删除操作");
}
}
3.具体的实现都在DownloadService这个类中
这个类中需要注意几点问题:
1
./**设置文件保存路径*/
request.setDestinationInExternalFilesDir(getApplicationContext(), Environment.DIRECTORY_DOWNLOADS, "XXXX.apk");
2.
/**
* 接受下载完成广播
*/
DownLoadBroadcast
这个方法中需要适配7.0以上的路径保存
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "xxxxx.apk");
path = FileProvider.getUriForFile(context, "包名.fileprovider", file);
1.建一个xml文件夹 建一个provider_paths文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<root-path path="" name="camera_photos" />
//注意 里面可写多个 但是name不能一样
</paths>
</resources>
2.在配置中 注册
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.github.phoenix.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
3.权限问题
<!-- 网络权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 8.0系统 获取 未知应用安装权限 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!--SD卡创建与删除权限-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!--VISIBILITY_HIDDEN表示不显示任何通知栏提示的权限-->
<!-- 文件读写权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE"></uses-permission>
//存储的工具类
public class SPUtil {
private static SharedPreferences spf;
private SPUtil(){}
static {
spf = BaseApplication.getContext().getSharedPreferences(Constant.SP_NAME, Context.MODE_PRIVATE);
}
/**
* 通过 instanceof 来判断数据类型再强转成对应的数据类型进行存储
* @param key
* @param obj
*/
public static void put(String key, Object obj){
SharedPreferences.Editor editor = spf.edit();
if (obj instanceof String) {
editor.putString(key, (String) obj);
}else if (obj instanceof Long) {
editor.putLong(key, (Long) obj);
}else if (obj instanceof integer) {
editor.putInt(key, (int) obj);
}else if (obj instanceof Boolean) {
editor.putBoolean(key, (Boolean) obj);
}else if (obj instanceof Float) {
editor.putFloat(key, (Float) obj);
}
editor.apply();
}
/**
* 通过instanceof 来判断数据类型再进行取值然后再进行类型转换,这种方法比较麻烦取出值之后在应用的地方还要进行类型转换
* @param key
* @param obj
* @return
*/
public static Object get(String key, Object obj){
if (obj instanceof String) {
return spf.getString(key, (String) obj);
}else if (obj instanceof String) {
return spf.getLong(key, (Long) obj);
}else if (obj instanceof integer) {
return spf.getInt(key, (int) obj);
}else if (obj instanceof Boolean) {
return spf.getBoolean(key, (Boolean) obj);
}else if (obj instanceof Float) {
return spf.getFloat(key, (Float) obj);
}
return null;
}
/**
* 全部清除文件中的内容
*/
public static void clearSpf(){
SharedPreferences.Editor editor = spf.edit();
editor.clear().commit();
}
/**
* 清除指定key 的内容
* @param key
*/
public static void remove(String key){
SharedPreferences.Editor editor = spf.edit();
editor.remove(key).commit();
}
/**
* 获取String值
*
* @param key
* @param defValue
* @return
*/
public static String getString(String key, String defValue) {
return spf.getString(key, defValue);
}
/**
* 获取int值
*
* @param key
* @param defValue
* @return
*/
public static int getInt(String key, int defValue) {
return spf.getInt(key, defValue);
}
/**
* 获取long值
*
* @param key
* @param defValue
* @return
*/
public static long getLong(String key, long defValue) {
return spf.getLong(key, defValue);
}
/**
* 获取float值
*
* @param key
* @param defValue
* @return
*/
public static float getFloat(String key, float defValue) {
return spf.getFloat(key, defValue);
}
/**
* 获取bo0lean值
*
* @param key
* @param defValue
* @return
*/
public static boolean getBoolean(String key, boolean defValue) {
return spf.getBoolean(key, defValue);
}
}
public class Constant {
public static final String SP_NAME = "xxxxx";
/**apk 文件存储路径*/
public static final String SP_DOWNLOAD_PATH = "download.path";
}
部分源码
https://blog.csdn.net/m0_37714581/article/details/88712003