1# Customise this file, documentation can be found here: 2# https://github.com/KrauseFx/fastlane/tree/master/docs 3fastlane_require 'fileutils' 4fastlane_require 'shellwords' 5 6fastlane_version "2.141.0" 7default_platform :ios 8 9STAGING_API_URL = 'https://staging.exp.host/' 10 11# path relative to Fastfile 12output_directory = File.expand_path('./Deployment') 13 14def update_bundle_versions 15 bundle_short_version = Actions.lane_context[SharedValues::VERSION_NUMBER] 16 bundle_version = bundle_short_version + ".10" + number_of_commits.to_s 17 18 puts "Setting CFBundleVersion for Exponent to #{bundle_version}..." 19 set_info_plist_value( 20 path: "./ios/Exponent/Supporting/Info.plist", 21 key: "CFBundleVersion", 22 value: bundle_version 23 ) 24 25 puts "Setting CFBundleVersion to #{bundle_version} and CFBundleShortVersionString #{bundle_short_version} for ExpoNotificationServiceExtension..." 26 set_info_plist_value( 27 path: "./ios/ExpoNotificationServiceExtension/Info.plist", 28 key: "CFBundleVersion", 29 value: bundle_version 30 ) 31 32 set_info_plist_value( 33 path: "./ios/ExpoNotificationServiceExtension/Info.plist", 34 key: "CFBundleShortVersionString", 35 value: bundle_short_version 36 ) 37end 38 39# This will keep a copy of the original Info.plist 40@original_info_plist = nil 41@original_notification_extension_info_plist = nil 42 43def save_original_info_plists 44 update_info_plist( 45 xcodeproj: "ios/Exponent.xcodeproj", 46 plist_path: "Exponent/Supporting/Info.plist", 47 block: proc do |plist| 48 @original_info_plist = Marshal.load(Marshal.dump(plist)) 49 end 50 ) 51 52 update_info_plist( 53 xcodeproj: "ios/Exponent.xcodeproj", 54 plist_path: "ExpoNotificationServiceExtension/Info.plist", 55 block: proc do |plist| 56 @original_notification_extension_info_plist = Marshal.load(Marshal.dump(plist)) 57 end 58 ) 59end 60 61def restore_original_info_plists 62 update_info_plist( 63 xcodeproj: "ios/Exponent.xcodeproj", 64 plist_path: "Exponent/Supporting/Info.plist", 65 block: proc do |plist| 66 puts "Restoring original Exponent/Info.plist..." 67 plist.replace(@original_info_plist) 68 end 69 ) 70 71 update_info_plist( 72 xcodeproj: "ios/Exponent.xcodeproj", 73 plist_path: "ExpoNotificationServiceExtension/Info.plist", 74 block: proc do |plist| 75 puts "Restoring original ExpoNotificationServiceExtension/Info.plist..." 76 plist.replace(@original_notification_extension_info_plist) 77 end 78 ) 79end 80 81def remove_background_location 82 update_info_plist( 83 xcodeproj: "ios/Exponent.xcodeproj", 84 plist_path: "Exponent/Supporting/Info.plist", 85 block: proc do |plist| 86 puts "Removing background location permission strings and background mode..." 87 88 puts "Deleting NSLocationAlwaysAndWhenInUseUsageDescription key..." 89 plist.delete("NSLocationAlwaysAndWhenInUseUsageDescription") 90 91 puts "Deleting NSLocationAlwaysUsageDescription key..." 92 plist.delete("NSLocationAlwaysUsageDescription") 93 94 puts "Deleting location from UIBackgroundModes..." 95 plist["UIBackgroundModes"].delete("location") 96 end 97 ) 98end 99 100def remove_background_audio 101 update_info_plist( 102 xcodeproj: "ios/Exponent.xcodeproj", 103 plist_path: "Exponent/Supporting/Info.plist", 104 block: proc do |plist| 105 puts "Removing background audio background mode..." 106 plist["UIBackgroundModes"].delete("audio") 107 end 108 ) 109end 110 111def remove_background_notification 112 update_info_plist( 113 xcodeproj: "ios/Exponent.xcodeproj", 114 plist_path: "Exponent/Supporting/Info.plist", 115 block: proc do |plist| 116 puts "Removing remote-notification from UIBackgroundModes..." 117 plist["UIBackgroundModes"].delete("remote-notification") 118 end 119 ) 120end 121 122def configure_for_app_store 123 puts "Configuring app for App Store submission..." 124 remove_background_location 125 remove_background_audio 126 remove_background_notification 127end 128 129platform :ios do 130 131 before_all do 132 FileUtils.mkdir_p(output_directory) 133 Actions.lane_context[SharedValues::VERSION_NUMBER] = get_version_number( 134 xcodeproj: "./ios/Exponent.xcodeproj", 135 target: "Expo Go (versioned)" 136 ) 137 save_original_info_plists 138 update_bundle_versions 139 setup_circle_ci 140 end 141 142 lane :prepare_schemes do |options| 143 recreate_schemes( 144 project: "ios/Pods/#{options[:pod]}.xcodeproj" 145 ) 146 end 147 148 lane :test_module do |options| 149 scan( 150 project: "ios/Pods/#{options[:pod]}.xcodeproj", 151 # This scheme is autogenerated by CocoaPods when a testspec is included in the Podfile 152 scheme: "#{options[:pod]}-Unit-#{options[:testSpecName]}", 153 clean: false, 154 ) 155 end 156 157 lane :unit_tests do |options| 158 workspace = "apps/native-tests/ios/NativeTests.xcworkspace" 159 160 generated_scheme = generate_test_scheme( 161 scheme_name: 'NativeTests', 162 workspace_path: workspace, 163 targets: options[:targets] 164 ) 165 166 run_tests( 167 workspace: workspace, 168 scheme: generated_scheme, 169 devices: ["iPhone 13 Pro Max"], 170 configuration: 'Debug', 171 clean: false, 172 skip_build: true, 173 prelaunch_simulator: true, 174 skip_detect_devices: true, 175 skip_package_dependencies_resolution: true, 176 derived_data_path: "/tmp/ExpoUnitTestsDerivedData", 177 ) 178 end 179 180 lane :test do 181 scan( 182 workspace: "ios/Exponent.xcworkspace", 183 scheme: "Exponent", 184 devices: ["iPhone SE", "iPhone X"], 185 clean: false, 186 ) 187 end 188 189 lane :create_simulator_build do |options| 190 directory = "./ios/simulator-build" 191 puts "Build will be written to: " + File.expand_path(directory) 192 193 flavor = options.fetch(:flavor, "versioned") 194 195 xcbuild( 196 workspace: "ios/Exponent.xcworkspace", 197 scheme: "Expo Go (#{flavor})", 198 sdk: "iphonesimulator", 199 configuration: "Release", 200 derivedDataPath: directory, 201 xcargs: "ARCHS=\"x86_64\" ONLY_ACTIVE_ARCH=NO -quiet", 202 raw_buildlog: is_ci? 203 ) 204 end 205 206 lane :create_expo_client_build do |options| 207 directory = "./ios" + prompt( 208 ci_input: "/../expo-client-build", 209 text: "Please enter the path where we should output the build, relative to ./ios (i.e. ../my-build):", 210 ) 211 puts "Build will be written to: " + File.expand_path(directory) 212 213 flavor = options.fetch(:flavor, "versioned") 214 215 xcbuild( 216 workspace: "ios/Exponent.xcworkspace", 217 scheme: "Expo Go (#{flavor})", 218 configuration: "Release", 219 derivedDataPath: directory, 220 sdk: "iphoneos", 221 destination: "generic/platform=iOS", 222 archive: true, 223 archive_path: directory + "/Exponent.xcarchive", 224 xcargs: "CODE_SIGNING_ALLOWED=NO APP_OWNER=Public -quiet" 225 ) 226 end 227 228 lane :release do |options| 229 cert( 230 team_id: "C8D8QTF339", 231 ) 232 233 sigh( 234 app_identifier: "host.exp.Exponent", 235 output_path: output_directory, 236 filename: "Exponent-distribution.mobileprovision", 237 ) 238 239 xcodebuild_args = { 240 APP_PROVISIONING_PROFILE: Actions.lane_context[Actions::SharedValues::SIGH_UDID], 241 } 242 xcodebuild_args = xcodebuild_args.map do |k,v| 243 "#{k.to_s.shellescape}=#{v.shellescape}" 244 end.join ' ' 245 246 configure_for_app_store 247 248 flavor = options.fetch(:flavor, "versioned") 249 250 gym( 251 workspace: "ios/Exponent.xcworkspace", 252 scheme: "Expo Go (#{flavor})", 253 configuration: "Release", 254 xcargs: xcodebuild_args, 255 clean: true, 256 output_directory: output_directory, 257 output_name: "Exponent.ipa", 258 ) 259 260 deliver( 261 team_id: "17102800", 262 ) 263 end 264 265 after_all do |lane| 266 # FileUtils.rm_rf(output_directory) 267 restore_original_info_plists 268 end 269 270 error do |lane, exception| 271 # slack( 272 # message: exception.message, 273 # success: false 274 # ) 275 end 276 277end 278 279platform :android do 280 281 private_lane :verify_changelog_exists do |version_code: | 282 changelog_path = "android/metadata/en-US/changelogs/#{version_code}.txt" 283 UI.user_error!("Missing changelog file at #{changelog_path}") unless File.exist?(changelog_path) 284 UI.message("Changelog exists for version code #{version_code}") 285 end 286 287 private_lane :verify_upload_to_staging do |version_name: | 288 UI.message "Skipping staging verification step" 289 # require 'open-uri' 290 # staging_version = nil 291 # begin 292 # versions = JSON.parse(open(URI.join(STAGING_API_URL, "/--/api/v2/versions")).read) 293 # latest_major_version = versions['sdkVersions'].keys.map(&:to_i).sort().reverse().first() 294 # latest_version = versions['sdkVersions']["#{latest_major_version}.0.0"] 295 # staging_version = latest_version['androidClientVersion'] 296 # rescue StandardError => e 297 # UI.user_error!("Unable to validate androidClientVersion for latest SDK version on versions endpoint: #{e.inspect}. If this issue persists, remove the verify_upload_to_staging step from Fastfile and manually verify that the Android client has been deployed and tested on staging.") 298 # end 299 300 # unless staging_version == version_name 301 # UI.user_error!("APK version #{version_name} is not yet uploaded to staging. Please download from the client_android CI job, test and upload manually.") 302 # end 303 # UI.message "APK version #{version_name} has been uploaded to staging" 304 end 305 306 lane :start do |flavor: "unversioned"| 307 gradle( 308 project_dir: "android", 309 task: "install", 310 build_type: "Debug", 311 flavor: flavor, 312 ) 313 adb(command: "shell am start -n host.exp.exponent/host.exp.exponent.LauncherActivity") 314 end 315 316 lane :build do |build_type: "Debug", flavor: "versioned", sign: true, aab: false| 317 ENV['ANDROID_UNSIGNED'] = '1' unless sign 318 gradle( 319 project_dir: "android", 320 task: aab ? "app:bundle": "app:assemble", 321 flavor: flavor, 322 build_type: build_type, 323 ) 324 end 325 326 lane :prod_release do 327 build_gradle = File.read("../android/app/build.gradle") 328 329 verify_changelog_exists(version_code: build_gradle.match(/versionCode (\d+)/)[1]) 330 verify_upload_to_staging(version_name: build_gradle.match(/versionName '([\d\.]+)'/)[1]) 331 332 supply( 333 package_name: "host.exp.exponent", 334 metadata_path: "./fastlane/android/metadata", 335 aab: "./android/app/build/outputs/bundle/versionedRelease/app-versioned-release.aab", 336 track: "production", 337 skip_upload_images: true, 338 skip_upload_screenshots: true 339 ) 340 end 341 342end 343