11赞
521
当前位置:  开发笔记 > 编程语言 > 正文

Android版本、权限适配相关总结

针对Android6.0(API23)已以上版本,Google增强全新的权限,应用程序在使用敏感权限(如拍照、查阅联系人或存储)时需要先征求用户必须赢得用户同意。

请求存储权限

首先需要在 AndroidManifest.xml 文件中声明权限:


在代码中请求用户权限:

    // 权限请求码
    private static final int PERMISSION_REQ_ID = 0;  
    // 请求权限
    private static final String[] REQUESTED_PERMISSIOnS= {
            Manifest.permission.READ_EXTERNAL_STORAGE
    };

    ...

     // 判断有没有存储权限
    if (checkSelfPermission(REQUESTED_PERMISSIONS[0],PERMISSION_REQ_ID)){
        //YSE 
    }else {
        //NO
    }
    private boolean checkSelfPermission(String permissions,int requestCode){
        if (ContextCompat.checkSelfPermission(this,permissions) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);
            return false;
        }
        return true;
    }

    // 重写此方法,接收用户授权回调
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        Log.i(TAG, "onRequestPermissionsResult: requestCode =" + requestCode
                +"\n,permissiOns=" + Arrays.toString(permissions)
                +"\n,grantResults =" + Arrays.toString(grantResults));
        if (requestCode == PERMISSION_REQ_ID){
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
                //用户同意权限
            }else {
                //用户拒绝权限
            }
        }
    

版本适配

从 Android 6.0 到 Android 10 存储/访问文件功能,有发生了很多变化。

Android 7.0 前

在Android 7.0 以前我们访问内存中的文件可以通过 Uri.fromFile,将 File 转换成 Uri 对象,这个 Uri 对象表示这本地真实路径。 访问一个图片:

String fileName = "default_Image.jpg";
File file = new File("file_path", fileName);
Uri uri = Uri.fromFile(file);

Android 7.0 后

在 7.0 后,这种通过真实路径来获取的 Uri 被认为是不安全的,所以提供了一种新的解决方案,就是通过 FileProvide 来实现文件的访问,FileProvider 是一种比较特殊的内容提供器,他使用了类似于内容提供器的机制来对数据进行保护。 访问一个图片:

    File file = new File(CACHE_IMG, "file_name");
    Uri imageUri = FileProvider.getUriForFile(activity,"com.sandan.fileprovider", file); //这里进行替换uri的获得方式

然而上面这种真的好吗,对用开发者而且这算是好处吧,但是对用用户而言,上述的无疑一些流氓作用,因为开发者完全可以访问的内存中的所有位置,并作出一些改变,导致 SD 卡中的空间变得非常乱,即使卸载了 app,但是一些垃圾文件却还在内存中。

Android 10.0

在 Android 10.0 ,为了解决上述问题,Google 在 Android 10.0 中加入了 作用域功能。

什么是作用域

就是 Android 系统对 SD 卡做了很大的限制,从 Android 10.0 开始,每个程序只能有权在自己的外置存储空间关联的目录下读取和创建相应的文件,也称作沙箱。获取该目录的代码是:getExternalFilesDir() ,关联的目录路径大致如下:

 Html CSS Javascript Vb vbs Asp PHP Perl Python Ruby C# C++ SQL Delphi Diff Groovy Java JavaFX ActionScript3 Bash/shell powershell Plain Text Scala XML显示语言名称 显示行号 允许折叠 

将数据放在这个目录下,你可以使用之前的方法对文件进行读写,不需要作出任何变更和适配。但是这个文件夹中的文件会随着应用卸载而被随之删除。 那如果需要访问其他目录怎么办呢?比如获取相册中的图片,向相册中添加一张图片。为此,Android 系统针对系统文件类型进行了分类:图片,音频,视频 这三类文件可以通过 MediaStore API 来进行访问,这种称为共享空间,其他的系统文件需要使用 系统的文件选择器来进行访问,另外,如果程序向媒体库写入图片,视频,音频,将会自动用于读写权限,不需要额外申请权限,如果你要读取其他程序向媒体贡献的图片,视频,音频,则必须要申请 READ_EXTERNAL_STORAGE 权限,WRITE_EXTERNAL_STORAGE 权限会在未来的版本中被废弃。

举个栗子

举例说明:有一张本地图片,向这张图片添加水印,并保存到相册。

直接上代码:

    /**
     * 保存图片到相册
     *
     * @param context 上下文
     * @param text 水印文字
     */
    private void savePhotoAlbum(final Context context, final String text) {
        //这里开启子线程,防止堵塞。
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //从本地获取一张图片,转成Bitmap
                    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon_info);
                    //在沙箱中创建文件,名称:info.jpg
                    File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_PICTURES), "info.jpg");
                    //判断文件是否存在,不存在创建文件。
                    if (!file.exists()) {
                        file.createNewFile();
                    }
                    // 向图片添加水印
                    Bitmap newBitmap = addInfoWatermark(context, bitmap, text);
                    // 更新相册
                    updatePhotoAlbum(context, newBitmap, file);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start(); //开始线程
    }

   /**
     * 保存到相册
     *
     * @param context 上下文
     * @param src  源图片
     * @param text 水印文字
     */
    private Bitmap addInfoWatermark(final Context context, Bitmap src, String text) {
        //判断图片/水印文字 是否为空
        if (isEmptyBitmap(src) || text == null ) {
            return null;
        }
        // 从源图片复制一份
        Bitmap ret = src.copy(src.getConfig(), true);
        // 初始化画笔
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
         // 初始化画布
        Canvas canvas = new Canvas(ret);
        // 水印文字:黑色
        paint.setColor(Color.BLACK);
        // 文字大小:19dp
        paint.setTextSize(dip2px(context, 19));
         // 开始绘画
        canvas.drawText(text, 10, 10 , paint);
        // 循环利用资源
        if (!src.isRecycled()) {
            src.recycle(); 
        }
        return ret;
    }

    /**
     * 保存到相册
     *
     * @param context 上下文
     * @param src  源图片
     * @param file 要保存到的文件
     */
    private void savePhotoAlbum(final Context context, Bitmap src, final File file) {
        //判断图片 是否为空
        if (isEmptyBitmap(src)) {
            return;
        }
        // 保存文件
        OutputStream outputStream;
        try {
            //输出这个文件
            outputStream = new BufferedOutputStream(new FileOutputStream(file));
            // 压缩
            src.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
            // 循环利用资源
            if (!src.isRecycled()) {
                src.recycle();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 更新图库,这个在 Android 6.0 和 Android 10.0 更新图库,存在差异。
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {  
            // Android 10.0 及以上
            // 创建 ContentValues 对象,准备插入数据
            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, file.getName());
            values.put(MediaStore.MediaColumns.MIME_TYPE, getMimeType(file));
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
            ContentResolver cOntentResolver= context.getContentResolver();
            // 插入数据,返回所插入数据对应的Uri
            Uri uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            if (uri == null) {
                return;
            }
            try {
                // 获取刚插入的数据的Uri对应的输出流
                outputStream = contentResolver.openOutputStream(uri);
                FileInputStream fileInputStream = new FileInputStream(file);
                // 从一个流复制到另一个流上
                FileUtils.copy(fileInputStream, outputStream);
                //关闭流
                fileInputStream.close();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            // android 6.0 - 10.0
            // 扫描文件
            MediaScannerConnection.scanFile( context.getApplicationContext(), new String[]{file.getAbsolutePath()}, new String[]{"image/jpeg"},
                    new MediaScannerConnection.OnScanCompletedListener() {
                        @Override
                        public void onScanCompleted(String path, Uri uri) {
                            //通知相册更新
                            // 插入图片
                            MediaStore.Images.Media.insertImage( context.getContentResolver(),  BitmapFactory.decodeFile(path), file.getName(), null);
                            Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                            Uri u = Uri.fromFile(file);
                            intent.setData(u);
                            context.sendBroadcast(intent);  // 发广播通知,更新相册
                        }
                    });
        }
    }

    /**
     * Bitmap对象是否为空。
     */
    private static boolean isEmptyBitmap(Bitmap src) {
        return src == null || src.getWidth() == 0 || src.getHeight() == 0;
    }

    /**
     * 获取 Mime 类型
     *
     * @param file 文件
     * @return Mime 类型
     */
    private static String getMimeType(File file) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String type = fileNameMap.getContentTypeFor(file.getName());
        return type;
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public int dip2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

以上就是Android 版本、权限适配相关总结的详细内容,更多关于Android 版本、权限适配的资料请关注其它相关文章!


推荐阅读
  • FastMM是非常优秀的内存管理器,但是从FastMM4Options.inc中找到合适自已程序的选项设置免不了一顿英文的纠缠,所以我把这个文件里的所有英文注释都翻译成了中文。如果 ... [详细]
  • Android版数据结构与算法(七):赫夫曼树
    版权声明:本文出自汪磊的博客,未经作者允许禁止转载。近期忙着新版本的开发,此外正在回顾C语言,大部分时间没放在数据结构与算法的整理上,所以更新有点慢了,不过既然写了就肯定尽力将这部分完全整理好分享 ... [详细]
  • VB与VB.net各自的优势与区别是什么?vb.net是vb的升级。vb.net基于.net框架,是vb发展的必然趋势。vb功能非常强大,但是也存在众多的缺点,所以微软才会开发vb ... [详细]
  • JNI技术
    1.JNI介绍JavaNativeInterface(JNI)是Java语言的本地编程接口,是J2SDK的一部分。在java程序中,我们可以通过JNI实现一些用java语言不便实现 ... [详细]
  • Android开发教程:扩展的ListView实例
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 问题    我对编程很感兴趣,比较会c语言和c++语言,现在很想学C++.net。    正在看牛力和傅韵编的VisualC++.NET编程宝典,感觉难度很 ... [详细]
  • pipinstallbootstarp使用bower安装bootstrap的命令是:bash$bowerinstallbootstrap不过问题出在如何安装bower上。官方网站上 ... [详细]
  • transform:translateY(50px);transform:translateY(0px);这两行代码实现了元素从下向上移动opacity:0;opacity:0 ... [详细]
  • IOS多线程操作
    多线程的概念 进程·正在运行中的程序被成为进程,负责程序运行的内存分配 ·没一个进程都有自己独立的虚拟内存空间 线程·线程是进程中一个独立的执行路径也称之为控制单元·一个进程至少 ... [详细]
  • 你真的会用console吗—前端开发
    你真的会用console吗—前端开发 ... [详细]
  • 如何解决《select2没有响应,宽度大于容器》经验,为你挑选了2个好方法。 ... [详细]
  • 如何解决《XcodeLocalizable.string多个目标问题》经验,是哪儿的问题? ... [详细]
  • 成员变量,本例中的是实例成员变量,是作用于整个类对象内的。从生命周期来看,它比局部变量要长一些,但它默认是私有的,其他对象是无法访问到的。 比如你一个变量放在@interfa ... [详细]
author-avatar
手机用户2502931241
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有