pindo 5.10.6 → 5.10.8

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/funlog.rb +12 -1
  3. data/lib/pindo/base/pindocontext.rb +3 -0
  4. data/lib/pindo/command/android/autobuild.rb +62 -9
  5. data/lib/pindo/command/android/build.rb +6 -6
  6. data/lib/pindo/command/android/debug.rb +9 -9
  7. data/lib/pindo/command/deploy/build.rb +2 -4
  8. data/lib/pindo/command/deploy/cert.rb +4 -5
  9. data/lib/pindo/command/deploy/configproj.rb +3 -3
  10. data/lib/pindo/command/deploy/confusecode.rb +1 -1
  11. data/lib/pindo/command/deploy/confuseproj.rb +1 -1
  12. data/lib/pindo/command/deploy/pem.rb +3 -4
  13. data/lib/pindo/command/dev/autobuild.rb +1 -1
  14. data/lib/pindo/command/dev/build.rb +1 -1
  15. data/lib/pindo/command/dev/feishu.rb +1 -1
  16. data/lib/pindo/command/gplay/pullconfig.rb +48 -0
  17. data/lib/pindo/command/gplay.rb +6 -5
  18. data/lib/pindo/command/ios/adhoc.rb +6 -5
  19. data/lib/pindo/command/ios/autobuild.rb +24 -24
  20. data/lib/pindo/command/ios/build.rb +7 -6
  21. data/lib/pindo/command/ios/debug.rb +1 -0
  22. data/lib/pindo/command/ipa/import.rb +2 -3
  23. data/lib/pindo/command/ipa/output.rb +2 -3
  24. data/lib/pindo/command/jps/upload.rb +6 -5
  25. data/lib/pindo/command/unity/apk.rb +19 -2
  26. data/lib/pindo/command/unity/autobuild.rb +58 -63
  27. data/lib/pindo/command/unity/initpack.rb +1 -1
  28. data/lib/pindo/command/unity/ipa.rb +17 -14
  29. data/lib/pindo/command/unity/pack.rb +1 -1
  30. data/lib/pindo/command/unity/upload.rb +1 -1
  31. data/lib/pindo/command/unity/web.rb +2 -2
  32. data/lib/pindo/command/utils/icon.rb +1 -1
  33. data/lib/pindo/command/utils/renewcert.rb +1 -2
  34. data/lib/pindo/command/utils/renewproj.rb +9 -10
  35. data/lib/pindo/command/web/autobuild.rb +2 -2
  36. data/lib/pindo/command/web/run.rb +1 -1
  37. data/lib/pindo/command.rb +2 -1
  38. data/lib/pindo/module/android/android_build_config_helper.rb +267 -35
  39. data/lib/pindo/module/android/android_build_helper.rb +300 -0
  40. data/lib/pindo/module/android/android_project_helper.rb +279 -0
  41. data/lib/pindo/module/android/gp_compliance_helper.rb +33 -87
  42. data/lib/pindo/module/android/gradle_helper.rb +524 -255
  43. data/lib/pindo/module/android/java_env_helper.rb +633 -0
  44. data/lib/pindo/module/android/keystore_helper.rb +1118 -0
  45. data/lib/pindo/module/appselect.rb +109 -0
  46. data/lib/pindo/module/appstore/appstore_in_app_purchase.rb +1 -1
  47. data/lib/pindo/module/build/{buildhelper.rb → build_helper.rb} +1 -2
  48. data/lib/pindo/module/build/{commonconfuseproj.rb → confuse_xcodeproj.rb} +2 -2
  49. data/lib/pindo/module/cert/cert_helper.rb +245 -0
  50. data/lib/pindo/module/cert/keychain_helper.rb +152 -0
  51. data/lib/pindo/module/cert/pem_helper.rb +67 -0
  52. data/lib/pindo/module/cert/xcodecerthelper.rb +2 -2
  53. data/lib/pindo/module/{build/unityhelper.rb → unity/unity_helper.rb} +0 -17
  54. data/lib/pindo/module/xcode/{xcodereshandler.rb → res/xcode_res_handler.rb} +1 -1
  55. data/lib/pindo/module/xcode/{xcodebuildconfig.rb → xcode_build_config.rb} +7 -6
  56. data/lib/pindo/module/xcode/{xcodebuildhelper.rb → xcode_build_helper.rb} +4 -3
  57. data/lib/pindo/module/xcode/{xcodehelper.rb → xcode_project_helper.rb} +4 -2
  58. data/lib/pindo/module/xcode/{xcodereshelper.rb → xcode_res_helper.rb} +12 -9
  59. data/lib/pindo/version.rb +185 -7
  60. data/lib/pindo.rb +14 -9
  61. metadata +24 -23
  62. data/lib/pindo/module/android/apk_helper.rb +0 -138
  63. data/lib/pindo/module/android/base_helper.rb +0 -964
  64. data/lib/pindo/module/android/build_helper.rb +0 -128
  65. data/lib/pindo/module/android/so_helper.rb +0 -18
  66. data/lib/pindo/module/cert/certhelper.rb +0 -246
  67. data/lib/pindo/module/cert/keychainhelper.rb +0 -150
  68. data/lib/pindo/module/cert/pemhelper.rb +0 -65
  69. /data/lib/pindo/module/android/{androidreshelper.rb → android_res_helper.rb} +0 -0
  70. /data/lib/pindo/module/appstore/{iap_tier.json → appstore_iap_tier.json} +0 -0
  71. /data/lib/pindo/module/build/{swarkhelper.rb → swark_helper.rb} +0 -0
  72. /data/lib/pindo/module/build/{versionhelper.rb → version_helper.rb} +0 -0
  73. /data/lib/pindo/module/cert/{provisioninghelper.rb → provisioning_helper.rb} +0 -0
  74. /data/lib/pindo/module/unity/{nugethelper.rb → nuget_helper.rb} +0 -0
  75. /data/lib/pindo/module/xcode/{xcoderesconstant.rb → res/xcode_res_constant.rb} +0 -0
