Android打开相册,上传文件

 

最近我最了一个上传文件的功能在这个过程我发现了一个问题,不管我用系统的意图获取还是用第三方框架获取,最终的onActivityResult回调中返回的路径都是一个被系统加密过的路径,导致我上传的时候总是失败的.下面我通过获取加密的和我解决问题后转换的给大家看一下

64194d0a58054cbba67c0a71a26229c7.png

 这个就是在没有转换的时候返回的路径,这种的路径我目前没有查资料看过,但我想应该就是sdk对这些路径进行了加密后的路径

我们接下来对他进行一个转换

首先我们在方法获取按钮的点击事件中写

String  mFilePath = context.getExternalFilesDir(Environment.DIRECTORY_DCIM).getPath()+"/" ;
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        File path = new File(mFilePath);
        try {
            if (!path.exists()) {
                path.mkdirs();
            }
            //随便定义的名字,
            String mFileName = System.currentTimeMillis()+"png";
            File file = new File(path, mFileName);
            if (file.exists()) {
                //用完即删
                file.delete();
            }
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
            intent.setType("*/*");
            intent.putExtra(MediaStore.EXTRA_OUTPUT, getUriForFile(context, file));
            intent.addCategory(Intent.CATEGORY_OPENABLE);

            context.startActivityForResult(intent, 101);
        }catch (Exception e){

        }

我这里呢是一个多选和全部的样式,如果说你们的需求只是上传图片,你可以将intent.setType("*image/*") 单选是把这行代码注释掉intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

 //清单文件 设置读取文件权限
    public static Uri getUriForFile(Context context, File file) {
        if (context == null || file == null) {
            throw new NullPointerException();
        }
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {
            uri = FileProvider.getUriForFile(context, "an.jian.project", file);
            Log.e("文件真实路径", "外部存储可用..." + uri.toString());
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }

这里是重点,看到我们上边的代码中有清单文件,getURIForFeit中传了一个context一个是类的名称,另一个是我们的文件,那个这个an.jian.project是从哪里来的呢

我们需要打开清单文件AndroidManifest.xml,然后写下面的代码

因为我的项目是老项目了,所有包是v4的包,我给大家再写一个AndroidX的

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="an.jian.project"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

这个是AndroidX的

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.myFileProvider"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/my_file_paths"
                tools:replace="android:resource" />
        </provider>

其中呢会有一个resource是xml中的,大家应该都看到了这个是需要我们自己创建的

在res文件夹下创建一个xml文件夹,然后创建一个对应名称的xml就可以了

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- path=""代表根目录,也可以指定特定目录,name="camera_picture"是虚拟目录camera_picture -->

    <!--指定共享目录-->
    <paths>
        <external-path
            name="files"
            path="" />

        <root-path
            name="root"
            path="" />

        <files-path
            name="files"
            path="" />

        <cache-path
            name="cache"
            path="" />

        <!--<external-path
            name="external"
            path=""/>-->

        <external-files-path
            name="external_file_path"
            path="" />

        <external-cache-path
            name="external_cache_path"
            path="" />
    </paths>

</resources>

这个文件是通用的不存在v7 v4的老项目不能用

然后我们在app中需要通过回调写一个获取数据

if (requestCode == 101) {
            final List<File> file = uriToFileApiQ(data);

            List<MultipartBody.Part> list = new ArrayList<MultipartBody.Part>();
            for (int i = 0; i < file.size(); i++) {
                list.add(createImageMultipartBody(file.get(i)));
            }
             Log.i(TAG, "路径为:" + list);
        }

然后再创建我们的uriToFileApiQ方法

@RequiresApi(api = Build.VERSION_CODES.Q)
    public List<File> uriToFileApiQ(Intent data) {
        List<File> files = new ArrayList<>();
        File file = null;
        if (data!=null){
            Uri uri = data.getData();
            if (uri == null) {
                for (int i = 0; i < data.getClipData().getItemCount(); i++) {
                    uri = data.getClipData().getItemAt(i).getUri();
                    //android10以上转换
                    if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
                        file = new File(uri.getPath());
                    } else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
                        //把文件复制到沙盒目录
                        ContentResolver contentResolver = getContentResolver();
                        String displayName = System.currentTimeMillis() + Math.round((Math.random() + 1) * 1000)
                                + "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(contentResolver.getType(uri));
                        try {
                            InputStream is = contentResolver.openInputStream(uri);
                            File cache = new File(getCacheDir().getAbsolutePath(), displayName);
                            FileOutputStream fos = new FileOutputStream(cache);
                            FileUtils.copy(is, fos);
                            file = cache;
                            fos.close();
                            is.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    files.add(file);
                }
            } else {
                //android10以上转换
                if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
                    file = new File(uri.getPath());
                } else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
                    //把文件复制到沙盒目录
                    ContentResolver contentResolver = getContentResolver();
                    String displayName = System.currentTimeMillis() + Math.round((Math.random() + 1) * 1000)
                            + "." + MimeTypeMap.getSingleton().getExtensionFromMimeType(contentResolver.getType(uri));
                    try {
                        InputStream is = contentResolver.openInputStream(uri);
                        File cache = new File(getCacheDir().getAbsolutePath(), displayName);
                        FileOutputStream fos = new FileOutputStream(cache);
                        FileUtils.copy(is, fos);
                        file = cache;
                        fos.close();
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                files.add(file);

            }
            return files;

        }
        return files;
    }

在这个方法中我们可以很清晰的看到,我们是通过获取到文件的加密路径后,将它复制到了沙盒中,沙盒呢是在我们的Android10的时候有重点讲述,这个大家可以去Android的官方文档中查看,我在这里就不多说了

最后呢,给大家看一下我们转换后的路径

b0254f3344fb44e49faf9bb3b5f283f7.png

下边的就是我们已经转换好的路径,然后就可以直接把这个路径放到list中然后一条一条的add添加到里面就可以了 

最后我创建了一个QQ群,为了方便给大家解决一些问题

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值