欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

FileProvider进阶知识点,你所不知道的

程序员文章站 2022-04-15 22:13:24
...

FileProvider是什么?为什么要用FileProvider?怎么用?网上已经有很多文章了,文章末尾也会推荐给大家比较好的文章。我们说一些网上没有或者很少提到的。

1、流行的FileProvider的写法

例子一:调用相机拍照并进行保存

    /**
     *
     * @param context
     * @param saveFile      照片保存路径
     * @param authorities   身份认证字符串,用FileProvider生成分享URI的时候使用
     */
    private void takeAndSavePhoto(Context context, File saveFile, String authorities) {
        if (saveFile != null) {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            Uri imageUri = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                imageUri = FileProvider.getUriForFile(context, authorities, saveFile);
            } else {
                imageUri = Uri.fromFile(saveFile);
            }
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            context.startActivity(intent);
        }
    }

上面的写法是标准的写法,在代码中做了版本判断,如果当前运行的系统版本大于7.0,采用FileProvider的方式分享URI,否则采用之前的方式。简单说明一下为什么要区分版本,虽然说分享文件使用FileProvider方式,在7.0系统上是强制要求的(否则会报错),但是在7.0以下使用FileProvider也是没有问题的,只是在4.4及一下会有问题,这是由于不同系统实现不同导致的。所以为了解决这个问题,就直接以7.0为界限进行了版本区分。那么问题来了,上面这段代码就百分之百没有问题吗?答案是否定的。

请看saveFile参数,这个参数是用来表示照片要保存的地方。我们都知道,对于一个app来说,有三个目录的概念,简单来说:

私有目录      data/data/<包名>/files [及cache]   context.getFilesDir() [及context.getCacheDir()]

SD卡公有目录   storage/emulated/0   Enviroment.getExternalStorageDirectory()   这个是SD卡的根目录

SD卡私有目录   storage/emulated/0/Android/data/<包名>/files[及cache]  context.getExternalFilesDir()[及context.getExternalCacheDir()]

对于这三个目录都可以用来保存照片吗?不是的。

采用FileProvider的方式,这三个目录都可以,Uri.fromFile的方式,只有SD卡的这两个目录可以,所以大家在使用的时候一定要注意。

例子二:调用系统安装器安装apk包

    /**
     * @param context
     * @param installFile       apk包所在路径
     * @param authorities
     */
    private void installApk(Context context, File installFile, String authorities) {
        if (installFile != null) {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            Uri apkUri = FileProvider.getUriForFile(context, authorities, installFile);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            context.startActivity(intent);
        }
    }

上面这段代码是安装apk的标准写法,不过这里面有个坑,还是出在路径上,如果apk所在的目录位于SD卡的公共目录里,调起安装器时就会包“解析安装包失败”的错误,不过需要说的一点是如果采用Uri.fromFile的方式,是可以正常安装的。

不过需要注意在android 8.0系统上安装apk时候的权限问题,否则在8.0系统上拉不起安装界面,具体看参考文章

2、上面说的FileProvider用法,都是调用系统相机和安装器。那么,我们自己写两个app,怎么共享数据呢?

比如,我们怎么把上面相机保存的图片(App A),怎么共享给另一个app(B)。

App A

                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.lzy.fileproviderclient", "com.lzy.fileproviderclient.MainActivity"));
                File imageFile = new File(mContext.getExternalFilesDir(null) + "/image/" + "photo.jpg");
                Uri uri = FileProvider.getUriForFile(mContext, "com.lzy.myapplication.fileProvider", imageFile);
                intent.setData(uri);
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                startActivity(intent);

App B

        mImageView = (ImageView) findViewById(R.id.photo_image_view);
        if (getIntent() != null) {
            Uri uri = getIntent().getData();
            if (uri != null) {
                try {
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inSampleSize = 4;
                    Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
                    mImageView.setImageBitmap(bitmap);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }

 

 

 

参考:

Android FileProvider的使用

Android 7.0 行为变更 通过FileProvider在应用间共享文件吧

记 Android 7.0 8.0版本更新安装遇到的坑