Is there a way to work with FileManager and NSBundle to get all the applications that support a given type of file in the /Applications directory? - swift

I'm creating a Commandline tool that will get an input from a user to search for a specific application that supports a certain file extension. For example, if I enter mp4, it will probably show me QuickTime. I'm looking for the specific FileManager manipulation to achieve this in Swift.

I think you are looking for NSWorkspace.urlForApplication(toOpen:). It finds the application that would be opened if you had double clicked on a file, and returns its URL. Since it requires a file to work, you need to first create a temporary empty file somewhere, with the desired extension, then call this method.
let tempFileURL = FileManager.default.temporaryDirectory.appendingPathComponent("foo.mp4")
FileManager.default.createFile(atPath: tempFileURL.path, contents: nil, attributes: nil)
// this gives me the URL for QuickTime Player:
// file:///System/Applications/QuickTime%20Player.app/
let url = NSWorkspace.shared.urlForApplication(toOpen: tempFileURL)

Related

Mac Sandbox issues with opening embedded RTF files

My Mac programs usually ship with some internal Rich Text files containing legal details. I use the NSWorkspace openFile call to open the files within TextEdit.
The code looks something like this:
guard let aPath = Bundle.main.path(forResource: “Legal.rtf”, ofType: nil) else { return }
NSWorkspace.shared.openFile(aPath, withApplication: nil)
This has always worked, until recently when this code returns “The application can’t be opened. -50”. Is that a Sandbox issue? Accessing files within your bundle should be allowed. We do it for images and such.
What do I have set wrong?
Thank you!
Thank you for your comments.
I should have mentioned at first that parameter string I had included both filename and the file type (extension). So I would have to split them, something that was easy to do with NSString, but is not immediately available for Swift String. A bit of conversion would have given me the two strings.
However, that OpenFile has been replaced with the newer open(_:)
let name = "Legal.rtf"
guard let aURL = Bundle.main.url(forResource: name, withExtension: "") else { return }
NSWorkspace.shared.open(aURL)
This call does NOT mind if you pass it string with both parts.

Swift 3 Mac OS Copy Audio File to NSPasteboard

I am trying to copy an audio file to the NSPasteboard so that it can be pasted somewhere else on the computer or into another program like Ableton or Pro Tools. Here is how I am getting the url of the file. (An example url d after casting to string is: file:///Users/ben/Music/Ableton/User%20Library/Vox.wav )
let url = directoryItems?[tableview.selectedRow].url
let urlString = (url?.absoluteString)! as String
let pb = NSPasteboard.general()
let pasted = pb.writeFileContents(urlString)
It is not being copied to the pasteboard (pasted is set to false) and I can not find any resources that talk about writing audio files to the NSPasteboard. Any help would be greatly appreciated.
Edit:
I also tried using the url instead of the string and had the same outcome
let pb = NSPasteboard.general()
let pasted = pb.writeObjects([url as! NSPasteboardWriting])
To copy a file in such a way that you can paste it in the Finder, you'd want a file URL, not a string.
As for copying the music into a music editor, presumably you'd need to load the music file yourself into some waveform format that can be pasted into that editor.

Accessing File saved in today extension from project

I am trying to access a file I saved from my today extension.In my today extenson I did this to save the file:
func startRecording() {
let audioFilename = getDocumentsDirectory().appendingPathComponent("recording.m4a")
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 12000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
do {
audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings)
audioRecorder.delegate = self
audioRecorder.record()
recordButton.setTitle("Stop", for: .normal)
} catch {
finishRecording(success: false)
}
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
I then tried to get the data for my AVAudio Player in the main part of the project using this code:
let path = Bundle.main.path(forResource: "recording.m4a", ofType:nil)!
let url = URL(fileURLWithPath: path)
However, it gave the error: unexpectedly found nil while unwrapping an Optional value.
Thanks for the help.
Your extension saves the file to its document directory and your app code is looking for the file in the app bundle. The app bundle only contains the resources that are distributed with the app. You'll need to delve into the file system.
However, there's another problem. The extension and containing app don't share a documents directory. They each have their own container for writing data local to themselves. If you want to share data between them, it's a little more work. In summary:
Create an app group identifier for the app and the extension to share.
Use FileManager.containerURL(forSecurityApplicationGroupIdentifier:) to get the file URL for the shared container directory.
From the container URL, append the file name.
In the extension, you'll set up the AVAudioRecorder as usual and start recording.
In the main app, you'll want to use the NSFileCoordinator API to ensure that only one process is writing to the file at a time. Hopefully, the AVAudioRecorder uses the NSFileCoordinator API internally, although I didn't immediately find confirmation of this.
For more details about shared containers, see this blog post.
I just tried the same - record audio from a Today Extension. The code looks sooo familiar, so I'm taking a wild guess: you want to capture voice and send the file to the Google Speech API, correct?
Nonetheless, I think we're hitting restrictions of extensions: judging by https://developer.apple.com/library/content/qa/qa1872/_index.html extensions cannot record audio. The article has been writting for iOS 8, but I don't believe Apple ever lifted the restriction. Please correct me if I'm wrong, since I keep running into problems doing what OP does myself.
btw, check the result of audioRecorder.record(). It might be false and indicate that the capture never started (that's my error currently).

VLCKit Subtitle not showing

I use VLCKit in swift, so i created customize video player view
and i have external subtitles for movies from links, i read files from server and convert it so string
do {
let text = try NSString(contentsOfURL: NSURL(string: self.subtitleUrl)!, encoding: NSUTF8StringEncoding)
self.mediaPlayer.openVideoSubTitlesFromFile(text as String)
}catch {
print("Error")
}
and i called a function named "openVideoSubTitlesFromFile"
in player but not working
anyone can give me a solution
This method (which will be deprecated in the next major release of VLCKit) does only accept local file paths, no remote URLs. You need to download the subtitles file, cache it locally and provide the path of the stored file to the method. Additionally, you may only use this method after playback started.

How to get the Log Directory in Swift?

I see the ability to get the path to the ApplicationsSupport Directory using Swift.
Is there an interface to get the Log directory?
As far as I can see, there is no Apple-provided way to get this. This seems odd at first glance, but I believe Apple's rationale is that we are actually not supposed to need to directly access this directory, and instead should use their logging API which takes care of these details.
However, I'm using SwiftyBeaver to write logs to a file, and used the following code to generate the logs directory URL:
let bundleID = Bundle.main.bundleIdentifier!
let logsUrl = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask)[0]
.appendingPathComponent("Logs", isDirectory: true)
.appendingPathComponent(bundleID, isDirectory: true)