Android混淆发布依赖

在这里插入图片描述

1.任务目标

  在Android开发中经常用仓库依赖或者jar引入第三方功能库,这次我将混淆发布依赖的过程出个sdk给外部调用,利用在公司打包的经验说说,共同看看有什么更好方法。
先看我们打出的混淆jar会显示的代码样式:

在这里插入图片描述

在这里插入图片描述

2.环境准备

  开发中虽然喜欢稳定的编译环境,奈何每年google都发布新的Android,我们的AndroidStudio也只能跟着升级,不然无法使用高级的功能或兼容高级sdk。比较常遇到的编译级错误就有Android 11带来的广告id,清单文件中要query标签,要升级才行;另一个bugly大家常用的热修复功能,gradle文件下的插件在老鼠或者狐狸版直接失效,编译都不过,需要降级,除非你注释掉热修复不用(>_<)。

  整个混淆发布过程我在windows和mac独立做了一次,发布文章做的第3次,源码里存在windows的痕迹都注释掉了,开发sdk的项目是AndroidJar 中的sdk module,发布对外依赖的项目 UseJar,所有的app module都是测试业务的
创建项目的选Java语言(kotlin没研究过),我使用的gradle version:

classpath ‘com.android.tools.build:gradle:7.1.2’

3.业务开发

  我们开发sdk应该尽量使用原生api,不引入第三方库,而且保持功能的隔离,不应该引入无用的工具类,不然容易在开发者调用sdk时就疯狂报重复类、版本不一致、引入三方库会增大sdk的大小。

  开发这个sdk其实在我们眼中就是个library module,在此sdk module的build.gradle文件中编写常规配置脚本代码,,发现没有so库的打包其实很简单,但是们引入有so的库mmkv,一般的打包java代码就不行,每次调用就 libxx.so无法找到而拖蹦目标APP。c++的坑,我们的sdk module被app module依赖 implementation project(‘:sdk’),这种方式使用sdk时不会报错,c的so库没问题,但是以jar依赖就崩溃了,因为jar里面确实没有打包进so库,这就导致mmkv初始化就拖蹦 (>_<)。

使用的sdk module的build.gradle文件:

plugins {
    id 'com.android.library'
}

