添加依赖:
implementation 'com.github.LuoGuoXin:BaseAndroid:1.0.5'//版本更新
在project—build.gradle下配置
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
添加下载apk权限及注册内容提供者(安装APK在Android7.0后需要用到)
<!--请求安装应用权限-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.everywhere.trip"
android:exported="false"
android:grantUriPermissions="true">
<!-- 元数据 -->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path" />
</provider>
向服务器获取版本号之后
VersionName版本检测
UpdateManager instance = UpdateManager.getInstance();
info = versionInfo.getResult().getInfo();
if (instance.updateApp(instance.getVersionName(this), info.getVersion())){
int type = 0;
if(luo.library.base.utils.UpdateManager.getInstance().isWifi(this)) {
type = 1;
}
if(false) {
type = 2;
}
String downLoadPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/downloads/";
File dir = new File(downLoadPath);
if(!dir.exists()) {
dir.mkdir();
}
//getDownload_url()为接口中的下载路径
fileName = info.getDownload_url().substring(info.getDownload_url().lastIndexOf("/") + 1, info.getDownload_url().length());
if(fileName == null && TextUtils.isEmpty(fileName) && !fileName.contains(".apk")) {
fileName = this.getPackageName() + ".apk";
}
File file = new File(downLoadPath + fileName);
UpdateManager.getInstance().setType(type).setUrl(info.getDownload_url()).setUpdateMessage("更新了UI\n添加图片缩放功能").setFileName(fileName).setIsDownload(file.exists());
if(type == 1 && !file.exists()) {
UpdateManager.getInstance().downloadFile(this);
} else {
UpdateManager.getInstance().showDialog(this);
}
}
VersionCode版本检测
BaseAndroid.checkUpdate(MainActivity.this, 2, downloadUrl,"更新了XXX\n修复OOO", false);
下面进行代码分析哈:首先是主方法
/**
* 版本更新
*
* @param context
* @param versionCode 版本号
* @param url apk下载地址
* @param updateMessage 更新内容
* @param isForced 是否强制更新
*/
public static void checkUpdate(Context context, int versionCode, String url, String updateMessage, boolean isForced) {
if (versionCode > UpdateManager.getInstance().getVersionCode(context)) {
int type = 0;//更新方式,0:引导更新,1:安装更新,2:强制更新
if (UpdateManager.getInstance().isWifi(context)) {
type = 1;
}
if (isForced) {
type = 2;
}
//检测是否已下载
String downLoadPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/downloads/";
File dir = new File(downLoadPath);
if (!dir.exists()) {
dir.mkdir();
}
String fileName = url.substring(url.lastIndexOf("/") + 1, url.length());
if (fileName == null && TextUtils.isEmpty(fileName) && !fileName.contains(".apk")) {
fileName = context.getPackageName() + ".apk";
}
File file = new File(downLoadPath + fileName);
//设置参数
UpdateManager.getInstance().setType(type).setUrl(url).setUpdateMessage(updateMessage).setFileName(fileName).setIsDownload(file.exists());
if (type == 1 && !file.exists()) {
UpdateManager.getInstance().downloadFile(context);
} else {
UpdateManager.getInstance().showDialog(context);
}
}
}
然后就是UpdateManager的封装啦,自己看代码吧
/**
* 版本更新
*/
public class UpdateManager {
private String downLoadPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/downloads/";
private int type = 0;//更新方式,0:引导更新,1:安装更新,2:强制更新
private String url = "";//apk下载地址
private String updateMessage = "";//更新内容
private String fileName = null;//文件名
private boolean isDownload = false;//是否下载
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
private AlertDialog dialog;
private ProgressDialog progressDialog;
public static UpdateManager updateManager;
public static UpdateManager getInstance() {
if (updateManager == null) {
updateManager = new UpdateManager();
}
return updateManager;
}
private UpdateManager() {
}
/**
* 弹出版本更新提示框
*/
public void showDialog(final Context context) {
String title = "";
String left = "";
boolean cancelable = true;
if (type == 1 | isDownload) {
title = "安装新版本";
left = "立即安装";
} else {
title = "发现新版本";
left = "立即更新";
}
if (type == 2) {
cancelable = false;
}
dialog = new AlertDialog.Builder(context).setTitle(title).setMessage(updateMessage).setCancelable(cancelable)
.setNegativeButton(left, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (type == 1 | isDownload) {
InstallUtil.installApk(context,downLoadPath+fileName);
} else {
if (url != null && !TextUtils.isEmpty(url)) {
if (type == 2) {
createProgress(context);
} else {
createNotification(context);
}
downloadFile(context);
} else {
Toast.makeText(context, "下载地址错误", Toast.LENGTH_SHORT).show();
}
}
dialog.dismiss();
}
})
.setPositiveButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (type == 2) {
System.exit(0);
}
}
})
.create();
dialog.show();
}
private static final String TAG = "UpdateManager";
/**
* 下载apk
*
*/
public void downloadFile(final Context context) {
RequestParams params = new RequestParams(url);
params.setSaveFilePath(downLoadPath + fileName);
x.http().request(HttpMethod.GET, params, new Callback.ProgressCallback<File>() {
@Override
public void onSuccess(File result) {
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
Toast.makeText(context, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
@Override
public void onWaiting() {
}
@Override
public void onStarted() {
}
@Override
public void onLoading(long total, long current, boolean isDownloading) {
//实时更新通知栏进度条
if (type == 0) {
Log.e(TAG, "onLoading:"+current+"/"+total );
notifyNotification(current, total);
} else if (type == 2) {
progressDialog.setProgress((int) (current * 100 / total));
}
if (total == current) {
if (type == 0) {
mBuilder.setContentText("下载完成");
mNotifyManager.notify(10086, mBuilder.build());
} else if (type == 2) {
progressDialog.setMessage("下载完成");
}
if (type == 1) {
showDialog(context);
} else {
InstallUtil.installApk(context,downLoadPath+fileName);
}
}
}
});
}
/**
* 强制更新时显示在屏幕的进度条
*
*/
private void createProgress(Context context) {
progressDialog = new ProgressDialog(context);
progressDialog.setMax(100);
progressDialog.setCancelable(false);
progressDialog.setMessage("正在下载...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.show();
}
/**
* 创建通知栏进度条
*
*/
private void createNotification(Context context) {
mNotifyManager = (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(context);
mBuilder.setSmallIcon(BaseAndroid.getBaseConfig().getAppLogo());
mBuilder.setContentTitle("版本更新");
mBuilder.setContentText("正在下载...");
mBuilder.setProgress(0, 0, false);
Notification notification = mBuilder.build();
notification.flags = Notification.FLAG_AUTO_CANCEL;
mNotifyManager.notify(10086, notification);
}
/**
* 更新通知栏进度条
*
*/
private void notifyNotification(long percent, long length) {
mBuilder.setProgress((int) length, (int) percent, false);
mNotifyManager.notify(10086, mBuilder.build());
}
/**
* 安装apk
*
* @param context 上下文
* @param file APK文件
*/
private void installApk(Context context, File file) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
context.startActivity(intent);
}
/**
* @return 当前应用的版本号
*/
public int getVersionCode(Context context) {
try {
PackageManager manager = context.getPackageManager();
PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
int version = info.versionCode;
// String versionName = info.versionName;
return version;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* @return 当前应用的版本名
*/
public String getVersionName(Context context) {
try {
PackageManager manager = context.getPackageManager();
PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
// int version = info.versionCode;
String version = info.versionName;
return version;
} catch (Exception e) {
e.printStackTrace();
return "1.0";
}
}
/**
* 判断当前网络是否wifi
*/
public boolean isWifi(Context mContext) {
ConnectivityManager connectivityManager = (ConnectivityManager) mContext
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetInfo != null && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI) {
return true;
}
return false;
}
public UpdateManager setUrl(String url) {
this.url = url;
return this;
}
public UpdateManager setType(int type) {
this.type = type;
return this;
}
public UpdateManager setUpdateMessage(String updateMessage) {
this.updateMessage = updateMessage;
return this;
}
public UpdateManager setFileName(String fileName) {
this.fileName = fileName;
return this;
}
public UpdateManager setIsDownload(boolean download) {
isDownload = download;
return this;
}
/**
* 判断当前是否为最新版本
* @param localVersion 当前安装的版本
* @param newVersion 获取到的最新版本
* @return
*/
public boolean updateApp(String localVersion, String newVersion) {
String[] localVersionArray = localVersion.split("\\.");
String[] newVersionArray = newVersion.split("\\.");
if (localVersionArray.length < newVersionArray.length) {
int cha = newVersionArray.length - localVersionArray.length;
for (int i = 0; i < cha; i++) {
localVersion = localVersion + ".0";
}
localVersionArray = localVersion.split("\\.");
}
try {
for (int i = 0; i < newVersionArray.length; i++) {
int temp = Integer.parseInt(newVersionArray[i]);
int compar = Integer.parseInt(localVersionArray[i]);
if (temp > compar) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
然后是安装APK用到的工具类:
public class InstallUtil {
/*调用安装的Activity中复写onActivityResult()方法
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == InstallUtil.UNKNOWN_CODE) {
InstallUtil.installApk(this,mPath);//再次执行安装流程,包含权限判等
}
}*/
public static final int UNKNOWN_CODE = 2019;
public static void installApk(Context context, String path) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startInstallO(context, path);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
startInstallN(context, path);
} else {
startInstall(context, path);
}
}
/**
* android1.x-6.x
*
* @param path 文件的路径
*/
public static void startInstall(Context context, String path) {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.parse("file://" + path), "application/vnd.android.package-archive");
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);
}
/**
* android7.x
*
* @param path 文件路径
*/
@RequiresApi(api = Build.VERSION_CODES.N)
public static void startInstallN(Context context, String path) {
//参数1 上下文, 参数2 在AndroidManifest中的android:authorities值, 参数3 共享的文件
Uri apkUri = FileProvider.getUriForFile(context, "com.everywhere.trip", new File(path));
Intent install = new Intent(Intent.ACTION_VIEW);
//由于没有在Activity环境下启动Activity,设置下面的标签
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
context.startActivity(install);
}
/**
* android8.x
*/
@RequiresApi(api = Build.VERSION_CODES.O)
private static void startInstallO(final Context context, String path) {
boolean isGranted = context.getPackageManager().canRequestPackageInstalls();
if (isGranted) {
startInstallN(context, path);//安装应用的逻辑(写自己的就可以)
} else {
new AlertDialog.Builder(context)
.setCancelable(false)
.setTitle("安装应用需要打开未知来源权限,请去设置中开启权限")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int w) {
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
Activity act = (Activity) context;
act.startActivityForResult(intent, UNKNOWN_CODE);
}
})
.show();
}
}
}
FileProvider:
/**
* 类:FileProviderUtils
* 从APP向外共享的文件URI时,必须使用该类进行适配,
* 否则在7.0以上系统,会报错:FileUriExposedException(文件Uri暴露异常)
*/
public class FileProviderUtils {
/**
* 从文件获得URI
* @param activity 上下文
* @param file 文件
* @return 文件对应的URI
*/
public static Uri uriFromFile(Activity activity, File file) {
Uri fileUri;
//7.0以上进行适配
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String p = activity.getPackageName() + "";
fileUri = FileProvider.getUriForFile(
activity,
p,
file);
} else {
fileUri = Uri.fromFile(file);
}
return fileUri;
}
/**
* 设置Intent的data和类型,并赋予目标程序临时的URI读写权限
* @param activity 上下文
* @param intent 意图
* @param type 类型
* @param file 文件
* @param writeAble 是否赋予可写URI的权限
*/
public static void setIntentDataAndType(Activity activity,
Intent intent,
String type,
File file,
boolean writeAble) {
//7.0以上进行适配
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setDataAndType(uriFromFile(activity, file), type);
//临时赋予读写Uri的权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (writeAble) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} else {
intent.setDataAndType(Uri.fromFile(file), type);
}
}
/**
* 设置Intent的data和类型,并赋予目标程序临时的URI读写权限
* @param context 上下文
* @param intent 意图
* @param type 类型
* @param fileUri 文件uri
* @param writeAble 是否赋予可写URI的权限
*/
public static void setIntentDataAndType(Context context,
Intent intent,
String type,
Uri fileUri,
boolean writeAble) {
//7.0以上进行适配
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setDataAndType(fileUri, type);
//临时赋予读写Uri的权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (writeAble) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
} else {
intent.setDataAndType(fileUri, type);
}
}
}
用到的xml文件,在res文件下创建xml包,在此包下创建:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<root-path
name="root"
path="" />
<files-path
name="files"
path="" />
<cache-path
name="cache"
path="" />
<external-path
name="external"
path="" />
<external-files-path
name="external_file"
path="" />
<external-cache-path
name="external_cache"
path="" />
</resources>