Android踩坑日记:android7.0动态相机权限_android 7.0 相机权限-程序员宅基地

技术标签: Java  Android学习笔记  android  7.0  【Android 知识框架】  相机权限  

前提:

项目中使用的动态权限开源库github:https://github.com/yanzhenjie/AndPermission。

转载必须注明本文转自严振杰的博客:http://blog.csdn.net/yanzhenjie1003

添加依赖:

compile 'com.yanzhenjie:permission:1.0.3'

Android6.0:

众所周知,Android6.0时相机摄像头权限改成了动态权限申请。实际上在xml中加入CAMERA,WRITE_EXTERNAL_STORAGE全向后,直接调用摄像头。此时是没有“检查权限是否授予”,“没有授予再申请权限”的代码的。

但是(重点),我发现

1,在VIVO,华为等国产机会弹出对话框,

2,三星,sony等外国机不会有弹窗,调用摄像头直接崩溃,

3,魅族手机没有弹出,但是可以直接用摄像头。

我猜测是VIVO,华为定制系统帮助用户检查并申请了相机权限,外国机则没有,魅族可能直接授予权限。为统一,建议android6.0每次都检查并申请相机权限,如下.

 /**
     * 申请相机权限
     *
     * @param context
     * @param photoFromCamera  拍照保存图片路径
     *
     *
     * @see {https://github.com/yanzhenjie/AndPermission}
     * */

    public static void requestCameraPermission(final Context context, final String photoFromCamera){
        //API >=23
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
          
            AndPermission.with(context)
                    .requestCode(PERMISSION_MEDIA_REQUEST_CODE)
                    .permission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE)
                    .rationale(new RationaleListener() {
                        @Override
                        public void showRequestPermissionRationale(int requestCode, Rationale rationale) {
                            // 此对话框可以自定义,调用rationale.resume()就可以继续申请。
                            AndPermission.rationaleDialog(context, rationale).show();
                        }
                    })
                    .callback(new PermissionListener() {
                        @Override
                        public void onSucceed(int requestCode, @NonNull List<String> grantPermissions) {
                            // 权限申请成功回调。
                            if(requestCode == PERMISSION_MEDIA_REQUEST_CODE) {
                                UIRouter.JumpToCameraActivity(context,photoFromCamera);
                            }
                        }

                        @Override
                        public void onFailed(int requestCode, @NonNull List<String> deniedPermissions) {
                            // 权限申请失败回调。
                            if(requestCode == PERMISSION_MEDIA_REQUEST_CODE) {
                                ToastView.showToast(context,"拒绝授权");
                            }
                        }
                    })
                    .start();
        }
    }

   /**
     * 调用系统拍照
     * @param saveImagePathFromCamera 拍照图片保存路径
     * @param context
     */
    public static void JumpToCameraActivity(Context context, String saveImagePathFromCamera) {
       /*调用系统拍照*/
      
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        Uri uri = null; 
        File imageFile = FileUtil.getFile(saveImagePathFromCamera);//此路径可以为storage/mounted/0/DCIM或其他外部存储路径
       uri = Uri.fromFile(imageFile); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); ((Activity) context).startActivityForResult(intent, CAMERA_REQUEST_CODE); }




Android7.0以上:

