花了两天时间,百度n多文章,终于解决了在线更新的问题,现记录下来,以备后用。
注:以下内容虽然是自己写的,但是参考了大量的网上文章理解后的内容,参考的文章太多,也搞不清楚应该写转载谁的了,就厚颜标为原创,请见谅。
整个操作步骤如下:
1. 下载配置文件,解析配置文件内容,获取版本号、描述、apk包文件。
2. 判断版本号是否高于当前正在使用的app的版本号,否则放弃更新操作。
3. 显示提示框,提示用户有新的版本,需要更新吗?
4. 下载apk文件。
5. 完成后,自动运行apk,完成更新。
前面4步操作比较简单,在第5步的时候,卡了两天时间。
1. 下载文件需要写操作权限。
1.1 在app的AndroidManifest.xml文件里,添加申明读写安装权限。
<!-- 以下权限用于读写文件,执行apk包(用于升级安装) -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
1.2 还需要在代码中申请读写权限。
if (Build.VERSION.SDK_INT >= 23) {
//android版本大于23(6.0)的,才需要此方法。
boolean _b1 = false;
if (_context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
//没有读取文件权限
_b1 = false;
}
if (_context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
//没有写文件权限;
_b1 = false;
}
if (_b1) {
//已经请求了权限的,不再执行申请操作
return;
}
String[] _ss = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
//requestCode,自定义值,用于在Activity的onRequestPermissionsResult方法中识别当前操作是否成功,这里直接使用常量101代替。
//如果不在Activity中重写onRequestPermissionsResult函数,此值就没啥意义。
ActivityCompat.requestPermissions(_context, _ss, 101);
}
2. 执行apk文件需要申明权限
2.1 在AndroidManifest.xml添加申明:AndroidManifest.xml, 上面操作步骤1.1中已经完成。
2.2 API24以后,执行apk不能使用file://开始的uri,说是不安全,所以要在AndroidManifest.xml添加FileProvider的定义。
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.trap.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/paths"/>
</provider>
注:
1) 在name项目中,旧版本使用的是:android.support.v4.content.FileProvider
2) 在authoritites一项中, com.trap 是app的包名称,后面的fileProvider也可以自定义,后面在引用的时候记得相同就好。
3) 在meta-data一项中,@xml=paths,指向的是res/xml/paths.xml文件,所以我们还需要在res下面创建一个xml文件夹,再添加一个paths.xml文件。
2.3 在res下,添加xml文件夹,并创建paths.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="." name="download" />
</paths>
</resources>
2.4 在代码中,申请执行apk的权限。
if (Build.VERSION.SDK_INT >= 26) {
boolean _b1 = _activity.getPackageManager().canRequestPackageInstalls();
if (!_b1) {
//requestCode,自定义值,用于在Activity的onRequestPermissionsResult方法中识别当前操作是否成功,这里用103代替,
//如果不在Activity中重写onRequestPermissionsResult函数,此值就没啥意义。
ActivityCompat.requestPermissions(_activity, new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 103);
//_activity.requestPermissions(new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 103);
}
}
2.5 权限已经申明(AndroidManifest.xml)了, 也向系统申请(代码)了,执行apk。
if (Build.VERSION.SDK_INT < 24) {
//android 7.0及以下版本;
Intent _intent = new Intent(Intent.ACTION_VIEW);
_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
_intent.setDataAndType(Uri.parse("file://" + _file), "application/vnd.android.package-archive");
_activity.startActivity(_intent);
} else {
//android 7.0及以上版本,需要apk安装权限;
File _apkFile = new File(_file);
if (_apkFile.isFile() && _apkFile.exists()) {
// 这里必须和AndroidManifest.xml中定义的FileProvider中内容匹配。
Uri _uri = FileProvider.getUriForFile(_activity, "com.trap.fileProvider", _apkFile);
Intent _intent = new Intent(Intent.ACTION_VIEW);
_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
_intent.setDataAndType(_uri, "application/vnd.android.package-archive");
//requestCode:1这个值是自定义的,随便填;
//如果不重写Activity的onActivityResult方法,此值没意义。
_activity.startActivityForResult(_intent, 1);
}
}
到此,在线更新基本完成。
之前想法是自动判断手机是否有SD卡,有则下载到SD卡下的download文件夹,无则下载到当前应用的cache/download文件夹下。因为使用file://描述的uri不支持解读,只能使用FileProvider.getUriForFile生成的uri,这样子的话,我就不知道在paths.xml中如何配置了,只好放弃。在getExternalStorageDirectory()下创建了download保存下载文件,这个download是否与paths.xml中的name一项有关系,没有深入研究,弄了两天,真累,就算误打误撞成功了吧。