├── .gitignore ├── .gitmodules ├── screenshot ├── Helper.js ├── changeCarrierName ├── LICENSE ├── installOnSimulator ├── README.md ├── changeLanguage └── run /.gitignore: -------------------------------------------------------------------------------- 1 | Results/**/* 2 | *.trace 3 | Latest 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tuneup_js"] 2 | path = tuneup_js 3 | url = git://github.com/alexvollmer/tuneup_js/ 4 | -------------------------------------------------------------------------------- /screenshot: -------------------------------------------------------------------------------- 1 | open /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone\ Simulator.app 2 | ./run ../$1.js $1 3 | 4 | -------------------------------------------------------------------------------- /Helper.js: -------------------------------------------------------------------------------- 1 | function captureLocalizedScreenshot(name) 2 | { 3 | var target = UIATarget.localTarget(); 4 | var model = target.model(); 5 | var rect = target.rect(); 6 | 7 | if (model.match(/iPhone/)) 8 | { 9 | if (rect.size.height > 480) model = "iphone5"; 10 | else model = "iphone"; 11 | } 12 | else 13 | { 14 | model = "ipad"; 15 | } 16 | 17 | var orientation = "portrait"; 18 | if (rect.size.height < rect.size.width) orientation = "landscape"; 19 | 20 | var language = target.frontMostApp().preferencesValueForKey("AppleLanguages")[0]; 21 | 22 | var parts = [language, model, name]; // orientation 23 | target.captureScreenWithName(parts.join("-")); 24 | } -------------------------------------------------------------------------------- /changeCarrierName: -------------------------------------------------------------------------------- 1 | # Use my stackoverflow answer to change the carrier name 2 | # http://stackoverflow.com/questions/12580694/how-to-customize-carrier-name-in-ios-6-simulator/14292811#14292811 3 | 4 | cd ~/Desktop/ 5 |   6 | # Don't forget to change the language 'en' to the one you want to modify 7 | 8 | # Copy the file here. 9 | sudo cp /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/System/Library/CoreServices/SpringBoard.app/en.lproj/SpringBoard.strings ~/Desktop 10 |   11 | # Change the format from binary to XML. 12 | sudo plutil -convert xml1 SpringBoard.strings 13 | 14 | # When you open the .strings file with any text editor (e.g. Textmate, vim), you can search for CARRIER and replace its value 15 |   16 | # Now copy back to the simulator folder. 17 | sudo cp SpringBoard.strings /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk/System/Library/CoreServices/SpringBoard.app/en.lproj/ 18 | 19 | # Make sure not to mix up any languages -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Toursprung 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /installOnSimulator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript 2 | 3 | on run argv 4 | if count of argv < 2 then 5 | logEvent("Usage: ./installOnSimulator PathToProject ProjectName iOSVersion(6.1,5.0)") 6 | error number -128 7 | end 8 | 9 | set iOSVersion to item 3 of argv 10 | set projectName to item 2 of argv 11 | set projectPath to item 1 of argv 12 | 13 | set posixProjectPath to (the POSIX path of projectPath) 14 | 15 | tell application "Xcode" 16 | open posixProjectPath 17 | end tell 18 | 19 | delay(20) 20 | 21 | tell application "Xcode" to activate 22 | 23 | try 24 | tell application "System Events" 25 | tell process "Xcode" 26 | tell menu bar 1 27 | tell menu bar item "Product" 28 | tell menu 1 29 | tell menu item "Scheme" 30 | tell menu 1 31 | -- Set the proper scheme if we're using workspaces (e.g. cocoapods) 32 | click menu item projectName 33 | end tell 34 | end tell 35 | end tell 36 | end tell 37 | end tell 38 | end tell 39 | tell process "Xcode" 40 | tell menu bar 1 41 | tell menu bar item "Product" 42 | tell menu 1 43 | tell menu item "Destination" 44 | tell menu 1 45 | -- Set the proper scheme if we're using workspaces (e.g. cocoapods) 46 | click menu item ("iPhone " & iOSVersion & " Simulator") 47 | end tell 48 | end tell 49 | end tell 50 | end tell 51 | end tell 52 | end tell 53 | tell process "Xcode" 54 | tell menu bar 1 55 | tell menu bar item "Product" 56 | tell menu 1 57 | click menu item "Run" 58 | end tell 59 | end tell 60 | end tell 61 | end tell 62 | end tell 63 | on error errMsg 64 | logEvent ("Error: " & errMsg) 65 | end try 66 | end run 67 | 68 | 69 | on logEvent(themessage) 70 | -- All the recent events, results and error can be found at the give path 71 | -- It can easily be opened with the regular "Console" app 72 | set theLine to (do shell script "date +'%Y-%m-%d %H:%M:%S'" as string) & " " & themessage 73 | do shell script "echo '" & theLine & "' >> ~/Library/Logs/AppleScript-events.log" 74 | end log_event 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [discontinued] iOS-Screenshot-Automator 2 | ======================== 3 | 4 | 5 | ----- 6 | 7 | # Use [fastlane](https://docs.fastlane.tools/getting-started/ios/screenshots/) instead to automate your screenshots 👍 8 | 9 | ----- 10 | 11 | Batch-creates screenshots for all iOS devices in every language you define, ready for immediate upload in iTunes Connect. Uses and integrates with UIAutomation from Apple. Also great for unit testing. 12 | 13 | Follow the developer on Twitter: [KrauseFx](http://twitter.com/krausefx) (Felix Krause) 14 | 15 | The script is based on UIAutomation to navigate the app and take the screenshots. 16 | 17 | Define which languages and simulator types you want to use in the "run"-file. 18 | 19 | #Run the script:# 20 | ```shell 21 | ./run ../TestScript.js AppName 22 | ``` 23 | 24 | To take screenshots with UIAutomation use captureLocalizedScreenshot. It will automatically name the file properly and put it in the Results folder. (Don't forget to import Helper.js in your javascript UIAutomation script) 25 | 26 | 27 | If you want to set the carrier name manually, take a look at the "changeCarrierName" file 28 | 29 | You can use tuneup_js to start your scripts and define tests. It's a really great library that helps you develop unit tests faster. You can also use these scripts to do unit testing. 30 | 31 | To fetch the tuneup_js submodule, use the following git command. 32 | git submodule update --init 33 | 34 | 35 | Example of TestScript.js 36 | ```javascript 37 | #import "iOS-Screenshot-Automator/Helper.js" 38 | 39 | 40 | test("Login Test", loginTest); 41 | test("Route Test", routeDetailsTest); 42 | ... 43 | 44 | function loginTest(target, app) 45 | { 46 | var window = app.mainWindow(); 47 | var navBar = window.navigationBar(); 48 | 49 | ... 50 | 51 | captureLocalizedScreenshot("Login"); 52 | 53 | .... 54 | } 55 | ``` 56 | 57 | If you want to add the orientation of the iDevice in your screenshot names as well, configure it in the Helper.js file. 58 | 59 | #Open Todos:# 60 | * Put all resulting screenshots in one folder (or more meaningful folders) 61 | * Raise AppleScript exception when UIAutomation script fails 62 | * If possible: Automate uploading screenshots to iTunesConnect directly 63 | 64 | ![iOS Screenshot Automator](http://www.toursprung.com/wp-content/uploads/2013/01/ScreenshotToolImage.png) 65 | -------------------------------------------------------------------------------- /changeLanguage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright (c) 2012 Jonathan Penn (http://cocoamanifest.net/) 3 | 4 | # Permission is hereby granted, free of charge, to any person obtaining a copy 5 | # of this software and associated documentation files (the "Software"), to deal 6 | # in the Software without restriction, including without limitation the rights 7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | # copies of the Software, and to permit persons to whom the Software is 9 | # furnished to do so, subject to the following conditions: 10 | 11 | # The above copyright notice and this permission notice shall be included in 12 | # all copies or substantial portions of the Software. 13 | 14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | # THE SOFTWARE. 21 | 22 | # Tell bash that we want the whole script to fail if any part fails. 23 | set -e 24 | 25 | function main { 26 | if [[ -z $1 ]]; then 27 | # If there are no arguments for this command, then print the current 28 | # language of the first simulator it finds 29 | echo $(_print_current_languages | head -1) 30 | else 31 | # Otherwise, change the language of every simulator SDK 32 | _close_sim 33 | _change_language $1 34 | fi 35 | } 36 | 37 | # Grab the global pref file for every simulator version in a string 38 | pref_files=$(ls ~/Library/Application\ Support/iPhone\ Simulator/[0-9]*/Library/Preferences/.GlobalPreferences.plist) 39 | 40 | # Set the string split delimiter to a newline for the 'for..in' 41 | IFS=" 42 | " 43 | 44 | function _change_language { 45 | # Alters the global preference file for every simulator type and moves the 46 | # chosen language identifier to the top. 47 | 48 | echo "Localizing for $1" 49 | 50 | for file in $pref_files; do 51 | # Disable errors temporarily just in case the prefs don't have the key 52 | # we're trying to delete. This could happen when experimenting and leaving 53 | # the prefs file in an inconsistent state. If anything goes horribly wrong, 54 | # just reset the simulator and everything will be fine. 55 | set +e 56 | _plistbuddy "$file" -c "Delete :AppleLanguages" 57 | _plistbuddy "$file" -c "Delete :AppleLocale" 58 | set -e 59 | 60 | # Create the language array with just the given language 61 | _plistbuddy "$file" \ 62 | -c "Add :AppleLanguages array" \ 63 | -c "Add :AppleLanguages:0 string '$1'" \ 64 | -c "Add :AppleLocale string '$1'" 65 | done 66 | } 67 | 68 | function _print_current_languages { 69 | for file in $pref_files; do 70 | _plistbuddy "$file" -c "Print :AppleLanguages:0" 71 | done 72 | } 73 | 74 | function _plistbuddy { 75 | /usr/libexec/PlistBuddy $* 76 | } 77 | 78 | function _close_sim { 79 | osascript -e 'tell application "iPhone Simulator" to quit' 80 | } 81 | 82 | main $* 83 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript 2 | 3 | on run argv 4 | -- Set all devices you want to use for screenshots here 5 | -- (has to match the name of the menu items of the iOS Simulator) 6 | set allDevices to {"iPhone Retina (3.5-inch)" , "iPhone Retina (4-inch)", "iPad Retina"} 7 | -- Set all languages your app is translated to. 8 | set allLanguages to {"en", "de" } 9 | 10 | 11 | 12 | 13 | -- set allDevices to {"iPhone (Retina 4-inch)"} 14 | -- Set all languages your app is translated to. 15 | -- set allLanguages to {"en"} 16 | 17 | 18 | 19 | set iOSVersion to "7.0.3" 20 | 21 | setupFolders() 22 | 23 | set userName to short user name of (system info) 24 | 25 | if count of argv < 2 then 26 | logEvent("Usage: ./run TestScript.js AppName") 27 | error number -128 28 | end 29 | 30 | set scriptName to item 1 of argv 31 | set appName to item 2 of argv 32 | 33 | set automationTemplate to "instruments -t /Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/Automation.tracetemplate" 34 | set applicationsFolder to "/Users/" & userName & "/Library/Application Support/iPhone Simulator/" & iOSVersion & "/Applications/" 35 | 36 | 37 | set applicationsFolderPosix to POSIX file applicationsFolder 38 | tell application "Finder" 39 | set subFolders to every folder of folder applicationsFolderPosix 40 | end tell 41 | 42 | repeat with currentFolder in subFolders 43 | tell application "Finder" 44 | set subFiles to every file of currentFolder 45 | end tell 46 | 47 | repeat with currentSubfolder in subFiles 48 | -- inside the app 49 | if (currentSubFolder as string) contains (appName & ".app") then 50 | set appFolderName to currentSubFolder 51 | end if 52 | end repeat 53 | end repeat 54 | 55 | if not appFolderName as string = "" then 56 | logEvent("Found the app: " & appFolderName) 57 | else 58 | logEvent("Couldn't find the app you were looking for") 59 | error number -128 60 | end if 61 | 62 | set unixPathToApplication to (the POSIX path of (appFolderName as alias)) 63 | 64 | logEvent("Unix Path: " & unixPathToApplication) 65 | 66 | set errorLog to " " 67 | 68 | try 69 | -- save the actual value of "UIDeviceFamily" field 70 | changeInfoPlist(unixPathToApplication, "Copy :UIDeviceFamily :UIDeviceFamily_backup") 71 | on error 72 | -- ignore any "Entry Already Exists" error. It may happen when this command exits 73 | -- without in the middle of the execution. In this case we can just ignore the 74 | -- the value of UIDeviceFamily because the correct value is aler 75 | end 76 | 77 | changeInfoPlist(unixPathToApplication, "Delete :UIDeviceFamily") 78 | repeat with currentDevice in allDevices 79 | -- make the app support only iPhone or iPad because universal apps don't work 80 | -- well with the Instruments. (Instruments always opens them with iPad simulator) 81 | set deviceFamily to "1" 82 | if currentDevice contains "iPad" 83 | set deviceFamily to "2" 84 | end if 85 | changeInfoPlist(unixPathToApplication, "Add :UIDeviceFamily array") 86 | changeInfoPlist(unixPathToApplication, "Add :UIDeviceFamily:0 integer " & deviceFamily) 87 | 88 | changeDevice(currentDevice) 89 | 90 | repeat with currentLang in allLanguages 91 | do shell script "./changeLanguage " & currentLang 92 | logEvent("Changed language to " & currentLang) 93 | 94 | logEvent("Executing " & automationTemplate & " \"" & unixPathToApplication & "\" -e UIASCRIPT \"" & scriptName & "\" -e UIARESULTSPATH Results") 95 | set currentResults to do shell script automationTemplate & " \"" & unixPathToApplication & "\" -e UIASCRIPT \"" & scriptName & "\" -e UIARESULTSPATH Results" 96 | 97 | if (currentResults as string) contains "Fail:" then 98 | set errorLog to (errorLog & currentResults) 99 | end if 100 | 101 | 102 | logEvent("Results: " & currentResults) 103 | 104 | try 105 | do shell script "mv Results/Run\\ 1/* Latest/" 106 | do shell script "rm -rf Results/Run\\ 1" 107 | on error errMsg 108 | logEvent(errMsg) 109 | end try 110 | 111 | tell application "iPhone Simulator" to quit 112 | end repeat 113 | changeInfoPlist(unixPathToApplication, "Delete :UIDeviceFamily") 114 | end repeat 115 | 116 | -- restore the value of "UIDeviceFamily" field 117 | changeInfoPlist(unixPathToApplication, "Copy :UIDeviceFamily_backup :UIDeviceFamily") 118 | changeInfoPlist(unixPathToApplication, "Delete :UIDeviceFamily_backup") 119 | 120 | do shell script "rm -rf ./instrumentscli*" 121 | 122 | if length of errorLog > 10 then 123 | logEvent("Some errors occurred: " & errorLog) 124 | do shell script "echo '" & errorLog & "' > Latest/errorLog.txt" 125 | end if 126 | end run 127 | 128 | 129 | on logEvent(themessage) 130 | -- All the recent events, results and error can be found at the give path 131 | -- It can easily be opened with the regular "Console" app 132 | set theLine to (do shell script "date +'%Y-%m-%d %H:%M:%S'" as string) & " " & themessage 133 | do shell script "echo '" & theLine & "' >> ~/Library/Logs/AppleScript-events.log" 134 | end logEvent 135 | 136 | on changeInfoPlist(appPath, plistCommand) 137 | do shell script "/usr/libexec/PlistBuddy -c '" & plistCommand & "' '" & appPAth & "/Info.plist'" 138 | end changeInfoPlist 139 | 140 | on setupFolders() 141 | -- Clear useless instrumentscli files and copy the screenshots to the proper folder 142 | -- If you prefer other folder names, just change it here. 143 | do shell script "rm -rf ./instrumentscli*" 144 | 145 | try 146 | do shell script "mkdir Results" 147 | on error errMsg -- to ignore errors when the folder already exists 148 | end try 149 | 150 | do shell script "rm -rf Results/Run*" 151 | 152 | do shell script "mkdir Results/Build-" & (do shell script "date +'%Y.%m.%d-%H:%M:%S'" as string) 153 | 154 | -- Create the link to the latest build 155 | try 156 | do shell script "rm Latest" 157 | on error errMsg -- to ignore errors when the folder was not yet created 158 | end try 159 | 160 | do shell script "ln -s Results/Build-" & (do shell script "date +'%Y.%m.%d-%H:%M:%S'" as string) & " Latest" 161 | try 162 | do shell script "mv Results/Run* Results/Build-" & (do shell script "date +'%Y.%m.%d-%H:%M:%S'" as string) & "/" 163 | on error errMsg 164 | logEvent(errMsg) 165 | end try 166 | end setupFolders 167 | 168 | on changeDevice(deviceName) 169 | delay (1) 170 | logEvent("Start changing device to " & deviceName) 171 | 172 | tell application "iPhone Simulator" to activate 173 | tell application "System Events" 174 | tell process "iPhone Simulator" 175 | tell menu bar 1 176 | tell menu bar item 5 177 | -- Hardware menu 178 | tell menu 1 179 | -- Device 180 | tell menu item 1 181 | -- Device sub menu 182 | tell menu 1 183 | click menu item deviceName 184 | end tell 185 | end tell 186 | end tell 187 | end tell 188 | end tell 189 | end tell 190 | end tell 191 | 192 | logEvent("Changed device to " & deviceName) 193 | end changeDevice 194 | --------------------------------------------------------------------------------