diff --git a/README.md b/README.md index f9272d4..5e98375 100644 --- a/README.md +++ b/README.md @@ -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) @@ -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) @@ -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 diff --git a/Snaptake.xcodeproj/project.pbxproj b/Snaptake.xcodeproj/project.pbxproj index 7954fd0..568805f 100644 --- a/Snaptake.xcodeproj/project.pbxproj +++ b/Snaptake.xcodeproj/project.pbxproj @@ -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 */ @@ -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 = ""; }; + 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 = ""; }; 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 = ""; }; 8D8A726520824F840021D344 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -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 = ""; }; 8D8A728D208252340021D344 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 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 */ @@ -61,9 +63,11 @@ 8D8A725720824F840021D344 = { isa = PBXGroup; children = ( + 7CF46E6C28EE02E800674B91 /* fastlane */, 8D8A726220824F840021D344 /* Snaptake */, 8D8A728A208252340021D344 /* SnaptakeUITests */, 8D8A726120824F840021D344 /* Products */, + 341730F475918518DF10427A /* README.md */, ); sourceTree = ""; }; @@ -92,8 +96,8 @@ 8D8A728A208252340021D344 /* SnaptakeUITests */ = { isa = PBXGroup; children = ( + 7C30150D28EF157C0079BF6D /* SnapshotHelper.swift */, 8D8A728B208252340021D344 /* SnaptakeUITests.swift */, - 8D8A7293208252440021D344 /* SnapshotHelper.swift */, 8D8A728D208252340021D344 /* Info.plist */, ); path = SnaptakeUITests; @@ -210,7 +214,7 @@ buildActionMask = 2147483647; files = ( 8D8A728C208252340021D344 /* SnaptakeUITests.swift in Sources */, - 8D8A7294208252440021D344 /* SnapshotHelper.swift in Sources */, + 7C30150E28EF157C0079BF6D /* SnapshotHelper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -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; @@ -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; diff --git a/fastlane/Fastfile b/fastlane/Fastfile index e9a092b..5705e1c 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -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 diff --git a/fastlane/SnapshotHelper.swift b/fastlane/SnapshotHelper.swift index 3b449e6..5ca961f 100644 --- a/fastlane/SnapshotHelper.swift +++ b/fastlane/SnapshotHelper.swift @@ -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) @@ -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)