Runar Ovesen Hjerpbakk

Science-based software development

Xnapshot

Xnapshot - automated, localised screenshots of your iOS app on every device using C#.

Taking screenshots of your app on every device and localisation quickly becomes time consuming. With two languages, four different iPhones and five screenshots you are faced with forty screenshots per release. If we increase the number of languages to 10 and add iPad support, this number explodes to 10 (languages) x 7 (devices) x 5 (screenshots) = 350 screenshots!

Xnapshot enables you to use C#, together with Xamarin.UITest, to automatically take the screenshots for you. Just derive from the abstract Screenshots class, implement one method per screenshot and use your time productively while your computer takes the screenshots.

PM> Install-Package Xnapshot

tl;dr

  • Create an awesome iOS app using C# and Xamarin.
  • Add the Xamarin.TestCloud.Agent nuget package to your iOS project and update your AppDelegate class to enable Calabash while running in debug mode.
public override void FinishedLaunching(UIApplication application) {
  #if DEBUG
    Xamarin.Calabash.Start();
  #endif

  • Add a new Console project to your solution and add the Xnapshot nuget package.
  • Create a new class, AppNameScreenshots and derive from the abstract Xnapshot.Screenshots class.
  • Add your preferred device type, iOS version, screenshots folder and path to your App bundle as constructor arguments. See Usage below for allowed values.
public class GoldenRatioScreenshots : Screenshots {
  public GoldenRatioScreenshots() : base(
    DeviceType.iPhone,
    "iOS-9-2", 
    "/Users/sankra/Projects/GoldenRatioCalculator/screenshots/en-US", 
    "/Users/sankra/Projects/GoldenRatioCalculator/iOS/bin/iPhoneSimulator/Debug/GoldenRatioCalculatoriOS.app") {
  }
}
  • It’s now time to implement the SetAppStateForScreenshotX methods. Use Xamarin.UITest to automate your app, putting it in the correct state before each screenshot. The examples below are from my Golden Ratio Calculator app. SetAppStateForScreenshot1 is empty because the first screenshot is of the first screen.
protected override void SetAppStateForScreenshot1() {
}

protected override void SetAppStateForScreenshot2() {
  App.Tap(c => c.Marked("ratioPicker"));
  App.Tap(v => v.Text("Silver Ratio"));
  App.Tap(c => c.Marked("Done"));
}

protected override void SetAppStateForScreenshot3() {
  App.Tap(c => c.Marked("ratioPicker"));
  App.Tap(v => v.Text("Bronze Ratio"));
  App.Tap(c => c.Marked("Done"));
}

protected override void SetAppStateForScreenshot4() {
  App.Tap(c => c.Marked("ratioPicker"));
  App.Tap(v => v.Text("Yamato Ratio"));
  App.Tap(c => c.Marked("Done"));
  App.Tap(c => c.Marked("rotateButton"));
}

protected override void SetAppStateForScreenshot5() {
  App.Tap(c => c.Marked("Cog.png"));
}
  • Call the TakeScreenshots() method of your class and run your console app to take the screenshots.
public static void Main(string[] args) {
  var screenshots = new GoldenRatioScreenshots();
  screenshots.TakeScreenshots();

  Environment.Exit(0);
}

The screenshots look like this after this example app has run:

example_screenshots_small

And the screenshots folder contains screenshots for all configured devices:

example_screenshots_folder

Usage

Advanced Options

Xnapshot.Screenshots has a couple of advanced options that can be set in your AppNameScreenshots constructor.

OptimizeImagesAfterSave

Set to false as default. Set this to true if you want to run ImageOptim on every screenshot after save. ImageOptim must be installed in your Applications folder and will losslessly decrease the file size of the screenshots.

SaveScreenshots

Set to true as default. Set this to false if you want to do a dry run, testing your SetAppStateForScreenshotX methods without actually taking screenshots. The methods will be run in the same order, the only difference being that nothing is saved.