当前位置:网站首页>使用OKGO进行软件版本更新、下载、安装等操作
使用OKGO进行软件版本更新、下载、安装等操作
2022-07-21 10:32:00 【nanjumufeng】
在各大APP软件中都含有一个功能,就是在软件中进行检查软件版本号,并进行下载安装的操作。
今天,我也记录一下,我使用OkGo网络协议进行软件版本更新的操作。
一、基础配置
1.如果安卓版本号是安卓9或更高版本,如要在application中添加
android:usesCleartextTraffic=“true” 。这句话。因为在安卓高版本中,谷歌对设备访问网络做了限制,具体原因可以去查询。
2. 在Mainfest.xml中,添加权限。
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!--下面这个权限一定还要添加,否则程序不会自动安装-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
开启未知应用安装权限的入口,并设置允许安装。
3.创建一个空类,继承自FileProvider
//空类
public class MyFileProvider extends FileProvider {
}
4.创建res/xml/fiel_path.xml文件
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 其中external-path节点表示Environment.getExternalStorageDirectory()路径
path表示apk文件在Environment.getExternalStorageDirectory()路径下的文件夹名称-->
<external-path name="external_storage_root" path="download" />
</paths>
5.清单文件中添加provider
<provider
android:name="com.example.updatesoft.MyFileProvider"
android:authorities="${applicationId}.MyFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
二.在MainActivity的布局文件中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<!--更新按钮-->
<TextView
android:id="@+id/text_iew"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="更新软件按钮"
android:layout_gravity="center"
android:layout_marginTop="50dp"
android:background="@drawable/bg_button_pressed"
android:padding="10dp"/>
<!--版本信息-->
<TextView
android:id="@+id/version_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="这是1.0版本"
android:layout_marginTop="50dp"/>
<!--下载进程圆圈-->
<ProgressBar
android:id="@+id/progress_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:visibility="gone"/>
<!--下载进程-->
<TextView
android:id="@+id/tvDownloadSize"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text=""
android:layout_marginTop="50dp"/>
</LinearLayout>
三.安卓6.0之后需要动态添加权限,需要访问本地文件
//android6.0之后要动态获取权限
private void checkPermission(Activity activity) {
// Storage Permissions
final int REQUEST_EXTERNAL_STORAGE = 1;
String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
try {
//检测是否有写的权限
int permission = ActivityCompat.checkSelfPermission(MainActivity.this,
"android.permission.WRITE_EXTERNAL_STORAGE");
if (permission != PackageManager.PERMISSION_GRANTED) {
// 没有写的权限,去申请写的权限,会弹出对话框
ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
四.进行版本号比较
获取本地的版本号与云端版本号。通过比较两个版本号信息,判断时候需要进行版本更新操作。如果本地的版本号小于云端版本号,就可以进行下载并安装的操作。但是本地的版本号与云端版本号相同,就无需进行下载安装,并可以对用户进行提示。
获取本地版本号的方法:
/** * 获取当前软件版本信息 * 根据包名获取应用程序相关信息 * flags:指定信息的标签,指定了标签就会获取相应的相关信息 * getPackageName():获取应用程序的包名 */
public static String getPresentVersion(Context context) {
String presentVersion = "";
PackageManager packageManager = context.getPackageManager(); //包的管理者,获取应用程序中清单文件中的信息
try {
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
presentVersion = packageInfo.versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace(); //找不到包的异常
}
return presentVersion;
}
版本号比较大小的方法:
/** * 版本号比较 * 0代表相等,1代表version1大于version2,-1代表version1小于version2 * * @param version1 * @param version2 * @return */
private static int compareVersion(String version1, String version2) {
if (version1.equals(version2)) {
return 0;
}
String[] version1Array = version1.split("\\.");
String[] version2Array = version2.split("\\.");
int index = 0;
// 获取最小长度值
int minLen = Math.min(version1Array.length, version2Array.length);
int diff = 0;
// 循环判断每位的大小
while (index < minLen
&& (diff = Integer.parseInt(version1Array[index])
- Integer.parseInt(version2Array[index])) == 0) {
index++;
}
if (diff == 0) {
// 如果位数不一致,比较多余位数
for (int i = index; i < version1Array.length; i++) {
if (Integer.parseInt(version1Array[i]) > 0) {
return 1;
}
}
for (int i = index; i < version2Array.length; i++) {
if (Integer.parseInt(version2Array[i]) > 0) {
return -1;
}
}
return 0;
} else {
return diff > 0 ? 1 : -1;
}
}
通过OkGo获取云端版本号并进行版本比较的方法
public void upApk(){
//StyledDialog.buildMdLoading("正在获取新版本信息,请稍等").show();
OkGo.<String>post("这里填写获取APK的云端服务器地址")
.tag(this)
.params("appId","1") //向服务器传送请求appId为1的软件信息,这里根据自己的实际情况进行填写。
.execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(response.body());
String dataStr = jsonObject.getString("data");
JSONObject dataObj = new JSONObject(dataStr);
String cloudVersion = dataObj.getString("version"); //获取云端版本号
String presentVersion = getPresentVersion(MainActivity.this);
String apkPath=dataObj.getString("apk");//获取云端软件的下载地址
if (compareVersion(presentVersion,cloudVersion)==-1) {
//比较两个版本号,判断是否需要下载
Toast.makeText(MainActivity.this, "可以更新", Toast.LENGTH_LONG).show();
downloadApk(apkPath);
}else{
Toast.makeText(MainActivity.this, "已是最新版本", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onError(Response<String> response) {
Toast.makeText(MainActivity.this, "访问出错了", Toast.LENGTH_LONG).show();
super.onError(response);
}
@Override
public void onFinish() {
super.onFinish();
//StyledDialog.dismissLoading(MainActivity.this);
}
});
}
五.下载APK
/** * @description 下载APK */
public void downloadApk(String apkPath){
String headStr = "这里填写获取APK的云端服务器地址";
final String downloadFile = headStr + apkPath;
final String filePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/download"; //APK的下载目录
final String fileName = "abc.apk"; //下载的APK的新文件名
file = new File(filePath + "/" + fileName);
file = new File(filePath);
if (file.exists())
file.delete();
final Context finalContext = context;
OkGo.<File>post(downloadFile)
.tag(context)
.execute(new FileCallback(filePath,fileName) {
@Override
public void onSuccess(Response<File> response) {
String absolutePath = response.body().getAbsolutePath();
File apkFile = response.body().getAbsoluteFile();
}
//@Override
@SuppressLint("SetTextI18n")
public void downloadProgress(Progress progress) {
super.downloadProgress(progress);
//如何拿到当前的下载进度
progressBar.setVisibility(View.VISIBLE);
//progressBar.setProgress((int)(progress.fraction*100));
//这里回调下载进度(该回调在主线程,可以直接更新ui)
//currentSize totalSize以字节byte为单位
Log.e("currentSize", String.valueOf(progress.currentSize)); //当前下载大小
Log.e("totalSize", String.valueOf(progress.totalSize)); //APK总的大小值
Log.e("speed", String.valueOf(progress.speed)); //下载速度
tvDownloadSize.setText(progress.currentSize + "/" + progress.totalSize);
if (progress.currentSize==progress.totalSize){
progressBar.setVisibility(View.GONE);
installApk(); //下载完后进行安装APK
}
}
});
}
六.安装APK
private void installApk() {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String type = "application/vnd.android.package-archive";
Uri uri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(MainActivity.this, "com.example.updatesoft.MyFileProvider",getApkFile());
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
uri = Uri.fromFile(getApkFile());
}
intent.setDataAndType(uri, type);
MainActivity.this.startActivity(intent);
}
获取本地APK文件
/** * 获取本地Apk文件 */
private static File getApkFile() {
String apkDir = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator
+ "download" + File.separator;
String apkName = "abc.apk";
File newApkFile = new File(apkDir, apkName); //File()的第一个参数为文件的父路径,第二个参数是文件名
return newApkFile;
}
整个操作流程到此就完成了。
边栏推荐
- CMake系列教程2-HelloWorld
- Why use new instead of malloc when dynamically creating objects
- Packet format of network packets
- CodeQL使用流程
- String类常用方法
- 高效开发工具使用技巧
- 【机器学习】Kmeans聚类
- Introduction and simple application of CGI
- [numpy learning record] np CoV detailed explanation
- MySQL 45 Lecture Notes - string prefix index & MySQL dirty page analysis
猜你喜欢
随机推荐
[paper notes] objectbox: from centers to boxes for anchor free object detection
Virbox 编译器,支持全平台全架构的源代码加密
剑指 Offer 50. 第一个只出现一次的字符
看界面控件DevExpress WinForms——如何自定义辅助功能属性(下)
剑指 Offer 49. 丑数
[machine learning] dimension reduction technology PCA
js教程实践(JS基础)
Alibaba Cloud Toolkit一键自动部署jar包
游戏中的数学之3D基础
剑指 Offer 40. 最小的k个数
centos7安装mysql5.7全过程及各种问题解答
【机器学习】NMF(非负矩阵分解)
剑指 Offer 48. 最长不含重复字符的子字符串
剑指 Offer 42. 连续子数组的最大和
同一个Activity中不同Fragment的数据传递
极化SAR——极化椭圆
Application of workflow engine in vivo marketing automation | engine 03
6.0系统中Fragment请求权限所踩过的坑
问一下REITs是什么呢?请问,手机开户股票开户安全吗?
网络开发包 libpcap