pindo 5.12.2 → 5.13.2

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 (115) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/git_handler.rb +692 -0
  3. data/lib/pindo/command/android/autobuild.rb +2 -2
  4. data/lib/pindo/command/android.rb +0 -1
  5. data/lib/pindo/command/appstore/adhocbuild.rb +258 -311
  6. data/lib/pindo/command/appstore/autobuild.rb +203 -0
  7. data/lib/pindo/command/appstore/autoresign.rb +35 -17
  8. data/lib/pindo/command/appstore/bundleid.rb +120 -0
  9. data/lib/pindo/command/appstore/cert.rb +212 -0
  10. data/lib/pindo/command/appstore/configproj.rb +81 -0
  11. data/lib/pindo/command/{deploy → appstore}/getitcinfo.rb +76 -91
  12. data/lib/pindo/command/appstore/iap.rb +788 -24
  13. data/lib/pindo/command/appstore/initconfig.rb +105 -0
  14. data/lib/pindo/command/appstore/itcapp.rb +95 -13
  15. data/lib/pindo/command/{deploy → appstore}/itcinfo.rb +90 -118
  16. data/lib/pindo/command/appstore/pem.rb +136 -0
  17. data/lib/pindo/command/appstore/pullconfig.rb +99 -0
  18. data/lib/pindo/command/appstore/quswark.rb +87 -0
  19. data/lib/pindo/command/appstore/quswauth.rb +67 -0
  20. data/lib/pindo/command/appstore/tag.rb +77 -0
  21. data/lib/pindo/command/appstore.rb +13 -1
  22. data/lib/pindo/command/env/quarkenv.rb +11 -13
  23. data/lib/pindo/command/env/swarkenv.rb +11 -16
  24. data/lib/pindo/command/ios/autobuild.rb +64 -43
  25. data/lib/pindo/command/ios/autoresign.rb +34 -19
  26. data/lib/pindo/command/ios/build.rb +10 -7
  27. data/lib/pindo/command/ios/cert.rb +27 -20
  28. data/lib/pindo/command/jps/upload.rb +3 -3
  29. data/lib/pindo/command/unity/autobuild.rb +2 -2
  30. data/lib/pindo/command/utils/clearcert.rb +2 -17
  31. data/lib/pindo/command/{deploy → utils}/fabric.rb +13 -13
  32. data/lib/pindo/command/utils/renewcert.rb +62 -38
  33. data/lib/pindo/command/utils/renewproj.rb +0 -3
  34. data/lib/pindo/command/{deploy → utils}/updateconfig.rb +6 -7
  35. data/lib/pindo/command/utils.rb +2 -0
  36. data/lib/pindo/command/web/autobuild.rb +2 -2
  37. data/lib/pindo/command.rb +30 -3
  38. data/lib/pindo/config/build_info_manager.rb +176 -0
  39. data/lib/pindo/config/ios_config_parser.rb +404 -0
  40. data/lib/pindo/module/android/android_build_helper.rb +110 -0
  41. data/lib/pindo/module/android/android_config_helper.rb +9 -5
  42. data/lib/pindo/module/android/gradle_helper.rb +88 -0
  43. data/lib/pindo/module/appstore/bundleid_helper.rb +349 -0
  44. data/lib/pindo/module/appstore/itcapp_helper.rb +228 -0
  45. data/lib/pindo/module/build/build_helper.rb +12 -0
  46. data/lib/pindo/module/build/swark_helper.rb +116 -77
  47. data/lib/pindo/module/cert/cert_helper.rb +74 -0
  48. data/lib/pindo/module/cert/pem_helper.rb +72 -0
  49. data/lib/pindo/module/cert/{xcodecerthelper.rb → xcode_cert_helper.rb} +208 -6
  50. data/lib/pindo/module/task/model/appstore/appstore_task.rb +18 -0
  51. data/lib/pindo/module/task/model/appstore/appstore_upload_ipa_task.rb +151 -0
  52. data/lib/pindo/module/task/model/appstore/appstore_upload_metadata_task.rb +250 -0
  53. data/lib/pindo/module/task/model/appstore/appstore_upload_screenshot_task.rb +276 -0
  54. data/lib/pindo/module/task/model/build/android_build_adhoc_task.rb +210 -0
  55. data/lib/pindo/module/task/model/build/{android_dev_build_task.rb → android_build_dev_task.rb} +2 -2
  56. data/lib/pindo/module/task/model/build/android_build_gplay_task.rb +210 -0
  57. data/lib/pindo/module/task/model/build/android_build_task.rb +13 -0
  58. data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +197 -0
  59. data/lib/pindo/module/task/model/build/ios_build_appstore_task.rb +367 -0
  60. data/lib/pindo/module/task/model/build/{ios_dev_build_task.rb → ios_build_dev_task.rb} +37 -27
  61. data/lib/pindo/module/task/model/build/ios_build_task.rb +13 -0
  62. data/lib/pindo/module/task/model/build/{web_dev_build_task.rb → web_build_dev_task.rb} +1 -1
  63. data/lib/pindo/module/task/model/build_task.rb +15 -12
  64. data/lib/pindo/module/task/model/jps_resign_task.rb +185 -0
  65. data/lib/pindo/module/task/model/{upload_task.rb → jps_upload_task.rb} +3 -3
  66. data/lib/pindo/module/task/model/unity_export_task.rb +3 -1
  67. data/lib/pindo/module/task/pindo_task.rb +19 -10
  68. data/lib/pindo/module/unity/unity_helper.rb +2 -1
  69. data/lib/pindo/module/xcode/ipa_resign_helper.rb +210 -0
  70. data/lib/pindo/module/xcode/{xcodeappconfig.rb → xcode_app_config.rb} +79 -0
  71. data/lib/pindo/module/xcode/xcode_build_config.rb +152 -17
  72. data/lib/pindo/module/xcode/xcode_build_helper.rb +151 -1
  73. data/lib/pindo/module/xcode/xcode_swark_helper.rb +341 -0
  74. data/lib/pindo/options/core/global_options_state.rb +268 -0
  75. data/lib/pindo/options/core/option_configuration.rb +206 -0
  76. data/lib/pindo/options/core/option_initializer.rb +51 -0
  77. data/lib/pindo/options/core/option_item.rb +144 -0
  78. data/lib/pindo/options/core/option_value_parser.rb +54 -0
  79. data/lib/pindo/options/groups/build_options.rb +60 -0
  80. data/lib/pindo/options/groups/jps_options.rb +70 -0
  81. data/lib/pindo/options/groups/option_group.rb +73 -0
  82. data/lib/pindo/options/helpers/bundleid_selector.rb +103 -0
  83. data/lib/pindo/options/options.rb +14 -0
  84. data/lib/pindo/version.rb +1 -1
  85. metadata +49 -41
  86. data/lib/pindo/command/android/build.rb +0 -186
  87. data/lib/pindo/command/appstore/import.rb +0 -259
  88. data/lib/pindo/command/deploy/build.rb +0 -250
  89. data/lib/pindo/command/deploy/bundleid.rb +0 -259
  90. data/lib/pindo/command/deploy/cert.rb +0 -202
  91. data/lib/pindo/command/deploy/check.rb +0 -93
  92. data/lib/pindo/command/deploy/configproj.rb +0 -120
  93. data/lib/pindo/command/deploy/confusecode.rb +0 -262
  94. data/lib/pindo/command/deploy/confuseproj.rb +0 -122
  95. data/lib/pindo/command/deploy/iap.rb +0 -826
  96. data/lib/pindo/command/deploy/initconfig.rb +0 -138
  97. data/lib/pindo/command/deploy/itcapp.rb +0 -146
  98. data/lib/pindo/command/deploy/pem.rb +0 -55
  99. data/lib/pindo/command/deploy/pullconfig.rb +0 -56
  100. data/lib/pindo/command/deploy/pushconfig.rb +0 -93
  101. data/lib/pindo/command/deploy/quswark.rb +0 -156
  102. data/lib/pindo/command/deploy/quswauth.rb +0 -76
  103. data/lib/pindo/command/deploy/reportbug.rb +0 -145
  104. data/lib/pindo/command/deploy/resign.rb +0 -300
  105. data/lib/pindo/command/deploy/tag.rb +0 -108
  106. data/lib/pindo/command/deploy/uploadipa.rb +0 -73
  107. data/lib/pindo/command/deploy.rb +0 -42
  108. data/lib/pindo/command/dev/autobuild.rb +0 -117
  109. data/lib/pindo/command/dev/build.rb +0 -94
  110. data/lib/pindo/command/dev/debug.rb +0 -112
  111. data/lib/pindo/module/task/model/build/android_release_build_task.rb +0 -29
  112. data/lib/pindo/module/task/model/build/ios_adhoc_build_task.rb +0 -53
  113. data/lib/pindo/module/task/model/build/ios_release_build_task.rb +0 -53
  114. data/lib/pindo/options/appconfigoptions.rb +0 -24
  115. data/lib/pindo/options/deployoptions.rb +0 -372
