import AVFoundation enum RCTVideoSave { static func save( options:NSDictionary!, resolve: @escaping RCTPromiseResolveBlock, reject:@escaping RCTPromiseRejectBlock, playerItem: AVPlayerItem? ) { let asset:AVAsset! = playerItem?.asset guard asset != nil else { reject("ERROR_ASSET_NIL", "Asset is nil", nil) return } guard let exportSession = AVAssetExportSession(asset: asset, presetName:AVAssetExportPresetHighestQuality) else { reject("ERROR_COULD_NOT_CREATE_EXPORT_SESSION", "Could not create export session", nil) return } var path:String! = nil path = RCTVideoSave.generatePathInDirectory( directory: URL(fileURLWithPath: RCTVideoSave.cacheDirectoryPath() ?? "").appendingPathComponent("Videos").path, withExtension: ".mp4") let url:NSURL! = NSURL.fileURL(withPath: path) as NSURL exportSession.outputFileType = AVFileType.mp4 exportSession.outputURL = url as URL? exportSession.videoComposition = playerItem?.videoComposition exportSession.shouldOptimizeForNetworkUse = true exportSession.exportAsynchronously(completionHandler: { switch (exportSession.status) { case .failed: reject("ERROR_COULD_NOT_EXPORT_VIDEO", "Could not export video", exportSession.error) break case .cancelled: reject("ERROR_EXPORT_SESSION_CANCELLED", "Export session was cancelled", exportSession.error) break default: resolve(["uri": url.absoluteString]) break } }) } static func generatePathInDirectory(directory: String?, withExtension `extension`: String?) -> String? { let fileName = UUID().uuidString + (`extension` ?? "") RCTVideoSave.ensureDirExists(withPath: directory) return URL(fileURLWithPath: directory ?? "").appendingPathComponent(fileName).path } static func cacheDirectoryPath() -> String? { let array = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).map(\.path) return array[0] } static func ensureDirExists(withPath path: String?) -> Bool { var isDir: ObjCBool = false var error: Error? let exists = FileManager.default.fileExists(atPath: path ?? "", isDirectory: &isDir) if !(exists && isDir.boolValue) { do { try FileManager.default.createDirectory(atPath: path ?? "", withIntermediateDirectories: true, attributes: nil) } catch { } if error != nil { return false } } return true } }