pindo 5.13.1 → 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 (110) 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/appstore/adhocbuild.rb +258 -311
  5. data/lib/pindo/command/appstore/autobuild.rb +203 -0
  6. data/lib/pindo/command/appstore/autoresign.rb +35 -17
  7. data/lib/pindo/command/appstore/bundleid.rb +120 -0
  8. data/lib/pindo/command/appstore/cert.rb +212 -0
  9. data/lib/pindo/command/appstore/configproj.rb +81 -0
  10. data/lib/pindo/command/{deploy → appstore}/getitcinfo.rb +76 -91
  11. data/lib/pindo/command/appstore/iap.rb +788 -24
  12. data/lib/pindo/command/appstore/initconfig.rb +105 -0
  13. data/lib/pindo/command/appstore/itcapp.rb +95 -13
  14. data/lib/pindo/command/{deploy → appstore}/itcinfo.rb +90 -118
  15. data/lib/pindo/command/appstore/pem.rb +136 -0
  16. data/lib/pindo/command/appstore/pullconfig.rb +99 -0
  17. data/lib/pindo/command/appstore/quswark.rb +87 -0
  18. data/lib/pindo/command/appstore/quswauth.rb +67 -0
  19. data/lib/pindo/command/appstore/tag.rb +77 -0
  20. data/lib/pindo/command/appstore.rb +13 -1
  21. data/lib/pindo/command/env/quarkenv.rb +11 -13
  22. data/lib/pindo/command/env/swarkenv.rb +11 -16
  23. data/lib/pindo/command/ios/autobuild.rb +64 -43
  24. data/lib/pindo/command/ios/autoresign.rb +34 -19
  25. data/lib/pindo/command/ios/build.rb +9 -6
  26. data/lib/pindo/command/ios/cert.rb +27 -20
  27. data/lib/pindo/command/jps/upload.rb +3 -3
  28. data/lib/pindo/command/unity/autobuild.rb +2 -2
  29. data/lib/pindo/command/utils/clearcert.rb +2 -17
  30. data/lib/pindo/command/{deploy → utils}/fabric.rb +13 -13
  31. data/lib/pindo/command/utils/renewcert.rb +62 -38
  32. data/lib/pindo/command/utils/renewproj.rb +0 -3
  33. data/lib/pindo/command/{deploy → utils}/updateconfig.rb +6 -7
  34. data/lib/pindo/command/utils.rb +2 -0
  35. data/lib/pindo/command/web/autobuild.rb +2 -2
  36. data/lib/pindo/command.rb +30 -3
  37. data/lib/pindo/config/build_info_manager.rb +176 -0
  38. data/lib/pindo/config/ios_config_parser.rb +404 -0
  39. data/lib/pindo/module/android/android_config_helper.rb +9 -5
  40. data/lib/pindo/module/appstore/bundleid_helper.rb +349 -0
  41. data/lib/pindo/module/appstore/itcapp_helper.rb +228 -0
  42. data/lib/pindo/module/build/build_helper.rb +12 -0
  43. data/lib/pindo/module/build/swark_helper.rb +116 -77
  44. data/lib/pindo/module/cert/cert_helper.rb +74 -0
  45. data/lib/pindo/module/cert/pem_helper.rb +72 -0
  46. data/lib/pindo/module/cert/{xcodecerthelper.rb → xcode_cert_helper.rb} +208 -6
  47. data/lib/pindo/module/task/model/appstore/appstore_task.rb +18 -0
  48. data/lib/pindo/module/task/model/appstore/appstore_upload_ipa_task.rb +151 -0
  49. data/lib/pindo/module/task/model/appstore/appstore_upload_metadata_task.rb +250 -0
  50. data/lib/pindo/module/task/model/appstore/appstore_upload_screenshot_task.rb +276 -0
  51. data/lib/pindo/module/task/model/build/android_build_adhoc_task.rb +210 -0
  52. data/lib/pindo/module/task/model/build/{android_dev_build_task.rb → android_build_dev_task.rb} +2 -2
  53. data/lib/pindo/module/task/model/build/android_build_gplay_task.rb +210 -0
  54. data/lib/pindo/module/task/model/build/android_build_task.rb +13 -0
  55. data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +197 -0
  56. data/lib/pindo/module/task/model/build/ios_build_appstore_task.rb +367 -0
  57. data/lib/pindo/module/task/model/build/{ios_dev_build_task.rb → ios_build_dev_task.rb} +37 -27
  58. data/lib/pindo/module/task/model/build/ios_build_task.rb +13 -0
  59. data/lib/pindo/module/task/model/build/{web_dev_build_task.rb → web_build_dev_task.rb} +1 -1
  60. data/lib/pindo/module/task/model/build_task.rb +15 -12
  61. data/lib/pindo/module/task/model/jps_resign_task.rb +185 -0
  62. data/lib/pindo/module/task/model/{upload_task.rb → jps_upload_task.rb} +3 -3
  63. data/lib/pindo/module/task/model/unity_export_task.rb +3 -1
  64. data/lib/pindo/module/unity/unity_helper.rb +2 -1
  65. data/lib/pindo/module/xcode/ipa_resign_helper.rb +210 -0
  66. data/lib/pindo/module/xcode/{xcodeappconfig.rb → xcode_app_config.rb} +79 -0
  67. data/lib/pindo/module/xcode/xcode_build_config.rb +152 -17
  68. data/lib/pindo/module/xcode/xcode_build_helper.rb +151 -1
  69. data/lib/pindo/module/xcode/xcode_swark_helper.rb +341 -0
  70. data/lib/pindo/options/core/global_options_state.rb +268 -0
  71. data/lib/pindo/options/core/option_configuration.rb +206 -0
  72. data/lib/pindo/options/core/option_initializer.rb +51 -0
  73. data/lib/pindo/options/core/option_item.rb +144 -0
  74. data/lib/pindo/options/core/option_value_parser.rb +54 -0
  75. data/lib/pindo/options/groups/build_options.rb +60 -0
  76. data/lib/pindo/options/groups/jps_options.rb +70 -0
  77. data/lib/pindo/options/groups/option_group.rb +73 -0
  78. data/lib/pindo/options/helpers/bundleid_selector.rb +103 -0
  79. data/lib/pindo/options/options.rb +14 -0
  80. data/lib/pindo/version.rb +1 -1
  81. metadata +49 -40
  82. data/lib/pindo/command/appstore/import.rb +0 -259
  83. data/lib/pindo/command/deploy/build.rb +0 -250
  84. data/lib/pindo/command/deploy/bundleid.rb +0 -259
  85. data/lib/pindo/command/deploy/cert.rb +0 -202
  86. data/lib/pindo/command/deploy/check.rb +0 -93
  87. data/lib/pindo/command/deploy/configproj.rb +0 -120
  88. data/lib/pindo/command/deploy/confusecode.rb +0 -262
  89. data/lib/pindo/command/deploy/confuseproj.rb +0 -122
  90. data/lib/pindo/command/deploy/iap.rb +0 -826
  91. data/lib/pindo/command/deploy/initconfig.rb +0 -138
  92. data/lib/pindo/command/deploy/itcapp.rb +0 -146
  93. data/lib/pindo/command/deploy/pem.rb +0 -55
  94. data/lib/pindo/command/deploy/pullconfig.rb +0 -56
  95. data/lib/pindo/command/deploy/pushconfig.rb +0 -93
  96. data/lib/pindo/command/deploy/quswark.rb +0 -156
  97. data/lib/pindo/command/deploy/quswauth.rb +0 -76
  98. data/lib/pindo/command/deploy/reportbug.rb +0 -145
  99. data/lib/pindo/command/deploy/resign.rb +0 -300
  100. data/lib/pindo/command/deploy/tag.rb +0 -108
  101. data/lib/pindo/command/deploy/uploadipa.rb +0 -73
  102. data/lib/pindo/command/deploy.rb +0 -42
  103. data/lib/pindo/command/dev/autobuild.rb +0 -117
  104. data/lib/pindo/command/dev/build.rb +0 -94
  105. data/lib/pindo/command/dev/debug.rb +0 -112
  106. data/lib/pindo/module/task/model/build/android_release_build_task.rb +0 -29
  107. data/lib/pindo/module/task/model/build/ios_adhoc_build_task.rb +0 -53
  108. data/lib/pindo/module/task/model/build/ios_release_build_task.rb +0 -53
  109. data/lib/pindo/options/appconfigoptions.rb +0 -24
  110. data/lib/pindo/options/deployoptions.rb +0 -372
