iOS UI test target is missing entitlement icloud-services - xcode

I have an app that uses iCloud. This works fine.
I now tried to write a UI test that checks first if the iCloud account is accessible, i.e. that the user is logged in to iCloud and iCloud is enabled for the app.
To do so, I tried to call (CloudKit is imported)
let container = CKContainer(identifier: kICloudContainerID)
container.accountStatus() { (status, error) in
// …
}
However as soon as I try to access CKContainer (1st line), I get the error
The application is missing required entitlement com.apple.developer.icloud-services
(null)
Of corse, my app has iCloud entitlements set, but such entitlements cannot be set for a test target.
I have read this post. The suggested solutions (disabling breakpoints, toggle iCloud capabilities, clearing out the code signing entitlements) did not work.
Any idea how to solve this problem?
EDIT:
For testing, I created a new Single View App with UI Tests included.
In the app target, I enabled only CloudKit:
In the app delegate, I imported CloudKit, and accessed CKContainer:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let container = CKContainer(identifier: "iCloud.com.zeh4soft.EntitlementUITest")
return true
}
This works.
In the UI Tests, I imported also CloudKit, and added the same line:
func testExample() {
let container = CKContainer(identifier: "iCloud.com.zeh4soft.EntitlementUITest")
}
This does not work, but gives the same error:

I contacted Apple, and they found the solution for a device, but not for a simulator.
I did the following steps:
Setup in Xcode a completely new Single View App project and include UI tests. Call it „EntitlementUITest“.
This will create in the project navigator a folder called „EntitlementUITestUITests“.
Select in this folder „EntitlementUITestUITests.swift“.
There is a function testExample(). Add in this function the line
let _ = CKContainer(identifier: "iCloud.com.yourid.EntitlementUITest")
yourid is e.g. your company name.
This is the statement that causes the run time error if the project has not been prepared as laid out below.
Select in the project navigator the project.
This will display an additional pane with the project and the targets.
There are 2 targets: The main target „EntitlementUITest“ and the UI test target „EntitlementUITestUITests“.
Select the main target „EntitlementUITest“.
In the top bar of the window right of the pane, select „Capabilities“. You will see that you can select iCloud usage.
Now select the test target „EntitlementUITestUITests“. The top bar now does not have „Capabilities“. This means, the setup that allows your UI tests to use iCloud is much more complicated, and has to be done manually.
First, one needs an entitlements file that specifies the capabilities that the app wants to use. I manually created the following file (actually, I copied the entitlements file of the main target and edited it):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.yourid.EntitlementUITest</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudKit</string>
</array>
</dict>
</plist>
I added this file to the project.
In order to allow the UI test target to use iCloud, one needs now a few action in the development center.
In your web browser, open the development center, and open there „Certificates, Identifiers & Profiles“.
The test target is treated as a new app. Thus, it needs a separate app ID.
Open App IDs, and add a new ID „EntitlementUITestUITests“.
It should be an „Explicit App ID“ that uses the bundle ID of your test target, here
com.yourid.EntitlementUITest.
Enable iCloud and Push notifications.
I am not sure if Push Notifications are required, but Apple told me to do so. Probably, you can omit it in the entitlements file and here.
If it is present, please ensure that a valid certificate is specified for the push notification service.
When you enable iCloud, ensure that iCloud.com.yourid.EntitlementUITest is the only one selected among the assigned iCloud containers.
Create next a new development provisioning profile (one that uses your iOS developer certificate) and associate with com.yourid.EntitlementUITestUITests.
Download the profile.
Back in Xcode, select again target „EntitlementUITestUITests“ with tab General.
In the section Signing, uncheck Automatically manage signing, since this does not work.
In Signing (Debug), select in the drop down menu Provisioning profile to import your just downloaded profile. This will also be selected in the Signing (Release) section.
Now the project should build for testing without errors.
Run the testExample. It should run now without run time error.
Conclusion:
It is possible to access a CKContainer in an UI test, but this is incredibly complicated.
Why is this process not as easy as with the main targets?
Maybe too less developers UI test their iCloud apps, otherwise more enhancement requests to Xcode would have been written…
One more thing: If everything was done right, the test runs only on a device, not on a simulator. Apple said, running this test on a simulator gives unpredictable results. For me, it was predictable - it fails always.

Related

Electron app crashes when I ask permission to use camera. Error message asks for string in com.apple.security.device.camera. Shouldn't it be boolean?

I have an Electron app that needs access to the camera. On Windows it works fine but on MacOS it doesn't and even crashes when I try to ask permisson.
When I call the routine to check the permission status (shown bellow) it gives me a not-determined answer.
systemPreferences.getMediaAccessStatus('camera')
Then, to ask for permission (and hopefully show the allow/deny pop-up) I use the following:
const { systemPreferences } = require('electron')
systemPreferences.askForMediaAccess('camera')
But when I do, it instantaneously crashes the app and gives me a long detailed crash report that, among other things, says this:
This app has crashed because it attempted to access privacy-sensitive data without a usage description.
The app's Info.plist must contain an com.apple.security.device.camera key with a string value explaining to the user how the app uses this data.
Additionally, the Info.plist generated in the root of the app instalation has all of the entries needed. I even included the hardenedRuntime as true.
<key>NSCameraUsageDescription</key>
<string>This app needs access to the Camera</string>
<key>com.apple.security.device.camera</key>
<true/>
<key>hardenedRuntime</key>
<true/>
Some final notes...
I was struggling with app signing and finally made it to use a valid certificate to sign during the build. Before that the app did not crash when I asked for the permission. It simply did nothing at all. The crashing started as soon as I managed to sign the App.
I'm using electron-builder to build the .dmg and installing from that. npm run electron:build. When I run the app in dev mode through npm run electron:serve it works perfectly and doesn't even pop the permission pop-up. The access status returns as granted.
Shouldn't com.apple.security.device.camera be a boolean? Everywhere I read about it it is a Boolean. Although the error message asks me to define a string with a description. (which I already tried and did not change anything)
Any ideas on how to solve that?
I already tried to change the Info.plist mannualy. Didn't work. How can I make sure I'm working on the right Info.plist file. There are a few. The one I was using is the largest and seems to be the main one. The others are helpers.
I also tried to manage the permission in the MacOS System Preferences. Did not work either.
Try to add "com.apple.security.cs.allow-unsigned-executable-memory": true
mac: {
....
extendInfo: {
"NSCameraUsageDescription": "some description",
"com.apple.security.device.camera": true,
"com.apple.security.cs.allow-unsigned-executable-memory": true
}
}

