Android10填坑适配指南,实际经验代码,持续补充

2023-10-29

Android10填坑适配指南,包含实际经验代码,绝不照搬翻译文档

1.Region.Op相关异常:java.lang.IllegalArgumentException: Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed

targetSdkVersion >= Build.VERSION_CODES.P 时调用 canvas.clipPath(path, Region.Op.XXX); 引起的异常,参考源码如下:

@Deprecated
public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) {
     checkValidClipOp(op);
     return nClipPath(mNativeCanvasWrapper, path.readOnlyNI(), op.nativeInt);
}

private static void checkValidClipOp(@NonNull Region.Op op) {
     if (sCompatiblityVersion >= Build.VERSION_CODES.P
         && op != Region.Op.INTERSECT && op != Region.Op.DIFFERENCE) {
         throw new IllegalArgumentException(
                    "Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed");
     }
}

我们可以看到当目标版本从Android P开始,Canvas.clipPath(@NonNull Path path, @NonNull Region.Op op) ; 已经被废弃,而且是包含异常风险的废弃API,只有 Region.Op.INTERSECT 和 Region.Op.DIFFERENCE 得到兼容,几乎所有的博客解决方案都是如下简单粗暴:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    canvas.clipPath(path);
} else {
    canvas.clipPath(path, Region.Op.XOR);// REPLACE、UNION 等
}

但我们一定需要一些高级逻辑运算效果怎么办?如小说的仿真翻页阅读效果,解决方案如下,用Path.op代替,先运算Path,再给canvas.clipPath:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
    Path mPathXOR = new Path();
    mPathXOR.moveTo(0,0);
    mPathXOR.lineTo(getWidth(),0);
    mPathXOR.lineTo(getWidth(),getHeight());
    mPathXOR.lineTo(0,getHeight());
    mPathXOR.close();
    //以上根据实际的Canvas或View的大小,画出相同大小的Path即可
    mPathXOR.op(mPath0, Path.Op.XOR);
    canvas.clipPath(mPathXOR);
}else {
    canvas.clipPath(mPath0, Region.Op.XOR);
}

2.明文HTTP限制

targetSdkVersion >= Build.VERSION_CODES.P 时,默认限制了HTTP请求,并出现相关日志:

java.net.UnknownServiceException: CLEARTEXT communication to xxx not permitted by network security policy

第一种解决方案:在AndroidManifest.xml中Application添加如下节点代码

<application android:usesCleartextTraffic="true">

第二种解决方案:在res目录新建xml目录,已建的跳过 在xml目录新建一个xml文件network_security_config.xml,然后在AndroidManifest.xml中Application添加如下节点代码

android:networkSecurityConfig="@xml/network_config"

名字随机,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

3.Android Q中的媒体资源读写

1、扫描系统相册、视频等,图片、视频选择器都是通过ContentResolver来提供,主要代码如下:

private static final String[] IMAGE_PROJECTION = {
            MediaStore.Images.Media.DATA,
            MediaStore.Images.Media.DISPLAY_NAME,
            MediaStore.Images.Media._ID,
            MediaStore.Images.Media.BUCKET_ID,
            MediaStore.Images.Media.BUCKET_DISPLAY_NAME};

 Cursor imageCursor = mContext.getContentResolver().query(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    IMAGE_PROJECTION, null, null, IMAGE_PROJECTION[4] + " DESC");

String path = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[0]));
String name = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[1]));
int id = imageCursor.getInt(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[2]));
String folderPath = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[3]));
String folderName = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[4]));

//Android Q 公有目录只能通过Content Uri + id的方式访问,以前的File路径全部无效,如果是Video,记得换成MediaStore.Videos
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
      path  = MediaStore.Images.Media
                       .EXTERNAL_CONTENT_URI
                       .buildUpon()
                       .appendPath(String.valueOf(id)).build().toString();
 }

2、判断公有目录文件是否存在,自Android Q开始,公有目录File API都失效,不能直接通过new File(path).exists();判断公有目录文件是否存在,正确方式如下:

public static boolean isAndroidQFileExists(Context context, String path){
        AssetFileDescriptor afd = null;
        ContentResolver cr = context.getContentResolver();
        try {
            Uri uri = Uri.parse(path);
            afd = cr.openAssetFileDescriptor(uri, "r");
            if (afd == null) {
                return false;
            } else {
                close(afd);
            }
        } catch (FileNotFoundException e) {
            return false;
        }finally {
            close(afd);
        }
        return true;
}

 

3、copy或者下载文件到公有目录,保存Bitmap同理,如Download,MIME_TYPE类型可以自行参考对应的文件类型,这里只对APK作出说明,从私有目录copy到公有目录demo如下(远程下载同理,只要拿到OutputStream即可,亦可下载到私有目录再copy到公有目录):

public static void copyToDownloadAndroidQ(Context context, String sourcePath, String fileName, String saveDirName){
        ContentValues values = new ContentValues();
        values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
        values.put(MediaStore.Downloads.MIME_TYPE, "application/vnd.android.package-archive");
        values.put(MediaStore.Downloads.RELATIVE_PATH, "Download/" + saveDirName.replaceAll("/","") + "/");

        Uri external = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
        ContentResolver resolver = context.getContentResolver();

        Uri insertUri = resolver.insert(external, values);
        if(insertUri == null) {
            return;
        }

        String mFilePath = insertUri.toString();

        InputStream is = null;
        OutputStream os = null;
        try {
            os = resolver.openOutputStream(insertUri);
            if(os == null){
                return;
            }
            int read;
            File sourceFile = new File(sourcePath);
            if (sourceFile.exists()) { // 文件存在时
                is = new FileInputStream(sourceFile); // 读入原文件
                byte[] buffer = new byte[1444];
                while ((read = is.read(buffer)) != -1) {
                    os.write(buffer, 0, read);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            close(is,os);
        }

}

 4、保存图片相关

 /**
     * 通过MediaStore保存,兼容AndroidQ,保存成功自动添加到相册数据库,无需再发送广播告诉系统插入相册
     *
     * @param context      context
     * @param sourceFile   源文件
     * @param saveFileName 保存的文件名
     * @param saveDirName  picture子目录
     * @return 成功或者失败
     */
    public static boolean saveImageWithAndroidQ(Context context,
                                                  File sourceFile,
                                                  String saveFileName,
                                                  String saveDirName) {
        String extension = BitmapUtil.getExtension(sourceFile.getAbsolutePath());

        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.DESCRIPTION, "This is an image");
        values.put(MediaStore.Images.Media.DISPLAY_NAME, saveFileName);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
        values.put(MediaStore.Images.Media.TITLE, "Image.png");
        values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/" + saveDirName);

        Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        ContentResolver resolver = context.getContentResolver();

        Uri insertUri = resolver.insert(external, values);
        BufferedInputStream inputStream = null;
        OutputStream os = null;
        boolean result = false;
        try {
            inputStream = new BufferedInputStream(new FileInputStream(sourceFile));
            if (insertUri != null) {
                os = resolver.openOutputStream(insertUri);
            }
            if (os != null) {
                byte[] buffer = new byte[1024 * 4];
                int len;
                while ((len = inputStream.read(buffer)) != -1) {
                    os.write(buffer, 0, len);
                }
                os.flush();
            }
            result = true;
        } catch (IOException e) {
            result = false;
        } finally {
            close(os, inputStream);
        }
        return result;
}

4.EditText默认不获取焦点,不自动弹出键盘

该问题出现在 targetSdkVersion >= Build.VERSION_CODES.P 情况下,且设备版本为Android P以上版本,解决方法在onCreate中加入如下代码,可获得焦点,如需要弹出键盘可延迟一下:

mEditText.post(() -> {
       mEditText.requestFocus();
       mEditText.setFocusable(true);
       mEditText.setFocusableInTouchMode(true);
});

 5.安装APK Intent及其它共享文件相关Intent

/*
* 自Android N开始,是通过FileProvider共享相关文件,但是Android Q对公有目录 File API进行了限制,只能通过Uri来操作,
* 从代码上看,又变得和以前低版本一样了,只是必须加上权限代码Intent.FLAG_GRANT_READ_URI_PERMISSION
*/ 
private void installApk() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
            //适配Android Q,注意mFilePath是通过ContentResolver得到的,上述有相关代码
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.parse(mFilePath) ,"application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            startActivity(intent);
            return ;
        }

        File file = new File(saveFileName + "demo.apk");
        if (!file.exists())
            return;
        Intent intent = new Intent(Intent.ACTION_VIEW);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "net.oschina.app.provider", file);
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        startActivity(intent);
}

6.Activity透明相关,windowIsTranslucent属性

Android Q 又一个天坑,如果你要显示一个半透明的Activity,这在android10之前普通样式Activity只需要设置windowIsTranslucent=true即可,但是到了AndroidQ,它没有效果了,而且如果动态设置View.setVisibility(),界面还会出现残影...

解决办法:使用Dialog样式Activity,且设置windowIsFloating=true,此时问题又来了,如果Activity根布局没有设置fitsSystemWindow=true,默认是没有侵入状态栏的,使界面看上去正常。

7.剪切板兼容

Android Q中只有当应用处于可交互情况(默认输入法本身就可交互)才能访问剪切板和监听剪切板变化,在onResume回调也无法直接访问剪切板,这么做的好处是避免了一些应用后台疯狂监听响应剪切板的内容,疯狂弹窗。

因此如果还需要监听剪切板,可以使用应用生命周期回调,监听APP后台返回,延迟几毫秒访问剪切板,再保存最后一次访问得到的剪切板内容,每次都比较一下是否有变化,再进行下一步操作。

8.第三方分享图片等操作,直接使用文件路径的,如QQ图片分享,都需要注意,这是不可行的,都只能通过MediaStore等API,拿到Uri来操作

本文转载自:https://blog.csdn.net/huanghaibin_dev/article/details/103237821

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android10填坑适配指南,实际经验代码,持续补充 的相关文章

  • Unity快速适配IOS/安卓刘海屏(又简单又快 适配了O版本和P版本)

    刘海屏适配 其实就是知道刘海高度 横屏游戏 来对ui进行偏移 所以刘海屏适配的关键是获取刘海高度 获取刘海高度有三种方案 1 大数据 收集各种型号对应的刘海数据 听说腾讯有些项目这么搞 2 代码获取 热门机型获取刘海数据 小众机型不是and
  • VNDK extensions

    Android P要求开VNDK 如果HAL需要链接android原生库 原生库的Android bp必须包含下面内容 如果没有对原生库做任何修改 编译不会出现问题 如果对原生库做了修改 这个时候编译会出错 会提示不允许链接该库 这个时候就
  • Android中的DPI和PPI

    DPI是Android开发中的像素密度 PPI是Android手机物理像素密度 他们两者是完全没有关系的 千万不要把ppi的公式等同于dpi dpi是通过displayMetrics获取的 val densityDpi resources
  • Android10填坑适配指南,实际经验代码,持续补充

    Android10填坑适配指南 包含实际经验代码 绝不照搬翻译文档 1 Region Op相关异常 java lang IllegalArgumentException Invalid Region Op only INTERSECT an
  • 怎样简便的使用vw完成移动端rem适配

    怎样简便的完成移动端rem适配 了解一些必要的单位 px 像素 进行页面开发的基础单位 em 相对单位 rem 相对单位 vw 相对宽度 vh 相对高度 如何进行简单的px rem转换 了解一些必要的单位 px 像素 进行页面开发的基础单位
  • 安卓9.0适配方案和踩坑

    年初的时候就已经适配了安卓9 0 但由于业务需求一直没有使用上 前段时间发布了 结果有用户反馈在安卓9 0的手机上更新下载App发生了闪退 这个时候发现9 0对权限 加密和Apache HTTP client发生了相关变化 一 首先我遇到的
  • java.net.UnknownServiceException: CLEARTEXT communication to www.httpbin.org not permitted by networ

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 在Android9 0系统的手机上访问http的api 出现以下异常 java net UnknownServiceException
  • Android 10(Android Q) 适配

    官方网站 沙盒存储 Android Q 中的隐私权 重大隐私权变更 官方网站 展示时间敏感的通知 1 设备硬件信息读取限制 在Android10中 系统不允许普通App请求android permission READ PHONE STAT
  • 浏览器适配,各大浏览器适配,主流/冷门浏览器适配,css

    浏览器适配 各大浏览器适配 主流 冷门浏览器适配 flex布局问题 flex布局早在2009年就有了 到现在已经有了好几个版本 详细内容可查看这篇文章 flex布局兼容性 其中IE10部分支持2012 需要使用 ms 前缀 而IE9不支持f
  • Rk3399 Android9.0 恢复出厂设置流程

    Reset 流程 1 原生设置中响应 恢复出厂设置 功能 继而发出重置广播 Intent ACTION FACTORY RESET 2 frameWork层 接收到此广播 根据广播所携带的参数执行Android层的Reset设定 3 And
  • Android 13 媒体权限适配指南

    在 Android 系统最近的几个大版本里 更新方向有很大一部分都集中在了隐私安全这一方面 每个版本都会新增隐私安全限制 或者是对之前的隐私项进行进一步的升级 Android 10 分区存储 限制访问不可重置的硬件标识符 限制对剪贴板数据的
  • 适配IPv6遇到的坑,终极解决方案

    6 1AppStore发布之后的应用要兼容IPv6 然而我上个星期发布的版本并没有因为没兼容而被拒 这次提交却遇到IPv6兼容问题 话不多说 上代码 NSString getIPWithHostName const NSString hos
  • 移动端适配方案之postcss-px-to-viewport

    之前做移动端适配时 基本上是采用rem方案 现在发现了一个新的方案 就是用viewport单位 现在viewport单位越来越受到众多浏览器的支持 postcss px to viewport 将px单位自动转换成viewport单位 用起
  • Wifi模块—源码分析Wifi热点扫描2(Android P)

    一 前言 这次接着讲Wifi工程流程中的Wifi热点扫描过程部分的获取扫描结果的过程 也是Wifi扫描过程的延续 可以先看前面Wifi扫描的分析过程 Wifi模块 源码分析Wifi热点扫描 Android P 二 图示调用流程 这次的调用流
  • Android 兼容8.0 App全局字体调节、禁止App字体随系统字体大小而更改

    在APP中 字体的大小单位一般会用sp 然而在改变系统字体大小时 App字体就会随着系统字体大小改变而改变 这就可能造成APP布局的错位 造成这种情况的原因是 sp单位除了受屏幕密度影响外 还受到用户的字体大小影响 通常情况下 建议使用sp
  • Unity屏幕适配解决方案

    文章目录 UI尺寸选择 市面设备比例 内存占用 分辨率适配 高分辨率 分屏模式 宽高比适配 常规尺寸适配 刘海屏适配 全面屏适配 UI尺寸选择 市面设备比例 截至2017年9月 iOS与Android移动游戏设备比例约为iOS占28 And
  • android刘海屏之终极适配

    前言 作为安卓开发 也得承认苹果设计一直在引领潮流 所以自从 iPhone X 发布之后 刘海屏 就一直被热议 作为我自己必须先吐槽一下 真没觉得刘海屏好看 但是作为苦逼的开发者 还是要必须去适配刘海屏的 自然而然的在吐槽完毕以后还是有了这
  • android 手机获取是否开启了底部导航栏兼容小米、华为

    TargetApi Build VERSION CODES JELLY BEAN MR1 public static boolean isNavigationBarShow WindowManager windowManager Displ
  • 大屏数据可视化——屏幕适配方案(多分辨率下)

    文章目录 前言 一 一些前提概念 1 1 常见大屏分辨率 1 2 设备像素 二 适配痛点 三 关于rem 四 关于px2rem 五 适配方案 5 1 rem自适应缩放 5 2 css3缩放scale 六 demo演示 6 1 1366 76
  • 移动端适配方案的优缺点比较

    当我们说到适配方案的时候越来越多的人会潜意识的翻译成移动端适配方案 确实是这样 在移动端蓬勃发展的今天 移动端的适配显得尤为重要 PC应用的适配已经不是适配方案主要需要考虑的了 随着移动互联网的来临 追求移动端的完美展示才是王道 最近也在做

