日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 自动检测版本更新(包含强制更新)并安装

發(fā)布時間:2023/12/18 Android 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 自动检测版本更新(包含强制更新)并安装 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

因為只是個demo測試,用于記錄,所以后臺使用 spring+springmvc+dbutils

數(shù)據(jù)庫部分:

就這么一個很簡單的 tb_version 表?

v_id: 主鍵

v_code:? 版本號(一般是整數(shù)數(shù)值)

v_name: 版本名稱 (如:1.0.1)

v_desc: 版本描述介紹

v_down_url: 下載地址

v_type: 0選擇性更新? ? 1代表強制更新(沒有取消按鈕)

v_date: 版本發(fā)布時間

接下來是后臺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);} }

記得改下清單文件和必要的權(quán)限

<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"/> <!-- 可以跳轉(zhuǎn)并安裝apk所需權(quán)限,不然不能兼容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() {//向后臺服務器發(fā)請求,獲取最新的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();//把服務器返回的結(jié)果轉(zhuǎn)成實體類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();//動態(tài)權(quán)限申請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();//動態(tài)權(quán)限申請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私有文件,所以需要創(chuàng)建個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下創(chuàng)建xml文件夾及文件

文件內(nèi)容為:

<?xml version="1.0" encoding="utf-8"?> <paths><!--path:需要臨時授權(quán)訪問的路徑(.代表所有路徑) name:就是你給這個訪問路徑起個名字--><external-pathname="external_files"path="." /> </paths>

至此全部搞定

效果圖:

此時的code:

當檢測到更新時:

強制版的效果圖就不展示了,點擊更新后

就會開始下載,然后開始安裝

本人個人原創(chuàng),如有雷同,純屬巧合,或者與本人聯(lián)系,做改動。請轉(zhuǎn)載或者CV組合標明出處,謝謝!(如有疑問或錯誤歡迎指出,本人QQ:752231513)

總結(jié)

以上是生活随笔為你收集整理的Android 自动检测版本更新(包含强制更新)并安装的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 在线观看成人小视频 | 中文字幕无产乱码 | 欧美激情一二区 | av资源新版在线天堂 | 日韩高清不卡在线 | 国产精品一区在线观看你懂的 | 亚洲黄色三级视频 | 精品一二三区 | 综合网视频 | 超碰在线98 | 久久不射电影网 | 日韩中文在线播放 | 亚洲综合图色40p | 成人一区二区三区 | 香蕉视频免费在线看 | 性生交大全免费看 | 久久久久黄 | 欧美成人午夜精品久久久 | 超碰95在线 | 91国产一区二区 | 欧美日本色图 | 国产av日韩一区二区三区精品 | 蜜桃久久久久久久 | 日韩成人在线影院 | 成人蜜桃av | 国产 欧美 日韩 一区 | 综合久久久久综合 | 久久精品美女视频 | 17c在线 | 成人免费视频观看 | 伊人久久一区二区三区 | 91日韩一区二区 | 亚洲国产视频在线 | 欧美一区二区在线观看 | 影音先锋中文字幕一区二区 | 超碰在线一区 | 国产18p| 极品熟妇大蝴蝶20p 国产偷自拍视频 | 精品亚洲一区二区三区四区五区高 | 成人av影视在线观看 | 欧美极品少妇xxxxⅹ免费视频 | 久久九精品 | 免费看a毛片| 日韩福利电影在线 | 久草福利资源站 | 亚洲视频456| 男女无套免费视频网站动漫 | 日韩伦理视频 | 最新地址av | 亚洲777| 久久福利影视 | 久久精品黄aa片一区二区三区 | 白浆av| xxx精品| 日本黄色视屏 | 国产一区二区伦理 | 国产啊啊啊啊 | 亚洲最新av网站 | 夜夜狠狠 | 成品人视频ww入口 | 美女免费毛片 | 黄色免费看网站 | 亚洲人视频在线 | 日本在线成人 | 久久精品国产亚洲av麻豆色欲 | 蜜臀99久久精品久久久久久软件 | 性色av一区二区三区在线观看 | 久久久久久久久久久久久女国产乱 | 国产精品三级av | 2级黄色片 | 国产精品视频在线看 | 亚洲在线激情 | 国模人体私拍xvideos | 四虎国产成人永久精品免费 | 日韩一区二区三区四区 | 福利在线一区二区 | 苍井空亚洲精品aa片在线播放 | 伊人成人在线 | 日韩欧美视频一区二区 | 色不卡 | 97人人爽人人爽人人爽 | 国产日韩中文 | 欧洲色视频| 一区二区一级片 | 人人超碰在线 | 亚洲另类一区二区 | 操碰人人 | 日本美女视频 | av成人免费 | 亚洲精品国产一区二区 | 99爱这里只有精品 | 在线毛片观看 | 亚洲三级国产 | 中文字幕av一区二区三区人妻少妇 | 超碰在线视屏 | 五月婷婷社区 | 午夜影院入口 | 精品福利三区3d卡通动漫 | 亚洲偷偷|