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
|
@@ -95,7 +95,7 @@ module Pindo
|
|
|
95
95
|
|
|
96
96
|
project_fullname = Dir.glob(File.join(project_dir, "/*.xcodeproj")).max_by {|f| File.mtime(f)}
|
|
97
97
|
project_obj = Xcodeproj::Project.open(project_fullname)
|
|
98
|
-
select_target = project_obj.targets.select { |target| target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]) }.first
|
|
98
|
+
select_target = project_obj.targets.select { |target| target.respond_to?(:product_type) && target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]) }.first
|
|
99
99
|
file_ref = select_target.resources_build_phase.files_references.select { |file| file.display_name.include?("GoogleService-Info.plist") }.first
|
|
100
100
|
|
|
101
101
|
if !file_ref.nil?
|
|
@@ -113,10 +113,10 @@ module Pindo
|
|
|
113
113
|
end
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
-
#
|
|
116
|
+
# 获取扩展 Target 名称后缀到 config key 的映射
|
|
117
|
+
# 注意:MainTarget 不在此映射中,主应用 target 直接使用 app_identifier
|
|
117
118
|
def get_target_name_map
|
|
118
119
|
return {
|
|
119
|
-
"MainTarget" => "bundle_id",
|
|
120
120
|
"Content" => "bundle_id_pushcontent",
|
|
121
121
|
"Service" => "bundle_id_pushservice",
|
|
122
122
|
"Keyboard" => "bundle_id_keyboard",
|
|
@@ -143,24 +143,47 @@ module Pindo
|
|
|
143
143
|
end
|
|
144
144
|
|
|
145
145
|
project_obj.targets.each do |target|
|
|
146
|
+
# 跳过非 native target(如 PBXAggregateTarget)
|
|
147
|
+
next unless target.respond_to?(:product_type)
|
|
146
148
|
|
|
147
149
|
exe_binary_name = config_json['app_info']['app_display_name']
|
|
148
150
|
exe_binary_name = exe_binary_name.gsub(/ /, '');
|
|
149
151
|
exe_binary_name = exe_binary_name.gsub(/\'/, '');
|
|
150
152
|
|
|
153
|
+
target_name_map = get_target_name_map
|
|
154
|
+
|
|
155
|
+
# 根据 target 类型确定 bundle_id
|
|
156
|
+
target_bundle_id = nil
|
|
157
|
+
if target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application])
|
|
158
|
+
# 主应用 target:使用 app_identifier
|
|
159
|
+
target_bundle_id = config_json['app_info']['app_identifier']
|
|
160
|
+
else
|
|
161
|
+
# 扩展 target:从 target_name_map 查找对应的 bundle_id
|
|
162
|
+
# target_name_map 的 value 是 bundle_id_* 格式,config_json 中实际字段名是 app_identifier_*
|
|
163
|
+
target_name_map.each do |suffix, config_key|
|
|
164
|
+
if target.name.to_s.end_with?(suffix)
|
|
165
|
+
json_key = config_key.sub('bundle_id_', 'app_identifier_')
|
|
166
|
+
target_bundle_id = config_json['app_info'][json_key]
|
|
167
|
+
break
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
151
172
|
target.build_configurations.each do |config|
|
|
152
173
|
config.build_settings['CURRENT_PROJECT_VERSION'] = config_json['app_info']['app_build_version']
|
|
153
174
|
config.build_settings['MARKETING_VERSION'] = config_json['app_info']['app_version']
|
|
154
175
|
config.build_settings['INFOPLIST_KEY_CFBundleDisplayName'] = config_json['app_info']['app_display_name']
|
|
176
|
+
if target_bundle_id && !target_bundle_id.empty? && !target_bundle_id.include?("*")
|
|
177
|
+
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = target_bundle_id
|
|
178
|
+
end
|
|
155
179
|
end
|
|
156
180
|
|
|
157
|
-
|
|
158
|
-
if target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application])
|
|
181
|
+
if target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application])
|
|
159
182
|
target.build_configurations.each do |config|
|
|
160
183
|
config.build_settings['PRODUCT_NAME'] = exe_binary_name
|
|
161
184
|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = ios_deployment_targe
|
|
162
185
|
end
|
|
163
|
-
|
|
186
|
+
else
|
|
164
187
|
target_name_map.each do |k, v|
|
|
165
188
|
if target.name.to_s.end_with?(k)
|
|
166
189
|
target.build_configurations.each do |config|
|
|
@@ -321,33 +344,171 @@ module Pindo
|
|
|
321
344
|
|
|
322
345
|
end
|
|
323
346
|
|
|
347
|
+
# 解析 INFOPLIST_FILE 路径,处理 Xcode 变量和引号
|
|
348
|
+
# @param project_dir [String] 项目目录
|
|
349
|
+
# @param raw_path [String] INFOPLIST_FILE 原始值
|
|
350
|
+
# @param target [Xcodeproj::Project::Object::PBXNativeTarget, nil] target(用于解析 TARGET_NAME 等变量)
|
|
351
|
+
# @return [String, nil] 解析后的绝对路径,文件不存在时返回 nil
|
|
352
|
+
def resolve_info_plist_path(project_dir, raw_path, target: nil)
|
|
353
|
+
return nil if raw_path.nil? || raw_path.empty?
|
|
354
|
+
|
|
355
|
+
# 去除首尾引号
|
|
356
|
+
resolved = raw_path.gsub(/\A["']|["']\z/, '')
|
|
357
|
+
|
|
358
|
+
# 解析 Xcode 变量
|
|
359
|
+
resolved = resolved
|
|
360
|
+
.gsub('$(SRCROOT)', project_dir)
|
|
361
|
+
.gsub('${SRCROOT}', project_dir)
|
|
362
|
+
.gsub('$(PROJECT_DIR)', project_dir)
|
|
363
|
+
.gsub('${PROJECT_DIR}', project_dir)
|
|
364
|
+
|
|
365
|
+
# 解析 target 相关变量
|
|
366
|
+
if target
|
|
367
|
+
target_name = target.name.to_s
|
|
368
|
+
resolved = resolved
|
|
369
|
+
.gsub('$(TARGET_NAME)', target_name)
|
|
370
|
+
.gsub('${TARGET_NAME}', target_name)
|
|
371
|
+
|
|
372
|
+
# PRODUCT_NAME 从 build settings 获取,降级到 TARGET_NAME
|
|
373
|
+
product_name = target.build_configurations.first.build_settings['PRODUCT_NAME'] || target_name
|
|
374
|
+
# PRODUCT_NAME 本身可能是 $(TARGET_NAME),递归替换
|
|
375
|
+
product_name = product_name
|
|
376
|
+
.gsub('$(TARGET_NAME)', target_name)
|
|
377
|
+
.gsub('${TARGET_NAME}', target_name)
|
|
378
|
+
resolved = resolved
|
|
379
|
+
.gsub('$(PRODUCT_NAME)', product_name)
|
|
380
|
+
.gsub('${PRODUCT_NAME}', product_name)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# 如果仍有未解析的变量,尝试去掉变量部分做 glob 匹配
|
|
384
|
+
if resolved.match?(/\$[\({]/)
|
|
385
|
+
# 将未解析的变量替换为通配符,尝试 glob 查找
|
|
386
|
+
glob_pattern = resolved.gsub(/\$[\({][^)\}]+[\)}]/, '*')
|
|
387
|
+
glob_path = File.absolute_path?(glob_pattern) ? glob_pattern : File.join(project_dir, glob_pattern)
|
|
388
|
+
matches = Dir.glob(glob_path)
|
|
389
|
+
return matches.first if matches.size == 1
|
|
390
|
+
if matches.size > 1
|
|
391
|
+
Funlog.instance.fancyinfo_warning("INFOPLIST_FILE 变量解析后匹配到多个文件: #{matches.join(', ')},跳过")
|
|
392
|
+
end
|
|
393
|
+
return nil
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
# 如果是相对路径,拼接 project_dir
|
|
397
|
+
abs_path = File.absolute_path?(resolved) ? resolved : File.join(project_dir, resolved)
|
|
398
|
+
File.exist?(abs_path) ? abs_path : nil
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# 确保 Info.plist 文件存在,不存在时自动创建并配置 Xcode 工程
|
|
402
|
+
# 仅在需要写入复杂配置(URL Schemes 等)时调用
|
|
403
|
+
# @param project_dir [String] 项目目录
|
|
404
|
+
# @param target [Xcodeproj::Project::Object::PBXNativeTarget] Xcode target
|
|
405
|
+
# @param project_obj [Xcodeproj::Project] Xcode 工程对象
|
|
406
|
+
# @return [String, nil] Info.plist 文件路径
|
|
407
|
+
def ensure_info_plist_exists(project_dir:, target:, project_obj:)
|
|
408
|
+
# 1. 尝试从 build settings 获取已有路径
|
|
409
|
+
raw_path = target.build_configurations.first.build_settings['INFOPLIST_FILE']
|
|
410
|
+
existing_path = resolve_info_plist_path(project_dir, raw_path, target: target)
|
|
411
|
+
return existing_path if existing_path
|
|
412
|
+
|
|
413
|
+
# 2. 检查是否是 GENERATE_INFOPLIST_FILE=YES 的合法模式
|
|
414
|
+
generate_flag = target.build_configurations.first.build_settings['GENERATE_INFOPLIST_FILE']
|
|
415
|
+
is_generated_mode = (generate_flag.to_s.upcase == 'YES') && (raw_path.nil? || raw_path.empty?)
|
|
416
|
+
|
|
417
|
+
# 3. 创建 Info.plist(GENERATE_INFOPLIST_FILE 模式下作为补充 plist,Xcode 会合并)
|
|
418
|
+
target_name = target.name.to_s
|
|
419
|
+
# 优先使用原始 INFOPLIST_FILE 路径(用已知变量替换后)创建,避免覆盖工程配置
|
|
420
|
+
if raw_path && !raw_path.empty?
|
|
421
|
+
# 用 resolve 中相同的变量替换逻辑解析路径(不检查文件是否存在)
|
|
422
|
+
resolved_raw = raw_path
|
|
423
|
+
.gsub(/\A["']|["']\z/, '')
|
|
424
|
+
.gsub('$(SRCROOT)', project_dir).gsub('${SRCROOT}', project_dir)
|
|
425
|
+
.gsub('$(PROJECT_DIR)', project_dir).gsub('${PROJECT_DIR}', project_dir)
|
|
426
|
+
.gsub('$(TARGET_NAME)', target_name).gsub('${TARGET_NAME}', target_name)
|
|
427
|
+
product_name = target.build_configurations.first.build_settings['PRODUCT_NAME'] || target_name
|
|
428
|
+
product_name = product_name.gsub('$(TARGET_NAME)', target_name).gsub('${TARGET_NAME}', target_name)
|
|
429
|
+
resolved_raw = resolved_raw.gsub('$(PRODUCT_NAME)', product_name).gsub('${PRODUCT_NAME}', product_name)
|
|
430
|
+
|
|
431
|
+
# 如果仍含未解析变量,降级到 target_name/Info.plist
|
|
432
|
+
if resolved_raw.match?(/\$[\({]/)
|
|
433
|
+
relative_plist_path = "#{target_name}/Info.plist"
|
|
434
|
+
elsif File.absolute_path?(resolved_raw)
|
|
435
|
+
# 绝对路径转为相对路径
|
|
436
|
+
relative_plist_path = resolved_raw.sub(/\A#{Regexp.escape(project_dir)}\//, '')
|
|
437
|
+
else
|
|
438
|
+
relative_plist_path = resolved_raw
|
|
439
|
+
end
|
|
440
|
+
else
|
|
441
|
+
relative_plist_path = "#{target_name}/Info.plist"
|
|
442
|
+
end
|
|
443
|
+
info_plist_path = File.join(project_dir, relative_plist_path)
|
|
444
|
+
|
|
445
|
+
if is_generated_mode
|
|
446
|
+
Funlog.instance.fancyinfo_warning("Target #{target_name} 使用 GENERATE_INFOPLIST_FILE 模式,创建补充 Info.plist 用于复杂配置")
|
|
447
|
+
else
|
|
448
|
+
Funlog.instance.fancyinfo_warning("Target #{target_name} 未找到 Info.plist,自动创建: #{relative_plist_path}")
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
# 3.1 创建目录和最小 Info.plist
|
|
452
|
+
FileUtils.mkdir_p(File.dirname(info_plist_path))
|
|
453
|
+
empty_plist = {}
|
|
454
|
+
Xcodeproj::Plist.write_to_path(empty_plist, info_plist_path)
|
|
455
|
+
|
|
456
|
+
# 3.2 设置 build settings
|
|
457
|
+
target.build_configurations.each do |config|
|
|
458
|
+
config.build_settings['INFOPLIST_FILE'] = relative_plist_path
|
|
459
|
+
# 保持 GENERATE_INFOPLIST_FILE = YES,Xcode 自动合并
|
|
460
|
+
config.build_settings['GENERATE_INFOPLIST_FILE'] ||= 'YES'
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# 3.3 将文件添加到 Xcode 工程引用,保持与实际相对路径一致
|
|
464
|
+
plist_dir = File.dirname(relative_plist_path)
|
|
465
|
+
plist_name = File.basename(relative_plist_path)
|
|
466
|
+
target_group =
|
|
467
|
+
if plist_dir == "." || plist_dir.empty?
|
|
468
|
+
project_obj.main_group.find_subpath(target_name, true)
|
|
469
|
+
else
|
|
470
|
+
project_obj.main_group.find_subpath(plist_dir, true)
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
unless target_group.files.any? { |f| f.path == plist_name } ||
|
|
474
|
+
project_obj.files.any? { |f| f.path == relative_plist_path }
|
|
475
|
+
target_group.new_file(plist_name)
|
|
476
|
+
Funlog.instance.fancyinfo_success("已将 Info.plist 添加到 Xcode 工程: #{relative_plist_path}")
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
project_obj.save
|
|
480
|
+
|
|
481
|
+
info_plist_path
|
|
482
|
+
end
|
|
483
|
+
|
|
324
484
|
def modify_info_plist(project_dir:nil, proj_name:nil, config_json:nil)
|
|
325
485
|
|
|
326
486
|
## Main Info.plist
|
|
327
487
|
proj_fullname = File.join(project_dir, proj_name) + ".xcodeproj"
|
|
328
488
|
project_obj = Xcodeproj::Project.open(proj_fullname)
|
|
329
489
|
|
|
330
|
-
info_plist_path = nil
|
|
331
490
|
project_obj.targets.each do |target|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
#
|
|
338
|
-
#
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
491
|
+
# 跳过非 native target(如 PBXAggregateTarget)
|
|
492
|
+
next unless target.respond_to?(:product_type)
|
|
493
|
+
|
|
494
|
+
is_app_target = target.product_type.to_s.eql?("com.apple.product-type.application")
|
|
495
|
+
|
|
496
|
+
# 主应用 target:确保 Info.plist 存在(需要写入 URL Schemes 等复杂配置)
|
|
497
|
+
# 非主应用 target:仅在已有 Info.plist 时修改,不强制创建
|
|
498
|
+
if is_app_target
|
|
499
|
+
info_plist_path = ensure_info_plist_exists(
|
|
500
|
+
project_dir: project_dir,
|
|
501
|
+
target: target,
|
|
502
|
+
project_obj: project_obj
|
|
503
|
+
)
|
|
504
|
+
else
|
|
505
|
+
raw_path = target.build_configurations.first.build_settings['INFOPLIST_FILE']
|
|
506
|
+
info_plist_path = resolve_info_plist_path(project_dir, raw_path, target: target)
|
|
348
507
|
end
|
|
349
508
|
|
|
350
|
-
if
|
|
509
|
+
next if info_plist_path.nil?
|
|
510
|
+
|
|
511
|
+
if is_app_target
|
|
351
512
|
modify_maintarget_info_plist(plist_file_name:info_plist_path, config_json:config_json, target_name:proj_name)
|
|
352
513
|
end
|
|
353
514
|
|
|
@@ -513,7 +674,7 @@ module Pindo
|
|
|
513
674
|
project_obj = Xcodeproj::Project.open(project_fullname)
|
|
514
675
|
|
|
515
676
|
project_build_platform = project_obj.root_object.build_configuration_list.get_setting("SDKROOT")["Release"]
|
|
516
|
-
main_target = project_obj.targets.select { |target| target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]) }.first
|
|
677
|
+
main_target = project_obj.targets.select { |target| target.respond_to?(:product_type) && target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]) }.first
|
|
517
678
|
provisioning_profile_name = main_target.build_configurations.first.build_settings['PROVISIONING_PROFILE_SPECIFIER'].downcase
|
|
518
679
|
|
|
519
680
|
# 确定构建类型和 iCloud 环境
|
|
@@ -125,7 +125,7 @@ module Pindo
|
|
|
125
125
|
config.build_settings['CODE_SIGN_IDENTITY'] = "iPhone Developer"
|
|
126
126
|
config.build_settings['DEVELOPMENT_TEAM'] = "9WX2E4VC26"
|
|
127
127
|
config.build_settings['PROVISIONING_PROFILE'] = ""
|
|
128
|
-
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = bundle_id unless bundle_id.
|
|
128
|
+
config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = bundle_id unless bundle_id.include?("*")
|
|
129
129
|
config.build_settings['PROVISIONING_PROFILE_SPECIFIER'] = "match Development " + bundle_id
|
|
130
130
|
# config.build_settings['TARGETED_DEVICE_FAMILY'] = "1,2"
|
|
131
131
|
if is_extention
|
|
@@ -8,23 +8,38 @@ module Pindo
|
|
|
8
8
|
|
|
9
9
|
class XcodeResHelper
|
|
10
10
|
class << self
|
|
11
|
+
def macos_project?(proj_dir)
|
|
12
|
+
xcodeproj_file_name = Dir.glob(File.join(proj_dir, "*.xcodeproj")).max_by { |f| File.mtime(f) }
|
|
13
|
+
return false if xcodeproj_file_name.nil?
|
|
14
|
+
|
|
15
|
+
project_obj = Xcodeproj::Project.open(xcodeproj_file_name)
|
|
16
|
+
sdkroot_settings = project_obj.root_object.build_configuration_list.get_setting("SDKROOT")
|
|
17
|
+
sdkroot = sdkroot_settings.values.compact.first
|
|
18
|
+
!sdkroot.nil? && sdkroot.eql?("macosx")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def image_dimensions(image_data)
|
|
22
|
+
width, height = image_data.fetch("size").split("x").map(&:to_f)
|
|
23
|
+
scale = image_data.fetch("scale", "1x").to_s.chomp("x").to_f
|
|
24
|
+
|
|
25
|
+
[
|
|
26
|
+
(width * scale).to_i,
|
|
27
|
+
(height * scale).to_i
|
|
28
|
+
]
|
|
29
|
+
end
|
|
11
30
|
|
|
12
31
|
def create_icon(icon_name:nil, new_icon_dir:nil, xcode_icon_json:nil)
|
|
13
32
|
if !File.exist?(icon_name)
|
|
14
33
|
raise Informative, "文件不存在:#{icon_name}"
|
|
15
34
|
end
|
|
16
35
|
xcode_icon_json["images"].each do |image_data|
|
|
17
|
-
width,height
|
|
36
|
+
width, height = image_dimensions(image_data)
|
|
18
37
|
image_name = image_data["filename"]
|
|
19
|
-
|
|
20
|
-
width = width.to_f * iNum
|
|
21
|
-
height = height.to_f * iNum
|
|
22
|
-
|
|
23
|
-
width = width.to_i
|
|
24
|
-
height = height.to_i
|
|
38
|
+
next if image_name.nil? || image_name.empty?
|
|
25
39
|
|
|
26
40
|
command = [
|
|
27
41
|
'sips',
|
|
42
|
+
'-s', 'format', 'png',
|
|
28
43
|
'--matchTo', '/System/Library/ColorSync/Profiles/sRGB Profile.icc',
|
|
29
44
|
'-z', width.to_s, height.to_s,
|
|
30
45
|
icon_name,
|
|
@@ -48,14 +63,9 @@ module Pindo
|
|
|
48
63
|
raise Informative, "文件不存在:#{image_icon_name} or #{icon_name}"
|
|
49
64
|
end
|
|
50
65
|
xcode_icon_json["images"].each do |image_data|
|
|
51
|
-
|
|
52
|
-
height, width = image_data["size"].split("x")
|
|
66
|
+
width, height = image_dimensions(image_data)
|
|
53
67
|
image_name = image_data["filename"]
|
|
54
|
-
|
|
55
|
-
width = width.to_f * iNum
|
|
56
|
-
height = height.to_f * iNum
|
|
57
|
-
width = width.to_i
|
|
58
|
-
height = height.to_i
|
|
68
|
+
next if image_name.nil? || image_name.empty?
|
|
59
69
|
|
|
60
70
|
icon_ori_name = image_icon_name
|
|
61
71
|
if width.to_s.eql?(height.to_s)
|
|
@@ -64,6 +74,7 @@ module Pindo
|
|
|
64
74
|
|
|
65
75
|
command = [
|
|
66
76
|
'sips',
|
|
77
|
+
'-s', 'format', 'png',
|
|
67
78
|
'--matchTo', '/System/Library/ColorSync/Profiles/sRGB Profile.icc',
|
|
68
79
|
'-z', width.to_s, height.to_s,
|
|
69
80
|
icon_ori_name,
|
|
@@ -77,13 +88,18 @@ module Pindo
|
|
|
77
88
|
end
|
|
78
89
|
end
|
|
79
90
|
|
|
80
|
-
def create_icons(icon_name:nil, new_icon_dir:nil)
|
|
91
|
+
def create_icons(icon_name:nil, new_icon_dir:nil, proj_dir:nil)
|
|
81
92
|
begin
|
|
82
93
|
FileUtils.mkdir_p(new_icon_dir)
|
|
83
94
|
rescue => e
|
|
84
95
|
puts e
|
|
85
96
|
end
|
|
86
|
-
|
|
97
|
+
xcode_icon_json = if !proj_dir.nil? && macos_project?(proj_dir)
|
|
98
|
+
XcodoeResConst.xcode_macos_icon_json
|
|
99
|
+
else
|
|
100
|
+
XcodoeResConst.xcode_ios_icon_json
|
|
101
|
+
end
|
|
102
|
+
create_icon(icon_name: icon_name, new_icon_dir: new_icon_dir, xcode_icon_json: xcode_icon_json)
|
|
87
103
|
icon_dir = File.dirname(icon_name)
|
|
88
104
|
imessage_icon = File.join(icon_dir, "icon1024_768.png")
|
|
89
105
|
new_imessage_icon_dir = File.join(new_icon_dir, "imessage")
|
|
@@ -19,13 +19,13 @@ module Pindo
|
|
|
19
19
|
type: String,
|
|
20
20
|
env_name: 'PINDO_BUNDLE_ID',
|
|
21
21
|
optional: true,
|
|
22
|
-
cacheable:
|
|
22
|
+
cacheable: false, # 从 JPSBuildConfig.json 获取,不需要缓存
|
|
23
23
|
verify_block: proc do |value|
|
|
24
24
|
unless value =~ /^[a-zA-Z0-9\-\.\*]+$/
|
|
25
25
|
raise "Bundle ID 格式错误: #{value},应该类似 com.example.app"
|
|
26
26
|
end
|
|
27
27
|
end,
|
|
28
|
-
example: 'pindo ios autobuild --bundleid=com.example
|
|
28
|
+
example: 'pindo ios autobuild --bundleid=com.example.*'
|
|
29
29
|
),
|
|
30
30
|
|
|
31
31
|
bundle_name: OptionItem.new(
|
|
@@ -35,14 +35,14 @@ module Pindo
|
|
|
35
35
|
type: String,
|
|
36
36
|
env_name: 'PINDO_BUNDLE_NAME',
|
|
37
37
|
optional: true,
|
|
38
|
-
cacheable:
|
|
38
|
+
cacheable: false, # 从 JPSBuildConfig.json 获取,不需要缓存
|
|
39
39
|
verify_block: proc do |value|
|
|
40
40
|
# 允许标准格式(com.example.app)或带通配符格式(com.example.*)
|
|
41
|
-
unless value =~
|
|
41
|
+
unless value =~ /\A[a-z][a-z0-9_]*(\.(?:[a-z][a-z0-9_]*|\*))+\z/i
|
|
42
42
|
raise "Package Name 格式错误: #{value},应该类似 com.example.app 或 com.example.*"
|
|
43
43
|
end
|
|
44
44
|
end,
|
|
45
|
-
example: 'pindo android autobuild --bundle_name=com.example
|
|
45
|
+
example: 'pindo android autobuild --bundle_name=com.example.*'
|
|
46
46
|
),
|
|
47
47
|
|
|
48
48
|
build_type: OptionItem.new(
|
|
@@ -81,19 +81,19 @@ module Pindo
|
|
|
81
81
|
git_commit: OptionItem.new(
|
|
82
82
|
key: :git_commit,
|
|
83
83
|
name: 'Git 未提交处理方式',
|
|
84
|
-
description: '处理未提交文件的方式: commit/skip/reset/stash/exit',
|
|
84
|
+
description: '处理未提交文件的方式: commit/skip-with-tag/skip-without-tag/reset/stash/exit',
|
|
85
85
|
type: String,
|
|
86
86
|
env_name: 'PINDO_GIT_COMMIT',
|
|
87
87
|
default_value: nil,
|
|
88
88
|
optional: true,
|
|
89
89
|
cacheable: false,
|
|
90
90
|
verify_block: proc do |value|
|
|
91
|
-
allowed = %w[commit skip reset delete stash exit resetde discard]
|
|
91
|
+
allowed = %w[commit skip-with-tag skip-without-tag reset delete stash exit resetde discard]
|
|
92
92
|
unless allowed.include?(value.to_s.downcase)
|
|
93
93
|
raise "git_commit 值错误: #{value}, 必须是 #{allowed.join(', ')} 之一"
|
|
94
94
|
end
|
|
95
95
|
end,
|
|
96
|
-
example: 'pindo unity autobuild --git-commit=skip'
|
|
96
|
+
example: 'pindo unity autobuild --git-commit=skip-with-tag'
|
|
97
97
|
)
|
|
98
98
|
}
|
|
99
99
|
end
|
|
@@ -122,8 +122,10 @@ module Pindo
|
|
|
122
122
|
case value.to_s.downcase
|
|
123
123
|
when 'commit', 'comm'
|
|
124
124
|
Pindo::UncommittedFilesProcessType::COMMIT
|
|
125
|
-
when 'skip'
|
|
126
|
-
Pindo::UncommittedFilesProcessType::
|
|
125
|
+
when 'skip-with-tag'
|
|
126
|
+
Pindo::UncommittedFilesProcessType::SKIP_WITH_TAG
|
|
127
|
+
when 'skip-without-tag'
|
|
128
|
+
Pindo::UncommittedFilesProcessType::SKIP_WITHOUT_TAG
|
|
127
129
|
when 'reset', 'delete', 'resetde', 'discard'
|
|
128
130
|
Pindo::UncommittedFilesProcessType::RESET
|
|
129
131
|
when 'stash'
|
|
@@ -41,6 +41,17 @@ module Pindo
|
|
|
41
41
|
default_value: false,
|
|
42
42
|
optional: true,
|
|
43
43
|
example: 'pindo unity autobuild --skipyoo'
|
|
44
|
+
),
|
|
45
|
+
|
|
46
|
+
kill_unity: OptionItem.new(
|
|
47
|
+
key: :kill_unity,
|
|
48
|
+
name: '自动关闭Unity',
|
|
49
|
+
description: '自动关闭检测到的Unity进程(不询问用户确认)',
|
|
50
|
+
type: OptionItem::Boolean,
|
|
51
|
+
env_name: 'PINDO_KILL_UNITY',
|
|
52
|
+
default_value: false,
|
|
53
|
+
optional: true,
|
|
54
|
+
example: 'pindo unity autobuild --kill-unity'
|
|
44
55
|
)
|
|
45
56
|
}
|
|
46
57
|
end
|
|
@@ -94,6 +94,31 @@ module Pindo
|
|
|
94
94
|
bundleids
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
+
# 加载 all_bundleid_group 映射表
|
|
98
|
+
# @return [Hash] group_name => bundle_id 的映射,如 {"fancyapptest" => "com.heroneverdie101.fancyapptest"}
|
|
99
|
+
def self.load_bundleid_group
|
|
100
|
+
config_file = File.join(pindo_env_configdir, 'bundleid_config.json')
|
|
101
|
+
return {} unless File.exist?(config_file)
|
|
102
|
+
|
|
103
|
+
begin
|
|
104
|
+
config = JSON.parse(File.read(config_file))
|
|
105
|
+
config['all_bundleid_group'] || {}
|
|
106
|
+
rescue => e
|
|
107
|
+
puts "加载 bundleid_config.json 失败: #{e.message}"
|
|
108
|
+
{}
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# 通过 group name 查找真实 bundle ID
|
|
113
|
+
# @param group_name [String] 组名(如 "fancyapptest"、"wildcarddevelopmentid")
|
|
114
|
+
# @return [String, nil] 真实 bundle ID(如 "com.heroneverdie101.fancyapptest"),未找到返回 nil
|
|
115
|
+
def self.resolve_bundleid_by_group_name(group_name)
|
|
116
|
+
return nil if group_name.nil? || group_name.empty?
|
|
117
|
+
|
|
118
|
+
group = load_bundleid_group
|
|
119
|
+
group[group_name]
|
|
120
|
+
end
|
|
121
|
+
|
|
97
122
|
# 获取 pindo 环境配置目录
|
|
98
123
|
def self.pindo_env_configdir
|
|
99
124
|
require_relative '../../config/pindoconfig'
|
|
@@ -18,11 +18,12 @@ module Pindo
|
|
|
18
18
|
# Git 未提交文件处理类型枚举
|
|
19
19
|
# 用于控制构建前未提交文件的处理方式
|
|
20
20
|
module UncommittedFilesProcessType
|
|
21
|
-
COMMIT = :commit
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
COMMIT = :commit # 自动提交所有更改
|
|
22
|
+
SKIP_WITH_TAG = :skip_with_tag # 不提交,但合并分支并打 tag
|
|
23
|
+
SKIP_WITHOUT_TAG = :skip_without_tag # 不提交,不合并分支,不打 tag
|
|
24
|
+
RESET = :reset # 丢弃所有更改,重置到远程
|
|
25
|
+
STASH = :stash # 保存到 stash 区域
|
|
26
|
+
EXIT = :exit # 退出程序,要求手动处理
|
|
27
|
+
NONE = :none # 没有需要提交的内容
|
|
27
28
|
end
|
|
28
29
|
end
|
data/lib/pindo/version.rb
CHANGED
|
@@ -6,13 +6,13 @@ require 'time'
|
|
|
6
6
|
|
|
7
7
|
module Pindo
|
|
8
8
|
|
|
9
|
-
VERSION = "5.
|
|
9
|
+
VERSION = "5.18.3"
|
|
10
10
|
|
|
11
11
|
class VersionCheck
|
|
12
12
|
RUBYGEMS_API = 'https://rubygems.org/api/v1/gems/pindo.json'
|
|
13
13
|
VERSION_INFO_FILE = File.expand_path('~/.pindo/version_info.yml')
|
|
14
14
|
CHECK_INTERVAL = 5 * 60 * 60 # 5小时检查一次
|
|
15
|
-
CONFIG_MIN_VERSION = '1.
|
|
15
|
+
CONFIG_MIN_VERSION = '1.7.0' # 硬编码的配置版本要求
|
|
16
16
|
|
|
17
17
|
class << self
|
|
18
18
|
# 主版本检查方法(保持向后兼容)
|
|
@@ -557,4 +557,4 @@ module Pindo
|
|
|
557
557
|
end
|
|
558
558
|
end
|
|
559
559
|
end
|
|
560
|
-
end
|
|
560
|
+
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pindo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.18.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- wade
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: claide
|
|
@@ -109,20 +109,20 @@ dependencies:
|
|
|
109
109
|
requirements:
|
|
110
110
|
- - "~>"
|
|
111
111
|
- !ruby/object:Gem::Version
|
|
112
|
-
version: '2.
|
|
112
|
+
version: '2.2'
|
|
113
113
|
- - ">="
|
|
114
114
|
- !ruby/object:Gem::Version
|
|
115
|
-
version: 2.0
|
|
115
|
+
version: 2.2.0
|
|
116
116
|
type: :runtime
|
|
117
117
|
prerelease: false
|
|
118
118
|
version_requirements: !ruby/object:Gem::Requirement
|
|
119
119
|
requirements:
|
|
120
120
|
- - "~>"
|
|
121
121
|
- !ruby/object:Gem::Version
|
|
122
|
-
version: '2.
|
|
122
|
+
version: '2.2'
|
|
123
123
|
- - ">="
|
|
124
124
|
- !ruby/object:Gem::Version
|
|
125
|
-
version: 2.0
|
|
125
|
+
version: 2.2.0
|
|
126
126
|
- !ruby/object:Gem::Dependency
|
|
127
127
|
name: rqrcode
|
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -304,6 +304,7 @@ files:
|
|
|
304
304
|
- lib/pindo/command/appstore/quswauth.rb
|
|
305
305
|
- lib/pindo/command/appstore/screenshots.rb
|
|
306
306
|
- lib/pindo/command/appstore/tag.rb
|
|
307
|
+
- lib/pindo/command/appstore/updateid.rb
|
|
307
308
|
- lib/pindo/command/appstore/upload.rb
|
|
308
309
|
- lib/pindo/command/env.rb
|
|
309
310
|
- lib/pindo/command/env/dreamstudio.rb
|
|
@@ -348,14 +349,17 @@ files:
|
|
|
348
349
|
- lib/pindo/command/unity/packinit.rb
|
|
349
350
|
- lib/pindo/command/unity/packpush.rb
|
|
350
351
|
- lib/pindo/command/utils.rb
|
|
352
|
+
- lib/pindo/command/utils/allcopyconfig.rb
|
|
351
353
|
- lib/pindo/command/utils/boss.rb
|
|
352
354
|
- lib/pindo/command/utils/clearcert.rb
|
|
355
|
+
- lib/pindo/command/utils/copyconfig.rb
|
|
353
356
|
- lib/pindo/command/utils/decrypt.rb
|
|
354
357
|
- lib/pindo/command/utils/device.rb
|
|
355
358
|
- lib/pindo/command/utils/encrypt.rb
|
|
356
359
|
- lib/pindo/command/utils/fabric.rb
|
|
357
360
|
- lib/pindo/command/utils/icon.rb
|
|
358
361
|
- lib/pindo/command/utils/installskills.rb
|
|
362
|
+
- lib/pindo/command/utils/renewbundleid.rb
|
|
359
363
|
- lib/pindo/command/utils/renewcert.rb
|
|
360
364
|
- lib/pindo/command/utils/renewproj.rb
|
|
361
365
|
- lib/pindo/command/utils/repoinit.rb
|
|
@@ -379,6 +383,7 @@ files:
|
|
|
379
383
|
- lib/pindo/module/android/gradle_helper.rb
|
|
380
384
|
- lib/pindo/module/android/java_env_helper.rb
|
|
381
385
|
- lib/pindo/module/android/keystore_helper.rb
|
|
386
|
+
- lib/pindo/module/android/workflow_gradle_injector.rb
|
|
382
387
|
- lib/pindo/module/appselect.rb
|
|
383
388
|
- lib/pindo/module/appstore/appstore_iap_tier.json
|
|
384
389
|
- lib/pindo/module/appstore/appstore_in_app_purchase.rb
|
|
@@ -511,7 +516,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
511
516
|
- !ruby/object:Gem::Version
|
|
512
517
|
version: 3.0.0
|
|
513
518
|
requirements: []
|
|
514
|
-
rubygems_version:
|
|
519
|
+
rubygems_version: 4.0.3
|
|
515
520
|
specification_version: 4
|
|
516
521
|
summary: easy work
|
|
517
522
|
test_files: []
|