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