pindo 5.17.4 → 5.18.3
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.
- checksums.yaml +4 -4
- data/lib/pindo/base/git_handler.rb +120 -38
- data/lib/pindo/command/android/autobuild.rb +92 -31
- data/lib/pindo/command/appstore/adhocbuild.rb +1 -1
- data/lib/pindo/command/appstore/autobuild.rb +1 -1
- data/lib/pindo/command/appstore/autoresign.rb +1 -1
- data/lib/pindo/command/appstore/updateid.rb +229 -0
- data/lib/pindo/command/appstore.rb +1 -0
- data/lib/pindo/command/ios/autobuild.rb +70 -33
- data/lib/pindo/command/ios/podpush.rb +1 -1
- data/lib/pindo/command/unity/autobuild.rb +38 -18
- data/lib/pindo/command/utils/allcopyconfig.rb +144 -0
- data/lib/pindo/command/utils/copyconfig.rb +207 -0
- data/lib/pindo/command/utils/icon.rb +2 -2
- data/lib/pindo/command/utils/renewbundleid.rb +199 -0
- data/lib/pindo/command/utils/renewcert.rb +56 -54
- data/lib/pindo/command/utils.rb +3 -0
- data/lib/pindo/command/web/autobuild.rb +10 -8
- data/lib/pindo/config/build_info_manager.rb +1 -3
- data/lib/pindo/module/android/android_build_helper.rb +198 -33
- data/lib/pindo/module/android/android_config_helper.rb +305 -88
- data/lib/pindo/module/android/android_project_helper.rb +124 -14
- data/lib/pindo/module/android/android_res_helper.rb +349 -51
- data/lib/pindo/module/android/keystore_helper.rb +611 -295
- data/lib/pindo/module/android/workflow_gradle_injector.rb +702 -0
- data/lib/pindo/module/appselect.rb +4 -4
- data/lib/pindo/module/appstore/bundleid_helper.rb +204 -14
- data/lib/pindo/module/build/build_helper.rb +76 -10
- data/lib/pindo/module/build/git_repo_helper.rb +4 -4
- data/lib/pindo/module/cert/mode/base_cert_operator.rb +12 -6
- data/lib/pindo/module/pgyer/pgyerhelper.rb +124 -39
- data/lib/pindo/module/task/model/build/android_build_dev_task.rb +64 -6
- data/lib/pindo/module/task/model/git/git_commit_task.rb +70 -54
- data/lib/pindo/module/task/model/git/git_tag_task.rb +13 -9
- data/lib/pindo/module/task/model/jps/jps_upload_task.rb +110 -3
- data/lib/pindo/module/task/model/unity/unity_export_task.rb +2 -1
- data/lib/pindo/module/task/model/unity/unity_update_task.rb +2 -1
- data/lib/pindo/module/task/model/unity/unity_yoo_asset_task.rb +2 -1
- data/lib/pindo/module/task/model/unity_task.rb +2 -1
- data/lib/pindo/module/unity/unity_helper.rb +13 -10
- data/lib/pindo/module/unity/unity_proc_helper.rb +27 -2
- data/lib/pindo/module/xcode/applovin_xcode_helper.rb +6 -2
- data/lib/pindo/module/xcode/res/xcode_res_constant.rb +72 -0
- data/lib/pindo/module/xcode/res/xcode_res_handler.rb +3 -3
- data/lib/pindo/module/xcode/xcode_build_config.rb +46 -17
- data/lib/pindo/module/xcode/xcode_build_helper.rb +186 -25
- data/lib/pindo/module/xcode/xcode_project_helper.rb +1 -1
- data/lib/pindo/module/xcode/xcode_res_helper.rb +32 -16
- data/lib/pindo/options/groups/build_options.rb +5 -5
- data/lib/pindo/options/groups/git_options.rb +7 -5
- data/lib/pindo/options/groups/unity_options.rb +11 -0
- data/lib/pindo/options/helpers/bundleid_selector.rb +25 -0
- data/lib/pindo/options/helpers/git_constants.rb +7 -6
- data/lib/pindo/version.rb +3 -3
- metadata +12 -7
|
@@ -83,8 +83,8 @@ module Pindo
|
|
|
83
83
|
|
|
84
84
|
fixed_bundleid_array.each do |bundle_id|
|
|
85
85
|
# begin
|
|
86
|
-
if bundle_id.
|
|
87
|
-
bundle_id =
|
|
86
|
+
if bundle_id.include?("*")
|
|
87
|
+
bundle_id = bundle_id.gsub(".*", "")
|
|
88
88
|
end
|
|
89
89
|
fixed_cert(bundle_id:bundle_id, renew_flag:@renew_cert_flag, upload_flag:@upload_flag, fixed_bundleid_flag:@fixedid_flag)
|
|
90
90
|
# rescue => err
|
|
@@ -123,58 +123,60 @@ module Pindo
|
|
|
123
123
|
)
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
end
|
|
126
|
+
Pindo::Command::Appstore::Bundleid::run([])
|
|
127
|
+
|
|
128
|
+
# if @fast_flag
|
|
129
|
+
|
|
130
|
+
# if @dev_bundle_id_array.include?(bundle_id) || @tool_bundle_id_array.include?(bundle_id)
|
|
131
|
+
# args_temp = []
|
|
132
|
+
# args_temp << "--config=#{config_file_path}"
|
|
133
|
+
# args_temp << "--build_type=dev"
|
|
134
|
+
# if renew_flag
|
|
135
|
+
# args_temp << "--renew"
|
|
136
|
+
# end
|
|
137
|
+
# if upload_flag
|
|
138
|
+
# args_temp << "--upload"
|
|
139
|
+
# end
|
|
140
|
+
# Pindo::Command::Appstore::Cert::run(args_temp)
|
|
141
|
+
# end
|
|
142
|
+
|
|
143
|
+
# if @deploy_bundle_id_array.include?(bundle_id)
|
|
144
|
+
# args_temp = []
|
|
145
|
+
# args_temp << "--config=#{config_file_path}"
|
|
146
|
+
# args_temp << "--build_type=adhoc"
|
|
147
|
+
# if renew_flag
|
|
148
|
+
# args_temp << "--renew"
|
|
149
|
+
# end
|
|
150
|
+
# if upload_flag
|
|
151
|
+
# args_temp << "--upload"
|
|
152
|
+
# end
|
|
153
|
+
# Pindo::Command::Appstore::Cert::run(args_temp)
|
|
154
|
+
# end
|
|
155
|
+
|
|
156
|
+
# else
|
|
157
|
+
|
|
158
|
+
# args_temp = []
|
|
159
|
+
# args_temp << "--config=#{config_file_path}"
|
|
160
|
+
# args_temp << "--build_type=dev"
|
|
161
|
+
# if renew_flag
|
|
162
|
+
# args_temp << "--renew"
|
|
163
|
+
# end
|
|
164
|
+
# if upload_flag
|
|
165
|
+
# args_temp << "--upload"
|
|
166
|
+
# end
|
|
167
|
+
# Pindo::Command::Appstore::Cert::run(args_temp)
|
|
168
|
+
|
|
169
|
+
# args_temp = []
|
|
170
|
+
# args_temp << "--config=#{config_file_path}"
|
|
171
|
+
# args_temp << "--build_type=adhoc"
|
|
172
|
+
# if renew_flag
|
|
173
|
+
# args_temp << "--renew"
|
|
174
|
+
# end
|
|
175
|
+
# if upload_flag
|
|
176
|
+
# args_temp << "--upload"
|
|
177
|
+
# end
|
|
178
|
+
# Pindo::Command::Appstore::Cert::run(args_temp)
|
|
179
|
+
# end
|
|
178
180
|
end
|
|
179
181
|
|
|
180
182
|
|
data/lib/pindo/command/utils.rb
CHANGED
|
@@ -7,6 +7,9 @@ require 'pindo/command/utils/device'
|
|
|
7
7
|
# require 'pindo/command/utils/tgate'
|
|
8
8
|
# require 'pindo/command/utils/boss'
|
|
9
9
|
require 'pindo/command/utils/renewcert'
|
|
10
|
+
require 'pindo/command/utils/renewbundleid'
|
|
11
|
+
require 'pindo/command/utils/copyconfig'
|
|
12
|
+
require 'pindo/command/utils/allcopyconfig'
|
|
10
13
|
require 'pindo/command/utils/repoinit'
|
|
11
14
|
require 'pindo/command/utils/tag'
|
|
12
15
|
require 'pindo/command/utils/updateconfig'
|
|
@@ -155,7 +155,7 @@ module Pindo
|
|
|
155
155
|
pindo_project_dir = Dir.pwd
|
|
156
156
|
|
|
157
157
|
# 加载 JPS 配置(如果存在)
|
|
158
|
-
Pindo::BuildHelper.share_instance.load_jps_build_config(pindo_project_dir)
|
|
158
|
+
Pindo::BuildHelper.share_instance.load_jps_build_config(pindo_project_dir, conf: @args_conf)
|
|
159
159
|
|
|
160
160
|
# 准备配置
|
|
161
161
|
config = prepare_web_config(pindo_project_dir)
|
|
@@ -270,12 +270,14 @@ module Pindo
|
|
|
270
270
|
)
|
|
271
271
|
tasks << git_commit_task
|
|
272
272
|
|
|
273
|
-
# 2. Git
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
273
|
+
# 2. Git 标签任务(skip_without_tag 模式下不创建)
|
|
274
|
+
git_tag_task = nil
|
|
275
|
+
unless process_type == Pindo::UncommittedFilesProcessType::SKIP_WITHOUT_TAG
|
|
276
|
+
git_tag_task = Pindo::TaskSystem::GitTagTask.new(config[:project_path])
|
|
277
|
+
git_tag_task.dependencies << git_commit_task.id
|
|
278
|
+
tasks << git_tag_task
|
|
279
|
+
last_task = git_tag_task
|
|
280
|
+
end
|
|
279
281
|
|
|
280
282
|
# 3. Unity 更新必备库任务(可选)
|
|
281
283
|
unless @args_skip_lib
|
|
@@ -417,7 +419,7 @@ module Pindo
|
|
|
417
419
|
)
|
|
418
420
|
# 依赖 Git Commit、Git Tag 和 Bind Package 任务
|
|
419
421
|
workflow_message_task.dependencies << git_commit_task.id
|
|
420
|
-
workflow_message_task.dependencies << git_tag_task.id
|
|
422
|
+
workflow_message_task.dependencies << git_tag_task.id if git_tag_task
|
|
421
423
|
workflow_message_task.dependencies << bind_package_task.id
|
|
422
424
|
tasks << workflow_message_task
|
|
423
425
|
end
|
|
@@ -174,9 +174,7 @@ module Pindo
|
|
|
174
174
|
end
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
# 修改仓库设置(测试环境)
|
|
177
|
+
# 将仓库注册到 git_base_url.json,指定其所属 org
|
|
180
178
|
def modify_repo_setting(repo_name:, owner_org:)
|
|
181
179
|
pindo_setting_dir = pindo_single_config.pindo_env_configdir
|
|
182
180
|
git_repo_file = pindo_single_config.git_base_url_fullname
|
|
@@ -4,6 +4,7 @@ require_relative 'gradle_helper'
|
|
|
4
4
|
require_relative 'gp_compliance_helper'
|
|
5
5
|
require_relative 'java_env_helper'
|
|
6
6
|
require_relative 'keystore_helper'
|
|
7
|
+
require_relative 'workflow_gradle_injector'
|
|
7
8
|
require 'fileutils'
|
|
8
9
|
|
|
9
10
|
module Pindo
|
|
@@ -19,7 +20,7 @@ module Pindo
|
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
def auto_build_apk(project_dir, debug = false, ignore_sub = false)
|
|
23
|
+
def auto_build_apk(project_dir, debug = false, ignore_sub = false, bundle_name: nil, workflow_name: nil)
|
|
23
24
|
raise ArgumentError, "项目目录不能为空" if project_dir.nil?
|
|
24
25
|
raise ArgumentError, "项目目录不存在" unless File.directory?(project_dir)
|
|
25
26
|
|
|
@@ -40,10 +41,16 @@ module Pindo
|
|
|
40
41
|
# 2. 处理 Unity 作为 lib 的原生工程(Unity 放在 Unity 目录下)
|
|
41
42
|
elsif Pindo::AndroidProjectHelper.unity_as_lib_android_project?(project_dir)
|
|
42
43
|
puts "处理 Unity 作为 lib 的原生工程..."
|
|
44
|
+
|
|
45
|
+
# 确保主工程能继承 Unity 导出的关键 gradle.properties 配置
|
|
46
|
+
# 包括 android.aapt2FromMavenOverride 与 org.gradle.java.home
|
|
47
|
+
Pindo::AndroidProjectHelper.sync_gradle_properties_from_unity_to_main(project_dir)
|
|
48
|
+
|
|
43
49
|
unity_dir = File.join(project_dir, "Unity")
|
|
44
50
|
|
|
45
51
|
if File.directory?(unity_dir)
|
|
46
52
|
puts "找到 Unity 模块目录: Unity/"
|
|
53
|
+
validate_unity_libs_state!(unity_dir, stage: "导出前")
|
|
47
54
|
|
|
48
55
|
# 如果 Unity 子目录是完整的 Unity 导出工程,对其进行处理
|
|
49
56
|
if Pindo::AndroidProjectHelper.unity_android_project?(unity_dir)
|
|
@@ -67,6 +74,7 @@ module Pindo
|
|
|
67
74
|
raise RuntimeError, "编译 Unity 模块 SO 库失败"
|
|
68
75
|
end
|
|
69
76
|
copy_so_files(unity_dir, project_dir)
|
|
77
|
+
validate_unity_libs_state!(project_dir, stage: "导出后")
|
|
70
78
|
|
|
71
79
|
# SO 库拷贝完成后,重新配置主工程的 Java Home 和 Gradle 环境
|
|
72
80
|
puts "Unity SO库编译完成,切换到主工程编译环境"
|
|
@@ -89,26 +97,44 @@ module Pindo
|
|
|
89
97
|
# 检查并配置 local.properties(所有项目类型都需要)
|
|
90
98
|
Pindo::AndroidProjectHelper.check_main_local_properties(project_dir)
|
|
91
99
|
|
|
92
|
-
# 配置 Keystore
|
|
100
|
+
# 配置 Keystore 签名(从 JPS 获取,alias_name 为 Application ID)
|
|
93
101
|
build_type = debug ? "debug" : "release"
|
|
94
|
-
if
|
|
95
|
-
|
|
102
|
+
raise "bundle_name 不能为空,Keystore 签名需要 Application ID" if bundle_name.nil? || bundle_name.empty?
|
|
103
|
+
|
|
104
|
+
unless Pindo::KeystoreHelper.apply_keystore_config(project_dir, build_type, bundle_id: bundle_name)
|
|
105
|
+
raise RuntimeError, "Keystore 签名配置失败"
|
|
106
|
+
end
|
|
107
|
+
puts "✓ Android 签名配置成功"
|
|
108
|
+
|
|
109
|
+
if workflow_name && !workflow_name.to_s.empty?
|
|
110
|
+
injector = Pindo::Android::WorkflowGradleInjector.new
|
|
111
|
+
ctx = injector.prepare!(
|
|
112
|
+
project_dir: project_dir,
|
|
113
|
+
workflow_name: workflow_name,
|
|
114
|
+
enable_pad: true
|
|
115
|
+
)
|
|
116
|
+
apk_path = nil
|
|
117
|
+
begin
|
|
118
|
+
apk_path = build_apk(project_dir, debug, workflow_build_type: ctx[:workflow_build_type])
|
|
119
|
+
ensure
|
|
120
|
+
injector.cleanup!(ctx)
|
|
121
|
+
end
|
|
122
|
+
# JKS 仅在 universal.apk 已成功产出后删除;失败则保留,便于排查(Gradle 注入已在 ensure 中恢复)
|
|
123
|
+
Pindo::KeystoreHelper.cleanup_managed_signing_paths! if apk_path && File.exist?(apk_path.to_s)
|
|
124
|
+
Pindo::Android::WorkflowGradleInjector.remove_project_pindo_tmp_dir!(project_dir)
|
|
96
125
|
else
|
|
97
|
-
|
|
126
|
+
# 兼容旧行为:仍会永久写入 PAD 相关变更(如需临时恢复,请传 workflow_name 走注入管线)
|
|
127
|
+
setup_play_asset_delivery(project_dir)
|
|
128
|
+
apk_path = build_apk(project_dir, debug)
|
|
129
|
+
Pindo::KeystoreHelper.cleanup_managed_signing_paths! if apk_path && File.exist?(apk_path.to_s)
|
|
98
130
|
end
|
|
99
|
-
|
|
100
|
-
# 处理 Play Asset Delivery 配置(如果存在)
|
|
101
|
-
setup_play_asset_delivery(project_dir)
|
|
102
|
-
|
|
103
|
-
# 构建 APK
|
|
104
|
-
build_apk(project_dir, debug)
|
|
105
131
|
end
|
|
106
132
|
|
|
107
|
-
def build_apk(project_path, debug)
|
|
133
|
+
def build_apk(project_path, debug, workflow_build_type: nil)
|
|
108
134
|
raise ArgumentError, "项目路径不能为空" if project_path.nil? || project_path.empty?
|
|
109
135
|
|
|
110
136
|
# 构建 AAB 文件
|
|
111
|
-
unless build_aab(project_path, debug)
|
|
137
|
+
unless build_aab(project_path, debug, workflow_build_type: workflow_build_type)
|
|
112
138
|
raise RuntimeError, "AAB 构建失败"
|
|
113
139
|
end
|
|
114
140
|
|
|
@@ -116,7 +142,11 @@ module Pindo
|
|
|
116
142
|
main_module = Pindo::AndroidProjectHelper.get_main_module(project_path)
|
|
117
143
|
raise ArgumentError, "无法找到主模块" unless main_module
|
|
118
144
|
|
|
119
|
-
keystore_config = Pindo::KeystoreHelper.get_keystore_config_from_project(
|
|
145
|
+
keystore_config = Pindo::KeystoreHelper.get_keystore_config_from_project(
|
|
146
|
+
project_path,
|
|
147
|
+
debug,
|
|
148
|
+
workflow_build_type: workflow_build_type
|
|
149
|
+
)
|
|
120
150
|
raise ArgumentError, "无法从 build.gradle 中获取 keystore 信息" unless keystore_config
|
|
121
151
|
|
|
122
152
|
build_tools = Pindo::AndroidProjectHelper.get_build_tools
|
|
@@ -132,7 +162,11 @@ module Pindo
|
|
|
132
162
|
end
|
|
133
163
|
|
|
134
164
|
# 准备输出路径
|
|
135
|
-
build_type =
|
|
165
|
+
build_type = if workflow_build_type && !workflow_build_type.to_s.empty?
|
|
166
|
+
workflow_build_type.to_s
|
|
167
|
+
else
|
|
168
|
+
debug ? 'debug' : 'release'
|
|
169
|
+
end
|
|
136
170
|
main_module_name = File.basename(main_module)
|
|
137
171
|
output_dir = File.join(project_path, "build/apks")
|
|
138
172
|
|
|
@@ -176,14 +210,37 @@ module Pindo
|
|
|
176
210
|
# --- END ---
|
|
177
211
|
|
|
178
212
|
# puts "解析 keystore 配置"
|
|
179
|
-
|
|
180
|
-
#
|
|
181
|
-
|
|
182
|
-
#
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
213
|
+
# 与 Gradle 对 storeFile 的生效顺序一致:常见写法为
|
|
214
|
+
# storeFile file(System.getenv("RELEASE_KEYSTORE_PATH") ?: "signing/gxdebug.jks")
|
|
215
|
+
# apply_keystore_config 已在当前进程设置 RELEASE_*,Gradle 打 AAB 时走 ENV 指向的真实 jks;
|
|
216
|
+
# get_keystore_config_from_project 若只解析到 ?: 右侧占位路径,会与 AAB 实际签名不一致且文件可能不存在。
|
|
217
|
+
# 故:当 RELEASE_KEYSTORE_PATH 展开后文件存在时,bundletool 必须使用同一套 RELEASE_*(非「失败回退」)。
|
|
218
|
+
kh = Pindo::KeystoreHelper
|
|
219
|
+
env_ks = ENV[kh::ENV_RELEASE_KEYSTORE_PATH]
|
|
220
|
+
env_ks_abs = env_ks && !env_ks.to_s.empty? ? File.expand_path(env_ks) : nil
|
|
221
|
+
gradle_ks = keystore_config[:store_file]
|
|
222
|
+
|
|
223
|
+
use_release_env = env_ks_abs && File.exist?(env_ks_abs)
|
|
224
|
+
if use_release_env
|
|
225
|
+
ks = env_ks_abs
|
|
226
|
+
ks_pass = ENV[kh::ENV_RELEASE_KEYSTORE_PASSWORD] || keystore_config[:store_password]
|
|
227
|
+
key_alias = ENV[kh::ENV_RELEASE_KEY_ALIAS] || keystore_config[:key_alias]
|
|
228
|
+
key_pass = ENV[kh::ENV_RELEASE_KEY_PASSWORD] || keystore_config[:key_password]
|
|
229
|
+
else
|
|
230
|
+
ks = gradle_ks || env_ks
|
|
231
|
+
ks = File.expand_path(ks.to_s) if ks && !ks.to_s.empty?
|
|
232
|
+
ks_pass = keystore_config[:store_password] || ENV[kh::ENV_RELEASE_KEYSTORE_PASSWORD]
|
|
233
|
+
key_alias = keystore_config[:key_alias] || ENV[kh::ENV_RELEASE_KEY_ALIAS]
|
|
234
|
+
key_pass = keystore_config[:key_password] || ENV[kh::ENV_RELEASE_KEY_PASSWORD]
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
ks_display = ks && !ks.to_s.empty? ? File.expand_path(ks.to_s) : ks.to_s
|
|
238
|
+
# puts "[bundletool] universal.apk 实际使用的签名 keystore: #{ks_display}"
|
|
239
|
+
# if workflow_build_type && !workflow_build_type.to_s.empty?
|
|
240
|
+
# puts "[bundletool] workflow buildType: #{workflow_build_type}"
|
|
241
|
+
# end
|
|
242
|
+
# puts "[bundletool] 签名来源: #{use_release_env ? "RELEASE_KEYSTORE_PATH(文件存在,与 Gradle 打 AAB 一致)" : "build.gradle 解析 / ENV 兜底(非 RELEASE 路径或文件不存在时)"}"
|
|
243
|
+
# puts "[bundletool] keyAlias: #{key_alias.inspect}(口令不落日志)"
|
|
187
244
|
|
|
188
245
|
# 构建 APK
|
|
189
246
|
# 确保使用正确的 Java 版本 (Java 11+)
|
|
@@ -212,8 +269,12 @@ module Pindo
|
|
|
212
269
|
raise RuntimeError, "AAB 文件不存在: #{paths[:bundle]}"
|
|
213
270
|
end
|
|
214
271
|
|
|
272
|
+
if ks.nil? || ks.to_s.empty?
|
|
273
|
+
raise RuntimeError, "Keystore 路径为空:无法从 build.gradle 解析签名配置,且未从环境变量获取到 #{Pindo::KeystoreHelper::ENV_RELEASE_KEYSTORE_PATH}"
|
|
274
|
+
end
|
|
275
|
+
|
|
215
276
|
unless File.exist?(ks)
|
|
216
|
-
raise RuntimeError, "Keystore
|
|
277
|
+
raise RuntimeError, "Keystore 文件不存在: #{ks}"
|
|
217
278
|
end
|
|
218
279
|
|
|
219
280
|
unless system(*bundletool_cmd)
|
|
@@ -238,12 +299,85 @@ module Pindo
|
|
|
238
299
|
paths[:universal_apk]
|
|
239
300
|
end
|
|
240
301
|
|
|
241
|
-
def build_aab(project_path, debug)
|
|
302
|
+
def build_aab(project_path, debug, workflow_build_type: nil)
|
|
242
303
|
# 使用子 Shell 切换目录执行,避免影响主进程当前目录 (Thread Safe)
|
|
243
|
-
|
|
304
|
+
# --no-daemon:签名依赖当前进程注入的 RELEASE_* 环境变量;已存在的 Gradle Daemon
|
|
305
|
+
# 继承的是其首次启动时的环境,会看不到 pindo 刚设置的变量,从而回退到 build.gradle 里 ?: 的本地 jks。
|
|
306
|
+
main_module = Pindo::AndroidProjectHelper.get_main_module(project_path)
|
|
307
|
+
module_name = main_module ? File.basename(main_module) : nil
|
|
308
|
+
prefix = module_name && !module_name.empty? ? ":#{module_name}:" : ""
|
|
309
|
+
|
|
310
|
+
task_name = if workflow_build_type && !workflow_build_type.to_s.empty?
|
|
311
|
+
"bundle#{workflow_build_type.to_s[0].upcase}#{workflow_build_type.to_s[1..]}"
|
|
312
|
+
else
|
|
313
|
+
debug ? "bundleDebug" : "bundleRelease"
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
bundle_task = "#{prefix}#{task_name}"
|
|
317
|
+
skip_clean = ENV['PINDO_SKIP_GRADLE_CLEAN'] == '1'
|
|
318
|
+
# 任意 bundle 变体(含 debug)均先 clean,避免 aabresguard 等任务因残留输出报「文件已存在」;本地加速可设 PINDO_SKIP_GRADLE_CLEAN=1
|
|
319
|
+
puts ' AAB 构建前先执行 Gradle clean(环境变量 PINDO_SKIP_GRADLE_CLEAN=1 可跳过)' unless skip_clean
|
|
320
|
+
puts ' 已跳过 Gradle clean(PINDO_SKIP_GRADLE_CLEAN=1)' if skip_clean
|
|
321
|
+
|
|
322
|
+
gradle_clean_resilient!(project_path) unless skip_clean
|
|
323
|
+
|
|
324
|
+
cmd = "cd \"#{project_path}\" && ./gradlew --no-daemon #{bundle_task}"
|
|
244
325
|
system(cmd)
|
|
245
326
|
end
|
|
246
327
|
|
|
328
|
+
# clean 失败(占用、.DS_Store 竞态等)时:停 Daemon → 再删 .DS_Store → 物理删除各模块 build/,与 Gradle clean 产物一致,不中断后续 bundle
|
|
329
|
+
private def gradle_clean_resilient!(project_path)
|
|
330
|
+
prune_ds_store_before_gradle_clean!(project_path)
|
|
331
|
+
cmd = %(cd "#{project_path}" && ./gradlew --no-daemon clean)
|
|
332
|
+
return if system(cmd)
|
|
333
|
+
|
|
334
|
+
puts ' ⚠ Gradle clean 失败,正在自动恢复:--stop、清理 .DS_Store、删除各模块 build/ ...'
|
|
335
|
+
system(%(cd "#{project_path}" && ./gradlew --stop), out: File::NULL, err: File::NULL)
|
|
336
|
+
sleep 0.3
|
|
337
|
+
prune_ds_store_before_gradle_clean!(project_path)
|
|
338
|
+
remove_android_module_build_dirs!(project_path)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# 删除 Gradle 模块产物目录(与 clean 目标一致:根 build、一级子模块/build、常见二级子模块/build)
|
|
342
|
+
private def remove_android_module_build_dirs!(project_path)
|
|
343
|
+
return unless project_path && File.directory?(project_path)
|
|
344
|
+
|
|
345
|
+
paths = []
|
|
346
|
+
root_build = File.join(project_path, 'build')
|
|
347
|
+
paths << root_build if File.directory?(root_build)
|
|
348
|
+
|
|
349
|
+
Dir.each_child(project_path) do |name|
|
|
350
|
+
next if name.start_with?('.')
|
|
351
|
+
|
|
352
|
+
mod_build = File.join(project_path, name, 'build')
|
|
353
|
+
paths << mod_build if File.directory?(mod_build)
|
|
354
|
+
|
|
355
|
+
sub = File.join(project_path, name)
|
|
356
|
+
next unless File.directory?(sub)
|
|
357
|
+
|
|
358
|
+
Dir.each_child(sub) do |subname|
|
|
359
|
+
next if subname.start_with?('.')
|
|
360
|
+
|
|
361
|
+
nested = File.join(sub, subname, 'build')
|
|
362
|
+
paths << nested if File.directory?(nested)
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
paths.uniq.each do |p|
|
|
367
|
+
FileUtils.rm_rf(p)
|
|
368
|
+
end
|
|
369
|
+
rescue StandardError => e
|
|
370
|
+
puts " ⚠ 物理删除 build 目录时出现异常(将继续尝试 bundle): #{e.message}"
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# macOS 在 clean 遍历删除 build 目录时 Finder 可能写入 .DS_Store,Gradle 会报 Unable to delete / New files were found
|
|
374
|
+
private def prune_ds_store_before_gradle_clean!(project_path)
|
|
375
|
+
return unless project_path && File.directory?(project_path)
|
|
376
|
+
|
|
377
|
+
system('find', project_path, '-name', '.DS_Store', '-type', 'f', '-delete',
|
|
378
|
+
out: File::NULL, err: File::NULL)
|
|
379
|
+
end
|
|
380
|
+
|
|
247
381
|
def build_so_library(project_path)
|
|
248
382
|
# 编译so库 (Thread Safe)
|
|
249
383
|
cmd = "cd \"#{project_path}\" && ./gradlew unityLibrary:BuildIl2CppTask"
|
|
@@ -282,24 +416,55 @@ module Pindo
|
|
|
282
416
|
|
|
283
417
|
# 递归合并拷贝:将源目录的内容合并到目标目录
|
|
284
418
|
def copy_merge_recursive(src_dir, dst_dir)
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
next if File.basename(src_item) == '.' || File.basename(src_item) == '..'
|
|
289
|
-
|
|
290
|
-
dst_item = File.join(dst_dir, File.basename(src_item))
|
|
419
|
+
Dir.each_child(src_dir) do |name|
|
|
420
|
+
src_item = File.join(src_dir, name)
|
|
421
|
+
dst_item = File.join(dst_dir, name)
|
|
291
422
|
|
|
292
423
|
if File.directory?(src_item)
|
|
293
424
|
# 如果是目录,确保目标子目录存在,然后递归拷贝
|
|
294
425
|
FileUtils.mkdir_p(dst_item)
|
|
295
426
|
copy_merge_recursive(src_item, dst_item)
|
|
296
427
|
else
|
|
297
|
-
#
|
|
428
|
+
# Unity/EDM 常在 libs 下放置指向解析缓存的符号链接;BuildIl2CppTask 后可能出现断裂链接,
|
|
429
|
+
# FileUtils.cp 跟随链接会导致 No such file or directory。
|
|
430
|
+
unless File.exist?(src_item)
|
|
431
|
+
puts " ⚠ 跳过缺失或断裂的引用: #{name}"
|
|
432
|
+
next
|
|
433
|
+
end
|
|
434
|
+
|
|
298
435
|
FileUtils.cp(src_item, dst_item)
|
|
299
436
|
end
|
|
300
437
|
end
|
|
301
438
|
end
|
|
302
439
|
|
|
440
|
+
def validate_unity_libs_state!(android_root, stage:)
|
|
441
|
+
# 某些项目会将 unityLibrary 作为缓存/中间产物纳入仓库,但 libs 下的 .aar -> .srcaar
|
|
442
|
+
# 符号链接目标是由 EDM4U/导出过程生成,初次拉取代码时可能为断链。
|
|
443
|
+
# 默认仍严格失败;如确有需要,可通过环境变量临时跳过此校验继续构建。
|
|
444
|
+
return if ENV["PINDO_SKIP_UNITY_LIBS_VALIDATE"] == "1"
|
|
445
|
+
|
|
446
|
+
libs_dir = File.join(android_root, "unityLibrary", "libs")
|
|
447
|
+
return unless File.directory?(libs_dir)
|
|
448
|
+
|
|
449
|
+
broken_links = []
|
|
450
|
+
Dir.each_child(libs_dir) do |name|
|
|
451
|
+
file_path = File.join(libs_dir, name)
|
|
452
|
+
next unless File.symlink?(file_path)
|
|
453
|
+
next if File.exist?(file_path)
|
|
454
|
+
|
|
455
|
+
broken_links << "#{name} -> #{File.readlink(file_path)}"
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
return if broken_links.empty?
|
|
459
|
+
|
|
460
|
+
raise RuntimeError, <<~MSG
|
|
461
|
+
Unity 依赖校验失败(#{stage}):发现失效的符号链接,请先在 Unity 中执行 EDM4U Resolve 后重新导出。
|
|
462
|
+
扫描目录: #{libs_dir}
|
|
463
|
+
失效条目:
|
|
464
|
+
- #{broken_links.join("\n- ")}
|
|
465
|
+
MSG
|
|
466
|
+
end
|
|
467
|
+
|
|
303
468
|
# 设置 Play Asset Delivery:直接扫描导出工程中的资源目录,按照 Android 原生方式创建 .androidpack 目录
|
|
304
469
|
# 仅适用于 Unity 项目,对于原生 Android 项目会静默跳过
|
|
305
470
|
def setup_play_asset_delivery(project_dir)
|