branch_io_cli 0.12.10 → 0.13.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|