Android7.0打开sdacrd图片问题

1.点击item,通过intent打开指定路径的图片。

2.测试6.0,5.0正常运行代码:

File file=new File(item.address);

Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");

intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);

Uri uri = Uri.fromFile(new File(item.address));

intent.setDataAndType (uri, "image/*");

startActivity(intent);

3.在7.0上运行报错。

com.aolian.mychezai, PID: 3881
   android.os.FileUriExposedException: file:///storage/emulated/0/AA/17-03-01%2009-31-08%202335-01%E7%AB%AF%20B%E7%B3%BB%20STU-V-N-LOG.txt exposed beyond app through Intent.getData()
   at android.os.StrictMode.onFileUriExposed(StrictMode.java:1816)
   at android.net.Uri.checkFileUriExposed(Uri.java:2350)
   at android.content.Intent.prepareToLeaveProcess(Intent.java:9076)
   at android.content.Intent.prepareToLeaveProcess(Intent.java:9037)
   at android.app.Instrumentation.execStartActivity(Instrumentation.java:1530)
   at android.app.Activity.startActivityForResult(Activity.java:4391)
   at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:50)
   at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:79)
   at android.app.Activity.startActivityForResult(Activity.java:4335)
   at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:859)
   at android.app.Activity.startActivity(Activity.java:4697)
   at android.app.Activity.startActivity(Activity.java:4665)
   at com.aolian.mychezai.view.FileManagerActivity$7.onItemLongClick(FileManagerActivity.java:377)
   at android.widget.AbsListView.performLongPress(AbsListView.java:3298)
   at android.widget.AbsListView$CheckForLongPress.run(AbsListView.java:3215)
   at android.os.Handler.handleCallback(Handler.java:755)
                                                                    

4. 从Android 7.0开始,一个应用提供自身文件给其它应用使用时,如果给出一个file://格式的URI的话,应用会抛出FileUriExposedException。这是由于谷歌认为目标app可能    不具有文件权限,会造成潜在的问题。所以让这一行为快速失败。详见这里。这里讨论两种解决方式。

http://blog.csdn.net/xiaoyu940601/article/details/54406725

<1> FileProvider方式

(1) manifest声明 
在manifest中声明一个provider。name(即类名)为android.support.v4.content.FileProvider。

<manifest>
    ...
    <application>
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.mydomain.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
        ...
    </application>
</manifest>
其中authorities可以自定义。为了避免和其它app冲突,最好带上自己app的包名。file_paths.xml中编写该Provider对外提供文件的目录。文件放置在res/xml/下。 

(2)编写file_paths.xml

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <files-path name="my_images" path="images/"/>
    ...
</paths>

内部的element可以是files-path,cache-path,external-path,external-files-path,external-cache-path,分别对应Context.getFilesDir(),Context.getCacheDir(),Environment.getExternalStorageDirectory(),Context.getExternalFilesDir(),Context.getExternalCacheDir()等几个方法。后来翻看源码发现还有一个没有写进文档的,但是也可以使用的element,是root-path,直接对应文件系统根目录。不过既然没有写进文档中,其实还是有将来移除的可能的。使用的话需要注意一下风险。

(3)在Java代码当中使用 以分享一个图片为例:

File file = ...;    //要分享的图片文件
Uri uri = FileProvider.getUriForFile(context, "com.mydomain.fileprovider", file);    //第二个参数是manifest中定义的`authorities`
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("image/*");
intent.putExtra(Intent.EXTRA_TITLE, title);
intent.putExtra(Intent.EXTRA_TEXT, text);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);    //这一步很重要。给目标应用一个临时的授权。
startActivity(intent);    //或者其它最

2 VmPolicy方式

以上方法固然是推荐使用的,正确的方法。但是我在实际开发中遇到这样的问题。某些应用(此处点名新浪微博)根本无法理解一个指向文件的content://格式的URI。新浪微博接收到这类URI之后,无法加载图片,并会在点击发送微博时崩溃。 
另一方面,新浪微博对权限管理的处理采取了一种比较流氓的方式。它会在启动时申请文件读写权限,而如果拒绝该权限的话,居然就直接退出了。我反正是不信什么需要文件权限来放缓存放数据的说辞。放缓存放数据有着一堆不需要权限的目录可用。但是这样一来,我们其实是不需要担心传递一个file://格式URI过去而对方没有权限的。 
话说回来,如何解决这一问题呢?我在调研的时候观察到严格模式的一个方法:StrictMode.VmPolicy.Builder.detectFileUriExposure()。顾名思义,调用这个方法就会检测FileUriExposure这件事。这个方法其实从API18就有了,是不是有可能在API24变成了默认选项呢? 
在Application.onCreate加入如下代码,置入一个不设防的VmPolicy:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
    StrictMode.setVmPolicy(builder.build());
}

再用旧的方式直接把file://格式的URI发送出去。没有再抛出FileUriExposedException。

-----

时间: 2024-09-30 19:06:28

