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
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.
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.
On the Apple Developer website it states:
To deliver an OS X app extension, it’s recommended that you submit
your containing app to the App Store, but it’s not required.
However, to make a Today Extension from what I understand: I must create a Cocoa OS X application then add a "Today Extension" as a target. However, I do not want/need this main containing app. All I need is the extension.
So, how do I create an extension without a containing app? Even though technically I need to develop the containing app to create an extension target.
I think you are misreading this: what they are saying is that an OS X app extension may be distributed OUTSIDE the app store - if you continue reading, you will see the following:
If you distribute an OS X app extension outside of the Mac App Store, Gatekeeper prevents the extension from running until the user opens and approves the containing app. Further, if you code sign with a certificate other than your Developer ID, users must explicitly override Gatekeeper to open the containing app to make your extension available.
All extensions, at this writing, must be part of a container app and Apple devotes a large number of pages describing how, why, etc. My understanding (and work on extensions) is that all extensions must be part of a containing application. If there is a way to do so without the container app, Apple has not indicated it.
I am trying to submit an iOS App + Apple watch extension to the App Store.
I selected the app as my target, created an archive (Product > Archive).
I clicked on the archive in Window > Organizer and clicked Export (I am using the Application loader to submit the app).
I selected "Save for iOS App Store Deployment"
In the next window (in Binary and Entitlements), I expected to see the the app and the watchkit extension. But I see only the app. Why is this ? Is it expected ? Or did I miss some setting change somewhere ?
Because this is a very special piece of application, and you can not just simply submit the application like the way you used to do.
The differences are the total number of provisioning profile. Without WatchKitExtension, a provisioning profile is enough. However, you have to apply for three different application identifiers and three different provisioning profile in order to let the Xcode to detect you actually have your phone app, watch app and watch extension.
So, what you need to do is really simple. Just create two more app identifiers based on the bundle identifier you saw from the WatchApp target and WatchExtension target. Then, create two more provisioning profile. Last step, import them into your Xcode. And you are good to go.
I have an OS X app targeting 10.7 (Lion) platform. I use XCode 4.4 on a development machine where iCloud is enabled. The OS X version on this machine is 10.8 (Mountain Lion).
I have an APP ID that I enabled iCloud using the Developer Certificate Utility: com.company.appname. The utility shows a green tick next to iCloud label under description of the App ID.
From XCode Target/Summary tab I enabled Entitlements and added iCloud Container com.company.appname. Of course internally it is preceded by the team id in the Entitlements file: teamid.com.company.appname.
I also have a valid (green ticked) provisioning profile on my Mac with the same id:teamid.com.company.appname.
Derived Data locations is set to Relative from XCode/Preferences.
The app builds OK. But when I run it I get "Could not launch "appname". Permission denied." error.
If I remove the iCloud container id com.company.appname from iCloud Containers list box under Entitlements and build the app, it runs OK. But of course I cannot access iCloud container enabled for the app.
I have been working on this problem for the past 24 hours. I have read the guides; Developing for the App Store, App Sandbox Design Guide, and Entitlement Key Reference inside out. Yet I am stuck. What went wrong?
I am desperate and I will be grateful if you can help me.
I think the most likely problem is that the AppID, the Entitlement and your provisioning profile do not match each other.
This can happen easily if you experiment a lot with those settings. It should work right out of the box if you create a fresh new project with valid settings, but it might get corrupted if you convert, change or edit existing projects.
Do not forget about the 10-digit prefix of your app bundle id. This is required, esp. for iCloud Key-Value-Storage!
Log into developer.apple.com, check the AppIDs tab
Create an AppID if necessary
Check the iCloud settings for this app
Note down the exact app identifier in the form ABCDE01234.com.domain.app
Switch back to Xcode, update your Provisioning Profiles and Entitlements in the "Teams" section of the "Devices" Tab in the Organizer
Go to the project settings, select the app target and search for "Code Sign"
Make sure the correct code signing identity is selected (see the application identifier above)
Go to the summary tab and put in your app ID
Open the Entitlements file and check if the right ID is in there as well.
Then it should work.
Hopefully.
Edit: thought it would be nice to add the link to the app id center:
https://developer.apple.com/certificates/index.action#bundlelist