fastlane 2.186.0 → 2.187.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +86 -86
  3. data/fastlane/lib/fastlane/actions/create_keychain.rb +5 -2
  4. data/fastlane/lib/fastlane/actions/docs/build_app.md +1 -1
  5. data/fastlane/lib/fastlane/actions/docs/capture_android_screenshots.md +25 -26
  6. data/fastlane/lib/fastlane/actions/docs/capture_ios_screenshots.md +2 -2
  7. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +171 -67
  8. data/fastlane/lib/fastlane/actions/latest_testflight_build_number.rb +3 -4
  9. data/fastlane/lib/fastlane/actions/lcov.rb +0 -4
  10. data/fastlane/lib/fastlane/actions/mailgun.rb +21 -27
  11. data/fastlane/lib/fastlane/actions/make_changelog_from_jenkins.rb +1 -1
  12. data/fastlane/lib/fastlane/actions/modify_services.rb +59 -24
  13. data/fastlane/lib/fastlane/actions/nexus_upload.rb +2 -2
  14. data/fastlane/lib/fastlane/actions/notarize.rb +1 -4
  15. data/fastlane/lib/fastlane/actions/number_of_commits.rb +1 -1
  16. data/fastlane/lib/fastlane/actions/oclint.rb +15 -14
  17. data/fastlane/lib/fastlane/actions/pod_push.rb +0 -2
  18. data/fastlane/lib/fastlane/actions/podio_item.rb +0 -7
  19. data/fastlane/lib/fastlane/actions/prompt.rb +3 -4
  20. data/fastlane/lib/fastlane/actions/push_git_tags.rb +1 -1
  21. data/fastlane/lib/fastlane/actions/puts.rb +1 -2
  22. data/fastlane/lib/fastlane/actions/register_devices.rb +0 -1
  23. data/fastlane/lib/fastlane/actions/reset_git_repo.rb +5 -8
  24. data/fastlane/lib/fastlane/actions/reset_simulator_contents.rb +0 -2
  25. data/fastlane/lib/fastlane/actions/resign.rb +2 -9
  26. data/fastlane/lib/fastlane/actions/rsync.rb +3 -6
  27. data/fastlane/lib/fastlane/actions/run_tests.rb +1 -1
  28. data/fastlane/lib/fastlane/actions/s3.rb +1 -1
  29. data/fastlane/lib/fastlane/actions/say.rb +2 -3
  30. data/fastlane/lib/fastlane/actions/scp.rb +4 -10
  31. data/fastlane/lib/fastlane/actions/set_build_number_repository.rb +1 -1
  32. data/fastlane/lib/fastlane/actions/set_changelog.rb +1 -1
  33. data/fastlane/lib/fastlane/actions/set_github_release.rb +2 -8
  34. data/fastlane/lib/fastlane/actions/set_info_plist_value.rb +1 -1
  35. data/fastlane/lib/fastlane/actions/set_pod_key.rb +3 -4
  36. data/fastlane/lib/fastlane/actions/setup_ci.rb +1 -2
  37. data/fastlane/lib/fastlane/actions/setup_circle_ci.rb +1 -1
  38. data/fastlane/lib/fastlane/actions/setup_jenkins.rb +7 -12
  39. data/fastlane/lib/fastlane/actions/setup_travis.rb +1 -1
  40. data/fastlane/lib/fastlane/actions/sh.rb +2 -4
  41. data/fastlane/lib/fastlane/actions/slack.rb +6 -8
  42. data/fastlane/lib/fastlane/actions/slather.rb +3 -19
  43. data/fastlane/lib/fastlane/actions/sonar.rb +12 -19
  44. data/fastlane/lib/fastlane/actions/sourcedocs.rb +62 -98
  45. data/fastlane/lib/fastlane/actions/splunkmint.rb +2 -2
  46. data/fastlane/lib/fastlane/actions/spm.rb +3 -3
  47. data/fastlane/lib/fastlane/actions/ssh.rb +5 -10
  48. data/fastlane/lib/fastlane/actions/testfairy.rb +0 -1
  49. data/fastlane/lib/fastlane/actions/tryouts.rb +2 -3
  50. data/fastlane/lib/fastlane/actions/twitter.rb +0 -5
  51. data/fastlane/lib/fastlane/actions/unlock_keychain.rb +3 -3
  52. data/fastlane/lib/fastlane/actions/update_app_group_identifiers.rb +1 -4
  53. data/fastlane/lib/fastlane/actions/update_code_signing_settings.rb +8 -15
  54. data/fastlane/lib/fastlane/actions/update_fastlane.rb +2 -2
  55. data/fastlane/lib/fastlane/documentation/docs_generator.rb +1 -1
  56. data/fastlane/lib/fastlane/version.rb +1 -1
  57. data/fastlane/swift/Deliverfile.swift +1 -1
  58. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  59. data/fastlane/swift/Fastlane.swift +57 -57
  60. data/fastlane/swift/Gymfile.swift +1 -1
  61. data/fastlane/swift/GymfileProtocol.swift +1 -1
  62. data/fastlane/swift/Matchfile.swift +1 -1
  63. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  64. data/fastlane/swift/Precheckfile.swift +1 -1
  65. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  66. data/fastlane/swift/Scanfile.swift +1 -1
  67. data/fastlane/swift/ScanfileProtocol.swift +1 -1
  68. data/fastlane/swift/Screengrabfile.swift +1 -1
  69. data/fastlane/swift/ScreengrabfileProtocol.swift +4 -4
  70. data/fastlane/swift/Snapshotfile.swift +1 -1
  71. data/fastlane/swift/SnapshotfileProtocol.swift +1 -1
  72. data/fastlane/swift/formatting/Brewfile.lock.json +11 -11
  73. data/produce/lib/produce/commands_generator.rb +99 -27
  74. data/produce/lib/produce/developer_center.rb +42 -4
  75. data/produce/lib/produce/options.rb +1 -1
  76. data/produce/lib/produce/service.rb +270 -179
  77. data/screengrab/lib/screengrab/android_environment.rb +2 -52
  78. data/screengrab/lib/screengrab/dependency_checker.rb +0 -20
  79. data/screengrab/lib/screengrab/options.rb +5 -2
  80. data/screengrab/lib/screengrab/runner.rb +108 -106
  81. data/snapshot/lib/assets/SnapfileTemplate +2 -1
  82. data/snapshot/lib/assets/SnapfileTemplate.swift +2 -1
  83. data/snapshot/lib/assets/SnapshotHelper.swift +14 -10
  84. data/snapshot/lib/snapshot/reports_generator.rb +3 -1
  85. data/snapshot/lib/snapshot/test_command_generator.rb +16 -2
  86. data/spaceship/lib/spaceship/connect_api/models/bundle_id.rb +8 -0
  87. data/spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb +58 -17
  88. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +41 -1
  89. metadata +20 -21
  90. data/fastlane/lib/fastlane/helper/.git_helper.rb.swp +0 -0
@@ -4,31 +4,21 @@ require 'fastlane_core/command_executor'
4
4
  module Screengrab
5
5
  class AndroidEnvironment
6
6
  attr_reader :android_home
7
- attr_reader :build_tools_version
8
7
 
9
8
  # android_home - the String path to the install location of the Android SDK
10
- # build_tools_version - the String version of the Android build tools that should be used
11
- def initialize(android_home, build_tools_version)
9
+ # build_tools_version - the String version of the Android build tools that should be used, ignored
10
+ def initialize(android_home, build_tools_version = nil)
12
11
  @android_home = android_home
13
- @build_tools_version = build_tools_version
14
12
  end
15
13
 
16
14
  def platform_tools_path
17
15
  @platform_tools_path ||= find_platform_tools(android_home)
18
16
  end
19
17
 
20
- def build_tools_path
21
- @build_tools_path ||= find_build_tools(android_home, build_tools_version)
22
- end
23
-
24
18
  def adb_path
25
19
  @adb_path ||= find_adb(platform_tools_path)
26
20
  end
27
21
 
28
- def aapt_path
29
- @aapt_path ||= find_aapt(build_tools_path)
30
- end
31
-
32
22
  private
33
23
 
34
24
  def find_platform_tools(android_home)
@@ -38,38 +28,6 @@ module Screengrab
38
28
  File.directory?(platform_tools_path) ? platform_tools_path : nil
39
29
  end
40
30
 
41
- def find_build_tools(android_home, build_tools_version)
42
- return nil unless android_home
43
-
44
- build_tools_dir = Helper.localize_file_path(File.join(android_home, 'build-tools'))
45
-
46
- return nil unless build_tools_dir && File.directory?(build_tools_dir)
47
-
48
- return Helper.localize_file_path(File.join(build_tools_dir, build_tools_version)) if build_tools_version
49
-
50
- version = select_build_tools_version(build_tools_dir)
51
-
52
- return version ? Helper.localize_file_path(File.join(build_tools_dir, version)) : nil
53
- end
54
-
55
- def select_build_tools_version(build_tools_dir)
56
- # Collect the sub-directories of the build_tools_dir, rejecting any that start with '.' to remove . and ..
57
- dir_names = Dir.entries(build_tools_dir).select { |e| !e.start_with?('.') && File.directory?(File.join(build_tools_dir, e)) }
58
-
59
- # Collect a sorted array of Version objects from the directory names, handling the possibility that some
60
- # entries may not be valid version names
61
- versions = dir_names.map do |d|
62
- begin
63
- Gem::Version.new(d)
64
- rescue
65
- nil
66
- end
67
- end.reject(&:nil?).sort
68
-
69
- # We'll take the last entry (highest version number) as the directory name we want
70
- versions.last.to_s
71
- end
72
-
73
31
  def find_adb(platform_tools_path)
