Skip to content

🦈 Shark 类详解 ​

Shark API构建 / CI 工具链

Shark 是 ClassyShark 面向构建与持续集成(CI)工具链的对外 API。它以建造者风格绑定一个归档文件(APK / JAR / AAR / DEX),再把所有读取请求委托给 SilverGhostFacade。

源码位置:ClassySharkWS/src/com/google/classyshark/Shark.java,模块参考见 Shark。

设计要点 🏗️ ​

mermaid
flowchart LR
    A["你的 CI 脚本 / Gradle 任务"] -->|"Shark.with(apk)"| B["Shark 实例"]
    B -->|"getGeneratedClass / getAllClassNames ..."| C["SilverGhostFacade"]
    C --> D["ContentReader"]
    C --> E["TranslatorFactory"]
    C --> F["DexMethodsDumper"]
    C --> G["DexStringsDumper"]
    D & E & F & G --> H["解析结果"]
特性说明
入口Shark.with(File archiveFile) 静态工厂,返回 Shark 实例
状态仅持有一个 File archiveFile 字段,无其它可变状态
委托所有方法都转发到 SilverGhostFacade 的静态方法
不可变构造器私有,只能通过 with(...) 创建,线程安全只读
包com.google.classyshark

API 速查 📚 ​

方法返回值委托目标用途
with(File)Shark—建造者入口,绑定归档文件
getGeneratedClass(String className)StringSilverGhostFacade.getGeneratedClassString反编译单个类的伪源码
getAllClassNames()List<String>SilverGhostFacade.getAllClassNames全量类名清单
getManifest()StringSilverGhostFacade.getManifestAndroidManifest 文本(仅 APK)
getAllMethods()List<String>SilverGhostFacade.getAllMethods所有 DEX 方法签名
getAllStrings()List<String>SilverGhostFacade.getAllStrings所有字符串池内容
isMultiDex()booleanSilverGhostFacade.isMultiDex是否多 DEX
isCustomMultiDex()booleanSilverGhostFacade.isCustomMultiDex是否自定义 DEX 加载

方法详解 🔍 ​

with(File archiveFile) ​

静态工厂,私有构造器的唯一入口。

java
public static Shark with(File archiveFile) {
    return new Shark(archiveFile);
}

💡 调用后即可链式或顺序访问所有读取方法,无需关心 ContentReader、Translator 的初始化。

getGeneratedClass(String className) ​

反编译单个类并返回伪 Java 源码字符串。委托 SilverGhostFacade.getGeneratedClassString(className, archiveFile),内部经 TranslatorFactory 选派翻译器并 translator.apply()。

java
/**
 * @param className class name to generate such as
 *                  "com.bumptech.glide.request.target.BaseTarget"
 */
public String getGeneratedClass(String className) {
    return getGeneratedClassString(className, archiveFile);
}

⚠️ 类不存在时,Facade 捕获 NullPointerException 并打印 Class doesn't exist in the writeArchive,返回空串 ""。

getAllClassNames() / getManifest() / getAllMethods() / getAllStrings() ​

方法实现备注
getAllClassNames()new ContentReader(file).load(); loader.getAllClassNames()含 .dex 条目,可用于遍历
getManifest()仅当文件名以 .apk 结尾时翻译 AndroidManifest.xml,否则返回 ""非 APK 永远空串
getAllMethods()非 APK 返回空 LinkedList,否则 DexMethodsDumper.dumpMethods见 DexMethodsDumper
getAllStrings()非 APK 返回空 LinkedList,否则 DexStringsDumper.dumpStrings见 DexStringsDumper

isMultiDex() / isCustomMultiDex() ​

isMultiDex() 统计以 .dex 结尾的条目,达到 2 个即返回 true。isCustomMultiDex() 在多 DEX 前提下进一步判断:

  • 条目中包含 classes1.dex → true
  • 任一 dex 条目不以 classes 开头 → true(自定义加载)

完整示例 🧪 ​

参照 Samples/SampleGradle/src/main/java/Main.java,下面是一个可运行的 CI 检查任务:

java
import com.google.classyshark.Shark;
import java.io.File;

public class Main {
    public static void main(String[] args) {
        // 1. 绑定归档(示例路径请替换为产物路径)
        File apk = new File(args[0]);
        Shark shark = Shark.with(apk);

        // 2. 反编译指定类
        System.out.println(
                shark.getGeneratedClass("com.bumptech.glide.request.target.BaseTarget"));

        // 3. 全量类名
        System.out.println(shark.getAllClassNames());

        // 4. AndroidManifest
        System.out.println(shark.getManifest());

        // 5. 所有方法签名
        System.out.println(shark.getAllMethods());

        // 6. 统计汇总
        System.out.println("\n\nAll Classes " + shark.getAllClassNames().size() +
                "\nAll Methods " + shark.getAllMethods().size());

        // 7. 多 DEX 检测
        System.out.println("isMultiDex        = " + shark.isMultiDex());
        System.out.println("isCustomMultiDex  = " + shark.isCustomMultiDex());

        // 8. 字符串池(数据量大,按需开启)
        // System.out.println(shark.getAllStrings());
    }
}

Gradle 集成示意:

groovy
plugins { id 'application' }

application {
    mainClass = 'Main'
}

dependencies {
    // 把 ClassyShark 作为库依赖引入
    implementation files('libs/ClassyShark.jar')
}

// CI 钩子:产物 APK 一就绪就跑分析
task analyzeApk(type: JavaExec) {
    classpath = sourceSets.main.runtimeClasspath
    mainClass = 'Main'
    args = [layout.buildDirectory.file("outputs/apk/release/app-release.apk").get().asFile.path]
}
build.finalizedBy analyzeApk

CI 场景建议 ✅ ​

场景用到的 API
确认没有引入禁用类getAllClassNames() 过滤黑名单
核对方法数是否逼近 65k 上限getAllMethods().size()
校验 MultiDex 配置isMultiDex() / isCustomMultiDex()
自动审计 Manifest 权限getManifest() 解析 XML
关键类源码快照归档getGeneratedClass(className)
硬编码密钥扫描getAllStrings() 关键字匹配

与 CLI 的关系 🔗 ​

CLI 的 -inspect、-methodcounts、-export 等命令同样走 SilverGhostFacade,差别只在 CLI 用 CliMode 分发参数、Shark 用建造者绑定 File。当你需要嵌入到 Gradle/Jenkins 脚本里以编程方式取数据时,用 Shark;需要一行命令快速看结果时,用 CLI(见 CLI 参考)。

📌 进阶模块参考:Shark、SilverGhostFacade、TranslatorFactory、ContentReader。

最后更新:

基于 Apache 2.0 协议发布