Default container on iCloud not working for key-value storage - xcode6

Somewhere in the change from Xcode 5 to Xcode 6, and the changes online to the iCloud management system, I lost the ability to store data into key-value storage in iCloud. More specifically, now, both:
[[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
and
[NSFileManager defaultManager].ubiquityIdentityToken
now both return nil. Previously (at least) URLForUbiquityContainerIdentifier returned non-nil.
I tried the answers given here: Why ubiquityIdentityToken returns nil? and here https://devforums.apple.com/thread/229509 but no joy.

I have found a fix to this. I first tried a sample project with Xcode 6, targeting iOS6 (I need to maintain iOS6 compatibility). I had these settings under Capabilities:
It seems like the default container setting is not working with just key-value storage. That is, with settings as above, ubiquityIdentityToken returns nil.
I next tried checking the CloudKit box, and then specifying a custom container. That might have worked except for my iOS6 compatibility issue. CloudKit doesn't work on iOS6.
I then tried checking the iCloud Documents box (hacking my way to greatness? ;)):
This causes ubiquityIdentityToken to return non-nil! And when I make this change in my actual application, as opposed to this test application, my key-value storage works again! (It does also work on iOS8.1).
The relevant parts of my entitlement file are now:
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.$(CFBundleIdentifier)</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudDocuments</string>
</array>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>iCloud.$(CFBundleIdentifier)</string>
</array>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>

Related

File icons getting changed to App icon in macOS Catalina

I have a Mac app that opens office files(.doc, .xls, etc.) and I need to show custom icon for these supported files.
I used to achieve by adding the supported UTI types in CFBundleDocumentTypes and assign my custom icns icon. Also set my app as the default app which opens these file types.
Now this approach worked flawlessly until macOS Catalina beta, even with Microsoft apps being present along with my app. In macOS Catalina beta onwards, I am seeing my app icon in place of all the file icons.
I tried clearing icon cache and even relaunching Finder, but to no avail.
Later on I even tried by adding the UTI types under UTExportedTypeDeclarations and UTImportedTypeDeclarations.
Is this a bug with Catalina Beta? Or anything I can do to get this working.
My plist has UTExportedTypeDeclarations looking like this. UTImportedTypeDeclarations and CFBundleDocumentTypes have similar values.
<key>UTExportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>org.openxmlformats.spreadsheetml.sheet</string>
<string>org.openxmlformats.openxml</string>
<string>public.composite-content</string>
</array>
<key>UTTypeDescription</key>
<string>Excel Open XML spreadsheet</string>
<key>UTTypeIconFile</key>
<string>custom.icns</string>
<key>UTTypeIdentifier</key>
<string>com.microsoft.excel.openxmlformats.spreadsheetml.sheet</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>com.apple.ostype</key>
<string>XLSX</string>
<key>public.filename-extension</key>
<array>
<string>xlsx</string>
</array>
</dict>
</dict>
</array>
It looks like macOS 10.15 changed the way how the corresponding icon for a type is resolved.
I found a way how to get proper document icons for my app on Catalina:
Previously I only had an icon defined for the CFBundleTypeIconFile key in my CFBundleDocumentTypes dictionaries. But since Catalina, the system uses the LSItemContentTypes array to find an exported UTI and then uses the icon of that UTI (defined via the UTTypeIconFile).
If the LSItemContentTypes array contains types that are not known to the system yet (= newly introduced custom types), those types must also be exported by defining dictionaries in UTExportedTypeDeclarations.
This works for my case because I use a custom file format with its own UTI.
For the case you are describing, where existing UTIs are used, I am not sure if it is still possible to override the icons of UTIs that you don't "own".
I think the correct way to define custom icons for 3rd party types would be to define dictionaries in the imported types array (UTImportedTypeDeclarations). In that case the system should choose your custom icon as long as no other app declares ownership of an UTI by exporting it. I suppose that the icon of the app that is set as Default application for a type wins in the case where 2 or more apps claim ownership for it (Haven't tried that).
Another issue I ran into was, that the icon file assigned to UTTypeIconFile can't come from an Asset Catalog (this worked for CFBundleTypeIconFile). It needs to refer to an .icns file in the Resource folder in your bundle.
Existing .iconset folders from the Asset Catalog can be converted to icns with the following command:
iconutil --convert icns iconname.iconset
I am not sure if this intended behavior or if this is just a bug in the Asset Catalog compiler build phase of Xcode 11. I filed a bug via Feedback Assistant.
I also have this issue. Tried empty project and reproduced it with bundled macOS applications, so it's mostly safe to assume this is a bug in macOS Catalina.
As trojanfoe suggested in a comment the only thing to do right now is reporting it to Apple via the Feedback Assistant.
Thomas Zoechling refers to another issue that may affect earlier macOS versions too, but does not solve the main issue here.

application:handleOpenUrl: is appending the wrong extension to the file

When I attempt to export a file to my app, from within Mail, it is sending the file to export with the wrong extension.
Here's an example:
I e-mail an attachment to myself
Open the attachment in Mail
Export the file and open with my app
The url passed to application:handleOpenUrl: is wrong
The name of the file I am attempting to export is named 'NSIS.nsi' (without quotes). Mail (iOS?) renames the file to 'NSIS.4th' when it passes it back to my app via application:handleOpenUrl. One thing I did notice is that the first extension (item) within the Exported Type UTIs > Item 0 > Conforms to UTIs > Equivalent Types > public.filename-extension is '4th' (again, without quotes).
Another thing to note is that I do have the 'nsi' extension in the same public.filename-extension array.
And yet another thing to note is that this appears to happen only with the 'nsi' extension. I haven't tested all of the extensions my app supports (there's 92 of them. I got tired after about the 40th one). But this extension in particular is having issues.
By the way here is the code sample... it really is this simple. The NSURL passed contains the wrong extension. This will log the url passed -- which is the wrong one. So, I can say for certain that there is nothing in my app that is doing something with the NSURL before it gets passed to application:handleOpenUrl:.
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
NSLog(#"url: %#", url);
...
}
I also don't know if this helps, but in the Mail app it does show my app's icon next to the NSIS.nsi file. And yes, the file's name displays as 'NSIS.nsi' within Mail.
Update 2
I was able to confirm that changing the first extension to '5th' (for kicks) and then imported the 'NSIS.nsi' file it indeed changed the file extension to 'NSIS.5th'. I think what's happening is I'm defining the UTIs that my app supports incorrectly. All I want to do is say, "Hey, iOS, I support all of these file extensions. Don't change the name. Just give me the file and let me do what I need to do with it." In reality I just want my app to support all types of text files (text, utf8, utf16, etc). That's the end result.
The problem is, when I tell iOS that I support plain.text, utf8 and utf16 it still won't display my app in the list of apps that can open a file unless I specifically set the extension in the public.filename-extension array. I wish there was just an all encompassing "I support all text files" configuration value in the plist.
One other thing I noticed is that the issue does affect other file extensions. For example, I have a file that I am exporting from Mail to my app called 'Ada.adb'. iOS is returning the file as 'Ada.ada' (notice the 'a' at the end instead of a 'b'). This makes sense... I don't even have 'ada' in my list of file extensions within the public.filename-extension array or anywhere in my app for that matter.
Update 3
I figured out how to support all types of public.text files.
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeIconFiles</key>
<array>
<string>icon_buffer_ipad_small.png</string>
<string>icon_buffer_iphone_small.png</string>
</array>
<key>LSItemContentTypes</key>
<array>
<string>public.text</string>
</array>
<key>NSExportableTypes</key>
<array>
<string>public.text</string>
</array>
<key>CFBundleTypeName</key>
<string>Source File</string>
<key>LSHandlerRank</key>
<string>Default</string>
</dict>
</array>
Essentially you need to include the NSExportableTypes in addition to the LSItemContentTypes. I'll add an update when I figure out how to make other "public.text" file types such as 4th, md, and the huge list of other file types that are public.text, associated to your app. Hopefully this won't be necessary. Regardless, I'll update with my findings.
Update 4
You guys aren't going to believe this. This issue affects every app I have tested this with. Essentially, when I attempt to export the 'Ada.adb' file it exports the file as 'Ada.ada' to every application. Wow! I'm going to figure out how to file this bug with Apple. Unless, of course, this is expected behavior!
Small update: I filed the bug to Apple. Bug ID# 12802236
I do not recall this occurred in iOS 5. I believe this is a regression introduced in iOS 6.
If the file name doesn't change, how about change its extension manually after - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url receive the url? Of course, you have to know what the right extension is.

Finder NSService Context Menu errors with: Cannot find service provider for selector

UPDATE 1: Getting closer
Someone on IRC mentioned that my NSPortName should be my application, not Finder. I changed this and now I'm seeing a log message in my app when the context menu is selected:
Cannot find service provider for selector shareFile:userData:error: or shareFile:: for service shareFile
This seems odd considering I do have such an object registered.
I am trying to setup an NSService contextual menu for Finder to trigger my app on certain files.
The files have extension *.acxx and the action is simply to share. Note: I've changed all references of the bundle to be generic for this posting: com.mycompany.myproject.
My NSServices section of my infoPlist looks like this: (Note i have Document TYpes/UTIs setup for *.acxx as well)
<key>NSServices</key>
<array>
<dict>
<key>NSRequiredContext</key>
<dict>
<key>NSTextContent</key>
<array>
<string>URL</string>
<string>FilePath</string>
</array>
</dict>
<key>NSSendFileTypes</key>
<array>
<string>com.mycompany.myproject.acxx</string>
</array>
<key>NSPortName</key>
<string>Finder</string>
<key>NSMessage</key>
<string>shareFile</string>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>Share with myproject</string>
</dict>
</dict>
</array>
I have an object setup in my code that has the following method defined:
- (void)shareFile:(NSPasteboard*)pboard userData:(NSString*) error:(NSString**)err
And I register this elsewhere in my code:
// Register services
if (self.shareSvcMgr == nil)
{
self.shareSvcMgr = [[ACAShareServiceManager alloc] init];
}
[NSApp setServicesProvider:self.shareSvcMgr];
NSUpdateDynamicServices();
Now, when I run the app and then make sure it's registered with pbs, it looks fine:
/System/Library/CoreServices/pbs -debug en|grep -i myproj
NSBundleIdentifier = "com.mycompany.myproject";
NSBundlePath = "/Users/me/Library/Developer/Xcode/DerivedData/myproject-gihhiqhnzhwqbchflymzyafwxvws/Build/Products/Debug/myproject.app";
default = "Share with myproject";
"com.mycompany.myproject.acxx"
So when I go to the Finder and click on a *.acxx file, sure enough in Finder -> Services, my menu item Share with myproject shows up.
PROBLEM:
All is fine and dandy right? Well no. When I click 'share with myproject', nothing happens. I have a breakpoint setup in the shareFile method and the program is running and yet nothing happens, it never gets hit, etc.
I had read that I could debug the Finder using -NSDebugServices but I can't seem to get that to work right. I've executed:
/System/Library/CoreServices/Finder.app/Contents/MacOS/Finder -NSDebugServices com.mycompany.myproject
This seems to start up a process but I get no Finder window to try to interact with.
I'm not sure where to go next. The idea of course is to pass the filename or file contents to my application when Share is sent and then I can do what is needed with it from there.
Are the SendFileTypes not setup right or something for this model? Any help appreciated. Thanks
I ran into the same issue and was able to resolve this by deleting derived data.
I think what happened was that I was trying to test something by creating a dummy app, and I used the same message name for the service. By deleting the derived data from the dummy app, everything started to work.
You should be able to find the derived data in a directory somewhere in this path:
~/Library/Developer/Xcode/DerivedData/
Remove the old stuff, and it might resolve it for you.
Alright. Someone on IRC pointed out that my method definition was missing something:
- (void)shareFile:(NSPasteboard*)pboard userData:(NSString*) error:(NSString**)err
It was missing a variable definition (which can totally mess up the selector matching). So it should have been this:
- (void)shareFile:(NSPasteboard*)pboard userData:(NSString*)***udata*** error:(NSString**)err
Once I changed that, the selector finally started getting called =)

Sandboxing my App with Scripting Bridge to send email

I'm using a scripting bridge for sending mails from my Mac App. Now I need to sandbox the app and sending mails is not longer working while sandboxing is enabled.
Does anybody know how to fix that?
Thanks,
Andreas
Code:
`
/* create a Scripting Bridge object for talking to the Mail application */
MailApplication *mail = [SBApplication applicationWithBundleIdentifier:#"com.apple.Mail"];
/* create a new outgoing message object */
MailOutgoingMessage *emailMessage =
[[[mail classForScriptingClass:#"outgoing message"] alloc]
initWithProperties:
[NSDictionary dictionaryWithObjectsAndKeys:
[self.subjectField stringValue], #"subject",
[[self.messageContent textStorage] string], #"content",
nil]];
/* add the object to the mail app */
[[mail outgoingMessages] addObject: emailMessage];
...
`
You can't use the ScriptingBridge with Sandboxing enabled. Please file a bug report. This is what Apple recommends, if Sandboxing is a problem for you and there are no other solutions. They might add entitlements (not just temporary exceptions) for the ScriptingBridge, but as of now there is no further information available.
There are Entitlements Keys, especially the com.apple.security.temporary-exception.apple-events key, you can add to your Entitlements.plist file, but the key for Apple Events is a temporary exception.
Unfortunately, I was unable to get ScriptingBridge working even with the correct entitlements set. I hope you're luckier than me.
Apple is going to require Sandboxing for all apps submitted to the Mac App Store starting on the 1st of November!
com.apple.security.temporary-exception.apple-events
Add this code to your Entitlements.plist, I tested It's ok.I can get selected mail from Mail now.
<key>com.apple.security.temporary-exception.apple-events</key>
<array>
<string>com.apple.mail</string>
</array>
I have modified Apple's SBSendEmail sample application to be Sandboxed and can successfully compose an e-mail. It appears that it is not possible to send the e-mail, but at least you could set everything up for the user just to press send.
https://github.com/Whiffer/SBSendEmail
of mac os x 10.8 and later, it has changed:
<key>com.apple.security.scripting-targets</key>
<dict>
<key>com.apple.mail</key>
<array>
<string>com.apple.mail.compose</string>
</array>
</dict>