android {
    compileSdk 32

    defaultConfig {
        minSdk 21
        targetSdk 32

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles "consumer-rules.pro"

        ndk {
            abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86'
        }
    }

    buildTypes {
        release {
            minifyEnabled true //开启混淆
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' //根据混淆文件打包
        }
        debug {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    sourceSets{
        main{
            jniLibs.srcDirs = ['libs']
        }
    }

    lintOptions{
        abortOnError false
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.4.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    implementation 'com.tencent:mmkv:1.0.22'   //编译打包会生成so
    implementation 'com.squareup.okhttp3:okhttp:3.6.0' //基础流行网络库
    implementation 'com.github.gzu-liyujiang:Android_CN_OAID:4.2.4' //兼容Android11以上的广告id,此库需要ide4.0以上版本
}

  注意点这里说下,为什么要okhttp3.6,现在都4.x了,开始我用的4.9.3,我在编译的时候展开Project->External Libraries,发现竟然存在kotlin的插件库,但是我全程没有用kotlin的库或文件,然后在目标app运行时,当初始化sdk就拖崩溃APP(>_<)。没道理啊,灵机一动感觉是依赖库使用了kotlin相关插件库,然后我就将mmkv,okhttp,oaid每次都单独依赖,其他两个注释掉,看哪个家伙导入的kotlin库,发现是okhttp,在仓库查看有什么历史版本,选中个热门降低版本,然后发现他缺okio这个库,在这里又下载okio-3.0.0.jar,放到libs文件夹。

  这里都已经一波三折了,要翻墙下载,各种库引入打出sdk的jar包后,放到开发的项目运行,然后崩溃又回到sdk中修复,而且崩溃可以是多样的,不一定是业务代码问题,很多靠经验才知道,混淆文件的配置,依赖库又引入其他恶心的库,还有c++等等,这里我算比较复杂的打包,网上基本就打个java代码给你调用成功就拜拜。。。

4.gradlew 打jar包

  百度基本打包就是构建makeJar的任务,这种打出来的是明文代码,代码无混淆,我们构建makeProguardJar任务是混淆jar,里面的类名、API名、变量名变成abcd…,在写完整个sdk功能后运行依赖了sdk的app module,这样就可以在sdk/build看到生成的临时文件库,整个任务构建包括:a.引入需要的代码库,这些都是/build/各依赖库.jar ;b.指定生成路径后完成整个任务代码编写并同步依赖,在ide右侧Gradle找到makeJar任务双击 ;c.在sdk/build/libs/xxlib-0.0.2.jar就是我们的jar。

  关键在a步骤,mac电脑和window电脑获取路径方式一样,只是路径挺大不同,我用window获取到时双反斜杠,mac是单斜杠路径。sdk需要引入的第三库,在Project->External Libraries下依赖的库copy path,自身业务代码一般是classes.jar,注意是debug或release下运行,选择build variants。

  非混淆包已经可以对外使用了,下面做混淆包jar,也有几个坑让我一一踩啦。百度获取makeProguardJar的任务代码,坑比来了,当时我做的是5月份开始做打包,type: proguard.gradle.ProGuardTask 这变量一直报错,百度看到所有文章都是这个类型没毛病?把自己的ide缓存啥的清理重启,都不行,为啥我不降级呢,因为引入了oaid这个库必须要Androidstudio4.0以上的,我就没想过要降级,实在搞不了我单独不依赖任务库,在gradle3.5.2能成功运行,当然获取classes.jar这路径都变了,就是gradle插件问题,当时只能百度、Google,csdn都没有当前gradle7.1.2的跑,基本都是3.x或者4.0.x,大家抄来抄去。无奈被迫放弃。

  后面8月又搞一波,接着坑直接找到gradle的github,因为我看文章说这开源的,直接去找它源码看到底弄啥,看issue发现有人提了,还是老外潮流,然后看到作者在7月份把开发出新版 com.guardsquare:proguard-gradle:7.2.2 ,注意只有这个可用progrardTask这个类。(https://github.com/Guardsquare/proguard)

**在高版本gradle创建项目setting.gradle、根build.gradle脚本结构完全改变,看到这个 id ‘com.android.library’ version 7.1.2 apply false ,跟以前的依赖代码 classpath ‘com.android.tools.build:gradle:7.1.2’ 导入的方式完全不会写,是分组织了还有冒号无法编译通过,被迫改成以前的脚本结构,有知道在高版本如何依赖gradle告诉我,没研究过。最后双击makeProguardJar就可以将明文jar包打成混淆包。

在这里插入图片描述

5.混淆协议编写

  上面打出混淆包发现依然没混淆,是混淆规则没搞对,我看百度基本写通用的混淆规则就可以混淆代码了,我这不行可能跟版本有关,只能老实处理混淆文件规则,而且更高级能为所欲为,也不少坑(>_<)。

  sdk的混淆规则有 consumer-rules.pro和proguard-rules.pro决定,不同是是否应用于项目所有module的混淆,混淆语句的错误使用会导致APP崩溃,而且可能无法指定崩溃代码行数,讲下遇到的坑。大体有内部类、匿名内部类、反射调用、接口的声明位置等,一开始不知道以上坑,每次编译都能正常生成混淆jar包,十分愉快,然后再拷贝到目标项目引入运行各种不知类名的无法找到的崩溃(><),每写个内部类就有崩的可能,而且代码量大的时候开发没注意后面真的排错能搞一天,而且都是正常打包调用就崩溃,每次大量重复的把jar拉到目标项目,gradle sync同步,当jar能成功引入会出现‘>’,能展开代码文件才能正常跑,而且由于ide缓存,经常同步无效要关掉项目窗口重开就行了 (><)。

  贴出完整的proguard-rules.pro代码,自己写的文件调试还算清晰,但是工作量是不少,由于混淆文件都是自己把握,基本掌握混淆的语法代码后是为所欲为(>.<),导致很多放宽的类没被混淆或者严格混淆,连对外API的参数名提示都变abc,要是多人写sdk就更复杂,每次都要打出混淆jar,依赖到目标项目才能看到jar里面的代码,手麻了已经。

#有效 不混淆整个包的文件
-keep class com.hwj.sdk.**

#有效 不混淆某个类的public方法,但里面的内容会
#-keepclassmembers class com.hwj.sdk.SdkLibUtil{
# public *;
#}

#不混淆某个类,看到所有信息
#-keep class com.hwj.sdk.SdkLibUtil {*;}
#看到类名
-keep class com.hwj.sdk.SdkLibUtil
#指定GreeNp类下的某些方法 testXX()不被混淆,注意修改返回值
-keep class com.hwj.sdk.SdkLibUtil {
    public java.lang.String test*(...);
    public void init(...);
}

#这些都是sdk里的文件,如果写成文件名就会报红线
-keep class com.hwj.sdk.MMKVUtil
-keep class com.hwj.sdk.NpHttpUtil {*;}
-keep class com.hwj.sdk.NpHttpUtil

#反射的使用,混淆后导致无法找到方法 ,这里必须找到类的具体路径
#需要直接在jar包中找到对应的三方库,每个层级下查看类路径,然后抽出来单独不混淆
#当然你要最简单,整个库都不混淆那就没技术含量了 (>_<)
-keep class okhttp3.internal.tls.TrustRootIndex {*;}
-keep class okhttp3.internal.tls.TrustRootIndex
-keep class java.security.cert.** {*;}
-keep class com.hwj.sdk.TrustAllCerts {*;}
-keep class com.hwj.sdk.TrustAllCerts

#不混淆某个依赖库下的所有文件,只是类名清晰,里面的函数、内部类、接口依然混淆
-keep class com.tencent.mmkv.** {*;}
-keep class com.github.gzuliyujiang.oaid.** {*;}
-keep class okio.** {*;}
-keep class okhttp3.** {*;}
-keep class javax.net.ssl.** {*;}

-keep class javax.net.ssl.HostnameVerifier{*;}
#内部类对象需要单独处理,否则依然混淆 ,如HostnameVerifier$.verifier()被混淆成a()
#代表保留  A$* 表示所有A的内部类都保留下来
-keep class javax.net.ssl.HostnameVerifier$* {*;}
-keep class com.lyentech.sdk.NpHttpUtil$* {*;}

#是否混淆第三方jar
-dontskipnonpubliclibraryclasses

#####混淆保护自己项目的部分代码以及引用的第三方jar包library#######
-libraryjars libs/okio-3.0.0.jar

# java.io.IOException: Please correct the above warnings first. 66666忽略警告
-ignorewarnings

#-dontwarn com.lyentech.sdk.**
#-dontwarn com.lyentech.reformcode.**

-optimizationpasses 5
-dontskipnonpubliclibraryclassmembers
-printmapping proguardMapping.txt
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-keepattributes *Annotation*,InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable

# 保留本地native方法不被混淆
-keepclasseswithmembernames class * {
    native <methods>;
}

#表示混淆时不使用大小写混合类名
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
#打印混淆的详细信息
-verbose

#不优化,作用于全局
-dontoptimize

-dontpreverify

-keepattributes *Annotation*

-dontwarn com.squareup.okhttp.**
-keep class com.squareup.okhttp.** {*;}
-keep interface com.squareup.okhttp.** {*;}
-dontwarn okio.**

6.github发布、jitpack仓库打包

  目前的混淆jar已经可以手动集成使用,但现在流行gradle集成依赖,所以另外建一个新的项目UseJar,一般大公司内外网,外网还要加域名隔离,不用公司网口或者私服连代码都拉不了。这里我们在AndroidJar项目下开发sdk的所有业务功能,打出混淆包后复制粘贴到UseJar项目中,创建Android library中引用jar,对标这里的UseJar:litesdk,然后对整个UseJar代码提交到github,push、tag、release、publish to jitpack。意思是UseJar项目托管这sdk,但是引用的jar代码是混淆过,部分接口端口可以用技术手段隐匿掉,只给外部用却不知道明码。

在这里插入图片描述
在这里插入图片描述

  因为sdk用到so库,所以在AndroidJar的app下运行后将apk解压获取所有的so,然后复制粘贴到UseJar的litesdk的libs,配置sourceSets{}引用so。

在这里插入图片描述
  发布前还要将把代理的配置注释掉,因为公司拉取github、google等库是龟速,所以开了代理,但是到jitpack打包时是直接根据gradle运行脚本,一直不通过,我就把gradle.properties文件的代理端口注释,这里坑大发了(>_<)。

7.外部调用依赖测试集成

  gradle集成是否成功,看控制台build是否通过,成功后External Libraries会出现仓库代码依赖地址,不行的要复验jitpack发布是否成功,看日志是否status:ok,error就是发布终止的不能下载到依赖代码,简单的校验命令(mac电脑):

./gradlew publishToMavenLocal

发现windows 带 ./ 会报错,呜呜windows直接gradlew。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pYfvicEK-1661995976564)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/32ec6e98471741689c37558021dc1ecb~tplv-k3u1fbpfcp-watermark.image?)]

小结

  其实打混淆包过程不复杂,但是在插件高版本,网域限制,使用的多样性(so库、三方库),依赖重复库,混淆警告编译不过,代码编写语法上的匿名内部类、内部接口或反射使用,多种情况叠加一起,有个在混淆文件写成库名(少个字母啥的没提示)。问题多了只能一步一步排查,需要具体到引用的库的类路径,不深入无法解决源头bug,没经验或者感觉的不到基本失败,自力更生~

在这里插入图片描述

电脑的内存和我都到极限了,歇息!

2022/08/31 何伟杰
掘金浏览 https://juejin.cn/post/7137968960997163045

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值