Android 7.0 打开系统相机适配及使用FileProvider

针对部分高版本机型打开系统相机的适配代码

/**
 * 类名称:PhotographForSignActivity
 * 类功能:打开系统相机拍照
 * 类作者:Qw
 * 类日期:
 **/
public class PhotographForSignActivity extends Activity {
    private static final int PHOTO = 9; // 拍照
    private String photoPath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.empty_view);
        startPhoto();
    }


    /**
     * 打开照相机拍摄,并保存照片到指定路径中
     */
    private void startPhoto() {
        if (hasCamera()) {
            //先验证手机是否有sdcard
            String status = Environment.getExternalStorageState();
            if (status.equals(Environment.MEDIA_MOUNTED)) {
                try {
                    String photoSavePath = Environment.getExternalStorageDirectory()
                            + "/相册名/";
                    File imgDir = new File(photoSavePath);
                    FileUtils.DeleteFile(photoSavePath);
                    if (!imgDir.exists()) {
                        imgDir.mkdir();
                    }
                    String photoSaveName = String.valueOf(System.currentTimeMillis())
                            + ".jpg";
                    photoPath = photoSavePath + photoSaveName;
                    Intent openCameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    File MyFile = new File(photoPath);
                    Uri imageUri = Uri.fromFile(MyFile);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        if (!MyFile.getParentFile().exists()) MyFile.getParentFile().mkdirs();
                        imageUri = FileProvider.getUriForFile(this, "包名.fileprovider", MyFile);//通过FileProvider创建一个content类型的Uri
                        openCameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
                        openCameraIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
                        openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
                        startActivityForResult(openCameraIntent, PHOTO);
                    } else {
                        openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
                        startActivityForResult(openCameraIntent, PHOTO);
                    }
                } catch (ActivityNotFoundException e) {
                    Toast.makeText(this, "没有找到储存目录", Toast.LENGTH_LONG).show();
                }
            } else {
                Toast.makeText(this, "没有储存卡", Toast.LENGTH_LONG).show();
            }
        } else {
            Toast.makeText(this, "没有可用的照相机", Toast.LENGTH_LONG).show();
            finish();
        }
    }

    /**
     * 拍完照后,把照片的储存路径返回给正常签收页面处理
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PHOTO && resultCode == Activity.RESULT_OK) {
            Toast.makeText(this, "拍照完成", Toast.LENGTH_LONG).show();
            EventCenter messageEvent = new EventCenter<>("photoPath", photoPath);
            EventBus.getDefault().post(messageEvent);
            Intent intent = new Intent();
            intent.putExtra("photoPath", photoPath);
            setResult(RESULT_OK, intent);
            finish();
        } else {
            finish();
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onConfigurationChanged(Configuration config) {
        super.onConfigurationChanged(config);
    }


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("filePaths", photoPath);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        if (TextUtils.isEmpty(photoPath)) {
            photoPath = savedInstanceState.getString("filePaths");
        }
    }

    /**
     * 判断系统中是否存在可以启动的相机应用
     *
     * @return 存在返回true,不存在返回false
     */
    private boolean hasCamera() {
        PackageManager packageManager = PhotographForSignActivity.this.getPackageManager();
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        return list.size() > 0;
    }
}

provider的代码放在AndroidManifest.xml application里面

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

在 res/xml 目录下新建一个 xml 文件,用于存放应用需要共享的目录文件。这个 xml 文件的内容类似这样:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

元素必须包含一到多个子元素。这些子元素用于指定共享文件的目录路径,必须是这些元素之一:

<files-path>:内部存储空间应用私有目录下的 files/ 目录,等同于 Context.getFilesDir() 所获取的目录路径;

<cache-path>:内部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getCacheDir() 所获取的目录路径;

<external-path>:外部存储空间根目录,等同于 Environment.getExternalStorageDirectory() 所获取的目录路径;

<external-files-path>:外部存储空间应用私有目录下的 files/ 目录,等同于 Context.getExternalFilesDir(null) 所获取的目录路径;

<external-cache-path>:外部存储空间应用私有目录下的 cache/ 目录,等同于 Context.getExternalCacheDir();

可以看出,这五种子元素基本涵盖内外存储空间所有目录路径,包含应用私有目录。同时,每个子元素都拥有 name 和 path 两个属性。

其中,path 属性用于指定当前子元素所代表目录下需要共享的子目录名称。注意:path 属性值不能使用具体的独立文件名,只能是目录名。

而 name 属性用于给 path 属性所指定的子目录名称取一个别名。后续生成 content:// URI 时,会使用这个别名代替真实目录名。这样做的目的,很显然是为了提高安全性。

这样适配就可以解决由于7.0 及以上版本的手机用户在使用到应用部分功能时可能出现 App 崩溃闪退。其中,大部分原因都是由项目中使用到 file:// 类型的 URI 所引发的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值