seb*_*dev 5 macos applescript objective-c recent-file-list
我目前正在构建AppleScript应用程序.(请注意,这是一个普通的AppleScript"应用"通过使用AppleScript编辑器创建一个AppleScript,然后保存该脚本为应用程序创建).对于这个应用程序,我需要知道当前用户最近打开的文件的文件路径.到目前为止,我尝试了很多不同的方法,但似乎都没有给我提供我需要的信息.
我尝试过以下方法:
com.apple.recentitems.plist文件,但包含在此文件中的文件路径信息似乎是十六进制格式,当其转换成ASCII码是充斥着大量的天书的,和天书的格式似乎改变了不同文件和在不同的计算机上.find命令过滤在过去一天打开的文件,但是在这里我只能选择之间最近修改,最近访问的,最近没有打开.最近修改过的文件不包括未修改的打开文件(如打开但未编辑的图像),最近访问的文件似乎显示所有在Finder中以缩略图视图显示的文件,即使它们没有已被用户打开.LaunchServices/LSSharedFileList.h文件kLSSharedFileListRecentDocumentItems(类似于这个答案),但是之前我从未使用过Objective-C,因此我无法正常使用它.任何人都可以提供帮助我获取当前用户最近打开的文件列表的任何帮助将非常感谢.此外,任何能够将最近更改的文件列表写入文本文件的帮助都会很棒.
您的解决方案可能有效,但也许我想出的方案可能更可行。
在您提出的建议 3 个选项中,LSSharedFile*命令确实是最好的解决方案。
随着 AppleScript 脚本包 (.scptd) 和可保存为应用程序包 (.app) 的脚本的出现,您可以轻松地将自定义可执行文件包含在包中。因此,如果您无法单独使用 AppleScript 或默认的 BSD 子系统工具来完成您需要做的事情,您可以使用这些可执行文件来完成它。
因此,在 Xcode 中我创建了一个新的“Foundation Tool”项目,它使用以下代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
UInt32 resolveFlags = 0;
NSArray *arguments = [[NSProcessInfo processInfo] arguments];
if (arguments.count > 1) {
NSArray *revisedArguments = [arguments
subarrayWithRange:NSMakeRange(1, arguments.count - 1)];
for (NSString *arg in revisedArguments) {
if ([arg isEqualToString:@"--noUserInteraction"]) {
resolveFlags |= kLSSharedFileListNoUserInteraction;
} else if ([arg isEqualToString:@"--doNotMountVolumes"]) {
resolveFlags |= kLSSharedFileListDoNotMountVolumes;
}
}
}
LSSharedFileListRef sharedFileListRef = LSSharedFileListCreate(NULL,
kLSSharedFileListRecentDocumentItems, NULL);
NSArray *sharedFileListItemRefs =
(NSArray *)LSSharedFileListCopySnapshot(sharedFileListRef, NULL);
for (id itemRef in sharedFileListItemRefs) {
NSURL *resolvedURL = nil;
LSSharedFileListItemResolve((LSSharedFileListItemRef)itemRef,
resolveFlags, (CFURLRef *)&resolvedURL, NULL);
if (resolvedURL) {
printf("%s\n", resolvedURL.path.fileSystemRepresentation);
[resolvedURL release];
}
}
if (sharedFileListRef) CFRelease(sharedFileListRef);
[sharedFileListItemRefs release];
return EXIT_SUCCESS;
}
}
Run Code Online (Sandbox Code Playgroud)
虽然此代码与您的代码类似,但不必将结果写入中间文件,它只是将文件路径打印到标准输出。这应该可以大大简化 AppleScript 端的编码。构建此 Xcode 项目的结果是一个名为“Unix 可执行文件”的文件recentItemsFinagler而不是应用程序包。
要在 AppleScript 中使用这个内置的可执行文件,您首先需要确保脚本保存为脚本包或应用程序,然后Bundle Contents应启用工具栏项,如下图所示:

单击该工具栏项将显示抽屉,其中显示脚本包或应用程序包的内容。要添加自定义可执行文件,只需将其从 Finder 中拖放即可,如下图所示:

这会将其复制到脚本包中,如下所示:

要在运行时找到此可执行文件,您可以使用path to resourceAppleScript 命令,该命令是StandardAdditions.osax. (请注意,根据您尝试在脚本中使用该path to resource命令的方式,当您从 AppleScript 编辑器中运行脚本而不是通过在 Finder 中双击脚本来运行脚本时,您可能会遇到“找不到资源”错误如果遇到此类错误,请首先确保已保存对脚本的所有更改,然后退出 AppleScript 编辑器,然后在 Finder 中双击脚本应用程序来启动脚本应用程序运行完成后,重新打开 AppleScript 编辑器,然后重新打开脚本应用程序,然后尝试在 AppleScript 编辑器中运行并查看是否有效)。
因此,要在 AppleScript 中使用它recentItemsFinagler,您可以执行如下操作:
property recentItemsFinagler : missing value
if (recentItemsFinagler = missing value) then
set recentItemsFinagler to (path to resource "recentItemsFinagler")
end if
set toolPath to quoted form of POSIX path of recentItemsFinagler
set recentItemsString to (do shell script toolPath & " --noUserInteraction --doNotMountVolumes")
set recentItemsPaths to paragraphs of recentItemsString
Run Code Online (Sandbox Code Playgroud)
我将逐行浏览这个 AppleScript 来解释它的作用。我们首先创建一个全局属性recentItemsFinagler,并将其初始值设置为missing value。(missing valueAppleScript 相当于 Objective-C 的nil)。
如果您没有意识到,AppleScript 中的全局属性就像其他语言中的全局变量一样,但有一个重要的补充:当您运行脚本并向属性赋值时,该值实际上保存在脚本文件本身中,并将持续到您下次运行脚本时。
该脚本首先检查是否recentItemsFinagler等于missing value,如果等于,则将其设置为 的结果(path to resource "recentItemsFinagler"),这是一个 AppleScriptalias引用。这类似于 Finder 中的别名,因为它能够成功跟踪重命名以及从一个文件夹移动到另一个文件夹等更改。如果我将其存储为简单的字符串,然后将此 AppleScript 应用程序包从我的文档文件夹移动到我的桌面,则该路径将不再有效,并且每次运行脚本时都必须更新该属性。
不管怎样,我们然后设置recentItemsString为 AppleScript 工具的结果do shell script recentItemsFinagler,它是一个字符串。要将其转换为代表路径的 AppleScript 字符串列表,您可以使用paragraphs of命令。
因此,通过将可执行文件包含在脚本或 AppleScript 应用程序包中,您可以用不到 10 行代码获得所需的结果。