Automate Screenshots for App Store Using Fastlane

Save yourself from spending hours on screenshots for the App Store. Here's a step-by-step guide on how you automate the process of taking screenshots for all supported screen sizes and languages.

Written by 

In my last post, I shared with you the source code for an app called QCards that I released on the App Store. The screenshots that went on the App Store were all generated using Fastlane. In this post, we'll go over how I went about generating them.

Here's why you shouldn't create screenshots for the App Store manually. Imagine your want four different screenshots to preview you app. But you also support four different languages. And not to mention, you support both iPhone and iPad which is three screen sizes in total (iPhone 5.5", 6.5" and iPad Pro).

4 previews x 4 languages x 3 screen sizes = 48 screenshots 😱

And get ready to repeat the process each time you change the layout of the app. So let's instead automate this.

Initializing Fastlane

The first thing you need to do is to install Fastlane if you haven't already. Open your terminal and run this command: sudo gem install fastlane -NV.

Next up, navigate to the directory of your project. From here, you want to run fastlane snapshot init which will create two files, Snapfile and SnapshotHelper.swift, for you.

Create a new folder in the root of your project folder. Call it "fastlane" and move Snapfile into the folder.

UI Test Target

What you want to do now is to add a UI Testing Bundle target to your project.

Give the target a name. You could call it "FastlaneSnapshot".

Now, you need to move the SnapshotHelper.swift file to this newly created target. Make sure to update the target membership of this file to FastlaneSnapshot.

UI Test Scheme

Add a new scheme called "FastlaneSnapshot". Make sure to select the UI Test target here. 

Once you've done that, go to Edit Scheme -> Build. Make sure to give it the following settings:

Also, make sure to check off the Shared option.

Update Snapfile

Open up the Snapfile and update it to your needs, including the scheme to "FastlaneSnapshot". Here's how it could look:

# Uncomment the lines below you want to change by removing the # in the beginning

# A list of devices you want to take the screenshots from
devices([
  "iPhone 11 Pro Max",
  "iPhone 8 Plus",
  "iPad Pro (12.9-inch) (3rd generation)"
])

languages([
  "en-US"
])

# The name of the scheme which contains the UI Tests
scheme("FastlaneSnapshot")

# Where should the resulting screenshots be stored?
output_directory("./fastlane/screenshots")

# remove the '#' to clear all previously generated screenshots before creating new ones
clear_previous_screenshots(true)

# Arguments to pass to the app on launch. See https://docs.fastlane.tools/actions/snapshot/#launch-arguments
# launch_arguments(["-favColor red"])

# For more information about all available options run
# fastlane action snapshot

Now we are set up and ready to take the actual screenshots of the app.

Take the screenshots

What you need to do is write UI tests that navigate through the screens you want to capture. I won't go over how this works in this post, but it's not too difficult to figure out. Make sure to check out the code from my QCards app here for inspiration.

The entry point for Fastlane is a test function called testGenerateScreenshots that you need to provide. From here, you can navigate your app as you like. I usually split navigation between my screens up in several functions that I call from testGenerateScreenshots to keep it slim and readable.

What's provided by the SnapshotHelper.swift file is a function func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20). You call this throughout your UI tests, whenever you want to capture a screenshot. It could look something like snapshot("LoginScreen").

Here's an example of the snapshot function in action:

import XCTest

let deckTitle = "My presentation" 
let cardTitle = "First topic" 
let cardContent = "Here are some very important points"

class FastlaneSnapshot: XCTestCase {
    
    override func setUp() {
        super.setUp()
        
        continueAfterFailure = false
        
        let app = XCUIApplication()
        setupSnapshot(app)
        app.launch()
    }
    
    func testGenerateScreenshots() {
        let app = XCUIApplication()
        
        app.navigationBars["QCards"].buttons["createDeckButton"].tap()
        
        let deckTitleField = app.textFields["deckTitleTextField"]
        deckTitleField.tap()
        deckTitleField.typeText(deckTitle)
        
        app.buttons["addButton"].tap()
        
        snapshot("AllDecks")
        
        createCard()
    }

    func createCard() {
        app.tables.staticTexts[deckTitle].tap()
        app.navigationBars[deckTitle].buttons["addButton"].tap()

        let cardTitleTextField = app.textFields["cardTitleTextField"]
        cardTitleTextField.tap()
        cardTitleTextField.typeText(cardTitle)

        let cardContentTextView = app.textViews["cardContentTextView"]
        cardContentTextView.tap()
        cardContentTextView.typeText(cardContent)

        snapshot("CreateCard")
    }
}

Running the tests won't capture the screenshots. What you need to do is to open your terminal, navigate to the fastlane folder inside your project and run fastlane snapshot. This will create a screenshots folder inside the fastlane folder, containing all of your captured screenshots.

Conclusion

That was it! A great way to automate a tedious task that would otherwise cost you several hours now and each time you change your layout of your app. It doesn't take long to setup and grab the screenshots you need, so there’s no reason to hold back!

In the next post, we'll go over how you automate framing you screenshots, adding a background and localized texts.

If you haven't done so already, check out the source code for the QCards app on GitHub.

Share this post

Facebook
Twitter
LinkedIn
Reddit

You may also like

Automation

iOS Continuous Integration Using Travis CI and Fastlane

Continuous Integration (CI) is a powerful practice to keep any app in a stable state throughout its development. Here’s how you set up CI for iOS apps to automatically perform code validation and testing whenever your code changes.

DevOps

3 EAS Pipelines for Deploying React Native Apps in Teams

One of the best ways to increase productivity in a react native project is to automate the process of deploying builds you want to share internally in your team or with actual costumers via the app store. And you might be surprised at how easy it can actually be implemented when you have the right set of tools like GitHub Actions and EAS.