{"id":21857534,"url":"https://github.com/hjerpbakk/xnapshot","last_synced_at":"2025-08-19T20:10:31.045Z","repository":{"id":144135190,"uuid":"49326157","full_name":"hjerpbakk/Xnapshot","owner":"hjerpbakk","description":"Automated, localized screenshots of your iOS app on every device using C#.","archived":false,"fork":false,"pushed_at":"2019-07-10T20:28:36.000Z","size":184,"stargazers_count":14,"open_issues_count":14,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-28T06:51:16.142Z","etag":null,"topics":["automation","dotnet","imageoptim","ios","localization","nuget","screenshot","xamarin","xamarin-uitest","xnapshot"],"latest_commit_sha":null,"homepage":"https://hjerpbakk.com/blog/2019/07/10/xnapshot","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hjerpbakk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-01-09T13:54:24.000Z","updated_at":"2022-03-27T19:36:49.000Z","dependencies_parsed_at":"2023-11-29T15:20:28.679Z","dependency_job_id":"ab79052f-4767-41d2-8a36-d85fc75cb9a6","html_url":"https://github.com/hjerpbakk/Xnapshot","commit_stats":null,"previous_names":["hjerpbakk/xnapshot","sankra/xnapshot"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjerpbakk%2FXnapshot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjerpbakk%2FXnapshot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjerpbakk%2FXnapshot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hjerpbakk%2FXnapshot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hjerpbakk","download_url":"https://codeload.github.com/hjerpbakk/Xnapshot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248936626,"owners_count":21186066,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","dotnet","imageoptim","ios","localization","nuget","screenshot","xamarin","xamarin-uitest","xnapshot"],"created_at":"2024-11-28T02:29:31.197Z","updated_at":"2025-04-14T18:31:24.791Z","avatar_url":"https://github.com/hjerpbakk.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Xnapshot\n\n[![Build status](https://ci.appveyor.com/api/projects/status/tkls3ydfbu9lcmqu?svg=true)](https://ci.appveyor.com/project/Sankra/xnapshot) [![Latest version](https://img.shields.io/nuget/v/Xnapshot.svg)](https://www.nuget.org/packages/Xnapshot/) [![Downloads from NuGet](https://img.shields.io/nuget/dt/Xnapshot.svg)](https://www.nuget.org/packages/Xnapshot/)\n\nTaking screenshots of your app on every device and localization quickly becomes time-consuming. With 2 languages, 6 different iPhones and 10 screenshots, you are faced with 120 screenshots per release. If we increase the number of languages to 10 and add iPad support, this number explodes to 10 (languages) x 11 (devices) x 10 (screenshots) = **1 100 screenshots**!\n\n[Xnapshot](https://hjerpbakk.com/blog/2019/07/10/xnapshot) enables you to use C#, together with Xamarin.UITest, to automatically take the screenshots for you. Just derive from the abstract [Screenshots](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot/Screenshots.cs#L49) class, implement one method per screenshot and use your time productively while your computer takes the screenshots.\n\nSee Xnapshot in action in the video below:\n\n[![See Xnapshot in action](https://hjerpbakk.com/img/Xnapshot/xnapshot-youtube.png)](https://www.youtube.com/watch?v=cAVcWUZBLSo)\n\n## Complete working example\n\nDownload this repository, open the solution in Visual Studio for Mac and run [Xnapshot.Example.Usage](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot.Example.Usage/Program.cs) to see a working example. The solution contains the Xnapshot source, an iOS app to be screenshotted and the configuration of Xnapshot needed to actually take screenshots.\n\n## Usage\n\n### Prerequisites\n\n- Create your [awesome iOS app](https://itunes.apple.com/no/app/id953899091?at=11l5UV\u0026ct=website) using C# and Xamarin.\n- Add the [Xamarin.TestCloud.Agent](https://www.nuget.org/packages/Xamarin.TestCloud.Agent/) NuGet package to your iOS project and update your `AppDelegate` class to enable [Calabash](https://github.com/calabash), the remote control for your app, while running in debug mode.\n\n```cs\npublic override void FinishedLaunching(UIApplication application) {\n  #if DEBUG\n    Xamarin.Calabash.Start();\n  #endif\n  // Rest of method omitted for brevity\n}\n```\n\n### Configuration\n\nI use the settings for one of my own apps, [Golden Ratio Calculator](https://itunes.apple.com/no/app/id953899091?at=11l5UV\u0026ct=website), to illustrate the usage of Xnapshot.\n\n- Add a new .Net Framework `Console project` to your solution and add the [Xnapshot](https://www.nuget.org/packages/Xnapshot/) NuGet package. I name such projects `[AppName].Screens`. The project must a .Net Framework project, version 4.5 or newer. .Net Core is not supported as Xamarin.UITests, which is needed to automate the before each screenshot, does not support .Net Core.\n- Create a new class, `[AppName]Screenshots` and derive from the abstract [Xnapshot.Screenshots](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot/Screenshots.cs#L49) class.\n- Add your iOS version, screenshots folder, the path to your App bundle and devices you wish to screenshot as constructor arguments. The devices listed below covers all iPhone screen sizes of the time of writing.\n\n```cs\npublic class GoldenRatioScreenshots : Screenshots {\n  public GoldenRatioScreenshots() : base(\n    \"iOS-12-2\",\n    \"/Users/sankra/Projects/GoldenRatioCalculator/screenshots/en-US\",\n    \"/Users/sankra/Projects/GoldenRatioCalculator/iOS/bin/iPhoneSimulator/Debug/GoldenRatioCalculatoriOS.app\",\n    new[] {\n      \"iPhone-XS-Max\",\n      \"iPhone-XS\",\n      \"iPhone-XR\",\n      \"iPhone-8-Plus\",\n      \"iPhone-8\",\n      \"iPhone-SE\"\n    }) {\n  }\n}\n```\n\n- It’s now time to implement the [SetAppStateForScreenshotX](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot/Screenshots.cs#L124) methods in `[AppName]Screenshots`. [Xamarin.UITest](https://docs.microsoft.com/en-us/appcenter/test-cloud/uitest/) is used in these methods to automate your [app](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot.Example.Usage/ExampleScreenshots.cs#L24), putting it in the correct state before each screenshot. `SetAppStateForScreenshot1` is empty below because the first screenshot is of the first screen.\n\n```cs\nprotected override void SetAppStateForScreenshot1() {\n}\n\nprotected override void SetAppStateForScreenshot2() {\n  App.Tap(c =\u003e c.Marked(\"ratioPicker\"));\n  App.Tap(v =\u003e v.Text(\"Silver Ratio\"));\n  App.Tap(c =\u003e c.Marked(\"Done\"));\n}\n\nprotected override void SetAppStateForScreenshot3() {\n  App.Tap(c =\u003e c.Marked(\"ratioPicker\"));\n  App.Tap(v =\u003e v.Text(\"Bronze Ratio\"));\n  App.Tap(c =\u003e c.Marked(\"Done\"));\n}\n\nprotected override void SetAppStateForScreenshot4() {\n  App.Tap(c =\u003e c.Marked(\"ratioPicker\"));\n  App.Tap(v =\u003e v.Text(\"Yamato Ratio\"));\n  App.Tap(c =\u003e c.Marked(\"Done\"));\n  App.Tap(c =\u003e c.Marked(\"rotateButton\"));\n}\n\nprotected override void SetAppStateForScreenshot5() {\n  App.Tap(c =\u003e c.Marked(\"Cog.png\"));\n}\n```\n\n- Add the `TakeScreenshots()` method of your class to [Program.cs](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot.Example.Usage/Program.cs#L7) and run your console app to take the screenshots.\n\n```cs\npublic static void Main(string[] args) {\n  var screenshots = new GoldenRatioScreenshots();\n  screenshots.TakeScreenshots();\n\n  Environment.Exit(0);\n}\n```\n\nMy screenshots look like this after this example app has run (I've framed them for the occasion):\n\n\u003cimg src=\"https://hjerpbakk.com/img/Xnapshot/screenshots.png\" width=\"805\" height=\"374\"\u003e\n\nAnd the screenshots folder contains screenshots for all configured devices:\n\n\u003cimg src=\"https://hjerpbakk.com/img/Xnapshot/screenshots-folder.png\" width=\"822\" height=\"742\"\u003e\n\n## Advanced Options\n\nThe abstract [Screenshots](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot/Screenshots.cs) class has a couple of advanced options that can be optionally set in your `[AppName]Screenshots` constructor:\n\n```cs\npublic class ExampleScreenshots : Screenshots {\n  public ExampleScreenshots() : base(/*removed for brevity*/) {\n    SaveScreenshots = true;\n    OptimizeImagesAfterSave = false;\n  }\n}\n```\n\n### [SaveScreenshots](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot.Example.Usage/ExampleScreenshots.cs#L18)\n\nSet 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.\n\n### [OptimizeImagesAfterSave](https://github.com/Sankra/Xnapshot/blob/master/Xnapshot.Example.Usage/ExampleScreenshots.cs#L21)\n\nSet to `false` as default. Set this to `true` if you want to run   [ImageOptim](https://imageoptim.com) on every screenshot after save. ImageOptim must be installed in your Applications folder and will losslessly decrease the file size of the screenshots.\n\n## From 1.x to 2.x\n\nVersion 2.x contains breaking changes. Here's how you update your code from 1.x to use the new version.\n\n- Update the Xnapshot Nuget-package to 2.x.\n- Change your `[AppName]Screenshots` constructor from:\n\n```cs\npublic class GoldenRatioScreenshots : Screenshots {\n  public GoldenRatioScreenshots() : base(\n    DeviceType.iPhone,\n    \"iOS-9-2\",\n    \"/Users/sankra/Projects/GoldenRatioCalculator/screenshots/en-US\",\n    \"/Users/sankra/Projects/GoldenRatioCalculator/iOS/bin/iPhoneSimulator/Debug/GoldenRatioCalculatoriOS.app\") {\n  }\n}\n```\n\nto\n\n```cs\npublic class GoldenRatioScreenshots : Screenshots {\n  public GoldenRatioScreenshots() : base(\n    \"iOS-12-2\",\n    \"/Users/sankra/Projects/GoldenRatioCalculator/screenshots/en-US\",\n    \"/Users/sankra/Projects/GoldenRatioCalculator/iOS/bin/iPhoneSimulator/Debug/GoldenRatioCalculatoriOS.app\",\n    new[] {\n      \"iPhone-XS-Max\",\n      \"iPhone-XS\",\n      \"iPhone-XR\",\n      \"iPhone-8-Plus\",\n      \"iPhone-8\",\n      \"iPhone-SE\"\n    }) {\n  }\n}\n```\n\nThe rest of the code should work as is.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhjerpbakk%2Fxnapshot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhjerpbakk%2Fxnapshot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhjerpbakk%2Fxnapshot/lists"}