测试过程中,发现在android7.0以上的设备上使用摄像头时,直接崩溃掉了。原因是android7.0开始,相机拍照的图像保存路径必须在此应用的内部存储文件夹(storage/mounted/0/Android/data/包名//files/pictures文件夹)。需要使用FileProvider获取内部文件的uri

 /**
     * 申请相机权限
     *
     * @param context
     * @param photoFromCamera  拍照保存图片路径
     *
     *
     * @see {https://github.com/yanzhenjie/AndPermission}
     * */

    public static void requestCameraPermission(final Context context, final String photoFromCamera){
        //API <23
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
            UIRouter.JumpToCameraActivity(context,photoFromCamera);
        }else {
            //API >=23
            AndPermission.with(context)
                    .requestCode(PERMISSION_MEDIA_REQUEST_CODE)
                    .permission(Manifest.permission.CAMERA,Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.READ_EXTERNAL_STORAGE)
                    .rationale(new RationaleListener() {
                        @Override
                        public void showRequestPermissionRationale(int requestCode, Rationale rationale) {
                            // 此对话框可以自定义,调用rationale.resume()就可以继续申请。
                            AndPermission.rationaleDialog(context, rationale).show();
                        }
                    })
                    .callback(new PermissionListener() {
                        @Override
                        public void onSucceed(int requestCode, @NonNull List<String> grantPermissions) {
                            // 权限申请成功回调。
                            if(requestCode == .PERMISSION_MEDIA_REQUEST_CODE) {
                                UIRouter.JumpToCameraActivity(context,photoFromCamera);
                            }
                        }

                        @Override
                        public void onFailed(int requestCode, @NonNull List<String> deniedPermissions) {
                            // 权限申请失败回调。
                            if(requestCode ==PERMISSION_MEDIA_REQUEST_CODE) {
                                ToastView.showToast(context,"拒绝授权");
                            }
                        }
                    })
                    .start();
        }
    }

    /**
     * 调用系统拍照
     *
     * @param context
     */
    public static void JumpToCameraActivity(Context context, String saveImagePathFromCamera) {
       /*调用系统拍照*/
      
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        Uri uri = null;
        try {

            File imageFile = FileUtil.getFile(saveImagePathFromCamera);
            //API>=24 android 7.0
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
                if (intent.resolveActivity(context.getPackageManager()) != null){
                    String imageName = imageFile.getName();
                    //7.0以上 的拍照文件必须在storage/emulated/0/Android/data/包名/files/pictures文件夹
                    File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
                    File file = FileUtil.getFile(storageDir+"/"+imageName);

                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); //添加这一句表示对目标应用临时授权该Uri所代表的文件
                    uri = FileProvider.getUriForFile(context,"包名.fileprovider",file);
                }
            }else {//<24 

                uri = Uri.fromFile(imageFile);
            }

            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            ((Activity) context).startActivityForResult(intent, CAMERA_REQUEST_CODE);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

1,在manifest.xml中加入:

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

2,在res中新建xml文件夹,创建file_paths.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <paths>
        <external-path
            name="camera_photos"<!--任意-->
            path="Android/data/包名/files/Pictures" /><!--相机图片保存图片路径,属于APP的存储空间-->
    </paths>

</resources>




版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/tuke_tuke/article/details/78871991

智能推荐

前端提高篇(九十四):jQuery鼠标事件-程序员宅基地

文章浏览阅读833次,点赞26次,收藏26次。javascript是前端必要掌握的真正算得上是编程语言的语言,学会灵活运用javascript,将对以后学习工作有非常大的帮助。掌握它最重要的首先是学习好基础知识,而后通过不断的实战来提升我们的编程技巧和逻辑思维。这一块学习是持续的,直到我们真正掌握它并且能够灵活运用它。如果最开始学习一两遍之后,发现暂时没有提升的空间,我们可以暂时放一放。继续下面的学习,javascript贯穿我们前端工作中,在之后的学习实现里也会遇到和锻炼到。真正学习起来并不难理解,关键是灵活运用。

IntelliJ:idea怎么设置eclipse快捷键_idea修改快捷键为eclipse-程序员宅基地

文章浏览阅读1k次。idea怎么设置eclipse快捷键_idea修改快捷键为eclipse

世界时间经纬_世界主要城市经纬度及时区列表-程序员宅基地

文章浏览阅读4.7k次。◎欧洲各地经纬度简表国家 城市 经度 纬度 时区 罗马尼亚 布加勒斯特 东经26:06 北纬44:26 +2保加利亚 索非亚 东经23:19 北纬42:41 +2希腊 雅典 东经23:43 北纬37:58 +2希腊 斯巴达 东经22:25 北纬37:05 +2马其顿 斯科普里 东经21:28 北纬42:00 +2波兰 华沙 东经21:00 北纬52:15 +1南斯拉夫 贝尔格莱德 东经20:30 ..._全球城市经纬度

ZOJ 2112 Dynamic Rankings (动态第k大,树状数组套主席树)_动态第k大 树状数组套平衡树-程序员宅基地

文章浏览阅读294次。题目链接:题目大意:询问一个区间的第k大 但是有操作会对某个位置的值进行改变 即动态第k大思路:树状数组套主席树普通主席树装未修改的数据树状数组套主席树装的是修改的数据,即修改操作在树状数组中进行#include #include #include #include #include #include #include #include #include _动态第k大 树状数组套平衡树

oracle声明纪录变量,oracle – 在SQL * Plus中声明绑定变量-程序员宅基地

