Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
A
appzxhy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wanglei
appzxhy
Commits
ef7b6034
Commit
ef7b6034
authored
Jun 27, 2025
by
wanglei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[打包]替换脚本
parent
1db89a5e
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
359 additions
and
25 deletions
+359
-25
test9.py
app/test9.py
+359
-25
No files found.
app/test9.py
View file @
ef7b6034
...
...
@@ -13,6 +13,10 @@ import regex as re2
# import chardet
import
string
import
random
import
nltk
import
sys
from
nltk.corpus
import
words
def
detect_encoding
(
file_path
):
...
...
@@ -300,9 +304,17 @@ def sub_map_text_impl(mapping, result, skip_type, skip_name, is_reverse=True, pa
reverse
=
sorted
(
list
(
mapping
.
keys
()),
key
=
len
,
reverse
=
is_reverse
)
text_result
=
text
# 遍历映射规则替换
for
name
in
reverse
:
text_result
=
re2
.
sub
(
str
(
name
),
mapping
[
name
],
text_result
)
patterns
=
sorted
(
mapping
.
keys
(),
key
=
len
,
reverse
=
is_reverse
)
for
pattern
in
patterns
:
try
:
print
(
f
"正在替换 pattern: {pattern}"
)
text_result
=
re
.
sub
(
pattern
,
mapping
[
pattern
],
text_result
)
except
Exception
as
e
:
print
(
f
"替换失败: pattern={pattern}, 错误: {e}"
)
# # 遍历映射规则替换
# for name in reverse:
# text_result = re2.sub(str(name), mapping[name], text_result)
# 方案 3:针对特定 import 的直接替换
text_result
=
re
.
sub
(
...
...
@@ -400,7 +412,8 @@ def check_class_mapping():
mapping
=
{}
classes
=
get_classes
()
for
i
in
classes
:
if
'_D'
in
i
or
os
.
path
.
basename
(
i
)
==
"GlobalConfig.kt"
:
# 跳过 GlobalConfig.kt
#or os.path.basename(i) == "GlobalConfig.kt" 去除跳过GlobalConfig
if
'_D'
in
i
:
# 跳过 GlobalConfig.kt
continue
print
(
i
)
name
=
os
.
path
.
basename
(
i
)
...
...
@@ -510,13 +523,65 @@ def deal_ids_type(ids_type):
sub_map
=
{}
for
i
in
type_ids_mapping
:
if
i
in
type_ids_mapping
and
type_ids_mapping
[
i
]
.
startswith
(
"android"
):
continue
# mapped = type_ids_mapping[i]
#
# sub_map['<' + ids_type + ' name="' + i + '"'] = '<' + ids_type + ' name="' + mapped + '"'
# sub_map['<item name="' + i + '"(.*? type="' + ids_type + '")>'] = '<item name="' + mapped + '"\\g<1>>'
# sub_map[r'(?<=[^\.])R\.' + ids_type + r'\.' + re.escape(i) + r'(?=\W)'] = 'R.' + ids_type + '.' + mapped
# sub_map[r'(?<=>|")@' + ids_type + '/' + re.escape(i) + r'(?=<|")'] = '@' + ids_type + '/' + mapped
# sub_map[r'(?<=[@=:])@' + ids_type + '/' + re.escape(i) + r'(?=[}"\'\s])'] = '@' + ids_type + '/' + mapped
#
# # ✅ DataBinding 表达式中所有 @xxx/yyy(包括拼接字符串等复杂表达式)
# sub_map[r'(?<=@{[^}]*?)@' + ids_type + r'/' + re.escape(i) + r'(?=[^}]*})'] = '@' + ids_type + '/' + mapped
#
# # ✅ <style name="..." parent="xxx"> 资源引用
# sub_map[r'<' + ids_type + r'(.*?) parent="' + re.escape(i) + r'"(.*?)>'] = (
# r'<' + ids_type + r'\g<1> parent="' + mapped + r'"\g<2>>'
# )
sub_map
[
'<'
+
ids_type
+
' name="'
+
i
+
'"'
]
=
'<'
+
ids_type
+
' name="'
+
type_ids_mapping
[
i
]
+
'"'
sub_map
[
'<item name="'
+
i
+
'"(.*? type="'
+
ids_type
+
'")>'
]
=
\
'<item name="'
+
type_ids_mapping
[
i
]
+
'"
\\
g<1>>'
sub_map
[
'<item name="'
+
i
+
'"(.*? type="'
+
ids_type
+
'")>'
]
=
'<item name="'
+
type_ids_mapping
[
i
]
+
'"
\\
g<1>>'
sub_map
[
'(?<=[^
\\
.])R
\\
.'
+
ids_type
+
'
\\
.'
+
i
+
'(?=
\\
W)'
]
=
'R.'
+
ids_type
+
'.'
+
type_ids_mapping
[
i
]
sub_map
[
'(?<=>|")@'
+
ids_type
+
'/'
+
i
+
'(?=<|")'
]
=
'@'
+
ids_type
+
'/'
+
type_ids_mapping
[
i
]
sub_map
[
'<'
+
ids_type
+
'(.*?) parent="'
+
i
+
'"(.*?)>'
]
=
\
'<'
+
ids_type
+
'
\\
g<1> parent="'
+
type_ids_mapping
[
i
]
+
'"
\\
g<2>>'
sub_map
[
r'(?<=[@=:])@'
+
ids_type
+
'/'
+
i
+
r'(?=[}"\'\s])'
]
=
'@'
+
ids_type
+
'/'
+
type_ids_mapping
[
i
]
sub_map
[
r'(?<=@{[^}]*?)@'
+
ids_type
+
r'/'
+
i
+
r'(?=[^}]*})'
]
=
'@'
+
ids_type
+
'/'
+
type_ids_mapping
[
i
]
# ⬅ 适配 data binding 表达式
sub_map
[
'<'
+
ids_type
+
'(.*?) parent="'
+
i
+
'"(.*?)>'
]
=
'<'
+
ids_type
+
'
\\
g<1> parent="'
+
\
type_ids_mapping
[
i
]
+
'"
\\
g<2>>'
escaped_i
=
re
.
escape
(
i
)
sub_map
[
rf
'(?<![a-zA-Z0-9_/])@{ids_type}/{escaped_i}(?![a-zA-Z0-9_])'
]
=
f
'@{ids_type}/{type_ids_mapping[i]}'
# 带包名前缀的资源路径 com.retrytech.ledgeapp.R.color.xxx
# sub_map[rf'(\b[\w\.]+)\.R\.{ids_type}\.{re.escape(i)}\b'] = rf'\1.R.{ids_type}.{type_ids_mapping[i]}'
# sub_map[
# rf'(?<!android\.)(\b[\w\.]+)\.R\.{ids_type}\.{re.escape(i)}\b'] = rf'\1.R.{ids_type}.{type_ids_mapping[i]}'
sub_map
[
rf
'(?<!
\b
android
\
.)
\b
([
\
w
\
.]+)
\
.R
\
.{ids_type}
\
.{re.escape(i)}
\b
'
]
=
rf
'
\1
.R.{ids_type}.{type_ids_mapping[i]}'
# ✅ 推荐的替换逻辑(万能适配 DataBinding 场景)
# sub_map[f'@{ids_type}/{i}'] = f'@{ids_type}/{type_ids_mapping[i]}'
# # ✅ 适配 DataBinding 表达式中包括拼接、三目等形式的字符串资源引用
# sub_map[rf'(?<=@{{[^}}]*?)@{ids_type}/{re.escape(i)}(?=[^}}]*}})'] = f'@{ids_type}/{type_ids_mapping[i]}'
# # DataBinding 表达式中字符串拼接,如:@{@string/subscribe_to+" "+@string/pro}
# sub_map[r'(?<=@{[^}]*?)@' + ids_type + r'/' + re.escape(i) + r'(?=[^}]*})'] = '@' + ids_type + '/' + \
# type_ids_mapping[i]
# sub_map['<' + ids_type + ' name="' + i + '"'] = '<' + ids_type + ' name="' + type_ids_mapping[i] + '"'
# sub_map['<item name="' + i + '"(.*? type="' + ids_type + '")>'] = \
# '<item name="' + type_ids_mapping[i] + '"\\g<1>>'
# sub_map['(?<=[^\\.])R\\.' + ids_type + '\\.' + i + '(?=\\W)'] = 'R.' + ids_type + '.' + type_ids_mapping[i]
# sub_map['(?<=>|")@' + ids_type + '/' + i + '(?=<|")'] = '@' + ids_type + '/' + type_ids_mapping[i]
# sub_map['(?<=[@=:])@' + ids_type + '/' + i + r'(?=[}"\'\s])'] = '@' + ids_type + '/' + type_ids_mapping[i]
# sub_map['<' + ids_type + '(.*?) parent="' + i + '"(.*?)>'] = \
# '<' + ids_type + '\\g<1> parent="' + type_ids_mapping[i] + '"\\g<2>>'
# # 匹配 @color/xxx 出现在 @{} 表达式中,适配 data binding 多种情况
# sub_map[r'(?<=@{[^}]*?)@' + ids_type + r'/' + i + r'(?=[^}]*})'] = '@' + ids_type + '/' + type_ids_mapping[i]
sub_map
[
rf
'android
\
.R
\
.color
\
.(
\
w+)'
]
=
lambda
m
:
'android.R.color.'
+
type_ids_mapping
.
get
(
m
.
group
(
1
),
m
.
group
(
1
))
sub_map_text
(
sub_map
)
...
...
@@ -675,7 +740,9 @@ def replace_package_in_imports(root_path, old_package, new_package):
patterns
=
[
(
re
.
compile
(
rf
'import {re.escape(old_package)}(
\
.databinding
\
.
\
w+)'
),
rf
'import {new_package}
\1
'
),
(
re
.
compile
(
rf
'import {re.escape(old_package)}
\
.R
\b
'
),
rf
'import {new_package}.R'
),
(
re
.
compile
(
rf
'import {re.escape(old_package)}
\
.BuildConfig'
),
rf
'import {new_package}.BuildConfig'
)
(
re
.
compile
(
rf
'import {re.escape(old_package)}
\
.BuildConfig'
),
rf
'import {new_package}.BuildConfig'
),
(
re
.
compile
(
rf
'{re.escape(old_package)}
\
.R
\b
'
),
rf
'{new_package}.R'
),
]
# 遍历目录中的所有文件
...
...
@@ -729,7 +796,6 @@ def replace_package_in_imports(root_path, old_package, new_package):
# return re.findall(class_pattern, text)
def
get_method_names
(
text
,
filename
):
"""
获取 Java 或 Kotlin 文件中的所有方法名
...
...
@@ -749,6 +815,7 @@ def get_method_names(text, filename):
# 匹配所有方法名
return
re
.
findall
(
method_pattern
,
text
)
def
get_variable_names
(
text
,
filename
):
"""
获取 Java 或 Kotlin 文件中的所有变量名
...
...
@@ -768,6 +835,7 @@ def get_variable_names(text, filename):
# 匹配所有变量名
return
re
.
findall
(
variable_pattern
,
text
)
def
get_file_names_without_extension
(
root_path
):
"""
获取所有 `.kt` 和 `.java` 文件的路径(无扩展名)
...
...
@@ -785,6 +853,7 @@ def get_file_names_without_extension(root_path):
# 存储每个文件名的映射关系
file_to_class_map
=
{}
def
get_constant_names
(
text
,
filename
):
"""
获取 Java 或 Kotlin 文件中的所有常量名
...
...
@@ -910,9 +979,6 @@ def replace_with_mapped_names(all_files, name_mapping, constant_mapping):
print
(
f
"文件 {file_path} 引用的名称已进行统一混淆处理。"
)
def
deal_code
():
print
(
"deal_code start"
)
# 替换点击事件
...
...
@@ -959,9 +1025,6 @@ def deal_code():
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
# 修改依赖
sub_map
=
{}
for
i
in
mapping
:
...
...
@@ -992,7 +1055,8 @@ def deal_code():
classes
=
get_classes
()
print
(
class_mapping
)
for
i
in
classes
:
if
'_D'
in
i
or
os
.
path
.
basename
(
i
)
==
"GlobalConfig.kt"
:
# 跳过 GlobalConfig.kt
#"or os.path.basename(i) == "GlobalConfig.kt" 去除跳过 GlobalConfig.kt
if
'_D'
in
i
:
continue
name
=
os
.
path
.
basename
(
i
)
name
=
name
[:
name
.
rfind
(
'.'
)]
...
...
@@ -1005,6 +1069,12 @@ def deal_code():
# 添加排除前缀 "styleable." 的逻辑
# 原规则匹配整个单词,添加排除前缀 "styleable." 的逻辑,并允许后面有引号的匹配
regex_pattern
=
r'(?<!")(?<!\bstyleable\.)\b'
+
i
+
r'\b'
if
'AppComponent'
in
class_mapping
:
obfuscated_name
=
class_mapping
[
'AppComponent'
]
dagger_pattern
=
rf
'(?<!")(?<!
\b
styleable
\
.)
\b
DaggerAppComponent
\b
'
sub_map
[
dagger_pattern
]
=
f
'Dagger{obfuscated_name}'
else
:
print
(
"⚠️ class_mapping 中没有 AppComponent,跳过 DaggerAppComponent 规则"
)
# 保持原有规则的匹配,优先处理非引号的情况
sub_map
[
regex_pattern
]
=
class_mapping
[
i
]
...
...
@@ -1012,7 +1082,6 @@ def deal_code():
sub_map_text
(
sub_map
)
print
(
"类名 over"
)
# 混淆字典
check_obfuscation_dictionary
()
print
(
root_path
)
...
...
@@ -1039,7 +1108,6 @@ def deal_code():
# # 第二步:替换其他文件中的引用,保证同样的混淆名
# replace_with_mapped_names(all_files, name_mapping, constant_mapping)
replace_package_in_imports
(
root_path
,
mapping
[
applicationId
],
applicationId
)
...
...
@@ -1079,8 +1147,45 @@ def deal_res_type(res_type):
sub_map
=
{}
for
i
in
type_mapping
:
sub_map
[
'R
\\
.'
+
res_type
+
'
\\
.'
+
i
+
'(
\\
W)'
]
=
'R.'
+
res_type
+
'.'
+
type_mapping
[
i
]
+
'
\\
g<1>'
sub_map
[
'(>|")@'
+
res_type
+
'/'
+
i
+
'(<|")'
]
=
'
\\
g<1>@'
+
res_type
+
'/'
+
type_mapping
[
i
]
+
'
\\
g<2>'
mapped
=
type_mapping
[
i
]
# 普通 R.xxx.xxx
sub_map
[
r'R\.'
+
res_type
+
r'\.'
+
re
.
escape
(
i
)
+
r'(\W)'
]
=
r'R.'
+
res_type
+
'.'
+
mapped
+
r'\1'
# # # 包名限定的 com.retrytech.ledgeapp.R.drawable.xxx
# sub_map[r'(\b[\w\.]+)\.R\.' + res_type + r'\.' + re.escape(
# i) + r'(\W)'] = r'\1.R.' + res_type + '.' + mapped + r'\2'
# sub_map[r'(\b[\w\.]+)\.R\.' + res_type + r'\.' + re.escape(
# i) + r'(?=[\s)\];,])'] = r'\1.R.' + res_type + '.' + mapped
# ✅ 推荐统一写法:以单词边界结尾,适配更多结尾符号(避免重复)
sub_map
[
rf
'(
\b
[
\
w
\
.]+)
\
.R
\
.{res_type}
\
.{re.escape(i)}
\b
'
]
=
rf
'
\1
.R.{res_type}.{mapped}'
# XML 资源:@drawable/xxx
sub_map
[
r'(>|")@'
+
res_type
+
r'/'
+
re
.
escape
(
i
)
+
r'(<|")'
]
=
r'\1@'
+
res_type
+
'/'
+
mapped
+
r'\2'
# DataBinding 表达式中:@{ condition ? @drawable/xxx :@drawable/yyy }
# # 匹配 ? 后的资源
# sub_map[r'(?<=\? *@' + res_type + r'\/)' + re.escape(i) + r'(?= *:)'] = mapped
# # 匹配 : 后的资源
# sub_map[r'(?<=: *@' + res_type + r'\/)' + re.escape(i) + r'(?= *})'] = mapped
# ? 后的资源
sub_map
[
r'(?<=\? *@'
+
res_type
+
r'/)'
+
re
.
escape
(
i
)
+
r'(?=\b)'
]
=
mapped
# : 后的资源
sub_map
[
r'(?<=: *@'
+
res_type
+
r'/)'
+
re
.
escape
(
i
)
+
r'(?=\b)'
]
=
mapped
# ✅ 通配 DataBinding 内的任意资源引用
sub_map
[
r'(@\{[^}]*?)@'
+
res_type
+
r'/'
+
re
.
escape
(
i
)
+
r'(?=[^}]*})'
]
=
r'\1@'
+
res_type
+
'/'
+
mapped
# 通用 DataBinding 表达式中任意位置(不拆三元)
# sub_map[r'(?<=@{[^}]*?)@' + res_type + r'/' + re.escape(i) + r'(?=[^}]*})'] = '@' + res_type + '/' + mapped
# sub_map['R\\.' + res_type + '\\.' + i + '(\\W)'] = 'R.' + res_type + '.' + type_mapping[i] + '\\g<1>'
# sub_map[
# r'(\b[\w\.]+)\.R\.' + res_type + r'\.' + i + r'(\W)'
# ] = r'\1.R.' + res_type + '.' + type_mapping[i] + r'\2'
#
# sub_map['(>|")@' + res_type + '/' + i + '(<|")'] = '\\g<1>@' + res_type + '/' + type_mapping[i] + '\\g<2>'
# # 适配 DataBinding 表达式中的 @drawable/xxx 写法
# sub_map[r'(?<=@{[^}]*?)@' + res_type + r'/' + i + r'(?=[^}]*})'] = '@' + res_type + '/' + type_mapping[i]
sub_map_text
(
sub_map
)
...
...
@@ -1478,7 +1583,7 @@ def deal_res():
'R.styleable.'
+
styleable_mapping
[
styleable_id
]
+
'_'
+
styleable_mapping
[
attr
+
'_A'
]
+
'
\\
g<1>'
sub_map
[
'app:'
+
attr
+
'='
]
=
'app:'
+
styleable_mapping
[
attr
+
'_A'
]
+
'='
sub_map
[
'
\\
?attr/'
+
attr
]
=
'?attr/'
+
styleable_mapping
[
attr
+
'_A'
]
# 新增的替换规则
sub_map
[
'<item name=
\"
'
+
attr
+
'
\"
'
]
=
'<item name=
\"
'
+
styleable_mapping
[
attr
+
'_A'
]
+
'
\"
'
# 新增的替换规则
sub_map
[
'<item name=
\"
'
+
attr
+
'
\"
'
]
=
'<item name=
\"
'
+
styleable_mapping
[
attr
+
'_A'
]
+
'
\"
'
# 新增的替换规则
# 判断 attr 是否以 "android:" 开头
if
attr
.
startswith
(
"android:"
):
new_attr
=
"android_"
+
attr
[
8
:]
# 去掉 "android:" 并替换为 "android_"
...
...
@@ -1500,9 +1605,28 @@ def deal_res():
sub_map
[
'(>|")@(
\\
+)?id/'
+
i
+
'(<|")'
]
=
'
\\
g<1>@
\\
g<2>id/'
+
view_ids_mapping
[
key
]
+
'
\\
g<3>'
sub_map
[
'R
\\
.id
\\
.'
+
i
+
'(
\\
W)'
]
=
'R.id.'
+
view_ids_mapping
[
key
]
+
'
\\
g<1>'
sub_map
[
'([bB]inding
\\
??(?:
\\
.
\\
w+)?
\\
??)
\\
.'
+
key
+
'(
\\
W)'
]
=
'
\\
g<1>.'
+
view_ids_mapping
[
key
]
+
'
\\
g<2>'
sub_map
[
'([bB]inding
\\
??(?:
\\
.
\\
w+)?
\\
??)
\\
.'
+
key
+
'
\\
.'
+
key
+
'(
\\
W)'
]
=
'
\\
g<1>.'
+
view_ids_mapping
[
key
]
+
'.'
+
view_ids_mapping
[
key
]
+
'
\\
g<2>'
sub_map
[
'([bB]inding
\\
??(?:
\\
.
\\
w+)?
\\
??)
\\
.'
+
key
+
'
\\
.'
+
key
+
'(
\\
W)'
]
=
'
\\
g<1>.'
+
view_ids_mapping
[
key
]
+
'.'
+
view_ids_mapping
[
key
]
+
'
\\
g<2>'
sub_map
[
r'\(binding as (\w+Binding)\)\.'
+
key
+
r'(\W)'
]
=
r'(binding as \1).'
+
view_ids_mapping
[
key
]
+
r'\2'
sub_map
[
'(?<=app:constraint_referenced_ids=".*?)'
+
i
+
'(?=.*?")'
]
=
view_ids_mapping
[
key
]
# 新增 Kotlin 特有写法适配
sub_map
[
r'(binding!!(?:\.\w+)*?)\.'
+
key
+
r'(\W)'
]
=
r'\1.'
+
view_ids_mapping
[
key
]
+
r'\2'
sub_map
[
r'(binding\?\?(?:\.\w+)*?)\.'
+
key
+
r'(\W)'
]
=
r'\1.'
+
view_ids_mapping
[
key
]
+
r'\2'
sub_map
[
r'(binding(?:\.\w+)*?)\.'
+
key
+
r'(\W)'
]
=
r'\1.'
+
view_ids_mapping
[
key
]
+
r'\2'
sub_map
[
'this
\\
.'
+
i
+
'(
\\
W)'
]
=
'this.'
+
view_ids_mapping
[
key
]
+
'
\\
g<1>'
sub_map
[
'this
\\
.'
+
i
+
'(
\\
.[
\\
w
\\
?]+(?:
\\
([^)]*
\\
))?)'
]
=
'this.'
+
view_ids_mapping
[
key
]
+
'
\\
g<1>'
# sub_map['this\\.(\\w+)(\\.[\\w\\?]+(?:\\([^)]*\\))?)'] = 'this.' + view_ids_mapping[key] + '\\g<1>\\g<2>'
sub_map
[
'popupView
\\
.'
+
i
+
'(
\\
W)'
]
=
'popupView.'
+
view_ids_mapping
[
key
]
+
'
\\
g<1>'
# sub_map['\\b' + i + '\\.(\\w+)(\\s*=\\s*[^\\s]+)'] = view_ids_mapping[key] + '.\\g<1>\\g<2>'
sub_map
[
'(?<!
\\
()
\\
b'
+
i
+
'
\\
.(
\\
w+)(
\\
s*=
\\
s*[^
\\
s]+)'
]
=
view_ids_mapping
[
key
]
+
'.
\\
g<1>
\\
g<2>'
# sub_map['this\\.' + view_ids_mapping['title']] = 'this.title'
if
i
==
'imgIcon'
:
sub_map
[
r'\.into\(\s*this\.(imgIcon)\s*\)'
]
=
r'.into(this.'
+
view_ids_mapping
[
key
]
+
')'
sub_map_text
(
sub_map
)
# 改 layout 文件名
...
...
@@ -1542,12 +1666,126 @@ def deal_res():
# 改图片内容
deal_image
()
# 主执行逻辑
mapping_file
=
"./mapping.json"
java_path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
mapping_data
=
load_color_mapping
(
mapping_file
)
# 调用正确的函数
# 调试信息:检查 color_ids_mapping 内容
print
(
"Color IDs Mapping:"
)
for
original_color
,
mapped_color
in
mapping_data
.
items
():
print
(
f
"{original_color}: {mapped_color}"
)
# 进行文件处理
process_color_files
(
java_path
,
mapping_data
)
def
process_color_files
(
src_path
,
color_ids
):
for
root
,
dirs
,
files
in
os
.
walk
(
src_path
):
for
file
in
files
:
if
file
.
endswith
(
".kt"
)
or
file
.
endswith
(
".java"
):
file_path
=
os
.
path
.
join
(
root
,
file
)
print
(
f
"Processing file: {file_path}"
)
replace_color_ids_in_file
(
file_path
,
color_ids
)
def
replace_color_ids_in_file
(
file_path
,
color_ids_mapping
):
print
(
"replace_color_ids_in_file"
)
print
(
color_ids_mapping
)
with
open
(
file_path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
content
=
f
.
read
()
if
"paperedto"
in
content
:
print
(
f
"Found 'paperedto' in: {file_path}"
)
if
"android.R.color.paperedto"
in
content
:
print
(
f
"Found 'android.R.color.paperedto' in: {file_path}"
)
changed
=
False
for
original_color
,
mapped_color
in
color_ids_mapping
.
items
():
print
(
'original_color'
+
original_color
)
print
(
'mapped_color'
+
mapped_color
)
if
mapped_color
in
content
:
pattern
=
r'android.R.color.'
+
re
.
escape
(
mapped_color
)
+
r'(?=[^\w])'
print
(
pattern
)
replacement
=
'android.R.color.'
+
original_color
print
(
replacement
)
if
re
.
search
(
pattern
,
content
):
print
(
f
"Matched: {mapped_color} → {original_color}"
)
matches
=
re
.
findall
(
pattern
,
content
)
if
matches
:
print
(
f
"Matched: {mapped_color} → {original_color} ({len(matches)} times)"
)
content
=
re
.
sub
(
pattern
,
replacement
,
content
)
changed
=
True
if
changed
:
with
open
(
file_path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
content
)
def
get_path
(
path
):
paths
=
path
.
split
(
'
\\
'
)
return
str
(
os
.
path
.
join
(
*
paths
))
def
deal_global
():
mapping_file_path
=
'mapping.json'
src_dir
=
'src/main/java'
# 加载映射文件
with
open
(
mapping_file_path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
mapping_data
=
json
.
load
(
f
)
class_mapping
=
mapping_data
.
get
(
"class"
,
{})
dir_mapping
=
mapping_data
.
get
(
"dir"
,
{})
# 获取混淆后的 GlobalConfig 文件名
obfuscated_name
=
class_mapping
.
get
(
"GlobalConfig"
)
if
not
obfuscated_name
:
print
(
"❌ GlobalConfig not found in class mapping."
)
return
obfuscated_filename
=
obfuscated_name
+
'.kt'
reversed_dir_mapping
=
{
v
:
k
for
k
,
v
in
dir_mapping
.
items
()}
found
=
False
for
root
,
dirs
,
files
in
os
.
walk
(
src_dir
):
if
obfuscated_filename
in
files
:
found
=
True
kt_file_path
=
os
.
path
.
join
(
root
,
obfuscated_filename
)
with
open
(
kt_file_path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
content
=
f
.
read
()
original_content
=
content
updated
=
False
# 精确匹配 PACKAGE_NAME 行
match
=
re
.
search
(
r'(const\s+val\s+PACKAGE_NAME\s*=\s*")([^"]+)(")'
,
content
)
if
match
:
current_package
=
match
.
group
(
2
)
for
obf_pkg
,
original_pkg
in
reversed_dir_mapping
.
items
():
if
current_package
.
startswith
(
obf_pkg
):
restored_package
=
current_package
.
replace
(
obf_pkg
,
original_pkg
,
1
)
new_line
=
f
'{match.group(1)}{restored_package}{match.group(3)}'
content
=
content
.
replace
(
match
.
group
(
0
),
new_line
)
print
(
f
"✅ Updated PACKAGE_NAME in {kt_file_path}: '{current_package}' → '{restored_package}'"
)
updated
=
True
break
else
:
print
(
f
"❌ PACKAGE_NAME not found in {kt_file_path}"
)
if
updated
and
content
!=
original_content
:
with
open
(
kt_file_path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
content
)
else
:
print
(
f
"ℹ️ No PACKAGE_NAME replacement needed in {kt_file_path}"
)
break
if
not
found
:
print
(
f
"❌ File {obfuscated_filename} not found under {src_dir}"
)
def
main
():
if
not
os
.
path
.
exists
(
get_path
(
'.
\\
src
\\
main
\\
java
\\
'
+
applicationId
[:
applicationId
.
find
(
'.'
)])):
print
(
get_path
(
'.
\\
src
\\
main
\\
java
\\
'
+
applicationId
[:
applicationId
.
find
(
'.'
)]))
...
...
@@ -1558,6 +1796,9 @@ def main():
deal_code
()
deal_global
()
def
load_mapping
(
file_path
):
"""加载 mapping.json 文件并打印内容."""
try
:
...
...
@@ -1570,6 +1811,7 @@ def load_mapping(file_path):
print
(
f
"Error loading mapping file: {e}"
)
return
{}
def
replace_identifiers_in_file
(
file_path
,
mapping
,
replacements_log
):
"""替换单个文件中的标识符,并存储替换的内容到 JSON 日志."""
with
open
(
file_path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
...
...
@@ -1647,6 +1889,7 @@ def replace_identifiers_in_file(file_path, mapping, replacements_log):
else
:
print
(
"No replacements made."
)
def
process_files_in_directory
(
directory
,
mapping
,
replacements_log
):
"""处理目录下的所有文件并打印文件路径."""
for
root
,
_
,
files
in
os
.
walk
(
directory
):
...
...
@@ -1682,13 +1925,104 @@ def solve_runapplyalso():
json
.
dump
(
replacements_log
,
log
,
ensure_ascii
=
False
,
indent
=
4
)
print
(
f
"
\n
Replacement completed. Log saved to {log_file}."
)
def
load_color_mapping
(
file_path
):
"""加载 mapping.json 文件并打印内容."""
try
:
with
open
(
file_path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
data
=
json
.
load
(
f
)
print
(
"Loaded color Mapping:"
)
print
(
json
.
dumps
(
data
,
indent
=
4
,
ensure_ascii
=
False
))
# 打印映射内容
color_ids
=
data
.
get
(
"color_ids"
,
{})
print
(
f
"color_ids extracted: {color_ids}"
)
# 检查 color_ids 是否存在
return
color_ids
except
(
FileNotFoundError
,
json
.
JSONDecodeError
)
as
e
:
print
(
f
"Error loading mapping file: {e}"
)
return
{}
# 自动下载 NLTK 的 "words" 数据包(只下载一次)
try
:
nltk
.
data
.
find
(
"corpora/words"
)
except
LookupError
:
print
(
"🔄 正在下载 NLTK 'words' 数据集..."
)
nltk
.
download
(
"words"
)
# 获取当前目录(兼容 PyInstaller 打包)
if
getattr
(
sys
,
'frozen'
,
False
):
base_dir
=
os
.
path
.
dirname
(
sys
.
executable
)
else
:
base_dir
=
os
.
path
.
abspath
(
os
.
path
.
dirname
(
__file__
))
mapping_path
=
os
.
path
.
join
(
base_dir
,
"mapping.json"
)
word_file_path
=
os
.
path
.
join
(
base_dir
,
"word_file.json"
)
# 是否需要生成 word_file.json
need_generate
=
True
if
os
.
path
.
exists
(
mapping_path
):
print
(
"✅ 已存在 mapping.json,跳过生成 word_file.json。"
)
need_generate
=
False
else
:
print
(
"✅ 不存在 mapping.json,将生成 word_file.json。"
)
# 删除旧的 word_file.json(若存在)
if
os
.
path
.
exists
(
word_file_path
):
try
:
os
.
remove
(
word_file_path
)
print
(
"🗑️ 已删除旧的 word_file.json"
)
except
Exception
as
e
:
print
(
f
"❌ 删除旧文件失败:{e}"
)
sys
.
exit
(
1
)
# Kotlin + Java 保留关键字(统一为小写)
kotlin_java_keywords
=
{
kw
.
lower
()
for
kw
in
{
'as'
,
'as?'
,
'break'
,
'class'
,
'continue'
,
'do'
,
'else'
,
'false'
,
'for'
,
'fun'
,
'if'
,
'in'
,
'!in'
,
'interface'
,
'is'
,
'!is'
,
'null'
,
'object'
,
'package'
,
'return'
,
'super'
,
'this'
,
'throw'
,
'true'
,
'try'
,
'typealias'
,
'typeof'
,
'val'
,
'var'
,
'when'
,
'while'
,
'by'
,
'catch'
,
'constructor'
,
'delegate'
,
'dynamic'
,
'field'
,
'file'
,
'finally'
,
'get'
,
'import'
,
'init'
,
'param'
,
'property'
,
'receiver'
,
'set'
,
'setparam'
,
'where'
,
'actual'
,
'abstract'
,
'annotation'
,
'companion'
,
'const'
,
'crossinline'
,
'data'
,
'enum'
,
'expect'
,
'external'
,
'final'
,
'infix'
,
'inline'
,
'inner'
,
'internal'
,
'lateinit'
,
'noinline'
,
'open'
,
'operator'
,
'out'
,
'override'
,
'private'
,
'protected'
,
'public'
,
'reified'
,
'sealed'
,
'suspend'
,
'tailrec'
,
'vararg'
,
'assert'
,
'boolean'
,
'byte'
,
'case'
,
'char'
,
'default'
,
'double'
,
'extends'
,
'float'
,
'goto'
,
'implements'
,
'instanceof'
,
'int'
,
'long'
,
'native'
,
'new'
,
'short'
,
'static'
,
'strictfp'
,
'switch'
,
'synchronized'
,
'throws'
,
'transient'
,
'void'
,
'volatile'
}
}
def
generate_and_save
():
sample_size
=
10000
sampled
=
random
.
sample
(
word_list
,
min
(
sample_size
,
len
(
word_list
)))
filtered
=
[
w
.
lower
()
for
w
in
sampled
if
w
.
lower
()
not
in
kotlin_java_keywords
]
with
open
(
word_file_path
,
"w"
,
encoding
=
"utf-8"
)
as
f
:
json
.
dump
({
"word"
:
filtered
},
f
,
ensure_ascii
=
False
,
indent
=
4
)
print
(
f
"✅ 成功生成 {len(filtered)} 个小写英文单词!"
)
print
(
f
"📄 文件保存至:{word_file_path}"
)
if
__name__
==
'__main__'
:
if
need_generate
:
# 加载 NLTK 单词列表并生成
try
:
word_list
=
list
(
set
(
words
.
words
()))
except
Exception
as
e
:
print
(
f
"❌ 加载 NLTK 词库失败:{e}"
)
sys
.
exit
(
1
)
generate_and_save
()
# 继续执行 gradle 文件查找逻辑
if
os
.
path
.
exists
(
'build.gradle'
):
gradle_path
=
'build.gradle'
elif
os
.
path
.
exists
(
'build.gradle.kts'
):
gradle_path
=
'build.gradle.kts'
else
:
exit
(
'找不到 build.gradle 文件'
)
exit
(
'❌ 找不到 build.gradle 文件'
)
print
(
f
"✅ 找到构建文件:{gradle_path}"
)
applicationId
=
re
.
search
(
'namespace .*?["
\'
](.*?)["
\'
]'
,
open
(
gradle_path
,
'r'
,
encoding
=
'utf-8'
)
.
read
())[
1
]
print
(
applicationId
)
main
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment