how to open an app from Mac from Xcode project (Cocoa App) - swift

Today I have created an Cocoa Application for the very first time . I want to create a simple App which will open an APP from my Mac , if the file not found it will show a Link in a Label to download the App. Here is my code below which I am struggling with .
if let fileCheck = NSURL.fileURL(withPath: "/Applications/Mango.app") {
if NSWorkspace.shared().open(fileCheck as URL) {
print("url successfully opened")
}
} else {
self.downloadLink.insertText("Invalid Path")
}
NSURL.fileURL(withPath: "/Applications/Mango.app") giving me Conditional Binding Must be Optional , I don't know how to fix that. And I am struggling with how to show a link on my Label either. Any kind hearted Dev please help.

got the solution by someone , I don't know why he deleted that !
if FileManager().fileExists(atPath: "/Applications/Mango.app") {
NSWorkspace.shared().open(NSURL(fileURLWithPath: "/Applications/Mango.app") as URL)
} else {
downloadLink.isHidden = false
}

Related

Unable to save images to Egnyte/Google Drive/Dropbox - Swift/Xcode

UPDATE
I tried the following code solution and it allows for me to save to Google Drive now, but Egnyte and Dropbox are still greyed out.
func exportPhotosToFileLocation() {
var fileURLArray = [URL]()
for data in reviewDataController.tableViewReviewData {
guard let imageData = data.image.jpegData(compressionQuality: 1.00) else {
print("ERROR: Unable to print convert image to jpegData in exportPhotosToFileLocation!")
return
}
let fileManager = FileManager.default
do {
let fileURL = fileManager.temporaryDirectory.appendingPathComponent("\(data.imageTitle)").appendingPathExtension("jpeg")
try imageData.write(to: fileURL)
fileURLArray.append(fileURL)
print("Successfully created file from jpegData in exportPhotosToFileLocation!")
} catch {
print("ERROR: Unable to create file from jpegData in exportPhotosToFileLocation!")
return
}
}
if #available(iOS 14, *) {
let controller = UIDocumentPickerViewController(forExporting: fileURLArray)
present(controller, animated: true)
}
else {
let controller = UIDocumentPickerViewController(urls: fileURLArray, in: .exportToService)
present(controller, animated: true)
}
}
Here is the developer documents for Egnyte. Unfortunately, none of it makes sense to me as a beginner.
Egnyte Developer Documentation
----------------------------------------------------------------------------------------------
ORIGINAL POST
In my app, I'm trying to allow the user to select a save location (so choose a folder). Whenever I use this code, Egnyte/Google Drive/Dropbox are all "greyed" out and inaccessible.
let supportedTypes : [UTType] = [UTType.folder]
let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes)
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)
If I change supportedTypes to
let supportedTypes : [UTType] = [UTType.text]
It does let me access them. Does anyone have a solution for this? I obviously need the user to be able to select a folder in these applications... you can see why that is important.
This is up to the file provider extension (Google Drive, etc.). To allow picking a folder, the file provider has to lay content in its directory in a hierarchical manner... if they do this, they need to specify NSExtensionFileProviderSupportsPickingFolders in their Info.plist to tell the system it's allowed to choose folders.
Do you need to choose a save location and persist it? If yes, then you'll be blocked on the file provider implementing the necessary API. If not, the type you pass should the type of the document you are actually saving. The document will be saved once in the chosen folder (without any additional requirements on the file provider extension), and you will have to use the document picker again to save the next document.
If you are trying to select Dropbox as a location to import files from in the Apple File Importer but it does not advance to the file selection screen I found that restarting my iPhone seemed to resolve that issue.

Got an error when dragging files using NSEvent. (macOS)

