美文网首页安卓进阶
Gradle task批量修改Been文件(文件名、类名和引用)

Gradle task批量修改Been文件(文件名、类名和引用)

作者: 寻水的鱼Chock | 来源:发表于2022-03-22 21:18 被阅读0次

    前言

    因为应用市场审核的原因,马甲包现在需要上线是越来越难了。目前也出现了很多绕过检测的方法,比如修改主包路劲、添加垃圾代码等。但是效果并不如人意,特别是现在机器学习这么流行的情况下,这种“小伎俩”还是很容易被识破的。所以最好是从源头入手,彻底改变代码结构,从源头上解决问题。

    那为什么要修改Been的类名? 众所周知的原因,Been是没办法加入混淆的,且跟反射调用有着密切的关系,所以往往Been对象都是“裸奔”的。在“裸奔”的情况下,如何避免相似度的检测?如果是你,你如何检测APK的相似度?

    我能想到的且相对简单的方法就是反编译源代码,相互匹配类名(不考虑包路径),类名相同的概率*权重就可以当成这两个应用的相似度(当然还需要其他检测方法相互配合,类名只是其中一个因子而已)。

    实现思路

    大致可将其分为几步

    • 查找Been文件。(可以是配置的目录或者通过名字正则匹配,例如:“**/**Been.java”)
    • 遍历工程文件,替换使用到这个Been的所有代码。如果有使用DataBinding, 还需要遍历layout xml文件。

    编写脚本

    警告!!!!
    此脚本会覆盖你本地源代码代码,请确保你的代码有加入到版本管理(Git 或者 SVN) ,以便恢复。

    完整的源码地址: https://gitee.com/tinyqiu/java-bean-rename-gradle

    配置参数

    首先定义需要用到的参数

    ext {
        //需要批量重命名的Been路径
        renameBeenPath = "src/main/java/com/chockqiu/testpck/bean"
        //Been对象名字以什么字符串结尾, 默认Been, 例如设为Beax, 则所有Been都会以Beax结尾, 如GoodsBeax.kt
        beenNameSuffix = "Bear"
        //Been名字的前缀, 例如KoGoodsBeen
        beenPrefix = "Ko"
        //Been对象 Been的前面加的字符串 KoGoodsFishBeen
        beenMidfix = "Fish"
        //特殊的Been比配
        specialBeensMatcher = ["**/*Been.kt",  "**/*Been.java"]
    }
    
    类名匹配

    利用Gradle内建函数FileTree可以轻松实现

    FileTree beenTree = fileTree(renameBeenPath) {
        include '**/*.java'
        include '**/*.kt'
        include specialBeensMatcher
    }
    //........
    
    类名转换

    根据已有的类名,增加前缀后缀等方式进行转换,这里可以根据具体需求灵活实现。

    //遍历匹配的类
    beenTree.each { File beenFile ->
        //println(beenFile.path + " Processing...")
        def sname = beenFile.name
        def fileEx = sname.substring(sname.lastIndexOf("."))
        sname = sname.replace(fileEx, "")
        def tName = ""
        if (sname.endsWith("Been")) {
            tName = beenPrefix + sname.replace("Been", beenMidfix + beenNameSuffix)
        } else if (sname.endsWith("Bean")) {//兼容有些人把Been写成了Bean
            tName = beenPrefix + sname.replace("Bean", beenMidfix + beenNameSuffix)
        } else {
            tName = beenPrefix + sname + beenMidfix + beenNameSuffix
        }
        beenFile.renameTo(beenFile.parentFile.path + File.separator + tName + fileEx)
        //..........
    }
    
    引用替换

    替换所用使用到这个Been的代码

    遍历可能使用到的地方

    主要是Kotlin和Java代码,如果有使用DataBinding,还有XML的Layout文件。

    FileTree processTree = fileTree("src") {
        include '**/*.java'
        include '**/*.kt'
        include '**/layout/*.xml'
    }
    processTree.each { File f ->
        ImportBeenReplacer(f.path, sname, tName)
    }
    
    字符串匹配规则

    Been的使用比较复杂,简单的字符串替换是无法实现的,所以这里需要引入正则表达式进行匹配。

    针对xml的匹配规则:

    (?<![a-zA-Z0-9]+)(?<=[\\.]+)$sourceBeenName(?=[ \"\\./>]*)(?![a-zA-Z0-9]+)
    

    针对Java/Kotlin的匹配规则

    (?<![a-zA-Z0-9]+)(?<=[ \\.<:\\s\\,(]+)$sourceBeenName(?=[ \"\\.>\\?\\:\\(]*)(?![a-zA-Z0-9]+)
    

    其中$sourceBeenName是需要被替换的类名字。

    正则表达式不熟的同学参考:https://www.runoob.com/regexp/regexp-metachar.html

    正则表达式匹配规则是比较关键的,如果写的不够完整,将导致输出的代码编译无法通过,所以需要不断的进行迭代更新,以适应不同的情况。

    如果本文对你有帮助就点个赞支持下吧~

    相关文章

      网友评论

        本文标题:Gradle task批量修改Been文件(文件名、类名和引用)

        本文链接:https://www.haomeiwen.com/subject/eznfjrtx.html