@@ -1,296 +1,565 @@
1
- require_relative 'base_helper'
1
+ require_relative 'android_project_helper'
2
2
  require 'net/http'
3
3
  require 'uri'
4
4
  require 'zip'
5
+ require_relative '../../base/funlog'
5
6
 
6
7
  module Pindo
7
- module GradleHelper
8
- include BaseAndroidHelper
9
-
10
-
11
- # Gradle缓存目录
12
- GRADLE_CACHE_DIR = File.expand_path("~/.pindo/pindo_common_config/android_tools/gradle-cache")
13
-
14
- def check_gradle_files(project_path)
15
- puts "\e[36m=== 检查Gradle Wrapper配置 ===\e[0m"
16
-
17
- # 使用基于gradle-wrapper.properties的自动配置
18
- if File.exist?(File.join(project_path, "gradle/wrapper/gradle-wrapper.properties"))
19
- puts "检测到gradle-wrapper.properties文件,使用自动配置..."
20
- if setup_gradle_wrapper_from_properties(project_path)
21
- puts "\e[32m✓ 基于gradle-wrapper.properties的自动配置成功\e[0m"
22
- return true
8
+ class GradleHelper
9
+ class << self
10
+
11
+ # Gradle缓存目录
12
+ GRADLE_CACHE_DIR = File.expand_path("~/.pindo/android_tools/gradle-cache")
13
+
14
+ # Gradle 插件版本映射表(AGP版本映射)
15
+ # 仅升级旧版本到 4.2.2,不降级新版本
16
+ GRADLE_PLUGIN_VERSION_MAP = {
17
+ # 旧版本升级到 4.2.2
18
+ '3.4.0' => '4.2.2',
19
+ '3.4.1' => '4.2.2',
20
+ '3.5.0' => '4.2.2',
21
+ '3.5.1' => '4.2.2',
22
+ '3.6.0' => '4.2.2',
23
+ '3.6.1' => '4.2.2',
24
+ '4.0.0' => '4.2.2',
25
+ '4.0.1' => '4.2.2',
26
+ '4.1.0' => '4.2.2',
27
+ '4.2.0' => '4.2.2',
28
+ '4.2.1' => '4.2.2',
29
+ '4.2.2' => '4.2.2' # 保持当前版本
30
+ }
31
+
32
+ # =================== 公共方法 ===================
33
+
34
+ # 获取项目的 Gradle 配置路径(统一管理三种工程结构的路径)
35
+ # @param project_path [String] 项目路径
36
+ # @return [Hash] 包含各种路径信息和项目类型
37
+ def get_gradle_paths(project_path)
38
+ paths = {}
39
+
40
+ if Pindo::AndroidProjectHelper.unity_android_project?(project_path)
41
+ # Unity 独立工程
42
+ paths[:type] = :unity_standalone
43
+ paths[:gradle_dir] = project_path
44
+ paths[:wrapper_properties] = File.join(project_path, "gradle/wrapper/gradle-wrapper.properties")
45
+ paths[:build_gradle] = File.join(project_path, "build.gradle")
46
+ paths[:build_gradle_kts] = File.join(project_path, "build.gradle.kts")
47
+
48
+ elsif Pindo::AndroidProjectHelper.unity_as_lib_android_project?(project_path)
49
+ # Unity 作为 lib 的原生工程 - 需要处理两套配置
50
+ paths[:type] = :unity_as_lib
51
+
52
+ # Unity 模块的路径
53
+ paths[:unity_gradle_dir] = File.join(project_path, "Unity")
54
+ paths[:unity_wrapper_properties] = File.join(project_path, "Unity/gradle/wrapper/gradle-wrapper.properties")
55
+ paths[:unity_build_gradle] = File.join(project_path, "Unity/build.gradle")
56
+ paths[:unity_build_gradle_kts] = File.join(project_path, "Unity/build.gradle.kts")
57
+
58
+ # 主工程的路径
59
+ paths[:main_gradle_dir] = project_path
60
+ paths[:main_wrapper_properties] = File.join(project_path, "gradle/wrapper/gradle-wrapper.properties")
61
+ paths[:main_build_gradle] = File.join(project_path, "build.gradle")
62
+ paths[:main_build_gradle_kts] = File.join(project_path, "build.gradle.kts")
63
+
64
+ # 保留原有路径以兼容其他代码
65
+ paths[:gradle_dir] = paths[:unity_gradle_dir]
66
+ paths[:wrapper_properties] = paths[:unity_wrapper_properties]
67
+ paths[:build_gradle] = paths[:unity_build_gradle]
68
+ paths[:build_gradle_kts] = paths[:unity_build_gradle_kts]
69
+
23
70
  else
