branch_io_cli 0.12.10 → 0.13.0.pre.1
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/README.md +32 -47
- data/lib/assets/completions/completion.bash +1 -1
- data/lib/assets/completions/completion.zsh +1 -1
- data/lib/assets/templates/completion.zsh.erb +1 -1
- data/lib/assets/templates/validate_description.erb +20 -10
- data/lib/branch_io_cli.rb +1 -0
- data/lib/branch_io_cli/branch_app.rb +70 -0
- data/lib/branch_io_cli/command/report_command.rb +6 -2
- data/lib/branch_io_cli/command/setup_command.rb +1 -9
- data/lib/branch_io_cli/command/validate_command.rb +74 -9
- data/lib/branch_io_cli/configuration/configuration.rb +55 -0
- data/lib/branch_io_cli/configuration/option.rb +11 -0
- data/lib/branch_io_cli/configuration/report_configuration.rb +1 -5
- data/lib/branch_io_cli/configuration/report_options.rb +1 -7
- data/lib/branch_io_cli/configuration/setup_configuration.rb +6 -36
- data/lib/branch_io_cli/configuration/setup_options.rb +1 -7
- data/lib/branch_io_cli/configuration/validate_configuration.rb +4 -0
- data/lib/branch_io_cli/configuration/validate_options.rb +22 -3
- data/lib/branch_io_cli/core_ext/xcodeproj.rb +6 -4
- data/lib/branch_io_cli/helper/branch_helper.rb +8 -0
- data/lib/branch_io_cli/helper/ios_helper.rb +107 -5
- data/lib/branch_io_cli/helper/report_helper.rb +0 -64
- data/lib/branch_io_cli/helper/tool_helper.rb +78 -13
- data/lib/branch_io_cli/rake_task.rb +4 -2
- data/lib/branch_io_cli/version.rb +1 -1
- metadata +61 -66
@@ -79,11 +79,14 @@ module BranchIOCLI
|
|
79
79
|
attr_reader :workspace_path
|
80
80
|
attr_reader :pod_repo_update
|
81
81
|
attr_reader :sdk
|
82
|
+
attr_reader :keys
|
83
|
+
attr_reader :apps
|
82
84
|
|
83
85
|
def initialize(options)
|
84
86
|
@options = options
|
85
87
|
@pod_repo_update = options.pod_repo_update if self.class.available_options.map(&:name).include?(:pod_repo_update)
|
86
88
|
@sdk = "iphonesimulator" # to load Xcode build settings for commands without a --sdk option
|
89
|
+
@confirm = options.confirm
|
87
90
|
|
88
91
|
Configuration.current = self
|
89
92
|
|
@@ -269,6 +272,54 @@ EOF
|
|
269
272
|
end
|
270
273
|
end
|
271
274
|
|
275
|
+
def validate_keys(optional: false)
|
276
|
+
@keys = {}
|
277
|
+
@apps = {}
|
278
|
+
|
279
|
+
# 1. Check the options passed in. If nothing (nil) passed, continue.
|
280
|
+
validate_key options.live_key, :live, accept_nil: true
|
281
|
+
validate_key options.test_key, :test, accept_nil: true
|
282
|
+
|
283
|
+
# 2. Did we find a valid key above?
|
284
|
+
while !optional && @keys.empty?
|
285
|
+
# 3. If not, prompt.
|
286
|
+
say "A live key, a test key or both is required."
|
287
|
+
validate_key nil, :live
|
288
|
+
validate_key nil, :test
|
289
|
+
end
|
290
|
+
|
291
|
+
# 4. We have at least one valid key now, unless optional is truthy.
|
292
|
+
end
|
293
|
+
|
294
|
+
def key_valid?(key, type)
|
295
|
+
return false if key.nil?
|
296
|
+
return true if key.empty?
|
297
|
+
unless key =~ /^key_#{type}_.+/
|
298
|
+
say "#{key.inspect} is not a valid #{type} Branch key. It must begin with key_#{type}_."
|
299
|
+
return false
|
300
|
+
end
|
301
|
+
|
302
|
+
# For now: When using --no-validate with the setup command, don't call the Branch API.
|
303
|
+
return true unless respond_to?(:validate) && validate
|
304
|
+
|
305
|
+
begin
|
306
|
+
# Retrieve info from the API
|
307
|
+
app = BranchApp[key]
|
308
|
+
@apps[key] = app
|
309
|
+
true
|
310
|
+
rescue StandardError => e
|
311
|
+
say "Error fetching app for key #{key} from Branch API: #{e.message}"
|
312
|
+
false
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def validate_key(key, type, options = {})
|
317
|
+
return if options[:accept_nil] && key.nil?
|
318
|
+
key = ask "Please enter your #{type} Branch key or use --#{type}-key [enter for none]: " until key_valid? key, type
|
319
|
+
@keys[type] = key unless key.empty?
|
320
|
+
instance_variable_set "@#{type}_key", key
|
321
|
+
end
|
322
|
+
|
272
323
|
def pod_install_required?
|
273
324
|
# If this is set, its existence has been verified.
|
274
325
|
return false unless podfile_path
|
@@ -344,6 +395,10 @@ EOF
|
|
344
395
|
path && path.sub(/\.h$/, '.m')
|
345
396
|
end
|
346
397
|
|
398
|
+
def ios_urischemes_from_api(apps = @apps)
|
399
|
+
Set.new apps.map(&:ios_uri_scheme).compact
|
400
|
+
end
|
401
|
+
|
347
402
|
# TODO: How many of these can vary by configuration?
|
348
403
|
|
349
404
|
def modules_enabled?
|
@@ -1,6 +1,17 @@
|
|
1
1
|
module BranchIOCLI
|
2
2
|
module Configuration
|
3
3
|
class Option
|
4
|
+
def self.global_options
|
5
|
+
[
|
6
|
+
new(
|
7
|
+
name: :confirm,
|
8
|
+
description: "Enable or disable many prompts",
|
9
|
+
default_value: true,
|
10
|
+
skip_confirmation: true
|
11
|
+
)
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
4
15
|
attr_accessor :name
|
5
16
|
attr_accessor :env_name
|
6
17
|
attr_accessor :type
|
@@ -12,11 +12,6 @@ module BranchIOCLI
|
|
12
12
|
|
13
13
|
attr_reader :report_path
|
14
14
|
|
15
|
-
def initialize(options)
|
16
|
-
@confirm = options.confirm
|
17
|
-
super
|
18
|
-
end
|
19
|
-
|
20
15
|
def validate_options
|
21
16
|
@clean = options.clean
|
22
17
|
@header_only = options.header_only
|
@@ -67,6 +62,7 @@ EOF
|
|
67
62
|
<%= color('Xcode project:', BOLD) %> #{xcodeproj_path || '(none)'}
|
68
63
|
<%= color('Scheme:', BOLD) %> #{scheme || '(none)'}
|
69
64
|
<%= color('Target:', BOLD) %> #{target || '(none)'}
|
65
|
+
<%= color('Target type:', BOLD) %> #{target.product_type}
|
70
66
|
<%= color('Configuration:', BOLD) %> #{configuration || '(none)'}
|
71
67
|
<%= color('SDK:', BOLD) %> #{sdk}
|
72
68
|
<%= color('Podfile:', BOLD) %> #{relative_path(podfile_path) || '(none)'}
|
@@ -77,14 +77,8 @@ module BranchIOCLI
|
|
77
77
|
example: "./report.txt",
|
78
78
|
type: String,
|
79
79
|
env_name: "BRANCH_REPORT_PATH"
|
80
|
-
),
|
81
|
-
Option.new(
|
82
|
-
name: :confirm,
|
83
|
-
description: "Confirm before running certain commands",
|
84
|
-
default_value: true,
|
85
|
-
skip_confirmation: true
|
86
80
|
)
|
87
|
-
]
|
81
|
+
] + Option.global_options
|
88
82
|
end
|
89
83
|
end
|
90
84
|
end
|
@@ -27,11 +27,9 @@ module BranchIOCLI
|
|
27
27
|
"Skip adding the framework to the project." => :skip
|
28
28
|
}
|
29
29
|
|
30
|
-
attr_reader :keys
|
31
30
|
attr_reader :all_domains
|
32
31
|
|
33
32
|
def initialize(options)
|
34
|
-
@confirm = options.confirm
|
35
33
|
super
|
36
34
|
# Configuration has been validated and logged to the screen.
|
37
35
|
confirm_with_user if options.confirm
|
@@ -52,7 +50,7 @@ module BranchIOCLI
|
|
52
50
|
|
53
51
|
validate_xcodeproj_path
|
54
52
|
validate_target
|
55
|
-
|
53
|
+
validate_keys
|
56
54
|
validate_all_domains options, !target.extension_target_type?
|
57
55
|
validate_uri_scheme options
|
58
56
|
validate_setting options
|
@@ -77,6 +75,7 @@ module BranchIOCLI
|
|
77
75
|
message = <<-EOF
|
78
76
|
<%= color('Xcode project:', BOLD) %> #{xcodeproj_path}
|
79
77
|
<%= color('Target:', BOLD) %> #{target.name}
|
78
|
+
<%= color('Target type:', BOLD) %> #{target.product_type}
|
80
79
|
<%= color('Live key:', BOLD) %> #{keys[:live] || '(none)'}
|
81
80
|
<%= color('Test key:', BOLD) %> #{keys[:test] || '(none)'}
|
82
81
|
<%= color('Domains:', BOLD) %> #{all_domains}
|
@@ -118,39 +117,6 @@ module BranchIOCLI
|
|
118
117
|
say message
|
119
118
|
end
|
120
119
|
|
121
|
-
def validate_keys_from_setup_options(options)
|
122
|
-
@keys = {}
|
123
|
-
|
124
|
-
# 1. Check the options passed in. If nothing (nil) passed, continue.
|
125
|
-
validate_key options.live_key, :live, accept_nil: true
|
126
|
-
validate_key options.test_key, :test, accept_nil: true
|
127
|
-
|
128
|
-
# 2. Did we find a valid key above?
|
129
|
-
while @keys.empty?
|
130
|
-
# 3. If not, prompt.
|
131
|
-
say "A live key, a test key or both is required."
|
132
|
-
validate_key nil, :live
|
133
|
-
validate_key nil, :test
|
134
|
-
end
|
135
|
-
|
136
|
-
# 4. We have at least one valid key now.
|
137
|
-
end
|
138
|
-
|
139
|
-
def key_valid?(key, type)
|
140
|
-
return false if key.nil?
|
141
|
-
key.empty? || key =~ /^key_#{type}_/
|
142
|
-
end
|
143
|
-
|
144
|
-
def validate_key(key, type, options = {})
|
145
|
-
return if options[:accept_nil] && key.nil?
|
146
|
-
until key_valid? key, type
|
147
|
-
say "#{key.inspect} is not a valid #{type} Branch key. It must begin with key_#{type}_." if key
|
148
|
-
key = ask "Please enter your #{type} Branch key or use --#{type}-key [enter for none]: "
|
149
|
-
end
|
150
|
-
@keys[type] = key unless key.empty?
|
151
|
-
instance_variable_set "@#{type}_key", key
|
152
|
-
end
|
153
|
-
|
154
120
|
def validate_all_domains(options, required = true)
|
155
121
|
app_link_roots = app_link_roots_from_domains options.domains
|
156
122
|
|
@@ -174,6 +140,10 @@ module BranchIOCLI
|
|
174
140
|
end
|
175
141
|
end
|
176
142
|
|
143
|
+
def domains_from_api
|
144
|
+
helper.domains @apps
|
145
|
+
end
|
146
|
+
|
177
147
|
def validate_uri_scheme(options)
|
178
148
|
# No validation at the moment. Just strips off any trailing ://
|
179
149
|
uri_scheme = options.uri_scheme
|
@@ -139,14 +139,8 @@ module BranchIOCLI
|
|
139
139
|
example: "message",
|
140
140
|
argument_optional: true,
|
141
141
|
label: "Commit message"
|
142
|
-
),
|
143
|
-
Option.new(
|
144
|
-
name: :confirm,
|
145
|
-
description: "Confirm configuration before proceeding",
|
146
|
-
default_value: true,
|
147
|
-
skip_confirmation: true
|
148
142
|
)
|
149
|
-
]
|
143
|
+
] + Option.global_options
|
150
144
|
end
|
151
145
|
end
|
152
146
|
end
|
@@ -19,6 +19,7 @@ module BranchIOCLI
|
|
19
19
|
def validate_options
|
20
20
|
validate_xcodeproj_path
|
21
21
|
validate_target
|
22
|
+
validate_keys optional: true
|
22
23
|
end
|
23
24
|
|
24
25
|
def log
|
@@ -26,6 +27,9 @@ module BranchIOCLI
|
|
26
27
|
say <<EOF
|
27
28
|
<%= color('Xcode project:', BOLD) %> #{xcodeproj_path}
|
28
29
|
<%= color('Target:', BOLD) %> #{target.name}
|
30
|
+
<%= color('Target type:', BOLD) %> #{target.product_type}
|
31
|
+
<%= color('Live key:', BOLD) %> #{keys[:live] || '(none)'}
|
32
|
+
<%= color('Test key:', BOLD) %> #{keys[:test] || '(none)'}
|
29
33
|
<%= color('Domains:', BOLD) %> #{domains || '(none)'}
|
30
34
|
<%= color('Configurations:', BOLD) %> #{(configurations || xcodeproj.build_configurations.map(&:name)).join(',')}
|
31
35
|
EOF
|
@@ -4,9 +4,23 @@ module BranchIOCLI
|
|
4
4
|
class << self
|
5
5
|
def available_options
|
6
6
|
[
|
7
|
+
Option.new(
|
8
|
+
name: :live_key,
|
9
|
+
description: "Branch live key expected in project",
|
10
|
+
example: "key_live_xxxx",
|
11
|
+
type: String,
|
12
|
+
aliases: "-L"
|
13
|
+
),
|
14
|
+
Option.new(
|
15
|
+
name: :test_key,
|
16
|
+
description: "Branch test key expected in project",
|
17
|
+
example: "key_test_yyyy",
|
18
|
+
type: String,
|
19
|
+
aliases: "-T"
|
20
|
+
),
|
7
21
|
Option.new(
|
8
22
|
name: :domains,
|
9
|
-
description: "Comma-separated list of domains to
|
23
|
+
description: "Comma-separated list of domains expected to be configured in the project (Branch domains or non-Branch domains)",
|
10
24
|
type: Array,
|
11
25
|
example: "example.com,www.example.com",
|
12
26
|
aliases: "-D",
|
@@ -14,7 +28,7 @@ module BranchIOCLI
|
|
14
28
|
),
|
15
29
|
Option.new(
|
16
30
|
name: :xcodeproj,
|
17
|
-
description: "Path to an Xcode project to
|
31
|
+
description: "Path to an Xcode project to validate",
|
18
32
|
type: String,
|
19
33
|
example: "MyProject.xcodeproj"
|
20
34
|
),
|
@@ -29,8 +43,13 @@ module BranchIOCLI
|
|
29
43
|
description: "Comma-separated list of configurations to validate (default: all)",
|
30
44
|
type: Array,
|
31
45
|
example: "Debug,Release"
|
46
|
+
),
|
47
|
+
Option.new(
|
48
|
+
name: :universal_links_only,
|
49
|
+
description: "Validate only the Universal Link configuration",
|
50
|
+
default_value: false
|
32
51
|
)
|
33
|
-
]
|
52
|
+
] + Option.global_options
|
34
53
|
end
|
35
54
|
end
|
36
55
|
end
|
@@ -73,7 +73,7 @@ module Xcodeproj
|
|
73
73
|
end
|
74
74
|
|
75
75
|
# TODO: What is the correct resolution order here? Which overrides which in
|
76
|
-
# Xcode?
|
76
|
+
# Xcode?
|
77
77
|
if setting_value.nil? && defined?(BranchIOCLI::Configuration::XcodeSettings)
|
78
78
|
setting_value = BranchIOCLI::Configuration::XcodeSettings[configuration][setting_name]
|
79
79
|
end
|
@@ -92,6 +92,8 @@ module Xcodeproj
|
|
92
92
|
# @param configuration [String] Name of any valid configuration for this target
|
93
93
|
# @return [String] A copy of the original string with all embedded build settings expanded
|
94
94
|
def expand_build_settings(string, configuration)
|
95
|
+
return nil if string.nil?
|
96
|
+
|
95
97
|
search_position = 0
|
96
98
|
string = string.clone
|
97
99
|
|
@@ -118,13 +120,13 @@ module Xcodeproj
|
|
118
120
|
# Everything else becomes a hyphen, including underscores.
|
119
121
|
expanded_macro.gsub!(/[^A-Za-z0-9-]/, '-') if modifier == "rfc1034identifier"
|
120
122
|
|
121
|
-
string.gsub!(/\$\(#{original_macro}\)|\$\{#{original_macro}\}/, expanded_macro)
|
123
|
+
string.gsub!(/\$\(#{original_macro}\)|\$\{#{original_macro}\}|^#{original_macro}/, expanded_macro)
|
122
124
|
search_position += expanded_macro.length
|
123
125
|
end
|
124
126
|
|
125
127
|
# HACK: When matching against an xcconfig, as here, sometimes the macro is just returned
|
126
|
-
# without delimiters
|
127
|
-
#
|
128
|
+
# without delimiters, e.g. TARGET_NAME or PROJECT_DIR/PROJECT_NAME/BridgingHeader.h. We allow
|
129
|
+
# these two patterns for now.
|
128
130
|
string = string.split("/").map do |component|
|
129
131
|
next component unless component =~ /^[A-Z0-9_]+$/
|
130
132
|
expanded_build_setting(component, configuration) || component
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "active_support/core_ext/hash"
|
1
2
|
require "branch_io_cli/helper/android_helper"
|
2
3
|
require "branch_io_cli/helper/ios_helper"
|
3
4
|
require "net/http"
|
@@ -67,6 +68,13 @@ module BranchIOCLI
|
|
67
68
|
end
|
68
69
|
end
|
69
70
|
end
|
71
|
+
|
72
|
+
def domains(apps)
|
73
|
+
apps.inject Set.new do |result, k, v|
|
74
|
+
next result unless v
|
75
|
+
result + v.domains
|
76
|
+
end
|
77
|
+
end
|
70
78
|
end
|
71
79
|
end
|
72
80
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "active_support/core_ext/object"
|
1
2
|
require "json"
|
2
3
|
require "openssl"
|
3
4
|
require "plist"
|
@@ -110,7 +111,7 @@ module BranchIOCLI
|
|
110
111
|
end
|
111
112
|
end
|
112
113
|
|
113
|
-
def
|
114
|
+
def info_plist_path(configuration)
|
114
115
|
# find the Info.plist paths for this configuration
|
115
116
|
info_plist_path = config.target.expanded_build_setting "INFOPLIST_FILE", configuration
|
116
117
|
|
@@ -118,12 +119,19 @@ module BranchIOCLI
|
|
118
119
|
|
119
120
|
project_parent = File.dirname config.xcodeproj_path
|
120
121
|
|
121
|
-
|
122
|
+
File.expand_path info_plist_path, project_parent
|
123
|
+
end
|
122
124
|
|
125
|
+
def info_plist(path)
|
123
126
|
# try to open and parse the Info.plist (raises)
|
124
|
-
info_plist = File.open(
|
125
|
-
raise "Failed to parse #{
|
127
|
+
info_plist = File.open(path) { |f| Plist.parse_xml f }
|
128
|
+
raise "Failed to parse #{path}" if info_plist.nil?
|
129
|
+
info_plist
|
130
|
+
end
|
126
131
|
|
132
|
+
def update_info_plist_setting(configuration = RELEASE_CONFIGURATION, &b)
|
133
|
+
info_plist_path = info_plist_path(configuration)
|
134
|
+
info_plist = info_plist(info_plist_path)
|
127
135
|
yield info_plist
|
128
136
|
|
129
137
|
Plist::Emit.save_plist info_plist, info_plist_path
|
@@ -249,7 +257,14 @@ module BranchIOCLI
|
|
249
257
|
nil
|
250
258
|
end
|
251
259
|
|
260
|
+
def reset_aasa_cache
|
261
|
+
@aasa_files = {}
|
262
|
+
end
|
263
|
+
|
252
264
|
def contents_of_aasa_file(domain)
|
265
|
+
@aasa_files ||= {}
|
266
|
+
return @aasa_files[domain] if @aasa_files[domain]
|
267
|
+
|
253
268
|
uris = [
|
254
269
|
URI("https://#{domain}/.well-known/apple-app-site-association"),
|
255
270
|
URI("https://#{domain}/apple-app-site-association")
|
@@ -289,7 +304,7 @@ module BranchIOCLI
|
|
289
304
|
signature.verify nil, cert_store, nil, OpenSSL::PKCS7::NOVERIFY
|
290
305
|
data = signature.data
|
291
306
|
else
|
292
|
-
@
|
307
|
+
@errors << "[#{domain}] Unsigned AASA files must be served via HTTPS" and next if uri.scheme == "http"
|
293
308
|
data = response.body
|
294
309
|
end
|
295
310
|
|
@@ -299,6 +314,7 @@ module BranchIOCLI
|
|
299
314
|
|
300
315
|
@errors << "[#{domain}] Failed to retrieve AASA file" and return nil if data.nil?
|
301
316
|
|
317
|
+
@aasa_files[domain] = data
|
302
318
|
data
|
303
319
|
rescue IOError, SocketError => e
|
304
320
|
@errors << "[#{domain}] Socket error: #{e.message}"
|
@@ -409,6 +425,92 @@ module BranchIOCLI
|
|
409
425
|
|
410
426
|
associated_domains.select { |d| d =~ /^applinks:/ }.map { |d| d.sub(/^applinks:/, "") }
|
411
427
|
end
|
428
|
+
|
429
|
+
# Validates Branch-related settings in a project (keys, domains, URI schemes)
|
430
|
+
def project_valid?(configuration)
|
431
|
+
@errors = []
|
432
|
+
|
433
|
+
info_plist_path = info_plist_path(configuration)
|
434
|
+
info_plist = info_plist(info_plist_path).symbolize_keys
|
435
|
+
branch_key = info_plist[:branch_key]
|
436
|
+
|
437
|
+
if branch_key.blank?
|
438
|
+
say "branch_key not found in Info.plist. ❌"
|
439
|
+
return false
|
440
|
+
end
|
441
|
+
|
442
|
+
if branch_key.kind_of?(Hash)
|
443
|
+
branch_keys = branch_key.map { |k, v| v }
|
444
|
+
else
|
445
|
+
branch_keys = [branch_key]
|
446
|
+
end
|
447
|
+
|
448
|
+
branch_keys = branch_keys.map { |key| config.target.expand_build_settings key, configuration }
|
449
|
+
|
450
|
+
valid = true
|
451
|
+
|
452
|
+
# Retrieve app data from Branch API for all keys in the Info.plist
|
453
|
+
apps = branch_keys.map do |key|
|
454
|
+
begin
|
455
|
+
BranchApp[key]
|
456
|
+
rescue StandardError => e
|
457
|
+
# Failed to retrieve a key in the Info.plist from the API.
|
458
|
+
say "[#{key}] #{e.message} ❌"
|
459
|
+
valid = false
|
460
|
+
nil
|
461
|
+
end
|
462
|
+
end.compact.uniq
|
463
|
+
|
464
|
+
# Get domains and URI schemes loaded from API
|
465
|
+
domains_from_api = domains apps
|
466
|
+
|
467
|
+
# Make sure all domains and URI schemes are present in the project.
|
468
|
+
domains = domains_from_project(configuration)
|
469
|
+
missing_domains = domains_from_api - domains
|
470
|
+
unless missing_domains.empty?
|
471
|
+
valid = false
|
472
|
+
missing_domains.each do |domain|
|
473
|
+
say "[#{domain}] Domain from Dashboard missing from #{configuration} configuration. ❌"
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
valid
|
478
|
+
end
|
479
|
+
|
480
|
+
def branch_keys_from_project(configurations)
|
481
|
+
configurations.map do |c|
|
482
|
+
path = info_plist_path(c)
|
483
|
+
info_plist = info_plist(path).symbolize_keys
|
484
|
+
branch_key = info_plist[:branch_key]
|
485
|
+
if branch_key.blank?
|
486
|
+
say "branch_key not found in Info.plist. ❌"
|
487
|
+
return []
|
488
|
+
end
|
489
|
+
|
490
|
+
if branch_key.kind_of?(Hash)
|
491
|
+
keys = branch_key.values
|
492
|
+
else
|
493
|
+
keys = [branch_key]
|
494
|
+
end
|
495
|
+
|
496
|
+
keys.map { |key| config.target.expand_build_settings key, c }
|
497
|
+
end.compact.flatten.uniq
|
498
|
+
end
|
499
|
+
|
500
|
+
def branch_apps_from_project(configurations)
|
501
|
+
branch_keys_from_project(configurations).map { |key| BranchApp[key] }
|
502
|
+
end
|
503
|
+
|
504
|
+
def uri_schemes_from_project(configurations)
|
505
|
+
schemes = configurations.map do |c|
|
506
|
+
path = info_plist_path(c)
|
507
|
+
info_plist = info_plist(path)
|
508
|
+
url_types = info_plist["CFBundleURLTypes"] || []
|
509
|
+
url_types.map { |t| t["CFBundleURLSchemes"] }
|
510
|
+
end
|
511
|
+
|
512
|
+
schemes.compact.flatten.uniq
|
513
|
+
end
|
412
514
|
end
|
413
515
|
end
|
414
516
|
end
|