Using OSX Security-Scoped Bookmarks in a Firemonkey app - macos

I have been developing an OSX app with Delphi XE3 and running into various problems. The latest one is with the sanboxed version built for the Apple Appstore.
The user has to select an arbitrary folder and the app needs to get access to it. Since there is a problem with the OpenDialog, I had to turn to drag-drop functionality instead.
The user drags a folder to the app, the sandbox gives the app temporary access to it and all works properly.
To preserve the access to this folder when the app is restarted I have to use the so-called "security-scoped bookmarks"
I am having two issues with them:
1) How to add the "com.apple.security.files.bookmarks.app-scope" entitlement to an XE3 firemonkey app? It is not available in the Project Options->Entitlements. If I add it manually in the ".entitlements" file it gets overwritten when the app is built.
So is there a way to add a custom entitlement that is not in the list in the project options?
2) To create the bookmark I should use the NSURL.bookmarkDataWithOptions method. I think it should be used like this, but I am not sure of the exact syntax:
var
URL: NSURL;
Err: NSError;
Data: NSData;
...
URL := TNSURL.Create;
Data := URL.bookmarkDataWithOptions(NSURLBookmarkCreationWithSecurityScope, nil, #Err);
...
Maybe there should be a call to Wrap(...) instead of Create.
I have not yet experimented with it, because it is pointless without the answer to issue 1).
It seems no one has written anything about these problems for Delphi, but I hope someone here has experience with that.
Thanks in advance.
Edit:
For problem 1) I tried to add edit manually the ".entitlements" file in the OSX32 folder and set it to read-only to prevent it from being overwritten. It was too easy to be true of course, because the linker complained that the file can not be modified...

OK, I finally found the way to manually add entitlements that are not available in the Project Options > Entitlements.
Instead of selecting the "App Store" build in the Project Manager you have to select a Normal release build and deploy the application as usual.
The application gets deployed in the PAServer scratch-dir as APP package. Inside this package there is an "Entitlements.plist" file, which is in XML format and can be edited with a text editor. It is quite obvious how to add new entitlements once you open the file.
After it is edited, the app has to be code-signed manually and a package has to be prepared. It is slightly more complicated than using the Delphi IDE, but there are instructions about it on the Embarcadero and Apple websites and it actually went without problems.
Still haven't tried the bookmarkDataWithOptions functions.

An alternative could be to deactivate the checkbox for the entitlements-file in the deployment page.
But attention: Evry time you change between Build/Release or App Store/Normal, delphi activates the checkbox. That means you have to deactivate it again in the deplayment-page, to avoid the transfer of this file to the mac PC.
By the way: Do you have tryed meanwhile the StartAccessingSecurityScopedResource function?
In the MacApi.Foundation unit the function is not declared in the NSURL interface.
Do you have found a way to use this function?

Related

Cannot run exported application

I've developed a simple MacOS application (i.e. a product consisting of main application and launch helper application) with Xcode 9.4. Application runs fine in Xcode. I've archived and exported the app (either "Export without re-signing" or "Development" using "Automatic signing"). The export process runs without errors.
However, it is not possible to the application. Upon starting outside of Xcode, nothing happens; no error message etc.
How can this be further diagnosed?
Finally found it thanks to #clemens. Embedded libraries have their place inside the generated package in /Contents/Frameworks. Since I had previously embedded a login item I had set a /Contents/Library/LoginItems target path that was used below Frameworks which is clearly not the expected place. Removing the library, cleaning the path and re-adding fixed it for me.

Windows Universal app crashes after Associating identity with Store

I'm creating a cordova app for Windows.
Now when I build this normally (with my own identity of which I have no clue where he gets it from) everything works fine and my app launches with success.
Although when I then associate my app with the Store, and have my actual app name + package name etc filled in for me, I get a blank screen when trying to run my app.
The head and body tags stay empty and no error is thrown in my JavaScript console.
Any idea of why this happens? The problem definitely is that I associate my app with the Store and then something happens which makes my app crash or fail to start.
But why does it do this? And how can I resolve it?
(currently building with VS2017)
edit
Alright, so I figured out that because the package name changed, I had to edit that as well in the manifest. Now My main root component is loaded, but it isn't setting the app root to any page, just a blank screen. (with a menu that can open on swipe).
Alright, so my Microsoft assigned package name was different than my own. This caused the app to look for my own package name instead of the Microsoft one I associated with.
The solution was quite simple, just set your widget-id in your config.xml to the Microsoft assigned package name and rebuild your solution.
(I was using Ionic framework so re-execute ionic build windows --release --prod --arch="arm")

QLPreviewView can not show the quicklook preview in sandbox

I use QLPreviewView to show the quicklook preview in the app. Without sandbox, this works well, but once change the app to sandbox, the preview can not show up.
I found the error in Console: QuickLookUIHelpe(20786) deny file-read-data XXX.
I have used the security-scoped bookmarks & com.apple.security.files.user-selected.read-write to grant access the user home dir, then:
[allowedURL startAccessingSecurityScopedResource];
self.myPreiviewItem.myURL = fileURL;
self.myQLPreviewView.previewItem = self.myPreiviewItem;
[self.myQLPreviewView refreshPreviewItem];
[allowedURL stopAccessingSecurityScopedResource];
with these, I can delete files of user home dir, but the QLPreviewView can not work.
I do not know what is the difference between these 2 scenes, does QLPreviewView need more for sandbox?
If I add com.apple.security.files.downloads.read-only into the entitlement, the files in "Downloads" can be previewed, but other files of user home dir can not be previewed.
Finally I have found the solution!
refreshPreviewItem is an async call, so before Mac finishes loading the preview, the following api stopAccessingSecurityScopedResource immediately shutdown the access, as a result, Mac failed to load the preview successfully.
so the solution is: do NOT call stopAccessingSecurityScopedResource here, keep the allowedURL's access right until you do not need the QL preview function, and then call stopAccessingSecurityScopedResource there, such as when closing the window.
I encountered this, or at least a similar, issue a while back (in Mavericks).
This is why I started asking users for access to parent folders of files they wish to Quick Look. Feel free to look at how I do it in this app of mine, version 1.1 at the time of this writing. Just go into Chikoo → Preferences… → Folder Access. Here are two screenshots:
I confess that this is not a great solution. It’s a compromise that I came up with to work around the problem.

DocumentPicker Extension immediately stopped on clicking on the icon

I have created the document picker extension(Both File provide and document picker , with the default implementations) and when i try to open the extension using the DocumentPickerViewController, its immediately closing the DocumentPickerViewController by showing the below issue
plugin com.apple.UIKit.fileprovider.default invalidated.
I have setup the basic app groups and iCloud entitlement as well, Which are all fine. Even from the documentViewController the default iCloud is working perfectly fine.
Actually i am testing the extension using the same container application.
If somebody can provide some insight about this behavior, it would be a great help !!
Thanks,
Vishnu
I got the issue, actually the value of NSExtensionFileProviderDocumentGroup key was put incorrectly put on the info.plist of the file provider extension by XCode by the time of adding the App group.
Then I compared the files with the NBox sample from Apple and finally figured it out.
So sometimes beware of XCode automatic actions, make a cross check so to save to time.

Problem in working with core data

Am using core data framework in my cocoa application,I have created couple of entities and created reference using NSEntityDescription. When i run the application am getting an error saying that "The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store."
You need to delete the application from your device / simulator, then build and run again.
This will happen each time you change your model, because the old data store will remain in the apps documents folder, while the classes accessing it have been altered.
In a later stage of development, you will propably want to introduce store migration, sou your testers and users won't have to delete their data each time a new version is released. If your model remains static though, you don't need to migrate the data during future updates.
You might want to take a look at the Core Data Migration Programming Guide for further information.
The answer is a bit tricky but this always works for me. This is for a clean installation of a new compatible .sqlite file, not a migration!
launch simulator, delete the app and the data (the popup after you delete the app).
quit simulator
open X-Code, after making any edits to your data model
delete the {*appname*}.sqlite file (or back it up, remove it from project folder, and delete reference)
clean the app (Product > Clean)
Run the app in a simulator (for this tutorial I will assume 4.2)
While the simulator is running, in a Finder window, navigate to:
{*home*} > Library > Application Support > iPhone Simulator > 4.2 > Applications > {*random identifier*} > Documents > {*appname*}.sqlite
Copy this file to another location
Stop running your app in X-Code
Drag and drop the {appname}.sqlite file into the files list in X-Code.
In the dialog that pops up, make sure the copy to folder checkbox, is checked.
Product > Clean
Then run the app in the simulator again
Now you should have a working sqlite file!
Cheers,
Robert
You must delete the persistent store file from either:
~/Library/$AppName
~/Library/Application Support/$AppName
(Depending on your version of Xcode.)

Resources