Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 42 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,22 @@ class func snaptakeStart(_ name: String, timeWaitingForIdle timeout: TimeInterva
#if os(OSX)
XCUIApplication().typeKey(XCUIKeyboardKeySecondaryFn, modifierFlags: [])
#else
guard let simulator = ProcessInfo().environment["SIMULATOR_DEVICE_NAME"], let screenshotsDir = screenshotsDirectory else { return nil }
guard let simulator = ProcessInfo().environment["SIMULATOR_DEVICE_NAME"], let screenshotsDir = screenshotsDirectory, let cacheDirectory else { return nil }

let path = "screenshots/\(locale)/\(simulator)-\(name).mp4"
let simulatorNamePath = cacheDirectory.appendingPathComponent("simulator-name.txt")

let simulatorTrimmed = simulator.replacingOccurrences(of: "Clone 1 of ", with: "")
let path = "./videos/\(locale)/\(simulatorTrimmed)-\(name).mp4"
let recordingFlagPath = screenshotsDir.appendingPathComponent("recordingFlag.txt")

do {
try path.write(to: recordingFlagPath, atomically: false, encoding: String.Encoding.utf8)
let localeURL = screenshotsDir.appending(component: locale)
if !FileManager.default.fileExists(atPath: localeURL.path) {
try FileManager.default.createDirectory(at: localeURL, withIntermediateDirectories: true)
}

try simulator.trimmingCharacters(in: .newlines).write(to: simulatorNamePath, atomically: false, encoding: .utf8)
try path.trimmingCharacters(in: .newlines).write(to: recordingFlagPath, atomically: false, encoding: String.Encoding.utf8)
} catch let error {
print("Problem setting recording flag: \(recordingFlagPath)")
print(error)
Expand Down Expand Up @@ -151,10 +160,15 @@ After we called ```plot``` in ```snaptake``` we finally are going to stop record

```swift
class func snaptakeStop(_ recordingFlagPath: URL) {
guard let screenshotsDir = cacheDirectory else { return }

let simulatorNamePath = screenshotsDir.appendingPathComponent("simulator-name.txt")

let fileManager = FileManager.default

do {
try fileManager.removeItem(at: recordingFlagPath)
try fileManager.removeItem(at: simulatorNamePath)
} catch let error {
print("Problem removing recording flag: \(recordingFlagPath)")
print(error)
Expand Down Expand Up @@ -188,26 +202,45 @@ lane :videos do |options|
File.delete(mp4_file_path)
end

simulatorNamePath = '~/Library/Caches/tools.fastlane'
cacheDirectory = '~/Library/Caches/tools.fastlane/screenshots'

# Ensure that caching folder for screenshots and recording flags exists
Dir.mkdir(File.expand_path('~/Library/Caches/tools.fastlane/screenshots')) unless Dir.exist?(File.expand_path('~/Library/Caches/tools.fastlane/screenshots'))
Dir.mkdir(File.expand_path(cacheDirectory)) unless Dir.exist?(File.expand_path(cacheDirectory))

# Setup listeners for starting and ending recording
fastlane_require 'listen'
path = nil
process = nil
name = nil
trimming_time_dictionary = {}
recordingListener = Listen.to(File.expand_path('~/Library/Caches/tools.fastlane/screenshots'), only: /\.txt$/) do |modified, added, removed|
recordingListener = Listen.to(File.expand_path(cacheDirectory), only: /\.txt$/) do |modified, added, removed|
if (!added.empty?) && File.basename(added.first) == 'recordingFlag.txt'
recording_flag_path = added.first
expanded = File.expand_path("simulator-name.txt", simulatorNamePath)
name = File.read(expanded)
path = File.read(recording_flag_path)
process = IO.popen("xcrun simctl io booted recordVideo '#{path}'") # Start recording of current simulator to path determined in recordingFlag.txt
# Start recording of current simulator to path determined in recordingFlag.txt
expandedPath = File.expand_path(path)

# Ensure that path exists
pathWithoutFileName = File.dirname(expandedPath)
FileUtils.mkdir_p(pathWithoutFileName) unless Dir.exist?(pathWithoutFileName)

process = IO.popen("xcrun simctl --set testing io '#{name}' recordVideo '#{expandedPath}' --force")

puts "Starting recording for #{name} #{process.pid} to #{expandedPath}"
end
if (!removed.empty?) && File.basename(removed.first) == 'recordingFlag.txt'
pid = process.pid
Process.kill("INT", pid) # Stop recording by killing process with id pid
trimming_flag_path = File.expand_path('~/Library/Caches/tools.fastlane/screenshots/trimmingFlag.txt')
# Stop recording by killing process with id pid
Process.kill("INT", pid)
trimming_flag_path = File.expand_path(cacheDirectory + '/trimmingFlag.txt')
trimming_time = File.read(trimming_flag_path)
trimming_time_dictionary[path] = trimming_time # Storing trimming time determined in trimmingFlag.txt for recorded video (necessary due to initial black simulator screen after starting recording)
# Storing trimming time determined in trimmingFlag.txt for recorded video (necessary due to initial black simulator screen after starting recording)
trimming_time_dictionary[path] = trimming_time

puts "Finished recording for #{name} #{pid}"
end
end

Expand Down
16 changes: 10 additions & 6 deletions Snaptake.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
objects = {

/* Begin PBXBuildFile section */
7C30150E28EF157C0079BF6D /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C30150D28EF157C0079BF6D /* SnapshotHelper.swift */; };
8D8A726420824F840021D344 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8A726320824F840021D344 /* AppDelegate.swift */; };
8D8A726620824F840021D344 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8A726520824F840021D344 /* ViewController.swift */; };
8D8A726920824F840021D344 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D8A726720824F840021D344 /* Main.storyboard */; };
8D8A726B20824F850021D344 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8D8A726A20824F850021D344 /* Assets.xcassets */; };
8D8A726E20824F850021D344 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D8A726C20824F850021D344 /* LaunchScreen.storyboard */; };
8D8A728C208252340021D344 /* SnaptakeUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8A728B208252340021D344 /* SnaptakeUITests.swift */; };
8D8A7294208252440021D344 /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8A7293208252440021D344 /* SnapshotHelper.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -27,6 +27,9 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
341730F475918518DF10427A /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
7C30150D28EF157C0079BF6D /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotHelper.swift; path = fastlane/SnapshotHelper.swift; sourceTree = SOURCE_ROOT; };
7CF46E6C28EE02E800674B91 /* fastlane */ = {isa = PBXFileReference; lastKnownFileType = folder; path = fastlane; sourceTree = "<group>"; };
8D8A726020824F840021D344 /* Snaptake.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Snaptake.app; sourceTree = BUILT_PRODUCTS_DIR; };
8D8A726320824F840021D344 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
8D8A726520824F840021D344 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
Expand All @@ -37,7 +40,6 @@
8D8A7289208252340021D344 /* SnaptakeUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SnaptakeUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8D8A728B208252340021D344 /* SnaptakeUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnaptakeUITests.swift; sourceTree = "<group>"; };
8D8A728D208252340021D344 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8D8A7293208252440021D344 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SnapshotHelper.swift; path = fastlane/SnapshotHelper.swift; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -61,9 +63,11 @@
8D8A725720824F840021D344 = {
isa = PBXGroup;
children = (
7CF46E6C28EE02E800674B91 /* fastlane */,
8D8A726220824F840021D344 /* Snaptake */,
8D8A728A208252340021D344 /* SnaptakeUITests */,
8D8A726120824F840021D344 /* Products */,
341730F475918518DF10427A /* README.md */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -92,8 +96,8 @@
8D8A728A208252340021D344 /* SnaptakeUITests */ = {
isa = PBXGroup;
children = (
7C30150D28EF157C0079BF6D /* SnapshotHelper.swift */,
8D8A728B208252340021D344 /* SnaptakeUITests.swift */,
8D8A7293208252440021D344 /* SnapshotHelper.swift */,
8D8A728D208252340021D344 /* Info.plist */,
);
path = SnaptakeUITests;
Expand Down Expand Up @@ -210,7 +214,7 @@
buildActionMask = 2147483647;
files = (
8D8A728C208252340021D344 /* SnaptakeUITests.swift in Sources */,
8D8A7294208252440021D344 /* SnapshotHelper.swift in Sources */,
7C30150E28EF157C0079BF6D /* SnapshotHelper.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -295,7 +299,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.3;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
Expand Down Expand Up @@ -349,7 +353,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.3;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
Expand Down
31 changes: 25 additions & 6 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,45 @@ platform :ios do
File.delete(mp4_file_path)
end

simulatorNamePath = '~/Library/Caches/tools.fastlane'
cacheDirectory = '~/Library/Caches/tools.fastlane/screenshots'

# Ensure that caching folder for screenshots and recording flags exists
Dir.mkdir(File.expand_path('~/Library/Caches/tools.fastlane/screenshots')) unless Dir.exist?(File.expand_path('~/Library/Caches/tools.fastlane/screenshots'))
Dir.mkdir(File.expand_path(cacheDirectory)) unless Dir.exist?(File.expand_path(cacheDirectory))

# Setup listeners for starting and ending recording
fastlane_require 'listen'
path = nil
process = nil
name = nil
trimming_time_dictionary = {}
recordingListener = Listen.to(File.expand_path('~/Library/Caches/tools.fastlane/screenshots'), only: /\.txt$/) do |modified, added, removed|
recordingListener = Listen.to(File.expand_path(cacheDirectory), only: /\.txt$/) do |modified, added, removed|
if (!added.empty?) && File.basename(added.first) == 'recordingFlag.txt'
recording_flag_path = added.first
expanded = File.expand_path("simulator-name.txt", simulatorNamePath)
name = File.read(expanded)
path = File.read(recording_flag_path)
process = IO.popen("xcrun simctl io booted recordVideo '#{path}'") # Start recording of current simulator to path determined in recordingFlag.txt
# Start recording of current simulator to path determined in recordingFlag.txt
expandedPath = File.expand_path(path)

# Ensure that path exists
pathWithoutFileName = File.dirname(expandedPath)
FileUtils.mkdir_p(pathWithoutFileName) unless Dir.exist?(pathWithoutFileName)

process = IO.popen("xcrun simctl --set testing io '#{name}' recordVideo '#{expandedPath}' --force")

puts "Starting recording for #{name} #{process.pid} to #{expandedPath}"
end
if (!removed.empty?) && File.basename(removed.first) == 'recordingFlag.txt'
pid = process.pid
Process.kill("INT", pid) # Stop recording by killing process with id pid
trimming_flag_path = File.expand_path('~/Library/Caches/tools.fastlane/screenshots/trimmingFlag.txt')
# Stop recording by killing process with id pid
Process.kill("INT", pid)
trimming_flag_path = File.expand_path(cacheDirectory + '/trimmingFlag.txt')
trimming_time = File.read(trimming_flag_path)
trimming_time_dictionary[path] = trimming_time # Storing trimming time determined in trimmingFlag.txt for recorded video (necessary due to initial black simulator screen after starting recording)
# Storing trimming time determined in trimmingFlag.txt for recorded video (necessary due to initial black simulator screen after starting recording)
trimming_time_dictionary[path] = trimming_time

puts "Finished recording for #{name} #{pid}"
end
end

Expand Down
24 changes: 19 additions & 5 deletions fastlane/SnapshotHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -213,13 +213,22 @@ open class Snapshot: NSObject {
#if os(OSX)
XCUIApplication().typeKey(XCUIKeyboardKeySecondaryFn, modifierFlags: [])
#else
guard let simulator = ProcessInfo().environment["SIMULATOR_DEVICE_NAME"], let screenshotsDir = screenshotsDirectory else { return nil }

let path = "screenshots/\(locale)/\(simulator)-\(name).mp4"
guard let simulator = ProcessInfo().environment["SIMULATOR_DEVICE_NAME"], let screenshotsDir = screenshotsDirectory, let cacheDirectory else { return nil }

let simulatorNamePath = cacheDirectory.appendingPathComponent("simulator-name.txt")

let simulatorTrimmed = simulator.replacingOccurrences(of: "Clone 1 of ", with: "")
let path = "./screenshots/\(locale)/\(simulatorTrimmed)-\(name).mp4"
let recordingFlagPath = screenshotsDir.appendingPathComponent("recordingFlag.txt")

do {
try path.write(to: recordingFlagPath, atomically: false, encoding: String.Encoding.utf8)
let localeURL = screenshotsDir.appending(component: locale)
if !FileManager.default.fileExists(atPath: localeURL.path) {
try FileManager.default.createDirectory(at: localeURL, withIntermediateDirectories: true)
}

try simulator.trimmingCharacters(in: .newlines).write(to: simulatorNamePath, atomically: false, encoding: .utf8)
try path.trimmingCharacters(in: .newlines).write(to: recordingFlagPath, atomically: false, encoding: String.Encoding.utf8)
} catch let error {
print("Problem setting recording flag: \(recordingFlagPath)")
print(error)
Expand Down Expand Up @@ -261,10 +270,15 @@ open class Snapshot: NSObject {
}

class func snaptakeStop(_ recordingFlagPath: URL) {
guard let screenshotsDir = cacheDirectory else { return }

let fileManager = FileManager.default

let simulatorNamePath = screenshotsDir.appendingPathComponent("simulator-name.txt")

do {
try fileManager.removeItem(at: recordingFlagPath)
try fileManager.removeItem(at: simulatorNamePath)
} catch let error {
print("Problem removing recording flag: \(recordingFlagPath)")
print(error)
Expand Down