24
- puts "\e[31m✗ 自动配置失败\e[0m"
25
- return false
71
+ # Android 原生工程
72
+ paths[:type] = :native_android
73
+ paths[:gradle_dir] = project_path
74
+ paths[:wrapper_properties] = File.join(project_path, "gradle/wrapper/gradle-wrapper.properties")
75
+ paths[:build_gradle] = File.join(project_path, "build.gradle")
76
+ paths[:build_gradle_kts] = File.join(project_path, "build.gradle.kts")
26
77
  end
27
- else
28
- puts "\e[31m✗ 未找到gradle-wrapper.properties文件\e[0m"
29
- return false
30
- end
31
- end
32
-
33
-
34
- def update_build_gradle(project_path)
35
- # 更新build.gradle 或 build.gradle.kts
36
- build_gradle_path = File.join(project_path, "build.gradle")
37
- build_gradle_kts_path = File.join(project_path, "build.gradle.kts")
38
-
39
- # 优先使用 build.gradle.kts,如果不存在则使用 build.gradle
40
- if File.exist?(build_gradle_kts_path)
41
- build_gradle_path = build_gradle_kts_path
42
- elsif !File.exist?(build_gradle_path)
43
- return
44
- end
45
-
46
- content = File.read(build_gradle_path)
47
- content.gsub!("classpath 'com.android.tools.build:gradle:4.0.1'",
48
- "classpath 'com.android.tools.build:gradle:4.2.2'")
49
- File.write(build_gradle_path, content)
50
- end
51
-
52
- def update_gradle_version(project_path)
53
- # 直接调用setup_gradle_wrapper_from_properties,功能相同
54
- setup_gradle_wrapper_from_properties(project_path)
55
- end
56
-
57
- # 基于gradle-wrapper.properties自动配置gradle工具
58
- def setup_gradle_wrapper_from_properties(project_path)
59
- wrapper_properties_path = File.join(project_path, "gradle/wrapper/gradle-wrapper.properties")
60
-
61
- unless File.exist?(wrapper_properties_path)
62
- puts "\e[33m⚠ 未找到gradle-wrapper.properties文件: #{wrapper_properties_path}\e[0m"
63
- return false
64
- end
65
78
 
66
- # 解析gradle-wrapper.properties文件
67
- gradle_version = parse_gradle_version(wrapper_properties_path)
68
- if gradle_version.nil?
69
- puts "\e[31m✗ 无法解析gradle版本\e[0m"
70
- return false
79
+ paths
71
80
  end
72
81
 
73
- puts "\e[36m=== 自动配置Gradle Wrapper ===\e[0m"
74
- puts "检测到Gradle版本: #{gradle_version}"
82
+ # =================== 核心功能 ===================
83
+
84
+ def check_gradle_with_project(project_path, configure_main: false)
85
+ Funlog.fancyinfo_start("检查Gradle Wrapper配置")
86
+
87
+ # 使用统一的路径获取方法
88
+ paths = get_gradle_paths(project_path)
89
+
90
+ if paths[:type] == :unity_as_lib
91
+ if configure_main
92
+ # 配置主工程的 Gradle(在 SO 编译完成后调用)
93
+ Funlog.info("配置主工程的Gradle Wrapper用于编译APK...")
94
+
95
+ unless File.exist?(paths[:main_wrapper_properties])
96
+ Funlog.fancyinfo_error("未找到主工程的gradle-wrapper.properties: #{paths[:main_wrapper_properties]}")
97
+ return false
98
+ end
99
+
100
+ main_gradle_version = extract_gradle_version(paths[:main_wrapper_properties])
101
+ Funlog.info("主工程Gradle版本: #{main_gradle_version}")
102
+
103
+ # 确保主工程的 Gradle 缓存存在
104
+ unless ensure_gradle_available(main_gradle_version)
105
+ Funlog.fancyinfo_error("无法获取主工程的Gradle #{main_gradle_version}")
106
+ return false
107
+ end
108
+
109
+ # 配置主工程的 Gradle Wrapper
110
+ unless setup_gradle_wrapper(paths[:main_gradle_dir], paths[:main_wrapper_properties])
111
+ Funlog.fancyinfo_error("主工程Gradle Wrapper配置失败")
112
+ return false
113
+ end
75
114
 
76
- # 改进的wrapper生成策略:优先使用官方Gradle命令
77
- if setup_gradle_wrapper_improved(project_path, gradle_version)
78
- puts "\e[32m✓ Gradle Wrapper配置完成\e[0m"
79
- return true
80
- else
81
- puts "\e[31m✗ Gradle Wrapper配置失败\e[0m"
82
- return false
115
+ Funlog.fancyinfo_success("主工程Gradle配置完成,准备编译APK")
116
+ true
117
+ else
118
+ # 配置 Unity 模块的 Gradle(默认行为,在 SO 编译前调用)
119
+ Funlog.info("检测到 Unity as lib 工程,配置Unity模块的Gradle")
120
+
121
+ # 1. 配置 Unity 模块的 Gradle(7.5.1 + Java 11,用于编译SO库)
122
+ unless File.exist?(paths[:unity_wrapper_properties])
123
+ Funlog.fancyinfo_error("未找到Unity模块的gradle-wrapper.properties: #{paths[:unity_wrapper_properties]}")
124
+ return false
125
+ end
126
+
127
+ unity_gradle_version = extract_gradle_version(paths[:unity_wrapper_properties])
128
+ Funlog.info("配置Unity模块的Gradle Wrapper (版本: #{unity_gradle_version})...")
129
+ unless setup_gradle_wrapper(paths[:unity_gradle_dir], paths[:unity_wrapper_properties])
130
+ Funlog.fancyinfo_error("Unity模块Gradle Wrapper配置失败")
131
+ return false
132
+ end
133
+
134
+ # 2. 检查主工程的 Gradle 配置文件是否存在
135
+ unless File.exist?(paths[:main_wrapper_properties])
136
+ Funlog.fancyinfo_error("未找到主工程的gradle-wrapper.properties: #{paths[:main_wrapper_properties]}")
137
+ return false
138
+ end
139
+
140
+ main_gradle_version = extract_gradle_version(paths[:main_wrapper_properties])
141
+ Funlog.info("主工程Gradle配置 (版本: #{main_gradle_version}),待SO编译完成后配置")
142
+
143
+ # 确保主工程的 Gradle 缓存存在
144
+ unless ensure_gradle_available(main_gradle_version)
145
+ Funlog.info("下载主工程所需的Gradle #{main_gradle_version}...")
146
+ end
147
+
148
+ Funlog.info("Unity模块: Gradle #{unity_gradle_version} + Java 11 (编译SO库)")
149
+ Funlog.info("主工程: Gradle #{main_gradle_version} + Java 17 (编译APK)")
150
+ Funlog.fancyinfo_success("Unity模块Gradle配置完成,准备编译SO库")
151
+ true
152
+ end
153
+ else
154
+ # Unity standalone 或原生 Android 工程:只配置一个 Gradle
155
+ unless File.exist?(paths[:wrapper_properties])
156
+ Funlog.fancyinfo_error("未找到gradle-wrapper.properties文件: #{paths[:wrapper_properties]}")
157
+ return false
158
+ end
159
+
160
+ if setup_gradle_wrapper(paths[:gradle_dir], paths[:wrapper_properties])
161
+ Funlog.fancyinfo_success("Gradle Wrapper配置成功")
162
+ true
163
+ else
164
+ Funlog.fancyinfo_error("Gradle Wrapper配置失败")
165
+ false
166
+ end
167
+ end
83
168
  end
84
- end
85
169
 
86
170
 
87
- private
171
+ def update_build_gradle(project_path)
172
+ paths = get_gradle_paths(project_path)
173
+
174
+ if paths[:type] == :unity_as_lib
175
+ # Unity as lib 工程:只更新 Unity 模块的 build.gradle
176
+ # 主工程的 AGP 保持原版本(如 8.8.0),因为它使用独立的 Gradle 8.10.2
177
+ Funlog.info("检测到 Unity as lib 工程,仅更新Unity模块的AGP版本")
88
178
 
89
- # 解析gradle版本
90
- def parse_gradle_version(properties_path)
91
- content = File.read(properties_path)
92
-
93
- # 匹配distributionUrl中的gradle版本
94
- if content =~ /distributionUrl=.*gradle-(\d+\.\d+(?:\.\d+)?(?:-.*)?)-bin\.zip/
95
- return $1
179
+ # 更新 Unity 模块的 build.gradle(根据映射表更新旧版本)
180
+ if paths[:unity_build_gradle] || paths[:unity_build_gradle_kts]
181
+ Funlog.info("更新Unity模块的build.gradle...")
182
+ update_single_build_gradle(paths[:unity_build_gradle], paths[:unity_build_gradle_kts])
183
+ end
184
+
185
+ Funlog.info("Unity模块的AGP版本更新完成(主工程保持原版本)")
186
+ else
187
+ # Unity standalone 或原生 Android 工程:只更新一个 build.gradle
188
+ update_single_build_gradle(paths[:build_gradle], paths[:build_gradle_kts])
189
+ end
96
190
  end
97
-
98
- # 匹配gradleVersion属性
99
- if content =~ /gradleVersion=(\d+\.\d+(?:\.\d+)?(?:-.*)?)/
100
- return $1
191
+
192
+ # 设置 Gradle Wrapper(简化后的核心函数)
193
+ def setup_gradle_wrapper(gradle_dir, wrapper_properties_path)
194
+ # 解析gradle版本
195
+ gradle_version = parse_gradle_version(wrapper_properties_path)
196
+ if gradle_version.nil?
197
+ Funlog.error("无法解析gradle版本")
198
+ return false
199
+ end
200
+
201
+ # 下载并设置 Gradle
202
+ unless ensure_gradle_available(gradle_version)
203
+ Funlog.error("无法获取 Gradle #{gradle_version}")
204
+ return false
205
+ end
206
+
207
+ # 生成 Wrapper
208
+ generate_gradle_wrapper(gradle_dir, gradle_version)
101
209
  end
