Swift - Get File Path of Currently Opened Document in Another Application

Swift - Get file path of currently opened document in another application

Thanks to the help of another post from @JamesWaldrop, I was able to answer this myself and wanted to post here for anyone looking for something similar:

let proToolsBundleIdentifier = "com.avid.ProTools"
let proToolsApp : NSRunningApplication? = NSRunningApplication
.runningApplications(withBundleIdentifier: proToolsBundleIdentifier).last as NSRunningApplication?


if let pid = proToolsApp?.processIdentifier {

var result = [AXUIElement]()
var windowList: AnyObject? = nil // [AXUIElement]

let appRef = AXUIElementCreateApplication(pid)
if AXUIElementCopyAttributeValue(appRef, "AXWindows" as CFString, &windowList) == .success {
result = windowList as! [AXUIElement]
}

var docRef: AnyObject? = nil
if AXUIElementCopyAttributeValue(result.first!, "AXDocument" as CFString, &docRef) == .success {
let result = docRef as! AXUIElement
print("Found Document: \(result)")
let filePath = result as! String
print(filePath)
}
}

This gets the AXDocument just like the AppleScript does. Would still be open to other methods of doing this that may be better or not using Accessibility.

How to get file paths for current open documents in a macOS project in Swift?

You can get the documents from NSDocumentController and the URL from each document.

for document in NSDocumentController.shared().documents {
print("\(document.fileURL)")
}

How to get file paths for current open documents in a macOS project in Swift?

You can get the documents from NSDocumentController and the URL from each document.

for document in NSDocumentController.shared().documents {
print("\(document.fileURL)")
}

iOS file path is changing at every launch/rerun the application


Edit 1:

Hi I created the new project and use the same code I posted in main, and it's working. But in the real project it not working.

Not sure what exactly going on in your project, try to debug it. It's part of development as well. :)

If you are in hurry to fix this issue in this weekend try to use the following code snippet.

// collect data from bundle
let constFileURL = Bundle.main.url(forResource: "AppConst", withExtension: "json")!
let data = try! Data(contentsOf: constFileURL)

// try to write data in document directory
do {
let constFileURL = try saveFileInDocumentDirectory(filePath: "MyFolder/AppConst.json", data: data)
// use your `constFileURL`
} catch (let error as FileOperationError) {
switch error {
case .fileAlreadyExists(let url):
let data = try! Data(contentsOf: url)
print(String(data: data, encoding: .utf8))
case .IOError(let error):
print("IO Error \(error)")
}
} catch {
print("Unknown Error \(error)")
}

// Helpers
enum FileOperationError: Error {
case fileAlreadyExists(url: URL)
case IOError(Error)
}
func saveFileInDocumentDirectory(filePath: String, data: Data) throws -> URL {

// final destination path
let destURLPath = fullURLPathOf(filePath, relativeTo: .documentDirectory)
// check for file's existance and throw error if found
guard FileManager.default.fileExists(atPath: destURLPath.path) == false else {
throw FileOperationError.fileAlreadyExists(url: destURLPath)
}
// Create Intermidiate Folders
let intermidiateDicPath = destURLPath.deletingLastPathComponent()
if FileManager.default.fileExists(atPath: intermidiateDicPath.path) == false {
do {
try FileManager.default.createDirectory(at: intermidiateDicPath, withIntermediateDirectories: true, attributes: nil)
} catch {
throw FileOperationError.IOError(error)
}
}

// File Writing
do {
try data.write(to: destURLPath, options: .atomic)
} catch {
throw FileOperationError.IOError(error)
}
return destURLPath
}
func fullURLPathOf(_ relativePath: String, relativeTo dic:FileManager.SearchPathDirectory ) -> URL {
return FileManager.default.urls(for: dic, in: .userDomainMask).first!.appendingPathComponent(relativePath)
}

Original Answer

Why don't you just return "MyFolder/\(fileName)" on successful file operation? If you need to access the path later you can always do that using FileManager APIs.

let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let constFilePath = docDir.appendingPathComponent("MyFolder/\(fileName)")

// Access const file data
do {
let fileData = try Data(contentsOf: constFilePath)

// Use you data for any further checking

} catch {
// Error in reading file data
print("Error in file data access : \(error)")
}

How to handle a file sent with 'Open in...' from another app to my own iOS app?

This is handled in your AppDelegate, more precisely, you get passed an URL to the document and then you handle it from there in optional function, e.g.:

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
do {
let data = try Data(contentsOf: url)
// Do something with the file
} catch {
print("Unable to load data: \(error)")
}

return true
}

More info: https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623112-application

Different path URL for FileManager everytime I open the app

You are using the wrong API. absoluteString (in rootURL.absoluteString) returns the string representation including the scheme file://. The correct API for file system URLs is path

I recommend to use the URL related API as much as possible

public func directoryExists(at url: URL) -> Bool {
let fileManager = FileManager.default
var isDir : ObjCBool = false
if fileManager.fileExists(atPath: url.path, isDirectory:&isDir) {
return isDir.boolValue
} else {
return false
}
}

and compose the URL in a more reliable way

func createARObjectDirectory() {
let rootURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
if directoryExists(at: rootURL.appendingPathComponent(DefaultURL.arObjectUrlDirectoryName) {
Logger.logServer("ARObject directly found")
} else {
createNewDirectory(name: DefaultURL.arObjectUrlDirectoryName)
}
}

And this is swiftier too

public func createNewDirectory(name: String) {

let documentDirectory = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let dirURL = documentDirectory.appendingPathComponent(name)
do
{
try FileManager.default.createDirectory(at: dirURL, withIntermediateDirectories: false, attributes: nil)
}
catch let error as NSError
{
Logger.logError("Unable to create directory \(error.debugDescription)")
}
Logger.logInfo("Dir Path = \(dirPath.path)")
}



Related Topics



Leave a reply



Submit