Android7.0打开sdacrd图片问题的相关文章

拍照、本地图片工具类(兼容至Android7.0)

拍照.本地图片工具类:解决了4.4以上剪裁会提示"找不到文件"和6.0动态授予权限,及7.0报FileUriExposedException异常问题. package com.hb.weex.util; import android.Manifest; import android.app.Activity; import android.app.Dialog; import android.content.ClipData; import android.content.Conten

Android7.0新特性,及Android N适配

新特性部分 Android 7.0 Nougat 提供新功能以提升性能.生产效率和安全性,主要新增了以下的新特性和优化: 一.新的Notification Android N 增加了许多新的notifications API,进行了重新的设计,引入了新的风格. 模板更新: 开发者将能够充分利用新模板,只需进行少量的代码调整. 消息样式自定义: 新增自定义样式.消息回复.消息分组等更加灵活. 捆绑通知: 系统可以将消息组合在一起(例如,按消息主题)并显示组.用户可以适当地进行 Dismiss 或

Android7.0 Doze模式分析(一)Doze介绍 &amp;amp; DeviceIdleController

 參考:http://blog.csdn.net/gaugamela/article/details/52981984 在Android M中,Google就引入了Doze模式.它定义了一种全新的.低能耗的状态. 在该状态,后台仅仅有部分任务被同意执行.其他任务都被强制停止. 在之前的博客中分析过Doze模式.就是device idle状态.可能有的地方分析的不是非常具体,如今在android7.0上又一次分析下. 一.基本原理 Doze模式能够简单概括为: 若推断用户在连续的一段时间内没有

Android7.0 FileUriExposedException 问题解决

一.FileUriExposedException的原因 Android7.0不识别uri以file://开头,要将其转换为content://才能识别uri 二.如何解决 1.xml的创建: file_paths.xml中编写该Provider对外提供文件的目录:文件放置在res/xml/下. 为了避免和其它app冲突,最好带上自己app的包名. 文件内容: <?xml version="1.0" encoding="utf-8"?><paths

Android7.0 Doze模式分析(一)Doze介绍 &amp; DeviceIdleController

 参考:http://blog.csdn.net/gaugamela/article/details/52981984 在Android M中,Google就引入了Doze模式.它定义了一种全新的.低能耗的状态. 在该状态,后台只有部分任务被允许运行,其它任务都被强制停止. 在之前的博客中分析过Doze模式,就是device idle状态.可能有的地方分析的不是很详细,现在在android7.0上重新分析下. 一.基本原理 Doze模式可以简单概括为: 若判断用户在连续的一段时间内没有使用手

Android7.0 Vold 进程工作机制分析之整体流程

Android7.0 Vold 进程工作机制分析之整体流程 一.Vold简介 Vold是Volume Daemon的缩写,负责管理和控制Android平台外部存储设备,包括SD插拨.挂载.卸载.格式化等.它是通过init进程解析init.rc脚本所启动的进程.它处于Native层. 二.基础架构 这里引用Gityuan博客的一张图. SystermServer进程和Vold进程是通过Socket进行通信的,Vold进程和Kernel是通过Netlink 进行通信的,Netlink 是一种特殊的S

Android7.0调用系统相机拍照、读取系统相册照片+CropImageView剪裁照片

Android手机拍照.剪裁,并非那么简单 简书地址:[我的简书–T9的第三个三角] 前言 项目中,基本都有用户自定义头像或自定义背景的功能,实现方法一般都是调用系统相机–拍照,或者系统相册–选择照片,然后进行剪裁,最终设为头像或背景. 而在Android6.0之后,需要动态获取权限,而且Android7.0之后,无法直接根据拍照返回的URI拿到图片,这是因为从安卓7.0开始,直接使用本地真实路径被认为是不安全的,会抛出FileUriExposedExCeption异常,本文就是基于这个功能去针

【转】Android7.0版本以上的手机Eclipse无法打出LogCat

本来想用Eclipse连下手机看下log的,结果LogCat没打出来任何信息,起初怀疑是我的DDMS有问题,结果连了下我老大的手机,完美打出log,看了下Android系统,老大的是6.0的,我的7.1的,所以怀疑是系统的问题,查了好多资料,终于搞定.原因是官网的ADT最新版本23.0.7不支持android7.0以上手机的日志输出,更换了第三方的24.2.0版本的ADT,下载地址:https://download.csdn.net/download/u013086341/10341796 1,

[Android Pro] Android7.0系统 关于Android获取流量计数TrafficStats.getUidRxBytes(uid)和TrafficStats.getUidTxBytes(uid)返回-1解决方案

reference : http://blog.csdn.net/zhangyong7112/article/details/54574214 最近一个关于流量的项目在Android7.0系统的手机上运行,一直获取不到流量的使用数据,查看源码然后发现TrafficStats.getUidRxBytes(uid)和TrafficStats.getUidTxBytes(uid)一直都是返回的-1, // 获取某个网络UID接收和发送字节的总和 long total = TrafficStats.ge