102
-
103
- nil
104
- end
105
-
106
-
107
- # 简化的Gradle Wrapper生成策略
108
- def setup_gradle_wrapper_improved(project_path, gradle_version)
109
- puts "\e[36m=== Gradle Wrapper生成策略 ===\e[0m"
110
-
111
- # 直接下载并设置项目对应的Gradle环境
112
- if download_and_setup_gradle(gradle_version)
113
- return generate_gradle_wrapper_official(project_path, gradle_version)
210
+
211
+ # 解析gradle版本
212
+ def parse_gradle_version(properties_path)
213
+ content = File.read(properties_path)
214
+
215
+ # 匹配distributionUrl中的gradle版本
216
+ if content =~ /distributionUrl=.*gradle-(\d+\.\d+(?:\.\d+)?(?:-.*)?)-bin\.zip/
217
+ return $1
218
+ end
219
+
220
+ # 匹配gradleVersion属性
221
+ if content =~ /gradleVersion=(\d+\.\d+(?:\.\d+)?(?:-.*)?)/
222
+ return $1
223
+ end
224
+
225
+ nil
114
226
  end
115
-
116
- puts "\e[31m✗ 无法获取有效的Gradle环境\e[0m"
117
- false
118
- end
119
-
120
-
121
-
122
- # 下载并设置Gradle环境
123
- def download_and_setup_gradle(gradle_version)
124
- puts "下载并设置Gradle #{gradle_version}环境..."
125
-
126
- # 确保缓存目录存在
127
- FileUtils.mkdir_p(GRADLE_CACHE_DIR)
128
-
129
- # 检查是否已解压
130
- gradle_home = File.join(GRADLE_CACHE_DIR, "gradle-#{gradle_version}")
131
- gradle_bin = File.join(gradle_home, "bin/gradle")
132
-
133
- if File.exist?(gradle_bin)
134
- puts "✓ 使用已解压的Gradle #{gradle_version}"
135
- setup_gradle_environment(gradle_home)
136
- return true
227
+
228
+ # 提取 gradle 版本(parse_gradle_version 的别名)
229
+ def extract_gradle_version(properties_path)
230
+ parse_gradle_version(properties_path)
137
231
  end
138
-
139
- # 下载Gradle分发包
140
- if download_gradle_distribution(gradle_version)
141
- setup_gradle_environment(gradle_home)
142
- return true
232
+
233
+ # 使用指定版本设置 Gradle Wrapper
234
+ def setup_gradle_wrapper_with_version(gradle_dir, wrapper_properties_path, gradle_version)
235
+ if gradle_version.nil?
236
+ Funlog.error("Gradle版本不能为空")
237
+ return false
238
+ end
239
+
240
+ # 下载并设置 Gradle
241
+ unless ensure_gradle_available(gradle_version)
242
+ Funlog.error("无法获取 Gradle #{gradle_version}")
243
+ return false
244
+ end
245
+
246
+ # 生成 Wrapper
247
+ generate_gradle_wrapper(gradle_dir, gradle_version)
143
248
  end
144
-
145
- false
146
- end
147
-
148
- # 下载Gradle分发包
149
- def download_gradle_distribution(gradle_version)
150
- puts "下载Gradle #{gradle_version}分发包..."
151
-
152
- distribution_url = "https://services.gradle.org/distributions/gradle-#{gradle_version}-bin.zip"
153
- cache_file = File.join(GRADLE_CACHE_DIR, "gradle-#{gradle_version}-bin.zip")
154
- extract_dir = File.join(GRADLE_CACHE_DIR, "gradle-#{gradle_version}")
155
-
156
- # 如果已存在ZIP文件,先检查完整性
157
- if File.exist?(cache_file)
158
- puts "✓ 发现缓存的Gradle分发包"
159
- if verify_zip_integrity(cache_file)
160
- puts "✓ 缓存文件完整性验证通过"
161
- return extract_gradle_distribution(cache_file, extract_dir, gradle_version)
249
+
250
+ # =================== 私有辅助方法 ===================
251
+
252
+ private
253
+
254
+ # 更新单个 build.gradle 文件
255
+ def update_single_build_gradle(gradle_path, gradle_kts_path)
256
+ # 优先使用 .kts 文件
257
+ target_file = if File.exist?(gradle_kts_path)
258
+ gradle_kts_path
259
+ elsif File.exist?(gradle_path)
260
+ gradle_path
162
261
  else