Where will get Location Updates feature in XCode?

I can not show/get the "XCode project (Project > Signing and Capabilities > "+ Capability" button) and select the Location Updates" feature in my XCode.
it is in the link
https://pub.dev/packages/geolocator
On iOS you'll need to add the following entries to your Info.plist file (located under ios/Runner) in order to access the device's location. Simply open your Info.plist file and add the following (make sure you update the description so it is meaningfull in the context of your App):
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>
If you would like to receive updates when your App is in the background, you'll also need to add the Background Modes capability to your XCode project (Project > Signing and Capabilities > "+ Capability" button) and select Location Updates. Be careful with this, you will need to explain in detail to Apple why your App needs this when submitting your App to the AppStore. If Apple isn't satisfied with the explanation your App will be rejected.
When using the requestTemporaryFullAccuracy({purposeKey: "YourPurposeKey"}) method, a dictionary should be added to the Info.plist file.
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
<dict>
<key>YourPurposeKey</key>
<string>The example App requires temporary access to the device&apos;s precise location.</string>
</dict>
The second key (in this example called YourPurposeKey) should match the purposeKey that is passed in the requestTemporaryFullAccuracy() method. It is possible to define multiple keys for different features in your app. More information can be found in Apple's documentation.
NOTE: The first time requesting temporary full accuracy access it might take several seconds for the pop-up to show. This is due to the fact that iOS is determining the exact user location which may take several seconds. Unfortunately, this is out of our hands.
you need to click + Capability then select background mode and then select location update

Automatically allow app (built & run by Xcode) to control your computer

I am developing an assistive MacOS app in Xcode / ObjC.
It intercepts keystrokes using event-taps.
When I run it from Xcode, I get:
2019-07-05 06:20:32.423783+0300 mapper[8108:1191874] unable to create event tap. must run as root or add privileges for assistive devices to this app.
2019-07-05 06:20:32.423809+0300 mapper[8108:1191874] No Event tap in place! You will need to call listen after tapEvents to get events.
I have to go to system preferences -> security & privacy -> privacy -> {unlock the padlock putting my admin password} -> {locate, uncheck and recheck my executable from the list}, like so:
Every time I modify a line of code and run again I have to go through this process of checking and unchecking.
It is a very clumsy development cycle.
Is there any way to avoid this?
This project was using a 4-year-old Xcode project file.
Starting with a fresh Cocoa App template and copying the files in, the first time I build and run I am now automatically presented with:
... which takes me to the preferences pane and previous screenshot. Subsequent rebuilds do NOT require toggling the setting in this dialog. It is only if I "Clean Build Folder" that this process repeats.
My guess is that the improved behaviour may be because the new project is derived from a Cocoa App template (which inherits its base object from NSApplicationDelegate, whereas the old one inherited from a Commandline App template (and I had to manually manage the run loop with CFRunloop).
Getting mouse coordinates on Mojave contains an answer offering instructions on how to add a row to entitlements.plist:
The entitlement that allows an application to use the Accessibility API is the com.apple.private.tcc.allow entitlement (with a value of kTCCServiceAccessibility). As you can probably guess from the name it is only allowed on Apple signed binaries.

Using OSX Security-Scoped Bookmarks in a Firemonkey app

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?

How can I edit entitlements for xcp-services in Xcode 4 for App-Sandboxing

I created an App and started to sandbox it. Now I did privilege separation using xpc-services. I downloaded the "SandboxedFetch" example from Apple, which shows two xpc-services like
an application (application-icon). In my App the xpc-services show the "pluggin"-icon. The summary tab in the project setting for my xpc-service is not available, which means that I cannot configure the entitlements like I can do on the main app. I copied a custom made entitlements-file to the xpc-service and referenced it in the project settings. But the service is running always without privilege restrictions applied to the service.
Do I need a new certificate for the service? If my app is named "com.mycompany.app" and my service is named "com.mycompany.app.service" I cannot apply my app certificate to the service. I am somehow confused about this sandboxing stuff. Do I need a new certificate for my xpc-service? If not, how can I apply the entitlements to it?
This seems to be a "bug" of Xcode. Maybe The XPC-service-template will have a summary-tab in future. Now you can create a entitlements plist file manually or use the application entitlement file and copy it into your xpc-service folder. In project settings type the path and name for this new entitlement file into the entitlement field. Change your entitlements inside this file. Sandboxing will run now.
For codesigning, select your "3rd Party Mac Developer" certificate (and not the Mac Developer certificate).

Resources