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.
Related
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.
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>
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 =)
Background
I'm learning Objective-C and Cocoa, and I thought creating simple programs to answer my needs would be a nice thing. I already have a solid .NET C# background, some Python knowledge, and a little of C.
One of my "simple first app" I tried to do is a simple QuickLook plug-in for Arduino's sketch files. I thought it would be a simple task to accomplish since these files are plain text C-like scripts, the only "different" thing is they have a .pde extension.
I uploaded the project on GitHub at ArduinoQuickLook as a reference (the first commit contains a vanilla Xcode 4.1 QuickLook plugin-project).
What I found
Looking around the net I found these resources:
QLStephen
QLColorCode
Introduction to Quick Look Programming Guide
What are my problems
Both of them use GeneratePreviewForURL.m and GenerateThumbnailForURL.m files, but when I created the project in Xcode 4.1 it created GeneratePreviewForURL.c and GenerateThumbnailForURL.c (note .c instead of .m).
Both QLStephen and QLColorCode use #import <Foundation/Foundation.h> in their GeneratePreviewForURL.m and GenerateThumbnailForURL.m files, but if I try to #import it it yields to many errors. (Maybe because my files are .c instead of .m?)
It's not clear to me how I declare which files my plug-in will handle, I understood I need to change ArduinoQuickLook/ArduinoQuickLook-Info.plist (row 14) but what I have to write there? Something like cc.arduino.pde?
This tutorial on creating a Quicklook plugin explains things nicely, but to summarise:
Point 1 and 2 are related - for some strange reason the Quicklook plugin template only contains .c files - as such, importing the Obj-C Foundation.h header causes errors.
You should just be able to rename the files from .c to .m and it will work as expected.
It's not clear to me how I declare which files my plug-in will handle
You need to do two things - one is say which UTI (Uniform Type Identifier) your plugin handles (e.g cc.arduino.pde), by changing the line you mention:
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>QLGenerator</string>
<key>LSItemContentTypes</key>
<array>
<string>cc.arduino.pde</string>
</array>
</dict>
</array>
...but you also have to describe that UTI (mostly so it can map the file-extension to that UTI)
There are two slightly different ways to declare UTI's, [as "Declaring New Uniform Type Identifiers"] describes:
Your UTI declarations must be either imported or exported:
An exported UTI declaration means that the type is available for use by all other parties. For example, an application that uses a proprietary document format should declare it as an exported UTI.
An imported UTI declaration is used to declare a type that the bundle does not own, but would like to see available on the system. For example, say a video-editing program creates files using a proprietary format whose UTI is declared in its application bundle. If you are writing an application or plugin that can read such files, you must make sure that the system knows about the proprietary UTI, even if the actual video-editing application is not available. To do so, your application should redeclare the UTI in its own bundle but mark it as an imported declaration.
For a Quicklook plugin, you probably want an "imported" UTI declaration, in which you would add something like this to your Info.plist:
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeIdentifier</key>
<string>cc.arduino.pde</string>
<key>UTTypeReferenceURL</key>
<string>http://www.example.com</string>
<key>UTTypeDescription</key>
<string>Arduino PDE file</string>
<key>UTTypeConformsTo</key>
<array>
<string>public.c-source</string>
<string>public.text</string>
</array>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>pde</string>
</array>
</dict>
</dict>
</array>
Here is the source for a project that provides QuickLook for Processing and Arduino .pde files: https://github.com/kroko/ProcessingQL I know this question is a year old, but this project might be helpful for anyone else attempting this.
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.