一、通知栏自动下载更新
XVersionUpdate是VersionUpdate的升级版,全面优化代码,提高兼容性和稳定性,增强用户体验,帮助我们快速实现版本更新功能。
(1).效果图:
更新内容:
最近更新内容:
1.修复重复下载和进度条显示异常的bug
2.新增取消下载功能
3.兼容Android8.0
4.修复优化评论中的其他问题。
(2).实现过程:
在build. gradle (app)
文件中注入以下依赖
dependencies {
......
implementation 'com.androidkun:xversionupdate:1.0.6'
}
可以在首次启动界面的Oncreate
方法下调用API检测版本更新,让其有新版本,在启动APP后自动下载更新。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
VersionUpdateConfig.getInstance()//获取配置实例
.setContext(LoginActivit这里写界面.this)//设置上下文
.setDownLoadURL("https://www.armpro.cn/assets/这里是下载地址.apk")//设置文件下载链接
.setNewVersion("3")//设置即将下载的APK的版本号,避免重复下载
.setFileSavePath("/storage/emulated/0/")//设置文件保存路径(可不设置)
.setNotificationIconRes(R.drawable.ic_launcher)//设置通知图标
.setNotificationSmallIconRes(R.drawable.ic_launcher)//设置通知小图标
.setNotificationTitle("软件有新版本,正在下载中...")//设置通知标题
.startDownLoad();//开始下载
}
接下来就不用再做任何处理了,有新版本时启动APP,就会自动在通知栏显示下载进度,在下载完成后会自动跳到安装页面。
项目源码地址:https://github.com/AndroidKun/XVersionUpdate
二、主界面弹窗选择 更新/强制更新/浏览器更新(通用更新)
这个版本的代码通用性很高,代码也很少,理论适用与任意的安卓系统(Android 10版本已测试可用
),最简单的源代码实现的更新服务,检测远程更新代码多种更新方式的选择,代码可修改定制性很强,支持同时多个更新链接配置进行容错处理,应用内直链直接下载时失败时会弹出提示错误弹窗,并可选择浏览器下载。可以简单使用gitee搭建静态网页当后台更新服务(源码见下方↓)。
(1).弹窗效果图:
(2).实现过程:
1. 搭建json格式网页
这里提供源码和搭建后数据展示情况,具体详细的搭建教程很简单,随便百度就可以找到,这里不再重复搭建过程。
搭建源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>https://yirj.gitee.io/项目名称</title>
</head>
<body>
<pre><code id="json"></code></pre>
</body>
<script type="text/javascript">
let btn = document.querySelector('#json');
let data = {
"hasUpdate": true,"NoIgnorable": true,"versionCode": 51,"versionName": "2.4.1","updateLog": "\n1、更改保存图片的存储路径。\n2、更改软件更新的提示模式。\n3、调整非强制更新控制方式。\n4、新增存储权限的申请授权位置。","apkUrl": "https://www.yuming.com/assets/a某o130.apk","webUrl": "https://yirj.gitee.io/update111","apkSize": "29.5MB"};
btn.textContent = JSON.stringify(data, null, 2);
</script>
</html>
搭建成的链接
https://yirj.gitee.io/项目名称
访问相关展示
{
hasUpdate: true, //是否有更新 默认true
NoIgnorable: true, //不 可忽略更新 强制:true 非强制:false
versionCode: 51, //服务端的版本号
versionName: "2.4.1", //服务端的版本名
updateLog: "\n1、更改保存图片的存储路径。\n2、更改软件更新的提示模式。\n3、调整非强制更新控制方式。\n4、新增存储权限的申请授权位置。", //更新提示内容
apkUrl: "https://www.yuming.com/assets/a某o130.apk",//新版本APK直链下载地址
webUrl: "https://yirj.gitee.io/update111",//浏览器更新链接,随意放(直链、蓝奏、官网均可)
apkSize: "29.5MB" //新版本的大小 随意写就好
}
2. 创建file_paths.xml及修改AndroidManifest.xml
创建file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
修改AndroidManifest.xml
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 修改或删除您的USB存储设备中的内容 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 查看网络连接 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
.....
android:label="@string/app_name"
android:requestLegacyExternalStorage="true">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
.........
</application>
3. 启动主界面加入检测更新代码
在软件的检测更新界面的Oncreate
方法下,加入检测更新的代码。
更新弹窗出现条件:hasUpdate
为true且用户使用的APP的版本号<服务端的版本号,就会提示更新。
强制更新出现条件:有更新后跳转到showDialogUpdate
方法,判断 NoIgnorable
为true则就是强制更新。
import android.Manifest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class MainActivity extends Activity {
private String TAG;
public static JSONObject jSONObject = null;
private static boolean hasUpdate, NoIgnorable = true; //是否有更新。 不可忽略的更新
private static int versionCode = 0;
private static String versionName, updateLog, apkSize, apkUrl, webUrl = "";
private static String[] upl = new String[]{
"https://yirj.gitee.io/更新链接1", "https://yirj.gitee.io/更新链接2"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//忽略证书校验的相关方法,http报证书异常或者不安全链接就启用它
//handleSSLHandshake();
//应用内直链更新,要先动态申请获取存储权限
getReadPermissions();
//启动子线程--更新功能实现调用
new Thread() {
@Override
public void run() {
Looper.prepare();
try {
GetServerJson();
//hasUpdate为true 且 本程序的版本号小于服务器的版本号,那么提示用户更新
if (hasUpdate & getVersionCode() < versionCode) {
showDialogUpdate();//弹出提示版本更新的对话框
} else {
//Toast.makeText(MainActivity.this, "当前已是最新版本", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
Looper.loop();
}
}.start();
}
/**
* 获取当前使用的软件包的版本号
*/
public int getVersionCode() {
try {
//获取packagemanager的实例
PackageManager packageManager = getPackageManager();
//getPackageName()是你当前类的包名,0代表是获取版本信息
PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);
Log.e("TAG", "版本号" + packInfo.versionCode); //更新软件用的是版本号
return packInfo.versionCode;
} catch (Exception e) {
e.printStackTrace();
}
return 1;
}
/**
* 提示版本更新的对话框
*/
public void showDialogUpdate() {
//hasUpdate为true且程序版本号<服务端版本号,提示用户更新
if (NoIgnorable) {
//NoIgnorable为true 就是强制更新,无“取消”按钮
// 这里的属性可以一直设置,因为每次设置后返回的是一个builder对象
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setCancelable(false); //开启强制更新,无法触摸外部关闭
builder.setTitle("是否升级到" + versionName + "版本?").
// 设置提示框的图标
setIcon(R.drawable.ic_launcher).
// 设置要显示的信息
setMessage("新版本大小:" + apkSize + "\n" + updateLog).
// 设置确定按钮
setPositiveButton("更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
loadNewVersionProgress();//程序内直接下载最新的版本程序
}
}).setNeutralButton("浏览器下载", new DialogInterface.OnClickListener() {
//中性按钮 应用内下载失败可用它更新
@Override
public void onClick(DialogInterface dialog, int which) {
Uri uri = Uri.parse(webUrl);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
finish(); //强制更新,点击后销毁应用
}
});
// 显示对话框
builder.create().show();
} else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// builder.setCancelable(false); //非强制更新,屏蔽此行,触摸外部或退出键可关闭
builder.setTitle("是否升级到" + versionName + "版本?").
setMessage("新版本大小:" + apkSize + "\n" + updateLog).
setPositiveButton("更新", new DialogInterface.OnClickListener() {
//正按钮
@Override
public void onClick(DialogInterface dialog, int which) {
loadNewVersionProgress();//下载最新的版本程序
}
}).setNegativeButton("取消", new DialogInterface.OnClickListener() {
//负按钮
@Override
public void onClick(DialogInterface dialog, int which) {
// finish(); //屏蔽销毁,不做任何处理
}
}).setNeutralButton("浏览器下载", new DialogInterface.OnClickListener() {
//中性按钮
@Override
public void onClick(DialogInterface dialog, int which) {
Uri uri = Uri.parse(webUrl);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
//finish(); //屏蔽销毁,访问浏览器,程序不会退出
}
});
// 显示对话框
builder.create().show();
}
}
//轮询验证两个更新链接,返回有效链接
public static String checkUrl(String[] ltl) {
String resultUrl = null;
for (String url : ltl) {
resultUrl = url;
try {
//调用检查链接是否有效的方法
String result = get(url);
if (result != null && result.length() != 0) {
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return resultUrl;
}
//检查更新链接是否有效的方法
public static String get(String url) {
URL infoUrl = null;
InputStream inStream = null;
String line = "";
try {
infoUrl = new URL(url);
URLConnection connection = infoUrl.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
inStream = httpConnection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inStream, "utf-8"));
StringBuilder strber = new StringBuilder();
while ((line = reader.readLine()) != null)
strber.append