Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update exported UTIs #27

Closed
alexstaravoitau opened this issue May 23, 2019 · 8 comments
Closed

Update exported UTIs #27

alexstaravoitau opened this issue May 23, 2019 · 8 comments

Comments

@alexstaravoitau
Copy link

alexstaravoitau commented May 23, 2019

Hi,

I'm a developer of another app working with Jupyter Notebook file format (Juno), and I have several suggestions regarding UTIs. As you probably know, iOS doesn't handle ambiguity in UTI association very well right now, hence there are issues like this one: #23. Although Jupyter Notebook format is not in the list of Apple's system-declared or imported UTIs, it is still a public format, so it would be much easier if we take a consistent and coordinated approach in managing it, to improve experience for users who will have both our apps installed on their devices. Here are several suggestions:

  1. Change UTI slightly. You've declared it as public.jupyter, which seems a bit ambiguous. I think something like public.jupyter-notebook will be more future-proof in case Jupyter products start exporting other file formats.
  2. Change exported type conformance. You've declared Jupyter notebook type conforming to public.source-code, although I'd argue that it should rather be public.data. My reasoning is: notebooks contain much more than source code, and although I understand that they are, in fact, simple text-based JSON files, semantically they can encode arbitrary binary data.
  3. Provide type icon. Additionally, if notebook UTI is declared conforming to a text-based type, iOS will ignore provided type icon and will try to create a preview based on file's content — which is meaningless in case of Jupyter notebooks, as whatever source code happens to be in them, it is wrapped in JSON anyway. If it's declared as a public.data format, you can provide a file icon for iOS to display, which will be much more user-friendly.
  4. Use Alternate handler rank. As per Apple documentation, Owner rank should only be used for file formats that you declare yourself (i.e. your internal file formats). Jupyter notebook file format is public, and therefore both Carnets and Juno should use Alternate rank, otherwise it will result in conflicts — which, as noted earlier, iOS doesn't handle very well right now.

This is what it will look like with icons, instead of previews based on text-based file conformance:

1 2
Grid List

I'm attaching a sample Info.plist file with suggested settings, as well Jupyter notebook type icons I've prepared as per Apple requirements and Jupyter design guidelines. Were you to adopt these changes, you can simply add these images to your bundle (not to an asset catalog), copy settings into your Info.plist, and it should just work (or let me know if you want me to submit a PR for it).

Info.plist

<?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>CFBundleDocumentTypes</key>
        <array>
            <dict>
                <key>CFBundleTypeIconFiles</key>
                <array>
                    <string>document_icon_29.png</string>
                    <string>document_icon_58.png</string>
                    <string>document_icon_64.png</string>
                    <string>document_icon_320.png</string>
                </array>
                <key>CFBundleTypeName</key>
                <string>Jupyter Notebook</string>
                <key>CFBundleTypeRole</key>
                <string>Editor</string>
                <key>LSHandlerRank</key>
                <string>Alternate</string>
                <key>LSItemContentTypes</key>
                <array>
                    <string>public.jupyter-notebook</string>
                </array>
            </dict>
        </array>
        <key>UTExportedTypeDeclarations</key>
        <array>
            <dict>
                <key>UTTypeConformsTo</key>
                <array>
                    <string>public.data</string>
                </array>
                <key>UTTypeDescription</key>
                <string>Jupyter Notebook</string>
                <key>UTTypeIconFiles</key>
                <array>
                    <string>document_icon_29.png</string>
                    <string>document_icon_58.png</string>
                    <string>document_icon_64.png</string>
                    <string>document_icon_320.png</string>
                </array>
                <key>UTTypeIdentifier</key>
                <string>public.jupyter-notebook</string>
                <key>UTTypeTagSpecification</key>
                <dict>
                    <key>public.filename-extension</key>
                    <array>
                        <string>ipynb</string>
                    </array>
                </dict>
            </dict>
        </array>
    </dict>
</plist>

Document icons
document_icons.zip

@holzschu
Copy link
Owner

