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>

android BLE连接参数更新请求 安卓更新链接_数据库

三、版本信息

(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);
}