FileProvider

一、概念

在Android 7.0以前的系统版本中,我们可以直接调用Uri.fromFile(file)来获取file的uri,这个uri以"file:///"为首,且无时效性限制,接受到此uri的应用可以对它进行保存后,随时获取此file。而在Android 7.0以后的系统版本中,我们只能通过FileProvider.getUriFromFile(file)来提供一个以"content://"为首的uri,这个uri有一定的时效性,其生命周期伴随着intent关联的组件(可以是Activity,也可以是Service)的生命周期结束而结束,所以很大程度上保障了开发者的应用私有文件的安全。

FileProvider是ContentProvider的子类,实现了query()和delete()方法,并使insert()和update()方法直接抛出异常,同时新增了getUriFromFile(File file)方法来让我们在应用中获取用于分享此file的 uri。

二、用法

1.在AndroidManifest中定义FileProvider


    ...
    
        ...
        
          
        
        ...
    

需要设置android:authorities属性,用于标识属于你的应用的 FileProvider;另外还需要在meta-data标签内设置android:resource属性,用于配置文件路径。

2.在xml文件夹下定义路径配置文件
路径配置文件限制了FileProvider可以获取到你的应有私有目录下具体的子文件夹,比如说你的应用目录下有 imgs 和 docs 两个子文件夹,而你只希望向外分享图片,则可以将下面的path属性值设置为 path="imgs"。



  

  


其中,name属性值用于组成最后生成的uri的一部分,所以这个属性可以任意定制,而前面的标签名的不同则决定了文件夹位置的不同。

"files_path" 对应 Context.getFilesDir() 的路径,物理路径为:data/data//files。
"cache-path" 对应 Context.getCacheDir(),物理路径为:/data/data//cache。
"external-path" 对应 Environment.getExternalStorageDirectory()。
"external-files-path" 对应 Context.getExternalFilesDir(String)、Context.getExternalFilesDir(null)。
"external-cache-path" 对应 Context.getExternalCacheDir()。

path属性就是第一段所提到的,当你的文件夹下有多个子文件夹,你只希望提供某一个文件夹的时候,可以在属性中填入相应的文件夹名。为空时,FileProvider可以为应用文件夹下的所有文件生成uri。

3.获取uri

File file = new File(Context.getFilesDir(), "default_image.jpg");
Uri contentUri = FileProvider.getUriForFile(getContext(), "com.mydomain.fileprovider", file);

可以获取到一个uri: content://com.mydomain.fileprovider/my_images/default_image.jpg
其中,"com.mydomain.fileprovider/"后的"my_images"就是前面路径配置文件中name属性指定的。

4.分享

Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION
            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(intent, requestCode);

以上只是适用于Android 7.0以上的系统,对于Android 7.0以下的系统,我们直接调用Uri.fromFile(file)获取uri即可。

三、例子

例1:

//build.gradle(module)
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.tomorrow.architetest"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:support-compat:28.0.0'

    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

//MainActivity
package com.tomorrow.architetest;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import java.io.File;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final int REQUEST_CODE_IMAGE_CAPTURE = 10;
    private String mPath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "zwm, onCreate");
        setContentView(R.layout.activity_main);

        mPath = getExternalCacheDir() + "/path/test.jpg";
        Log.d(TAG, "zwm, mPath: " + mPath);
        //Uri uri = FileProvider.getUriForFile(this, "com.tomorrow.fileprovider", new File(mPath));
        Uri uri = Uri.fromFile(new File(mPath));
        Log.d(TAG, "zwm, uri: " + uri);

        Intent intent = new Intent();
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION
                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        startActivityForResult(intent, REQUEST_CODE_IMAGE_CAPTURE);
    }
}

//输出log
2019-11-22 16:08:14.236 6871-6871/com.tomorrow.architetest D/MainActivity: zwm, onCreate
2019-11-22 16:08:15.307 6871-6871/com.tomorrow.architetest D/MainActivity: zwm, uri: file:///storage/emulated/0/Android/data/com.tomorrow.architetest/cache/test.jpg

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tomorrow.architetest/com.tomorrow.architetest.MainActivity}: android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.tomorrow.architetest/cache/test.jpg exposed beyond app through ClipData.Item.getUri()

例2:

//build.gradle(module)
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.tomorrow.architetest"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support:support-compat:28.0.0'

    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

//AndroidManifest.xml


    
    
        
            
                
                
            
        
        
            
        
    


//res/xml/file_paths.xml


    


//MainActivity
package com.tomorrow.architetest;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import java.io.File;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private static final int REQUEST_CODE_IMAGE_CAPTURE = 10;
    private String mPath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "zwm, onCreate");
        setContentView(R.layout.activity_main);

        mPath = getExternalCacheDir() + "/path/test.jpg";
        Log.d(TAG, "zwm, mPath: " + mPath);
        Uri uri = FileProvider.getUriForFile(this, "com.tomorrow.fileprovider", new File(mPath));
        Log.d(TAG, "zwm, uri: " + uri);

        Intent intent = new Intent();
        intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION
                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        startActivityForResult(intent, REQUEST_CODE_IMAGE_CAPTURE);
    }
}

//输出log
2019-11-22 18:07:51.398 11579-11579/com.tomorrow.architetest D/MainActivity: zwm, onCreate
2019-11-22 18:07:51.516 11579-11579/com.tomorrow.architetest D/MainActivity: zwm, mPath: /storage/emulated/0/Android/data/com.tomorrow.architetest/cache/path/test.jpg
2019-11-22 18:07:51.517 11579-11579/com.tomorrow.architetest D/MainActivity: zwm, uri: content://com.tomorrow.fileprovider/name/test.jpg

你可能感兴趣的:(FileProvider)