Android 12 需要更新适配点并不多,本篇主要介绍最常见的两个需要适配的点:android:exported
和 SplashScreen 。
它主要是设置 Activity
是否可由其他应用的组件启动, “true
” 则表示可以,而“false
”表示不可以。
若为“
false
”,则Activity
只能由同一应用的组件或使用同一用户 ID 的不同应用启动。
当然不止是 Activity
, Service
和 Receiver
也会有 exported
的场景。
一般情况下如果使用了 intent-filter
,则不能将 exported
设置为“false
”,不然在 Activity
被调用时系统会抛出 ActivityNotFoundException
异常。
相反如果没有
intent-filter
,那就不应该把Activity
的exported
设置为true
,这可能会在安全扫描时被定义为安全漏洞。
而在 Android 12 的平台上,也就是使用 targetSdkVersion 31
时,那么你就需要注意:
如果 Activity
、 Service
或 Receiver
使用 intent-filter
,并且未显式声明 android:exported
的值,App 将会无法安装。
这时候你可能会选择去 AndroidManifest
一个一个手动修改,但是如果你使用的 SDK 或者第三方库没有支持怎么办?或者你想要打出不同 target 平台的包?这时候下面这段 gradle 脚本可以给你省心:
/**
* 修改 Android 12 因为 exported 的构建问题
*/
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
output.processResources.doFirst { pm ->
String manifestPath = output.processResources.manifestFile
def manifestFile = new File(manifestPath)
def xml = new XmlParser(false, true).parse(manifestFile)
def exportedTag = "android:exported"
///指定 space
def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')
def nodes = xml.application[0].'*'.findAll {
//挑选要修改的节点,没有指定的 exported 的才需要增加
(it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(androidSpace.exported) == null
}
///添加 exported,默认 false
nodes.each {
def isMain = false
it.each {
if (it.name() == "intent-filter") {
it.each {
if (it.name() == "action") {
if (it.attributes().get(androidSpace.name) == "android.intent.action.MAIN") {
isMain = true
println("......................MAIN FOUND......................")
}
}
}
}
}
it.attributes().put(exportedTag, "${isMain}")
}
PrintWriter pw = new PrintWriter(manifestFile)
pw.write(groovy.xml.XmlUtil.serialize(xml))
pw.close()
}
}
}
/**
* 修改 Android 12 因为 exported 的构建问题
*/
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def processManifest = output.getProcessManifestProvider().get()
processManifest.doLast { task ->
def outputDir = task.multiApkManifestOutputDirectory
File outputDirectory
if (outputDir instanceof File) {
outputDirectory = outputDir
} else {
outputDirectory = outputDir.get().asFile
}
File manifestOutFile = file("$outputDirectory/AndroidManifest.xml")
println("----------- ${manifestOutFile} ----------- ")
if (manifestOutFile.exists() && manifestOutFile.canRead() && manifestOutFile.canWrite()) {
def manifestFile = manifestOutFile
///这里第二个参数是 false ,所以 namespace 是展开的,所以下面不能用 androidSpace,而是用 nameTag
def xml = new XmlParser(false, false).parse(manifestFile)
def exportedTag = "android:exported"
def nameTag = "android:name"
///指定 space
//def androidSpace = new groovy.xml.Namespace('http://schemas.android.com/apk/res/android', 'android')
def nodes = xml.application[0].'*'.findAll {
//挑选要修改的节点,没有指定的 exported 的才需要增加
//如果 exportedTag 拿不到可以尝试 it.attribute(androidSpace.exported)
(it.name() == 'activity' || it.name() == 'receiver' || it.name() == 'service') && it.attribute(exportedTag) == null
}
///添加 exported,默认 false
nodes.each {
def isMain = false
it.each {
if (it.name() == "intent-filter") {
it.each {
if (it.name() == "action") {
//如果 nameTag 拿不到可以尝试 it.attribute(androidSpace.name)
if (it.attributes().get(nameTag) == "android.intent.action.MAIN") {
isMain = true
println("......................MAIN FOUND......................")
}
}
}
}
}
it.attributes().put(exportedTag, "${isMain}")
}
PrintWriter pw = new PrintWriter(manifestFile)
pw.write(groovy.xml.XmlUtil.serialize(xml))
pw.close()
}
}
}
}
这段脚本你可以直接放到 app/build.gradle
下执行,也可以单独放到一个 gradle 文件之后 apply
引入,它的作用就是:
在打包过程中检索所有没有设置 exported
的组件,给他们动态配置上 exported
。这里有个特殊需要注意的是,因为启动 Activity
默认就是需要被 Launcher 打开的,所以 "android.intent.action.MAIN"
需要 exported
设置为 true
。(PS:应该是用 LAUNCHER 类别,这里故意用 MAIN)
如果有需要,还可以自己增加判断设置了
"intent-filter"
的才配置exported
。
Android 12 新增加了 SplashScreen
的 API,它包括启动时的进入应用的动作、显示应用的图标画面,以及展示应用本身的过渡效果。
它大概由如下 4 个部分组成,这里需要注意:
启动画面动画机制由进入动画和退出动画组成。
SplashScreenView
自定义。更详细的介绍这里就不展开了,有兴趣的可以自己看官方的资料: developer.android.com/guide/topic… ,这里主要介绍下如何适配和使用的问题。
首先不管你的 TargetSDK 什么版本,当你运行到 Android 12 的手机上时,所有的 App 都会增加 SplashScreen
的功能。
如果你什么都不做,那 App 的 Launcher 图标会变成 SplashScreen
界面的那个图标,而对应的原主题下 windowBackground
属性指定的颜色,就会成为 SplashScreen
界面的背景颜色。这个启动效果在所有应用的冷启动和热启动期间会出现。
其实不适配好像也没啥问题。
关于如何迁移和使用 SplashScreen
可以查阅官方详细文档: developer.android.com/guide/topic…
另外还可以参考 《Jetpack新成员SplashScreen:打造全新的App启动画面》 这篇文章,文章详细介绍了如果使用官方的 Jetpack
库来让这个效果适配到更低的 Target 平台。
而正常情况下我们可以做的就是:
compileSdkVersion 31
、 targetSdkVersion 31
& buildToolsVersion '31.0.0'
implementation "androidx.core:core-splashscreen:1.0.0-alpha02"
values-v31
的目录styles.xml
对应的主题,例如:
Activity
添加这个主题,不同目录下使用不同主题来达到适配效果。PS: 我个人是一点都不喜欢这个玩意。
Android 12 更改了可以完全自定义通知外观和行为,以前自定义通知能够使用整个通知区域并提供自己的布局和样式,现在它行为变了。
使用 TargetSDK 为 31 的 App,包含自定义内容视图的通知将不再使用完整通知区域;而是使用系统标准模板。
此模板可确保自定义通知在所有状态下都与其他通知长得一模一样,例如在收起状态下的通知图标和展开功能,以及在展开状态下的通知图标、应用名称和收起功能,与 Notification.DecoratedCustomViewStyle 的行为几乎完全相同。
Android App Links 是一种特殊类型的 DeepLink ,用于让 Web 直接在 Android 应用中打开相应对应 App 内容而无需用户选择应用。使用它需要执行以下步骤:
如何使用可查阅:developer.android.com/training/ap…
使用 TargetSDK 为 31 的 App,系统对 Android App Links 的验证方式进行了一些调整,这些调整会提升应用链接的可靠性。
如果你的 App 是依靠 Android App Links 验证在应用中打开网页链接,那么在为 Android App Links 验证添加 intent 过滤器时,请确保使用正确的格式,尤其需要注意的是确保这些
intent-filter
包含 BROWSABLE 类别并支持https
方案。
使用 TargetSDK 为 31 的 App,用户可以请求应用只能访问大致位置信息。
如果 App 请求
ACCESS_COARSE_LOCATION
但未请求ACCESS_FINE_LOCATION
那么不会有任何影响。
TargetSDK 为 31 的 App 请求 ACCESS_FINE_LOCATION
运行时权限,还必须请求 ACCESS_COARSE_LOCATION
权限。当 App 同时请求这两个权限时,系统权限对话框将为用户提供以下新选项:
Cookie 的 SameSite
属性决定了它是可以与任何请求一起发送,还是只能与同站点请求一起发送。
SameSite
属性的 Cookie 被视为 SameSite=Lax
。SameSite=None
的 Cookie 还必须指定 Secure
属性,这意味着它们需要安全的上下文,需要通过 HTTPS 发送。SameSite=None; Secure
,否则 Cookie 不会被发送。在 WebView devtools 中 切换界面标志 webview-enable-modern-cookie-same-site,可以在测试设备上手动启用 SameSite 行为。
Android 12 在 Android 11(API 级别 30)中引入的自动重置权限行为 的基础上进行了扩展。
如果 TargetSDK 为 31 的 App 用户几个月不打开,则系统会自动重置授予的所有权限并将App 置于休眠状态。
更多可以查阅:developer.android.com/topic/perfo…
PendingIntent 如果没有指定 FLAG_IMMUTABLE
或 FLAG_MUTABLE
会直接报错。(TargetSDK 31 下)
大致需要注意的就是这些,基本上其实除了 exproted
和 SplashScreen
之外,其他基本都不怎么需要适配,事实上 SplashScreen
我个人觉得会很遭产品嫌弃,毕竟 Material Design 在国内的待遇确实有点惨,没办法去掉 SplashScreen
这点估计需要和产品扯皮一段时间,不过产品和设计一般没有 Android 手机,何况 Android 12,所以日后再说吧~
错。(TargetSDK 31 下)
大致需要注意的就是这些,基本上其实除了 exproted
和 SplashScreen
之外,其他基本都不怎么需要适配,事实上 SplashScreen
我个人觉得会很遭产品嫌弃,毕竟 Material Design 在国内的待遇确实有点惨,没办法去掉 SplashScreen
这点估计需要和产品扯皮一段时间,不过产品和设计一般没有 Android 手机,何况 Android 12,所以日后再说吧~
分享给大家一份面试题合集。
下面的题目都是在Android交流群大家在面试时遇到的,如果大家有好的题目或者好的见解欢迎分享,楼主将长期维护此帖。
参考解析:郭霖、鸿洋、玉刚、极客时间、腾讯课堂…
内容特点:条理清晰,含图像化表示更加易懂。
内容概要:包括 Handler、Activity相关、Fragment、service、布局优化、AsyncTask相关
、Android 事件分发机制、 Binder、Android 高级必备 :AMS,WMS,PMS、Glide、 Android 组件化与插件化等面试题和技术栈!
常问的点:
Handler Looper Message 关系是什么?
Messagequeue 的数据结构是什么?为什么要用这个数据结构?
如何在子线程中创建 Handler?
Handler post 方法原理?
Android消息机制的原理及源码解析
Android Handler 消息机制
启动模式以及使用场景?
onNewIntent()和onConfigurationChanged()
onSaveInstanceState()和onRestoreInstanceState()
Activity 到底是如何启动的
启动模式以及使用场景
onSaveInstanceState以及onRestoreInstanceState使用
onConfigurationChanged使用以及问题解决
Activity 启动流程解析
Fragment 生命周期和 Activity 对比
Fragment 之间如何进行通信
Fragment的startActivityForResult
Fragment重叠问题
Fragment 初探
Fragment 重叠, 如何通信
Fragment生命周期
进程保活
Service的运行线程(生命周期方法全部在主线程)
Service启动方式以及如何停止
ServiceConnection里面的回调方法运行在哪个线程?
startService 和 bingService区别
进程保活一般套路
关于进程保活你需要知道的一切
什么情况下使用 ViewStub、include、merge?
他们的原理是什么?
ViewStub、include、merge概念解析
Android布局优化之ViewStub、include、merge使用与源码分析
注册方式,优先级
广播类型,区别
广播的使用场景,原理
Android广播动态静态注册
常见使用以及流程解析
广播源码解析
AsyncTask是串行还是并行执行?
AsyncTask随着安卓版本的变迁
AsyncTask完全解析
串行还是并行
onTouch和onTouchEvent区别,调用顺序
dispatchTouchEvent, onTouchEvent, onInterceptTouchEvent 方法顺序以及使用场景
滑动冲突,如何解决
事件分发机制
事件分发解析
dispatchTouchEvent, onTouchEvent, onInterceptTouchEvent方法的使用场景解析
简述 View 绘制流程
onMeasure, onlayout, ondraw方法中需要注意的点
如何进行自定义 View
view 重绘机制
Android LayoutInflater原理分析,带你一步步深入了解View(一)
Android视图状态及重绘流程分析,带你一步步深入了解View(二)
Android视图状态及重绘流程分析,带你一步步深入了解View(三)
Android自定义View的实现方法,带你一步步深入了解View(四)
Window、Activity、DecorView以及ViewRoot之间的关系
常见的 IPC 机制以及使用场景
为什么安卓要用 binder 进行跨进程传输
多进程带来的问题
AIDL 使用浅析
binder 原理解析
binder 最底层解析
多进程通信方式以及带来的问题
多进程通信方式对比
AMS,WMS,PMS 创建过程
AMS,WMS,PMS全解析
AMS启动流程
WindowManagerService启动过程解析
PMS 启动流程解析
为什么会发生 ANR?
如何定位 ANR?
如何避免 ANR?
什么是 ANR
如何避免以及分析方法
Android 性能优化之 ANR 详解
注意:内存泄漏和内存溢出是 2 个概念
什么情况下会内存泄漏?
如何防止内存泄漏?
内存泄漏和溢出的区别
OOM 概念以及安卓内存管理机制
内存泄漏的可能性
防止内存泄漏的方法
屏幕适配相关名词解析
现在流行的屏幕适配方式
屏幕适配名词以及概念解析
今日头条技术适配方案
LruCache使用极其原理
Android缓存机制
LruCache使用极其原理述
如何进行 内存 cpu 耗电 的定位以及优化
性能优化经常使用的方法
如何避免 UI 卡顿
性能优化全解析,工具使用
性能优化最佳实践
知乎高赞文章
好几种我该选择哪个?优劣点
任玉刚的文章:设计模式选择
这俩篇官方文章基础的够用了
必须贴一下官方文档:配置构建
Gradle 提示与诀窍
Gradle插件 了解就好
Gradle 自定义插件方式
全面理解Gradle - 执行时序
Gradle系列一
Gradle系列二
Gradle系列三
使用过程,特点,原理解析
RxJava 名词以及如何使用
Rxjava 观察者模式原理解析
Rxjava订阅流程,线程切换,源码分析 系列
OKHTTP完整解析
Retrofit使用流程,机制详解
从 HTTP 到 Retrofit
Retrofit是如何工作的
郭神系列 Glide 分析
Android图片加载框架最全解析(一),Glide的基本用法
Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程
Android图片加载框架最全解析(三),深入探究Glide的缓存机制
Android图片加载框架最全解析(四),玩转Glide的回调与监听
Android图片加载框架最全解析(五),Glide强大的图片变换功能
Android图片加载框架最全解析(六),探究Glide的自定义模块功能
Android图片加载框架最全解析(七),实现带进度的Glide图片加载功能
Android图片加载框架最全解析(八),带你全面了解Glide 4的用法
为什么要用组件化?
组件之间如何通信?
组件之间如何跳转?
Android 插件化和热修复知识梳理
为什么要用组件化
插件化框架历史
深入理解Android插件化技术
Android 插件化和热修复知识梳理
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
好啦,这份资料就给大家介绍到这了,有需要详细文档的小伙伴,可以微信扫下方二维码免费领取哈~