1、需要依赖
(1)、依赖包
implementation 'cn.bingoogolapple:bga-badgeview:1.1.2'
implementation files('libs/badgeview.jar')
jar包在下自取
链接:https://pan.baidu.com/s/1nXwSki25Ezxuh1ApRFv99g
提取码:sda8
(2)、AndroidManifest.xml修改
<!-- 应用安装权限 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<!-- application中添加provider -->
<application>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<application>
(3)、添加provider_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>
2、更新页面
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.VersionUpdateActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:layout_marginTop="0dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:id="@+id/app_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:layout_marginTop="20dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
android:gravity="center"
android:orientation="horizontal">
<!-- tools:ignore="MissingConstraints"-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="vertical" >
<TextView
android:id="@+id/app_version_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/black"
android:textSize="20dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="20dp"
android:text="版本信息"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="vertical" >
<TextView
android:id="@+id/app_version_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:textColor="@color/black"
android:textSize="16dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="5dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="20dp"
android:background="#ffffff"
android:text="现有版本"/>
<TextView
android:id="@+id/app_version_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:textColor="@color/black"
android:textSize="16dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="5dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="20dp"
android:background="#ffffff"
android:text="功能介绍"/>
<TextView
android:id="@+id/app_version_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:textColor="@color/black"
android:textSize="16dp"
android:layout_gravity="center_vertical"
android:layout_marginTop="5dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="20dp"
android:background="#ffffff"
android:text="版本更新"/>
<com.jauker.widget.BadgeView
android:id="@+id/badge_install"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:gravity="center"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
三、版本信息
(1)、当前版本信息
在build.gradle(app)里
android {
compileSdkVersion 30
buildToolsVersion "23.0.3"
defaultConfig {
versionCode 1
versionName "1.0"
}
}
(2)、获取当前版本信息
/*
* 获取当前apk版本名
*/
private String getVersionName() throws Exception {
PackageManager packageManager = getPackageManager();
PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);
return packInfo.versionName;
}
/*
* 获取当前当前apk版本号
*/
private int getVersionCode() {
PackageManager packageManager = getPackageManager();
PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);
return packInfo.versionCode;
}
(3)、获取服务器最新版本信息
设计的数据库表结构如下:
id | version_information |
1 | { “url”:“http://localhost:8080/androids/test.apk”,“versionName”:1, “versionCode”:“1.0”} |
四、比较版本号
检查当前app和服务器最新版本号,若低于当前最低版本,则显示红点。badgeView用来显示红点。
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 0:
try {
curVerCode = getVersionCode();
System.out.println("现版本号");
System.out.println(curVerCode);
} catch (Exception e) {
e.printStackTrace();
}
if (curVerCode < newVerCode) {
badgeView.setTargetView(app_version_update); //设置哪个控件显示数字提醒,参数就是一个view对象
badgeView.setText("New");//显示“New”
badgeView.setBadgeGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL); //设置badgeview的显示位置
badgeView.setBackground(12, Color.parseColor("#ff0000")); //设置badgeview的背景色
}
break;
}
}
};
五、点击红点的TextView,下载服务器apk
(1)、点击事件
app_version_update.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//如果有最新版本
if (curVerCode < newVerCode) {
showDialogUpdate();//弹出提示版本更新的对话框
} else {
//否则显示当前是最新版本
Toast.makeText(this, "当前已经是最新的版本", Toast.LENGTH_SHORT).show();
}
}
});
(2)、弹出对话框
/**
* 提示版本更新对话框
*/
private void showDialogUpdate() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 设置提示框的标题
builder.setTitle("版本升级").
// 设置提示框的图标
setIcon(R.mipmap.ic_launcher).
// 设置要显示的信息
setMessage("发现新版本!请及时更新").
// 设置确定按钮
setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
loadNewVersionProgress();//下载最新的版本程序
}
}).
// 设置取消按钮,null是什么都不做,并关闭对话框
setNegativeButton("取消", null);
// 创建对话框
AlertDialog alertDialog = builder.create();
// 显示对话框
alertDialog.show();
}
(3)、下载进度条
/**
* 下载新版本程序进度条
*/
private void loadNewVersionProgress() {
final String uri=apkurl;
final ProgressDialog pd; //进度条对话框
pd = new ProgressDialog(this);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMessage("正在下载更新");
pd.show();
//启动子线程下载任务
new Thread() {
@Override
public void run() {
try {
File file = new File(String.valueOf(getFileFromServer(uri, pd)));
sleep(3000);
installApk(file);
pd.dismiss(); //结束进度条对话框
} catch (Exception e) {
//下载apk失败
mHandler.sendEmptyMessage(0);
e.printStackTrace();
}
}
}.start();
}
(4)、从服务器下载后进行安装
/**
* 从服务器获取apk文件的代码
* 传入网址uri,进度条对象即可获得一个File文件
* (要在子线程中执行哦)
* @return
*/
public File getFileFromServer(String uri, ProgressDialog pd) throws Exception {
//如果相等的话表示当前的sdcard挂载在手机上并且是可用的
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
URL url = new URL(uri);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
//获取到文件的大小
pd.setMax(conn.getContentLength());
InputStream is = conn.getInputStream();
long time = System.currentTimeMillis();//当前时间的毫秒数
File dir = new
File(Environment.getExternalStoragePublicDirectory("/Download").getAbsolutePath());
System.out.println(dir);
if (!dir.exists()){
dir.mkdir();
System.out.println("创建目录");
}
//创建文件
File file = new File(dir+"/"+"SmartPir.apk");
if (!file.exists()){
file.createNewFile();
}
else
{
file.delete();
file.createNewFile();
}
System.out.println(file);
FileOutputStream fos = new FileOutputStream(String.valueOf(file));
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buffer = new byte[1024];
int len;
int total = 0;
while ((len = bis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
total += len;
//获取当前下载量
pd.setProgress(total);
}
fos.close();
bis.close();
is.close();
return file;
} else {
return null;
}
}
(5)、进行安装过程
/**
* 安装apk
* @param apkPath
* @return
*/
protected boolean installApk(File apkPath) {
Intent intent= new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >=24) {
File file1= (new File(String.valueOf(apkPath)));
//设置intent的标签
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//参数1:上下文, 参数2:Provider主机地址 和配置文件中保持一致,参数3:共享的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
Uri apkUri = FileProvider.getUriForFile(VersionUpdateActivity.this, "com.update.MyFileProvider", file1);//添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.setDataAndType(apkUri,"application/vnd.android.package-archive");
}else{
intent.setDataAndType(Uri.fromFile(new File(String.valueOf(apkPath))),"application/vnd.android.package-archive");
}
VersionUpdateActivity.this.startActivity(intent);
return false;
}
(6)、获取权限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == 1000)
{
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
{
//同意申请权限
} else
{
// 用户拒绝申请权限
Toast.makeText(VersionUpdateActivity.this,"请同意写操作", Toast.LENGTH_SHORT).show();
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}