@@ -97,6 +97,9 @@ module Pindo
97
97
  puts "⚠ Keystore 签名配置跳过(使用工程原有配置)"
98
98
  end
99
99
 
100
+ # 处理 Play Asset Delivery 配置(如果存在)
101
+ setup_play_asset_delivery(project_dir)
102
+
100
103
  # 构建 APK
101
104
  build_apk(project_dir, debug)
102
105
  end
@@ -298,6 +301,113 @@ module Pindo
298
301
  end
299
302
  end
300
303
 
304
+ # 设置 Play Asset Delivery:直接扫描导出工程中的资源目录,按照 Android 原生方式创建 .androidpack 目录
305
+ def setup_play_asset_delivery(project_dir)
306
+ # 获取 unityLibrary 路径
307
+ unity_library_path = File.join(project_dir, "unityLibrary", "src", "main")
308
+ unless File.directory?(unity_library_path)
309
+ puts "警告:Unity Library 目录不存在: #{unity_library_path}"
310
+ return
311
+ end
312
+
313
+ # 扫描 assets 目录下的资源(Unity 构建时会将 StreamingAssets 复制到这里)
314
+ assets_path = File.join(unity_library_path, "assets")
315
+ unless File.directory?(assets_path)
316
+ puts "未找到 assets 目录,跳过 Play Asset Delivery 设置"
317
+ return
318
+ end
319
+
320
+ # 扫描 assets 目录下的所有一级子目录
321
+ # 这些目录对应 StreamingAssets/{DefaultYooFolderName} 下的资源包
322
+ asset_subdirs = Dir.glob(File.join(assets_path, "*")).select { |path| File.directory?(path) }
323
+
324
+ if asset_subdirs.empty?
325
+ puts "未找到 assets 下的子目录,跳过 Play Asset Delivery 设置"
326
+ return
327
+ end
328
+
329
+ puts "检测到 #{asset_subdirs.length} 个 assets 子目录,开始设置 Play Asset Delivery..."
330
+
331
+ begin
332
+ # 收集所有创建的 asset pack 模块名
333
+ created_pack_modules = []
334
+
335
+ # 扫描每个子目录,为每个子目录创建一个 asset pack 模块
336
+ asset_subdirs.each do |subdir|
337
+ original_pack_name = File.basename(subdir)
338
+ if original_pack_name.downcase == 'bin'
339
+ puts "跳过 bin 目录,保持在 base 模块中"
340
+ next
341
+ end
342
+ sanitized_pack_name = sanitize_pack_name(original_pack_name)
343
+ module_name = "#{sanitized_pack_name}_pack"
344
+
345
+ # 检查目录是否为空
346
+ if Dir.glob(File.join(subdir, "*")).empty?
347
+ puts "警告:跳过空的 Asset Pack 目录: #{subdir}"
348
+ next
349
+ end
350
+
351
+ # 创建模块目录(在项目顶级目录,与 launcher、unityLibrary 同级)
352
+ android_pack_dir = File.join(project_dir, module_name)
353
+ FileUtils.rm_rf(android_pack_dir) if File.directory?(android_pack_dir)
354
+ FileUtils.mkdir_p(android_pack_dir)
355
+
356
+ # 在 asset pack 模块中创建 src/main/assets 目录
357
+ module_assets_dir = File.join(android_pack_dir, "src", "main", "assets")
358
+ FileUtils.mkdir_p(module_assets_dir)
359
+
360
+ # 复制整个子目录到模块的 assets 下,保留原始目录名
361
+ FileUtils.cp_r(subdir, module_assets_dir)
362
+
363
+ # 从 assets 目录中删除资源,避免被打包到 base 模块
364
+ puts " 从 assets 目录移除资源 #{subdir},避免重复打包到 base 模块..."
365
+ FileUtils.rm_rf(subdir)
366
+
367
+ # 创建 build.gradle 文件(默认使用 install-time delivery mode)
368
+ build_gradle_content = <<~GRADLE
369
+ plugins {
370
+ id 'com.android.asset-pack'
371
+ }
372
+
373
+ assetPack {
374
+ packName = "#{module_name}"
375
+ dynamicDelivery {
376
+ deliveryType = "install-time"
377
+ }
378
+ }
379
+ GRADLE
380
+
381
+ build_gradle_path = File.join(android_pack_dir, "build.gradle")
382
+ File.write(build_gradle_path, build_gradle_content)
383
+
384
+ # 记录模块名(项目顶级目录下的简单模块名)
385
+ created_pack_modules << ":#{module_name}"
386
+
387
+ puts "✓ 已创建 Asset Pack: #{module_name} -> #{android_pack_dir}"
388
+ end
389
+
390
+ # 更新 settings.gradle 文件,注册 asset pack 模块
391
+ if created_pack_modules.any?
392
+ GradleHelper.update_settings_gradle(project_dir, created_pack_modules)
393
+ # 更新 launcher/build.gradle 文件,添加 assetPacks 配置
394
+ GradleHelper.update_launcher_build_gradle(project_dir, created_pack_modules)
395
+ puts "✓ Play Asset Delivery 设置完成,共创建 #{created_pack_modules.length} 个 Asset Pack"
396
+ else
397
+ puts "未找到有效的 Asset Pack 目录"
398
+ end
399
+ rescue => e
400
+ puts "警告:设置 Play Asset Delivery 失败: #{e.message}"
401
+ puts e.backtrace.first(5).join("\n")
402
+ end
403
+ end
404
+
405
+ def sanitize_pack_name(name)
406
+ sanitized = name.to_s.gsub(/[^A-Za-z0-9_]/, '_')
407
+ sanitized = "p_#{sanitized}" unless sanitized.match?(/^[A-Za-z]/)
408
+ sanitized = sanitized.gsub(/__+/, '_')
409
+ sanitized.empty? ? "pack" : sanitized
410
+ end
301
411
 
