Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Deploy mobile apps with fastlane

Deploy mobile apps with fastlane


Alessandro Calzavara

September 27, 2017



  2. Agenda • What is fastlane • Why we use it

    • How we use it 2
  3. 3

  4. It’s a set of command line tools that helps us

    automating tasks fastlane
  5. Tools are highly specialized produce: create an iOS/macOS app into

    Apple Developer portal scan: run unit and UI tests snapshot: take screenshots of an iOS app deliver: upload iOS app, metadata and images into iTunes Connect (AppStore backend) and more
  6. Simpler tools: actions hockey: upload iOS/Android apps to HockeyApp website

    for internal (ad-hoc) deploy slack: post a notification on Slack backup_xcarchive: zip an .xcarchive file and place it somewhere else framer: take device screenshots and wrap them inside a template, adding also text and more, local and external
  7. fastlane glues everything together Defines a sequence of tools to

    execute, one after another The result of each tool is passed to the next ones, via shared context Supports .env files Create your own tools or run any shell command
  8. How to start [sudo] gem install fastlane cd ~/my-app fastlane

    init How to run cd ~/my-app fastlane my_fancy_lane
  9. DEMO VIDEO fastlane init 9

  10. 10 Fastfile content

  11. Why we use it? Some of these tools are amazing!

    It’s extendable and customizable (custom tools and actions) It allows to well define our procedures (less manual work, more shared knowledge) Everything is stored inside the app repository, with the actual code CI is well integrated (running tests on Jenkins)
  12. Add a user device for iOS development and internal testing

    12 How we use it?
  13. desc "Add development device and re-generate provisionig profiles" lane :add_device

    do device_owner = UI.input("Device owner (ex: Spreaker Sandro, TargetSpot someone): ") device_type = UI.input("Device type (ex: iPhone 7, iPad Mini 4, Apple Watch): ") device_uuid = UI.input("Device UUID: ") unless UI.confirm("Are entered information correct?") UI.error("Please enter information again.") end device_name = "#{device_owner} #{device_type}" register_devices( username: ENV['FASTLANE_USERNAME'], devices: { device_name => device_uuid } ) # Update all profiles recreate_provisionig_profiles end 1/3
  14. private_lane :recreate_provisionig_profiles do prod = { name: 'Prod', app_identifier: 'com.spreaker.Spreaker'

    } dev = { name: 'Dev', app_identifier: 'com.spreaker.Spreaker.dev' } beta = { name: 'Beta', app_identifier: 'com.spreaker.SpreakerTest' } # Development UI.message "Generating DEVELOPMENT profiles".green [prod, dev, beta].each do |profile| app_id = profile[:app_identifier] profile_name = "SpreakerRadio #{profile[:name]} Development" profile_file = "Certificates/development/#{profile_name.tr(" ", "_")}.mobileprovision" sigh( username: ENV['FASTLANE_USERNAME'], force: true, # to add new device development: true, app_identifier: app_id, provisioning_name: profile_name, filename: profile_file ) end [...] 2/3
  15. [...] # Ad Hoc UI.message "Generating AD HOC DISTRIBUTION profiles".green

    [dev, beta].each do |profile| app_id = profile[:app_identifier] profile_name = "SpreakerRadio #{profile[:name]} AdHoc Distribution" profile_file = "Certificates/distribution/#{profile_name.tr(" ", "_")}.mobileprovision" sigh( username: ENV['FASTLANE_USERNAME'], force: true, # to add new device adhoc: true, app_identifier: app_id, provisioning_name: profile_name, filename: profile_file ) end # Done UI.important "Job done!" end 3/3
  16. Take screenshots of the IOS Radio app 16 How we

    use it?
  17. desc "Take screenshots of the app" lane :take_screenshots do #

    Capture screens snapshot( skip_open_summary: true ) # Frame them framer end
  18. DEMO VIDEO fastlane take_screenshots 18

  19. 19

  20. Deploy iOS Radio app to the AppStore 20 How we

    use it?
  21. desc "Build and deploy app on AppStore" lane :deploy_appstore do

    |options| # Check ENV [...] # If no option is passed, prompt for them unless options.has_key?(:metadata) || options.has_key?(:screenshots) || options.has_key?(:ipa) tasks = ["ipa only", "metadata and ipa", "metadata, screenshots and ipa"] selected_task = UI.select("What do you want to deploy?", tasks) hint = "" case tasks.index(selected_task) when 0 options[:ipa] = true hint = "ipa:true" when 1 options[:ipa] = true; options[:metadata] = true hint = "ipa:true metadata:true" when 2 options[:ipa] = true; options[:metadata] = true; options[:screenshots] = true hint = "ipa:true metadata:true screenshots:true" end # Print hint for next time UI.important "Hint: next time try `fastlane deploy_appstore #{hint}`" end [...] 1/5
  22. [...] # Ensure no uncommitted file are still here ensure_git_status_clean

    # Upload metadata if options[:metadata] upload_metadata end # Upload screenshots if options[:screenshots] upload_screenshots end # Upload ipa to iTC if options[:ipa] [...] end end 2/5
  23. # Upload ipa to iTC if options[:ipa] # Build build_ipa(environment:

    'prod') # Upload and put build in "waiting for review" state upload_ipa_appstore(submit: true) # Notify on Slack slack({ message: "*Radio iOS #{ENV['APP_MARKETING_VERSION']}* has been uploaded and it's waiting for review ", success: true, username: "#{ENV['SLACK_USERNAME']} (fastlane)", channel: '#releases', payload: { 'CHANGELOG' => "```" + File.read("./metadata/whatsnew-en.txt") + "```" }, default_payloads: [], # No default payload }) end 3/5
  24. desc "Upload ipa (PROD) to AppStore, BTSync and HockeyApp" private_lane

    :upload_ipa_appstore do |options| # Check ENV [...] # Ensure correct value of option submit = options[:submit] || false # Upload build to iTunesConnect deliver( skip_metadata: true, skip_screenshots: true, submit_for_review: submit ) # Save zipped archive to BTSync folder backup_xcarchive( destination: "#{ENV['BTSYNC_FOLDER']}/iOS Radio", zip: true ) [...] 4/5
  25. [...] # Send dSYM to HockeyApp upload_ipa_hockeyapp( environment: 'prod', notes:

    "New build available in AppStore for everyone." ) # Notify on Slack slack({ message: "Uploaded Radio iOS (PROD) app #{ENV['APP_MARKETING_VERSION']} to AppStore", success: true, channel: '#dev-bot', username: "#{ENV['SLACK_USERNAME']} (fastlane)", payload: { 'iTunes Connect link' => itc_uri }, default_payloads: [], # No default payload }) # Reminder UI.important "Did you remember to tag the repo? `sh tag-release.sh`" end 5/5
  26. DEMO VIDEO fastlane upload_metadata 26

  27. That’s all guys! Thanks for listening!

  28. Links fastlane website https://fastlane.tools/ github repo https://github.com/fastlane/fastlane official docs https://docs.fastlane.tools/

    framer: our plugin for processing screenshots github repo https://github.com/spreaker/fastlane-framer-plugin