apk母包中合并第三方SDK代码
- 当我们需要将某些第三方SDK的代码合并到自己的apk母包的时候,一般的流程是解压第三方SDK的aar文件,然后合并里面的资源文件,assets、res目录直接拷贝合并就行,jni目录合并到apk的libs目录,AndroidManifest.xml文件则需要根据实际情况进行XML元素的合并,一部分元素或者属性不能进行合并,classes.jar以及libs下的jar文件则需要使用dx.jar或者d8.jar转为dex文件,然后再使用baksmali.jar转为smali文件,最后就可以合并到母包apk的smali目录里面了
- 在合并jar文件的时候需要特别注意一下jar文件里面是否还含有assets、unknown等其他资源文件,预防我们在手动进行合并的时候遗漏了,unknown资源文件的合并可以参考这篇文章:Android逆向开发处理unknown文件&AppsFlyer库中classes.jar中的a-,b-资源合并问题_林慈桥的博客-CSDN博客
使用dx.jar将aar包中的jar转为dex文件
- 首先进入dx.jar 所在的目录
- 然后再文件目录里面输入cmd按回车键,直接进入cmd命令窗口,可以看到已经定位到了dx.jar所在的目录
- 为了便于测试,我们在AS里面新建一个modul,然后编写一些代码,里面使用了java8的lambda表达式,gradle里面配置了java8的编译环境,这样我们构建一个aar包
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
package com.test.lib;
import android.util.Log;
import java.io.FileFilter;
public class Test {
public void fun() {
FileFilter fileFilter = file -> false;
Log.e("test", fileFilter.toString());
}
}
- 我们将生成的的x7.aar包拷贝到dx.jar所在目录,然后将x7.aar改为x7.zip,然后解压到x7目录下,然后我们执行java的jar命令,执行命令之前需要配置java环境变量,否则需要执行命令的时候需要输入java.exe所在的全路径,接下来执行命令:java -jar dx.jar --dex --output=x7/my.dex x7/classes.jar
H:\Sdk\build-tools\28.0.3\lib>java -jar dx.jar --dex --output=/my.dex x7/classes.jar
Uncaught translation error: com.android.dx.cf.code.SimException: ERROR in com.test.lib.Test.fun:()V: invalid opcode ba - invokedynamic requires --min-sdk-version >= 26 (currently 13)
1 error; aborting
- 很不幸的是jar转dex失败了,里面有提示:invalid opcode ba - invokedynamic requires --min-sdk-version >= 26 (currently 13) ,我们试着在命令里面加上--min-sdk-version=26参数,再执行命令:java -jar dx.jar --dex --min-sdk-version=26 --output=x7/my.dex x7/classes.jar
H:\Sdk\build-tools\28.0.3\lib>java -jar dx.jar --dex --min-sdk-version=26 --output=x7/my.dex x7/classes.jar
- OK,好像执行成功了,我们看下
- 接下来我们还需要将my.dex转为smali文件,我们将 baksmali.jar文件拷贝到dx.jar同目录下,方便我们执行命令,然后执行命令:java -jar baksmali.jar -o x7_smalid x7/my.dex
H:\Sdk\build-tools\28.0.3\lib>java -jar baksmali.jar -o x7_smalid x7/my.dex
Exception in thread "main" org.jf.util.ExceptionWithContext: x7\my.dex is not an apk, dex file or odex file.
at org.jf.dexlib2.DexFileFactory.loadDexFile(DexFileFactory.java:111)
at org.jf.dexlib2.DexFileFactory.loadDexFile(DexFileFactory.java:54)
at org.jf.baksmali.main.main(main.java:252)
- 结果转smali失败了,看来加了--min-sdk-version=26生成的dex文件还是有问题,baksmali.jar识别不到。产生这个问题的主要原因就是我们的源码里面使用了java8的lambda表达式,如果改成非lambda表达式方式,来执行dx.jar命令,就不会失败了,但是我们也不可能让第三方的SDK去改代码吧,所以还是要有其他方案来解决这个问题,还好google给我们提供了一个d8.jar工具,这个就可以用来处理java8新语法生成的jar转dex失败问题,下面是d8工具的命令说明:
H:\Sdk\build-tools\28.0.3\lib>java -jar d8.jar
Usage: d8 [options] <input-files>
where <input-files> are any combination of dex, class, zip, jar, or apk files
and options are:
--debug # Compile with debugging information (default).
--release # Compile without debugging information.
--output <file> # Output result in <outfile>.
# <file> must be an existing directory or a zip file.
--lib <file> # Add <file> as a library resource.
--classpath <file> # Add <file> as a classpath resource.
--min-api # Minimum Android API level compatibility
--intermediate # Compile an intermediate result intended for later
# merging.
--file-per-class # Produce a separate dex file per input class
--no-desugaring # Force disable desugaring.
--main-dex-list <file> # List of classes to place in the primary dex file.
--version # Print the version of d8.
--help # Print this message.
- 来执行下d8命令:
H:\Sdk\build-tools\28.0.3\lib>java -jar d8.jar --output H:\Sdk\build-tools\28.0.3\lib\x7 x7/classes.jar
Warning in x7\classes.jar:com/test/lib/Test.class:
Type `android.util.Log` was not found, it is required for default or static interface methods desugaring of `void com.test.lib.Test.fun()`
Warning in synthesized for lambda desugaring:
Interface `java.io.FileFilter` not found. It's needed to make sure desugaring of `com.test.lib.-$$Lambda$Test$3pJU-DzmeoaW6KjvNrGLr3KT1RM` is correct. Desugaring will assume that this interface has no default method.
- 可以看到已经生成了一个classes.dex文件,虽然有警告信息,但是执行是成功的,我们再使用baksmali.jar 工具来生成smali文件
H:\Sdk\build-tools\28.0.3\lib>java -jar baksmali.jar -o x7_smali x7\classes.dex
test
OK成功生成了smali文件,这样我们就可以将smali文件合并的母包apk中了
- 如果需要baksmali.jar工具的可以到这来下载:baksmali工具,用于将dex文件转为smali文件-Android文档类资源-CSDN下载
另一种生成smali文件的方法
- 如果我们不想将dx.jar工具升级为d8.jar该怎么办呢?有一种剑走偏锋的方法就是,引入一个空的项目工程,只引入第三方的SDK的代码,然后生成apk文件,再使用apktool进行反编译得到smali以及其他的代码资源文件
- 但是gradle需要配置minSdkVersion大于等于24,否则会有其他的问题出现 ,有兴趣的同学可以自己去试试