302
412
  end
303
413
  end
@@ -924,13 +924,15 @@ module Pindo
924
924
  puts "\n检测到项目 Icon URL: #{icon_url}"
925
925
 
926
926
  # 创建临时目录(所有 icon 处理都在此目录进行)
927
- temp_icon_dir = File.join(project_dir, ".pindo_temp_icon")
927
+ temp_icon_dir = File.join(project_dir, ".pindo_temp_android_icon")
928
928
  icon_download_path = nil
929
929
  replace_success = false
930
930
 
931
931
  begin
932
- FileUtils.mkdir_p(temp_icon_dir) unless File.exist?(temp_icon_dir)
933
- icon_download_path = File.join(temp_icon_dir, "downloaded_icon.png")
932
+ # 先清理旧的临时目录,确保干净的环境
933
+ FileUtils.rm_rf(temp_icon_dir) if File.exist?(temp_icon_dir)
934
+ FileUtils.mkdir_p(temp_icon_dir)
935
+ icon_download_path = File.join(temp_icon_dir, "android_downloaded_icon.png")
934
936
 
935
937
  # 使用带重试机制的下载
936
938
  unless IconDownloader.download_icon_with_retry(icon_url: icon_url, save_path: icon_download_path, max_retries: 3)
@@ -938,8 +940,10 @@ module Pindo
938
940
  return false
939
941
  end
940
942
 
941
- # 生成 icon 目录(在临时目录内部)
942
- new_icon_dir = File.join(temp_icon_dir, "generated_icons")
943
+ # 生成 icon 目录(在临时目录内部),先清理确保干净环境
944
+ new_icon_dir = File.join(temp_icon_dir, "android_generated_icons")
945
+ FileUtils.rm_rf(new_icon_dir) if File.exist?(new_icon_dir)
946
+ FileUtils.mkdir_p(new_icon_dir)
943
947
 
944
948
  # 创建各种密度的 icon
945
949
  Funlog.instance.fancyinfo_start("正在创建 Android icon...")
@@ -559,7 +559,95 @@ module Pindo
559
559
  end
560
560
  rescue => e
561
561
  false
562
+ end
563
+
564
+ end
565
+
566
+ # =================== Play Asset Delivery 相关方法 ===================
567
+
568
+ # 更新 settings.gradle 文件,注册 asset pack 模块
569
+ def self.update_settings_gradle(project_dir, pack_modules)
570
+ settings_gradle_path = File.join(project_dir, "settings.gradle")
571
+ settings_gradle_kts_path = File.join(project_dir, "settings.gradle.kts")
572
+
573
+ # 优先使用 settings.gradle.kts,否则使用 settings.gradle
574
+ settings_file = File.exist?(settings_gradle_kts_path) ? settings_gradle_kts_path : settings_gradle_path
575
+
576
+ unless File.exist?(settings_file)
577
+ puts "警告:未找到 settings.gradle 或 settings.gradle.kts 文件"
578
+ return
579
+ end
580
+
581
+ content = File.read(settings_file)
582
+ original_content = content.dup
583
+
584
+ # 模块名已经是正确的格式(如 :FGUI.androidpack)
585
+ pack_module_names = pack_modules
586
+
587
+ # 移除已存在的 asset pack 模块引用(避免重复)
588
+ pack_module_names.each do |module_name|
589
+ # 移除可能存在的旧引用
590
+ content.gsub!(/^\s*include\s+['"]#{Regexp.escape(module_name)}['"]\s*$/, '')
591
+ content.gsub!(/,\s*['"]#{Regexp.escape(module_name)}['"]/, '')
592
+ end
593
+
594
+ # 查找 include 语句的位置
595
+ include_pattern = /include\s+(['"]:launcher['"],\s*['"]:unityLibrary['"])/
596
+ if content.match(include_pattern)
597
+ # 在现有的 include 语句中添加 asset pack 模块
598
+ pack_includes = pack_module_names.map { |m| "'#{m}'" }.join(', ')
599
+ content.gsub!(include_pattern, "include \\1, #{pack_includes}")
600
+ else
601
+ # 如果没有找到标准格式,尝试在文件末尾添加
602
+ pack_includes = pack_module_names.map { |m| "'#{m}'" }.join(', ')
603
+ content += "\ninclude #{pack_includes}\n" unless content.include?(pack_includes)
604
+ end
605
+
606
+ # 只有当内容发生变化时才写入
607
+ if content != original_content
608
+ File.write(settings_file, content)
609
+ puts "✓ 已更新 #{File.basename(settings_file)},注册 #{pack_modules.length} 个 Asset Pack 模块"
610
+ puts " 模块: #{pack_module_names.join(', ')}"
611
+ else
612
+ puts "✓ #{File.basename(settings_file)} 已包含 Asset Pack 模块引用"
613
+ end
614
+ end
615
+
616
+ # 更新 launcher/build.gradle 文件,添加 assetPacks 配置
617
+ def self.update_launcher_build_gradle(project_dir, pack_modules)
618
+ launcher_build_gradle_path = File.join(project_dir, "launcher", "build.gradle")
619
+ unless File.exist?(launcher_build_gradle_path)
620
+ puts "警告:未找到 launcher/build.gradle 文件"
621
+ return
622
+ end
623
+
624
+ content = File.read(launcher_build_gradle_path)
625
+ original_content = content.dup
626
+
627
+ # 检查是否已有 assetPacks 配置
628
+ if content.match(/assetPacks\s*=\s*\[/)
629
+ # 更新现有的 assetPacks 配置
630
+ content.gsub!(/assetPacks\s*=\s*\[[^\]]*\]/, "assetPacks = #{pack_modules.inspect}")
631
+ else
632
+ # 在 android 块中添加 assetPacks 配置
633
+ android_block_pattern = /(android\s*\{)/
634
+ if content.match(android_block_pattern)
635
+ # 在 android { 后添加 assetPacks 配置
636
+ content.gsub!(android_block_pattern, "\\1\n assetPacks = #{pack_modules.inspect}")
637
+ else
638
+ puts "警告:未找到 android 块,无法添加 assetPacks 配置"
639
+ return
562
640
  end
563
641
  end
642
+
643
+ # 只有当内容发生变化时才写入
644
+ if content != original_content
645
+ File.write(launcher_build_gradle_path, content)
646
+ puts "✓ 已更新 launcher/build.gradle,添加 assetPacks 配置"
647
+ else
648
+ puts "✓ launcher/build.gradle 已包含 assetPacks 配置"
649
+ end
650
+ end
651
+
564
652
  end
565
653
  end
@@ -0,0 +1,349 @@
1
+ require 'spaceship'
2
+ require 'json'
3
+
4
+ module Pindo
5
+ # Bundle ID 管理辅助类
6
+ # 负责在 Apple 开发者中心创建和配置 Bundle ID
7
+ class BundleIdHelper
8
+
9
+ # 从配置文件中提取所有必要的信息
10
+ # @param config_json [Hash] 配置 JSON 对象
11
+ # @return [Hash] 提取的配置信息
12
+ def self.extract_config_info(config_json)
13
+ config_info = {}
14
+
15
+ # 提取 Apple ID
16
+ if config_json['account_info'] && config_json['account_info']['apple_acount_id']
17
+ config_info[:apple_id] = config_json['account_info']['apple_acount_id']
18
+ end
19
+
20
+ # 提取 Bundle ID 信息
21
+ if config_json['app_info']
22
+ app_info = config_json['app_info']
23
+ config_info[:bundle_id] = app_info['app_identifier']
24
+ config_info[:bundle_id_pushcontent] = app_info['app_identifier_pushcontent']
25
+ config_info[:bundle_id_pushservice] = app_info['app_identifier_pushservice']
26
+ config_info[:bundle_id_keyboard] = app_info['app_identifier_keyboard']
27
+ config_info[:bundle_id_imessage] = app_info['app_identifier_imessage']
28
+ config_info[:bundle_id_extension] = app_info['app_identifier_extension']
29
+ config_info[:bundle_id_siri] = app_info['app_identifier_siri']
30
+ config_info[:bundle_id_siriui] = app_info['app_identifier_siriui']
31
+ config_info[:bundle_id_widget] = app_info['app_identifier_widget']
32
+ config_info[:bundle_id_extensionad] = app_info['app_identifier_extensionad']
33
+ config_info[:bundle_id_watchapp] = app_info['app_identifier_watchapp']
34
+ config_info[:bundle_id_watchapp_extension] = app_info['app_identifier_watchapp_extension']
35
+ end
36
+
37
+ # 提取 App Group 和 iCloud ID
38
+ if config_json['app_setting']
39
+ app_setting = config_json['app_setting']
40
+ config_info[:group_id] = app_setting['app_group_id']
41
+ config_info[:icloud_id] = app_setting['app_icloud_id']
42
+ end
43
+
44
+ config_info
45
+ end
46
+
47
+ # 执行 Bundle ID 创建流程
48
+ # @param config_json [Hash] 配置 JSON 对象
49
+ # @param sign_flag [Boolean] 签名标志
50
+ def self.execute_bundleid_creation(config_json:, sign_flag: false)
51
+ # 提取配置信息
52
+ config_info = extract_config_info(config_json)
53
+
54
+ # 验证必需字段
55
+ raise "配置文件中缺少 Apple ID" if config_info[:apple_id].nil? || config_info[:apple_id].empty?
56
+ raise "配置文件中缺少 Bundle ID" if config_info[:bundle_id].nil? || config_info[:bundle_id].empty?
57
+
58
+ # 登录 Apple 开发者中心
59
+ puts config_info[:apple_id]
60
+ puts "Login #{config_info[:apple_id]}..."
61
+ Spaceship.login(config_info[:apple_id].to_s)
62
+ Spaceship.select_team
63
+
64
+ # 创建 App Group
65
+ app_group = nil
66
+ if !config_info[:group_id].nil?
67
+ app_group = create_group_id(group_id: config_info[:group_id])
68
+ end
69
+
70
+ # 配置参数
71
+ parms = ["push_notification", "app_group"]
72
+
73
+ # 创建 iCloud ID
74
+ app_icloud = nil
75
+ if !config_info[:icloud_id].nil?
76
+ app_icloud = create_icloud_id(icloud_id: config_info[:icloud_id])
77
+ parms << "iclound"
78
+ end
79
+
80
+ # 创建主应用 Bundle ID
81
+ app = create_bundleid(
82
+ bundle_id: config_info[:bundle_id],
83
+ app_group: app_group,
84
+ app_icloud: app_icloud,
85
+ setting_array: parms
86
+ )
87
+
88
+ # 创建各种扩展的 Bundle ID
89
+ create_extension_bundleids(app, app_group, app_icloud, config_info)
90
+ end
91
+
92
+ # 创建 Bundle ID
93
+ # @param bundle_id [String] Bundle ID
94
+ # @param app_group [Object] App Group 对象
95
+ # @param app_icloud [Object] iCloud Container 对象
96
+ # @param setting_array [Array] 配置数组
97
+ # @return [Object] 创建的 App 对象
98
+ def self.create_bundleid(bundle_id:, app_group: nil, app_icloud: nil, setting_array: [])
99
+ return nil if bundle_id.nil?
100
+
101
+ # 查找或创建 Bundle ID
102
+ app = Spaceship::Portal.app.find(bundle_id)
103
+ puts
104
+
105
+ if app.nil?
106
+ puts "Create bundle id #{bundle_id} in apple developer center..."
107
+ app = Spaceship::Portal.app.create!(bundle_id: bundle_id, name: bundle_id.gsub('.', ''))
108
+ else
109
+ puts "Find bundle id #{bundle_id} in apple developer center..."
110
+ end
111
+
112
+ bundle_id_obj = Spaceship::ConnectAPI::BundleId.find(bundle_id)
113
+
114
+ # 配置 Game Center
115
+ if !bundle_id_obj.nil?
116
+ if !setting_array.nil? && setting_array.to_s.include?("game_center")
117
+ puts "Enable #{bundle_id} game_center on"
118
+ bundle_id_obj.update_capability("GAME_CENTER", enabled: true)
119
+ else
120
+ puts "Enable #{bundle_id} game_center off"
121
+ bundle_id_obj.update_capability("GAME_CENTER", enabled: false)
122
+ end
123
+ end
124
+
125
+ return nil if setting_array.nil? || setting_array.length == 0
126
+
127
+ # 配置 Push Notification
128
+ if !app.nil? && setting_array.to_s.include?("push_notification")
129
+ puts "Enable #{bundle_id} push on"
130
+ app.update_service(Spaceship::Portal.app_service.push_notification.on)
131
+ else
132
+ app.update_service(Spaceship::Portal.app_service.push_notification.off)
133
+ puts "Enable #{bundle_id} push off"
134
+ end
135
+
136
+ # 配置 Siri
137
+ if !app.nil? && setting_array.to_s.include?("siri")
138
+ puts "Enable #{bundle_id} siri on"
139
+ app.update_service(Spaceship::Portal.app_service.siri_kit.on)
140
+ else
141
+ app.update_service(Spaceship::Portal.app_service.siri_kit.off)
142
+ puts "Enable #{bundle_id} siri off"
143
+ end
144
+
145
+ # 配置 Sign with Apple
146
+ if !bundle_id_obj.nil? && setting_array.to_s.include?("apple_signin")
147
+ puts "Enable #{bundle_id} Sign with Apple on"
148
+ settings = build_settings_for(settings_key: "APPLE_ID_AUTH_APP_CONSENT", options_key: "PRIMARY_APP_CONSENT")
149
+ bundle_id_obj.update_capability("APPLE_ID_AUTH", enabled: true, settings: settings)
150
+ else
151
+ puts "Enable #{bundle_id} Sign with Apple off"
152
+ bundle_id_obj.update_capability("APPLE_ID_AUTH", enabled: false)
153
+ end
154
+
155
+ # 配置 App Group
156
+ if !app_group.nil? && setting_array.to_s.include?("app_group")
157
+ puts "Enable #{bundle_id} group on"
158
+ app.update_service(Spaceship::Portal.app_service.app_group.on)
159
+ app.associate_groups([app_group])
160
+ else
161
+ puts "Enable #{bundle_id} group off"
162
+ app.update_service(Spaceship::Portal.app_service.app_group.off)
163
+ end
164
+
165
+ # 配置 iCloud
166
+ if !app_icloud.nil? && setting_array.to_s.include?("iclound")
167
+ puts "Enable #{bundle_id} icloud on"
168
+ app.update_service(Spaceship::Portal.app_service.cloud.on)
169
+ app.update_service(Spaceship::Portal.app_service.cloud_kit.cloud_kit)
170
+ app.associate_cloud_containers([app_icloud])
171
+ else
172
+ puts "Enable #{bundle_id} icloud off"
173
+ app.update_service(Spaceship::Portal.app_service.cloud.off)
174
+ end
175
+
176
+ app
177
+ end
178
+
179
+ # 创建 App Group
180
+ # @param group_id [String] Group ID
181
+ # @return [Object] App Group 对象
182
+ def self.create_group_id(group_id:)
183
+ return nil if group_id.nil?
184
+
185
+ app_group = Spaceship::Portal.app_group.find(group_id)
186
+
187
+ if app_group.nil?
188
+ puts "Create group_id #{group_id} in apple developer center..."
189
+ app_group = Spaceship::Portal.app_group.create!(group_id: group_id, name: group_id.gsub('.', ''))
190
+ else
191
+ puts "Group_id #{group_id} is existed in apple developer center !!!"
192
+ end
193
+
194
+ app_group
195
+ end
196
+
197
+ # 创建 iCloud Container
198
+ # @param icloud_id [String] iCloud ID
199
+ # @return [Object] iCloud Container 对象
200
+ def self.create_icloud_id(icloud_id:)
201
+ return nil if icloud_id.nil?
202
+
203
+ puts "icloud_id +++++ #{icloud_id}"
204
+ app_icloud = Spaceship::Portal.cloud_container.find(icloud_id)
205
+
206
+ if app_icloud.nil?
207
+ puts "Create icloud_id #{icloud_id} in apple developer center..."
208
+ app_icloud = Spaceship::Portal.cloud_container.create!(identifier: icloud_id, name: icloud_id.gsub('.', ''))
209
+ else
210
+ puts "icloud_id #{icloud_id} is existed in apple developer center !!!"
211
+ end
212
+
213
+ app_icloud
214
+ end
215
+
216
+ # 构建设置
217
+ # @param settings_key [String] 设置键
218
+ # @param options_key [String] 选项键
219
+ # @return [Array] 设置数组
220
+ def self.build_settings_for(settings_key:, options_key:)
221
+ [{
222
+ key: settings_key,
223
+ options: [{
224
+ key: options_key
225
+ }]
226
+ }]
227
+ end
228
+
229
+ # 创建扩展的 Bundle ID
230
+ # @param app [Object] 主应用对象
231
+ # @param app_group [Object] App Group 对象
232
+ # @param app_icloud [Object] iCloud Container 对象
233
+ # @param config_info [Hash] 配置信息
234
+ def self.create_extension_bundleids(app, app_group, app_icloud, config_info)
235
+ return if app.nil?
236
+
237
+ # Push Content Extension
238
+ if !config_info[:bundle_id_pushcontent].nil?
239
+ create_bundleid(
240
+ bundle_id: config_info[:bundle_id_pushcontent],
241
+ app_group: app_group,
242
+ app_icloud: app_icloud,
243
+ setting_array: ["push_notification"]
244
+ )
245
+ end
246
+
247
+ # Push Service Extension
248
+ if !config_info[:bundle_id_pushservice].nil?
249
+ create_bundleid(
250
+ bundle_id: config_info[:bundle_id_pushservice],
251
+ app_group: app_group,
252
+ app_icloud: app_icloud,
253
+ setting_array: ["push_notification"]
254
+ )
255
+ end
256
+
257
+ # Keyboard Extension
258
+ if !config_info[:bundle_id_keyboard].nil?
259
+ create_bundleid(
260
+ bundle_id: config_info[:bundle_id_keyboard],
261
+ app_group: app_group,
262
+ app_icloud: app_icloud,
263
+ setting_array: ["app_group"]
264
+ )
265
+ end
266
+
267
+ # iMessage Extension
268
+ if !config_info[:bundle_id_imessage].nil?
269
+ create_bundleid(
270
+ bundle_id: config_info[:bundle_id_imessage],
271
+ app_group: app_group,
272
+ app_icloud: app_icloud,
273
+ setting_array: ["app_group"]
274
+ )
275
+ end
276
+
277
+ # Siri Extension
278
+ if !config_info[:bundle_id_siri].nil?
279
+ create_bundleid(
280
+ bundle_id: config_info[:bundle_id_siri],
281
+ app_group: app_group,
282
+ app_icloud: app_icloud,
283
+ setting_array: ["app_group", "siri"]
284
+ )
285
+ end
286
+
287
+ # Siri UI Extension
288
+ if !config_info[:bundle_id_siriui].nil?
289
+ create_bundleid(
290
+ bundle_id: config_info[:bundle_id_siriui],
291
+ app_group: app_group,
292
+ app_icloud: app_icloud,
293
+ setting_array: ["app_group", "siri"]
294
+ )
295
+ end
296
+
297
+ # Widget Extension
298
+ if !config_info[:bundle_id_widget].nil?
299
+ create_bundleid(
300
+ bundle_id: config_info[:bundle_id_widget],
301
+ app_group: app_group,
302
+ app_icloud: app_icloud,
303
+ setting_array: ["app_group"]
304
+ )
305
+ end
306
+
307
+ # General Extension
308
+ if !config_info[:bundle_id_extension].nil?
309
+ create_bundleid(
310
+ bundle_id: config_info[:bundle_id_extension],
311
+ app_group: app_group,
312
+ app_icloud: app_icloud,
313
+ setting_array: ["app_group"]
314
+ )
315
+ end
316
+
317
+ # Ad Extension
318
+ if !config_info[:bundle_id_extensionad].nil?
319
+ create_bundleid(
320
+ bundle_id: config_info[:bundle_id_extensionad],
321
+ app_group: app_group,
322
+ app_icloud: app_icloud,
323
+ setting_array: ["app_group"]
324
+ )
325
+ end
326
+
327
+ # Watch App
328
+ if !config_info[:bundle_id_watchapp].nil?
329
+ create_bundleid(
330
+ bundle_id: config_info[:bundle_id_watchapp],
331
+ app_group: nil,
332
+ app_icloud: app_icloud,
333
+ setting_array: ["push_notification"]
334
+ )
335
+ end
336
+
337
+ # Watch App Extension
338
+ if !config_info[:bundle_id_watchapp_extension].nil?
339
+ create_bundleid(
340
+ bundle_id: config_info[:bundle_id_watchapp_extension],
341
+ app_group: nil,
342
+ app_icloud: app_icloud,
343
+ setting_array: ["push_notification"]
344
+ )
345
+ end
346
+ end
347
+
348
+ end
349
+ end