3

Ideally, I'd like to see these comments in the iOS files app.

7

While it appears that iCloud Drive does actually sync file comments, the Files app unfortunately has no built-in way to read these. Instead, you'll need to use a third-party app to achieve this. The following is a free, fairly straightforward (but limited—see below) approach using Scriptable:

  1. Install Scriptable from the App Store

  2. Launch Scriptable and press the + button in the top right to create a new script

  3. Paste the following:

const file = args.fileURLs[0]
const fm = FileManager.iCloud()
if (!fm.fileExists(file)) {
    QuickLook.present('Invalid file')
    return
}
fm.downloadFileFromiCloud(file)
const comment = fm.readExtendedAttribute(file, 'com.apple.metadata:kMDItemFinderComment')
if (comment === null) {
    QuickLook.present('Comment not found or failed to parse.')
    return
}
trailer = comment.slice(comment.length - 32, comment.length)
String.prototype.hexSlice = function (start, end) {
  return parseInt(this.slice(start, end).split('').map(c => ('0' + c.charCodeAt(0).toString(16)).slice(-2)).join(''), 16)
}
offsetTableStart = trailer.hexSlice(24, 32)
offsetTableOffsetSize = trailer.hexSlice(6, 7)
topObjectStart = comment.hexSlice(offsetTableStart, offsetTableStart + offsetTableOffsetSize)
topObjectLength = comment.hexSlice(topObjectStart, topObjectStart + 1) & 0x0F
if (topObjectLength === 0x0F) {
  lengthPower = comment.hexSlice(topObjectStart + 1, topObjectStart + 2) & 0x0F
  charsStart = topObjectStart + 2 + Math.pow(2, lengthPower)
  topObjectLength = comment.hexSlice(topObjectStart + 2, charsStart)
} else {
  charsStart = topObjectStart + 1
}
topObject = comment.slice(charsStart, charsStart + topObjectLength)
QuickLook.present(topObject)
  1. Tap the settings/"toggle switches" icon screenshot of icon, tap "Name," and give the script a name (e.g., "File Comments")

  2. Tap "Share Sheet Inputs" and select "File URLs" (then navigate back out by pressing Back > Done)

Now, whenever you want to view the comment for a file in the Files app, you can:

  1. Select the file and hit the Share icon

  2. Choose the "Run Script" action and tap the script you just created (the file comment should appear in an overlay)

Unfortunately, you'll probably find that the script fails for certain comments. This is because Scriptable can't handle certain characters, and unfortunately there's no way to work around this. (The (brief) technical explanation is that Scriptable attempts to read all extended attributes as strings, but since the comment is actually binary data, it seems to stumble on certain bytes. I don't fully understand why it fails when it does—it's not just on Unicode strings—but the whole approach is a bit hacky to begin with.)

An alternative, much more robust approach would be to use Pythonista ($9.99) to directly access the extended attributes and avoid Scriptable's problematic string conversions. Here's a Python script that does what you want (create the script in Pythonista, then press the settings cog and add it under Share Extension Shortcuts):

import appex
import console
import plistlib
import ui

from objc_util import *

def main():
    fp = appex.get_file_path()
    if not fp:
        console.hud_alert('Error: Invalid file', 'error')
        return
    extd_attrs = ObjCClass('NSFileManager').defaultManager().attributesOfItemAtPath_error_(fp, None)['NSFileExtendedAttributes']
    if extd_attrs is None:
        console.hud_alert('No extended attributes found', 'error')
        return
    attr_data = extd_attrs['com.apple.metadata:kMDItemFinderComment']
    if attr_data is None:
        console.hud_alert('No comment found', 'error')
        return
    attr_bytes = nsdata_to_bytes(attr_data)
    comment = plistlib.readPlistFromBytes(attr_bytes)
    tv = ui.TextView()
    tv.text = comment
    tv.editable = False
    tv.present()
  
main()

(Note that os.getxattr is broken in Pythonista, hence the Objective-C workaround.)

For those who are interested, here are some references for the (very, very rough) manual bplist parsing I implemented in JavaScript:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .