「Android」应用内升级,适配6.0及以上,附源码_知乎_

2022-04-14 0 443

多源影视搜索
应用内升级主要分为两部分:下载和安装,以下按照这两部分开始讲述,文章最后会附上全代码。 文中部分xxx需要替换成对应的包名或apk名称1. 权限配置 AndroidManifest.xml权限请求<uses-permission android:name=”android.permission.REQUEST_INSTALL_PACKAGES” /> <uses-permission android:name=”android.permission.ACCESS_DOWNLOAD_MANAGER” />provider配置,针对6.0以上系统<application …. <provider android:name=”androidx.core.content.FileProvider” android:authorities=”包名.fileprovider” android:exported=”false” android:grantUriPermissions=”true”> <meta-data android:name=”android.support.FILE_PROVIDER_PATHS” android:resource=”@xml/file_paths” /> </provider> …. </application>res/xml 新建一个 file_paths.xml 文件(如果没有就创建文件夹再创建文件)1. 具体 external-path 和 external-files-path 用法我也不是很懂[捂脸],建议直接google用法。2. 我下载时的路径是 getExternalFilesDir 设置的路径,按下面的方式写没有问题。<?xml version=”1.0″ encoding=”utf-8″?> <resources> <paths> <external-path name=”external_files_path” path=”Android/data”/> </paths> </resources>2. 下载Apk

配置没问题后,开始正式写代码,检查版本更新调用接口就不写了,按自己需求写,只挑重点讲述。

步骤检查版本更新对比版本号/** * 版本号比较 * * @param version1 服务器版本号 * @param version2 当前版本号 * @return 0代表相等,1代表version1大于version2,-1代表version1小于version2 */ private 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; } }

3. 展示版本更新提示

4. 检查权限是否开启(安装未知来源应用)

//版本判断 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //获取是否有安装未知来源应用的权限 haveInstallPermission = mContext.getPackageManager().canRequestPackageInstalls(); } if (!haveInstallPermission) { Toast.makeText(mContext, “请打开安装未知来源应用的权限”, Toast.LENGTH_SHORT).show(); Uri packageURI = Uri.parse(“package:” + mContext.getPackageName()); Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI); mContext.startActivityForResult(intent, requestCode); } // 在Activity中接收下载完成的回调 @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); // 请求完安装权限后的回调 if (requestCode == WBVersionUpdateManager.WBVersionUpdateManagerPermissionCode && getPackageManager().canRequestPackageInstalls()) { versionUpdateManager.downloadAPK(versionUpdateManager.updateVersion, versionUpdateManager.downloadURL); } }

5. 在activity中注册和取消注册广播 否则收不到下载完成通知

// 注册广播 downloadManagerReceiver = new DownloadManagerReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE); context.registerReceiver(downloadManagerReceiver, intentFilter); //解除注册 context.unregisterReceiver(downloadManagerReceiver); /** * 广播接收器 */ public class DownloadManagerReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // 下载完成 if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { //获取 downloadmanager 下载任务id long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); //安装应用 mListener.downloadCompleted(); } } }

6. 通知和权限问题写好后,开始正式下载Apk,使用原生的DownloadManager

