fastlane-plugin-branch 0.5.1 → 0.6.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.
@@ -0,0 +1,16 @@
1
+ module Fastlane
2
+ module Helper
3
+ class BranchOptions
4
+ attr_reader :params
5
+
6
+ # :param: params [FastlaneCore::Configuration] Params from an action
7
+ def initialize(params)
8
+ @params = params
9
+ end
10
+
11
+ def method_missing(method_sym, *arguments, &block)
12
+ return params[method_sym]
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module Branch
3
- VERSION = "0.5.1"
3
+ VERSION = "0.6.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-branch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Branch
@@ -9,10 +9,10 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-10-07 00:00:00.000000000 Z
12
+ date: 2017-11-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: fastlane-plugin-patch
15
+ name: branch_io_cli
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
18
  - - ">="
@@ -26,27 +26,13 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
- name: plist
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: '0'
35
- type: :runtime
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- version: '0'
42
- - !ruby/object:Gem::Dependency
43
- name: xcodeproj
29
+ name: pry
44
30
  requirement: !ruby/object:Gem::Requirement
45
31
  requirements:
46
32
  - - ">="
47
33
  - !ruby/object:Gem::Version
48
34
  version: '0'
49
- type: :runtime
35
+ type: :development
50
36
  prerelease: false
51
37
  version_requirements: !ruby/object:Gem::Requirement
52
38
  requirements:
@@ -54,7 +40,7 @@ dependencies:
54
40
  - !ruby/object:Gem::Version
55
41
  version: '0'
56
42
  - !ruby/object:Gem::Dependency
57
- name: pry
43
+ name: bundler
58
44
  requirement: !ruby/object:Gem::Requirement
59
45
  requirements:
60
46
  - - ">="
@@ -68,7 +54,7 @@ dependencies:
68
54
  - !ruby/object:Gem::Version
69
55
  version: '0'
70
56
  - !ruby/object:Gem::Dependency
71
- name: bundler
57
+ name: rspec
72
58
  requirement: !ruby/object:Gem::Requirement
73
59
  requirements:
74
60
  - - ">="
@@ -82,7 +68,7 @@ dependencies:
82
68
  - !ruby/object:Gem::Version
83
69
  version: '0'
84
70
  - !ruby/object:Gem::Dependency
85
- name: rspec
71
+ name: rake
86
72
  requirement: !ruby/object:Gem::Requirement
87
73
  requirements:
88
74
  - - ">="
@@ -96,7 +82,7 @@ dependencies:
96
82
  - !ruby/object:Gem::Version
97
83
  version: '0'
98
84
  - !ruby/object:Gem::Dependency
99
- name: rake
85
+ name: rspec_junit_formatter
100
86
  requirement: !ruby/object:Gem::Requirement
101
87
  requirements:
102
88
  - - ">="
@@ -127,16 +113,16 @@ dependencies:
127
113
  name: rubocop
128
114
  requirement: !ruby/object:Gem::Requirement
129
115
  requirements:
130
- - - ">="
116
+ - - "~>"
131
117
  - !ruby/object:Gem::Version
132
- version: '0'
118
+ version: 0.50.0
133
119
  type: :development
134
120
  prerelease: false
135
121
  version_requirements: !ruby/object:Gem::Requirement
136
122
  requirements:
137
- - - ">="
123
+ - - "~>"
138
124
  - !ruby/object:Gem::Version
139
- version: '0'
125
+ version: 0.50.0
140
126
  - !ruby/object:Gem::Dependency
141
127
  name: simplecov
142
128
  requirement: !ruby/object:Gem::Requirement
@@ -178,10 +164,7 @@ files:
178
164
  - lib/fastlane/plugin/branch.rb
179
165
  - lib/fastlane/plugin/branch/actions/setup_branch_action.rb
180
166
  - lib/fastlane/plugin/branch/actions/validate_universal_links_action.rb
181
- - lib/fastlane/plugin/branch/helper/android_helper.rb
182
- - lib/fastlane/plugin/branch/helper/branch_helper.rb
183
- - lib/fastlane/plugin/branch/helper/configuration_helper.rb
184
- - lib/fastlane/plugin/branch/helper/ios_helper.rb
167
+ - lib/fastlane/plugin/branch/helper/branch_options.rb
185
168
  - lib/fastlane/plugin/branch/version.rb
