Android N中那些变更适配

AndroidN

1.File文件的路径转化为Uri方式
文件:File file=new File(MainActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES),"/zwk/" + “zwk”+ “.jpg”);
路径是:/storage/emulated/0/Android/data/com.example.androidndemo/files/Pictures/zwk/zwk.jpg

  • 4.4之前

    Uri imageUri = Uri.fromFile(file);
    转化后的Uri:file:///storage/emulated/0/Android/data/com.example.androidndemo/files/Pictures/zwk/zwk.jpg

  • 7.0之后

    Uri imageUri = FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getPackageName() + ".fileprovider", file);
    转化后Uri:content://com.example.androidndemo.fileprovider/external-files-path/Pictures/zwk/zwk.jpg

**差别:**7.0前后的差别

  • ①是file://变成了content://.
  • ②多了com.example.androidndemo.fileprovider
  • ③/storage/emulated/0/Android/data/com.example.androidndemo/files/变成了/external-files-path/

关于这点差别,我们有必要看下androidN的知识。

2.AndroidN知识点

做过拍照功能,肯定遇到过这个异常:
android.os.FileUriExposedException: file:///xxxxx exposed beyond app through ClipData.Item.getUri()
这就是7.0的改变导致的版本的不适配问题。

  • 7.0为啥改变啥?
    因为fill://这种URI可能会留下无法访问的路径问题,触发FileUriExposedException异常。所以,7后分享私有文件内容推荐使用FileProvider这种方法。

  • 7.0适配

    • 拍照适配
      • 7.0前拍照

        使用6.0动态权限,先获取读写权限,然后进行调用拍照保存到指定路径:/storage/emulated/0/Android/data/com.example.androidndemo/files/Pictures/zwk/zwk.jpg

    File file = new File(MainActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "/zwk/" + "zwk" + ".jpg");
    if (!file.getParentFile().exists()) 
    file.getParentFile().mkdirs();
    Uri imageUri = Uri.fromFile(file);
    Intent intent = new Intent();
    intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
    intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
    startActivityForResult(intent, 10086);
    
    • 7.0拍照

      ①使用6.0动态权限,先获取读写权限。
      ②新建一个名为files-path.xml的文件

    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <files-path
            name="files-path"
            path="." />
        <cache-path
            name="cache-path"
            path="." />
        <external-path
            name="external-path"
            path="." />
        <external-files-path
            name="external-files-path"
            path="." />
        <external-cache-path
            name="external-cache-path"
            path="." />
        <external-media-path
            name="external-media-path"
            path="." />
        <root-path
            name="root"
            path=" " />
    	</paths>
    
    • paths:是路径别名的集合,其内必须有一个files-path

    • files-path:相当于context.getFilesDir().getAbsolutePath()获取的路径/data/user/0/com.example.androidndemo/files

    • cache-path:相当于context.getCacheDir().getAbsolutePath()获取的路径/data/user/0/com.example.androidndemo/cache

    • exteral-path:相当于Environment.getExternalStorageDirectory().getAbsolutePath()获取的路径/storage/emulated/0

    • external-files-path:相当于Context.getExternalFilesDir(null)获取的路径/storage/emulated/0/Android/data/com.example.androidndemo/files

    • external-cache-path:相当于context.getExternalCacheDir().getAbsolutePath()获取的路径/storage/emulated/0/Android/data/com.example.androidndemo/cache

    • path:path=".“代表目录整个目录 而 path=”/MyImage"代表一个子目录.
      <files-path name="files-path" path="." /> 代表了/data/user/0/com.example.androidndemo/files
      <files-path name="files-path" path="/MyImage" /> 代表了/data/user/0/com.example.androidndemo/files/MyImage 这个目录

    • name:相当于一个路径的别名,代表了一段路径。具体和父标签和path值有关,如上面的例子.


③ manifest的application下注明

		    <provider
		           android:name="android.support.v4.content.FileProvider"
		           android:authorities="com.example.androidndemo.fileprovider"
		           android:exported="false"
		           android:grantUriPermissions="true">
		           <meta-data
		                android:name="android.support.FILE_PROVIDER_PATHS"
		                android:resource="@xml/file_path" />
  • name="android.support.v4.content.FileProvider"或者androidx.core.content.FileProvider
  • authorities:一个标识常量,要确保唯一并且和④中FileProvider.getUriForFile()第二个参数保持一致,一般使用包名+.fileprovider.
  • exported:限制不让外部程序调用.
  • grantUriPermissions:设置为true,允许获得文件临时的访问权限
  • name:android.support.FILE_PROVIDER_PATHS 这个为啥这么写,没搞清楚可能是固定的写法
  • resource:可以共享的文件的路径

④ 拍照获取Uri的时候,将代码替换成
Uri imageUri = FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getPackageName() + ".fileprovider", file);

File file = new File(MainActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "/zwk/" + "zwk" + ".jpg");
if (!file.getParentFile().exists()) file.getParentFile().mkdirs();		
imageUri = FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getPackageName() + ".fileprovider", file);
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);//设置Action为拍照
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//将拍取的照片保存到指定URI
startActivityForResult(intent, 10086);
  • 下载安装app

       Intent installIntent = new Intent(Intent.ACTION_VIEW);
                    installIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK);
                    // 7.0 uri权限
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        installIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                        Uri uri = FileProvider.getUriForFile(Global.context, getApplicationContext().getPackageName() + ".provider", new File(updateDir, fileName));
                        installIntent.setDataAndType(uri, "application/vnd.android.package-archive");
                        // 兼容8.0
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                            boolean hasInstallPermission = getPackageManager().canRequestPackageInstalls();
                            if (hasInstallPermission) {
                                Log.d("zwk", "有安装未知应用的安装权限");
                                installIntent.setDataAndType(Uri.fromFile(new File(updateDir, fileName)), "application/vnd.android.package-archive");
                            } else {
                                Log.d("zwk", "没有安装未知应用的安装权限");
                                startInstallPermissionSettingActivity();
                                return;
                            }
    
                        }
    
                    } else {
                        installIntent.setDataAndType(Uri.fromFile(new File(updateDir, fileName)), "application/vnd.android.package-archive");
                    }
                    startActivity(installIntent);
    

    7.0前和后的区别,还是Uri变更导致的,只需要进行版本判断采用相应的方法就可以适配.

  • 分享

    使用Intent进行应用A和应用B之间得分享得时候,如果在7.0上应用B显示图片得时候常常会出现如下异常:

Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{f7cd2c 3445:com.example.androidnseconddemo/u0a88} (pid=3445, uid=10088) that is not exported from uid 10085
        at android.os.Parcel.readException(Parcel.java:1684)
原因就是7.0中分享,应用A需要加入临时权限				

shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
具体代码:
应用A:

	Intent shareIntent = new Intent();
	shareIntent.setAction(Intent.ACTION_SEND);
	shareIntent.setDataAndType(imageUri, "image/*");

	shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);// 权限

	startActivity(shareIntent);

应用B:

	Intent intent = getIntent();
	imgUri = intent.getData();
	imageView.setImageBitmap(BitmapFactory.decodeStream(getContentResolver().openInputStream(imgUri)));

  • Uri 适配

    Uri imageUri;
    if (Build.VERSION.SDK_INT>Build.VERSION_CODES.N){
     	imgUri=FileProvider.getUriForFile(context,authority,file);
    }else{
    	imageUri = Uri.fromFile(file)
    }
    
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值