@@ -1,826 +0,0 @@
1
- require 'app_store_dev_api'
2
- require 'json'
3
- require 'faraday'
4
-
5
-
6
- module Pindo
7
- class Command
8
- class Deploy < Command
9
- class Iap < Deploy
10
-
11
- include Command::DeployOptions
12
-
13
- include AppStoreInAppPurchase
14
-
15
- self.summary = '创建、修改AppStore中的Iap购买项,生成boss的iap购买项'
16
-
17
- self.description = <<-DESC
18
- 创建、修改AppStore中的Iap购买项,生成boss的iap购买项
19
-
20
- 支持功能:
21
- - 检查并验证App Store内购项目配置
22
- - 从App Store下载应用的内购信息
23
- - 生成Boss系统所需的内购配置文件
24
-
25
- 使用示例:
26
- pindo deploy iap path/to/config.json --check
27
- pindo deploy iap path/to/config.json --download
28
- pindo deploy iap path/to/config.json --boss
29
- pindo deploy iap path/to/config.json --download --boss
30
- DESC
31
-
32
- self.arguments = [
33
- CLAide::Argument.new('path/to/config.json', true),
34
- ]
35
-
36
- def self.options
37
- [
38
-
39
- ['--check', '检查iap信息'],
40
- ['--download', '从appstore下载app的iap信息,用法: pindo deploy iap --download'],
41
- ['--boss', '生成boss的iap信息, 用法: pindo deploy iap --boss'],
42
-
43
- ].concat(super)
44
- end
45
-
46
- def validate!
47
- super
48
-
49
- pindo_dir = File::expand_path(pindo_single_config.pindo_dir)
50
- config_repo_dir = File.join(pindo_dir, @bundle_id)
51
- @iapconfig_dir =File.join(config_repo_dir, "fastlane/iap")
52
-
53
- puts "iap dir: " + @iapconfig_dir
54
- puts
55
-
56
- end
57
-
58
- def initialize(argv)
59
-
60
- @check_flag = argv.flag?('check', false)
61
- @download_flag = argv.flag?('download', false)
62
- @boss_flag = argv.flag?('boss', false)
63
-
64
- super
65
- end
66
-
67
- def run
68
-
69
-
70
- if @download_flag
71
-
72
- login_api_key(apple_id:@apple_id)
73
- Spaceship::Tunes.login(@apple_id)
74
-
75
- appstore_iap_file = File.join(@iapconfig_dir, "iap_appstore_download.json")
76
- download_appstore_iap(appstore_iap_file:appstore_iap_file)
77
- elsif @boss_flag
78
-
79
- # puts "default boss vip auto =========\n\n\n"
80
- # appstore_iap_file = File.join(@iapconfig_dir, "iap_appstore.json")
81
- # produce_boss_iap(appstore_iap_file:appstore_iap_file, vip_mode:"autovip")
82
-
83
- puts "one === first auto vip for boss =========\n\n\n"
84
- appstore_iap_file = File.join(@iapconfig_dir, "one/iap_appstore.json")
85
- produce_boss_iap(appstore_iap_file:appstore_iap_file, vip_mode:"autovip")
86
-
87
- puts "two === second fancy vip for boss =========\n\n\n"
88
- appstore_iap_file = File.join(@iapconfig_dir, "two/iap_appstore.json")
89
- produce_boss_iap(appstore_iap_file:appstore_iap_file, vip_mode:"fancyvip")
90
-
91
- puts "three === third funny vip for boss =========\n\n\n"
92
- appstore_iap_file = File.join(@iapconfig_dir, "three/iap_appstore.json")
93
- produce_boss_iap(appstore_iap_file:appstore_iap_file, vip_mode:"funnyvip")
94
-
95
- else
96
-
97
- login_api_key(apple_id:@apple_id)
98
- Spaceship::Tunes.login(@apple_id)
99
-
100
- create_iap_tester()
101
- appstore_iap_file = File.join(@iapconfig_dir, "iap_appstore.json")
102
- create_appstore_iap(appstore_iap_file:appstore_iap_file)
103
- end
104
- end
105
-
106
- def download_appstore_iap(appstore_iap_file:nil)
107
- puts "正在下载appstore iap 信息 ..."
108
-
109
- app_list_response = @app_store_connect.list_apps(filter: {
110
- bundle_id: @bundle_id
111
- })
112
-
113
- current_app = nil
114
- app_list_response[:data].each do |app_info|
115
- if app_info[:attributes][:bundle_id].to_s.eql?(@bundle_id)
116
- current_app = app_info
117
- end
118
- end
119
-
120
- app_id = current_app[:id]
121
-
122
- puts " "
123
- puts "app_id : #{app_id} +++++++++"
124
-
125
- in_app_purchase_json = {}
126
-
127
- puts "正在下载消耗型购买项..."
128
- in_app_purchase_type = "CONSUMABLE"
129
- in_app_purchase_json["consumable"] = get_consumable_iap_items(appstore_client:@app_store_connect, app_id:app_id, in_app_purchase_type:in_app_purchase_type) || []
130
-
131
- puts "正在下载非消耗型购买项..."
132
- in_app_purchase_type = "NON_CONSUMABLE"
133
- in_app_purchase_json["non_consumable"] = get_consumable_iap_items(appstore_client:@app_store_connect, app_id:app_id, in_app_purchase_type:in_app_purchase_type) || []
134
-
135
- puts "正在下载非自动订阅购买项..."
136
- in_app_purchase_type = "NON_RENEWING_SUBSCRIPTION"
137
- in_app_purchase_json["non_renew"] = get_consumable_iap_items(appstore_client:@app_store_connect, app_id:app_id, in_app_purchase_type:in_app_purchase_type) || []
138
-
139
- puts "正在下载自动订阅购买项..."
140
- subscription_group_items = get_subscriptions_groups(appstore_client:@app_store_connect, app_id:app_id)
141
- in_app_purchase_json["auto_renew"] = subscription_group_items
142
-
143
- puts JSON.pretty_generate(in_app_purchase_json)
144
- File.open(appstore_iap_file, "w") do |f|
145
- f.write(JSON.pretty_generate(in_app_purchase_json))
146
- end
147
-
148
- pindo_dir = File::expand_path(pindo_single_config.pindo_dir)
149
- config_repo_dir = File.join(pindo_dir, @deploy_identifier)
150
- git_addpush_repo(path:config_repo_dir, message:"download app iap", commit_file_params:["fastlane/iap/iap_appstore_download.json"])
151
-
152
- update_app_share_secrets(app_id:app_id, need_create:false)
153
- end
154
-
155
- def produce_boss_iap(appstore_iap_file:nil, vip_mode:"autovip")
156
-
157
- if !File.exist?(appstore_iap_file)
158
-
159
- return
160
- end
161
-
162
- appstore_iap_file =File::expand_path(appstore_iap_file)
163
- appstore_iap_json = JSON.parse(File.read(appstore_iap_file))
164
-
165
- boss_iap_file =File.join(File::dirname(appstore_iap_file), "iap_boss.json")
166
-
167
-
168
- if !appstore_iap_json.nil? && !appstore_iap_json["auto_renew"].nil?
169
-
170
- appstore_iap_json["auto_renew"].each do |vip_group_item|
171
- if !vip_group_item.nil?
172
-
173
- appstore_iap_items = vip_group_item["items"] || vip_group_item["subscription_items"]
174
-
175
- boss_iap_json = {
176
- "client_vip" => {
177
- "situation_list" => [],
178
- "style_list" => []
179
- },
180
- "offer_map" => {}
181
- }
182
-
183
- situation_list_item = {
184
- "situation" => "launch",
185
- "style" => "tribble_style"
186
- }
187
- style_list_item = {
188
- "style" => "tribble_style",
189
- "best_deal" => "offer.id." + vip_mode + "0",
190
- "offer" => []
191
- }
192
-
193
- if !appstore_iap_items.nil? && appstore_iap_items.size > 0
194
- appstore_iap_items.each do |appstore_iap_item|
195
- boss_iap_item = {}
196
- boss_iap_item["offer_id"] = "offer.id." + vip_mode
197
- boss_iap_item["kind"] = "vip"
198
- boss_iap_item["way"] = "iap"
199
- boss_iap_item["type"] = "auto_renewable_subscription"
200
- boss_iap_item["subscription"] = {}
201
-
202
- if !appstore_iap_item["subscription_free_trial"].nil? && appstore_iap_item["subscription_free_trial"].eql?("3d")
203
- boss_iap_item["free_days"] = 3
204
- end
205
- boss_iap_item["iap"] = {}
206
- boss_iap_item["iap"]["price"] = appstore_iap_item["price"]
207
-
208
- if appstore_iap_item["subscription_duration"].include?("w")
209
- boss_iap_item["offer_id"] = boss_iap_item["offer_id"] + "0"
210
- boss_iap_item["subscription"]["period_type"] = "week"
211
- boss_iap_item["subscription"]["period"] = appstore_iap_item["subscription_duration"].gsub('w', '').to_i
212
- elsif appstore_iap_item["subscription_duration"].include?("m")
213
- boss_iap_item["offer_id"] = boss_iap_item["offer_id"] + "1"
214
- boss_iap_item["subscription"]["period_type"] = "month"
215
- boss_iap_item["subscription"]["period"] = appstore_iap_item["subscription_duration"].gsub('m', '').to_i
216
- boss_iap_item["iap"]["discount"] = 15
217
- elsif appstore_iap_item["subscription_duration"].include?("y")
218
- boss_iap_item["offer_id"] = boss_iap_item["offer_id"] + "2"
219
- boss_iap_item["subscription"]["period_type"] = "year"
220
- boss_iap_item["subscription"]["period"] = appstore_iap_item["subscription_duration"].gsub('y', '').to_i
221
- boss_iap_item["iap"]["discount"] = 50
222
- end
223
-
224
- if !boss_iap_item["iap"]["price"].to_s.include?("$")
225
- boss_iap_item["iap"]["price"] = "$" + boss_iap_item["iap"]["price"].to_s
226
- end
227
-
228
- boss_iap_item["iap"]["product_id"] = appstore_iap_item["product_id"]
229
- if boss_iap_item["iap"]["product_id"].include?("PRODUCT_BUNDLE_IDENTIFIER")
230
- temp_product_id = boss_iap_item["iap"]["product_id"]
231
- temp_product_id = temp_product_id.gsub(/PRODUCT_BUNDLE_IDENTIFIER/, @bundle_id);
232
- boss_iap_item["iap"]["product_id"] = temp_product_id
233
- end
234
-
235
- boss_iap_json["offer_map"][boss_iap_item["offer_id"]] = boss_iap_item
236
- style_list_item["offer"] << boss_iap_item["offer_id"]
237
- end
238
-
239
- if style_list_item["offer"].size == 3
240
- situation_list_item["style"] = "tribble_style"
241
- style_list_item["style"] = "tribble_style"
242
- elsif style_list_item["offer"].size == 2
243
- situation_list_item["style"] = "double_style"
244
- style_list_item["style"] = "double_style"
245
- elsif style_list_item["offer"].size == 1
246
- situation_list_item["style"] = "single_style"
247
- style_list_item["style"] = "single_style"
248
- end
249
-
250
- boss_iap_json["client_vip"]["situation_list"] << situation_list_item
251
- boss_iap_json["client_vip"]["style_list"] << style_list_item
252
- end
253
-
254
- puts JSON.pretty_generate(boss_iap_json)
255
- puts "\n\n\n"
256
- File.open(boss_iap_file, "w") do |f|
257
- f.write(JSON.pretty_generate(boss_iap_json))
258
- end
259
-
260
-
261
- end
262
- end
263
- end
264
-
265
- end
266
-
267
-
268
- def update_app_share_secrets(app_id:nil, need_create:true)
269
-
270
- app_secret_id = get_app_share_secrets(app_id:app_id, need_create:need_create)
271
- if !app_secret_id.nil?
272
- puts
273
- puts "App Shared Secret: #{app_secret_id}"
274
- puts
275
- pindo_dir = File::expand_path(pindo_single_config.pindo_dir)
276
- config_repo_dir = File.join(pindo_dir, @deploy_identifier)
277
-
278
- app_origin_config = File.join(config_repo_dir, "config.json")
279
- config_json = JSON.parse(File.read(app_origin_config))
280
- config_json['app_info']['appstore_iap_secret'] = app_secret_id
281
- File.open(app_origin_config, "w") do |file|
282
- file.write(JSON.pretty_generate(config_json))
283
- file.close
284
- end
285
-
286
- config_json = JSON.parse(File.read(@args_appconfig_fullname))
287
- config_json['app_info']['appstore_iap_secret'] = app_secret_id
288
- File.open(@args_appconfig_fullname, "w") do |file|
289
- file.write(JSON.pretty_generate(config_json))
290
- file.close
291
- end
292
-
293
- git_addpush_repo(path:config_repo_dir, message:"update app shared secret", commit_file_params:["config.json"])
294
-
295
- end
296
-
297
-
298
- end
299
-
300
- def create_appstore_iap(appstore_iap_file:nil)
301
-
302
- temp_iap_json = JSON.parse(File.read(appstore_iap_file))
303
-
304
- if @check_flag
305
- check_purchase_items_right(in_app_purchase_json:temp_iap_json, config_json:@config_json)
306
- end
307
-
308
- in_app_purchase_json = process_purchase_items(in_app_purchase_json:temp_iap_json, iap_tester:@iaptester)
309
-
310
-
311
- app_list_response = @app_store_connect.list_apps(filter: {
312
- bundle_id: @bundle_id
313
- })
314
-
315
-
316
- # puts app_list_response
317
- current_app = nil
318
-
319
- app_list_response[:data].each do |app_info|
320
- if app_info[:attributes][:bundle_id].to_s.eql?(@bundle_id)
321
- current_app = app_info
322
- end
323
- end
324
-
325
- app_id = current_app[:id]
326
-
327
- puts " "
328
- puts "app_id : #{app_id} +++++++++"
329
-
330
- puts " "
331
- puts "创建消耗型购买项============="
332
- create_consumable_iap_items(appstore_client:@app_store_connect, app_id:app_id, in_app_purchase_items:in_app_purchase_json["consumable"])
333
-
334
- puts " "
335
- puts "创建非消耗型购买项============="
336
- create_consumable_iap_items(appstore_client:@app_store_connect, app_id:app_id, in_app_purchase_items:in_app_purchase_json["non_consumable"])
337
-
338
- puts " "
339
- puts "创建非续期订阅购买项============="
340
- create_consumable_iap_items(appstore_client:@app_store_connect, app_id:app_id, in_app_purchase_items:in_app_purchase_json["non_renew"])
341
-
342
- puts " "
343
- puts "创建自动订阅购买项============="
344
- create_subscriptions_groups(appstore_client:@app_store_connect, app_id:app_id, subscription_group_items:in_app_purchase_json["auto_renew"])
345
-
346
- update_app_share_secrets(app_id:app_id)
347
- end
348
-
349
- def login_api_key (apple_id:nil)
350
-
351
- load_apikey_config = false
352
- api_key_json = nil
353
- pindo_dir = File::expand_path(pindo_single_config.pindo_dir)
354
- api_key_file = File.join(pindo_dir, "api_key.json")
355
-
356
- if File.exist?(api_key_file)
357
- api_key_json = JSON.parse(File.read(api_key_file))
358
- if !api_key_json.nil? && !api_key_json[apple_id].nil? && !api_key_json[apple_id]["issuer_id"].nil?
359
- issuer_id = api_key_json[apple_id]["issuer_id"]
360
- key_id = api_key_json[apple_id]["key_id"]
361
- private_key = api_key_json[apple_id]["private_key"]
362
- load_apikey_config = true
363
- end
364
- end
365
-
366
- if !load_apikey_config
367
- issuer_id = ask('请输入 issuer_id: ')
368
- key_id = ask('请输入 key_id: ')
369
- private_key_file = ask('请输入private key的文件路径: ')
370
- private_key = File.read(File.new(private_key_file))
371
-
372
- api_key_json = api_key_json || {}
373
- api_key_json[apple_id] = api_key_json[apple_id] || {}
374
- api_key_json[apple_id]["issuer_id"] = issuer_id
375
- api_key_json[apple_id]["key_id"] = key_id
376
- api_key_json[apple_id]["private_key"] = private_key
377
-
378
- answer = agree("请确认上面信息是否正确(Y/n):")
379
- unless answer
380
- raise Informative, "重新输入 !!!"
381
- end
382
-
383
- File.open(api_key_file, "w") do |f|
384
- f.write(JSON.pretty_generate(api_key_json))
385
- end
386
- load_apikey_config = true
387
-
388
-
389
- end
390
-
391
- if load_apikey_config
392
-
393
- puts "issuer_id : #{issuer_id}"
394
- puts "key_id : #{key_id}"
395
- puts "private_key : #{private_key}"
396
-
397
- AppStoreDevApi.config = {
398
- issuer_id: issuer_id,
399
- key_id: key_id,
400
- private_key: private_key
401
- }
402
- @app_store_connect = AppStoreDevApi::Client.new
403
- end
404
- end
405
-
406
-
407
- def check_purchase_items_right(in_app_purchase_json:nil, config_json:nil)
408
-
409
- puts
410
- puts "检查iap 配置"
411
- puts
412
- app_version = @config_json["app_info"]["app_version"]
413
- bundle_id = @bundle_id
414
- platform = @config_json["app_setting"]["kGUKeyAppPlatform"] || @config_json["app_setting"]["app_platform"]
415
- app_type = @config_json["project_info"]["app_type"]
416
-
417
- boss_client = BossClient.new(app_type:app_type, is_dev:false)
418
- data_json = Pindo::Command::Utils::Boss::get_config(boss_client:boss_client, app_version:app_version, bundle_id:bundle_id, platform:platform)
419
-
420
- # if !data_json["data"].nil?
421
- # puts JSON.pretty_generate(data_json["data"])
422
- # else
423
- # puts JSON.pretty_generate(data_json)
424
- # end
425
-
426
- gate_vip_items = get_gate_vip_items(app_type:app_type, boss_config:data_json["data"])
427
-
428
- if !gate_vip_items.nil? && gate_vip_items.size > 0
429
- itc_vip_items = []
430
- in_app_purchase_json["auto_renew"].each do |group_item|
431
- items = group_item["subscription_items"] || []
432
- itc_vip_items += items
433
- items = group_item["items"] || []
434
- itc_vip_items += items
435
- end
436
-
437
-
438
- gate_vip_items.each do |offer_id, boss_iap_item|
439
- boss_product_id = boss_iap_item["iap"]["product_id"]
440
- boss_price = boss_iap_item["iap"]["price"]
441
- free_days = boss_iap_item["free_days"]
442
-
443
- itc_vip_item = itc_vip_items.find { |item| item["product_id"].eql?(boss_product_id)}
444
- if !itc_vip_item.nil?
445
- puts "product id: #{boss_product_id} 与boss一致!"
446
-
447
- if boss_price.eql?("$"+itc_vip_item["price"].to_s)
448
- puts " 价格一致! 价格:#{boss_price}"
449
- else
450
- local_price = itc_vip_item["price"].to_s
451
- raise Informative, " 价格不一致 Boss:#{boss_price}, Local:$#{local_price}"
452
- end
453
-
454
- if !itc_vip_item["subscription_free_trial"].nil? && !free_days.nil? && itc_vip_item["subscription_free_trial"].to_s.eql?(free_days.to_s + "d")
455
- puts " 有三天试用, 一致!"
456
- elsif itc_vip_item["subscription_free_trial"].nil? && free_days.nil?
457
- puts " 无三天试用, 一致!"
458
- else
459
- raise Informative, " 三天试用不一致!"
460
- end
461
-
462
-
463
- else
464
- raise Informative, "product id: #{boss_product_id} 与boss不匹配!"
465
- end
466
- end
467
- end
468
-
469
- offer_vip_items = get_gate_vip_items(app_type:app_type, boss_config:data_json["data"])
470
- end
471
-
472
-
473
-
474
-
475
- def get_gate_vip_items(app_type:nil, boss_config:nil)
476
- vip_items = nil
477
-
478
- offer_ids = []
479
- if !boss_config.nil? && !boss_config["content"].nil? && !boss_config["content"]["client"].nil? && !boss_config["content"]["client"]["vip"].nil? && !boss_config["content"]["client"]["vip"]["style_list"].nil?
480
- style_list = boss_config["content"]["client"]["vip"]["style_list"] || {}
481
- style_item = style_list.find { |item| item["style"].eql?("tribble_style")}
482
- offer_ids = style_item["offer"] || []
483
- end
484
-
485
- if !boss_config.nil? && !boss_config["content"].nil? && !boss_config["content"]["common"].nil? && !boss_config["content"]["common"].nil? && !boss_config["content"]["common"]["offer_map"].nil?
486
- boss_vip_items = boss_config["content"]["common"]["offer_map"]
487
- vip_items = vip_items || {}
488
- offer_ids.each do |offer_id|
489
- if !boss_vip_items[offer_id].nil?
490
- vip_items[offer_id] = boss_vip_items[offer_id]
491
- end
492
- end
493
- end
494
-
495
- return vip_items
496
- end
497
-
498
- def process_purchase_items(in_app_purchase_json:nil, iap_tester:nil)
499
- new_in_app_purchase_json = {}
500
- new_in_app_purchase_json["iaptester"] = @iaptester
501
- new_in_app_purchase_json["bundle_id"] = @bundle_id
502
-
503
- new_in_app_purchase_json["review_note"] = "username: " + iap_tester["email"] + " password: " + iap_tester["password"]
504
-
505
- puts
506
- puts
507
- puts new_in_app_purchase_json["review_note"]
508
-
509
- in_app_purchase_type = "CONSUMABLE"
510
- items = process_consumable_iap_items(in_app_purchase_type:in_app_purchase_type, in_app_purchase_items:in_app_purchase_json["consumable"], iap_tester:iap_tester)
511
- new_in_app_purchase_json["consumable"] = items
512
-
513
- in_app_purchase_type = "NON_CONSUMABLE"
514
- items = process_consumable_iap_items(in_app_purchase_type:in_app_purchase_type, in_app_purchase_items:in_app_purchase_json["non_consumable"], iap_tester:iap_tester)
515
- new_in_app_purchase_json["non_consumable"] = items
516
-
517
- in_app_purchase_type = "NON_RENEWING_SUBSCRIPTION"
518
- items = process_consumable_iap_items(in_app_purchase_type:in_app_purchase_type, in_app_purchase_items:in_app_purchase_json["non_renew"], iap_tester:iap_tester)
519
- new_in_app_purchase_json["non_renew"] = items
520
-
521
- in_app_purchase_type = "Subscriptions"
522
- new_subscrptions_json = process_subscriptions_json(subscription_json:in_app_purchase_json["auto_renew"], iap_tester:iap_tester)
523
- new_in_app_purchase_json["auto_renew"] = new_subscrptions_json
524
-
525
- File.open(File.join(@iapconfig_dir, "iap_log.json"), "w") do |f|
526
- f.write(JSON.pretty_generate(new_in_app_purchase_json))
527
- end
528
-
529
- return new_in_app_purchase_json;
530
-
531
- end
532
-
533
- def process_consumable_iap_items(in_app_purchase_type:nil, in_app_purchase_items:nil, iap_tester:nil)
534
-
535
- tier_json = get_price_tier_dict
536
- iap_consumable_tier_dict = tier_json["consumable_price_tier"]
537
-
538
- in_app_purchase_items = in_app_purchase_items || []
539
- new_in_app_purchase_items = []
540
- in_app_purchase_items.each do |purchase_item|
541
- new_iap_items = {}
542
- new_iap_items["reference_name"] = purchase_item["reference_name"].to_s.strip || purchase_item["product_name"].to_s.strip
543
- if !purchase_item["reference_name"].nil? && purchase_item["reference_name"].length > 64
544
- puts purchase_item["reference_name"]
545
- puts "length: #{purchase_item["reference_name"].size}"
546
- raise Informative, "Reference Name 超出限定的64个字符 !!!"
547
- end
548
-
549
- temp_product_id = purchase_item["product_id"].to_s.strip
550
- new_iap_items["product_id"] = temp_product_id
551
- if new_iap_items["product_id"].include?("PRODUCT_BUNDLE_IDENTIFIER")
552
- temp_product_id = new_iap_items["product_id"]
553
- temp_product_id = temp_product_id.gsub(/PRODUCT_BUNDLE_IDENTIFIER/, @bundle_id);
554
- new_iap_items["product_id"] = temp_product_id
555
- end
556
- if !new_iap_items["product_id"].nil? && new_iap_items["product_id"].length > 100
557
- puts temp_product_id
558
- raise Informative, "product_id 超出限定的100个字符 !!!"
559
- end
560
-
561
- new_iap_items["in_app_purchase_type"] = in_app_purchase_type
562
- new_iap_items["price"] = purchase_item["price"].to_s.strip
563
- new_iap_items["price_tier"] = iap_consumable_tier_dict[new_iap_items["price"].to_s]
564
-
565
- if new_iap_items["price_tier"].nil?
566
- raise "购买项价格错误 " + new_iap_items["product_id"] + " 价格 :" + purchase_item["price"]
567
- end
568
-
569
- new_iap_items["localization"] = {}
570
- new_iap_items["localization"]["en-US"] = {}
571
- new_iap_items["localization"]["en-US"]["locale"] = "en-US"
572
- new_iap_items["localization"]["en-US"]["display_name"] = purchase_item["display_name"].to_s.strip
573
-
574
- if !new_iap_items["localization"]["en-US"]["display_name"].nil? && new_iap_items["localization"]["en-US"]["display_name"].length > 30
575
- puts temp_product_id
576
- raise Informative, "Display Name 超出限定的30个字符 !!!"
577
- end
578
-
579
- new_iap_items["localization"]["en-US"]["description"] = purchase_item["description"].to_s.strip
580
- if !new_iap_items["localization"]["en-US"]["description"].nil? && new_iap_items["localization"]["en-US"]["description"].length > 45
581
- puts temp_product_id
582
- raise Informative, "purchuse description 超出限定的45个字符 !!!"
583
- end
584
-
585
- new_iap_items["review_note"] = "username: " + iap_tester["email"] + " password: " + iap_tester["password"]
586
- if !purchase_item["review_screenshot"].nil?
587
- new_iap_items["review_screenshot"] = File.basename(purchase_item["review_screenshot"])
588
- new_iap_items["review_screenshot_fullpath"] = File.join(@iapconfig_dir, new_iap_items["review_screenshot"])
589
- else
590
- new_iap_items["review_screenshot_fullpath"] = nil
591
- end
592
-
593
- new_in_app_purchase_items << new_iap_items
594
- end
595
-
596
- return new_in_app_purchase_items
597
- end
598
-
599
-
600
- def process_subscriptions_json(subscription_json:nil, iap_tester:nil)
601
-
602
- tier_json = get_price_tier_dict
603
- subscription_json = subscription_json || []
604
- new_subscription_json = []
605
- subscription_json.each do |subscription_group_item|
606
- new_subscription_group_item = {}
607
- new_subscription_group_item["group_reference_name"] = subscription_group_item["group_reference_name"].to_s.strip
608
- new_subscription_group_item["localization"] = {}
609
- new_subscription_group_item["localization"]["en-US"] = {}
610
- new_subscription_group_item["localization"]["en-US"]["locale"] = "en-US"
611
- new_subscription_group_item["localization"]["en-US"]["group_display_name"] = subscription_group_item["group_display_name"].to_s.strip
612
-
613
- if !new_subscription_group_item["localization"]["en-US"]["group_display_name"].nil? && new_subscription_group_item["localization"]["en-US"]["group_display_name"].length > 45
614
- puts new_subscription_group_item["localization"]["en-US"]["group_display_name"]
615
- raise Informative, "group_display_name 超出限定的75个字符 !!!"
616
- end
617
- new_subscription_group_item["localization"]["en-US"]["custom_app_name"] = subscription_group_item["custom_app_name"].to_s.strip
618
- if !new_subscription_group_item["localization"]["en-US"]["custom_app_name"].nil? && new_subscription_group_item["localization"]["en-US"]["custom_app_name"].length > 45
619
- puts new_subscription_group_item["localization"]["en-US"]["custom_app_name"]
620
- raise Informative, "custom_app_name 超出限定的30个字符 !!!"
621
- end
622
-
623
- new_subscription_group_item["subscription_items"] = []
624
-
625
- old_subscription_group_items = subscription_group_item["subscription_items"] || []
626
- if old_subscription_group_items.size <= 0 && !subscription_group_item["items"].nil?
627
- old_subscription_group_items = subscription_group_item["items"] || []
628
- end
629
-
630
- new_subscription_group_item["subscription_items"] = process_subscriptions_item(subscription_items:old_subscription_group_items, iap_tester:iap_tester, subscription_duration_dict:tier_json["subscription_duration"])
631
- new_subscription_json << new_subscription_group_item
632
- end
633
-
634
- return new_subscription_json
635
- end
636
-
637
- def process_subscriptions_item(subscription_items:nil, iap_tester:nil, subscription_duration_dict:nil)
638
-
639
-
640
- subscription_items = subscription_items || []
641
- new_subscription_items = []
642
- subscription_items.each do |subs_item|
643
- new_subs_item = {}
644
-
645
- new_subs_item["reference_name"] = subs_item["reference_name"].to_s.strip || subs_item["product_name"].to_s.strip
646
- if !new_subs_item["reference_name"].nil? && new_subs_item["reference_name"].length > 64
647
- puts new_subs_item["reference_name"]
648
- raise Informative, " Reference Name 超出限定的64个字符 !!!"
649
- end
650
-
651
- new_subs_item["product_id"] = subs_item["product_id"].to_s.strip
652
- temp_product_id = new_subs_item["product_id"]
653
- if new_subs_item["product_id"].include?("PRODUCT_BUNDLE_IDENTIFIER")
654
- temp_product_id = new_subs_item["product_id"]
655
- temp_product_id = temp_product_id.gsub(/PRODUCT_BUNDLE_IDENTIFIER/, @bundle_id);
656
- new_subs_item["product_id"] = temp_product_id
657
- end
658
-
659
- if !new_subs_item["product_id"].nil? && new_subs_item["product_id"].length > 100
660
- puts temp_product_id
661
- raise Informative, "product_id 超出限定的100个字符 !!!"
662
- end
663
-
664
- new_subs_item["family_sharable"] = false
665
- new_subs_item["price"] = subs_item["price"].to_s.strip
666
- new_subs_item["subscription_duration"] = subscription_duration_dict[subs_item["subscription_duration"]]
667
-
668
- if !subs_item["subscription_free_trial"].nil?
669
- new_subs_item["subscription_free_trial"] = subs_item["subscription_free_trial"]
670
- end
671
- new_subs_item["localization"] = {}
672
- new_subs_item["localization"]["en-US"] = {}
673
- new_subs_item["localization"]["en-US"]["locale"] = "en-US"
674
- new_subs_item["localization"]["en-US"]["display_name"] = subs_item["display_name"].to_s.strip
675
- if !new_subs_item["localization"]["en-US"]["display_name"].nil? && new_subs_item["localization"]["en-US"]["display_name"].length > 30
676
- puts temp_product_id
677
- raise Informative, "Display Name 超出限定的30个字符 !!!"
678
-
679
- end
680
- new_subs_item["localization"]["en-US"]["description"] = subs_item["description"].to_s.strip
681
- if !new_subs_item["localization"]["en-US"]["description"].nil? && new_subs_item["localization"]["en-US"]["description"].length > 45
682
- puts temp_product_id
683
- raise Informative, "Description 超出限定的45个字符 !!!"
684
- end
685
-
686
- new_subs_item["review_note"] = "username: " + iap_tester["email"] + " password: " + iap_tester["password"]
687
- if !subs_item["review_screenshot"].nil?
688
- new_subs_item["review_screenshot"] = File.basename(subs_item["review_screenshot"])
689
- new_subs_item["review_screenshot_fullpath"] = File.join(@iapconfig_dir, new_subs_item["review_screenshot"])
690
- else
691
- new_subs_item["review_screenshot_fullpath"] = nil
692
- end
693
-
694
-
695
- new_subscription_items << new_subs_item
696
- end
697
-
698
- return new_subscription_items
699
- end
700
-
701
-
702
- def itc_has_sandbox_tester(email:nil)
703
-
704
- has_sandbox_account = false
705
- begin
706
- response = @app_store_connect.list_sandbox_testers()
707
- # puts JSON.pretty_generate(response)
708
- has_sandbox_account = false
709
- response[:data].each do |tester_item|
710
- if tester_item[:attributes][:ac_account_name].to_s.eql?(@iaptester['email'])
711
- has_sandbox_account = true
712
- # puts "itc_has_sandbox_tester SandboxTester : " + @iaptester['email'] + "账号已经存在"
713
- end
714
- end
715
- rescue => err
716
-
717
- end
718
-
719
- if !has_sandbox_account
720
-
721
- begin
722
- testers = Spaceship::ConnectAPI::SandboxTester.all()
723
- if !testers.nil? && testers.size > 0
724
- testers.each do | tester_item |
725
- # puts tester_item.email
726
- if tester_item.email.to_s.eql?(@iaptester['email'])
727
- has_sandbox_account = true
728
- # puts "itc_has_sandbox_tester ConnectAPI SandboxTester : " + @iaptester['email'] + "账号已经存在"
729
- end
730
- end
731
- end
732
- rescue => err
733
-
734
- end
735
-
736
- end
737
-
738
- return has_sandbox_account
739
- end
740
-
741
-
742
-
743
- def create_iap_tester_ex( )
744
- b_create_success = false
745
- testers = nil
746
- time = Time.local(1995 - rand(10), 12 - rand(10), 25- rand(20))
747
- birth_date = time.strftime("%Y-%m-%d")
748
- begin
749
- testers = Spaceship::ConnectAPI::SandboxTester.create(
750
- first_name: @iaptester['first_name'],
751
- last_name: @iaptester['last_name'],
752
- email: @iaptester['email'],
753
- password: @iaptester['password'],
754
- confirm_password: @iaptester['password'],
755
- secret_question: @iaptester['password'] + '1234?',
756
- secret_answer: @iaptester['password'],
757
- birth_date:birth_date,
758
- app_store_territory: @iaptester['territory'] || 'USA'
759
- )
760
- rescue => err
761
- b_create_success = false
762
- end
763
-
764
- # if !b_create_success || testers.nil?
765
- # begin
766
- # testers = Spaceship::Tunes::SandboxTester.create!(
767
- # email: @iaptester['email'],
768
- # password: @iaptester['password'],
769
- # first_name: @iaptester['first_name'],
770
- # last_name: @iaptester['last_name'],
771
- # country: @iaptester['territory'] || 'USA'
772
- # )
773
- # puts testers
774
- # rescue => err
775
-
776
- # end
777
- # end
778
-
779
- end
780
-
781
-
782
- def create_iap_tester()
783
-
784
- sandbox_tester_file = File.join(@iapconfig_dir, "iap_tester.json")
785
- sandbox_tester_json = {}
786
- if File.exist?(sandbox_tester_file)
787
- sandbox_tester_json = JSON.parse(File.read(sandbox_tester_file))
788
- else
789
- raise Informative, "缺少沙盒配置文件iap_tester.json !!!"
790
- end
791
-
792
- @iaptester = nil
793
- if !sandbox_tester_json.nil? && !sandbox_tester_json["iaptester"].nil?
794
- @iaptester = sandbox_tester_json["iaptester"]
795
- end
796
-
797
- if !@iaptester.nil? && @iaptester["need_create"]
798
- puts
799
- puts
800
- if itc_has_sandbox_tester(email:@iaptester["email"])
801
-
802
- puts "已存在沙盒账号:#{@iaptester["email"]},无需创建!!!"
803
- else
804
- puts "没有沙盒账号:#{@iaptester["email"]},需新创建!!!"
805
-
806
- create_iap_tester_ex()
807
- if itc_has_sandbox_tester(email:@iaptester["email"])
808
- puts "沙盒账号:#{@iaptester["email"]},创建成功!!!"
809
- else
810
- raise Informative, "沙盒账号:#{@iaptester["email"]},创建失败!!!"
811
- end
812
- end
813
- else
814
- raise Informative, "没有Sandbox Tester !!!"
815
- end
816
-
817
- end
818
-
819
-
820
-
821
-
822
-
823
- end
824
- end
825
- end
826
- end