fastlane 2.13.0 → 2.14.0
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/credentials_manager/lib/credentials_manager.rb +1 -1
- data/fastlane/lib/fastlane/actions/ipa.rb +2 -1
- data/fastlane/lib/fastlane/actions/mailgun.rb +15 -2
- data/fastlane/lib/fastlane/actions/scan.rb +14 -0
- data/fastlane/lib/fastlane/documentation/docs_generator.rb +24 -1
- data/fastlane/lib/fastlane/environment_printer.rb +2 -1
- data/fastlane/lib/fastlane/fast_file.rb +4 -4
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane_core/lib/fastlane_core.rb +1 -1
- data/fastlane_core/lib/fastlane_core/configuration/config_item.rb +44 -2
- data/fastlane_core/lib/fastlane_core/device_manager.rb +15 -0
- data/fastlane_core/lib/fastlane_core/helper.rb +1 -1
- data/fastlane_core/lib/fastlane_core/ui/disable_colors.rb +4 -4
- data/frameit/lib/frameit/config_parser.rb +8 -13
- data/frameit/lib/frameit/editor.rb +3 -2
- data/gym/lib/gym/options.rb +4 -2
- data/match/README.md +2 -2
- data/match/lib/match.rb +5 -19
- data/match/lib/match/generator.rb +8 -1
- data/match/lib/match/git_helper.rb +3 -1
- data/match/lib/match/nuke.rb +18 -14
- data/match/lib/match/options.rb +13 -2
- data/match/lib/match/runner.rb +20 -8
- data/match/lib/match/table_printer.rb +5 -4
- data/match/lib/match/utils.rb +12 -8
- data/scan/lib/scan/options.rb +24 -1
- data/scan/lib/scan/runner.rb +12 -11
- data/scan/lib/scan/test_command_generator.rb +10 -2
- data/sigh/lib/sigh/download_all.rb +1 -1
- data/sigh/lib/sigh/runner.rb +2 -2
- data/snapshot/lib/snapshot/options.rb +2 -1
- data/snapshot/lib/snapshot/runner.rb +12 -12
- data/spaceship/lib/spaceship.rb +1 -0
- data/spaceship/lib/spaceship/base.rb +27 -4
- data/spaceship/lib/spaceship/client.rb +3 -2
- data/spaceship/lib/spaceship/du/du_client.rb +26 -16
- data/spaceship/lib/spaceship/portal/app.rb +1 -1
- data/spaceship/lib/spaceship/portal/person.rb +53 -0
- data/spaceship/lib/spaceship/portal/persons.rb +49 -0
- data/spaceship/lib/spaceship/portal/portal.rb +2 -0
- data/spaceship/lib/spaceship/portal/portal_client.rb +69 -10
- data/spaceship/lib/spaceship/portal/provisioning_profile.rb +29 -1
- data/spaceship/lib/spaceship/tunes/application.rb +11 -1
- data/spaceship/lib/spaceship/tunes/iap.rb +113 -0
- data/spaceship/lib/spaceship/tunes/iap_detail.rb +185 -0
- data/spaceship/lib/spaceship/tunes/iap_families.rb +62 -0
- data/spaceship/lib/spaceship/tunes/iap_family_details.rb +59 -0
- data/spaceship/lib/spaceship/tunes/iap_family_list.rb +33 -0
- data/spaceship/lib/spaceship/tunes/iap_list.rb +72 -0
- data/spaceship/lib/spaceship/tunes/iap_status.rb +48 -0
- data/spaceship/lib/spaceship/tunes/iap_type.rb +45 -0
- data/spaceship/lib/spaceship/tunes/tunes.rb +1 -0
- data/spaceship/lib/spaceship/tunes/tunes_client.rb +163 -1
- metadata +21 -5
@@ -8,6 +8,7 @@ require 'spaceship/helper/net_http_generic_request'
|
|
8
8
|
require 'spaceship/helper/plist_middleware'
|
9
9
|
require 'spaceship/ui'
|
10
10
|
require 'tmpdir'
|
11
|
+
require 'cgi'
|
11
12
|
|
12
13
|
Faraday::Utils.default_params_encoder = Faraday::FlatParamsEncoder
|
13
14
|
|
@@ -78,8 +79,8 @@ module Spaceship
|
|
78
79
|
|
79
80
|
[
|
80
81
|
"Apple provided the following error info:",
|
81
|
-
@error_info['resultString'],
|
82
|
-
@error_info['userString']
|
82
|
+
CGI.unescapeHTML(@error_info['resultString']),
|
83
|
+
CGI.unescapeHTML(@error_info['userString'])
|
83
84
|
].compact.uniq # sometimes 'resultString' and 'userString' are the same value
|
84
85
|
end
|
85
86
|
end
|
@@ -15,49 +15,59 @@ module Spaceship
|
|
15
15
|
#####################################################
|
16
16
|
|
17
17
|
def upload_screenshot(app_version, upload_file, content_provider_id, sso_token_for_image, device, is_messages)
|
18
|
-
upload_file(app_version, upload_file, '/upload/image', content_provider_id, sso_token_for_image, screenshot_picture_type(device, is_messages))
|
18
|
+
upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/image', content_provider_id: content_provider_id, sso_token: sso_token_for_image, du_validation_rule_set: screenshot_picture_type(device, is_messages))
|
19
|
+
end
|
20
|
+
|
21
|
+
def upload_purchase_review_screenshot(app_id, upload_file, content_provider_id, sso_token_for_image)
|
22
|
+
upload_file(app_id: app_id, upload_file: upload_file, path: '/upload/image', content_provider_id: content_provider_id, sso_token: sso_token_for_image, du_validation_rule_set: 'MZPFT.SortedScreenShot')
|
19
23
|
end
|
20
24
|
|
21
25
|
def upload_large_icon(app_version, upload_file, content_provider_id, sso_token_for_image)
|
22
|
-
upload_file(app_version, upload_file, '/upload/image', content_provider_id, sso_token_for_image, 'MZPFT.LargeApplicationIcon')
|
26
|
+
upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/image', content_provider_id: content_provider_id, sso_token: sso_token_for_image, du_validation_rule_set: 'MZPFT.LargeApplicationIcon')
|
23
27
|
end
|
24
28
|
|
25
29
|
def upload_watch_icon(app_version, upload_file, content_provider_id, sso_token_for_image)
|
26
|
-
upload_file(app_version, upload_file, '/upload/image', content_provider_id, sso_token_for_image, 'MZPFT.GizmoAppIcon')
|
30
|
+
upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/image', content_provider_id: content_provider_id, sso_token: sso_token_for_image, du_validation_rule_set: 'MZPFT.GizmoAppIcon')
|
27
31
|
end
|
28
32
|
|
29
33
|
def upload_geojson(app_version, upload_file, content_provider_id, sso_token_for_image)
|
30
|
-
upload_file(app_version, upload_file, '/upload/geo-json', content_provider_id, sso_token_for_image)
|
34
|
+
upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/geo-json', content_provider_id: content_provider_id, sso_token: sso_token_for_image)
|
31
35
|
end
|
32
36
|
|
33
37
|
def upload_trailer(app_version, upload_file, content_provider_id, sso_token_for_video)
|
34
|
-
upload_file(app_version, upload_file, '/upload/purple-video', content_provider_id, sso_token_for_video)
|
38
|
+
upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/purple-video', content_provider_id: content_provider_id, sso_token: sso_token_for_video)
|
35
39
|
end
|
36
40
|
|
37
41
|
def upload_trailer_preview(app_version, upload_file, content_provider_id, sso_token_for_image)
|
38
|
-
upload_file(app_version, upload_file, '/upload/app-screenshot-image', content_provider_id, sso_token_for_image)
|
42
|
+
upload_file(app_version: app_version, upload_file: upload_file, path: '/upload/app-screenshot-image', content_provider_id: content_provider_id, sso_token: sso_token_for_image)
|
39
43
|
end
|
40
44
|
|
41
45
|
private
|
42
46
|
|
43
|
-
def upload_file(app_version, upload_file, path, content_provider_id, sso_token, du_validation_rule_set
|
47
|
+
def upload_file(app_version: nil, upload_file: nil, path: nil, content_provider_id: nil, sso_token: nil, du_validation_rule_set: nil, app_id: nil)
|
44
48
|
raise "File #{upload_file.file_path} is empty" if upload_file.file_size == 0
|
45
49
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
50
|
+
if app_id
|
51
|
+
app_id = app_id
|
52
|
+
app_type = nil
|
53
|
+
version = nil
|
54
|
+
referrer = nil
|
55
|
+
else
|
56
|
+
version = app_version.version
|
57
|
+
app_id = app_version.application.apple_id
|
58
|
+
app_type = app_version.app_type
|
59
|
+
referrer = app_version.application.url
|
60
|
+
end
|
51
61
|
|
52
62
|
r = request(:post) do |req|
|
53
63
|
req.url "#{self.class.hostname}#{path}"
|
54
64
|
req.body = upload_file.bytes
|
55
65
|
req.headers['Accept'] = 'application/json, text/plain, */*'
|
56
66
|
req.headers['Content-Type'] = upload_file.content_type
|
57
|
-
req.headers['X-Apple-Upload-Referrer'] = referrer
|
58
|
-
req.headers['Referrer'] = referrer
|
67
|
+
req.headers['X-Apple-Upload-Referrer'] = referrer if referrer
|
68
|
+
req.headers['Referrer'] = referrer if referrer
|
59
69
|
req.headers['X-Apple-Upload-AppleId'] = app_id
|
60
|
-
req.headers['X-Apple-Jingle-Correlation-Key'] = "#{app_type}:AdamId=#{app_id}:Version=#{version}"
|
70
|
+
req.headers['X-Apple-Jingle-Correlation-Key'] = "#{app_type}:AdamId=#{app_id}:Version=#{version}" if app_type
|
61
71
|
req.headers['X-Apple-Upload-itctoken'] = sso_token
|
62
72
|
req.headers['X-Apple-Upload-ContentProviderId'] = content_provider_id
|
63
73
|
req.headers['X-Original-Filename'] = upload_file.file_name
|
@@ -67,7 +77,7 @@ module Spaceship
|
|
67
77
|
end
|
68
78
|
|
69
79
|
if r.status == 500 and r.body.include?("Server Error")
|
70
|
-
return upload_file(app_version, upload_file, path, content_provider_id, sso_token, du_validation_rule_set)
|
80
|
+
return upload_file(app_version: app_version, upload_file: upload_file, path: path, content_provider_id: content_provider_id, sso_token: sso_token, du_validation_rule_set: du_validation_rule_set, app_id: app_id)
|
71
81
|
end
|
72
82
|
|
73
83
|
parse_upload_response(r)
|
@@ -103,7 +103,7 @@ module Spaceship
|
|
103
103
|
# @return (App) The app you're looking for. This is nil if the app can't be found.
|
104
104
|
def find(bundle_id, mac: false)
|
105
105
|
all(mac: mac).find do |app|
|
106
|
-
app.bundle_id ==
|
106
|
+
return app if app.bundle_id.casecmp(bundle_id) == 0
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Spaceship
|
2
|
+
module Portal
|
3
|
+
class Person < PortalBase
|
4
|
+
# @return (String) Person Id
|
5
|
+
attr_accessor :person_id
|
6
|
+
|
7
|
+
# @return (String) First name
|
8
|
+
attr_accessor :firstname
|
9
|
+
|
10
|
+
# @return (String) Last name
|
11
|
+
attr_accessor :lastname
|
12
|
+
|
13
|
+
# @return (String) Email Address
|
14
|
+
attr_accessor :email_address
|
15
|
+
|
16
|
+
# @return (String) Developer status (active, inactive)
|
17
|
+
attr_accessor :developer_status
|
18
|
+
|
19
|
+
# @return (String) Joined Date
|
20
|
+
attr_accessor :joined
|
21
|
+
|
22
|
+
# @return (String) Id in Team scope
|
23
|
+
attr_accessor :team_member_id
|
24
|
+
|
25
|
+
# @return (String) Role (member, admin or agent)
|
26
|
+
attr_accessor :type
|
27
|
+
|
28
|
+
attr_mapping(
|
29
|
+
'personId' => :person_id,
|
30
|
+
'firstName' => :firstname,
|
31
|
+
'lastName' => :lastname,
|
32
|
+
'email' => :email_address,
|
33
|
+
'developerStatus' => :developer_status,
|
34
|
+
'dateJoined' => :joined,
|
35
|
+
'teamMemberId' => :team_member_id
|
36
|
+
)
|
37
|
+
|
38
|
+
class << self
|
39
|
+
def factory(attrs)
|
40
|
+
self.new(attrs)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def remove!
|
45
|
+
client.team_remove_member!(team_member_id)
|
46
|
+
end
|
47
|
+
|
48
|
+
def change_role(role)
|
49
|
+
client.team_set_role(team_member_id, role)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Spaceship
|
2
|
+
module Portal
|
3
|
+
class Persons < PortalBase
|
4
|
+
class << self
|
5
|
+
def all
|
6
|
+
members = client.team_members
|
7
|
+
all_members = []
|
8
|
+
member = factory_member(members["members"], "member")
|
9
|
+
admins = factory_member(members["admins"], "admin")
|
10
|
+
agent = factory_member(members["agent"], "agent")
|
11
|
+
|
12
|
+
all_members.concat(member)
|
13
|
+
all_members.concat(admins)
|
14
|
+
all_members << agent
|
15
|
+
|
16
|
+
return all_members
|
17
|
+
end
|
18
|
+
|
19
|
+
def factory_member(members, type)
|
20
|
+
if members.kind_of?(Hash)
|
21
|
+
attrs = members
|
22
|
+
attrs[:type] = type
|
23
|
+
return Spaceship::Portal::Person.factory(attrs)
|
24
|
+
end
|
25
|
+
final_members = []
|
26
|
+
members.each do |member|
|
27
|
+
attrs = member
|
28
|
+
attrs[:type] = type
|
29
|
+
final_members << Spaceship::Portal::Person.factory(attrs)
|
30
|
+
end
|
31
|
+
return final_members
|
32
|
+
end
|
33
|
+
|
34
|
+
def find(email)
|
35
|
+
all.each do |member|
|
36
|
+
if member.email_address == email
|
37
|
+
return member
|
38
|
+
end
|
39
|
+
end
|
40
|
+
return nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def invite(email, role)
|
44
|
+
client.team_invite(email, role)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -236,6 +236,62 @@ module Spaceship
|
|
236
236
|
parse_response(r)
|
237
237
|
end
|
238
238
|
|
239
|
+
#####################################################
|
240
|
+
# @!group Team
|
241
|
+
#####################################################
|
242
|
+
def team_members
|
243
|
+
response = request(:post) do |req|
|
244
|
+
req.url "/services-account/#{PROTOCOL_VERSION}/account/getTeamMembers"
|
245
|
+
req.body = {
|
246
|
+
teamId: team_id
|
247
|
+
}.to_json
|
248
|
+
req.headers['Content-Type'] = 'application/json'
|
249
|
+
end
|
250
|
+
parse_response(response)
|
251
|
+
end
|
252
|
+
|
253
|
+
def team_set_role(team_member_id, role)
|
254
|
+
ensure_csrf(Spaceship::Portal::Persons)
|
255
|
+
response = request(:post) do |req|
|
256
|
+
req.url "/services-account/#{PROTOCOL_VERSION}/account/setTeamMemberRoles"
|
257
|
+
req.body = {
|
258
|
+
teamId: team_id,
|
259
|
+
role: role,
|
260
|
+
teamMemberIds: [team_member_id]
|
261
|
+
}.to_json
|
262
|
+
req.headers['Content-Type'] = 'application/json'
|
263
|
+
end
|
264
|
+
parse_response(response)
|
265
|
+
end
|
266
|
+
|
267
|
+
def team_remove_member!(team_member_id)
|
268
|
+
ensure_csrf(Spaceship::Portal::Persons)
|
269
|
+
response = request(:post) do |req|
|
270
|
+
req.url "/services-account/#{PROTOCOL_VERSION}/account/removeTeamMembers"
|
271
|
+
req.body = {
|
272
|
+
teamId: team_id,
|
273
|
+
teamMemberIds: [team_member_id]
|
274
|
+
}.to_json
|
275
|
+
req.headers['Content-Type'] = 'application/json'
|
276
|
+
end
|
277
|
+
parse_response(response)
|
278
|
+
end
|
279
|
+
|
280
|
+
def team_invite(email, role)
|
281
|
+
ensure_csrf(Spaceship::Portal::Persons)
|
282
|
+
response = request(:post) do |req|
|
283
|
+
req.url "/services-account/#{PROTOCOL_VERSION}/account/sendInvites"
|
284
|
+
req.body = {
|
285
|
+
invites: [
|
286
|
+
{ recipientEmail: email, recipientRole: role }
|
287
|
+
],
|
288
|
+
teamId: team_id
|
289
|
+
}.to_json
|
290
|
+
req.headers['Content-Type'] = 'application/json'
|
291
|
+
end
|
292
|
+
parse_response(response)
|
293
|
+
end
|
294
|
+
|
239
295
|
#####################################################
|
240
296
|
# @!group Devices
|
241
297
|
#####################################################
|
@@ -427,20 +483,23 @@ module Spaceship
|
|
427
483
|
parse_response(r)
|
428
484
|
end
|
429
485
|
|
430
|
-
def repair_provisioning_profile!(profile_id, name, distribution_method, app_id, certificate_ids, device_ids, mac: false)
|
486
|
+
def repair_provisioning_profile!(profile_id, name, distribution_method, app_id, certificate_ids, device_ids, mac: false, sub_platform: nil)
|
431
487
|
ensure_csrf(Spaceship::ProvisioningProfile) do
|
432
488
|
fetch_csrf_token_for_provisioning
|
433
489
|
end
|
434
490
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
}
|
491
|
+
params = {
|
492
|
+
teamId: team_id,
|
493
|
+
provisioningProfileId: profile_id,
|
494
|
+
provisioningProfileName: name,
|
495
|
+
appIdId: app_id,
|
496
|
+
distributionType: distribution_method,
|
497
|
+
certificateIds: certificate_ids.join(','),
|
498
|
+
deviceIds: device_ids
|
499
|
+
}
|
500
|
+
params[:subPlatform] = sub_platform if sub_platform
|
501
|
+
|
502
|
+
r = request(:post, "account/#{platform_slug(mac)}/profile/regenProvisioningProfile.action", params)
|
444
503
|
|
445
504
|
parse_response(r, 'provisioningProfile')
|
446
505
|
end
|
@@ -65,6 +65,11 @@ module Spaceship
|
|
65
65
|
# "ios"
|
66
66
|
attr_accessor :platform
|
67
67
|
|
68
|
+
# @return (String) The supported sub_platform for this profile
|
69
|
+
# @example
|
70
|
+
# "tvOS"
|
71
|
+
attr_accessor :sub_platform
|
72
|
+
|
68
73
|
# No information about this attribute
|
69
74
|
attr_accessor :managing_app
|
70
75
|
|
@@ -136,6 +141,7 @@ module Spaceship
|
|
136
141
|
'type' => :type,
|
137
142
|
'version' => :version,
|
138
143
|
'proProPlatform' => :platform,
|
144
|
+
'proProSubPlatform' => :sub_platform,
|
139
145
|
'managingApp' => :managing_app,
|
140
146
|
'appId' => :app
|
141
147
|
})
|
@@ -206,6 +212,8 @@ module Spaceship
|
|
206
212
|
app = Spaceship::App.find(bundle_id, mac: mac)
|
207
213
|
raise "Could not find app with bundle id '#{bundle_id}'" unless app
|
208
214
|
|
215
|
+
raise "Invalid sub_platform #{sub_platform}, valid values are tvOS" if !sub_platform.nil? and sub_platform != 'tvOS'
|
216
|
+
|
209
217
|
# Fill in sensible default values
|
210
218
|
name ||= [bundle_id, self.pretty_type].join(' ')
|
211
219
|
|
@@ -278,6 +286,20 @@ module Spaceship
|
|
278
286
|
end
|
279
287
|
end
|
280
288
|
|
289
|
+
# @return (Array) Returns all profiles registered for this account
|
290
|
+
# If you're calling this from a subclass (like AdHoc), this will
|
291
|
+
# only return the profiles that are of this type
|
292
|
+
def all_tvos
|
293
|
+
profiles = all(mac: false)
|
294
|
+
tv_os_profiles = []
|
295
|
+
profiles.each do |tv_os_profile|
|
296
|
+
if tv_os_profile.tvos?
|
297
|
+
tv_os_profiles << tv_os_profile
|
298
|
+
end
|
299
|
+
end
|
300
|
+
return tv_os_profiles
|
301
|
+
end
|
302
|
+
|
281
303
|
# @return (Array) Returns an array of provisioning
|
282
304
|
# profiles matching the bundle identifier
|
283
305
|
# Returns [] if no profiles were found
|
@@ -385,7 +407,8 @@ module Spaceship
|
|
385
407
|
app.app_id,
|
386
408
|
certificates.map(&:id),
|
387
409
|
devices.map(&:id),
|
388
|
-
mac: mac
|
410
|
+
mac: mac?,
|
411
|
+
sub_platform: tvos? ? 'tvOS' : nil
|
389
412
|
)
|
390
413
|
end
|
391
414
|
|
@@ -425,6 +448,11 @@ module Spaceship
|
|
425
448
|
platform == 'mac'
|
426
449
|
end
|
427
450
|
|
451
|
+
# @return (Bool) Is this a tvos provisioning profile?
|
452
|
+
def tvos?
|
453
|
+
sub_platform == 'tvOS'
|
454
|
+
end
|
455
|
+
|
428
456
|
def devices
|
429
457
|
fetch_details
|
430
458
|
|
@@ -63,7 +63,7 @@ module Spaceship
|
|
63
63
|
# as either the App ID or the bundle identifier
|
64
64
|
def find(identifier, mac: false)
|
65
65
|
all.find do |app|
|
66
|
-
(app.apple_id
|
66
|
+
((app.apple_id && app.apple_id.casecmp(identifier.to_s) == 0) || (app.bundle_id && app.bundle_id.casecmp(identifier.to_s) == 0)) &&
|
67
67
|
app.version_sets.any? { |v| (mac ? ["osx"] : ["ios", "appletvos"]).include?(v.platform) }
|
68
68
|
end
|
69
69
|
end
|
@@ -249,6 +249,16 @@ module Spaceship
|
|
249
249
|
client.availability(self.apple_id)
|
250
250
|
end
|
251
251
|
|
252
|
+
#####################################################
|
253
|
+
# @!group in_app_purchases
|
254
|
+
#####################################################
|
255
|
+
# Get base In-App-Purchases object
|
256
|
+
def in_app_purchases
|
257
|
+
attrs = {}
|
258
|
+
attrs[:application] = self
|
259
|
+
Tunes::IAP.factory(attrs)
|
260
|
+
end
|
261
|
+
|
252
262
|
#####################################################
|
253
263
|
# @!group Builds
|
254
264
|
#####################################################
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spaceship/tunes/iap_list'
|
2
|
+
require 'spaceship/tunes/iap_detail'
|
3
|
+
require 'spaceship/tunes/iap_status'
|
4
|
+
require 'spaceship/tunes/iap_type'
|
5
|
+
require 'spaceship/tunes/iap_family_list'
|
6
|
+
require 'spaceship/tunes/iap_families'
|
7
|
+
require 'spaceship/tunes/iap_family_details'
|
8
|
+
require 'spaceship/tunes/iap_families'
|
9
|
+
|
10
|
+
module Spaceship
|
11
|
+
module Tunes
|
12
|
+
class IAP < TunesBase
|
13
|
+
# @return (Spaceship::Tunes::Application) A reference to the application
|
14
|
+
attr_accessor :application
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def factory(attrs)
|
18
|
+
return self.new(attrs)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return (Spaceship::Tunes::IAPFamilies) A reference to the familie list
|
23
|
+
def families
|
24
|
+
attrs = {}
|
25
|
+
attrs[:application] = self.application
|
26
|
+
Tunes::IAPFamilies.factory(attrs)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Creates a new In-App-Purchese on iTunes Connect
|
30
|
+
# if the In-App-Purchase already exists an exception is raised. Spaceship::TunesClient::ITunesConnectError
|
31
|
+
# @param type (String): The Type of the in-app-purchase (Spaceship::Tunes::IAPType::CONSUMABLE,Spaceship::Tunes::IAPType::NON_CONSUMABLE,Spaceship::Tunes::IAPType::RECURRING,Spaceship::Tunes::IAPType::NON_RENEW_SUBSCRIPTION)
|
32
|
+
# @param versions (Hash): a Hash of the languages
|
33
|
+
# @example: {
|
34
|
+
# 'de-DE': {
|
35
|
+
# name: "Name shown in AppStore",
|
36
|
+
# description: "Description of the In app Purchase"
|
37
|
+
#
|
38
|
+
# }
|
39
|
+
# }
|
40
|
+
# @param reference_name (String): iTC Reference Name
|
41
|
+
# @param product_id (String): A unique ID for your in-app-purchase
|
42
|
+
# @param bundle_id (String): The bundle ID must match the one you used in Xcode. It
|
43
|
+
# @param cleared_for_sale (Boolean): Is this In-App-Purchase Cleared for Sale
|
44
|
+
# @param review_notes (String): Review Notes
|
45
|
+
# @param review_screenshot (String): Path to the screenshot (should be 640x940 PNG)
|
46
|
+
# @param pricing_intervals (Hash): a Hash of the languages
|
47
|
+
# @example:
|
48
|
+
# [
|
49
|
+
# {
|
50
|
+
# country: "WW",
|
51
|
+
# begin_date: nil,
|
52
|
+
# end_date: nil,
|
53
|
+
# tier: 1
|
54
|
+
# }
|
55
|
+
# ]
|
56
|
+
# @param family_id (String) Only used on RECURRING purchases, assigns the In-App-Purchase to a specific familie
|
57
|
+
# @param subscription_free_trial (String) Free Trial duration (1w,1m,3m....)
|
58
|
+
# @param subscription_duration (String) 1w,1m.....
|
59
|
+
def create!(type: "consumable",
|
60
|
+
versions: nil,
|
61
|
+
reference_name: nil,
|
62
|
+
product_id: nil,
|
63
|
+
cleared_for_sale: true,
|
64
|
+
review_notes: nil,
|
65
|
+
review_screenshot: nil,
|
66
|
+
pricing_intervals: nil,
|
67
|
+
family_id: nil,
|
68
|
+
subscription_free_trial: nil,
|
69
|
+
subscription_duration: nil)
|
70
|
+
|
71
|
+
client.create_iap!(app_id: self.application.apple_id,
|
72
|
+
type: type,
|
73
|
+
versions: versions,
|
74
|
+
reference_name: reference_name,
|
75
|
+
product_id: product_id,
|
76
|
+
cleared_for_sale: cleared_for_sale,
|
77
|
+
review_notes: review_notes,
|
78
|
+
review_screenshot: review_screenshot,
|
79
|
+
pricing_intervals: pricing_intervals,
|
80
|
+
family_id: family_id,
|
81
|
+
subscription_duration: subscription_duration,
|
82
|
+
subscription_free_trial: subscription_free_trial)
|
83
|
+
end
|
84
|
+
|
85
|
+
# find a specific product
|
86
|
+
# @param product_id (String) Product Id
|
87
|
+
def find(product_id)
|
88
|
+
all.each do |product|
|
89
|
+
if product.product_id == product_id
|
90
|
+
return product
|
91
|
+
end
|
92
|
+
end
|
93
|
+
return nil
|
94
|
+
end
|
95
|
+
|
96
|
+
# return all available In-App-Purchase's of current app
|
97
|
+
# this is not paged inside iTC-API so if you have a lot if IAP's (2k+)
|
98
|
+
# it might take some time to load, same as it takes when you load the list via iTunes Connect
|
99
|
+
def all(include_deleted: false)
|
100
|
+
r = client.iaps(app_id: self.application.apple_id)
|
101
|
+
return_iaps = []
|
102
|
+
r.each do |product|
|
103
|
+
attrs = product
|
104
|
+
attrs[:application] = self.application
|
105
|
+
loaded_iap = Tunes::IAPList.factory(attrs)
|
106
|
+
next if loaded_iap.status == "deleted" && !include_deleted
|
107
|
+
return_iaps << loaded_iap
|
108
|
+
end
|
109
|
+
return_iaps
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|