reproto 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. .git/COMMIT_EDITMSG +24 -25
  2. .git/index +0 -0
  3. .git/logs/HEAD +3 -0
  4. .git/logs/refs/heads/iyue +3 -0
  5. .git/logs/refs/remotes/gitlab/iyue +3 -0
  6. .git/logs/refs/remotes/origin/iyue +3 -0
  7. .git/objects/00/81a7e1ec3251cc192ed2b73d5be897593fb872 +0 -0
  8. .git/objects/00/885cebf557ff261574deb93cb96449d06db01c +0 -0
  9. .git/objects/02/33f5b60263e5dc6d041c0b223a0724eb650faa +0 -0
  10. .git/objects/07/557fbd1d149ce51af8e98e8ca8590757a89dfa +0 -0
  11. .git/objects/12/f9cc4ad0b4f0af4f7bae379f281b2cebe7cc7f +0 -0
  12. .git/objects/24/d78e796570a8572a03bc1dd26608a7cfb506f8 +2 -0
  13. .git/objects/2a/fe93d8bcbeab9e136d8b6766604c32b3610314 +0 -0
  14. .git/objects/2d/8a0da260a710010ae62be134ac1cea6ceecfd1 +0 -0
  15. .git/objects/2d/e8ecbb5ab5de1a032bef3f4606ce5fa7c6c4e8 +0 -0
  16. .git/objects/30/9347e5681d80bd3c7949882e27090dd9070d16 +0 -0
  17. .git/objects/33/633c9df669ff8cf38638717937a54990814268 +0 -0
  18. .git/objects/39/993e3600bf4ab82aa361b738ee97a108787450 +0 -0
  19. .git/objects/3b/ab663710fd6b43d9372313fced9043c4cb07dd +0 -0
  20. .git/objects/3e/b3f1273caf6814dfa69325ccbd9fd1340cf20a +0 -0
  21. .git/objects/45/fbc774dedb61c7c205ea732f59a8dca8d13555 +3 -0
  22. .git/objects/60/5cb6fd6a9f8894ad4d43a9b8e4785c1b3b0e17 +1 -0
  23. .git/objects/60/f61a0ea50091eac8d344c86597375cbdfc2785 +0 -0
  24. .git/objects/63/ddda2a403efaab3f4c6597b3a73a7b1147adb5 +0 -0
  25. .git/objects/66/6c5c5fc30435228116fa08c9d821bebaaa8926 +0 -0
  26. .git/objects/7c/ef0adfb28fd774bc78061c6f088e1ef9b050f6 +0 -0
  27. .git/objects/7d/dc129188a10c68ab756ef2cacb292c76920403 +0 -0
  28. .git/objects/80/17038e0f7818a44a742f77c86f4f88ed768fcd +0 -0
  29. .git/objects/87/c7db6c91c17a2df84b56d30bd24a0f6b9dbdd9 +0 -0
  30. .git/objects/92/984cf67b2c25d435468a8218daa26ba0466054 +0 -0
  31. .git/objects/93/140b54b1fb9116ee214afee8abf2c72a232487 +0 -0
  32. .git/objects/93/68f2c32f83054ab072b7c9686d8baa0bad7f12 +4 -0
  33. .git/objects/9a/5ad062be9f6e001f4237a598a08981aba731e6 +0 -0
  34. .git/objects/a1/655e0cb323c300562f97dcc67d5a446908c8ec +0 -0
  35. .git/objects/a5/38cc82cef7c49500d3522220f0f60a9ebc1ae6 +0 -0
  36. .git/objects/a9/41063a7ce89c353fa24378ec7c3f12f08f9df8 +0 -0
  37. .git/objects/ac/5c983d949d8c928bb022badf801e45e75e785e +0 -0
  38. .git/objects/b0/82ca2c1b5a03edff25da3c2b2b573d049877e9 +0 -0
  39. .git/objects/bc/e98bdb71c8681acb460195fdcbbe5d36290976 +0 -0
  40. .git/objects/c1/87d5e047eca86cfd8d444be2987aaa3f62c4d6 +0 -0
  41. .git/objects/c4/c2da96b0bb8db2acb0e6615cf340c7e51af26b +0 -0
  42. .git/objects/c5/13a96e7584636b20b12280c029750d5bc3da1e +0 -0
  43. .git/objects/c7/c34283697bd3cce07db53953eda25ee7cc371e +0 -0
  44. .git/objects/c9/d60d922a04b87587cd67b0abf9fe5a7b7b76cd +0 -0
  45. .git/objects/d2/69b1676dbf32f76a7c405d0b4ea6a70ac3a626 +0 -0
  46. .git/objects/d3/5a918b1d9125ad35d60e08b181323df3246f1a +0 -0
  47. .git/objects/d8/eaf86669fbfd10497570c1784db1ed2696b588 +0 -0
  48. .git/objects/d9/90e6d553577d37ebce8b28b3015ecbde038b42 +0 -0
  49. .git/objects/da/13cc15bcd8ee39c81f36dee7f179a569ecab0b +0 -0
  50. .git/objects/e4/4c1d8a90207ac082d8ab7ff0db66708e2ebc31 +0 -0
  51. .git/objects/f8/ed595d25bd9d500e765a792c513878f7ddb1f7 +0 -0
  52. .git/refs/heads/iyue +1 -1
  53. .git/refs/remotes/gitlab/iyue +1 -1
  54. .git/refs/remotes/origin/iyue +1 -1
  55. README.md +104 -190
  56. core/__init__.py +23 -0
  57. core/info_decoder.py +13 -4
  58. core/reconstructor.py +25 -16
  59. generation/__init__.py +17 -0
  60. generation/proto_generator.py +11 -5
  61. main.py +53 -56
  62. models/__init__.py +31 -24
  63. parsing/__init__.py +22 -0
  64. parsing/enum_parser.py +10 -2
  65. parsing/java_parser.py +7 -1
  66. pyproject.toml +1 -1
  67. reproto-0.1.3.dist-info/METADATA +209 -0
  68. {reproto-0.1.2.dist-info → reproto-0.1.3.dist-info}/RECORD +75 -30
  69. utils/__init__.py +40 -0
  70. utils/builtin_proto.py +8 -1
  71. utils/file_cache.py +8 -1
  72. utils/report_utils.py +71 -0
  73. utils/type_index.py +8 -1
  74. core/bytecode_parser.py +0 -274
  75. reproto-0.1.2.dist-info/METADATA +0 -295
  76. {reproto-0.1.2.dist-info → reproto-0.1.3.dist-info}/WHEEL +0 -0
  77. {reproto-0.1.2.dist-info → reproto-0.1.3.dist-info}/entry_points.txt +0 -0
