适配Android7.0版本更新功能

来源:互联网 发布:网络销售的工作好不好 编辑:程序博客网 时间:2024/06/03 15:32

适配Android7.0版本更新功能

测试手机:华为 Android 7.0

问题1 升级安装失败,程序崩溃:

前面有一篇文章讲过了使用DownloadManager在应用内实现版本更新 详见 Android学习之—-利用DownLoadManager实现版本升级,之前Android 7.0也还没有普及所以一直没有更新代码,没注意到Android7.0的一些版本变化,导致了在Android 7.0 上面使用之前的代码更新安装程序出错,具体错误为:

     Caused by: java.lang.SecurityException: COLUMN_LOCAL_FILENAME is deprecated; use ContentResolver.openFileDescriptor() instead at android.app.DownloadManager$CursorTranslator.getString(DownloadManager.java:1503)

会抛出这样一个异常终止程序运行。那么导致整个问题的主要原因就是Android 7.0在文件管理方面更加严格,不随便对外开发文件访问权限,想要访问文件可以使用FileProvider的方式来访问,在7.0系统中,Android禁止通过file://这样的方式来访问,需要使用content://这样的方式来对文件进行访问。 所以在我之前代码中的读取文件更新就会出现这个问题,不过现在我们来对这个问题进行修复。

问题2

安装出现安装包解析异常(图片引用其他文章)

我也网上到处翻查资料 大概有这样几种情况,

1 v1,v2签名的原因,2 apk的签名不一致3 安装文件路径问题

也可以参考 android升级安装包–包解析错误 这篇文章,但是我只遇到过以上的2,3问题,其中2的问题好解决,保证签名一致即可,第3个问题,就又可以牵扯到7.0的安装路径问题上。只要能够找到正确的文件路径,那么就可以正确的安装。

解决办法:

既然知道了问题原因,那么我们就查找对应的解决办法。

第一步骤:了解FileProvider的使用 可以参考官网例子: https://developer.android.google.cn/reference/android/support/v4/content/FileProvider.html

<providerandroid:name="android.support.v4.content.FileProvider"android:authorities="com.mydomain.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-data    android:name="android.support.FILE_PROVIDER_PATHS"    android:resource="@xml/file_paths" /></provider>

第二步骤:在manifest中 application中 添加provider标签,修改provider中 android:authorities为你自己的名称 建议使用包名+fileprovider
在res文件夹下面新建一个xml目录,新建一个file_paths文件,上面meta-data中使用到的。

<paths xmlns:android="http://schemas.android.com/apk/res/android">    <external-path name="download" path=""/></paths>

上面的代码paths中不止external-path这一种标签属性,还有其他的,这里不作详细讲解,步骤一里面给出的官网地址里面解释的比我清楚,不过声明这个地址表示 在这个对应的路径下的文件都是可以被共享访问的。

第三步骤:编写代码适配 android7.0,这里我只给出下载部分和安装部分的代码,因为对比之前 Android学习之—-利用DownLoadManager实现版本升级这篇文章除了加上第一步骤和第二步骤以外,其他的就修改了以下给出的代码,

下载部分修改实现细节

1 添加下载类型 -----> request.setMimeType("application/vnd.android.package-archive");2 创建需要保存的File --->  downloadFile = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "demo.apk");3 修改------> request.setDestinationInExternalFilesDir() 为request.setDestinationUri()4 调用  request.setDestinationUri(Uri.fromFile(downloadFile));

更新安装部分实现细节修改

1 兼容7.0 ---判断系统版本2 使用FileProvider获取文件uri

具体代码

下载部分

 public void gotoUpdate(Context context, String url) {        DownloadManager downloadManager = (DownloadManager) context.getSystemService(context.DOWNLOAD_SERVICE);        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));        request.setMimeType("application/vnd.android.package-archive"); //修改        downloadFile = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "demo.apk"); //修改        request.setDestinationUri(Uri.fromFile(downloadFile)); //修改        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);        request.setTitle("下载新版本");        request.setVisibleInDownloadsUi(true);        long downloadId = downloadManager.enqueue(request);        DownCompleteReceiver downCompleteReceiver = new DownCompleteReceiver(downloadId);        context.registerReceiver(downCompleteReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));    }