文章浏览阅读82次。不知道你为什么要使用PL / sql块.您没有使用您声明的ID,最好给它一个与列名称不同的名称以避免混淆.您可以在sql * Plus中声明一个绑定变量,然后选择:var l_test_quote varchar2(80); -- or whatever type/size you needvar l_test_id varchar2(80);declarel_id varchar2(80) :=..._"oracle:sp2-0552: 未声明绑定变量 \"empid\"。"

关于达梦数据库与oracle数据库的迁移_oracle迁移达梦方便吗-程序员宅基地

文章浏览阅读4.3k次,点赞2次,收藏9次。在这里和大家分享一下关于达梦与oracle之间进行数据迁移的注意事项:达梦数据库与oracle的兼容性是很高的,所以这两类数据库之间进行迁移 还是很方便的。首先,初始化实例的时候,将空格填充模式参数设置为零(BLANK_PAD_MODE=0),oracle兼容性参数 (COMPATIBLE_MODE=2)打开。需要注意的是,空格填充模式参数是初始化参数,只能在初始化实例的时候进行设置,这两个参..._oracle迁移达梦方便吗

随便推点

LSF系统介绍_lsf分组-程序员宅基地

文章浏览阅读1.4w次。LSF系统介绍http://scc.ustc.edu.cn/zh_CN/ 中科大超算中心http://www.sccas.cn/gb/index.html 中科院超算中心http://www.ssc.net.cn/ 上涨超算中心LSF简介LSF(Load Sharing Facility)是分布资源管理的工具,用来调度、监视、分析联网计算机的负载。目的通过集中监控和调度,充分共享计算机的CPU_lsf分组

鸿蒙开发初体验-程序员宅基地

文章浏览阅读5.1k次。/ 今日科技快讯 /近日,字节跳动回应:由美国CFIUS调查及“总统令”引发对TikTok的大量关注与报道,其中有很多猜测和不实信息。真实情况是, 我们确实在与一些公司探讨合作方..._鸿蒙的开发

python 获取窗口句柄 模拟 点击按钮,python和pywin32实现窗口查找、遍历和点击-程序员宅基地

文章浏览阅读9.9k次,点赞5次,收藏45次。1.如何利用句柄操作windows窗体首先,获得窗体的句柄 win32api.FindWindows()第二,获得窗体中控件的id号,spy++第三,根据控件的ID获得控件的句柄(hwnd) GetDlgItem(hwnd,loginID)最后,利用控件句柄进行操作python可以通过win32api轻松获取控件的属性值通过标签找到主窗口句柄,然后通过主句柄获取下属控件句柄#-*- codin..._python 获取窗口句柄 模拟 点击按钮

以集群方式运行pyspark_spark.yarn.appmasterenv.pyspark_python-程序员宅基地

文章浏览阅读2.4k次。一、背景说明  单机执行pyspark(python on spark)非常简单,只要在脚本所在服务器上部署个python环境或Anaconda这种集成运行环境,再通过python3命令执行就完了。  而想将python提交到spark集群中运行,则有两种方法,一种是在每个spark结点上部署python环境,在spark低版本与python集成没那么完善的时候,集群结点数又不多的情况下,的确可以这么干(实际上我就这么干过),这种方式比较大的优势是每次执行pyspark任务时,不用分发python环_spark.yarn.appmasterenv.pyspark_python

Android修行手册 - 实现POI上万行的大数据量Excel读写操作,解决内存溢出_android 读取超大excel文件-程序员宅基地

文章浏览阅读1.5k次,点赞15次,收藏11次。搞过POI的都知道,在处理Excel文件时,POI提供了两种模式:用户模式和SAX事件驱动模式。用户模式API丰富使用起来相对简单,但当遇到大文件、大量数据或复杂格式时,可能会导致内存溢出。因此,官方推荐使用SAX事件驱动模式来解析大型Excel文件。开始想解决方法之前,我们要先知道 Excel2003与Excel2007 的区别。_android 读取超大excel文件

cordova通过原生实现自定义功能_cordova 连拍-程序员宅基地

文章浏览阅读1w次。先闲谈说下最近的微信要出的小程序吧,感觉确实很牛逼,革命说不上吧但是也是一个新的大的机遇。不得不承认腾讯有两个相当好的平台,一个是QQ,一个是微信,毕竟人数基数大,任何新的东西都会带来相当多的机会和挑战。那个小程序好像是基于react native,也是一种混合架构。最近整理整理下混合架构的知识,有时间也好好学习去。 好了开始正题吧。 最近研究cordova通过原生_cordova 连拍

推荐文章

热门文章

相关标签