在外部应用程序 Objective-C 中获取当前文件

Posted

技术标签:

【中文标题】在外部应用程序 Objective-C 中获取当前文件【英文标题】:Getting Current File in External Application Objective-C 【发布时间】:2014-04-21 05:57:08 【问题描述】:

我正在尝试找出当前在 Mac OSX 上的其他活动应用程序中打开的文件。我知道我可以通过以下方式找到当前打开的应用程序:

NSWorkspace *ws = [[NSWorkspace alloc] init];

NSArray *apps = [ws runningApplications];

// loop through the apps and get the localizedName

但是,“runningApplications”(NSRunningApplication) 没有为我提供与该应用程序中打开的内容相关的任何内容。因此,假设用户打开了 Sublime Text 2。我想访问该应用程序并查看他们当前在其中打开了哪些文档(以及该文档的相关路径)。

我知道 applescript 和脚本桥是“选项”,但是我看到这 2 个问题如下:

Scripting Bridge 要求您从要与之交互的每个应用程序生成和添加头文件。 这对我来说的问题是我的应用程序不知道用户预先拥有哪些应用程序。 XCode(5) 似乎不允许我在安装时生成那些(即循环通过用户的应用程序目录并添加应用程序)或任何东西。

AppleScript 虽然不依赖于了解您要使用的应用程序,但并不适用于所有应用程序。只有某些人支持它。

这里的最终目标是能够查看用户当前打开了哪些应用程序,并获取有关这些应用程序当时打开了哪些应用程序的信息。

编辑:例如 - 如果用户使用“文本编辑”打开“/some/dir/example.txt”,我希望能够获取该信息。

【问题讨论】:

【参考方案1】:

要实现您的要求,您需要对多个 API 进行大量工作。我们实施了这一点,我们花了几个星期才完成它。这里有一些提示:

使用 NSRunningApplication 获取 Unix-PID 使用 AppleScript 和 AXAPI 获取窗口及其文档。 unixPID = 12345 -- 在此处插入数字 告诉应用程序 ID“com.apple.systemevents” 尝试 tell(unix id 为 unixPID 的应用程序进程) 超时 5 秒 在每个窗口中使用 thiWind 重复 将 isMain 设置为 thiWind 的属性“AXMain”的值 如果是主然后 thiWind 属性“AXDocument”的返回值 退出重复 万一 结束重复 结束超时 结束告诉 结束尝试 结束告诉 另外/另外使用CGWindow.h 遍历所有应用程序的窗口,然后为每个应用程序使用窗口ID 和特定脚本。例如: 告诉应用程序 ID“com.apple.TextEdit” 尝试 将 mydoc 设置为窗口 id 1234 的文档 -- 在此处插入窗口编号 mydoc的返回路径 结束尝试 结束告诉

要查看其性能示例,check out our app。该功能确实很难维护,并且在大多数情况下确实有效。在Developer Section 的此页面上查看其他应用程序应如何实现。

查看实际操作:

将包含各种文档的文件夹添加到 Raskin(例如单词、数字、文本、photoshop ......) 在他们的应用中打开这些文档 大多数文档在打开的地方都会显示一个徽章 然后您可以使用 cmd-alt-R 或 cmd-alt-scroll 从任何打开的文档返回到 Raskin 的 Surface 以公开此文件

【讨论】:

哇,这太不可思议了。那么第一个脚本适用于基于文档的应用程序,这些应用程序不一定具有正确的 AppleScript 字典设置?第二个是为那些这样做的人准备的? @JCole 完全正确。第一个仅适用于最前面的打开文档。您将在哪里以及如何需要此功能?我们可以共同努力。给 mahal(at)raskinformac.com 发邮件我很想赢得那笔赏金 :-)【参考方案2】:

您可以使用lsof 命令。它将返回打开文件的列表。

看看this的帖子

【讨论】:

【参考方案3】:

您可以使用lsof(列出打开的文件)命令来获取您想要的信息。该命令将产生旨在供其他程序读取的输出,并且您可以使用 NSTask/NSPipe 从应用程序执行。

HTH

附录:有些东西是无价的……

我看到你开了一个赏金,但有些东西是买不到的……你考虑过你的要求吗?

