Original situation:
I'm developing a sandboxed app on macOS 10.13. It's a shoebox-like app consisting of a main window with toolbar. Autosaving for the window frame and toolbar configuration are set up in Interface Builder.
If I run and quit the app, I can see a preferences file (named <app-identifier>.plist) containing the expected data in the app's sandbox container. Everything works fine.
Extending the app with App Groups:
To allow data exchange with other sandboxed apps, I created an app group in my target's Capabilities tab of Xcode.
So far this works, i.e. an additional group container is created when launching the app. It is also possible to store shared preferences into the group container by creating a UserDefaults object via UserDefaults.init(suiteName:"<group-name>").
The problem:
After adding the App Group, the autosaving mechanism for e.g. the toolbar configuration no longer works. Starting and quitting the app on a clean Mac no longer creates a .plist file in the Preferences directory of the app container. Instead the console shows messages like this:
[User Defaults] attempt to set <value> for key in <key> in
non-persistent preferences domain CFPrefsPlistSource<address>
(Domain: <app-identifier>, User: kCFPreferencesCurrentUser,
ByHost: No, Container: (null), Contents Need Refresh: Yes)
It looks for me, that the autosaving mechanism is no longer able to write its data into the preferences file.
Is it possible to concurrently use standard UserDefaults and shared ones in the app groups?
Problem solved: after a rebooting the Mac, everything works as expected. This is really weird.
Related
I’m trying to add a login item to a macOS app. The app is set to agent in its plist so it has no dock icon, hides its main window in launch, and places an icon in the status bar to provide its UI.
To add the login item, I have:
Created a new macOS app within the project (the launch helper)
Disabled Strip Debug Symbols During Copy in the base app
Added a Copy Files phase to the base app, destination set to Wrapper, Subpath set to Contents/Library/LoginItems, and added the helper app to the list of files to copy
Set the helper app to background only
Enabled Skip Install for the helper app
Removed the window from the helper app
Added code to the helper app’s applicationDidFinishLaunching to launch the base app
Added an option to the base app to call SMLoginItemSetEnabled((__bridge CFStringRef)#"com.mydomain.MyApp-Helper", enabled) to allow toggling the login item
Enabled sandbox and codesigning for both base and helper app
Built the project and copied the app to /Applications
Launched the app from /Applications and enabled the option to launch at login
The problem is that although I get feedback from the app that SMLoginItemSetEnabled was successful, the helper app does not run on login, or if it runs, it does not launch the base app.
I looked inside the base app bundle and the helper app is in there. I can run it manually, and it does launch the base app. I can even manually add it as a login item through System Preferences and it still launches the base app. So it would appear that even though SMLoginItemSetEnabled is returning true, it is not actually installing the login item. Or if it is, it’s not able to launch and run the base app from the login item even though it can if I do it manually.
The solution to this was to delete the DerivedData folder for both the base app and the helper app. It would seem that the login item was confused about which copy of the app to open, and was presumably trying to open one from DerivedData. Deleting these folders and leaving only the app in /Applications allowed the helper app to launch the base app from the login item.
I created a simple Finder Sync (FinderSync) extension (appex) and it comes by default with App Sandbox ON (in .entitlements com.apple.security.app-sandbox true).
Everything works fine but I need to access a specific folder on the macOS via this extension and I cannot do that with the Sandbox on.
I disabled the sandbox but the extension is not loaded anymore in Finder.
Any thoughts on this? Any workarounds?
Finder Sync extensions must be sandboxed. I couldn't find this requirement explicitly documented anywhere, but the following error appears in your system log if it's not sandboxed:
pkd[255]: ignoring mis-configured plug-in at /Applications/Liferay\ Sync.app/Contents/PlugIns/LiferayFinderSync.appex: plug-ins must be sandboxed
If you need to access a folder outside your application's container, you can use temporary exception entitlements like "com.apple.security.temporary-exception.files.home-relative-path.read-only". Note that apps submitted to the Mac App Store using these entitlements will likely be rejected.
For the next version of a NSDocument-based app, I am revising the document parameters, that is, the values in Info.plist > CFBundleDocumentTypes and UTExportedTypeDeclarations. Specifically, I am changing from a flat NSPersistentDocument to a document package (with the help of BSManagedDocument).
The revised app can create new documents, but they appear in Finder with a generic icon, and when I close such a new document and try to re-open it, -[NSDocumentController openDocumentWithContentsOfURL:display:completionHandler:]fails, creating an error in NSCocoaErrorDomain with code 256, description “newDoc.myExtension” could not be handled because MyApp cannot open files of this type, and failure reason MyApp cannot open files of this type.
I understand that there are several significant parameters CFBundleDocumentTypes and UTExportedTypeDeclarations, and these must all be correct or you get this error. In this case, they are correct. I've confirmed this by comparing the Info.plist in my built product with the Info.plist of a different but similar app that works.
I've also tried calling LSRegisterURL() with inUpdate = true from main(), but that did not help.
What might be wrong? I'm running in macOS 10.12.6, building with macOS 10.13 SDK and Xcode 9.
Apparently the problem is in updating the Launch Services database. I copied the new application, with the revised Info.plist, into /Applications, replacing an old version, then launched this copy once. After these two steps, document icons are now correct when I reopened a Finder window, and upon relaunching my new app, it can now reopen its own new documents without error.
UPDATE: Today (macOS 10.13 Beta 8) I had the same problem, but installing the corrected app into /Applications did not work. However, this time, rebuilding the Launch Services database by running the following command in Terminal, and then relaunching my app, did work:
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain u -domain s -domain l -v
A side effect of the above is that some apps will have generic icons in the dock and cmd-tab application switcher until relaunched.
I think that either Launch Services much prefers apps in /Applications over apps in Xcode's DerivedData folder, even if the latter is the only one currently running, or running apps from Xcode's DerivedData do not register at all, or both.
It seems from the documentation that calling LSRegisterURL() should have had the same effect, but apparently not.
How to check if sandboxing is enabled or not at OSX app runtime?
I need it for some assert tests for my library that can be run in different environments.
Finally I have chosen this workaround (because it is simple):
func isSandboxingEnabled() -> Bool {
let environment = NSProcessInfo.processInfo().environment
return environment["APP_SANDBOX_CONTAINER_ID"] != nil
}
This might help
In Finder, look at the contents of the ~/Library/Containers/ folder.
If the Quick Start app is sandboxed, there is now a container folder
named after your app. The name includes the company identifier for the
project, so the complete folder name would be, for example,
com.yourcompany.AppSandboxQuickStart.
The system creates an app’s container folder, for a given user, the
first time the user runs the app.
In Activity Monitor, check that the system recognizes the app as
sandboxed.
Launch Activity Monitor (available in /Applications/Utilities).
In Activity Monitor, choose View > Columns. Ensure that the Sandbox menu
item is checked.
In the Sandbox column, confirm that the value for the Quick Start app
is Yes.
To make it easier to locate the app in Activity monitor, enter
the name of the Quick Start app in the Filter field.
Check that the app binary is sandboxed.
codesign -dvvv --entitlements :- executable_path
I'm using NSUserDefaults to save some data in my application. Where can I find the file where my data is stored during development? It's a normal cocoa app (so no ios/iphone!)
Once it's deployed, it should be available in Library/Preferences/appname.plist, right? But where can I find it while I'm still working on the application?
There is no difference between "development" and "deployment". NSUserDefaults doesn't know whether you did a debug or release build. The location should be ~/Library/Preferences/yourAppIdentifier.plist no matter what.
If you are seeing a difference between development and deployment builds, maybe check the bundle identifier (CFBundleIdentifier) in your app's Info.plist.
Also: if your app is sandboxed, your prefs will end up in the sandbox: ~/Library/Containers/yourAppIdentifier/Data/Library/Preferences/yourAppIdentifier.plist. The documentation claims that the system automatically moves your old preferences file into the sandbox, if necessary, on the first launch of the sandboxed version of the app.