pindo 5.17.5 → 5.18.4
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 +81 -40
- 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/jps/apptest.rb +2 -2
- data/lib/pindo/command/jps/bind.rb +1 -1
- data/lib/pindo/command/jps/media.rb +1 -1
- data/lib/pindo/command/jps/upload.rb +52 -22
- data/lib/pindo/command/unity/autobuild.rb +61 -44
- 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 +32 -26
- data/lib/pindo/config/build_info_manager.rb +1 -3
- data/lib/pindo/module/android/android_build_helper.rb +193 -33
- data/lib/pindo/module/android/android_config_helper.rb +305 -88
- data/lib/pindo/module/android/android_project_helper.rb +69 -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 +110 -10
- data/lib/pindo/module/build/git_repo_helper.rb +4 -4
- data/lib/pindo/module/cert/mode/base_cert_operator.rb +8 -6
- data/lib/pindo/module/pgyer/pgyerhelper.rb +105 -42
- data/lib/pindo/module/task/core/task_executor.rb +2 -0
- 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 +104 -1
- 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/task/task_manager.rb +8 -0
- 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 +4 -2
- data/lib/pindo/module/xcode/res/xcode_res_constant.rb +72 -0
- data/lib/pindo/module/xcode/xcode_build_config.rb +36 -17
- data/lib/pindo/module/xcode/xcode_build_helper.rb +180 -23
- 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 +16 -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 +2 -2
- metadata +10 -5
|
@@ -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",
|
|
@@ -150,19 +150,40 @@ module Pindo
|
|
|
150
150
|
exe_binary_name = exe_binary_name.gsub(/ /, '');
|
|
151
151
|
exe_binary_name = exe_binary_name.gsub(/\'/, '');
|
|
152
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
|
+
|
|
153
172
|
target.build_configurations.each do |config|
|
|
154
173
|
config.build_settings['CURRENT_PROJECT_VERSION'] = config_json['app_info']['app_build_version']
|
|
155
174
|
config.build_settings['MARKETING_VERSION'] = config_json['app_info']['app_version']
|
|
156
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
|
|
157
179
|
end
|
|
158
180
|
|
|
159
|
-
|
|
160
|
-
if target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application])
|
|
181
|
+
if target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application])
|
|
161
182
|
target.build_configurations.each do |config|
|
|
162
183
|
config.build_settings['PRODUCT_NAME'] = exe_binary_name
|
|
163
184
|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = ios_deployment_targe
|
|
164
185
|
end
|
|
165
|
-
|
|
186
|
+
else
|
|
166
187
|
target_name_map.each do |k, v|
|
|
167
188
|
if target.name.to_s.end_with?(k)
|
|
168
189
|
target.build_configurations.each do |config|
|
|
@@ -323,35 +344,171 @@ module Pindo
|
|
|
323
344
|
|
|
324
345
|
end
|
|
325
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
|
+
|
|
326
484
|
def modify_info_plist(project_dir:nil, proj_name:nil, config_json:nil)
|
|
327
485
|
|
|
328
486
|
## Main Info.plist
|
|
329
487
|
proj_fullname = File.join(project_dir, proj_name) + ".xcodeproj"
|
|
330
488
|
project_obj = Xcodeproj::Project.open(proj_fullname)
|
|
331
489
|
|
|
332
|
-
info_plist_path = nil
|
|
333
490
|
project_obj.targets.each do |target|
|
|
334
491
|
# 跳过非 native target(如 PBXAggregateTarget)
|
|
335
492
|
next unless target.respond_to?(:product_type)
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if target.product_type.to_s.eql?("com.apple.product-type.application") && (info_plist_path.nil? || !File.exist?(info_plist_path))
|
|
351
|
-
raise Informative, "Target #{target.name.to_s} 没有找到Info.plist, 修改Info.plist出错了!!"
|
|
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)
|
|
352
507
|
end
|
|
353
508
|
|
|
354
|
-
if
|
|
509
|
+
next if info_plist_path.nil?
|
|
510
|
+
|
|
511
|
+
if is_app_target
|
|
355
512
|
modify_maintarget_info_plist(plist_file_name:info_plist_path, config_json:config_json, target_name:proj_name)
|
|
356
513
|
end
|
|
357
514
|
|
|
@@ -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(
|
|
@@ -71,6 +71,17 @@ module Pindo
|
|
|
71
71
|
env_name: 'PINDO_SCHEME',
|
|
72
72
|
optional: true,
|
|
73
73
|
example: 'pindo ios autobuild --scheme=MyAppScheme'
|
|
74
|
+
),
|
|
75
|
+
|
|
76
|
+
types: OptionItem.new(
|
|
77
|
+
key: :types,
|
|
78
|
+
name: '包类型',
|
|
79
|
+
description: '指定包类型,逗号分隔(ipa,apk,html,mac,exe)',
|
|
80
|
+
type: String,
|
|
81
|
+
env_name: 'PINDO_BUILD_TYPES',
|
|
82
|
+
optional: true,
|
|
83
|
+
cacheable: false,
|
|
84
|
+
example: 'pindo unity autobuild --types=ipa,apk'
|
|
74
85
|
)
|
|
75
86
|
}
|
|
76
87
|
end
|
|
@@ -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.4"
|
|
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.8.0' # 硬编码的配置版本要求
|
|
16
16
|
|
|
17
17
|
class << self
|
|
18
18
|
# 主版本检查方法(保持向后兼容)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pindo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.18.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- wade
|
|
@@ -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
|