How do I launch a non-document-based Cocoa application by dropping files on it?

The only way I've been able to get this working is with a document-based application (which this app isn't). In my non-document-based application I've defined the supported Document Types (from the Properties tab of the Target info window) and my AppDelegate implements application:openFile: and application:openFiles:. That enables dropping files on the application's Dock icon when it has already been launched but not its icon in the Finder (launched or otherwise). What am I missing?
Updated
As requested, my Document Types array:
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>nsf</string>
<string>nsfe</string>
</array>
<key>CFBundleTypeName</key>
<string>NSF Soundtrack</string>
<key>CFBundleTypeRole</key>
<string>None</string>
<key>LSTypeIsPackage</key>
<false/>
<key>NSPersistentStoreTypeKey</key>
<string>InMemory</string>
</dict>
</array>
Two parts of this make me suspicious:
<key>CFBundleTypeRole</key>
<string>None</string>
Don't you mean this to be Viewer at least?
<key>NSPersistentStoreTypeKey</key>
<string>InMemory</string>
What are you trying to do here? Why would your on-disk file be specified as an in-memory Core Data persistent store? If you want to just hoist the whole thing into memory when you load it, that's called Binary or XML, not InMemory.
I also recommend that you define UTIs for your document types, not just extensions.
You should also double-check what Launch Services thinks is going on by using lsregister. Sometimes the problem is that you have multiple versions of your app lying around and Launch Services hasn't found the one you think it should have. You can look the Launch Services database like this:
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -dump
This should work on 10.5 and 10.6. 10.4 has lsregister in a different place. I usually use locate to find it rather than trying to memorize it.
In your Target settings, go to the Properties tab and add to the Document Types table.