74
32
  return FastlaneCore::CommandExecutor.which('adb') unless platform_tools_path
75
33
 
@@ -78,14 +36,6 @@ module Screengrab
78
36
  return executable_command?(adb_path) ? adb_path : nil
79
37
  end
80
38
 
81
- def find_aapt(build_tools_path)
82
- return FastlaneCore::CommandExecutor.which('aapt') unless build_tools_path
83
-
84
- aapt_path = Helper.get_executable_path(File.join(build_tools_path, 'aapt'))
85
- aapt_path = Helper.localize_file_path(aapt_path)
86
- return executable_command?(aapt_path) ? aapt_path : nil
87
- end
88
-
89
39
  def executable_command?(cmd_path)
90
40
  Helper.executable?(cmd_path)
91
41
  end
@@ -6,7 +6,6 @@ module Screengrab
6
6
  return if Helper.test?
7
7
 
8
8
  check_adb(android_env)
9
- check_aapt(android_env)
10
9
  end
11
10
 
12
11
  def self.check_adb(android_env)
@@ -30,25 +29,6 @@ module Screengrab
30
29
  UI.user_error!('adb command not found')
31
30
  end
32
31
 
33
- def self.check_aapt(android_env)
34
- android_home = android_env.android_home
35
- aapt_path = android_env.aapt_path
36
-
37
- warn_if_command_path_not_relative_to_android_home('aapt', android_home, aapt_path)
38
- # aapt is not required in order to function, so we'll only warn if we can't find it.
39
- warn_missing_aapt(android_home) unless aapt_path
40
- end
41
-
42
- def self.warn_missing_aapt(android_home)
43
- if android_home
44
- UI.important("The `aapt` command could not be found relative to your provided ANDROID_HOME at #{android_home}")
45
- UI.important("Please ensure that the Android SDK is installed and you have the build tools downloaded")
46
- else
47
- UI.important("The `aapt` command could not be found on your PATH")
48
- UI.important("Please ensure that the Android SDK is installed and you have the build tools downloaded and present on your PATH")
49
- end
50
- end
51
-
52
32
  def self.warn_if_command_path_not_relative_to_android_home(cmd_name, android_home, cmd_path)
53
33
  if android_home && cmd_path && !cmd_path.start_with?(android_home)
54
34
  UI.important("Using `#{cmd_name}` found at #{cmd_path} which is not within the specified ANDROID_HOME at #{android_home}")
@@ -22,7 +22,8 @@ module Screengrab
22
22
  FastlaneCore::ConfigItem.new(key: :build_tools_version,
23
23
  short_option: "-i",
24
24
  optional: true,
25
- description: "The Android build tools version to use, e.g. '23.0.2'"),
25
+ description: "The Android build tools version to use, e.g. '23.0.2'",
26
+ deprecated: true),
26
27
  FastlaneCore::ConfigItem.new(key: :locales,
27
28
  description: "A list of locales which should be used",
28
29
  short_option: "-q",
@@ -82,10 +83,12 @@ module Screengrab
82
83
  env_name: 'SCREENGRAB_ENDING_LOCALE',
83
84
  optional: true,
84
85
  default_value: 'en-US',
85
- description: "Return the device to this locale after running tests"),
86
+ description: "Return the device to this locale after running tests",
87
+ deprecated: true),
86
88
  FastlaneCore::ConfigItem.new(key: :use_adb_root,
87
89
  env_name: 'SCREENGRAB_USE_ADB_ROOT',
88
90
  description: "Restarts the adb daemon using `adb root` to allow access to screenshots directories on device. Use if getting 'Permission denied' errors",
91
+ deprecated: true,
89
92
  default_value: false,
90
93
  type: Boolean),