163
- puts " 缓存文件损坏,重新下载"
164
- FileUtils.rm_f(cache_file)
262
+ Funlog.info("未找到build.gradle文件: #{gradle_path} 或 #{gradle_kts_path}")
263
+ return
264
+ end
265
+
266
+ Funlog.info("检查AGP版本: #{File.basename(target_file)}")
267
+ content = File.read(target_file)
268
+ updated = false
269
+ found_version = nil
270
+ target_version = nil
271
+
272
+ GRADLE_PLUGIN_VERSION_MAP.each do |old_version, new_version|
273
+ next if old_version == new_version
274
+
275
+ # Groovy 格式
276
+ if content.gsub!("classpath 'com.android.tools.build:gradle:#{old_version}'",
277
+ "classpath 'com.android.tools.build:gradle:#{new_version}'")
278
+ updated = true
279
+ found_version = old_version
280
+ target_version = new_version
281
+ end
282
+
283
+ # Kotlin DSL 格式
284
+ if content.gsub!("classpath(\"com.android.tools.build:gradle:#{old_version}\")",
285
+ "classpath(\"com.android.tools.build:gradle:#{new_version}\")")
286
+ updated = true
287
+ found_version = old_version
288
+ target_version = new_version
289
+ end
290
+
291
+ # 新格式(使用 id 和 version)
292
+ if content.gsub!("id 'com.android.application' version '#{old_version}'",
293
+ "id 'com.android.application' version '#{new_version}'")
294
+ updated = true
295
+ found_version = old_version
296
+ target_version = new_version
297
+ end
298
+
299
+ if content.gsub!("id 'com.android.library' version '#{old_version}'",
300
+ "id 'com.android.library' version '#{new_version}'")
301
+ updated = true
302
+ found_version = old_version
303
+ target_version = new_version
304
+ end
305
+ end
306
+
307
+ if updated
308
+ File.write(target_file, content)
309
+ Funlog.info("✓ AGP版本已更新: #{found_version} → #{target_version}")
310
+ else
311
+ Funlog.info("AGP版本无需更新或已是目标版本")
312
+ end
313
+ end
314
+
315
+ # 确保 Gradle 可用(下载或使用缓存)
316
+ def ensure_gradle_available(gradle_version)
317
+ gradle_home = File.join(GRADLE_CACHE_DIR, "gradle-#{gradle_version}")
318
+ gradle_bin = File.join(gradle_home, "bin/gradle")
319
+
320
+ # 如果已存在,直接使用
321
+ if File.exist?(gradle_bin)
322
+ setup_gradle_environment(gradle_home)
323
+ return true
165
324
  end
325
+
326
+ # 下载并解压
327
+ download_and_setup_gradle(gradle_version)
166
328
  end
167
-
168
- # 下载分发包
169
- puts "下载Gradle分发包: #{distribution_url}"
170
- if download_with_curl(distribution_url, cache_file)
171
- puts " Gradle分发包下载成功"
172
- return extract_gradle_distribution(cache_file, extract_dir, gradle_version)
329
+
330
+ # 生成 Gradle Wrapper
331
+ def generate_gradle_wrapper(project_path, gradle_version)
332
+ Dir.chdir(project_path) do
333
+ system("gradle wrapper")
334
+ end
335
+ rescue => e
336
+ false
173
337
  end
174
-
175
- puts "✗ Gradle分发包下载失败"
176
- false
177
- end
178
-
179
-
180
- # 简单的ZIP完整性检查
181
- def verify_zip_integrity(zip_file)
182
- puts "验证ZIP文件完整性..."
183
-
184
- # 1. 检查文件是否存在
185
- unless File.exist?(zip_file)
186
- puts "✗ 文件不存在: #{zip_file}"
187
- return false
338
+
339
+
340
+ # 查找主工程的 app 模块 build.gradle
341
+ def find_app_module_gradle(project_path)
342
+ # 常见的 app 模块路径
343
+ possible_paths = [
344
+ File.join(project_path, "app/build.gradle"),
345
+ File.join(project_path, "app/build.gradle.kts"),
346
+ File.join(project_path, "launcher/build.gradle"),
347
+ File.join(project_path, "launcher/build.gradle.kts")
348
+ ]
349
+
350
+ possible_paths.find { |path| File.exist?(path) }
188
351
  end
189
-
190
- # 2. 检查文件大小(Gradle分发包通常大于10MB)
191
- file_size = File.size(zip_file)
192
- if file_size < 10_000_000 # 10MB
193
- puts "✗ 文件大小异常: #{file_size} 字节 (应该大于10MB)"
194
- return false
352
+
353
+ # 从 build.gradle 文件中提取 SDK 版本信息
354
+ def extract_sdk_versions(gradle_file)
355
+ content = File.read(gradle_file)
356
+ versions = {}
357
+
358
+ # 提取 compileSdkVersion
359
+ if content =~ /compileSdkVersion\s+(\d+)/
360
+ versions[:compile_sdk] = $1
361
+ elsif content =~ /compileSdk\s*=?\s*(\d+)/
362
+ versions[:compile_sdk] = $1
363
+ end
364
+
365
+ # 提取 targetSdkVersion
366
+ if content =~ /targetSdkVersion\s+(\d+)/
367
+ versions[:target_sdk] = $1
368
+ elsif content =~ /targetSdk\s*=?\s*(\d+)/
369
+ versions[:target_sdk] = $1
370
+ end
371
+
372
+ # 提取 minSdkVersion
373
+ if content =~ /minSdkVersion\s+(\d+)/
374
+ versions[:min_sdk] = $1
375
+ elsif content =~ /minSdk\s*=?\s*(\d+)/
376
+ versions[:min_sdk] = $1
377
+ end
378
+
379
+ # 提取 buildToolsVersion
380
+ if content =~ /buildToolsVersion\s+["']([^"']+)["']/
381
+ versions[:build_tools] = $1
382
+ end
383
+
384
+ versions
195
385
  end
