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