兼容安装部分

 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {        Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", downloadFile); //修改  downloadFile 来源于上面下载文件时保存下来的        //  BuildConfig.APPLICATION_ID + ".fileprovider" 是在manifest中 Provider里的authorities属性定义的值        Intent installIntent = new Intent(Intent.ACTION_VIEW);        installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //临时授权        installIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);        intent.setDataAndType(uri, "application/vnd.android.package-archive");        context.startActivity(intent);    } else {        // 获取下载好的 apk 路径        String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));        // 提示用户安装        installAPP(Uri.parse("file://" + uriString), context);    }

总的步骤就是

1 manifest文件中添加Provider声明,声明好自己的authorities值,2 在res/xml 目录中新增 file_paths.xml文件,声明需要共享的文件路径3 使用DownloadManager下载文件的时候使用setDestinationUri的方式,保存事先创建的file对象,4 通过版本判断兼容Android7.0以上以及以下的版本 5 通过fileProvider获取到之前file对象的uri6 添加flag 临时授权uri权限

VersionUpdate.java 可以直接拷贝一下代码测试 只需要使用VersionUpdate.newInstance().gotoUpdate()方法即可

public class VersionUpdate {private static VersionUpdate versionUpdate = new VersionUpdate();File downloadFile;public static VersionUpdate newInstance() {    return versionUpdate;}private VersionUpdate() {}public void gotoUpdate(Context context, String url) {    DownloadManager downloadManager = (DownloadManager) context.getSystemService(context.DOWNLOAD_SERVICE);    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));    request.setMimeType("application/vnd.android.package-archive");    downloadFile = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "demo.apk");    request.setDestinationUri(Uri.fromFile(downloadFile));    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);    request.setTitle("下载新版本");    request.setVisibleInDownloadsUi(true);    long downloadId = downloadManager.enqueue(request);    DownCompleteReceiver downCompleteReceiver = new DownCompleteReceiver(downloadId);    context.registerReceiver(downCompleteReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));}public void createDialogUpdate(final Context context, final String url) {    AlertDialog.Builder alert = new AlertDialog.Builder(context);    alert.setTitle("更新提示")            .setMessage("发现新版本,是否立即更新?")            .setCancelable(false).setNeutralButton("取消", new DialogInterface.OnClickListener() {        @Override        public void onClick(DialogInterface dialog, int which) {            dialog.dismiss();        }    }).setPositiveButton("立即更新", new DialogInterface.OnClickListener() {        @Override        public void onClick(DialogInterface dialog, int which) {            gotoUpdate(context, url);            dialog.dismiss();        }    });    alert.create().show();}public class DownCompleteReceiver extends BroadcastReceiver {    long enqueueId;    public DownCompleteReceiver(long enqueueId) {        this.enqueueId = enqueueId;    }    @Override    public void onReceive(Context context, Intent intent) {        DownloadManager dm = (DownloadManager) context.getSystemService(context.DOWNLOAD_SERVICE);        long id = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID, -1);        if (enqueueId != id) {            return;        }        DownloadManager.Query query = new DownloadManager.Query();        query.setFilterById(enqueueId);        Cursor c = dm.query(query);        if (c != null && c.moveToFirst()) {            int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);            // 下载失败也会返回这个广播,所以要判断下是否真的下载成功            if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {                    Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileprovider", downloadFile);                    Intent installIntent = new Intent(Intent.ACTION_VIEW);                    installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                    installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);                    installIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);                    intent.setDataAndType(uri, "application/vnd.android.package-archive");                    context.startActivity(intent);                } else {                    // 获取下载好的 apk 路径                    String uriString = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));                    // 提示用户安装                    installAPP(Uri.parse("file://" + uriString), context);                }            }            c.close();        }    }    private void installAPP(Uri data, Context context) {        Intent promptInstall = new Intent(Intent.ACTION_VIEW)                .setDataAndType(data, "application/vnd.android.package-archive");        // FLAG_ACTIVITY_NEW_TASK 可以保证安装成功时可以正常打开 app        promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        context.startActivity(promptInstall);    }}

}

2017/9/19 22:16:41 好记性不如烂笔头。

原创粉丝点击