Categories
iOS Swift Xcode

Getting started with device framed screenshots for iOS App Store using fastlane

Creating screenshots manually for App Store is time consuming because of the number of devices and localisations. Moreover, as soon as UI changes we would need to update screenshots again. Therefore, it is best to automate the process. One way is to use fastlane and creating nice device framed screenshots with additional localised text. This time we’ll see how to add fastlane to existing project, setting up UI-testing target, scheme for App Store screenshot tests, and framing screenshots with additional text.

End result of a framed screenshot with additional text.

Installing required tools

First step is installing fastlane and as frameit command requires imagemagick, let’s install it now as well. When using homebrew installation goes as: brew install fastlane imagemagick.

Adding UI-testing target

Fastlane uses UI-tests for displaying views and then capturing screenshots. If project does not have UI-testing target set up, then this is the first step. In Xcode, open add target view (File > New > Target), choose UI-Testing Bundle and add it to the project. In our case the testing target’s name is FastlaneAppStoreScreenshotsUITests.

Support files for capturing screenshots

First thing we’ll do with fastlane is running the fastlane snapshot init command in the project folder. It will generate 2 files: Snapfile and SnapshotHelper.swift. First one contains configuration for snapshot command: devices, locales etc. Helper file we’ll move to UI-testing target: first drag it to testing target folder (FastlaneAppStoreScreenshotsUITests) and then to Xcode’s file navigator. Make sure to add it to the UI-testing target. Create subfolder named fastlane and move Snapfile to there. We’ll modify it a little bit later.

Project structure after adding UI-testing target and supporting SnapshotHelper.swift

Adding UI-test case for screenshots

We are going to define tests generating App Store screenshots in a separate XCTestCase. In Xcode, add a new UI-test case class (File > New File > UI-Test Case Class) and name it to AppStoreScreenshotUITests.

Best is when it is possible to record a UI-test which does not need any special configuration: launch the app, tap here and there, take a screeshot. In more complicated apps, we need to use launch arguments and configuring the app when it launches based on the launch arguments. In document based apps it might be needed to bundle example files in the app and then using launch arguments for choosing the file to open when running the test.

Firstly, let’s add 3 UI-tests which will cover 3 different views and calling the function snapshot(“file_name”) which is part of the SnapshotHelper.swift and handles creating screenshots and storing them in the folder specified by Snapfile.

final class AppStoreScreenshotUITests: XCTestCase {
    private var app: XCUIApplication!
    
    override func setUpWithError() throws {
        continueAfterFailure = false
        app = XCUIApplication()
        // Example of passing in launch arguments which can be read in the app
        // by calling CommandLine.arguments.contains("--uitesting")
        // app.launchArguments.append("--uitesting")
        setupSnapshot(app)
        app.launch()
    }

    override func tearDownWithError() throws {
        app = nil
    }

    func testScreenshot1() throws {
        snapshot("1-mainview")
    }
    
    func testScreenshot2() throws {
        XCTAssertTrue(app.buttons["Button1"].waitForExistence(timeout: 10))
        app.buttons["Button1"].tap()
        snapshot("2-sheet1")
    }
    
    func testScreenshot3() throws {
        XCTAssertTrue(app.buttons["Button2"].waitForExistence(timeout: 10))
        app.buttons["Button2"].tap()
        snapshot("3-sheet2")
    }
}

Separate scheme for App Store screenshots

UI-tests are set up for App Store screenshots, next is to add a separate scheme and adding those tests to the Test action. This scheme is the one fastlane is going to use for running tests.

For adding a new scheme, open manage schemes view (Product > Scheme > Manage Schemes). Click on the + button, select the app target and name it to AppStoreScreenshots.

AppStoreScreenshots scheme in Manage Scheme view.

After that, select the scheme and click on the Edit, open Test action and select only App Store tests. Also make sure the Shared checkbox is selected for allowing fastlane to run it.

Selecting tests in Test action for AppStoreScreenshots schemes.

Configuring Snapfile

Snapfile contains configuration for the snapshot command. There we define all the devices, locales, scheme name, location where to store generated screenshots etc. For getting started, we can start with one locale and two devices. We also need to select the scheme we added before.

devices([
   "iPhone X",
   "iPhone 11 Pro Max"
])
languages([
  "en-US",
])
scheme("AppStoreScreenshots")
output_directory("./AppStoreScreenshots")
clear_previous_screenshots(true)

Configuring Fastfile

App Store screen generation contains of two main steps: capturing screenshots and framing those. Fastfile allows us to create custom commands, lanes, and it is useful of adding one for app store screenshots. Create a file named Fastfile and add it to previously created Fastlane folder.

default_platform(:ios)

platform :ios do
  desc 'Generate App Store screenshots'
  lane :app_store_screenshots do
    capture_screenshots(
      clean: true
    )
    frame_screenshots
  end
end

Running fastlane app_store_screenshots will then generate screenshots and create framed versions as well. If you run it now, you’ll get screenshots with and without device frames.

Adding titles and keyword to framed screenshots

Now we have nice framed screenshots, only what is missing is adding some text to all the screenshots. If we ran fastlane app_store_screenshots in the previous step we can see that AppStoreScreenshots folder has appeared and taken screenshots are in the en-US folder. Adding text and background to each of the screenshot requires a couple of steps.

First we’ll create Framefile.json file in the AppStoreScreenshots folder which contains of configuration for frameit.

{
	"device_frame_version": "latest",
	"default": {
		"keyword": {
			"font": "./Fonts/SF-Pro-Display-Medium.otf",
			"color": "#FFFFFF"
		},
		"title": {
			"font": "./Fonts/SF-Pro-Display-Medium.otf",
			"color": "#FFFFFF"
		},
		"padding": 50,
		"show_complete_frame": false,
		"stack_title": true,
		"use_platform": "IOS"
	},
	"data": [ 
		{
			"filter": "mainview",
			"background": "./AppStoreBackgroundPortrait1.jpg"
		},
		{
			"filter": "sheet1",
			"background": "./AppStoreBackgroundPortrait2.jpg"
		},
		{
			"filter": "sheet2",
			"background": "./AppStoreBackgroundPortrait3.jpg"
		}
	]
}

Default dictionary contains shared settings for every frame operation. We can customise by adding data array which contains screenshot specific configuration (more). Filter in data dictionaries are used for matching the configuration to screenshot files (filenames used in UI-tests). In this example we have different backgrounds for every screenshot (background files are in the same AppStoreScreenshots folder). Fonts are configured by adding a path to Framefile.json and storing fonts in a subfolder.

Localised titles and keywords are handled with strings files. We’ll need to add title.strings and keyword.strings to the locale folder, in our case, en-US. Keys in strings files work the same way as filters in Framefile.json, therefore partial match with filename works. Example strings file for title.strings is shown here:

"mainview" = "Title1";
"sheet1" = "Title2";
"sheet2" = "Title3";

I suggest creating strings files with Xcode making sure the file encoding is correct. If we run the fastlane app_store_screenshots command again, we’ll get nice framed screenshots with additional text.

Summary

Automating App Store screenshots with fastlane is not difficult to set up. The most difficult part in this process is writing UI-tests and providing proper data in the app which is highly app specific.

If this was helpful, please let me know on Mastodon@toomasvahter or Twitter @toomasvahter. Feel free to subscribe to RSS feed. Thank you for reading.

Example project

FastlaneAppStoreScreenshots (Xcode 11.4)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s