补齐Android技能树 - 从害怕到玩转Android代码混淆(上)

简介: 本节稍微深入点探索下Android中的代码混淆~

0x0、引言


Android代码混淆,老生常谈了,不过大部分Android仔对它的认识可能还处于这样的阶段(比如:写这篇文章前的我):


  • 1、日常开发Debug包时不用混淆,正式发布Release包前开启代码混淆;


  • 2、混淆好处① → 类、方法、变量名变成短且无意义的名字,提高反编译后代码的阅读成本;


  • 3、混淆好处② → 删除无用的类、方法与属性,缩减了APK包的大小;


  • 4、混淆好处③ → 对字节码进行优化,移除无用指令,应用运行更快;


  • 5、怎么混淆 → 主项目的 build.gradle 设置 minifyEnabled trueproguard-rules.pro 加入混淆规则;


  • 6、混淆规则哪里来 → 网上搜索通用混淆模板复制粘贴,项目依赖到的第三方库官方文档复制粘贴;


大都止步于此,好一点的还知道下 ProGuard 听过 R8,了解 混淆配置语法,会 自定义混淆规则


会上面这些,日常开发已经 很够用了,但是现在IT行业这么 "卷",面试时,面试官问下:


混淆具体做了啥?有看过混淆源码吗?说下底层原理...


所以本节稍微深入点探索下Android中的代码混淆~


0x1、日常使用


Tips:照惯例,写下简单例子演示日常使用,走走过场,只对混淆原理感兴趣的可以跳过这Part~


1. 混淆前后的APK对比


新建项目,引下Kotlin相关依赖,协程等 (app层级的build.gradle):


dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.0'
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7'
}


新建MainActivity.kt,请求URL,加载内容:


class MainActivity : AppCompatActivity(), CoroutineScope by MainScope()  {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        et_url.setText("https://www.baidu.com")
        bt_load.setOnClickListener {
            launch {
                tv_content.text = "开始加载请求..."
                tv_content.text = "加载完毕,网页内容如下:\n\n\n ${loadUrl(et_url.text.toString())}"
            }
        }
    }
    private suspend fun loadUrl(url: String) = withContext(Dispatchers.IO) {
        var content = ""
        (URL(url).openConnection() as HttpURLConnection).apply {
            requestMethod = "GET"
            content = dealResponse(inputStream)
            disconnect()
        }
        return@withContext content
    }
    private fun dealResponse(inputStream: InputStream): String {
        val reader = BufferedReader(InputStreamReader(inputStream))
        return StringBuffer().apply {
            var str = reader.readLine()
            while (null != str) {
                append(str)
                str = reader.readLine()
            }
        }.toString()
    }
    override fun onDestroy() {
        super.onDestroy()
        cancel()
    }
}


运行下康康


网络异常,图片无法展示
|


app层级的build.gradle加下release的签名和编译配置:


signingConfigs {
    release {
        storeFile file('test.jks')
        storePassword '123456'
        keyAlias 'test'
        keyPassword '123456'
    }
}
buildTypes {
    release {
        // 启用代码压缩、优化及混淆
        minifyEnabled true
        // 启用资源压缩,需配合 minifyEnabled=true 使用
        shrinkResources true
        // 指定混淆保留规则
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        // 包签名
        signingConfig signingConfigs.release
    }
}


执行 gradle assemble 打下包,静待打包完毕,先康康Debug包:


网络异常,图片无法展示
|


裸奔,把APK直接拖到反编译工具 jadx-gui 里,看代码无压力:


网络异常,图片无法展示
|


再康康Release包:


网络异常,图片无法展示
|


体积着实少了一些,而且变量名都变成了abcd,顺带提下这个**Load Proguard mappings**,点击加载混淆文件(mapping.txt)后可以去掉代码混淆:


网络异常,图片无法展示
|


同样拖到jadx-gui里康康:


网络异常,图片无法展示
|


可读性明显降低~


2. 混淆后App Crash日志定位问题


不知道你有没有想过:混淆后的APK如果报错,日志信息会是怎样的呢


