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 xcargs: 'CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO', 178 ) 179 end 180 181 lane :test do 182 scan( 183 workspace: "ios/Exponent.xcworkspace", 184 scheme: "Exponent", 185 devices: ["iPhone SE", "iPhone X"], 186 clean: false, 187 ) 188 end 189 190 lane :create_simulator_build do |options| 191 directory = "./ios/simulator-build" 192 puts "Build will be written to: " + File.expand_path(directory) 193 194 flavor = options.fetch(:flavor, "versioned") 195 196 xcbuild( 197 workspace: "ios/Exponent.xcworkspace", 198 scheme: "Expo Go (#{flavor})", 199 sdk: "iphonesimulator", 200 configuration: "Release", 201 derivedDataPath: directory, 202 xcargs: "ARCHS=\"x86_64\" ONLY_ACTIVE_ARCH=NO -quiet", 203 raw_buildlog: is_ci? 204 ) 205 end 206 207 lane :create_expo_client_build do |options| 208 directory = "./ios" + prompt( 209 ci_input: "/../expo-client-build", 210 text: "Please enter the path where we should output the build, relative to ./ios (i.e. ../my-build):", 211 ) 212 puts "Build will be written to: " + File.expand_path(directory) 213 214 flavor = options.fetch(:flavor, "versioned") 215 216 xcbuild( 217 workspace: "ios/Exponent.xcworkspace", 218 scheme: "Expo Go (#{flavor})", 219 configuration: "Release", 220 derivedDataPath: directory, 221 sdk: "iphoneos", 222 destination: "generic/platform=iOS", 223 archive: true, 224 archive_path: directory + "/Exponent.xcarchive", 225 xcargs: "CODE_SIGNING_ALLOWED=NO APP_OWNER=Public -quiet" 226 ) 227 end 228 229 lane :release do |options| 230 cert( 231 team_id: "C8D8QTF339", 232 ) 233 234 sigh( 235 app_identifier: "host.exp.Exponent", 236 output_path: output_directory, 237 filename: "Exponent-distribution.mobileprovision", 238 ) 239 240 xcodebuild_args = { 241 APP_PROVISIONING_PROFILE: Actions.lane_context[Actions::SharedValues::SIGH_UDID], 242 } 243 xcodebuild_args = xcodebuild_args.map do |k,v| 244 "#{k.to_s.shellescape}=#{v.shellescape}" 245 end.join ' ' 246 247 configure_for_app_store 248 249 flavor = options.fetch(:flavor, "versioned") 250 251 gym( 252 workspace: "ios/Exponent.xcworkspace", 253 scheme: "Expo Go (#{flavor})", 254 configuration: "Release", 255 xcargs: xcodebuild_args, 256 clean: true, 257 output_directory: output_directory, 258 output_name: "Exponent.ipa", 259 ) 260 261 deliver( 262 team_id: "17102800", 263 ) 264 end 265 266 after_all do |lane| 267 # FileUtils.rm_rf(output_directory) 268 restore_original_info_plists 269 end 270 271 error do |lane, exception| 272 # slack( 273 # message: exception.message, 274 # success: false 275 # ) 276 end 277 278end 279 280platform :android do 281 282 private_lane :verify_changelog_exists do |version_code: | 283 changelog_path = "android/metadata/en-US/changelogs/#{version_code}.txt" 284 UI.user_error!("Missing changelog file at #{changelog_path}") unless File.exist?(changelog_path) 285 UI.message("Changelog exists for version code #{version_code}") 286 end 287 288 private_lane :verify_upload_to_staging do |version_name: | 289 UI.message "Skipping staging verification step" 290 # require 'open-uri' 291 # staging_version = nil 292 # begin 293 # versions = JSON.parse(open(URI.join(STAGING_API_URL, "/--/api/v2/versions")).read) 294 # latest_major_version = versions['sdkVersions'].keys.map(&:to_i).sort().reverse().first() 295 # latest_version = versions['sdkVersions']["#{latest_major_version}.0.0"] 296 # staging_version = latest_version['androidClientVersion'] 297 # rescue StandardError => e 298 # 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.") 299 # end 300 301 # unless staging_version == version_name 302 # 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.") 303 # end 304 # UI.message "APK version #{version_name} has been uploaded to staging" 305 end 306 307 lane :start do |flavor: "unversioned"| 308 gradle( 309 project_dir: "android", 310 task: "install", 311 build_type: "Debug", 312 flavor: flavor, 313 ) 314 adb(command: "shell am start -n host.exp.exponent/host.exp.exponent.LauncherActivity") 315 end 316 317 lane :build do |build_type: "Debug", flavor: "versioned", sign: true, aab: false| 318 ENV['ANDROID_UNSIGNED'] = '1' unless sign 319 gradle( 320 project_dir: "android", 321 task: aab ? "app:bundle": "app:assemble", 322 flavor: flavor, 323 build_type: build_type, 324 ) 325 end 326 327 lane :prod_release do 328 build_gradle = File.read("../android/app/build.gradle") 329 330 verify_changelog_exists(version_code: build_gradle.match(/versionCode (\d+)/)[1]) 331 verify_upload_to_staging(version_name: build_gradle.match(/versionName '([\d\.]+)'/)[1]) 332 333 supply( 334 package_name: "host.exp.exponent", 335 metadata_path: "./fastlane/android/metadata", 336 aab: "./android/app/build/outputs/bundle/versionedRelease/app-versioned-release.aab", 337 track: "production", 338 skip_upload_images: true, 339 skip_upload_screenshots: true 340 ) 341 end 342 343end 344