考虑lsof 在做什么——它报告操作系统为应用程序打开的文件;应用程序本身是一个黑匣子,操作系统维护着打开文件的信息,lsof 可以访问它。

您希望查看应用程序的黑匣子并代表用户确定应用程序知道的文件。这样的文件在操作系统意义上可能根本不是“打开”的——应用程序可能已经打开它,读入内容,然后关闭它。您认为如何发现这一点?来自黑匣子?

有可能,例如,NSDocument 被检测来提供此信息,但即使是这样,您如何从应用程序外部访问NSDocument 数据结构?如果应用程序没有使用NSDocument怎么办?

从 Apple 获取 TextEdit 示例代码并不要阅读它。在Xcode下运行一段时间,打开一些文件。现在点击调试暂停按钮。使用调试器命令(调试器可以调用应用程序中的方法)尝试发现打开文件的列表。您可以阅读NSDocument 上的任何文档以帮助您。如果您能找到路径名,那么您就是解决方案的开始(作为调试器可以做的任何事情,您可以从应用程序中做任何事情,但这可能并不简单)。

另一种方法:默认文件夹使用帮助应用程序来跟踪打开和保存对话框的使用情况。其他程序修补其他系统 API。如果您采用类似的方法,您也许可以设计一个帮助程序来跟踪某些NSDocument API 的使用并以这种方式维护“打开”文档的列表。它当然只适用于基于 NSDocument 的应用程序,并且只适用于在帮助程序运行时启动的应用程序(因此您需要一个守护程序)。

总而言之:您所问的问题不一定不可能,但它肯定远非微不足道(除非框架可以提供此信息,否则缺乏答案表明不是)。考虑一下你想要达到的目标,让你问这个问题,你能以另一种方式完成这项任务吗?

HTH

【讨论】:

这真的很有帮助,但是我试图在基于文档的应用程序(即文本编辑或崇高文本)中打开当前的“文档”。 lsof 似乎只显示应用程序直接使用的文件与用户使用应用程序打开的文件。因此,如果用户在“文本编辑”中打开了“example.txt”,我正在尝试获取该特定信息。不过,我赞成乐于助人! @JCole - 我添加了一个附录,它可能不是你想听到的,HTH。 嘿 CRD。谢谢你的信息。我一直在玩弄各种选项(从 bash、apple 脚本和脚本桥运行)。尽管这变得非常复杂,但我无法理解为什么。它只是让其中一个应用程序的文档打开。这是某种安全措施吗? @JCole - 安全是其中的一部分(你不能随便在另一个应用程序中四处寻找)。如您所知,如果 AppleScript 受支持,那么您就可以使用一些东西——即应用程序提供一些支持的情况。如果应用程序不提供支持,那么您将处于上述困难的境地。这就是它复杂的原因 - 没有应用程序的帮助,你有一个黑匣子和一个快速愚蠢的白痴(计算机),你需要准确地告诉你要做什么来发现信息(即编码你的逆向工程智能)。这里没有“公正”。【参考方案4】:

我建议您查看 Accessibility API。使用 Accessibility API,您可以遍历可访问性对象树。应用程序是树的最顶部的部分。然后,您可以浏览所有应用程序菜单,特别是 Window 菜单项,它通常具有应用程序中可用的文档数组。 Accessibility API 确实要求该进程是受信任的并且有权查看其他应用程序。要进行粗略的测试,以便您确信 API 满足您的需求,请使用 Xcode 附带的可访问性检查器工具(至少 5.+)。当您打开它时,您可以查看 OSX 应用程序提供的所有对象。我也使用 Sublime Text。如果每个文件都在自己的窗口中,它将显示正在使用的文件。

【讨论】:

以上是关于在外部应用程序 Objective-C 中获取当前文件的主要内容,如果未能解决你的问题,请参考以下文章

在外部 php 页面上仅获取 wordpress 页脚

检查实体是不是在外部表中被引用并获取实体

为啥我无法在外部点击时使用 react js 访问我的两个容器的当前目标值?

是否可以强制 AVPlayer 停止在外部播放视频(在 Apple TV 上)

在外部文本文件中查找字符串所在的行号

在外部循环中更新 Tkinter GUI