最近在使用蓝牙进行文件分享时,出现了一个奇怪的问题。同样的代码在android5.1上可以顺利运行,但是在android7.0上就运行失败。出现如下的错误:

Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/bluetooth/data.txt exposed beyond app through ClipData.Item.getUri()

出现这个问题的时候我立刻意识到这是一个兼容的问题,于是在网上找了一些方法,并解决了这个问题,我受到启发的网址是:

​ 出现FileUriExposedException这样的异常,原因是Andorid7.0的“私有目录被限制访问”,“StrictMode API 政策”。
由于从Android7.0开始,直接使用真实的路径的Uri会被认为是不安全的,会抛出一个FileUriExposedException这样的异常。需要使用FileProvider,选择性地将封装过的Uri共享到外部。

即以前的共享代码是这样写的:

Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("*/*");
sharingIntent.setComponent(new ComponentName("com.android.bluetooth","com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
sharingIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(path)));
startActivity(sharingIntent);

 

在android7.0版本以上时,不使用Uri.fromFile(),使用以下的代码:

Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("*/*");
sharingIntent.setComponent(new ComponentName("com.android.bluetooth","com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
sharingIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(BluetoothChat.this,"你的包名" + ".fileprovider", new File(path)));
sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(sharingIntent);

 

​ 如果是Andorid7.0或以上,则不再使用Uri.fromFile()方法获取文件的Uri,而是通过使用FileProvider(support.v4提供的类)的getUriForFile()。同时要添加多这么一行代码

sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

 

由于FileProvider是继承ContentProvider,属于四大组件之一,需要在AndroidManifest.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_provider_paths"/>
    </provider>

 

其中android:resource="@xml/file_provider_paths"的内容你可以在res目录下新建一个xml文件夹,在文件夹中新建一个file_provider_paths.xml文件即可,如下图所示

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path path="" name="myFile"></external-path>
    </paths>
</resources>

 

  上述代码中path=” “,是有特殊意义的,它代码根目录,也就是说你可以向其它的应用共享根目录及其子目录下任何一个文件了,如果你将path设为path=”pictures”, 那么它代表着根目录下的pictures目录(eg:/storage/emulated/0/pictures),如果你向其它应用分享pictures目录范围之外的文件是不行的。

分享文件代码如下:

    // 調用系統方法分享文件
    public static void shareFile(Context context, File file) {
        try{
            if (null != file && file.exists()) {
                Log.w("ppp-params", file.getPath());
                Intent share = new Intent(Intent.ACTION_SEND);
                share.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(context,"app.zhaohangwuliu.com.appada" + ".fileprovider", file));
                share.setType("*/*");//此处可发送多种文件
                share.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                share.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                context.startActivity(Intent.createChooser(share, "分享文件"));
            } else {
                //Toast.makeText(context, "分享文件不存在", Toast.LENGTH_SHORT).show();
            }
        }catch (Exception ex){
            Log.w("ppp-params", ex);
        }

    }

 

转: https://blog.csdn.net/kabuto_hui/article/details/78907572

posted @ 2019-07-24 10:55 云中雀 阅读(2735) 评论(0) 推荐(0) 编辑
摘要: 首先在res下创建raw,然后将mp3音乐拷贝到raw下 直接贴代码吧 //开始播放声音 public class PlayVoice { private static MediaPlayer mediaPlayer; public static void playVoice(Context context){ try { media... 阅读全文
posted @ 2018-11-07 11:41 云中雀 阅读(856) 评论(0) 推荐(0) 编辑
摘要: 最近的APP项目有一个需求就是连续点击两次返回按钮,退出整个APP,而不是返回到上一个页面,这个连续是有时间限制的,在我的项目里,我设置成2秒钟,如果两秒之内点击了两次,就代表用户想要退出整个APP,如果大于两秒则不会触发该效果。 实现方法是: 重写Activity里的onBackPressed方法 阅读全文
posted @ 2018-09-22 17:13 云中雀 阅读(1928) 评论(0) 推荐(0) 编辑
摘要: 后来发现,是没在清单文件配置Context,也就是下面的第三步。 解决方法: 转: https://blog.csdn.net/AndroidOliver/article/details/56481828v 阅读全文
posted @ 2018-09-07 15:15 云中雀 阅读(477) 评论(0) 推荐(0) 编辑
摘要: 在app的build.gradle文件的dependencies中,添加依赖: 注意,要在清单文件中,添加权限: <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission 阅读全文
posted @ 2018-09-04 14:46 云中雀 阅读(2269) 评论(0) 推荐(0) 编辑
摘要: 1、判断当前是否有网络 2、判断当前网络类型 3、判断当前手机网络类型 4、判断当前手机网络2G\3G\4G 阅读全文
posted @ 2018-09-01 10:30 云中雀 阅读(910) 评论(0) 推荐(0) 编辑
摘要: assets下的资源如下图: 下面是工具类: AssetsCopyTOSDcard .java MainActivity .java 在编程过程中遇到的两个问题: open failed: ENOENT (No such file or directory) open failed: EISDIR 阅读全文
posted @ 2018-09-01 10:21 云中雀 阅读(1393) 评论(0) 推荐(0) 编辑
摘要: AssetManager用于获取assets下的资源。 1、getassets()得到AssetManager 2、AssetManager.close() 关闭AssetManager 3、Resources和Assets 中的文件只可以读取而不能进行写的操作。 4、AssetManager类常用 阅读全文
posted @ 2018-09-01 10:06 云中雀 阅读(5021) 评论(0) 推荐(0) 编辑
摘要: 设计Android的工程师起名字还是挺规范的,而且一眼就知道是什么意思。RemoteViews,顾名思义,远程的View。Android为了能让进程A显示进程B的View,设计了这么一种View(其实不是真正的View)。其实我们开发过程中,发通知到状态栏显示也是利用了RemoteViews,我们来 阅读全文
posted @ 2018-08-31 10:29 云中雀 阅读(999) 评论(0) 推荐(0) 编辑
摘要: 首先,什么是桌面widget,桌面widget是一种桌面插件,如下图: 这种类型的控件叫做widget,一般长按桌面会弹出一个界面让你选择控件,选择完了拖到桌面就能使用了。 下面我们为这个app来添加一个widget,先看一下效果吧。 然后点击这个桌面widget,让他跳转到我们的app里面 怎么样 阅读全文
posted @ 2018-08-31 09:59 云中雀 阅读(1077) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示