196
-
197
- # 3. 使用unzip -t测试ZIP文件完整性
198
- test_cmd = "unzip -t '#{zip_file}' > /dev/null 2>&1"
199
- if system(test_cmd)
200
- puts "✓ ZIP文件完整性验证通过"
201
- return true
202
- else
203
- puts "✗ ZIP文件完整性验证失败"
204
- return false
386
+
387
+ # 更新模块的 SDK 版本
388
+ def update_module_sdk_versions(gradle_file, versions)
389
+ return if versions.empty?
390
+
391
+ content = File.read(gradle_file)
392
+ updated = false
393
+
394
+ # 更新 compileSdkVersion
395
+ if versions[:compile_sdk]
396
+ if content.gsub!(/compileSdkVersion\s+\d+/, "compileSdkVersion #{versions[:compile_sdk]}")
397
+ updated = true
398
+ elsif content.gsub!(/compileSdk\s*=?\s*\d+/, "compileSdk = #{versions[:compile_sdk]}")
399
+ updated = true
400
+ end
401
+ end
402
+
403
+ # 更新 targetSdkVersion
404
+ if versions[:target_sdk]
405
+ if content.gsub!(/targetSdkVersion\s+\d+/, "targetSdkVersion #{versions[:target_sdk]}")
406
+ updated = true
407
+ elsif content.gsub!(/targetSdk\s*=?\s*\d+/, "targetSdk = #{versions[:target_sdk]}")
408
+ updated = true
409
+ end
410
+ end
411
+
412
+ # 更新 minSdkVersion
413
+ if versions[:min_sdk]
414
+ if content.gsub!(/minSdkVersion\s+\d+/, "minSdkVersion #{versions[:min_sdk]}")
415
+ updated = true
416
+ elsif content.gsub!(/minSdk\s*=?\s*\d+/, "minSdk = #{versions[:min_sdk]}")
417
+ updated = true
418
+ end
419
+ end
420
+
421
+ # 更新 buildToolsVersion
422
+ if versions[:build_tools]
423
+ if content.gsub!(/buildToolsVersion\s+["'][^"']+["']/, "buildToolsVersion \"#{versions[:build_tools]}\"")
424
+ updated = true
425
+ end
426
+ end
427
+
428
+ File.write(gradle_file, content) if updated
205
429
  end
206
- rescue => e
207
- puts "✗ ZIP文件验证异常: #{e.message}"
208
- false
209
- end
210
-
211
- # 使用curl下载文件
212
- def download_with_curl(url, output_path)
213
- puts "使用curl下载: #{url}"
214
-
215
- # 简化的curl命令,避免特殊字符问题
216
- cmd = "curl -L -o '#{output_path}' '#{url}'"
217
-
218
- if system(cmd)
219
- puts "✓ curl下载成功: #{File.size(output_path)} 字节"
220
- return true
221
- else
222
- puts "✗ curl下载失败"
223
- return false
430
+
431
+
432
+ # 下载并设置Gradle环境
433
+ def download_and_setup_gradle(gradle_version)
434
+ # 确保缓存目录存在
435
+ FileUtils.mkdir_p(GRADLE_CACHE_DIR)
436
+
437
+ # 检查是否已解压
438
+ gradle_home = File.join(GRADLE_CACHE_DIR, "gradle-#{gradle_version}")
439
+ gradle_bin = File.join(gradle_home, "bin/gradle")
440
+
441
+ if File.exist?(gradle_bin)
442
+ # 使用缓存的Gradle,直接设置环境
443
+ setup_gradle_environment(gradle_home)
444
+ return true
445
+ end
446
+
447
+ # 下载Gradle分发包
448
+ if download_gradle_distribution(gradle_version)
449
+ setup_gradle_environment(gradle_home)
450
+ return true
451
+ end
452
+
453
+ false
224
454
  end
225
- rescue => e
226
- puts "✗ curl下载异常: #{e.message}"
227
- false
228
- end
229
-
230
- # 解压Gradle分发包
231
- def extract_gradle_distribution(zip_file, extract_dir, gradle_version)
232
- puts "解压Gradle分发包..."
233
-
234
- begin
235
- # 使用unzip命令解压
236
- extract_cmd = "cd '#{File.dirname(extract_dir)}' && unzip -q '#{zip_file}'"
237
- if system(extract_cmd)
238
- # 设置执行权限
239
- gradle_script = File.join(extract_dir, "bin/gradle")
240
- if File.exist?(gradle_script)
241
- system("chmod", "+x", gradle_script)
242
- puts "✓ Gradle分发包解压成功"
243
- return true
455
+
456
+ # 下载Gradle分发包
457
+ def download_gradle_distribution(gradle_version)
458
+ distribution_url = "https://services.gradle.org/distributions/gradle-#{gradle_version}-bin.zip"
459
+ cache_file = File.join(GRADLE_CACHE_DIR, "gradle-#{gradle_version}-bin.zip")
460
+ extract_dir = File.join(GRADLE_CACHE_DIR, "gradle-#{gradle_version}")
461
+
462
+ # 如果已存在ZIP文件,先检查完整性
463
+ if File.exist?(cache_file)
464
+ if verify_zip_integrity(cache_file)
465
+ return extract_gradle_distribution(cache_file, extract_dir, gradle_version)
244
466
  else