public void downloadAPK(String updateVersion, String downloadURL) { Toast.makeText(mContext, “正在下载….”, Toast.LENGTH_LONG).show(); downloadManager = (DownloadManager)mContext.getSystemService(DOWNLOAD_SERVICE); //已存在 — 删除 File apkFile = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), “xxx.apk”); if (apkFile != null && apkFile.exists()) { apkFile.delete(); } DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadURL)); // 完成后显示通知栏 request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //设置存储路径 –这个是应用专用的,软件卸载后,下载的文件将随着卸载全部被删除 request.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, “xxx.apk”); //设置 文件类型 request.setMimeType(“application/vnd.android.package-archive”); downloadManager.enqueue(request); }3. 安装Apk

下载完成后,可以直接执行安装操作了

步骤找到下载的路径Uri,需要适配6.0和以上版本,因为获取Uri的方式变了。安装,通过 activity.startActivity(intent) 直接完成安装。private Uri getUri() { Uri uri; File file_save = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString()+”/xxx.apk”); if (Build.VERSION.SDK_INT >= 24) { // 适配android7.0 ,不能直接访问原路径 // 需要对intent 授权 uri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + “.fileprovider”, file_save); } else { uri = Uri.fromFile(file_save); } return uri; } public void install(Activity activity) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(getUri(), “application/vnd.android.package-archive”); activity.startActivity(intent); }4. 错误解析

在做需求时碰到了两种错误,下面一一对应讲解:

“解析包异常”

大概率是路径问题,这里分两种情况解决:

1. 首先试试 6.0 版本是否有问题,如果有问题,说明是下载和安装时的路径填写不对,可以打印出来看看。

2. 试试 6.0 以上版本是否有问题,这种情况出问题的较多,原因可能是:

1. AndroidManifest.xml 中写的 fileprovider 不对

2. files_path.xml 文件写的不对

3. 下载的路径不对(如果6.0系统都没问题,这个应该也没问题)

4. 获取Uri的时候不对

以上问题最有效的方式还是分别把下载的路径和Uri打印出来,一目了然。

“安装错误”

恭喜!看到这个提示证明之前所有步骤都没问题,只是打包方式不同罢了,比如手机上安装的是AS运行的包,服务器上是打的 release 包。

打一个低版本的release包安装在手机上,打一个高版本的放服务器上即可

5. WBVersionUpdateManager源码「Android」应用内升级,适配6.0及以上,附源码_知乎_只需在 Activity 里调用一个 checkUpdateVersion() 方法即可。在 Activity 的 onResume() 和 onPause() 里分别调用 注册广播 和 解除广播 的方法在 Activity 的 onActivityResult 里做 “安装未知来源”权限的操作 (本操作暂时只能通过跳转方式,不能通过动态请求方式,并且返回后,应再次判断一下权限是否打开,再进行下一步操作)// 安装未知来源权限判断 getPackageManager().canRequestPackageInstalls()源码:WBVersionUpdateManager.java/**************************************************** * * @class: WBVersionUpdateManager * @desc: 版本更新管理类 * @date: 2/26/21 10:20 AM * * @author: wenbin * ****************************************************/ /** * 版本更新管理类 * 用法: * 1. 初始化 WBVersionUpdateManager * 2. 在activity的 onResume() 中调用 registerDownloadBroadcast注册广播 * 3. 在activity的 onPause() 中调用 unregisterDownloadBroadcast解除注册广播 * 4. 在初始化回调接口中处理 没有权限 和 下载完成 的处理 *(1) 没有权限: 跳转系统应用设置页面 *(2) 下载完成: 调用 install()方法安装apk, 如果没有注册广播收不到监听 */ public class WBVersionUpdateManager { /*没有权限请求时的requestCode*/ public static int WBVersionUpdateManagerPermissionCode = 010; /*传入的context*/ private Context mContext; /*监听listener*/ private WBVersionUpdateManager.versionUpdateListener mListener; /*最新的版本号*/ public String updateVersion; /*下载链接*/ public String downloadURL; /*是否有安装apk的权限*/ private Boolean haveInstallPermission = true; /*下载apk的manager*/ private DownloadManager downloadManager; /*下载完成的接收器*/ private DownloadManagerReceiver downloadManagerReceiver; /** * 初始化 * @param context context * @param listener listener */ public WBVersionUpdateManager(Context context, WBVersionUpdateManager.versionUpdateListener listener) { this.mContext = context; this.mListener = listener; } /** * 检查版本更新 */ public void checkUpdateVersion() { // 等于1意味着服务器版本号大于当前版本号, 需要弹出提示更新 // 如果弹出过当前最新版本的提示, 则不再弹出 if (compareVersion(updateVersion, versionName) == 1) { //版本判断 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //获取是否有安装未知来源应用的权限 haveInstallPermission = mContext.getPackageManager().canRequestPackageInstalls(); } showUpdateTipdialog(updateVersion, summary, downloadURL); } else { mListener.alreadyLastVersion(); } } /** * 版本号比较 * * @param version1 服务器版本号 * @param version2 当前版本号 * @return 0代表相等,1代表version1大于version2,-1代表version1小于version2 */ private 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; } } /** * 展示版本更新提示 * @param serverVersion 服务器版本号 * @param updateSummary 更新内容 * @param downloadURL 下载url */ private void showUpdateTipdialog(String serverVersion, String updateSummary, String downloadURL) { int mCurrentDialogStyle = com.qmuiteam.qmui.R.style.QMUI_Dialog; new QMUIDialog.MessageDialogBuilder(mContext) .setTitle(“检查到有新版本”) .setMessage(serverVersion + “\n” + updateSummary) .setCanceledOnTouchOutside(false) .setSkinManager(QMUISkinManager.defaultInstance(mContext)) .addAction(“取消”, new QMUIDialogAction.ActionListener() { @Override public void onClick(QMUIDialog dialog, int index) { mListener.clickCancel(); dialog.dismiss(); } }) .addAction(0, “立即更新”, QMUIDialogAction.ACTION_PROP_POSITIVE, new QMUIDialogAction.ActionListener() { @RequiresApi(api = Build.VERSION_CODES.O) @Override public void onClick(QMUIDialog dialog, int index) { dialog.dismiss(); XLog.d(“点击立即更新”); if (!haveInstallPermission) { Toast.makeText(mContext, “请打开安装未知来源应用的权限”, Toast.LENGTH_SHORT).show(); Uri packageURI = Uri.parse(“package:” + mContext.getPackageName()); Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageURI); mListener.haveNoInstallPermission(intent, WBVersionUpdateManagerPermissionCode); }else { //下载更新 downloadAPK(serverVersion, downloadURL); } } }) .create(mCurrentDialogStyle).show(); } /** * 下载apk并安装 * @param updateVersion 最新版本 * @param downloadURL 下载url */ public void downloadAPK(String updateVersion, String downloadURL) { if (updateVersion == null || downloadURL == null) { return; } Toast.makeText(mContext, “正在下载….”, Toast.LENGTH_LONG).show(); downloadManager = (DownloadManager)mContext.getSystemService(DOWNLOAD_SERVICE); //已存在 — 删除 File apkFile = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), “xxx.apk”); if (apkFile != null && apkFile.exists()) { apkFile.delete(); } //下载 (AppCont.Update_URL 是你的app下载地址) DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadURL)); // 完成后显示通知栏 request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //设置存储路径 –这个是应用专用的,软件卸载后,下载的文件将随着卸载全部被删除 request.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, “xxx.apk”); //设置 文件类型 request.setMimeType(“application/vnd.android.package-archive”); downloadManager.enqueue(request); } /** * 安装apk */ public void install(Activity activity) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(getUri(), “application/vnd.android.package-archive”); activity.startActivity(intent); } /** * 获取下载的apk的Uri地址 * @return Uri地址 */ private Uri getUri() { Uri uri; File file_save = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString()+”/xxx.apk”); if (Build.VERSION.SDK_INT >= 24) { // 适配android7.0 ,不能直接访问原路径 // 需要对intent 授权 uri = FileProvider.getUriForFile(mContext, mContext.getPackageName() + “.fileprovider”, file_save); } else { uri = Uri.fromFile(file_save); } XLog.d(uri); return uri; } /** * 注册广播 * @param context context */ public void registerDownloadBroadcast(Context context) { //注册广播 downloadManagerReceiver = new DownloadManagerReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE); context.registerReceiver(downloadManagerReceiver, intentFilter); } /** * 取消注册广播 * @param context context */ public void unregisterDownloadBroadcast(Context context) { //解除注册 context.unregisterReceiver(downloadManagerReceiver); } /** * 广播接收器 */ public class DownloadManagerReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); //下载完成 if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) { //获取 downloadmanager 下载任务id long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); //安装应用 mListener.downloadCompleted(); } } } /** * manager的回调接口 */ public interface versionUpdateListener { /** * 没有安装权限 */ void haveNoInstallPermission(Intent intent, int requestCode); /** * 下载完成 */ void downloadCompleted(); /** * 已经是最新版本 */ void alreadyLastVersion(); /** * 点击取消 */ void clickCancel(); } }源码:Activiy里的用法@Override protected void onCreate(Bundle savedInstanceState) { /*初始化检查更新manager*/ versionUpdateManager = new WBVersionUpdateManager(MainActivity.this, new WBVersionUpdateManager.versionUpdateListener() { @Override public void haveNoInstallPermission(Intent intent, int requestCode) { MainActivity.this.startActivityForResult(intent, requestCode); } @Override public void downloadCompleted() { versionUpdateManager.install(MainActivity.this); } @Override public void alreadyLastVersion() { XLog.d(“已是最新版本”); } @Override public void clickCancel() { XLog.d(“点击取消”); } }); /*检查更新*/ versionUpdateManager.checkUpdateVersion(); } @Override protected void onResume() { super.onResume(); // 注册下载更新的广播 versionUpdateManager.registerDownloadBroadcast(MainActivity.this); } @Override protected void onPause() { super.onPause(); //解除注册 versionUpdateManager.unregisterDownloadBroadcast(MainActivity.this); } @RequiresApi(api = Build.VERSION_CODES.O) @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); // 请求完安装权限后的回调 if (requestCode == WBVersionUpdateManager.WBVersionUpdateManagerPermissionCode && getPackageManager().canRequestPackageInstalls()) { versionUpdateManager.downloadAPK(versionUpdateManager.updateVersion, versionUpdateManager.downloadURL); } }
易优cms博客模板

苹果CMS模板 杂七杂八 「Android」应用内升级,适配6.0及以上,附源码_知乎_ https://www.pgcms.net/1889.html

常见问题
  • 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。
查看详情
  • 最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或联络我们。
查看详情

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务