Hi Alex,
all of this makes sense. I'm going to incorporate the changes immediately.
I'm terribly sorry about the "Owner" part. That was not intentional. I thought I had it set to "Default" or "Alternate".

@alexstaravoitau
Copy link
Author

Great, thank you! And no worries at all, frankly, I think iOS could have handled conflicting UTIs in a more graceful manner. 🙂

@holzschu
Copy link
Owner

By the way, somewhere in the TODO list, there is "thumbnail generation". That would replace the icons, once it's done.

@alexstaravoitau
Copy link
Author

That makes sense, yes. Personally, I decided against thumbnails in Juno for now, as supporting them might get tricky with different colour themes and/or dark mode.

@alexstaravoitau
Copy link
Author

Hi @holzschu, I've been watching WWDC18 session related to declaring document types, and now I think I got a couple of things wrong:

  1. LSHandlerRank should be Default for both Carnets and Juno (as they are both editors).
  2. Jupyter notebook UTI should be imported rather than exported, i.e. declaration is the same, but it should be declared under UTImportedTypeDeclarations key rather than UTExportedTypeDeclarations (they seem to suggest this for public UTIs which are not system-declared).

Sorry for confusion earlier, and let me know if I've missed something — as frankly I'm not 100% sure I got it right this time either. The session I'm referring to is: https://developer.apple.com/videos/play/wwdc2018/216.

Updated Info.plist

<?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>CFBundleDocumentTypes</key>
        <array>
            <dict>
                <key>CFBundleTypeIconFiles</key>
                <array>
                    <string>document_icon_29.png</string>
                    <string>document_icon_58.png</string>
                    <string>document_icon_64.png</string>
                    <string>document_icon_320.png</string>
                </array>
                <key>CFBundleTypeName</key>
                <string>Jupyter Notebook</string>
                <key>CFBundleTypeRole</key>
                <string>Editor</string>
                <key>LSHandlerRank</key>
                <string>Default</string>
                <key>LSItemContentTypes</key>
                <array>
                    <string>public.jupyter-notebook</string>
                </array>
            </dict>
        </array>
        <key>UTImportedTypeDeclarations</key>
        <array>
            <dict>
                <key>UTTypeConformsTo</key>
                <array>
                    <string>public.data</string>
                </array>
                <key>UTTypeDescription</key>
                <string>Jupyter Notebook</string>
                <key>UTTypeIconFiles</key>
                <array>
                    <string>document_icon_29.png</string>
                    <string>document_icon_58.png</string>
                    <string>document_icon_64.png</string>
                    <string>document_icon_320.png</string>
                </array>
                <key>UTTypeIdentifier</key>
                <string>public.jupyter-notebook</string>
                <key>UTTypeTagSpecification</key>
                <dict>
                    <key>public.filename-extension</key>
                    <array>
                        <string>ipynb</string>
                    </array>
                </dict>
            </dict>
        </array>
    </dict>
</plist>

@holzschu
Copy link
Owner

Hi @navoshta,
I agree with you that "Default" makes more sense than "Alternate".

About "Imported" vs. "Exported", none of the definitions do completely apply to our apps, although I agree with you that Public UTIs that are not system-declared should be Imported according to the WWDC presentation. With UTIs, there is also the difference between what the documentation says and what the system actually does.

Let me give it a try.

@alexstaravoitau
Copy link
Author

alexstaravoitau commented May 26, 2019

I've experimented a bit with several combinations of apps installed, and now I think that in our case it's safer to declare it as an exported type.

That's purely because Jupyter notebook UTI is not globally defined, and iOS doesn't handle clashing of different UTIs declared for same file extensions well. It seems that under current implementation of file handling in iOS, if another app claims notebook extension with a different UTI, both Juno and Carnets may not be able to open notebooks at all, or at least so my tests show. 🤷‍♂️

For instance, this is how this app declares its UTIs:

Screenshot 2019-05-26 at 21 10 44

@holzschu
Copy link
Owner

I also remember something similar from my previous experiments. So exported it is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants