Android 9适配经验总结

news/2025/2/22 23:26:10/

目录

  • 四大组件适配
    • Activity启动方式适配
    • Service启动方式适配
    • 前台服务需要添加权限
    • 限制静态广播的接收
    • 限制ContentResolver数据更新操作
  • 权限与安全相关主要适配点
    • 运行时动态权限申请
    • 默认不支持 http 请求
    • SharedPreferences 适配

四大组件适配

Android 应用的开发离不开 Android 四大组件的使用,Android 四大组件分别是:Activity,用于展示前台页面;Service,用于执行后台任务;BroadCast,用于组件之间的通信;ContentProvider,用于应用间数据的分享。

Activity启动方式适配

Activity 组件用于和用户进行交互,在 Android 9 版本中,系统对于应用进程的任务栈做了调整,Activity 组件是运行在任务栈(task stack)中,而其它三大组件 Broadcast、Service、ContentProvider不需要运行在任务栈中,由这些组件打开 Activity 时需要为这个 Activity 的运行指定一个新的任务栈,否则会导致应用崩溃,并抛出异常信息:

android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

适配方法,在 Broadcast、Service、ContentProvider 这些组件中拉起 Activity,需要添加FLAG_ACTIVITY_NEW_TASK标志,这样便会在拉起 Activity 的同时,创建出一个新的任务栈:

Intent intent = new Intent(context, "xxxxx");//xxxxx 表示 Activity 的类名
intent.addFlag(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActiviy(intent);

Service启动方式适配

Service 是 Activity 外最常用的组件之一,它承接着用户处理后台任务的需求,是一种长生命周期的,没有可视化界面,运行于后台的一种服务程序。在 Android 5.0 之后 google 出于安全的角度禁止了隐式声明 Intent 来启动 Service,隐式声明即是不通过指定 Service 包名和类名,而是通过Intent 过滤机制,设置 intent 的 action、dataType 等方式根据 intent 匹配规则来查找并调用 Service:

Intent intent = new Intent(); 
intent.setAction("xxxx");//xxxx 为Service 在 IntentFilter 中配置的 action
context.startService(intent);

隐式启动 Service 会产生一个问题,就是传入的 action、dataType 可能会匹配到别的应用的后台服务上去,Service 是在后台运行的,不被用户所感知,因此通过隐式方式启动 Service 可能拉起的不是实际想要启动的服务,从而会产生错误。

为了防止隐式启动 Service 带来的问题,从 Android5.0 开始系统就禁止隐式启动 Service 的方式,上述代码在 Android9 系统上运行时会导致应用崩溃,并抛出异常:

Service Intent must be explicit…

适配方法

解决方式一: 将隐式启动转换为显式启动,通过指定包名、类名的方式拉起服务:

ComponentName cn = new ComponentName("包名","类名"); 
Intent intent = new Intent(cn);//显示启动 Service 
context.startService(intent);

解决方式二:调用 intent 的 setPackage 方法指定包名:

Intent intent = new Intent(); 
intent.setAction("xxxx");//xxxx 为Service 在 IntentFilter 中配置的 action
intent.setPackage("应用包名");
context.startService(intent);

前台服务需要添加权限

在 Android 9.0 中,为了防止前台服务被滥用,比如各种通知信息,系统规定应用在使用前台服务之前必须先申请 FOREGROUND_SERVICE 权限,否则就会抛出 SecurityException 异常。

java.lang.SecurityException: Permission Denial: startForeground from pid=xxxx, uid=xxxx requires android.permission.FOREGROUND_SERVICE

适配方法,在 AndroidManifest 中添加权限声明:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
通过这样方式便可以申请前台服务的运行权限,前台服务的创建才会正常执行。

限制静态广播的接收

应用监听广播可以通过动态注册和静态注册两种方式,动态注册就是在程序运行起来后,调用注册方法进行注册,静态注册则是把广播注册放在 Manifest 配置文件中。

在一些场景中,比如监听开机启动广播来拉起应用,是需要通过静态注册方式来实现。但对于需要应用正常启动后才能对广播进行正确处理的场景,则应用使用动态注册的方式,这时如果采用静态注册的方式,在应用没有启动时,收到广播可能不会得到正确的处理,同时都采用静态注册的方式也会影响广播传递的效率,因为很多未启动的应用也会被广播唤醒。

也是出于这样的考虑,Android 9.0 之后,隐式广播将会被全面限制,用户的自定义广播和大部分系统广播通过隐式注册的方式,即在 AndroidManifest 中注册的 Receiver 的方式将不能够生效。

适配方法,使用动态注册的方式注册广播监听,如下代码:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("xxxx");//xxxx 标识广播 action
context.registerReceiver(broadcastReceiver, intentFilter);

采用代码中动态注册广播的方式不仅是 Android9 系统的要求,也是一种比较好的开发习惯,这有利于对广播的使用进行控制,在应用功能已经初始化完成的时候添加广播的监听,确保广播到来时的功能执行能正常进行。

限制ContentResolver数据更新操作

Android 提供 ContentProvider/ContentResolver 组件来让用户开放自己应用中的数据或者访问别的应用的数据,为了防止用户数据监听被滥用,从 Android8.0 系统起,通过 ContentResolver的registerContentObserver 方法监听应用数据变化的操作被加以限制,直接操作会报出如下错误,并导致应用崩溃:

Failed to find provider xxx for user xxx; expected to find a valid ContentProvider for this authority

适配方法,在 AndroidManifest.xml 文件中定义一个 Provider,使用监听数据更新的目标 ContentProvider的 authorities 作为这个 provider 的 authorities:

<providerandroid:name="com.xx.content.ContentProvider"android:authorities="com.xxx.androidclient" android:enabled="true" android:exported="false">
</provider>

权限与安全相关主要适配点

运行时动态权限申请

Google 在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限和危险权限。应用的相关功能每次在使用危险权限时需要动态的申请并得到用户的授权才能使用。

系统权限分为两类:正常权限和危险权限。

正常权限不会直接给用户隐私权带来风险。如果您的应用在其清单中列出了正常权限,系统将自动授予该权限。

危险权限会授予应用访问用户机密数据的权限。如果应用在其清单中列出了危险权限,则用户必须明确批准应用使用这些权限。

危险权限主要是和获取用户数据有关,应用会用到的危险权限包括:

android.permission.READ_EXTERNAL_STORAGE 读取外部存储数据
android.permission.WRITE_EXTERNAL_STORAGE 向外部存储写入数据

常用的正常权限包括:

BLUETOOTH 使用蓝牙权限
BROADCAST_STICKY 粘性广播
CHANGE_NETWORK_STATE 改变网络状态
CHANGE_WIFI_STATE 控制 WiFi 开关,改变 WiFi 状态
GET_PACKAGE_SIZE 获取应用安装包大小
INTERNET 网络权限
RECEIVE_BOOT_COMPLETED 监听启动广播
REQUEST_INSTALL_PACKAGES 安装应用程序
WRITE_SYNC_SETTINGS 修改系统设置

适配方法,应用运行过程中,动态申请需要的危险权限,如下代码:

requestPermissions(final @NonNull Activity activity,final @NonNullString[] permissions, final int requestCode)//permissions 即为需要申请权限列表

默认不支持 http 请求

出于网络安全的考虑,Android9 系统上,应用将被禁止使用 http 协议进行网络数据传输,而必须使用 https 安全网络协议,如果应用中使用了 http 协议传输数据,将会抛出下面的错误:

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

最好的适配方式是修改所有的网络接口,改为 https 协议;除了服务端接口改动,Google 也提供了两个方案来让客户端支持 http 协议。
方案 1:
在 AndroidManifest.xml 中的 application 节点添加以下配置, 允许所有明文请求。

<application
... android:usersCleartextTraffic=“true”
>

方案 2:
添加自定义的网络安全配置在 res 目录下新建 xml 文件夹,添加 network_security_config.xml文件:

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

AndroidManifest.xml 中的 application 添加:

<manifest ... ><applicationandroid:networkSecurityConfig="@xml/network_security_config">... </application>
</manifest>

SharedPreferences 适配

SharedPreferences 是 Android 中的数据存储组件,原先针对数据访问没有严格的限制,
Android9.0 以后给 SharedPreferences 引入数据文件访问权限控制,去除了被外部应用读取数据的权限,设置 MODE_WORLD_READABLEMODE_WORLD_WRITEABLE会触发安全异常。

适配方法
方案 1:
MODE_WORLD_READABLE模 式 换 成MODE_PRIVATE, 通 过 这 种 方 式 将 应 用 的SharedPreference 数据访问权限设置为私有,以防止别的应用对 SharedPreference 数据进行任意的读写操作,保证了应用自身的安全性,对于可以向别的应用暴露的数据,也可以通过ContentProvider组件实现数据共享。

方案 2:
对于需要全局读写的功能,可使用其他方式替换 SharedPreferences,例如DataStoreMMKV等。


http://www.ppmy.cn/news/29713.html

相关文章

python的opencv操作记录13——区域生长及分水岭算法

文章目录图像区域基本算法——形态学运算腐蚀与膨胀开运算与闭运算opencv中的形态学运算距离计算——distanceTransform函数连通域连通的定义计算连通域——connectedComponents连通域实验基于区域的分割区域生长算法自定义一个最简单区域生长算法实现区域分割一般区域分割open…

【软件测试】性能测试面试题都问什么?面试官想要什么?回答惊险避坑......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 1、你认为不同角色关…

地方征信平台第2讲:河北省征信

河北省征信有限公司&#xff0c;注册成立于2022年12月25日&#xff0c;注册资本6330万元人民币。股东及持股比例如下&#xff1a;河北省惠信大数据科技服务有限公司、35.1975%。唐山国控集团有限公司、14.22%。石家庄城控投资集团有限责任公司、 10.8215%。石家庄市国有资本经营…

离线数据仓库项目搭建——准备篇

文章目录&#xff08;一&#xff09;什么是数据仓库&#xff08;二&#xff09;数据仓库基础知识&#xff08;三&#xff09;数据仓库建模方式&#xff08;1&#xff09;星行模型&#xff08;2&#xff09;雪花模型&#xff08;3&#xff09;星型模型 VS 雪花模型&#xff08;四…

单链表详解

单链表一.概念二.一些类型的创建三.尾插四.头插五.头删尾删六.打印链表七.单链表查找,任意位置插入&#xff0c;任意位置删除八.源代码一.概念 该篇链表博客是按照工程项目的格式来记录的&#xff0c;与平常的算法链表有些许不同&#xff0c;注意区分。 二.一些类型的创建 三.尾…

Leaflet基础入门教程(一)

leaflet是一个前端的轻量的gis框架,为什么说它轻量呢。因为相比于传统的“庞大的”GIS框架比如openlayers和mapbox,leaflet不仅代码体积小,而且API构成也极为简单。是GIS行业小白入门级别学习的最好的框架,没有之一。 那么话不多说我们首先来学习一下如何使用leaflet搭建一…

Vulnhub靶场----9、DC-9

文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-9下载地址&#xff1a;https://download.vulnhub.com/dc/DC-9.zip kali&#xff1a;192.168.144.148 DC-9&#xff1a;192.168.144.158 二、渗透流程 1、信息收集nmap -T5 -A -p- -sV -sT 192.168.144.158思路&am…

首版次软件产品认证/山东省首版次高端软件申报通知

各市工业和信息化局&#xff1a; 为贯彻落实《山东省人民政府办公厅关于加快推动软件产业高质量发展的实施意见》(鲁政办发〔〕1号)&#xff0c;加速提升软件供给能力&#xff0c;努力打造山东软件“名品”&#xff0c;构建高端软件产业生态&#xff0c;现组织开展第七批山东省…