微信资源混淆,导致的约束布局 Constraintlayout 控件重叠!

问题

1、广告六要素

虽然我不参与广告 sdk 接入等相关工作,但是最近总是听到一个词广告六要素。这到底是什么?

国内下载类广告,尤其是针对移动应用推广的广告,其成功实施往往围绕几个关键要素进行,这些要素能够帮助广告主更有效地触达目标用户,促进应用下载。

经查阅知道,国内各大广告 SDK 平台优量汇、穿山甲、快手等已逐步开始(早已)支持广告六要素,提供了获取应用的下载六项信息:

  • 应用名称
  • 开发者公司名称
  • 应用版本
  • 隐私协议超链
  • 权限列表超链
  • 产品功能

下图以荣耀广告为例,这个是六要素控件显示正常的情况

2、布局错乱

在不使用自定义混淆(包含微信资源混淆 AndResGuard)出包运行布局是正确的!

使用微信资源混淆之后,运行错乱,六要素重叠显示!

AndResGuard Github

排查

通过使用uiautomatorviewer布局分析,定位找到了该广告的布局文件honor_ads_six_factor.xml,并确定了每个显示文本对应的控件,uiautomatorviewer 工具跟随 Android studio,安装目录下可以找到,也可以全局搜索查找。

C:\Users\Primer\AppData\Local\Android\Sdk\tools\bin\uiautomatorviewer.bat

我们知道,父容器使用的是约束布局ConstraintLayout(减少布局嵌套,布局优化),既然是因为使用了资源混淆导致问题出现,得了解资源混淆的配置是什么?

groovy 复制代码
andResGuard {
    mappingFile = null
    use7zip = true
    useSign = true
    // 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
    keepRoot = false
    // 设置这个值,会把arsc name列混淆成相同的名字,减少string常量池的大小
    fixedResName = "arg"
    // 打开这个开关会合并所有哈希值相同的资源,但请不要过度依赖这个功能去除去冗余资源
    mergeDuplicatedRes = true
    //混淆白名单
    whiteList = [
        // for your icon
        "R.drawable.icon",
        // for fabric
        "R.string.com.crashlytics.*",
        // for google-services
        "R.string.google_app_id",
        "R.string.gcm_defaultSenderId",
        "R.string.default_web_client_id",
        "R.string.ga_trackingId",
        "R.string.firebase_database_url",
        "R.string.google_api_key",
        "R.string.google_crash_reporting_api_key"
    ]
    compressFilePattern = [
        "*.png",
        "*.jpg",
        "*.jpeg",
        "*.gif",
    ]
    sevenzip {
         artifact = 'com.tencent.mm:SevenZip:1.2.21'
    }

    /**
    * 可选: 如果不设置则会默认覆盖assemble输出的apk
    **/
    // finalApkBackupPath = "${project.rootDir}/final.apk"

    /**
    * 可选: 指定v1签名时生成jar文件的摘要算法
    * 默认值为"SHA-1"
    **/
    // digestalg = "SHA-256"
}

1、首先,布局文件加白名单

白名单配置是whiteList ,一开始我们是连同布局文件也混淆的(上图是加白之后的),查看荣耀广告 SDK 的资源文件,发现文件名称都有统一前缀 honor_ads,所以加白了下面的资源,测试 -> 运行 -> 布局错乱 -> 异常

java 复制代码
"R.drawable.honor_ads*",
"R.interpolator.honor_ads*",
"R.anim.honor_ads*",
"R.animator.honor_ads*",
"R.attr.honor_ads*",
"R.color.honor_ads*",
"R.dimen.honor_ads*",
"R.mipmap.honor_ads*",
"R.id.honor_ads*",
"R.string.honor_ads*",
"R.layout.honor_ads*",
"R.style.honor_ads*",

2、仔细查看布局

上图的布局细看是这样的:

① 名称 广告 公司

② 隐私 权限 介绍 版本

  • 两行,七个控件
  • 第一行三个,第二行四个控件
  • 猜想:第二行如何很好的约束布局(按照我们的正常编码思维哈)
    • 1、第二行可能是:app:layout_constraintTop_toBottomOf="第一行",这个里是把第一行和第二行分别看成一个整体
      【很明显,该布局代码不是这样的(简单布局嵌套过深,没必要)】
    • 2、第二行的第一个可能是:app:layout_constraintTop_toBottomOf="第一行的第一个(名称)",然后第二行的其他元素像第一个或上一个控件对齐
      【很明显,布局代码也不是这样的(想必大多数人会这样写吧,没错我就是那大多数人)】
    • 3、使用 androidx.constraintlayout.widget.Barrier 进一步约束布局
      【代码确实是这样】

此前,我从未使用或了解过约束布局中的 androidx.constraintlayout.widget.Barrier这到底是什么?大概意思就是可以控制布局,具体如何使用自行搜索。

简书:Barrier的使用及实例

查资料他有两个重要的属性:

  • barrierDirection:方向
  • constraint_referenced_ids:被约束的控件 id 名称集合
xml 复制代码
<androidx.constraintlayout.widget.Barrier
    android:id="@+id/xlp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    <!-- 这里编译后是 3,我推测是 Bottom (你们可以验证下)-->
    app:barrierDirection="3"
    app:constraint_referenced_ids="ad_empty_view_top,ad_brand_name,ad_flag_view,ad_developer_view"/>

我们知道约束布局中 Direction 是这样的:

所以布局中的 Barrier 起到什么作用你应该知道了。

问题的关键是要找到关键问题(手动狗头),关键果然是 Barrier 的 app:constraint_referenced_ids,因为只有他会约束布局影响控件显示位置!

再细看 Barrier !

比如像这种属性值能正常替换

constraint_referenced_ids 属性值为什么不能被替换?

  • 像是插件还不支持比较新的属性值替换?
  • 或者属性值为数组列表的格式不同导致没有被替换?

3、解决

总之,问题清晰了,如果要进一步看资源混淆插件源码排查属性值为什么没被替换,自己尝试适配插件那可麻烦,耗时费力(除非你真的激情满满),所以最终解决就是给资源 id 名称加入白名单,保持 constraint_referenced_ids 集合里面的名称不被混淆即可!

还记的之前的加白里面虽然包含了 id,但是 keep 的是 honor_ads*,无效啊!

java 复制代码
"R.id.honor_ads*",

最终,再次提取加白前缀,那就是

java 复制代码
"R.id.ad_*",

app:constraint_referenced_ids="

ad_empty_view_top,

ad_brand_name,

ad_flag_view,

ad_developer_view"

荣耀联运 SDK 竟也有坑,只是当时没测到~

相关推荐
阿巴斯甜3 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker3 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95274 小时前
Andorid Google 登录接入文档
android
黄林晴6 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab18 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿21 小时前
Android MediaPlayer 笔记
android
Jony_21 小时前
Android 启动优化方案
android
阿巴斯甜21 小时前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇21 小时前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android