
Retake: OSS iOS App Store preview video generator
App Store preview videos captured on real iOS devices and defined in JSON as sets, scenes and edits.
以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。
App Store preview videos captured on real iOS devices and defined in JSON as sets, scenes and edits.
Retake plays your app on a USB-connected iPhone or iPad while the Mac records its screen and sound, then cuts the recordings into a finished preview with captions, touches, spotlights, cards, transitions, sound and music. Everything that makes the video is a file kept with your code, so when the app changes you record again and render the same edits: no screen recording by hand, no timeline to rebuild, and no guessing which frames you used last time.
showcase.mp4
Every frame of the video above was made by Retake from the example app, recorded on a physical iPhone and iPad, and cut for each from the one showcase edit.
How you use it. Install Retake, then start your favorite coding agent in your app's repository and ask it to integrate Retake. Describe the flows you want recorded, the state each one starts from, and what each video should emphasize. The agent writes the sets, composes the scenes on your device, records the takes, writes the edits and renders the cuts. Watch them, and keep asking for changes to the scenes and edits until the video looks just how you want it.
Retake is made to be driven that way: an agent composes a scene as you would, told after each action what happened and what's on screen; every file has a schema that retake validate checks a project against; and the commands that report something take --json.
What about App Store screenshots? Retake is purpose built for App Store preview videos. Its capture step saves stills from the same scenes, which can serve, but at the device's own resolution, which often isn't a size App Store Connect takes; see Captures.
Status: an early release; see the latest. Retake is an experiment in generalizing a tool I'd used for two of the apps I've released to the App Store.
Stability: until 1.0, nothing is guaranteed to stay the same between versions. If you'd like to avoid breakage, pin to an exact version: mise use github:justinseanmartin/Retake@<version>. Breaking changes will be documented in the release notes and come with a new minor version, from 0.1 to 0.2. Compatibility guarantees start at 1.0.
How it works
Install
Quick start
Embedding Retake into your app
Sets: the state a take starts from (state)
Scenes: the walk through the app
Takes: footage and a step log
Captures: stills from the same scenes
Edits: the video cut from the takes
What's recorded in each file
Devices
The Button Heist, and Retake's version pin
Project layout
Limitations
The full command reference is Documentation/cli.md, and every field of every file is in Documentation/reference, generated from Retake's schemas.
set + scene ──retake record──▶ take (movie + step log) ──retake cut──▶ video.mp4 edit.json
retake install puts a Debug build of your app on a USB-connected device, with what Retake needs to drive it embedded in the build. Your project doesn't change. (If you install builds yourself, retake embed does just the embedding.)
retake record <scene> launches the app on the scene's set, plays its steps, and records the device's screen and sound. A recording that succeeds becomes the scene's take, and the take it replaces is kept as the previous one.
retake cut <edit> renders the edit from each scene's take, for every device type it names, to a ProRes master and an .mp4 for App Store Connect.
Install
Retake is a single command for macOS, released with everything it needs:
mise use github:justinseanmartin/Retake # from GitHub Releases
Add @<version> to pin one, since nothing is guaranteed stable before 1.0 (see the status note above).
You don't need any other tools installed to use Retake. When a command fails and its message doesn't say why, retake doctor checks each part of the setup in turn, to find which.
retake init # Retake/: retake.json, a starter set, scene and edit; output/ gitignored retake devices add iphone # name the USB-connected device retake install --scheme MyApp # build Debug, embed Retake, and install it retake record launch # record the starter scene: the app launching retake cut preview --type iphone # cut the starter edit, for the iPhone only retake compose <scene> # then write your own scenes, a step at a time, on the device
NOTE: Start recording with the device on the home screen, and with Focus modes off, to keep extra noise out of the status bar, such as "◀ Safari" or a Do Not Disturb moon.
Take a look at the example app. Example is a simple notes app with its Retake/ project, ready to run. Its sets start the app fresh or as a returning user with stored notes. Its scenes walk through getting started, writing a note, sharing it and seeing it sync, and reordering notes with the device turned. Its edits cut those into an App Store preview (tour) and a tour of Retake's editing features (showcase), the video above. To run it from a clone of Retake, see running the example.
Retake needs nothing from your app's code. retake install takes a Debug build of it, adds The Button Heist's in-app server (TheInsideJob) and Retake's own small support library into the app's bundle, re-signs it with the identity and profile it was already signed with, and installs it. Both are loaded only when Retake launches the app, through the launch environment; the app's own executable is unchanged. Nothing is added to your project, so neither can reach an App Store build.
If you build and install the app yourself, with a script, fastlane, or CI, run retake embed on the built .app before installing it:
retake embed build/Debug-iphoneos/MyApp.app xcrun devicectl device install app --device "$UDID" build/Debug-iphoneos/MyApp.app
An embedded app behaves as it always does when opened from the home screen, so you can embed every build you install for testing, and record with whichever one is on the device. Run retake check on release archives if a build you embed could ever be archived.
install can also run your own build command, from retake.json, when one xcodebuild call can't build your app; see retake install.
Your app shouldn't link TheInsideJob itself. Retake always supplies its own, the exact version it's built against (see the version pin), and embed and install stop if the app already contains one. If you link it for other tooling, leave it out of the builds you record with.
What you may want to add, Debug-only and optional, is launch flags for content that varies. Anything that differs between takes or between viewers — prices by region, random picks, dates, a signed-in account — is best fixed by a flag your app reads at launch, which a set turns on.
The status bar takes care of itself. While a Mac records an iOS device's screen, iOS shows a clean status bar: 9:41, full signal, full battery.
So does the preview's shape. App Store previews have fixed shapes, which a device's screen rarely matches: an iPad preview is 3:4. A set's previewAspect lays the app out at the preview's shape, with no code in the app.
A set is everything that puts the app into a known state before a take: its data, its settings, and its launch environment. A scene names its set, so every take of the scene starts the same way.
{ "extends": "base", "state": "clean", "files": { "Documents/notes.sqlite": "data/returning-user/notes.sqlite", "Library/Application Support/Media/": "data/returning-user/media/" }, "defaults": { "hasSeenOnboarding": true, "sortOrder": "recent" }, "environment": { "MYAPP_REGION_NEUTRAL_PRICES": "1" }, "arguments": ["-AppleLanguages", "(en)", "-AppleLocale", "en_US"], "previewAspect": true }
files are put in the app's data before launch, at the paths the app reads them from, so an app that keeps its data in Documents or Application Support starts on a known state with no code at all. Their sources are relative to retake.json; .. can reach a fixture shared with the app project or another Retake project, while absolute paths are rejected so the project stays portable. defaults are what UserDefaults.standard holds at launch: strings, numbers, booleans, and lists and dictionaries of them, as JSON has; a Data or Date value can't be given yet. Give defaults this way, not as a plist in files: one copied into Library/Preferences isn't read. environment and arguments are added to the launch, for your app's own Debug-only flags and for the language and locale. extends builds on another set, so what every set shares is written once, and a flag only one scene needs goes in a small set of its own that extends the one it builds on. state and previewAspect are below, and every field is in the set reference.
A set's state says what the app's data starts as for a take, and whether the take's changes are kept. In the order to reach for them:
clean and cloned give each take its own copy of the app's data, so recording never changes the data you use the app with. Some of the app's state is out of their reach; see what state doesn't cover yet.
How it works. At launch, before any of the app's code runs, Retake's support library builds the take's home folder inside the app's container, puts the set's files in it, and points the app at it. Every standard folder lookup follows: NSHomeDirectory(), FileManager's Documents, Application Support and Caches, URL.documentsDirectory, NSTemporaryDirectory(), and the databases and files your code opens there, SQLite included. A cloned take's copy is a clone of the real files (clonefile), which takes no time to make and no space until the take writes to it.
Each take's copy is deleted when the app next launches under Retake, and record launches it once more at the end of a run to delete the last, so no copy is left on the device. retake clean --on-device does the same on demand, after a run that was interrupted. Only the app itself can delete files in its container, so both launch it in a mode that deletes them and quits before any of the app's own code runs. iOS then opens the app again, as it would from the home screen, and Retake closes it.
In clean and cloned, Retake replaces UserDefaults.standard for the take with an in-memory store. The app reads and writes it as it always does, through UserDefaults and @AppStorage; nothing is written to the app's real defaults, and everything is gone when the app quits. In clean, every take starts from exactly the set's values, whatever the last one changed. A clean start still reads launch arguments (-key value, as a set's arguments may give) and the global domain (such as AppleLanguages); only the app's own domain starts empty. In cloned, a key the set doesn't give, and the take hasn't written or removed, reads through to the app's real defaults, so the take sees them without copying them, and can't change them.
It behaves as the real defaults do in the ways an app notices: values the app registers with register(defaults:) still apply beneath the set's; the typed getters (bool(forKey:), integer(forKey:) and so on) read the same values; and every write updates @AppStorage views and key-value observers, and posts UserDefaults.didChangeNotification.
With "previewAspect": true, Retake's support library sizes the app's window to the App Store preview's shape for the device type being recorded, 886:1920 on an iPhone and 3:4 on an iPad, as wide as the screen and pinned to its top, and the edit crops the band left below it. The app lays itself out in its window as it always does, SwiftUI and UIKit alike: on an iPad it sees a 3:4 window, with the safe area of a window that doesn't reach the home indicator. Nothing in the app needs to know. Without it, the app fills the screen, and the edit crops the screen evenly to the preview's shape instead.
When a scene turns the device to landscape, the window takes the same shape turned (4:3 for 3:4), pinned to the screen's left. The keyboard and the system's status bar and home indicator aren't the app's window, so they still span the screen: a keyboard rises into the band the edit crops
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。