Android app版本更新功能模块,解决8.0及各权限问题

本篇文章主要解决app版本更新功能所遇到的一些问题,参考了一些代码,主要现在8.0所遇到的问题网上对应文章比较少,所以特意写一篇文章总结一下。

功能需求:一个带进度条的下载功能,以及下载完成后可以自动跳转安装界面。

1.下载apk文件

/**
         * 文件下载
         *
         * @param url
         */

        public void downFile (String url, String version){

            final ProgressDialog progressDialog = new ProgressDialog(getActivity());
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setTitle("正在下载");
            progressDialog.setMessage("请稍后...");
            progressDialog.setProgress(0);
            progressDialog.setMax(100);
            progressDialog.show();
            progressDialog.setCancelable(false);
            DownloadUtil.get().download(url, Environment.getExternalStorageDirectory().getAbsolutePath(), "tutor"+version + ".apk", new DownloadUtil.OnDownloadListener() {
                @Override
                public void onDownloadSuccess(File file) {
                    if (progressDialog != null && progressDialog.isShowing()) {
                        progressDialog.dismiss();
                    }
                    install(file.getAbsolutePath());
                    //下载完成进行相关逻辑操作
                }
                @Override
                public void onDownloading(int progress) {
                    progressDialog.setProgress(progress);
                }
                @Override
                public void onDownloadFailed(Exception e) {
                    TabletApp.prompt("下载异常");
                    //下载异常进行相关提示操作
                }
            });
        }

需要的下载工具类:

/**
 * 文件下载工具类(单例模式)
 * <p>
 * Created on 2017/10/16.
 */

public class DownloadUtil {
    private static DownloadUtil downloadUtil;
    private final OkHttpClient okHttpClient;

    public static DownloadUtil get() {
        if (downloadUtil == null) {
            downloadUtil = new DownloadUtil();
        }
        return downloadUtil;
    }

    private DownloadUtil() {
        okHttpClient = new OkHttpClient();
    }

    /**
     * @param url          下载连接
     * @param destFileDir  下载的文件储存目录
     * @param destFileName 下载文件名称
     * @param listener     下载监听
     */

    public void download(final String url, final String destFileDir, final String destFileName, final OnDownloadListener listener) {
        Request request = new Request.Builder().url(url).build();

        okHttpClient.newCall(request).enqueue(new Callback() {

            @Override
            public void onFailure(Call call, IOException e) {
                // 下载失败监听回调
                listener.onDownloadFailed(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                // 储存下载文件的目录

                File dir = new File(destFileDir);
                if (!Environment.getExternalStorageDirectory().canRead()){
                    TabletApp.prompt("没有权限");
                }
                if (!dir.exists()) {

                    dir.mkdirs();

                }
                File file = new File(dir, destFileName);
                try {
                    is = response.body().byteStream();
                    long total = response.body().contentLength();
                    fos = new FileOutputStream(file);
                    long sum = 0;
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                        sum += len;
                        int progress = (int) (sum * 1.0f / total * 100);
                        // 下载中更新进度条
                        listener.onDownloading(progress);
                    }
                    fos.flush();
                    // 下载完成
                    listener.onDownloadSuccess(file);
                } catch (Exception e) {
                    listener.onDownloadFailed(e);
                } finally {
                    try {
                        if (is != null)
                            is.close();
                    } catch (IOException e) {
                    }
                    try {
                        if (fos != null)
                            fos.close();
                    } catch (IOException e) {
                    }
                }
            }
        });

    }
    public interface OnDownloadListener {

        /**
         * @param file 下载成功后的文件
         */
        void onDownloadSuccess(File file);

        /**
         * @param progress 下载进度
         */
        void onDownloading(int progress);

        /**
         * @param e 下载异常信息
         */
        void onDownloadFailed(Exception e);
    }

}

2.安装方法

因为7.0 “为了提高私有文件的安全性,面向 Android 7.0 或更高版本的应用私有目录被限制访问”,所以需要授予 URI 临时访问权限。

1)在res/xml中新建一个文件file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <root-path name="root_path" path="."/>
        <external_path name="akp" path="" />
    </paths>
</resources>

 2)在AndroidManifest.xml中的application标签中添加provider的配置

<provider
            android:name="android.support.v4.content.FileProvider"
            //一般用包名,需要与下面用到的地方一致
            android:authorities="com.xxx.xxx.xxx"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

而在Android 8.0中强化了权限管理,未知来源应用权限的开关被移除掉了,取而代之的是未知来源应用的管理列表,如果你想要安装某个被自己所信任的开发者的app,则需要在每一次都手动授权"安装未知应用"的许可。

1)申请跳转权限

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

 2)跳转方法

 /**
     * 跳转到设置-允许安装未知来源-页面
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    private void startInstallPermissionSettingActivity() { //注意这个是8.0新API
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        getActivity().startActivity(intent);
    }

整合一下安装方法 

private void install (String filePath){
            Log.i(TAG, "开始执行安装: " + filePath);
            File apkFile = new File(filePath);
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                Log.w(TAG, "版本大于 N ,开始使用 fileProvider 进行安装");
                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                Uri contentUri = FileProvider.getUriForFile(
                        getActivity()
                        , "com.xxx.xxx.fileprovider"
                        , apkFile);
                intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    boolean hasInstallPermission = getContext().getPackageManager().canRequestPackageInstalls();
                    if (!hasInstallPermission) {
                        startInstallPermissionSettingActivity();

                    }
                }



            } else {
                Log.w(TAG, "正常进行安装");
                intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
            }
            try {
                getActivity().startActivity(intent);
            } catch (Exception e) {
                Log.d(TAG, e.toString());
            }
        }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private void startInstallPermissionSettingActivity() { //注意这个是8.0新API
        Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        getActivity().startActivity(intent);
    }

中间过程可能遇到的储存卡读取权限:

<!-- 写入扩展存储,向扩展卡写入数据,用于写入缓存定位数据 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- SD卡权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

还有些网络权限就不写了。第一次写文章,有写的不好的请指正。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值