186
169
  homepage: https://github.com/BranchMetrics/fastlane-plugin-branch
187
170
  licenses:
@@ -203,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
186
  version: '0'
204
187
  requirements: []
205
188
  rubyforge_project:
206
- rubygems_version: 2.6.13
189
+ rubygems_version: 2.6.14
207
190
  signing_key:
208
191
  specification_version: 4
209
192
  summary: Adds Branch keys, custom URI schemes and domains to iOS and Android projects.
@@ -1,86 +0,0 @@
1
- module Fastlane
2
- module Helper
3
- module AndroidHelper
4
- def add_keys_to_android_manifest(manifest, keys)
5
- add_metadata_to_manifest manifest, "io.branch.sdk.BranchKey", keys[:live] unless keys[:live].nil?
6
- add_metadata_to_manifest manifest, "io.branch.sdk.BranchKey.test", keys[:test] unless keys[:test].nil?
7
- end
8
-
9
- # TODO: Work on all XML/AndroidManifest formatting
10
-
11
- def add_metadata_to_manifest(manifest, key, value)
12
- element = manifest.elements["//manifest/application/meta-data[@android:name=\"#{key}\"]"]
13
- if element.nil?
14
- application = manifest.elements["//manifest/application"]
15
- application.add_element "meta-data", "android:name" => key, "android:value" => value
16
- else
17
- element.attributes["android:value"] = value
18
- end
19
- end
20
-
21
- def add_intent_filters_to_android_manifest(manifest, domains, uri_scheme, activity_name, remove_existing)
22
- if activity_name
23
- activity = manifest.elements["//manifest/application/activity[@android:name=\"#{activity_name}\""]
24
- else
25
- activity = find_activity manifest
26
- end
27
-
28
- raise "Failed to find an Activity in the Android manifest" if activity.nil?
29
-
30
- if remove_existing
31
- remove_existing_domains(activity)
32
- end
33
-
34
- add_intent_filter_to_activity activity, domains, uri_scheme
35
- end
36
-
37
- def find_activity(manifest)
38
- # try to infer the right activity
39
- # look for the first singleTask
40
- single_task_activity = manifest.elements["//manifest/application/activity[@android:launchMode=\"singleTask\"]"]
41
- return single_task_activity if single_task_activity
42
-
43
- # no singleTask activities. Take the first Activity
44
- # TODO: Add singleTask?
45
- manifest.elements["//manifest/application/activity"]
46
- end
47
-
48
- def add_intent_filter_to_activity(activity, domains, uri_scheme)
49
- # Add a single intent-filter with autoVerify and a data element for each domain and the optional uri_scheme
50
- intent_filter = REXML::Element.new "intent-filter"
51
- intent_filter.attributes["android:autoVerify"] = true
52
- intent_filter.add_element "action", "android:name" => "android.intent.action.VIEW"
53
- intent_filter.add_element "category", "android:name" => "android.intent.category.DEFAULT"
54
- intent_filter.add_element "category", "android:name" => "android.intent.category.BROWSABLE"
55
- intent_filter.elements << uri_scheme_data_element(uri_scheme) unless uri_scheme.nil?
56
- app_link_data_elements(domains).each { |e| intent_filter.elements << e }
57
-
58
- activity.add_element intent_filter
59
- end
60
-
61
- def remove_existing_domains(activity)
62
- # Find all intent-filters that include a data element with android:scheme
63
- # TODO: Can this be done with a single css/at_css call?
64
- activity.elements.each("//manifest//intent-filter") do |filter|
65
- filter.remove if filter.elements["data[@android:scheme]"]
66
- end
67
- end
68
-
69
- def app_link_data_elements(domains)
70
- domains.map do |domain|
71
- element = REXML::Element.new "data"
72
- element.attributes["android:scheme"] = "https"
73
- element.attributes["android:host"] = domain
74
- element
75
- end
76
- end
77
-
78
- def uri_scheme_data_element(uri_scheme)
79
- element = REXML::Element.new "data"
80
- element.attributes["android:scheme"] = uri_scheme
81
- element.attributes["android:host"] = "open"
82
- element
83
- end
84
- end
85
- end
86
- end
@@ -1,25 +0,0 @@
1
- require "fastlane/plugin/branch/helper/android_helper"
2
- require "fastlane/plugin/branch/helper/configuration_helper"
3
- require "fastlane/plugin/branch/helper/ios_helper"
4
-
5
- module Fastlane
6
- module Helper
7
- UI = FastlaneCore::UI
8
-
9
- class BranchHelper
10
- class << self
11
- attr_accessor :changes # An array of file paths (Strings) that were modified
12
- attr_accessor :errors # An array of error messages (Strings) from validation
13
-
14
- include AndroidHelper
15
- include ConfigurationHelper
16
- include IOSHelper
17
-
18
- def add_change(change)
19
- @changes ||= Set.new
20
- @changes << change.to_s
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,132 +0,0 @@
1
- module Fastlane
2
- module Helper
3
- module ConfigurationHelper
4
- def keys_from_params(params)
5
- live_key = params[:live_key]
6
- test_key = params[:test_key]
7
- keys = {}
8
- keys[:live] = live_key unless live_key.nil?
9
- keys[:test] = test_key unless test_key.nil?
10
- keys
11
- end
12
-
13
- def xcodeproj_path_from_params(params)
14
- return params[:xcodeproj] if params[:xcodeproj]
15
-
16
- # Adapted from commit_version_bump
17
- # https://github.com/fastlane/fastlane/blob/master/fastlane/lib/fastlane/actions/commit_version_bump.rb#L21
18
-
19
- # This may not be a git project. Search relative to the Gemfile.
20
- repo_path = Bundler.root
21
-
22
- all_xcodeproj_paths = Dir[File.expand_path(File.join(repo_path, '**/*.xcodeproj'))]
23
- # find an xcodeproj (ignoring the Cocoapods one)
24
- xcodeproj_paths = Fastlane::Actions.ignore_cocoapods_path(all_xcodeproj_paths)
25
-
26
- # no projects found: error
27
- UI.user_error!('Could not find a .xcodeproj in the current repository\'s working directory.') and return nil if xcodeproj_paths.count == 0
28
-
29
- # too many projects found: error
30
- if xcodeproj_paths.count > 1
31
- repo_pathname = Pathname.new repo_path
32
- relative_projects = xcodeproj_paths.map { |e| Pathname.new(e).relative_path_from(repo_pathname).to_s }.join("\n")
33
- UI.user_error!("Found multiple .xcodeproj projects in the current repository's working directory. Please specify your app's main project: \n#{relative_projects}")
34
- return nil
35
- end
36
-
37
- # one project found: great
38
- xcodeproj_paths.first
39
- end
40
-
41
- def domains_from_params(params)
42
- app_link_subdomains = app_link_subdomains_from_params params
43
- custom_domains = custom_domains_from_params params
44
- (app_link_subdomains + custom_domains).uniq
45
- end
46
-
47
- def app_link_subdomains_from_params(params)
48
- app_link_subdomain = params[:app_link_subdomain]
49
- live_key = params[:live_key]
50
- test_key = params[:test_key]
51
- return [] if live_key.nil? and test_key.nil?
52
- return [] if app_link_subdomain.nil?
53
-
54
- domains = []
55
- unless live_key.nil?
56
- domains += [
57
- "#{app_link_subdomain}.app.link",
58
- "#{app_link_subdomain}-alternate.app.link"
59
- ]
60
- end
61
- unless test_key.nil?
62
- domains += [
63
- "#{app_link_subdomain}.test-app.link",
64
- "#{app_link_subdomain}-alternate.test-app.link"
65
- ]
66
- end
67
- domains
68
- end
69
-
70
- def custom_domains_from_params(params)
71
- domains = params[:domains]
72
- return [] if domains.nil?
73
-
74
- if domains.kind_of? Array
75
- domains = domains.map(&:to_s)
76
- elsif domains.kind_of? String
77
- domains = domains.split(",")
78
- else
79
- raise ArgumentError, "Unsupported type #{domains.class.name} for :domains key"
80
- end
81
-
82
- domains
83
- end
84
-
85
- def podfile_path_from_params(params)
86
- # Disable Podfile update if add_sdk: false is present
87
- return nil unless add_sdk? params
88
-
89
- # Use the :podfile parameter if present
90
- if params[:podfile]
91
- UI.user_error! ":podfile argument must specify a path ending in '/Podfile'" unless params[:podfile] =~ %r{/Podfile$}
92
- podfile_path = File.expand_path params[:podfile], Bundler.root
93
- return podfile_path if File.exist? podfile_path
94
- UI.user_error! "#{podfile_path} not found"
95
- end
96
-
97
- # Look in the same directory as the project (typical setup)
98
- podfile_path = File.expand_path "../Podfile", params[:xcodeproj]
99
- return podfile_path if File.exist? podfile_path
100
- end
101
-
102
- def cartfile_path_from_params(params)
103
- # Disable Cartfile update if add_sdk: false is present
104
- return nil unless add_sdk? params
105
-
106
- # Use the :cartfile parameter if present
107
- if params[:cartfile]
108
- UI.user_error! ":cartfile argument must specify a path ending in '/Cartfile'" unless params[:cartfile] =~ %r{/Cartfile$}
109
- cartfile_path = File.expand_path params[:cartfile], Bundler.root
110
- return cartfile_path if File.exist? cartfile_path
111
- UI.user_error! "#{cartfile_path} not found"
112
- end
113
-
114
- # Look in the same directory as the project (typical setup)
115
- cartfile_path = File.expand_path "../Cartfile", params[:xcodeproj]
116
- return cartfile_path if File.exist? cartfile_path
117
- end
118
-
119
- def add_sdk?(params)
120
- add_sdk_param = params[:add_sdk]
121
- return false if add_sdk_param.nil?
122
-
123
- case add_sdk_param
124
- when String
125
- add_sdk_param.casecmp? "true"
126
- else
127
- add_sdk_param
128
- end
129
- end
130
- end
131
- end
132
- end
@@ -1,505 +0,0 @@
1
- require "fastlane/plugin/patch"
2
- require "plist"
3
-
4
- module Fastlane
5
- module Helper
6
- module IOSHelper
7
- APPLINKS = "applinks"
8
- ASSOCIATED_DOMAINS = "com.apple.developer.associated-domains"
9
- CODE_SIGN_ENTITLEMENTS = "CODE_SIGN_ENTITLEMENTS"
10
- DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM"
11
- PRODUCT_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER"
12
- RELEASE_CONFIGURATION = "Release"
13
-
14
- def add_keys_to_info_plist(project, target_name, keys, configuration = RELEASE_CONFIGURATION)
15
- update_info_plist_setting project, target_name, configuration do |info_plist|
16
- # add/overwrite Branch key(s)
17
- if keys.count > 1
18
- info_plist["branch_key"] = keys
19
- elsif keys[:live]
20
- info_plist["branch_key"] = keys[:live]
21
- else # no need to validate here, which was done by the action
22
- info_plist["branch_key"] = keys[:test]
23
- end
24
- end
25
- end
26
-
27
- def add_branch_universal_link_domains_to_info_plist(project, target_name, domains, configuration = RELEASE_CONFIGURATION)
28
- # Add all supplied domains unless all are app.link domains.
29
- return if domains.all? { |d| d =~ /app\.link$/ }
30
-
31
- update_info_plist_setting project, target_name, configuration do |info_plist|
32
- info_plist["branch_universal_link_domains"] = domains
33
- end
34
- end
35
-
36
- def update_info_plist_setting(project, target_name, configuration = RELEASE_CONFIGURATION, &b)
37
- # raises
38
- target = target_from_project project, target_name
39
-
40
- # find the Info.plist paths for this configuration
41
- info_plist_path = expanded_build_setting target, "INFOPLIST_FILE", configuration
42
-
43
- raise "Info.plist not found for configuration #{configuration}" if info_plist_path.nil?
44
-
45
- project_parent = File.dirname project.path
46
-
47
- info_plist_path = File.expand_path info_plist_path, project_parent
48
-
49
- # try to open and parse the Info.plist (raises)
50
- info_plist = File.open(info_plist_path) { |f| Plist.parse_xml f }
51
- raise "Failed to parse #{info_plist_path}" if info_plist.nil?
52
-
53
- yield info_plist
54
-
55
- Plist::Emit.save_plist info_plist, info_plist_path
56
- add_change info_plist_path
57
- end
58
-
59
- def add_universal_links_to_project(project, target_name, domains, remove_existing, configuration = RELEASE_CONFIGURATION)
60
- # raises
61
- target = target_from_project project, target_name
62
-
63
- relative_entitlements_path = expanded_build_setting target, CODE_SIGN_ENTITLEMENTS, configuration
64
- project_parent = File.dirname project.path
65
-
66
- if relative_entitlements_path.nil?
67
- relative_entitlements_path = File.join target.name, "#{target.name}.entitlements"
68
- entitlements_path = File.expand_path relative_entitlements_path, project_parent
69
-
70
- # Add CODE_SIGN_ENTITLEMENTS setting to each configuration
71
- target.build_configuration_list.set_setting CODE_SIGN_ENTITLEMENTS, relative_entitlements_path
72
-
73
- # Add the file to the project
74
- project.new_file relative_entitlements_path
75
-
76
- entitlements = {}
77
- current_domains = []
78
-
79
- add_change project.path
80
- new_path = entitlements_path
81
- else
82
- entitlements_path = File.expand_path relative_entitlements_path, project_parent
83
- # Raises
84
- entitlements = File.open(entitlements_path) { |f| Plist.parse_xml f }
85
- raise "Failed to parse entitlements file #{entitlements_path}" if entitlements.nil?
86
-
87
- if remove_existing
88
- current_domains = []
89
- else
90
- current_domains = entitlements[ASSOCIATED_DOMAINS]
91
- end
92
- end
93
-
94
- current_domains += domains.map { |d| "#{APPLINKS}:#{d}" }
95
- all_domains = current_domains.uniq
96
-
97
- entitlements[ASSOCIATED_DOMAINS] = all_domains
98
-
99
- Plist::Emit.save_plist entitlements, entitlements_path
100
- add_change entitlements_path
101
-
102
- new_path
103
- end
104
-
105
- def team_and_bundle_from_app_id(identifier)
106
- team = identifier.sub(/\..+$/, "")
107
- bundle = identifier.sub(/^[^.]+\./, "")
108
- [team, bundle]
109
- end
110
-
111
- def update_team_and_bundle_ids_from_aasa_file(project, target_name, domain)
112
- # raises
113
- identifiers = app_ids_from_aasa_file domain
114
- raise "Multiple appIDs found in AASA file" if identifiers.count > 1
115
-
116
- identifier = identifiers[0]
117
- team, bundle = team_and_bundle_from_app_id identifier
118
-
119
- update_team_and_bundle_ids project, target_name, team, bundle
120
- add_change project.path.expand_path
121
- end
122
-
123
- def validate_team_and_bundle_ids_from_aasa_files(project, target_name, domains = [], remove_existing = false, configuration = RELEASE_CONFIGURATION)
124
- @errors = []
125
- valid = true
126
-
127
- # Include any domains already in the project.
128
- # Raises. Returns a non-nil array of strings.
129
- if remove_existing
130
- # Don't validate domains to be removed (#16)
131
- all_domains = domains
132
- else
133
- all_domains = (domains + domains_from_project(project, target_name, configuration)).uniq
134
- end
135
-
136
- if all_domains.empty?
137
- # Cannot get here from SetupBranchAction, since the domains passed in will never be empty.
138
- # If called from ValidateUniversalLinksAction, this is a failure, possibly caused by
139
- # failure to add applinks:.
140
- @errors << "No Universal Link domains in project. Be sure each Universal Link domain is prefixed with applinks:."
141
- return false
142
- end
143
-
144
- all_domains.each do |domain|
145
- domain_valid = validate_team_and_bundle_ids project, target_name, domain, configuration
146
- valid &&= domain_valid
147
- UI.message "Valid Universal Link configuration for #{domain} ✅" if domain_valid
148
- end
149
- valid
150
- end
151
-
152
- def app_ids_from_aasa_file(domain)
153
- data = contents_of_aasa_file domain
154
- # errors reported in the method above
155
- return nil if data.nil?
156
-
157
- # raises
158
- file = JSON.parse data
159
-
160
- applinks = file[APPLINKS]
161
- @errors << "[#{domain}] No #{APPLINKS} found in AASA file" and return if applinks.nil?
162
-
163
- details = applinks["details"]
164
- @errors << "[#{domain}] No details found for #{APPLINKS} in AASA file" and return if details.nil?
165
-
166
- identifiers = details.map { |d| d["appID"] }.uniq
167
- @errors << "[#{domain}] No appID found in AASA file" and return if identifiers.count <= 0
168
- identifiers
169
- rescue JSON::ParserError => e
170
- @errors << "[#{domain}] Failed to parse AASA file: #{e.message}"
171
- nil
172
- end
173
-
174
- def contents_of_aasa_file(domain)
175
- uris = [
176
- URI("https://#{domain}/.well-known/apple-app-site-association"),
177
- URI("https://#{domain}/apple-app-site-association")
178
- # URI("http://#{domain}/.well-known/apple-app-site-association"),
179
- # URI("http://#{domain}/apple-app-site-association")
180
- ]
181
-
182
- data = nil
183
-
184
- uris.each do |uri|
185
- break unless data.nil?
186
-
187
- Net::HTTP.start uri.host, uri.port, use_ssl: uri.scheme == "https" do |http|
188
- request = Net::HTTP::Get.new uri
189
- response = http.request request
190
-
191
- # Better to use Net::HTTPRedirection and Net::HTTPSuccess here, but
192
- # having difficulty with the unit tests.
193
- if (300..399).cover?(response.code.to_i)
194
- UI.important "#{uri} cannot result in a redirect. Ignoring."
195
- next
196
- elsif response.code.to_i != 200
197
- # Try the next URI.
198
- UI.message "Could not retrieve #{uri}: #{response.code} #{response.message}. Ignoring."
199
- next
200
- end
201
-
202
- content_type = response["Content-type"]
203
- @errors << "[#{domain}] AASA Response does not contain a Content-type header" and next if content_type.nil?
204
-
205
- case content_type
206
- when %r{application/pkcs7-mime}
207
- # Verify/decrypt PKCS7 (non-Branch domains)
208
- cert_store = OpenSSL::X509::Store.new
209
- signature = OpenSSL::PKCS7.new response.body
210
- # raises
211
- signature.verify nil, cert_store, nil, OpenSSL::PKCS7::NOVERIFY
212
- data = signature.data
213
- else
214
- @error << "[#{domain}] Unsigned AASA files must be served via HTTPS" and next if uri.scheme == "http"
215
- data = response.body
216
- end
217
-
218
- UI.message "GET #{uri}: #{response.code} #{response.message} (Content-type:#{content_type}) ✅"
219
- end
220
- end
221
-
222
- @errors << "[#{domain}] Failed to retrieve AASA file" and return nil if data.nil?
223
-
224
- data
225
- rescue IOError, SocketError => e
226
- @errors << "[#{domain}] Socket error: #{e.message}"
227
- nil
228
- rescue OpenSSL::PKCS7::PKCS7Error => e
229
- @errors << "[#{domain}] Failed to verify signed AASA file: #{e.message}"
230
- nil
231
- end
232
-
233
- def validate_team_and_bundle_ids(project, target_name, domain, configuration)
234
- # raises
235
- target = target_from_project project, target_name
236
-
237
- product_bundle_identifier = expanded_build_setting target, PRODUCT_BUNDLE_IDENTIFIER, configuration
238
- development_team = expanded_build_setting target, DEVELOPMENT_TEAM, configuration
239
-
240
- identifiers = app_ids_from_aasa_file domain
241
- return false if identifiers.nil?
242
-
243
- app_id = "#{development_team}.#{product_bundle_identifier}"
244
- match_found = identifiers.include? app_id
245
-
246
- unless match_found
247
- @errors << "[#{domain}] appID mismatch. Project: #{app_id}. AASA: #{identifiers}"
248
- end
249
-
250
- match_found
251
- end
252
-
253
- def validate_project_domains(expected, project, target, configuration = RELEASE_CONFIGURATION)
254
- @errors = []
255
- project_domains = domains_from_project project, target, configuration
256
- valid = expected.count == project_domains.count
257
- if valid
258
- sorted = expected.sort
259
- project_domains.sort.each_with_index do |domain, index|
260
- valid = false and break unless sorted[index] == domain
261
- end
262
- end
263
-
264
- unless valid
265
- @errors << "Project domains do not match :domains parameter"
266
- @errors << "Project domains: #{project_domains}"
267
- @errors << ":domains parameter: #{expected}"
268
- end
269
-
270
- valid
271
- end
272
-
273
- def update_team_and_bundle_ids(project, target_name, team, bundle)
274
- # raises
275
- target = target_from_project project, target_name
276
-
277
- target.build_configuration_list.set_setting PRODUCT_BUNDLE_IDENTIFIER, bundle
278
- target.build_configuration_list.set_setting DEVELOPMENT_TEAM, team
279
-
280
- # also update the team in the first test target
281
- target = project.targets.find(&:test_target_type?)
282
- return if target.nil?
283
-
284
- target.build_configuration_list.set_setting DEVELOPMENT_TEAM, team
285
- end
286
-
287
- def target_from_project(project, target_name)
288
- if target_name
289
- target = project.targets.find { |t| t.name == target_name }
290
- raise "Target #{target} not found" if target.nil?
291
- else
292
- # find the first application target
293
- target = project.targets.find { |t| !t.extension_target_type? && !t.test_target_type? }
294
- raise "No application target found" if target.nil?
295
- end
296
- target
297
- end
298
-
299
- def domains_from_project(project, target_name, configuration = RELEASE_CONFIGURATION)
300
- # Raises. Does not return nil.
301
- target = target_from_project project, target_name
302
-
303
- relative_entitlements_path = expanded_build_setting target, CODE_SIGN_ENTITLEMENTS, configuration
304
- return [] if relative_entitlements_path.nil?
305
-
306
- project_parent = File.dirname project.path
307
- entitlements_path = File.expand_path relative_entitlements_path, project_parent
308
-
309
- # Raises
310
- entitlements = File.open(entitlements_path) { |f| Plist.parse_xml f }
311
- raise "Failed to parse entitlements file #{entitlements_path}" if entitlements.nil?
312
-
313
- entitlements[ASSOCIATED_DOMAINS].select { |d| d =~ /^applinks:/ }.map { |d| d.sub(/^applinks:/, "") }
314
- end
315
-
316
- def expanded_build_setting(target, setting_name, configuration)
317
- setting_value = target.resolved_build_setting(setting_name)[configuration]
318
- return if setting_value.nil?
319
-
320
- search_position = 0
321
- while (matches = /\$\(([^(){}]*)\)|\$\{([^(){}]*)\}/.match(setting_value, search_position))
322
- macro_name = matches[1] || matches[2]
323
- search_position = setting_value.index(macro_name) - 2
324
-
325
- expanded_macro = macro_name == "SRCROOT" ? "." : expanded_build_setting(target, macro_name, configuration)
326
- search_position += macro_name.length + 3 and next if expanded_macro.nil?
327
-
328
- setting_value.gsub!(/\$\(#{macro_name}\)|\$\{#{macro_name}\}/, expanded_macro)
329
- search_position += expanded_macro.length
330
- end
331
- setting_value
332
- end
333
-
334
- def add_system_frameworks(project, target_name, frameworks)
335
- target = target_from_project project, target_name
336
-
337
- target.add_system_framework frameworks
338
- end
339
-
340
- def patch_app_delegate_swift(project)
341
- app_delegate_swift = project.files.find { |f| f.path =~ /AppDelegate.swift$/ }
342
- return false if app_delegate_swift.nil?
343
-
344
- app_delegate_swift_path = app_delegate_swift.real_path.to_s
345
-
346
- app_delegate = File.open(app_delegate_swift_path, &:read)
347
- return false if app_delegate =~ /import\s+Branch/
348
-
349
- UI.message "Patching #{app_delegate_swift_path}"
350
-
351
- Actions::PatchAction.run(
352
- files: app_delegate_swift_path,
353
- regexp: /^\s*import .*$/,
354
- text: "\nimport Branch",
355
- mode: :prepend,
356
- offset: 0
357
- )
358
-
359
- # TODO: This is Swift 3. Support other versions, esp. 4.
360
- init_session_text = <<-EOF
361
- #if DEBUG
362
- Branch.setUseTestBranchKey(true)
363
- #endif
364
-
365
- Branch.getInstance().initSession(launchOptions: launchOptions) {
366
- universalObject, linkProperties, error in
367
-
368
- // TODO: Route Branch links
369
- }
370
- EOF
371
-
372
- Actions::PatchAction.run(
373
- files: app_delegate_swift_path,
374
- regexp: /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m,
375
- text: init_session_text,
376
- mode: :append,
377
- offset: 0
378
- )
379
-
380
- unless app_delegate =~ /application:.*continueUserActivity:.*restorationHandler:/
381
- # Add the application:continueUserActivity:restorationHandler method if it does not exist
382
- continue_user_activity_text = <<-EOF
383
-
384
-
385
- func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
386
- return Branch.getInstance().continue(userActivity)
387
- }
388
- EOF
389
-
390
- Actions::PatchAction.run(
391
- files: app_delegate_swift_path,
392
- regexp: /\n\s*\}[^{}]*\Z/m,
393
- text: continue_user_activity_text,
394
- mode: :prepend,
395
- offset: 0
396
- )
397
- end
398
-
399
- add_change app_delegate_swift_path
400
- true
401
- end
402
-
403
- def patch_app_delegate_objc(project)
404
- app_delegate_objc = project.files.find { |f| f.path =~ /AppDelegate.m$/ }
405
- return false if app_delegate_objc.nil?
406
-
407
- app_delegate_objc_path = app_delegate_objc.real_path.to_s
408
-
409
- app_delegate = File.open(app_delegate_objc_path, &:read)
410
- return false if app_delegate =~ %r{^\s+#import\s+<Branch/Branch.h>|^\s+@import\s+Branch;}
411
-
412
- UI.message "Patching #{app_delegate_objc_path}"
413
-
414
- Actions::PatchAction.run(
415
- files: app_delegate_objc_path,
416
- regexp: /^\s+@import|^\s+#import.*$/,
417
- text: "\n#import <Branch/Branch.h>",
418
- mode: :prepend,
419
- offset: 0
420
- )
421
-
422
- init_session_text = <<-EOF
423
- #ifdef DEBUG
424
- [Branch setUseTestBranchKey:YES];
425
- #endif // DEBUG
426
-
427
- [[Branch getInstance] initSessionWithLaunchOptions:launchOptions
428
- andRegisterDeepLinkHandlerUsingBranchUniversalObject:^(BranchUniversalObject *universalObject, BranchLinkProperties *linkProperties, NSError *error){
429
- // TODO: Route Branch links
430
- }];
431
- EOF
432
-
433
- Actions::PatchAction.run(
434
- files: app_delegate_objc_path,
435
- regexp: /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m,
436
- text: init_session_text,
437
- mode: :append,
438
- offset: 0
439
- )
440
-
441
- unless app_delegate =~ /application:.*continueUserActivity:.*restorationHandler:/
442
- # Add the application:continueUserActivity:restorationHandler method if it does not exist
443
- continue_user_activity_text = <<-EOF
444
-
445
-
446
- - (BOOL)application:(UIApplication *)app continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler
447
- {
448
- return [[Branch getInstance] continueUserActivity:userActivity];
449
- }
450
- EOF
451
-
452
- Actions::PatchAction.run(
453
- files: app_delegate_objc_path,
454
- regexp: /\n\s*@end[^@]*\Z/m,
455
- text: continue_user_activity_text,
456
- mode: :prepend,
457
- offset: 0
458
- )
459
- end
460
-
461
- add_change app_delegate_objc_path
462
- true
463
- end
464
-
465
- def patch_podfile(podfile_path)
466
- podfile = File.open(podfile_path, &:read)
467
-
468
- # Podfile already contains the Branch pod
469
- return false if podfile =~ /pod\s+('Branch'|"Branch")/
470
-
471
- UI.message "Adding pod \"Branch\" to #{podfile_path}"
472
-
473
- # TODO: Improve this patch. Should work in the majority of cases for now.
474
- Actions::PatchAction.run(
475
- files: podfile_path,
476
- regexp: /^(\s*)pod\s*/,
477
- text: "\n\\1pod \"Branch\"\n",
478
- mode: :prepend,
479
- offset: 0
480
- )
481
-
482
- true
483
- end
484
-
485
- def patch_cartfile(cartfile_path)
486
- cartfile = File.open(cartfile_path, &:read)
487
-
488
- # Cartfile already contains the Branch framework
489
- return false if cartfile =~ /git.+Branch/
490
-
491
- UI.message "Adding \"Branch\" to #{cartfile_path}"
492
-
493
- Actions::PatchAction.run(
494
- files: cartfile_path,
495
- regexp: /\z/,
496
- text: "git \"https://github.com/BranchMetrics/ios-branch-deep-linking\"\n",
497
- mode: :append,
498
- offset: 0
499
- )
500
-
501
- true
502
- end
503
- end
504
- end
505
- end