android外部存储读写权限问题

今天在做一个实现应用内更新的模块,在把下载的apk文件存入外部存储是遇到一个问题,最后终于解决了。现将过程记录下来。
我们知道,android分内部存储和外部存储,我们通常的理解就是除了sd卡的就是内部存储,而sd就是外部存储。现在大部分手机都没有sd卡,而是16G,8G什么的,其中并不是全部是内部存储,而是有一部分是像SD卡一样也是外部存储。
我们的应用程序就是处于内部存储,他的路径是data/data/<包名>,如果我们想把下载的文件下载在这里,调用Context类的getFileDir()就可以了,但是这样的话,该apk处于应用内部,就无法被其他应用程序使用了,使用如下代码去执行安装时,就会失败了:

/**
         * 安装新版本应用
         */
        private void installApp() throws  Exception{
            if(!file.exists()) {
                return;
            }
            // 跳转到新版本应用安装页面
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.parse("file://" + file.getPath()),"application/vnd.android.package-archive");
            context.startActivity(intent);
        }

所以我们需要下载到外部存储中,调用Context类的getExternalFilesDir()就可以了,另外需要在清单文件中添加权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
这样确实下载成功了,但是之后在华为E887(可能记错,但没关系)中出错,提示没有权限,该系统为android4.4.4 , 4G内存,并且插有2G的SD卡,我就纳闷了,我不是加了权限么?后来查阅google文档发现该方法,在android4.4以下系统中某些设备中既有外部存储(4G内存中也有外部存储),又有sd卡作为外部储存时,该方法无法获取文件的绝对路径进行读写,
可以调用Context类的getExternalFilesDirs()方法,该方法返回一个File数组,数组中的第一项被认为是主要外部存储,除非它不可用。

file=new File(context.getExternalFilesDirs(Environment.DIRECTORY_DOWNLOADS)[0],"Test.apk");

google原文如下:
Sometimes, a device that has allocated a partition of the internal memory for use as the external storage may also offer an SD card slot. When such a device is running Android 4.3 and lower, the getExternalFilesDir() method provides access to only the internal partition and your app cannot read or write to the SD card. Beginning with Android 4.4, however, you can access both locations by calling getExternalFilesDirs(), which returns a File array with entries each location. The first entry in the array is considered the primary external storage and you should use that location unless it’s full or unavailable. If you’d like to access both possible locations while also supporting Android 4.3 and lower, use the support library’s static method, ContextCompat.getExternalFilesDirs(). This also returns a File array, but always includes only one entry on Android 4.3 and lower.

另附一下下载完整代码

 /**
         * 下载新版本应用
         */
        private void downloadApp() {
            new Thread(new Runnable() {
                @TargetApi(Build.VERSION_CODES.KITKAT)
                @Override
                public void run() {
                    URL url1 = null;
                    InputStream in = null;
                    FileOutputStream out = null;
                    HttpURLConnection conn = null;
                    try {
                        url1 = new URL(url);
                        conn = (HttpURLConnection) url1.openConnection();
                        conn.connect();
                        long fileLength = conn.getContentLength();
                        in = conn.getInputStream();
                        file=new File(context.getExternalFilesDirs(Environment.DIRECTORY_DOWNLOADS)[0],"Test.apk");
                        out = new FileOutputStream(file);
                        byte[] buffer = new byte[1024];
                        int len = 0;
                        long readedLength =0;
                        while((len = in.read(buffer)) != -1) {
                            // 用户点击“取消”按钮,下载中断
                            if(isCancel) {
                                break;
                            }
                            out.write(buffer, 0, len);
                            readedLength += len;
                            curProgress = (int) (((float) readedLength / fileLength) * 100);
                            handler.sendEmptyMessage(UPDARE_TOKEN);
                            if(readedLength >= fileLength) {
                                dialog.dismiss();
                                // 下载完毕,通知安装
                                handler.sendEmptyMessage(INSTALL_TOKEN);
                                break;
                            }
                        }
                        out.flush();
                    } catch (Exception e) {

                        e.printStackTrace();
                    } finally {
                        if(out != null) {
                            try {
                                out.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if(in != null) {
                            try {
                                in.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if(conn != null) {
                            conn.disconnect();
                        }
                    }
                }
            }).start();
        }
发布了2 篇原创文章 · 获赞 1 · 访问量 8654
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览