I wanna drag files to my window and then perform actions.
I tried to use snippets below provided in this answer to distinguish whether you're dragging a file or a window.
// In my window controller
class MyWindowController: NSWindowController {
init() {
// Some initialization steps below are omitted
let win = NSWindow(...)
super.init(window: win)
let contentView = DropView(frame: win.frame)
win.contentView?.addSubview(contentView)
registerGlobalMouseEvent()
}
func registerGlobalMouseEvent() {
self.window?.acceptsMouseMovedEvents = true
NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
// Codes below will cause errors
let pasteBoard = NSPasteboard(name: .drag)
guard let fileNames = pasteBoard.propertyList(forType: .init(rawValue: "NSFilenamesPboardType")) as? NSArray else { return }
let changeCount = pasteBoard.changeCount
if fileNames.count > 0 && lastChangeCount != changeCount {
lastChangeCount = changeCount
// My actions when dragging
}
})
}
}
Then I ran my codes and started dragging, I got three errors:
[sandbox] Failed to get a sandbox extension
[Framework] Failed to issue sandbox extension for /Users/roy/Downloads/test.txt with error 1
[default] Failed to issue sandbox token for URL: 'file:///Users/roy/Downloads/test.txt' with error: 'Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedDescription=Cannot issue a sandbox extension for file "/Users/roy/Downloads/test.txt": Operation not permitted}'
 
But when I just do
NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
// My actions
})
, then everything went fine.
 
The first error seems harmless since it didn't prevent my app from running.
The second and the third ones are deadly and directly caused my app to crash.
I wonder if there are any problems in his code? Any useful thoughts would be great! :)
 
You need to know about Bookmarks and Security Scoped URLs when working with sandbox . A dragged URL gives your app process permission just once to read or read/write a “user selected file” depending on how you configure entitlements.
You can save a bookmark (blob of data) to keep access over subsequent sessions as long as the file isn’t updated by another process at which point the bookmark becomes stale and you will need to encourage the user to select the file again.
Handing a URL to another process across an XPC boundary like sharing requires that you own the file so may involve a copy to your sandbox cache.
e.g:
let dragurl = url_of_dragged_file //at this point you have at-least read access
let cachepath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).last!
let cachedir = URL(fileURLWithPath: cachepath)
let cacheurl = cachedir
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension(dragurl.pathExtension)
try FileManager.default.copyItem(at: dragurl, to: cacheurl)
At this point you have a copy in your local sandbox cache that can be handed off to a share sheet.
So I finally got a solution for this. :)
It appears that it indeed have something to do with the snippets I mentioned above, and here's the correction:
NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged, handler: { [self] event in
let pasteboard = NSPasteboard(name: .drag)
let changeCount = pasteboard.changeCount
if lastChangeCount != changeCount {
lastChangeCount = changeCount
if pasteboard.canReadObject(forClasses: [NSURL.self], options: [:]) {
/// actions
}
}
})
In this way, I got no errors and my codes run perfectly!

Finder Share Extension: Getting a preview image from NSItemProvider

I'm creating a Finder Share extension to be used when selecting a file. I'd like to show an image preview of the file that you are sharing (like you see in the Messages and Twitter Finder Share extensions, for example).
In the loadView method of the view controller for my share extension, I'm doing this:
let item = self.extensionContext!.inputItems[0] as! NSExtensionItem
if let attachments = item.attachments as? [NSItemProvider] {
if let attachment = attachments.first {
attachment.loadPreviewImage(options: nil, completionHandler: { (item, error) in
if error != nil {
//handle error...
} else if let img = item as? NSImage {
//put image preview in my "share sheet"...
}
})
}
}
The problem is that when I keep hitting the error condition. The error that I'm getting is:
Error Domain=NSItemProviderErrorDomain Code=-1000 "Cannot load preview." UserInfo={NSLocalizedDescription=Cannot load preview.}
For what it's worth, I am able to call attachment.loadItem() successfully and work with the file. But I don't really care to do anything with the file itself at this point, I just want a thumbnail image that represents the file which theoretically this method should give me...
Any ideas?
I am in the same situation. After read the manual, I think here is the reason.
"Loads the preview image for the item that is represented by the item provider."
However, it is not forced that the item provider must provides a preview. So the error simply says that there is no preview that the item provider can provide. You should do it yourself.

