Android 12 需要更新适配exported和 SplashScreen

1

android:exported

「它主要是设置 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()
        }
    }
}
 

这段脚本你可以直接放到 app/build.gradle 下执行,也可以单独放到一个 gradle 文件之后 apply 引入,它的作用就是:

「在打包过程中检索所有没有设置 exported 的组件,给他们动态配置上  exported」。这里有个特殊需要注意的是,因为启动 Activity 默认就是需要被 Launcher 打开的,所以 "android.intent.action.MAIN" 需要  exported 设置为 true 。

如果有需要,还可以自己增加判断设置了 "intent-filter" 的才配置  exported。

2

SplashScreen

Android 12 新增加了 SplashScreen 的 API,它包括启动时的进入应用的动作、显示应用的图标画面,以及展示应用本身的过渡效果。

图片

它大概由如下 4 个部分组成,这里需要注意:

1 最好是矢量的可绘制对象,当然它可以是静态或动画形式。

2 是可选的,也就是图标的背景。

3 与自适应图标一样,前景的三分之一被遮盖。

4 就是窗口背景。

• 启动画面动画机制由进入动画和退出动画组成。

• 进入动画由系统视图到启动画面组成,这由系统控制且不可自定义。

退出动画由隐藏启动画面的动画运行组成。如果要对其进行自定义,可以通过 SplashScreenView 自定义。

图片

更详细的介绍这里就不展开了,有兴趣的可以自己看官方的资料,这里主要介绍下如何适配和使用的问题。

https://developer.android.com/guide/topics/ui/splash-screen 

「首先不管你的 TargetSDK 什么版本,当你运行到 Android 12 的手机上时,所有的 App 都会增加 SplashScreen 的功能」。

如果你什么都不做,那 App 的 Launcher 图标会变成 SplashScreen 界面的那个图标,而对应的原主题下 windowBackground 属性指定的颜色,就会成为 SplashScreen 界面的背景颜色。「这个启动效果在所有应用的冷启动和热启动期间会出现。」

其实不适配好像也没啥问题。

关于如何迁移和使用  SplashScreen 可以查阅官方详细文档:

https://developer.android.com/guide/topics/ui/splash-screen/migrate

另外还可以参考 《Jetpack新成员SplashScreen:打造全新的App启动画面》 这篇文章,文章详细介绍了如果使用官方的 Jetpack 库来让这个效果适配到更低的 Target 平台:

https://juejin.cn/post/6997217571208445965

而正常情况下我们可以做的就是:

1、升级 compileSdkVersion 31 、 targetSdkVersion 31 & buildToolsVersion '31.0.0'

2、 添加依赖 implementation "androidx.core:core-splashscreen:1.0.0-alpha02"

3、增加 values-v31 的目录

4、添加 styles.xml 对应的主题,例如:

<resources>
    <style name="LaunchTheme" parent="Theme.SplashScreen">
        <item name="windowSplashScreenBackground">@color/splashScreenBackground</item>
        <!--<item name="windowSplashScreenAnimatedIcon">@drawable/splash</item>-->
        <item name="windowSplashScreenAnimationDuration">500</item>
        <item name="postSplashScreenTheme">@style/AppTheme</item>
    </style>
</resources>
 

5、给你的启动 Activity 添加这个主题,不同目录下使用不同主题来达到适配效果。

「PS: 我个人是一点都不喜欢这个玩意。」

3

其他

1、通知中心又又又变了

「Android 12 更改了可以完全自定义通知外观和行为,以前自定义通知能够使用整个通知区域并提供自己的布局和样式,现在它行为变了」。

使用 TargetSDK 为 31 的 App,包含自定义内容视图的通知将不再使用完整通知区域;而是使用系统标准模板。

此模板可确保自定义通知在所有状态下都与其他通知长得一模一样,例如在收起状态下的通知图标和展开功能,以及在展开状态下的通知图标、应用名称和收起功能,与 Notification.DecoratedCustomViewStyle 的行为几乎完全相同。