91
94
  FastlaneCore::ConfigItem.new(key: :app_apk_path,
@@ -6,12 +6,6 @@ require_relative 'module'
6
6
 
7
7
  module Screengrab
8
8
  class Runner
9
- NEEDED_PERMISSIONS = [
10
- 'android.permission.READ_EXTERNAL_STORAGE',
11
- 'android.permission.WRITE_EXTERNAL_STORAGE',
12
- 'android.permission.CHANGE_CONFIGURATION'
13
- ].freeze
14
-
15
9
  attr_accessor :number_of_retries
16
10
 
17
11
  def initialize(executor = FastlaneCore::CommandExecutor,
@@ -25,7 +19,6 @@ module Screengrab
25
19
 
26
20
  def run
27
21
  # Standardize the locales
28
- @config[:locales].map! { |locale| locale.gsub("_", "-") }
29
22
  FastlaneCore::PrintTable.print_values(config: @config, hide_keys: [], title: "Summary for screengrab #{Fastlane::VERSION}")
30
23
 
31
24
  app_apk_path = @config.fetch(:app_apk_path, ask: false)
@@ -59,14 +52,14 @@ module Screengrab
59
52
  device_serial = select_device
60
53
 
61
54
  device_screenshots_paths = [
62
- determine_external_screenshots_path(device_serial, @config[:locales]),
63
- determine_internal_screenshots_paths(@config[:app_package_name], @config[:locales])
55
+ determine_external_screenshots_path(device_serial, @config[:app_package_name], @config[:locales]),
56
+ determine_internal_screenshots_paths(device_serial, @config[:app_package_name], @config[:locales])
64
57
  ].flatten
65
58
 
66
59
  # Root is needed to access device paths at /data
67
60
  if @config[:use_adb_root]
68
- run_adb_command("-s #{device_serial} root", print_all: false, print_command: true)
69
- run_adb_command("-s #{device_serial} wait-for-device", print_all: false, print_command: true)
61
+ run_adb_command("-s #{device_serial.shellescape} root", print_all: false, print_command: true)
62
+ run_adb_command("-s #{device_serial.shellescape} wait-for-device", print_all: false, print_command: true)
70
63
  end
71
64
 
72
65
  clear_device_previous_screenshots(@config[:app_package_name], device_serial, device_screenshots_paths)
@@ -74,9 +67,7 @@ module Screengrab
74
67
  app_apk_path ||= select_app_apk(discovered_apk_paths)
75
68
  tests_apk_path ||= select_tests_apk(discovered_apk_paths)
76
69
 
77
- validate_apk(app_apk_path)
78
-
79
- number_of_screenshots = run_tests(device_type_dir_name, device_screenshots_paths, device_serial, app_apk_path, tests_apk_path, test_classes_to_use, test_packages_to_use, @config[:launch_arguments])
70
+ number_of_screenshots = run_tests(device_type_dir_name, device_serial, app_apk_path, tests_apk_path, test_classes_to_use, test_packages_to_use, @config[:launch_arguments])
80
71
 
81
72
  ReportsGenerator.new.generate
82
73
 
@@ -133,72 +124,71 @@ module Screengrab
133
124
  Dir.glob(File.join(output_directory, '**', device_type, '*.png'), File::FNM_CASEFOLD)
134
125
  end
135
126
 
136
- def determine_external_screenshots_path(device_serial, locales)
127
+ def get_device_environment_variable(device_serial, variable_name)
137
128
  # macOS evaluates $foo in `echo $foo` before executing the command,
138
129
  # Windows doesn't - hence the double backslash vs. single backslash
139
- command = Helper.windows? ? "shell echo \$EXTERNAL_STORAGE " : "shell echo \\$EXTERNAL_STORAGE"
140
- device_ext_storage = run_adb_command("-s #{device_serial} #{command}",
141
- print_all: true,
142
- print_command: true)
143
- device_ext_storage = device_ext_storage.strip
130
+ command = Helper.windows? ? "shell echo \$#{variable_name.shellescape.shellescape}" : "shell echo \\$#{variable_name.shellescape.shellescape}"
131
+ value = run_adb_command("-s #{device_serial.shellescape} #{command}",
132
+ print_all: true,
133
+ print_command: true)
134
+ return value.strip
135
+ end
136
+
137
+ # Don't need to use to use run-as if external
138
+ def use_adb_run_as?(path, device_serial)
139
+ device_ext_storage = get_device_environment_variable(device_serial, "EXTERNAL_STORAGE")
140
+ return !path.start_with?(device_ext_storage)
141
+ end
142
+
143
+ def determine_external_screenshots_path(device_serial, app_package_name, locales)
144
+ device_ext_storage = get_device_environment_variable(device_serial, "EXTERNAL_STORAGE")
144
145
  return locales.map do |locale|
145
- File.join(device_ext_storage, @config[:app_package_name], 'screengrab', locale, "images", "screenshots")
146
- end.flatten
146
+ [
147
+ File.join(device_ext_storage, app_package_name, 'screengrab', locale, "images", "screenshots"),
148
+ File.join(device_ext_storage, "Android", "data", app_package_name, 'files', 'screengrab', locale, "images", "screenshots")
149
+ ]
150
+ end.flatten.map { |path| [path, false] }
147
151
  end
148
152
 
149
- def determine_internal_screenshots_paths(app_package_name, locales)
153
+ def determine_internal_screenshots_paths(device_serial, app_package_name, locales)
154
+ device_data = get_device_environment_variable(device_serial, "ANDROID_DATA")
150
155
  return locales.map do |locale|
151
156
  [
152
- "/data/user/0/#{app_package_name}/files/#{app_package_name}/screengrab/#{locale}/images/screenshots",
157
+ "#{device_data}/user/0/#{app_package_name}/files/#{app_package_name}/screengrab/#{locale}/images/screenshots",
153
158
 
154
159
  # https://github.com/fastlane/fastlane/issues/15653#issuecomment-578541663
155
- "/data/data/#{app_package_name}/files/#{app_package_name}/screengrab/#{locale}/images/screenshots",
160
+ "#{device_data}/data/#{app_package_name}/files/#{app_package_name}/screengrab/#{locale}/images/screenshots",
156
161
 
157
- "/data/data/#{app_package_name}/app_screengrab/#{locale}/images/screenshots",
158
- "/data/data/#{app_package_name}/screengrab/#{locale}/images/screenshots"
162
+ "#{device_data}/data/#{app_package_name}/app_screengrab/#{locale}/images/screenshots",
163
+ "#{device_data}/data/#{app_package_name}/screengrab/#{locale}/images/screenshots"
159
164
  ]
160
- end.flatten
165
+ end.flatten.map { |path| [path, true] }
161
166
  end
162
167
 
163
168
  def clear_device_previous_screenshots(app_package_name, device_serial, device_screenshots_paths)
164
169
  UI.message('Cleaning screenshots on device')
165
170
 
166
- device_screenshots_paths.each do |device_path|
167
- if_device_path_exists(app_package_name, device_serial, device_path) do |path|
168
- run_adb_command("-s #{device_serial} shell run-as #{app_package_name} rm -rf #{path}",
171
+ device_screenshots_paths.each do |(device_path, needs_run_as)|
172
+ if_device_path_exists(app_package_name, device_serial, device_path, needs_run_as) do |path|
173
+ # Determine if path needs the run-as permission
174
+ run_as = needs_run_as ? " run-as #{app_package_name.shellescape.shellescape}" : ""
175
+
176
+ run_adb_command("-s #{device_serial.shellescape} shell#{run_as} rm -rf #{path.shellescape.shellescape}",
169
177
  print_all: true,
170
178
  print_command: true)
171
179
  end
172
180
  end
173
181
  end
174
182
 
175
- def validate_apk(app_apk_path)
176
- unless @android_env.aapt_path
177
- UI.important("The `aapt` command could not be found on your system, so your app APK could not be validated")
178
- return
179
- end
180
-
181
- UI.message('Validating app APK')
182
- apk_permissions = @executor.execute(command: "#{@android_env.aapt_path} dump permissions #{app_apk_path}",
183
- print_all: true,
184
- print_command: true)
185
-
186
- missing_permissions = NEEDED_PERMISSIONS.reject { |needed| apk_permissions.include?(needed) }
187
-
188
- if missing_permissions.any?
189
- UI.user_error!("The needed permission(s) #{missing_permissions.join(', ')} could not be found in your app APK")
190
- end
191
- end
192
-
193
183
  def install_apks(device_serial, app_apk_path, tests_apk_path)
194
184
  UI.message('Installing app APK')
195
- apk_install_output = run_adb_command("-s #{device_serial} install -t -r #{app_apk_path.shellescape}",
185
+ apk_install_output = run_adb_command("-s #{device_serial.shellescape} install -t -r #{app_apk_path.shellescape}",
196
186
  print_all: true,
197
187
  print_command: true)
198
188
  UI.user_error!("App APK could not be installed") if apk_install_output.include?("Failure [")
199
189
 
200
190
  UI.message('Installing tests APK')
201
- apk_install_output = run_adb_command("-s #{device_serial} install -t -r #{tests_apk_path.shellescape}",
191
+ apk_install_output = run_adb_command("-s #{device_serial.shellescape} install -t -r #{tests_apk_path.shellescape}",
202
192
  print_all: true,
203
193
  print_command: true)
204
194
  UI.user_error!("Tests APK could not be installed") if apk_install_output.include?("Failure [")
@@ -209,14 +199,14 @@ module Screengrab
209
199
 
210
200
  if packages.include?(app_package_name.to_s)
211
201
  UI.message('Uninstalling app APK')
212
- run_adb_command("-s #{device_serial} uninstall #{app_package_name}",
202
+ run_adb_command("-s #{device_serial.shellescape} uninstall #{app_package_name.shellescape}",
213
203
  print_all: true,
214
204
  print_command: true)
215
205
  end
216
206
 
217
207
  if packages.include?(tests_package_name.to_s)
218
208
  UI.message('Uninstalling tests APK')
219
- run_adb_command("-s #{device_serial} uninstall #{tests_package_name}",
209
+ run_adb_command("-s #{device_serial.shellescape} uninstall #{tests_package_name.shellescape}",
220
210
  print_all: true,
221
211
  print_command: true)
222
212
  end
@@ -224,26 +214,37 @@ module Screengrab
224
214
 
225
215
  def grant_permissions(device_serial)
226
216
  UI.message('Granting the permission necessary to change locales on the device')
227
- run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.CHANGE_CONFIGURATION",
217
+ run_adb_command("-s #{device_serial.shellescape} shell pm grant #{@config[:app_package_name].shellescape.shellescape} android.permission.CHANGE_CONFIGURATION",
228
218
  print_all: true,
229
- print_command: true)
219
+ print_command: true,
220
+ raise_errors: false)
230
221
 
231
- if device_api_version(device_serial) >= 23
232
- UI.message('Granting the permissions necessary to access device external storage')
233
- run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.WRITE_EXTERNAL_STORAGE",
234
- print_all: true,
235
- print_command: true)
236
- run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.READ_EXTERNAL_STORAGE",
237
- print_all: true,
238
- print_command: true)
239
- end
222
+ UI.message('Granting the permissions necessary to access device external storage')
223
+ run_adb_command("-s #{device_serial.shellescape} shell pm grant #{@config[:app_package_name].shellescape.shellescape} android.permission.WRITE_EXTERNAL_STORAGE",
224
+ print_all: true,
225
+ print_command: true,
226
+ raise_errors: false)
227
+ run_adb_command("-s #{device_serial.shellescape} shell pm grant #{@config[:app_package_name].shellescape.shellescape} android.permission.READ_EXTERNAL_STORAGE",
228
+ print_all: true,
229
+ print_command: true,
230
+ raise_errors: false)
231
+ end
232
+
233
+ def kill_app(device_serial, package_name)
234
+ run_adb_command("-s #{device_serial.shellescape} shell am force-stop #{package_name.shellescape.shellescape}.test",
235
+ print_all: true,
236
+ print_command: true)
237
+ run_adb_command("-s #{device_serial.shellescape} shell am force-stop #{package_name.shellescape.shellescape}",
238
+ print_all: true,
239
+ print_command: true)
240
240
  end
241
241
 
242
- def run_tests(device_type_dir_name, device_screenshots_paths, device_serial, app_apk_path, tests_apk_path, test_classes_to_use, test_packages_to_use, launch_arguments)
242
+ def run_tests(device_type_dir_name, device_serial, app_apk_path, tests_apk_path, test_classes_to_use, test_packages_to_use, launch_arguments)
243
+ sdk_version = device_api_version(device_serial)
243
244
  unless @config[:reinstall_app]
244
245
  install_apks(device_serial, app_apk_path, tests_apk_path)
245
246
  grant_permissions(device_serial)
246
- enable_clean_status_bar(device_serial, app_apk_path)
247
+ enable_clean_status_bar(device_serial, sdk_version)
247
248
  end
248
249
 
249
250
  number_of_screenshots = 0
@@ -253,25 +254,28 @@ module Screengrab
253
254
  uninstall_apks(device_serial, @config[:app_package_name], @config[:tests_package_name])
254
255
  install_apks(device_serial, app_apk_path, tests_apk_path)
255
256
  grant_permissions(device_serial)
256
- enable_clean_status_bar(device_serial, app_apk_path)
257
+ else
258
+ kill_app(device_serial, @config[:app_package_name])
257
259
  end
258
- number_of_screenshots += run_tests_for_locale(device_type_dir_name, device_screenshots_paths, locale, device_serial, test_classes_to_use, test_packages_to_use, launch_arguments)
260
+ number_of_screenshots += run_tests_for_locale(device_type_dir_name, locale, device_serial, test_classes_to_use, test_packages_to_use, launch_arguments, sdk_version)
259
261
  end
260
262
 
261
263
  number_of_screenshots
262
264
  end
263
265
 
264
- def run_tests_for_locale(device_type_dir_name, device_screenshots_paths, locale, device_serial, test_classes_to_use, test_packages_to_use, launch_arguments)
266
+ def run_tests_for_locale(device_type_dir_name, locale, device_serial, test_classes_to_use, test_packages_to_use, launch_arguments, sdk_version)
265
267
  UI.message("Running tests for locale: #{locale}")
266
268
 
267
- instrument_command = ["-s #{device_serial} shell am instrument --no-window-animation -w",
268
- "-e testLocale #{locale.tr('-', '_')}",
269
- "-e endingLocale #{@config[:ending_locale].tr('-', '_')}"]
269
+ instrument_command = ["-s #{device_serial.shellescape} shell am instrument --no-window-animation -w",
270
+ "-e testLocale #{locale.shellescape.shellescape}"]
271
+ if sdk_version >= 28
272
+ instrument_command << "--no-hidden-api-checks"
273
+ end
270
274
  instrument_command << "-e appendTimestamp #{@config[:use_timestamp_suffix]}"
271
- instrument_command << "-e class #{test_classes_to_use.join(',')}" if test_classes_to_use
272
- instrument_command << "-e package #{test_packages_to_use.join(',')}" if test_packages_to_use
275
+ instrument_command << "-e class #{test_classes_to_use.join(',').shellescape.shellescape}" if test_classes_to_use
276
+ instrument_command << "-e package #{test_packages_to_use.join(',').shellescape.shellescape}" if test_packages_to_use
273
277
  instrument_command << launch_arguments.map { |item| '-e ' + item }.join(' ') if launch_arguments
274
- instrument_command << "#{@config[:tests_package_name]}/#{@config[:test_instrumentation_runner]}"
278
+ instrument_command << "#{@config[:tests_package_name].shellescape.shellescape}/#{@config[:test_instrumentation_runner].shellescape.shellescape}"
275
279
 
276
280
  test_output = run_adb_command(instrument_command.join(" \\\n"),
277
281
  print_all: true,
@@ -285,30 +289,40 @@ module Screengrab
285
289
  end
286
290
  end
287
291
 
288
- pull_screenshots_from_device(locale, device_serial, device_screenshots_paths, device_type_dir_name)
292
+ pull_screenshots_from_device(locale, device_serial, device_type_dir_name)
289
293
  end
290
294
 
291
- def pull_screenshots_from_device(locale, device_serial, device_screenshots_paths, device_type_dir_name)
295
+ def pull_screenshots_from_device(locale, device_serial, device_type_dir_name)
292
296
  UI.message("Pulling captured screenshots for locale #{locale} from the device")
293
297
  starting_screenshot_count = screenshot_file_names_in(@config[:output_directory], device_type_dir_name).length
294
298
 
295
299
  UI.verbose("Starting screenshot count is: #{starting_screenshot_count}")
296
300
 
301
+ device_screenshots_paths = [
302
+ determine_external_screenshots_path(device_serial, @config[:app_package_name], [locale]),
303
+ determine_internal_screenshots_paths(device_serial, @config[:app_package_name], [locale])
304
+ ].flatten
305
+
297
306
  # Make a temp directory into which to pull the screenshots before they are moved to their final location.
298
307
  # This makes directory cleanup easier, as the temp directory will be removed when the block completes.
299
308
 
300
309
  Dir.mktmpdir do |tempdir|
301
- device_screenshots_paths.each do |device_path|
302
- if_device_path_exists(@config[:app_package_name], device_serial, device_path) do |path|
310
+ device_screenshots_paths.each do |(device_path, needs_run_as)|
311
+ if_device_path_exists(@config[:app_package_name], device_serial, device_path, needs_run_as) do |path|
312
+ UI.message(path)
303
313
  next unless path.include?(locale)
304
- out = run_adb_command("-s #{device_serial} pull #{path} #{tempdir}",
314
+ out = run_adb_command("-s #{device_serial.shellescape} pull #{path.shellescape} #{tempdir.shellescape}",
305
315
  print_all: false,
306
316
  print_command: true,
307
317
  raise_errors: false)
308
318
  if out =~ /Permission denied/
309
319
  dir = File.dirname(path)
310
320
  base = File.basename(path)
311
- run_adb_command("-s #{device_serial} shell run-as #{@config[:app_package_name]} \"tar -cC #{dir} #{base}\" | tar -xv -f- -C #{tempdir}",
321
+
322
+ # Determine if path needs the run-as permission
323
+ run_as = needs_run_as ? " run-as #{@config[:app_package_name].shellescape.shellescape}" : ""
324
+
325
+ run_adb_command("-s #{device_serial.shellescape} shell#{run_as} \"tar -cC #{dir} #{base}\" | tar -xv -f- -C #{tempdir}",
312
326
  print_all: false,
313
327
  print_command: true)
314
328
  end
@@ -372,8 +386,11 @@ module Screengrab
372
386
 
373
387
  # Some device commands fail if executed against a device path that does not exist, so this helper method
374
388
  # provides a way to conditionally execute a block only if the provided path exists on the device.
375
- def if_device_path_exists(app_package_name, device_serial, device_path)
376
- return if run_adb_command("-s #{device_serial} shell run-as #{app_package_name} ls #{device_path}",
389
+ def if_device_path_exists(app_package_name, device_serial, device_path, needs_run_as)
390
+ # Determine if path needs the run-as permission
391
+ run_as = needs_run_as ? " run-as #{app_package_name.shellescape.shellescape}" : ""
392
+
393
+ return if run_adb_command("-s #{device_serial.shellescape} shell#{run_as} ls #{device_path.shellescape.shellescape}",
377
394
  print_all: false,
378
395
  print_command: false).include?('No such file')
379
396
 
@@ -385,7 +402,7 @@ module Screengrab
385
402
 
386
403
  # Return an array of packages that are installed on the device
387
404
  def installed_packages(device_serial)
388
- packages = run_adb_command("-s #{device_serial} shell pm list packages",
405
+ packages = run_adb_command("-s #{device_serial.shellescape} shell pm list packages",
389
406
  print_all: true,
390
407
  print_command: true)
391
408
  packages.split("\n").map { |package| package.gsub("package:", "") }
@@ -393,7 +410,7 @@ module Screengrab
393
410
 
394
411
  def run_adb_command(command, print_all: false, print_command: false, raise_errors: true)
395
412
  adb_host = @config[:adb_host]
396
- host = adb_host.nil? ? '' : "-H #{adb_host} "
413
+ host = adb_host.nil? ? '' : "-H #{adb_host.shellescape} "
397
414
  output = ''
398
415
  begin
399
416
  errout = nil
@@ -414,36 +431,21 @@ module Screengrab
414
431
  end
415
432
 
416
433
  def device_api_version(device_serial)
417
- run_adb_command("-s #{device_serial} shell getprop ro.build.version.sdk",
434
+ run_adb_command("-s #{device_serial.shellescape} shell getprop ro.build.version.sdk",
418
435
  print_all: true, print_command: true).to_i
419
436
  end
420
437
 
421
- def enable_clean_status_bar(device_serial, app_apk_path)
422
- return unless device_api_version(device_serial) >= 23
423
-
424
- unless @android_env.aapt_path
425
- UI.error("The `aapt` command could not be found, so status bar could not be cleaned. Make sure android_home is configured for screengrab or ANDROID_HOME is set in the environment")
426
- return
427
- end
428
-
429
- # Check if the app wants to use the clean status bar feature
430
- badging_dump = @executor.execute(command: "#{@android_env.aapt_path} dump badging #{app_apk_path}",
431
- print_all: true, print_command: true)
432
- return unless badging_dump.include?('uses-feature: name=\'tools.fastlane.screengrab.cleanstatusbar\'')
438
+ def enable_clean_status_bar(device_serial, sdk_version)
439
+ return unless sdk_version >= 23
433
440
 
434
441
  UI.message('Enabling clean status bar')
435
442
 
436
- # Make sure the app requests the DUMP permission
437
- unless badging_dump.include?('uses-permission: name=\'android.permission.DUMP\'')
438
- UI.user_error!("The clean status bar feature requires the android.permission.DUMP permission but it could not be found in your app APK")
439
- end
440
-
441
443
  # Grant the DUMP permission
442
- run_adb_command("-s #{device_serial} shell pm grant #{@config[:app_package_name]} android.permission.DUMP",
443
- print_all: true, print_command: true)
444
+ run_adb_command("-s #{device_serial.shellescape} shell pm grant #{@config[:app_package_name].shellescape.shellescape} android.permission.DUMP",
445
+ print_all: true, print_command: true, raise_errors: false)
444
446
 
445
447
  # Enable the SystemUI demo mode
446
- run_adb_command("-s #{device_serial} shell settings put global sysui_demo_allowed 1",
448
+ run_adb_command("-s #{device_serial.shellescape} shell settings put global sysui_demo_allowed 1",
447
449
  print_all: true, print_command: true)
448
450
  end
449
451
  end