DEX 的三个特性会直接影响你怎么写查询。
一个 APK 里有多个 dex
APK 通常包含多个 classes*.dex。DexSQL 把它们放进同一组 SQL 关系,用 file_id 区分。由此有三条规则:
- 所有
*_idx索引只在单个 dex 内有效。method_idx = 42在不同 dex 里是不同的方法。join 时必须带上file_id,否则会跨 dex 串行。 - 同一个实体会在多个 dex 中各出现一次。 一个被 5 个 dex 引用的方法在
methods里有 5 行。要按实体计数,用DISTINCT descriptor。 - 字符串是例外:它的作用域是「池」,不是 dex。 键为
(string_pool_id, string_idx),从file_id经dex_files.string_pool_id到达。DEX 041 容器中多个逻辑 dex 共享一个池;041 之前每个 dex 各有一个自己的池。
descriptor 是什么
descriptor 是 DEX 用来指认一个实体的字符串,也是本 schema 中最常用的检索键:
| 实体 | 形式 | 例子 |
|---|---|---|
| 类型 | L<包路径>; |
Ljava/lang/String; |
| 方法 | <类><code>-></code><名>(<参数…>)<返回> |
Lpkg/Cls;->name(I)V |
| 字段 | <类><code>-></code><名>:<类型> |
Lpkg/Cls;->field:I |
基本类型是单字母:V void、Z boolean、B byte、S short、C char、I int、J long、F float、D double。数组加前缀 [,如 [Ljava/lang/String;。方法参数之间没有分隔符。
DEX 本身只存类型 descriptor;方法和字段的 descriptor 由 DexSQL 从各部分拼出来。
引用与定义
DEX 的 id 段(method_ids、field_ids、type_ids)登记的是当前 dex 引用到的实体,无论它在何处定义;成员的实际定义在 class-data 中,是另一份数据。DexSQL 保留这个区别:
| 关系 | 一行是 |
|---|---|
methods、fields、types |
一条引用 |
class_methods、class_fields、classes |
一条定义 |
只被引用的方法在 methods 中,其定义相关的列为 NULL。这些列的具体行为见 methods 条目。
Copyright (c) 2026 LSPosed Developers。本文档采用 MIT 许可证。