图片

2、Android App Links 验证

Android App Links 是一种特殊类型的 DeepLink ,用于让 Web 直接在 Android 应用中打开相应对应 App 内容而无需用户选择应用。使用它需要执行以下步骤:

如何使用可查阅:

https://developer.android.com/training/app-links/verify-site-associations#auto-verification

使用 TargetSDK 为 31 的 App,系统对 Android App Links 的验证方式进行了一些调整,这些调整会提升应用链接的可靠性。

如果你的 App 是依靠 Android App Links 验证在应用中打开网页链接,那么在为 Android App Links 验证添加 intent 过滤器时,请确保使用正确的格式,「尤其需要注意的是确保这些 intent-filter 包含 BROWSABLE 类别并支持 https 方案」。

3、安全和隐私设置

3.1、大致位置

「使用 TargetSDK 为 31 的 App,用户可以请求应用只能访问大致位置信息」。

如果 App 请求 ACCESS_COARSE_LOCATION 但未请求 ACCESS_FINE_LOCATION那么不会有任何影响。

TargetSDK 为 31 的 App 请求 ACCESS_FINE_LOCATION 运行时权限,还必须请求 ACCESS_COARSE_LOCATION 权限。当 App 同时请求这两个权限时,系统权限对话框将为用户提供以下新选项:

图片

3.2、SameSite Cookie

Cookie 的 SameSite 属性决定了它是可以与任何请求一起发送,还是只能与同站点请求一起发送。

• 没有 SameSite 属性的 Cookie 被视为 SameSite=Lax。

• 带有 SameSite=None 的 Cookie 还必须指定 Secure 属性,这意味着它们需要安全的上下文,需要通过 HTTPS 发送。

• 站点的 HTTP 版本和 HTTPS 版本之间的链接现在被视为跨站点请求,因此除非将 Cookie 正确标记为 SameSite=None; Secure,否则 Cookie 不会被发送。

在 WebView devtools 中 切换界面标志 webview-enable-modern-cookie-same-site,可以在测试设备上手动启用 SameSite 行为。

4、应用休眠

Android 12 在 Android 11(API 级别 30)中引入的自动重置权限行为 的基础上进行了扩展。

如果 TargetSDK 为 31 的 App 用户几个月不打开,则系统会自动重置授予的所有权限并将App 置于休眠状态。

更多可以查阅:

https://developer.android.com/topic/performance/app-hibernation

最后

大致需要注意的就是这些,基本上其实除了 exproted 和 SplashScreen 之外,其他基本都不怎么需要适配,「事实上 SplashScreen 我个人觉得会很遭产品嫌弃,毕竟 Material Design 在国内的待遇确实有点惨」,没办法去掉  SplashScreen 这点估计需要和产品扯皮一段时间,不过产品和设计一般没有 Android 手机,何况 Android 12,所以日后再说吧~

有什么想说的,欢迎点击阅读原文。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
android:exportedAndroidManifest.xml文件中的一个属性,用于指定一个Activity是否可以被其他应用程序访问。当android:exported属性的值为true时,表示该Activity可以被其他应用程序访问;当android:exported属性的值为false时,表示该Activity只能被同一应用程序内的其他组件访问。\[2\]这个属性的默认值是true,但是为了安全起见,建议在开发应用程序时明确指定android:exported属性的值,以确保只有需要被其他应用程序访问的Activity才能被访问到。\[2\]在应用程序中启动另外一个应用程序时,可以通过设置要启动的Activity的android:exported属性为true,然后使用Intent来启动该Activity。这样,其他应用程序就可以通过Intent来启动该Activity了。\[3\] #### 引用[.reference_title] - *1* [android:exported =true,什么是具有相同用户ID的Android应用程序](https://blog.csdn.net/u013066069/article/details/96479210)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Android开发-Activity中“android:exported“属性的作用,以及“Permission Denial: starting Intent“错误...](https://blog.csdn.net/liranke/article/details/123437721)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值