随机推荐

  • Spring 依赖注入

    依赖注入方式 1 构造器注入 2 setter注入 3 接口注入 maven pom xml配置 引入jar包和依赖jar
  • matlab读取文件夹的数据,根据文件名进行分类,加个分类后写入到不同文件夹中(.txt)

    读取文件夹下的所有文件 根据文件名中包含的内容进行分类 将不同的分类写入到不同的文件夹下 1 直接读取文件 根据文件名分类 不做任何处理 使用copyfile 将数据按照不同泳姿分类 不作其他处理 function Classificati
  • Linux IO实时监控iostat命令

    简介 iostat主要用于监控系统设备的IO负载情况 iostat首次运行时显示自系统启动开始的各项统计信息 之后运行iostat将显示自上次运行该命令以后的统计信息 用户可以通过指定统计的次数和时间来获得所需的统计信息 语法 iostat
  • nginx搭建前后端分离架构

    本人用的是vue cli 自动构建vue webpack 项目 这里不对webpack nginx进行讲解 本文主要解决前端开发环境搭建 测试环境搭建 生产环境搭建以及接口调试 一 需要工具 1 nginx 配置代理 2 webpack d
  • 了解基于Token的身份验证的来龙去脉

    简介 在Web领域基于Token的身份验证随处可见 在大多数使用Web API的互联网公司中 tokens 是多用户下处理认证的最佳方式 以下几点特性会让你在程序中使用基于Token的身份验证 1 无状态 可扩展 2 支持移动设备 3 跨程
  • C++的数据类型——常量

    2 2 常量 2 2 2 数值常量 数值常量就是通常所说的常数 在C 中可以从字面形式区分数值类型 1 整形常量 整数 的类型 通常有 int short int long int unsigned int 通常整数的类型不同 它们值的范围
  • Log4net创建日志及简单扩展

    1 概述 log4net是 Net下一个非常优秀的开源日志记录组件 log4net记录日志的功能非常强大 它可以将日志分不同的等级 以不同的格式 输出到不同的媒介 本文主要是介绍如何在Visual Studio2008中使用log4net快
  • tomcat8.5启动控制台乱码解决

    环境 win10 系统 tomcat8 5版本 现象 本地启动控制台日志乱码 解决办法 conf目录下 logging properties 文件 java util logging ConsoleHandler encoding UTF
  • java中mergesort函数怎么用,由mergeSort引发的一些思考

    重新梳理一下归并排序以及一些相关的东西 对于归并排序大家如果需要回忆下是个什么东西的话 可以点击这个链接 里面有各种排序的动画演示以及讲解 比我再用文字赘述一遍要好得多 功能相当强大 先给出归并排序的js代码实现 function merg
  • 如何处理公共异常处理

    一般而言为了使我们的代码更容易维护 会创建一个类集中处理异常 该异常类可以创建在公共工程中 创建例如 ControllerAdvice public class BaseExceptionHandler 异常处理 param e retur
  • Unity角色控制器CharacterController的简单介绍

    角色控制器 CharacterController 首先 角色控制器没有碰撞效果 这是和刚体的区别 不像刚体可以给其力 如果想使人物移动 直接复制官方文本中的CharacterController下的Move 方法 前台添加 Charact
  • 【Linux】网络设置之基础操作命令详解

    大家好 本篇文章主要讲的是Linux网络设置之基础操作命令详解 感兴趣的同学快来看一看吧 对你有用的话记得收藏起来 方便下次浏览 查看网络配置 查看网络接口信息 ifconfig 查看活动的网络接口设备 1 ifconfig 网卡名称 查看
  • 深度学习之前馈神经网络的入门学习(我觉得是全网最详细的)

    前馈神经网络 Feedforward Neural Network 是一种最基本的人工神经网络模型 它也被称为多层感知器 Multilayer Perceptron MLP 在前馈神经网络中 信息只能在输入层向前传递到输出层 不存在反馈连接
  • PG 数据库锁表问题

    转载文章 若有侵权还请联系 PG 数据库锁表问题解决方案 查询pg数据库锁表的语句和进程 通过进程pid杀掉进程进行批量表解锁 pg锁表解决办法 Fly L的博客 CSDN博客 查询锁表语句和 pid select pid query fr
  • p5js创意自画像

    实验要求 编程语言与工具 编程可以用p5 processing 若想用其他语言或工具 提前向老师说明情况 作品 一件编程创意作品 必须实现动态效果或交互效果 作品录制一段一分钟内的视频 作品可以是具象化地描绘自己的形象 也可以是任何形式表现
  • 2018人工智能应用例子_汇总贴

    大数据分析 e20180621 大数据统计分析 国家审计局 老鼠仓 利用职务便利 操作证券基金 转载于 https www cnblogs com 2010dream p 9218773 html
  • antlr4 Verilog2001.g4

    verilog which antlr4 antlr4 aliased to java Xmx500M cp usr local lib antlr 4 9 complete jar CLASSPATH org antlr v4 Tool
  • 子shell的理解

    创建子shell 在当前shell 使用bash 命令即可创建子shell程序 在子shell上还可以继续创建子shell 例子 使用命令 ps f 查看进程信息 程序运行后就是进程 它可以反应程序运行的状态信息 user1 localho
  • k8s.io/client-go@v0.20.2/tools/cache/reflector.go:167: Failed to watch *v1beta1.Ingress: failed to l

    原因 kubectl version v1 22 不再支持v1beta1 所以要解决这个问题需要把ingress nginx 换成最新的版本 1 0 0
  • Android10填坑适配指南,实际经验代码,持续补充

    Android10填坑适配指南 包含实际经验代码 绝不照搬翻译文档 1 Region Op相关异常 java lang IllegalArgumentException Invalid Region Op only INTERSECT an