在我们进行App开发的时候,免不了进行进行版本迭代,所以就将自己的版本迭代进行整理,以便大家使用,也对自己以后的开发更方便
首先是请求后台数据,获取当前后台版本号,然后和自己客户端的版本号进行比对,如果高于当前版本,就进行升级
//versionCode 是当前App的版本号
if (versionCode < 服务器版本号) {
//不强制更新(这是我们的判断,用来判断是否是强制更新)
if (SPUtil.getFormKey(this, Contact.ISFORCEUPDATE).equals("0")) {
//这是弹出框,用来展示更新描述的
final UpdateDialog updateDialog = new UpdateDialog(MainActivity.this, "版本更新", updateInfo, "升级");
updateDialog.setDialogListener(new DialogListener() {
@Override
public void confirm(String tag) {
//这些弹出框可以自己写,重要的就是这一句,其他的都是弹出框
//这是用来请求存储权限的
//downloadUrl = “可以随便写,比如fileurl(我是这么写的)”
permissionRequest(updateDialog, downloadUrl, "0", Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE);//Permission请求实例
}
});
updateDialog.show();
} else {
//强制更新(弹出框可以自定义,只需要在点击升级的时候做操作就行)
final UpdateDialog updateDialog = new UpdateDialog(MainActivity.this, "版本更新", updateInfo, "升级");
updateDialog.setCanceledOnTouchOutside(false);
updateDialog.setCancelable(false);
updateDialog.setDialogListener(new DialogListener() {
@Override
public void confirm(String tag) {
//这些弹出框可以自己写,重要的就是这一句,其他的都是弹出框
permissionRequest(updateDialog, downloadUrl, "1", Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE);//Permission请求实例
}
});
updateDialog.show();
}
} else {
//当前不更新
}
这个Version我创建了一个工具类,用来获取当前App的版本号和版本名称,自行选择
/**
* 获取 versioncode versionname 工具类
*/
public class APKVersionCodeUtils {
/**
* 获取当前本地apk的版本
*
* @param mContext
* @return
*/
public static int getVersionCode(Context mContext) {
int versionCode = 0;
try {
//获取软件版本号,对应AndroidManifest.xml下android:versionCode
versionCode = mContext.getPackageManager().
getPackageInfo(mContext.getPackageName(), 0).versionCode;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return versionCode;
}
/**
* 获取版本号名称
*
* @param context 上下文
* @return
*/
public static String getVerName(Context context) {
String verName = "";
try {
verName = context.getPackageManager().
getPackageInfo(context.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return verName;
}
}
因为我们在从服务器下载完安装包之后,就要将安装包保存到本地文件夹,所以在点击升级的时候,我们要先去申请读写权限,这个权限要在AndroidManifest里面声明一下,就不在多说
//这是申请权限的方法
private void permissionRequest(final UpdateDialog updateDialog, final String fileUrl, final String isForce, String... permissions) {
mSetting = new PermissionSetting(this);
AndPermission.with(this)
.permission(permissions)
.onGranted(new Action() {
@Override
public void onAction(List<String> permissions) {
//提示用户正在下载
Toast.makeText(getApplicationContext(), "正在下载...", Toast.LENGTH_LONG).show();
//我将下载APK和安装APK并替换放在了工具类中
DownloadUtils downloadUtils = new DownloadUtils(MainActivity.this);
downloadUtils.downloadAPK(fileUrl, "你下载安装包的名称,自行定义,以.apk结尾");
//判断当前弹出框是否是强制升级,如果是就不让他隐藏
if (isForce.equals("0")) {
updateDialog.dismiss();
} else {
}
}
})
.onDenied(new Action() {
@Override
public void onAction(@NonNull List<String> permissions) {
//权限申请失败,不做任何操作
Log.e("Main_Activity", "权限申请失败");
}
})
.start();
}
我这里的权限申请再次说明只是用来使用他的申请成功和申请失败的方法,你可以自己去找权限申请方法,只要你能申请下来,就都可以,没必要纠结我这个,因为我做了很多操作,代码有点麻烦,就不粘出来了
//下载APK并安装的工具类
public class DownloadUtils {
//下载器
private DownloadManager downloadManager;
//上下文
private Context mContext;
//下载的ID
private long downloadId;
private Uri imageUri;
public DownloadUtils(Context context) {
this.mContext = context;
}
//下载apk
public void downloadAPK(String url, String name) {
downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
//创建下载任务
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
//移动网络情况下是否允许漫游
request.setAllowedOverRoaming(false);
request.setMimeType("application/vnd.android.packed-archive");
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"");
//在通知栏中显示,默认就是显示的
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setTitle("通知栏的下载APP名称");
request.setDescription("通知栏的下载提示");
request.setVisibleInDownloadsUi(true);
//设置下载的路径
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, name);
File apkfile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "你之前下载的.apk结尾的安装包名称,以.apk结尾");
if (apkfile.exists()) {
apkfile.delete();
}
//获取DownloadManager
//将下载请求加入下载队列,加入下载队列后会给该任务返回一个long型的id,通过该id可以取消任务,重启任务、获取下载的文件等等
assert downloadManager != null;
downloadId = downloadManager.enqueue(request);
//注册广播接收者,监听下载状态
mContext.registerReceiver(receiver,
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
//广播监听下载的各个状态
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
checkStatus();
}
};
//检查下载状态
private void checkStatus() {
DownloadManager.Query query = new DownloadManager.Query();
//通过下载的id查找
query.setFilterById(downloadId);
Cursor c = downloadManager.query(query);
if (c.moveToFirst()) {
int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch (status) {
//下载暂停
case DownloadManager.STATUS_PAUSED:
break;
//下载延迟
case DownloadManager.STATUS_PENDING:
break;
//正在下载
case DownloadManager.STATUS_RUNNING:
break;
//下载完成
case DownloadManager.STATUS_SUCCESSFUL:
//下载完成安装APK
installApk();
DeafultToast.show("下载完成");
break;
//下载失败
case DownloadManager.STATUS_FAILED:
Toast.makeText(mContext, "下载失败", Toast.LENGTH_SHORT).show();
break;
}
}
c.close();
}
// /**
// * 7.0兼容
// */
// private void installAPK() {
// File apkFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "caizhidao.apk");
// Intent intent = new Intent(Intent.ACTION_VIEW);
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// if (Build.VERSION.SDK_INT >= 24) {
// Uri apkUri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + ".provider", apkFile);
// intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
// } else {
// intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
// }
// mContext.startActivity(intent);
// }
//去调用你下载完成的apk进行安装
private void installApk() {
File apkfile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "你之前下载完成的.apk名称,以.apk结尾");
if (!apkfile.exists()) {
return;
}
Intent i = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 7.0+以上版本
Uri apkUri = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", apkfile); //(重中之重,如果不一致,就会调用失败,他找不到你下载过的安装包,就会出现安装失败,再次提示,上线之前,一定要检查一下升级是否好使)与manifest中定义的provider中的authorities=""保持一致
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
i.setDataAndType(apkUri, "application/vnd.android.package-archive");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} else {
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.parse("file://" + apkfile.toString()),
"application/vnd.android.package-archive");
}
mContext.startActivity(i);
}
}
虽然我在代码中写了,但是还是要提醒一下大家,Uri apkUri = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", apkfile);(一定要和AndroidManifest中定义的provider中的authorities一致,不然找不到安装包啊!!!上线记得测试!测试!在测试!)
接下来就是我们AndroidManifest中的东西了,
//就在application下设置就行,可以存在多个
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="你的包名.provider"
android:exported="false"
android:grantUriPermissions="true">
<!-- 元数据 -->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path" />
</provider>
记住啊,这个authorities和你代码中写的一定要一样啊,这个@xml/file_path是我们安装后安装的路径,没必要指定,就放在系统默认的地方就行
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<external-path
name="download"
path="" />
</paths>
</resources>
这个就是那个file_path,现在是结束了,但是大家一定要测试一下,希望这篇文章对大家能有所帮助~
想了想,还是将我使用的权限升级写上吧,就是这个
implementation 'com.yanzhenjie:permission:2.0.0-rc4'