改下代码验证下,直接在点击处抛出一个空指针异常试试康:


网络异常,图片无法展示
|


单凭这里的b.b.a.a.onClick(Unknow Srouce:2),似乎很难直接定位到错误代码的真实位置。


一种低效的解决方法:自行对照混淆后生成的 mapping.txt 文件,比如直接搜上面的b.b.a.a:


网络异常,图片无法展示
|


顺着往下看不难发现问题所在,但日常开发不建议用此法,这里好找只是因为示例代码简单,推荐另一种方法:


去混淆,如果你的应用有发布到Google Play的话,可以照着官方文档走:


对崩溃堆栈轨迹进行去混淆处理或符号化解析


网络异常,图片无法展示
|


没有上传到Google Play也没关系,直接用 android-

sdk/tools/proguard/bin/proguardgui.bat


网络异常,图片无法展示
|


ProGuard和R8的混淆都可以去,老版本的脚本可能不支持R8,更新下sdk即可,不想更新的也可以直接用我提供的脚本包去R8混淆,下载地址(提取码: 1234):R8-Retrace.7z,使用流程如下图所示:


网络异常,图片无法展示
|


去混淆前后对比:


网络异常,图片无法展示
|


可以的,日常使用就讲到这里,接着过一下混淆的详细规则。


相关文章
|
3月前
|
编解码 Java Android开发
安卓虚拟摄像头免root版,虚拟摄像头替换真实摄像头,jar代码开源分享
通过动态替换摄像头输入流的方式实现虚拟摄像头功能,代码经过简化展示核心逻辑。实际开发中还需要考虑视频编解码优化
|
12月前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
205 1
|
12月前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异:从代码到用户体验
【10月更文挑战第5天】在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。它们在技术架构、开发环境及用户体验上有着根本的不同。本文通过比较这两种平台的开发过程,揭示背后的设计理念和技术选择如何影响最终产品。我们将深入探讨各自平台的代码示例,理解开发者面临的挑战,以及这些差异如何塑造用户的日常体验。
|
存储 Java Android开发
🔥Android开发大神揭秘:从菜鸟到高手,你的代码为何总是慢人一步?💻
在Android开发中,每位开发者都渴望应用响应迅速、体验流畅。然而,代码执行缓慢却是常见问题。本文将跟随一位大神的脚步,剖析三大典型案例:主线程阻塞导致卡顿、内存泄漏引发性能下降及不合理布局引起的渲染问题,并提供优化方案。通过学习这些技巧,你将能够显著提升应用性能,从新手蜕变为高手。
159 2
|
JSON JavaScript 前端开发
Android调用Vue中的JavaScript代码
Android调用Vue中的JavaScript代码
279 3
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
很多文章都介绍了FTPClient如何连接ftp服务器,但却很少有人说如何连接一台开了SSL认证的ftp服务器,现在代码来了。
300 2
|
存储 Java Android开发
🔥Android开发大神揭秘:从菜鸟到高手,你的代码为何总是慢人一步?💻
【7月更文挑战第28天】在Android开发中,每位开发者都追求极致的用户体验。然而,“代码执行慢”的问题时常困扰着开发者。通过案例分析,我们可探索从新手到高手的成长路径。
104 3
|
API Android开发
Android 监听Notification 被清除实例代码
Android 监听Notification 被清除实例代码
|
Java Android开发
Android项目架构设计问题之要提升代码的可读性和管理性如何解决
Android项目架构设计问题之要提升代码的可读性和管理性如何解决
93 0
|
JavaScript 前端开发 Android开发
kotlin安卓在Jetpack Compose 框架下使用webview , 网页中的JavaScript代码如何与native交互
在Jetpack Compose中使用Kotlin创建Webview组件,设置JavaScript交互:`@Composable`函数`ComposableWebView`加载网页并启用JavaScript。通过`addJavascriptInterface`添加`WebAppInterface`类,允许JavaScript调用Android方法如播放音频。当页面加载完成时,执行`onWebViewReady`回调。

热门文章

最新文章