core/bytecode_parser.py DELETED
@@ -1,274 +0,0 @@
1
- from typing import List, Dict, Tuple
2
- import re
3
- from ..models import FieldDefinition, OneofDefinition
4
- from utils.type_utils import naming_converter
5
-
6
- class BytecodeParser:
7
- """
8
- 重新设计的 Protobuf info_string 解析器,基于对 Google Protobuf Lite 格式的深入理解。
9
-
10
- info_string 格式分析:
11
- - 前面是头部信息(版本、字段数量等)
12
- - 后面是字段描述符,每个字段用特定格式编码
13
- - '<' 字符表示 oneof 字段
14
- - 数字表示字段标签
15
- """
16
-
17
- def __init__(self, info_bytes: bytes, objects: List[str]):
18
- """
19
- 初始化解析器。
20
-
21
- 参数:
22
- info_bytes (bytes): 从 info_string 编码而来的字节数组。
23
- objects (List[str]): 作为符号表的 objects 数组。
24
- """
25
- self.info_string = info_bytes.decode('utf-8')
26
- self.objects = objects
27
- # print(f" > 原始 info_string: {repr(self.info_string)}")
28
- # print(f" > 对象数组: {self.objects}")
29
-
30
- def parse(self) -> Tuple[List[FieldDefinition], Dict[str, OneofDefinition]]:
31
- """
32
- 解析 info_string 并返回字段定义。
33
-
34
- 基于观察到的模式:
35
- - SearchResult: "\\u0000\\u0002\\u0001\\u0000\\u0001\\u0002\\u0002\\u0000\\u0000\\u0000\\u0001<\\u0000\\u0002<\\u0000"
36
- - ContactPhone: "\\u0000\\u0003\\u0001\\u0000\\u0001\\u0003\\u0003\\u0000\\u0000\\u0000\\u0001<\\u0000\\u0002<\\u0000\\u0003<\\u0000"
37
- """
38
- fields: List[FieldDefinition] = []
39
- oneofs: Dict[str, OneofDefinition] = {}
40
-
41
- # 尝试解析字段描述符部分
42
- # 寻找 '<' 字符,它们标识 oneof 字段
43
- field_descriptors = self._extract_field_descriptors()
44
-
45
- if not field_descriptors:
46
- return fields, oneofs
47
-
48
- # 确定 oneof 名称(从 objects 数组中)
49
- oneof_name = self._determine_oneof_name()
50
-
51
- if oneof_name:
52
- # 这是一个 oneof 结构
53
- oneof_def = OneofDefinition(name=oneof_name)
54
-
55
- for i, desc in enumerate(field_descriptors):
56
- if desc.get('is_oneof'):
57
- field_tag = desc['tag']
58
- field_type = self._determine_field_type(i + 2) # objects[2], objects[3], etc.
59
- field_name = self._generate_field_name(field_type, field_tag)
60
-
61
- field = FieldDefinition(
62
- name=field_name,
63
- type=field_type,
64
- tag=field_tag,
65
- rule="optional"
66
- )
67
- oneof_def.fields.append(field)
68
-
69
- oneofs[oneof_name] = oneof_def
70
- else:
71
- # 常规字段结构
72
- for i, desc in enumerate(field_descriptors):
73
- field_tag = desc['tag']
74
- # 对于常规字段,从 objects 数组中获取字段名
75
- if field_tag - 1 < len(self.objects):
76
- raw_field_name = self.objects[field_tag - 1] # tag 从 1 开始,数组从 0 开始
77
- field_name = self._clean_field_name(raw_field_name)
78
- else:
79
- field_name = f"field_{field_tag}"
80
-
81
- # 尝试推断字段类型
82
- field_type = self._infer_field_type(desc, field_tag)
83
-
84
- # 检查是否是 repeated 字段
85
- if field_type.startswith("repeated "):
86
- rule = "repeated"
87
- field_type = field_type[9:] # 移除 "repeated " 前缀
88
- else:
89
- rule = "optional"
90
-
91
- field = FieldDefinition(
92
- name=field_name,
93
- type=field_type,
94
- tag=field_tag,
95
- rule=rule
96
- )
97
- fields.append(field)
98
-
99
- return fields, oneofs
100
-
101
- def _extract_field_descriptors(self) -> List[Dict]:
102
- """
103
- 从 info_string 中提取字段描述符。
104
-
105
- 基于观察:
106
- - 字段描述符通常在字符串的后半部分
107
- - '<' 字符标识 oneof 字段
108
- - 数字字符表示字段标签
109
- """
110
- descriptors = []
111
-
112
- # 先打印原始字符串的字符分析
113
- # print(f" > 字符串分析:")
114
- # for i, char in enumerate(self.info_string):
115
- # if ord(char) > 32: # 可打印字符
116
- # print(f" 位置 {i}: '{char}' (ord={ord(char)})")
117
- # else:
118
- # print(f" 位置 {i}: \\x{ord(char):02x}")
119
-
120
- # 寻找 '<' 字符的位置
121
- oneof_positions = []
122
- for i, char in enumerate(self.info_string):
123
- if char == '<':
124
- oneof_positions.append(i)
125
-
126
- # print(f" > 找到 oneof 标记位置: {oneof_positions}")
127
-
128
- # 对于每个 '<' 字符,查找前面的数字作为字段标签
129
- for pos in oneof_positions:
130
- # 查找 '<' 前面的字符
131
- if pos > 0:
132
- prev_char = self.info_string[pos - 1]
133
- prev_byte = ord(prev_char)
134
- # print(f" '<' 前面的字节: \\x{prev_byte:02x} (值={prev_byte})")
135
-
136
- # 检查是否是有效的字段标签(1-15 是常见范围)
137
- if 1 <= prev_byte <= 15:
138
- tag = prev_byte
139
- descriptors.append({
140
- 'tag': tag,
141
- 'is_oneof': True,
142
- 'position': pos
143
- })
144
- # print(f" 发现 oneof 字段: tag={tag}, 位置={pos}")
145
-
146
- # 如果没有找到 oneof 字段,尝试寻找普通字段
147
- if not descriptors:
148
- # 寻找可能的字段标签模式
149
- # 对于非 oneof 字段,我们需要查找其他模式
150
- # print(f" > 没有找到 oneof 字段,尝试寻找常规字段...")
151
-
152
- # 查找特殊字符 'Ȉ' (ord=520) 这似乎是字段标记
153
- for i, char in enumerate(self.info_string):
154
- if ord(char) == 520: # 'Ȉ' 字符
155
- # 查找前面的字节作为字段标签
156
- if i > 0:
157
- prev_byte = ord(self.info_string[i - 1])
158
- if 1 <= prev_byte <= 50: # 扩大范围以捕获更多字段
159
- descriptors.append({
160
- 'tag': prev_byte,
161
- 'is_oneof': False,
162
- 'position': i
163
- })
164
- # print(f" 发现常规字段: tag={prev_byte}, 位置={i}")
165
-
166
- # 如果还是没有找到,尝试其他数字模式
167
- if not descriptors:
168
- for i, char in enumerate(self.info_string):
169
- byte_val = ord(char)
170
- if 1 <= byte_val <= 20 and byte_val <= len(self.objects): # 可能的字段标签
171
- # 检查前后上下文以确认这是字段标签
172
- if i < len(self.info_string) - 1:
173
- next_char = self.info_string[i + 1]
174
- # 如果下一个字符是特殊标记,这可能是字段标签
175
- if ord(next_char) in [50, 60, 520, 27]: # 各种字段类型标记
176
- descriptors.append({
177
- 'tag': byte_val,
178
- 'is_oneof': False,
179
- 'position': i
180
- })
181
- # print(f" 发现可能的字段: tag={byte_val}, 位置={i}")
182
-
183
- return descriptors
184
-
185
- def _determine_oneof_name(self) -> str:
186
- """
187
- 从 objects 数组确定 oneof 的名称。
188
-
189
- 观察:
190
- - objects[0] 通常是 oneof 字段名(如 "result_", "sealedValue_")
191
- - objects[1] 通常是 case 字段名(如 "resultCase_", "sealedValueCase_")
192
- """
193
- if len(self.objects) >= 2:
194
- field_name = self.objects[0]
195
- case_name = self.objects[1]
196
-
197
- # 检查是否符合 oneof 模式
198
- if (field_name.endswith('_') and
199
- case_name.endswith('Case_') and
200
- case_name.startswith(field_name[:-1])):
201
-
202
- # 从字段名生成 oneof 名称
203
- base_name = field_name[:-1] # 移除末尾的 '_'
204
- return self._to_snake_case(base_name)
205
-
206
- return ""
207
-
208
- def _determine_field_type(self, object_index: int) -> str:
209
- """
210
- 从 objects 数组确定字段类型。
211
- """
212
- if object_index < len(self.objects):
213
- obj = self.objects[object_index]
214
- if obj.endswith('.class'):
215
- # 移除 '.class' 后缀,提取类名
216
- class_name = obj[:-6]
217
- # 提取最后一部分作为类型名
218
- return class_name.split('.')[-1]
219
- else:
220
- return obj
221
- return "unknown"
222
-
223
- def _generate_field_name(self, field_type: str, field_tag: int) -> str:
224
- """
225
- 根据字段类型和标签生成字段名称。
226
- """
227
- # 将类型名转换为 snake_case
228
- name = self._to_snake_case(field_type)
229
- return name
230
-
231
- def _to_snake_case(self, name: str) -> str:
232
- """
233
- 将 CamelCase 转换为 snake_case。
234
- """
235
- return naming_converter.to_snake_case(name)
236
-
237
- def _clean_field_name(self, name: str) -> str:
238
- """
239
- 清理字段名称,去除不必要的后缀或前缀。
240
- """
241
- # 去除末尾的下划线
242
- if name.endswith('_'):
243
- name = name[:-1]
244
- # 转换为 snake_case
245
- return self._to_snake_case(name)
246
-
247
- def _infer_field_type(self, desc: Dict, field_tag: int) -> str:
248
- """
249
- 根据字段描述符推断字段类型。
250
- """
251
- # 检查 info_string 中字段标签后面的字节来推断类型
252
- position = desc.get('position', -1)
253
- if position > 0 and position < len(self.info_string) - 1:
254
- # 查看字段标签后面的字节
255
- next_byte = ord(self.info_string[position + 1])
256
-
257
- # 根据字节值推断类型
258
- if next_byte == 27: # 0x1B - repeated message
259
- # 查找对应的类类型
260
- if field_tag < len(self.objects):
261
- class_obj = self.objects[field_tag] # objects[1] 对应 tag=1
262
- if class_obj.endswith('.class'):
263
- class_name = class_obj[:-6].split('.')[-1]
264
- return f"repeated {class_name}"
265
- return "repeated message"
266
- elif next_byte == 520: # 'Ȉ' - string field
267
- return "string"
268
- elif next_byte == 12: # 0x0C - enum
269
- return "int32" # 枚举通常映射为 int32
270
- elif next_byte == 50: # '2' - 可能是某种数字类型
271
- return "int32"
272
-
273
- # 默认返回 string
274
- return "string"
@@ -1,295 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: reproto
3
- Version: 0.1.2
4
- Summary: 一个强大的逆向工程工具, 能够从任何使用Google Protobuf Lite的Android应用中自动重构出完整的.proto文件结构.
5
- License: Proprietary
6
- Keywords: protobuf,reverse-engineering,android,jadx,proto
7
- Author: iyue
8
- Author-email: ys1231@126.com
9
- Requires-Python: >=3.12,<4.0
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Intended Audience :: Developers
12
- Classifier: License :: Other/Proprietary License
13
- Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3.12
15
- Classifier: Programming Language :: Python :: 3.13
16
- Classifier: Topic :: Software Development :: Code Generators
17
- Classifier: Topic :: Software Development :: Disassemblers
18
- Requires-Dist: loguru (>=0.7.3)
19
- Project-URL: Homepage, https://github.com/ys1231/reproto
20
- Project-URL: Repository, https://github.com/ys1231/reproto.git
21
- Description-Content-Type: text/markdown
22
-
23
- # Protobuf Reconstructor
24
-
25
- 🔧 **从JADX反编译的Java源码自动重构Protobuf .proto文件**
26
-
27
- 一个强大的逆向工程工具,能够从任何使用Google Protobuf Lite的Android应用中自动重构出完整的.proto文件结构。经过重大性能优化,执行效率提升20%+。
28
-
29
- ## ✨ 特性
30
-
31
- - 🎯 **精准解析**: 基于Google Protobuf Lite字节码的逆向工程
32
- - 🔄 **递归依赖**: 自动发现和处理所有依赖的消息和枚举类型
33
- - 📦 **完整支持**: 支持oneof、repeated、map、枚举等所有Protobuf特性
34
- - 🌐 **通用性**: 适用于任何Android应用,无需硬编码映射
35
- - 🧠 **智能推断**: 从Java源码直接读取类型信息,确保高准确性
36
- - 📝 **标准输出**: 严格遵循Google Proto Style Guide
37
- - 🚀 **高性能**: 文件缓存系统 + 智能路径构造,执行速度提升20%+
38
- - 🛠️ **特殊类型支持**: MapFieldLite、Internal.ProtobufList、Google Well-Known Types
39
-
40
- ## 🛠️ 安装
41
-
42
- ```bash
43
- # 克隆项目
44
- git clone https://github.com/ys1231/reproto.git
45
- cd reproto
46
-
47
- # 安装依赖
48
- pip install -r requirements.txt
49
- ```
50
-
51
- ## 📖 使用方法
52
-
53
- ### 基本用法
54
- ```bash
55
- python main.py <java_sources_dir> <root_class> <output_dir> [--verbose]
56
- ```
57
-
58
- ### 参数说明
59
- - `java_sources_dir`: JADX反编译的Java源码目录路径
60
- - `root_class`: 要重构的根类完整类名(如:com.example.Model)
61
- - `output_dir`: 生成的proto文件输出目录路径
62
- - `--verbose`: 显示详细处理信息
63
-
64
- ### 示例
65
- ```bash
66
- # 重构消息应用的数据模型
67
- python main.py ./out_jadx/sources com.example.messaging.v1.models.MessageData ./protos_generated --verbose
68
-
69
- # 重构内部类
70
- python main.py ./out_jadx/sources 'com.truecaller.accountonboarding.v1.Models$Onboarded' ./output --verbose
71
-
72
- # 重构包含特殊类型的类
73
- python main.py ./out_jadx/sources com.truecaller.search.v1.models.SearchResult ./output --verbose
74
- ```
75
-
76
- ## 🔍 工作原理
77
-
78
- ### 核心技术
79
- 1. **字节码解析**: 逆向工程Google Protobuf Lite的`newMessageInfo`调用
80
- 2. **依赖发现**: 递归分析Java文件中的类型引用
81
- 3. **智能推断**: 基于字段名和对象数组推断枚举和消息类型
82
- 4. **源码分析**: 直接从Java源码读取真实的字段类型声明
83
- 5. **🆕 性能优化**: 文件缓存系统 + 直接路径构造,避免全目录扫描
84
-
85
- ### 解析流程
86
- ```
87
- Java源码 → 字节码提取 → 类型解码 → 依赖发现 → 源码验证 → Proto生成
88
-
89
- 🚀 性能优化: 文件缓存 + 智能路径构造 + 统一类型检测
90
- ```
91
-
92
- ## 📁 项目结构
93
-
94
- ```
95
- reproto/
96
- ├── main.py # 主程序入口
97
- ├── core/ # 核心组件
98
- │ ├── reconstructor.py # 主协调器 (已优化)
99
- │ ├── info_decoder.py # 字节码解码器
100
- │ └── bytecode_parser.py # 字节码解析工具
101
- ├── parsing/ # 解析模块
102
- │ ├── java_parser.py # Java文件解析器
103
- │ ├── enum_parser.py # 枚举解析器 (🆕)
104
- │ └── java_source_analyzer.py # Java源码分析器 (已优化)
105
- ├── generation/ # 生成模块
106
- │ └── proto_generator.py # Proto文件生成器
107
- ├── models/ # 数据模型
108
- │ └── message_definition.py # 消息和枚举定义
109
- ├── utils/ # 工具函数 (大幅扩展)
110
- │ ├── logger.py # 日志系统
111
- │ ├── file_utils.py # 文件工具
112
- │ ├── file_cache.py # 文件缓存系统 (🆕)
113
- │ └── type_utils.py # 类型处理工具 (🆕)
114
- └── logs/ # 日志文件目录
115
- ```
116
-
117
- ## 📊 输出示例
118
-
119
- ### 输入:Java源码
120
- ```java
121
- public final class BulkSearchResult extends GeneratedMessageLite {
122
- private MapFieldLite<String, Contact> contacts_;
123
- private Internal.ProtobufList<String> phoneNumbers_;
124
-
125
- public static final int CONTACTS_FIELD_NUMBER = 1;
126
- public static final int PHONE_NUMBERS_FIELD_NUMBER = 2;
127
- }
128
- ```
129
-
130
- ### 输出:Proto文件
131
- ```protobuf
132
- syntax = "proto3";
133
-
134
- package com.truecaller.search.v1.models;
135
-
136
- option java_package = "com.truecaller.search.v1.models";
137
- option java_multiple_files = true;
138
-
139
- message BulkSearchResult {
140
- map<string, Contact> contacts = 1;
141
- repeated string phone_numbers = 2;
142
- }
143
- ```
144
-
145
- ## 🚀 性能优化亮点
146
-
147
- ### 🆕 重大性能提升
148
- - **总执行时间**: 从~81秒优化到~65秒,提升 **19.8%**
149
- - **基础类型检测**: 从2-3秒延迟优化为 **瞬间响应**,提升 **99%+**
150
- - **索引系统**: 移除未使用的索引系统,节省 **100%** 构建开销
151
- - **文件I/O**: 智能缓存系统,避免重复读取
152
-
153
- ### 🔧 技术优化
154
- 1. **文件缓存系统**: 线程安全的文件内容缓存,避免重复I/O
155
- 2. **直接路径构造**: 根据包名直接构造文件路径,避免全目录扫描
156
- 3. **统一类型检测**: 使用`TypeMapper`统一处理所有类型转换
157
- 4. **智能包名推断**: 基于包结构的智能类名解析
158
-
159
- ### 📈 性能监控
160
- ```bash
161
- 📊 文件缓存统计:
162
- 总请求数: 33
163
- 缓存命中: 0 # 表明程序高效,无重复读取
164
- 缓存未命中: 33 # 每个文件只读取一次
165
- 已缓存文件: 33 # 所有文件已缓存备用
166
- ```
167
-
168
- ## 🛠️ 特殊类型支持
169
-
170
- ### MapFieldLite 支持
171
- ```java
172
- // Java源码
173
- private MapFieldLite<String, Contact> contacts_;
174
-
175
- // 生成的Proto
176
- map<string, Contact> contacts = 1;
177
- ```
178
-
179
- ### Internal.ProtobufList 支持
180
- ```java
181
- // Java源码
182
- private Internal.ProtobufList<String> tags_;
183
-
184
- // 生成的Proto
185
- repeated string tags = 1;
186
- ```
187
-
188
- ### Google Well-Known Types
189
- - `google.protobuf.Any`
190
- - `google.protobuf.Timestamp`
191
- - `google.protobuf.Duration`
192
- - `google.protobuf.StringValue`
193
- - 等等...
194
-
195
- ## 🚀 工作流程
196
-
197
- 1. 使用JADX反编译Android应用:`jadx -d out_jadx app.apk`
198
- 2. 运行ReProto指定根Protobuf类
199
- 3. 自动解析所有相关类和依赖
200
- 4. 🆕 智能缓存和路径优化,快速处理
201
- 5. 生成完整的.proto文件结构
202
-
203
- ## 📝 配置选项
204
-
205
- ### 日志配置
206
- - 日志文件自动保存到 `./logs/` 目录
207
- - 文件格式: `reproto-YYYY-MM-DD-HH-MM-SS.log`
208
- - 使用 `--verbose` 参数查看详细处理过程
209
- - 🆕 性能统计和缓存监控信息
210
-
211
- ### 输出格式
212
- 生成的proto文件遵循Google Protobuf Style Guide:
213
- - 文件名:`snake_case.proto`
214
- - 字段名:`snake_case`
215
- - 消息名:`PascalCase`
216
- - 枚举值:`UPPER_SNAKE_CASE`
217
-
218
- ## 🔧 开发
219
-
220
- ```bash
221
- # 使用Poetry管理依赖
222
- poetry install
223
- poetry shell
224
-
225
- # 运行测试
226
- python main.py ../out_jadx/sources 'com.example.TestClass' ../test_output --verbose
227
-
228
- # 性能测试
229
- time python main.py ../out_jadx/sources com.truecaller.search.v1.models.SearchResult ../test_output
230
- ```
231
-
232
- ## 🐛 故障排除
233
-
234
- ### 常见问题
235
-
236
- 1. **文件找不到错误**
237
- ```bash
238
- # 确保JADX输出目录正确
239
- ls -la out_jadx/sources/com/example/
240
- ```
241
-
242
- 2. **内存不足**
243
- ```bash
244
- # 对于大型应用,增加Java堆内存
245
- export JAVA_OPTS="-Xmx4g"
246
- ```
247
-
248
- 3. **性能问题**
249
- ```bash
250
- # 查看缓存统计,确认没有重复I/O
251
- grep "缓存统计" logs/reproto-*.log
252
- ```
253
-
254
- ## 📊 支持的Protobuf特性
255
-
256
- | 特性 | 支持状态 | 示例 |
257
- |------|----------|------|
258
- | 基础类型 | ✅ 完整支持 | `string`, `int32`, `bool` |
259
- | 消息类型 | ✅ 完整支持 | `Contact`, `UserInfo` |
260
- | 枚举类型 | ✅ 完整支持 | `enum Status { ACTIVE = 0; }` |
261
- | repeated | ✅ 完整支持 | `repeated string tags` |
262
- | map | ✅ 完整支持 | `map<string, Contact> contacts` |
263
- | oneof | ✅ 完整支持 | `oneof data { ... }` |
264
- | 嵌套消息 | ✅ 完整支持 | `message Outer.Inner` |
265
- | Well-Known Types | ✅ 新增支持 | `google.protobuf.Timestamp` |
266
-
267
- ## 🎯 最新更新 (v2.0)
268
-
269
- ### 🚀 性能优化
270
- - 移除未使用的索引系统,提升执行效率20%+
271
- - 文件缓存系统,避免重复I/O操作
272
- - 智能路径构造,避免全目录扫描
273
- - 统一类型检测器,简化代码逻辑
274
-
275
- ### 🆕 新增功能
276
- - MapFieldLite自动转换为标准map语法
277
- - Internal.ProtobufList支持
278
- - Google Protobuf Well-Known Types支持
279
- - 增强的枚举解析器
280
- - 详细的性能监控和统计
281
-
282
- ### 🔧 技术改进
283
- - 代码复杂度显著降低
284
- - 内存使用优化
285
- - 错误处理增强
286
- - 日志系统改进
287
-
288
- ## 📄 许可证
289
-
290
- 本项目为私有项目,仅供授权用户使用。
291
-
292
- ---
293
-
294
- **�� 现在就体验20%+的性能提升!**
295
-