CloudKit - "Invalid bundle ID for container"

I've just create a project in Xcode 9 beta 6 and add this code:
let privateDB = CKContainer.default().privateCloudDatabase
let greatID = CKRecordID(recordName: "GreatPlace")
let place = CKRecord(recordType: "Place", recordID: greatID)
privateDB.save(place) { (record, error) in
if error != nil {
let er = (error as! CKError).errorUserInfo
print("Error: \n")
print("CKErrorDescription: \(er["CKErrorDescription"]!)\n")
print("ContainerID: \(er["ContainerID"]!)\n")
print("NSDebugDescription: \(er["NSDebugDescription"]!)\n")
print("NSUnderlyingError: \(er["NSUnderlyingError"]!)\n")
print("NSLocalizedDescription: \(er["NSLocalizedDescription"]!)\n")
print("ServerErrorDescription: \(er["ServerErrorDescription"]!)\n")
}
if record != nil {
print("record: \(record!)")
}
}
and add this capabilities:
and when I run the code I receive this error message:
What I am doing wrong ?
There was a bug causing some associations to be missed. That bug has been fixed and we automatically fixed the container/app associations that were broken during that time.
If for some reason you still need to redo an association you can either use the Capabilities pane in Xcode or use developer.apple.com -> Certificates, Identifiers & Profiles -> App IDs -> pick the ID -> Edit -> Edit under iCloud -> check the box for the container to disassociate, save, then re-associate.
If you're still stuck please email cloudkit[at]apple.com
My friend and I are having the same issue. We made 2 different projects and both of them had the same error message "Invalid bundle ID for container" which is CKError case 10 .
We are calling our fetch function to get the default "Users" record in the viewDidLoad.
func fetchWorkoutCompleted(completion: #escaping (Error?) -> Void = { _ in }) {
cloudKitManager.fetchRecord(ofType: "Users", sortDescriptors: nil) { (records, error) in
if let error = error {
print(error.localizedDescription)
completion(error)
return
}
guard let records = records else { completion(nil); return }
completion(nil)
}
}
Using Xamarin.IOS, I had to select manual provisioning rather than automatic provisioning in the info.plist file.
Had the same issue. what worked for me was changing the iCloud group name.
Before it was something like this: iCloud.com.companyName.appName.randomString
After changing to: iCloud.com.companyName.randomString it started working and synchronising.
If after adding the new container it's red press the refresh button(from under the groups) and try a clean install on your phone and it should work
Thanks to Dave Browning, this is based on his answer.
Following worked for me:
Check the container id
Check the container id used for initialisation of CKContainer
Note: If you are using NSPersistentCloudKitContainer we wouldn't be using the container id directly would be picked automatically from the entitlements file.
Try to disable and enable iCloud on the App ID
Disable and Enable iCloud on App ID
Go to https://developer.apple.com and sign in
Select Certificates, Identifiers & Profiles
Select Identifiers (App IDs)
Edit App ID for the app
Uncheck iCloud
Save
Check iCloud
Quit Xcode and Clear DerivedData
Run app

Styling Google Maps in swift 2

I'm facing a little problem I hope there is a simple solution.
Indeed I would like to custom my google map but I only found how to achieve this in Swift 3 (like the following instruction) but I'm currently developping in Swift 2.
do {
// Set the map style by passing the URL of the local file.
if let styleURL = Bundle.main.url(forResource: "style", withExtension: "json") {
mapView.mapStyle = try GMSMapStyle(contentsOfFileURL: styleURL)
} else {
NSLog("Unable to find style.json")
}
} catch {
NSLog("One or more of the map styles failed to load. \(error)")
}
Does somebody has an idea about how solve my problem in Swift 2 ?
Thank you for your answers !