Android 自动检测版本更新(包含强制更新)并安装
因為只是個demo測試,用于記錄,所以后臺使用 spring+springmvc+dbutils
數據庫部分:
就這么一個很簡單的 tb_version 表?
v_id: 主鍵
v_code:? 版本號(一般是整數數值)
v_name: 版本名稱 (如:1.0.1)
v_desc: 版本描述介紹
v_down_url: 下載地址
v_type: 0選擇性更新? ? 1代表強制更新(沒有取消按鈕)
v_date: 版本發布時間
接下來是后臺java部分:
@RestController @RequestMapping("/app") public class AppVersionController {@AutowiredQueryRunner qr;@RequestMapping("/version")public ResultBean checkVersion() throws Exception{ResultBean rb=new ResultBean();rb.setCode(1);String sql="select *from tb_version order by v_date desc limit 1";VersionBean vBean=qr.query(sql, new BeanHandler<VersionBean>(VersionBean.class));rb.setCode(0);rb.setData(vBean);return rb;}}很簡單就是查詢出最新的一條返回給客戶端
安卓端代碼
布局文件xml:? activity_main.xml
這里就一個文本控件,到時候用來顯示當前的版本號 和 版本名稱
<?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=".MainActivity"><TextViewandroid:id="@+id/tv_version"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>這里用了okgo請求框架,
implementation 'com.jakewharton:butterknife:10.2.1'annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'implementation 'com.lzy.net:okgo:3.0.4'implementation 'com.google.code.gson:gson:2.8.5'所以自定義個MyApplication來初始化
package com.ls.myversion;import android.app.Application;import com.lzy.okgo.OkGo;public class MyApplication extends Application {@Overridepublic void onCreate() {super.onCreate();//初始化okgoOkGo.getInstance().init(this);} }記得改下清單文件和必要的權限
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 可以跳轉并安裝apk所需權限,不然不能兼容8.0 --> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/><applicationandroid:name=".MyApplication".../>編寫對應的實體類VersionBean.class
public class VersionBean {private int v_code;private String v_name;private String v_desc;private String v_down_url;private int v_type;private String v_date;//省略get,set,toString() }安卓端核心代碼:
package com.ls.myversion;import android.Manifest; 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.util.Log; import android.widget.TextView; import android.widget.Toast;import com.google.gson.Gson; import com.lzy.okgo.OkGo; import com.lzy.okgo.callback.FileCallback; import com.lzy.okgo.callback.StringCallback; import com.lzy.okgo.model.Response;import org.json.JSONObject;import java.io.File;import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import butterknife.BindView; import butterknife.ButterKnife;public class MainActivity extends AppCompatActivity {@BindView(R.id.tv_version)TextView tvVersion;private Integer v_code;private String v_name;AlertDialog dialog=null;private VersionBean vb;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);//讀取當前版本的versionCode和versionNamePackageInfo pf=getMyVersion();v_code=pf.versionCode;v_name=pf.versionName;//顯示在文本空間上tvVersion.setText(v_code+"=="+v_name);//檢測是否需要更新apkcheckVersion();}private void checkVersion() {//向后臺服務器發請求,獲取最新的apk信息OkGo.<String>get("http://192.168.0.107:8080/xxxxx/app/version").execute(new StringCallback() {@Overridepublic void onSuccess(Response<String> response) {//請求成功時String result=response.body();try {JSONObject jsonObject=new JSONObject(result);int code=jsonObject.getInt("code");if (code==0){Gson gson=new Gson();//把服務器返回的結果轉成實體類vb=gson.fromJson(jsonObject.getString("data"),VersionBean.class);//判斷服務器返回的本版號是否大于當前的版本號if (vb.getV_code()>v_code){//大于則更新,然后判斷是可以取消的選擇性更新還是沒有取消按鈕的強制更新if (vb.getV_type()==0){showSelectDialog(vb);}else {//強制更新showMustDialog(vb);}}//不大于什么都不做...}}catch (Exception e){e.printStackTrace();}}});}//強制更新時的操作(彈出diglog)private void showMustDialog(VersionBean vb) {AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this);builder.setCancelable(false);String apkUrl=vb.getV_down_url();builder.setTitle("版本更新").setMessage(vb.getV_desc()).setPositiveButton("更新", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {dialog.dismiss();//動態權限申請if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);} else {if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);} else {showDownProgressDialog(vb);}}}});dialog=builder.create();dialog.show();}//下載彈窗private void showDownProgressDialog(VersionBean vb) {ProgressDialog pd=new ProgressDialog(MainActivity.this);pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);pd.setMessage("正在下載安裝包,請稍等...");pd.setCancelable(false);pd.show();String path= getSdPath()+"/download";OkGo.<File>get(vb.getV_down_url()).execute(new FileCallback(path,"自己命名的新名字.apk") {@Overridepublic void onSuccess(Response<File> response) {Toast.makeText(MainActivity.this,"下載成功!",Toast.LENGTH_SHORT).show();pd.dismiss();installApk(new File(path+"/自己命名的新名字.apk"));}});}private void installApk(File apk) {Intent intent=new Intent();intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.setAction(Intent.ACTION_VIEW);Uri apkFileUri;if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){apkFileUri= FileProvider.getUriForFile(MainActivity.this,BuildConfig.APPLICATION_ID+".provider",apk);}else{apkFileUri=Uri.fromFile(apk);}intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);intent.setDataAndType(apkFileUri,"application/vnd.android.package-archive");Log.i("tag","開始安裝");try {MainActivity.this.startActivity(intent); // finish();}catch (Exception e){e.printStackTrace();}}private String getSdPath(){File sdDir = null;boolean sdCardExist=Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);if (sdCardExist){sdDir=Environment.getExternalStorageDirectory();}return sdDir.toString();}private void showSelectDialog(VersionBean vb) {AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this);builder.setCancelable(false);String apkUrl=vb.getV_down_url();builder.setTitle("版本更新").setMessage(vb.getV_desc()).setPositiveButton("更新", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {dialog.dismiss();//動態權限申請if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);} else {if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);} else {showDownProgressDialog(vb);}}}}).setNegativeButton("取消", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialogInterface, int i) {dialog.dismiss();}});dialog=builder.create();dialog.show();}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {switch (requestCode) {case 1:if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);} else {showDownProgressDialog(vb);}} else {Toast.makeText(this, "你拒絕了無法下載喲!", Toast.LENGTH_SHORT).show();}break;default:}}private PackageInfo getMyVersion() {PackageInfo pf=null;try {PackageManager pm=getPackageManager();pf=pm.getPackageInfo(getPackageName(),0);}catch (Exception e){e.printStackTrace();}return pf;} }由于安卓7.0以后使用FileProvider訪問sdk私有文件,所以需要創建個FileProvider
1.在清單文件中這樣來寫
<applicationandroid:name=".MyApplication"android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.MyVersion"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><providerandroid:name="androidx.core.content.FileProvider"android:authorities="自己的包名(com.ls.myversion).provider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/provider_paths" /></provider></application>2.在res下創建xml文件夾及文件
文件內容為:
<?xml version="1.0" encoding="utf-8"?> <paths><!--path:需要臨時授權訪問的路徑(.代表所有路徑) name:就是你給這個訪問路徑起個名字--><external-pathname="external_files"path="." /> </paths>至此全部搞定
效果圖:
此時的code:
當檢測到更新時:
強制版的效果圖就不展示了,點擊更新后
就會開始下載,然后開始安裝
本人個人原創,如有雷同,純屬巧合,或者與本人聯系,做改動。請轉載或者CV組合標明出處,謝謝!(如有疑問或錯誤歡迎指出,本人QQ:752231513)
總結
以上是生活随笔為你收集整理的Android 自动检测版本更新(包含强制更新)并安装的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网站备案 服务器变更,网站变更服务器备案
- 下一篇: gcd