编写动态定位Safari或WebKit的AppleScripts

首先,一些背景信息“WebKit”,除了作为Safari核心的HTML / CSS / JavaScript Web渲染引擎的名称(现在,还有许多其他浏览器,如), is also the name of an application for the Mac that is, more or less, just like Safari but uses the latest nightly build of the WebKit rendering framework instead of the standard system-wide version of the WebKit framework that ships as part of Mac OS X您可以下载最新的WebKit每晚构建这里

WebKit应用程序非常像Safari,它的应用程序菜单 - Apple菜单旁边的应用程序菜单 - 甚至说“Safari”它读取和写入与Safari相同的首选项和书签它更像是Safari的幻像副本,而不是单独的应用程序。1但是WebKit作为自己独特的过程运行You can, for example, run Safari and WebKit at the same timeWebKit也有自己的应用程序图标而且,对于AppleScript,需要专门解决WebKit问题。

此脚本将启动或激活Safari:

告诉应用程序“Safari”激活

此脚本将启动或激活WebKit:

告诉应用程序“WebKit”激活

我有一些AppleScripts,我写过用Safari做事它们保存在一个文件夹中〜/资源库/脚本/应用/ Safari浏览器/,当Safari是当前应用程序时,它们出现在我的系统范围的脚本菜单的顶部(我用FastScripts而不是Apple的Script菜单,因为FastScripts允许您为脚本分配键盘快捷键。)

当我运行WebKit时,我想要访问我在Safari中创建的完全相同的脚本集显而易见的解决方案很乏味:

  1. 制作我的Safari脚本文件夹的副本,并将其命名为“WebKit”。
  2. 改变告诉申请从“Safari”到“WebKit”的每个脚本中的目标。

值得注意的是,因为WebKit只是Safari的幻像版本,所以它共享完全相同的脚本字典与Safari一起使用的脚本应该与WebKit完全相同 - 除了您需要使WebKit成为WebKit的目标告诉块这个显而易见的解决方案的问题是每次我更改脚本或创建一个新脚本时,我都必须保留两个单独的副本。

更好的解决方案是使用我所说的动态告诉目标- 而不是制作告诉定位硬编码的应用程序名称,使其成为在运行时确定的变量当我第一次开始这样做时,我找不到以前做过的例子也许那是因为这是AppleScript中很少需要做的事情当你说告诉应用程序“Foo”在AppleScript中,您告诉脚本当前块正在使用Foo脚本字典中的术语AppleScript的整个观点(和痛苦)的很大一部分是每个应用程序都提供自己独特的字典。

Safari和WebKit是个例外(假设您发现自己需要编写针对同一应用程序的多个版本的脚本,假设两个版本都使用相同的脚本术语,那么我在下面概述的技术也可能有用。)

解决方案

有两个主要的上下文,您可以从中运行一个动态定位Safari或WebKit的脚本:

  1. 假定默认浏览器是Safari或WebKit,以当前“默认”Web浏览器为目标的脚本。
  2. 目标是活动应用程序的目标中的任何一个的脚本这对于您打算从系统范围的“脚本”菜单运行的脚本最有用。

我创建的框架支持这两者Even for scripts I only intend to use from the Script menu (therefore using technique #2, dynamically targeting the current active application), it’s useful to include technique #1 as a fallback so that the script works while editing and debugging it — when you run a script from within Script Editor, Script Editor is the frontmost application.

这是基本框架:

set _browser to GetCurrentApp()
if _browser is not in {"Safari", "WebKit"} then
    set _browser to GetDefaultWebBrowser()
end if
using terms from application "Safari"
    tell application _browser
        -- do stuff with Safari or WebKit here
    end tell
end using terms from

on GetCurrentApp()
  tell application "System Events" to ¬
    get short name of first process whose frontmost is true
end GetCurrentApp

on GetDefaultWebBrowser()
    -- First line of _scpt is a workaround for Snow Leopard issues
    -- with 32-bit Mac:: Carbon modules
    set _scpt to "export VERSIONER_PERL_PREFER_32_BIT=yes; " & ¬
        "perl -MMac::InternetConfig -le " & ¬
        "'print +(GetICHelper \"http\")[1]'"
    return do shell script _scpt
end GetDefaultWebBrowser

有两个实用程序处理程序,GetCurrentApp()GetDefaultWebBrowser(),两者都将应用程序的名称作为字符串返回我要感谢Christopher Masto对于Perl代码的位获取用户当前的默认Web浏览器。2该脚本首先获取最前面的应用程序的名称如果它是“Safari”或“WebKit”,那么它会假定您正在定位的应用程序如果没有,它将获取用户默认Web浏览器的名称并使用它。这里有一个很大的假设:如果不是最前面的应用程序也不默认的Web浏览器是Safari或WebKit,该脚本将以当前默认Web浏览器的实际目标为目标,几乎肯定不会起作用如果您使用Safari或WebKit以外的其他内容作为默认浏览器,则需要更改此设置。

所以在这一点上变量_BROWSER是一个设置为“Safari”或“WebKit”的字符串并且您可以将此变量用作a的目标告诉申请块但是,如果你在里面使用任何Safari / WebKit特定的脚本术语告诉阻止 - 你几乎肯定会,因为这是编写一个针对这些应用程序的脚本的全部内容 - 如果没有外部脚本,脚本将无法编译使用来自的术语块。

运行AppleScript源代码需要两步处理:首先编译,然后运行但AppleScript无法在不知道具体应用程序字典的情况下编译术语,而且本练习的重点在于我们不想确定目标。告诉阻止直到运行时该使用来自的术语块让我们解决这个问题我们仍然需要硬编码特定应用程序的名称,但是将其放入使用来自的术语阻止而不是告诉阻止,它只是AppleScript使用的信息时间(We could just as easily use WebKit as the target of the使用来自的术语阻止,但我认为最好使用Safari,因为每个Mac都安装了Safari。)

在重新编写所有以Safari为目标的AppleScripts以使用此框架后,我只是为我做了一个别名〜/资源库/脚本/应用/ Safari浏览器/文件夹,并将别名命名为“WebKit”我现在有一组脚本可以在两个应用程序中工作(并出现在我的脚本菜单的顶部)。


  1. WebKit.app包实际上只有两件事:更新的WebKit框架和可执行二进制文件,它启动常规Safari二进制文件的实例,并带有使用新WebKit框架而不是标准系统框架的指令So as applications, Safari and WebKit are truly identical — the only difference is the rendering engine. ↩︎

  2. I updated the Perl bit slightly in September 2009 for compatibility with Mac OS X 10.6 (Snow Leopard). ↩︎

以前: 真相
下一个: '做Shell脚本'和过早优化