245
- puts "✗ 解压后未找到gradle可执行文件"
246
- return false
467
+ # 缓存文件损坏,删除并重新下载
468
+ FileUtils.rm_f(cache_file)
247
469
  end
248
- else
249
- puts "✗ Gradle分发包解压失败"
470
+ end
471
+
472
+ # 下载分发包
473
+ Funlog.fancyinfo_update("下载Gradle #{gradle_version}...")
474
+ if download_with_curl(distribution_url, cache_file)
475
+ return extract_gradle_distribution(cache_file, extract_dir, gradle_version)
476
+ end
477
+
478
+ Funlog.error("Gradle分发包下载失败")
479
+ false
480
+ end
481
+
482
+
483
+ # 简单的ZIP完整性检查
484
+ def verify_zip_integrity(zip_file)
485
+ # 1. 检查文件是否存在
486
+ unless File.exist?(zip_file)
250
487
  return false
251
488
  end
489
+
490
+ # 2. 检查文件大小(Gradle分发包通常大于10MB)
491
+ file_size = File.size(zip_file)
492
+ if file_size < 10_000_000 # 10MB
493
+ return false
494
+ end
495
+
496
+ # 3. 使用unzip -t测试ZIP文件完整性
497
+ test_cmd = "unzip -t '#{zip_file}' > /dev/null 2>&1"
498
+ system(test_cmd)
252
499
  rescue => e
253
- puts "✗ Gradle分发包解压异常: #{e.message}"
254
500
  false
255
501
  end
256
- end
257
-
258
- # 设置Gradle环境变量
259
- def setup_gradle_environment(gradle_home)
260
- # 直接检查gradle可执行文件
261
- gradle_bin_dir = File.join(gradle_home, "bin")
262
- gradle_executable = File.join(gradle_bin_dir, "gradle")
263
-
264
- unless File.exist?(gradle_executable)
265
- puts "✗ Gradle可执行文件不存在: #{gradle_executable}"
266
- return false
502
+
503
+ # 使用curl下载文件
504
+ def download_with_curl(url, output_path)
505
+ # 简化的curl命令,避免特殊字符问题
506
+ cmd = "curl -L -o '#{output_path}' '#{url}'"
507
+ system(cmd)
508
+ rescue => e
509
+ false
267
510
  end
268
-
269
- # 设置环境变量
270
- ENV['GRADLE_HOME'] = gradle_home
271
- ENV['PATH'] = "#{gradle_bin_dir}:#{ENV['PATH']}"
272
-
273
- puts " Gradle环境变量设置完成"
274
-
275
- true
276
- end
277
-
278
- # 使用官方Gradle命令生成wrapper
279
- def generate_gradle_wrapper_official(project_path, gradle_version)
280
- Dir.chdir(project_path) do
281
- # 使用gradle wrapper命令
282
- cmd = "gradle wrapper"
283
-
284
- if system(cmd)
285
- return true
286
- else
287
- puts "✗ 官方Gradle命令生成wrapper失败"
511
+
512
+ # 解压Gradle分发包
513
+ def extract_gradle_distribution(zip_file, extract_dir, gradle_version)
514
+ begin
515
+ # 使用unzip命令解压
516
+ extract_cmd = "cd '#{File.dirname(extract_dir)}' && unzip -q '#{zip_file}'"
517
+ if system(extract_cmd)
518
+ # 设置执行权限
519
+ gradle_script = File.join(extract_dir, "bin/gradle")
520
+ if File.exist?(gradle_script)
521
+ system("chmod", "+x", gradle_script)
522
+ return true
523
+ else
524
+ Funlog.error("解压后未找到gradle可执行文件")
525
+ return false
526
+ end
527
+ else
528
+ Funlog.error("Gradle分发包解压失败")
529
+ return false
530
+ end
531
+ rescue => e
532
+ false
533
+ end
534
+ end
535
+
536
+ # 设置Gradle环境变量
537
+ def setup_gradle_environment(gradle_home)
538
+ # 直接检查gradle可执行文件
539
+ gradle_bin_dir = File.join(gradle_home, "bin")
540
+ gradle_executable = File.join(gradle_bin_dir, "gradle")
541
+
542
+ unless File.exist?(gradle_executable)
288
543
  return false
289
544
  end
545
+
546
+ # 设置环境变量
547
+ ENV['GRADLE_HOME'] = gradle_home
548
+ ENV['PATH'] = "#{gradle_bin_dir}:#{ENV['PATH']}"
549
+
550
+ true
551
+ end
552
+
553
+ # 使用官方Gradle命令生成wrapper
554
+ def generate_gradle_wrapper_official(project_path, gradle_version)
555
+ Dir.chdir(project_path) do
556
+ # 使用gradle wrapper命令
557
+ cmd = "gradle wrapper"
558
+ system(cmd)
559
+ end
560
+ rescue => e
561
+ false
562
+ end
290
563
  end
291
- rescue => e
292
- puts "✗ 官方Gradle命令执行异常: #{e.message}"
293
- false
294
- end
295
564
  end
296
565
  end