[IBM DW] 实战 Safari 扩展开发

红薯 发布于 2010/11/13 08:15
阅读 812
收藏 2

简介: 今年 6 月 , Apple 刚刚发布了最新版本的 Safari 5, 其中很重要的一项功能就是扩展 (extension) 功能。 至此 , Firefox/Chrome/Safari 三大浏览器均已具备扩展支持 , 本文将详细介绍 Safari 5 中的这项新功能 , 并通过一个简单的例子来完整介绍 Safari 扩展的开发 / 部署流程及相关技术细节。

Safari 扩展的相关背景介绍

当我们谈到浏览器的扩展时 , 很容易被问到的问题是 : 我们为什么要给浏览器写扩展呢 ? 它能给我们带来什么好处或者便利 ? Safari 的扩展和其他浏览器的扩展有什么异同 ? 下面 , 让我们尝试着回答这些问题。 目前 , 基于浏览器的应用越来越多 , 而我们每天黏在浏览器上的时间也越来越长 , 看新闻 , 泡 BBS, 搜索技术文档 等等。 对于这样一个每天都要和它长时间打交道的东西 , 如何和它和睦相处无疑是很重要的。 而如果能把它打造成完全符合你个人需求的 , 适合你个人使用习惯 , 为你度身定做的软件 , 那将会使你的生活更美好些 , 让你的工作也更有效率些。

那么 , Safari 扩展具体能为我们提供哪些方面的便利呢 ? 请参考下面这幅图 :


图 1 .Safari 扩展支持
图 1 .Safari 扩展支持

从这副图能够看出 , 我们可以扩展 Safari 的如下几个部分 :

1. 我们能够在工具条上添加自己所需要的按钮

2. 我们能够添加自己所需要的扩展工具条

3. 可以对页面内容做混搭 (Mashup) 或自定义的修改

4. 可以对指定内容添加上下文相关菜单

好吧 , 看上去覆盖的功能面挺多 , 但还是不够直观 ? 让我来针对每条分别举一个直观点的例子吧 :

1. 我们可以在工具条上添加一个"GMail" 按钮 , 可定时检查新邮件并在图标上显示出新邮件的数量

2. 可以添加一个新的工具条 , 滚动显示当前的 Twitter 或者新浪微博里的信息 , 或者滚动显示每日单词 ( 我爱背单词 )

3. 对页面做一些增值混搭 , 按自己的喜好重新排版网页布局 , 或者自动过滤广告

4. 当用户选定了页面中的一些内容后 , 在右键的上下文菜单中添加一个"我要分享"选项 , 可以将所选的内容分享到其他 SNS ( 例如 : 开心 / 豆瓣等 )

是不是觉得有点意思了呢 ? 当然你也许已经有了更好的主意或是更有趣的点子 , 赶紧动手打造你自己的浏览器吧 !

Safari 扩展开发的准备工作

下面让我们来看一下开发 Safari 扩展都需要做些什么准备工作吧。 首先 , 开发 Safari 扩展是免费的 , 这和开发 iPhone 应用不同。 在 iTunes 上发布 iPhone 应用需要参加 iPhone Developer Program ( 个人用户每年 $99, 企业用户为每年 $299)。 而开发 Safari 扩展只需要在 Apple 网站上免费注册一个 Apple ID, 获取到你自己的开发者证书就可以了 ( 我们在下面会详细介绍这个步骤 )。 开发 Safari 扩展 , 也不需要你学习什么新的技术或是新的编程语言 , 只要你具有标准的 HTML/CSS/JavaScript 相关技术就可以了。 让我们开始吧 !

启用扩展功能

在 Safari 5 缺省状态下扩展功能是关闭的 , 用户需要手工开启这项功能。 打开 Safari 菜单中的"编辑", 再点击"偏好设置"菜单选项 , 在"高级"这个选项页中勾选底部的"在菜单中显示开发菜单"选项 ( 图二 )。


图 2. 启用"开发"菜单
图 2. 启用"开发"菜单

然后就能从 Safari 的顶级菜单看到一个独立的"开发"菜单项 ( 图三 ), 从中选择"启用扩展"就大功告成了 !


图 3. 启用扩展功能
图 3. 启用扩展功能

接下来同样在”开发”菜单中选择”显示扩展创建器 (Show Extension Builder)”, 就能打开 Safari 为开发人员准备的扩展开发功能了 ( 图四 ), 点击左下角的”+”按钮就能创建一个新扩展或是打开一个已存在的扩展项目 我们在第三部分中再来详细介绍这部分的功能。


图 4. 扩展创建器  
图 4. 扩展创建器  

让我们回到 Safari 菜单中的"编辑"里的"偏好设置"菜单选项 , 这时我们就能在"高级"的选项页旁边看到新增的"扩展"选项页了 ( 图五 )。 由于现在尚未安装任何扩展 , 所以当前列表是空的 , 让我们在添加了扩展之后再回来看看发生了什么变化。


图 5. 查看当前安装的扩展
图 5. 查看当前安装的扩展

注册 Apple ID 并获取 Safari 扩展开发的签名证书

接下来的工作是 , 作为一个 Safari 扩展的开发者 , 你需要去 Apple 的网站上注册一个免费的 Apple ID (http://developer.apple.com/programs/safari/), 此处步骤省略 , 请跟随 Apple 注册向导逐步完成即可 . 接着使用这个 Apple ID 登录 Safari 开发者网站 , 创建一个开发中要使用的签名证书 (https://developer.apple.com/safari/certificates /index.action), 选择左边标签页的第二个标签 (Request Certificates)


图 6. 创建签名证书
图 6. 创建签名证书

需要注意的是 , 在 Windows 和 Mac 上面的申请证书步骤略有不同 , 本文中将以 Mac 环境为例 , Windows 环境中的步骤请跟随网站上的申请向导逐步完成即可。

在所用的开发机上安装签名证书

同样需要注意的是 , 在 Windows 和 Mac 上的签名证书步骤也略有不同。 在 Windows 环境下直接点击生成的证书文件 , 系统即可自动安装好此证书。 而 Mac 环境下签名证书的步骤是个向导过程 , 本文写作时 , 在选择证书安装分类时 , 在 Mac 下应选择"登录"而不是"系统"分类。 而在 Windows 环境下有时候 Safari 不能正常识别出安装好的签名证书 , 请参看官方网站的相关指引做相应的修改。


图 7. 安装签名证书
图 7. 安装签名证书

图 8.Safari 成功识别出安装的签名证书
图 8.Safari 成功识别出安装的签名证书

如何制作 Safari 扩展

好了 , 通过上面两部分的介绍 , 相信您已经对 Safari 扩展有了个大致的了解 , 也为此准备好了开发环境。 在动手编写第一个扩展前 , 让我们先来了解一下 Safari 扩展的框架结构及相应开发工具吧。

Safari 扩展框架结构

我们知道 , 在 Safari 扩展中 , 我们可以如下几个部分来提供扩展功能 :

  • 工具栏按钮
  • 扩展工具条
  • 上下文关联菜单
  • 注入 (JavaScript) 脚本
  • 注入样式表单

而 Safari 扩展框架中其实是存在了一条分割线 , 将整个体系结构分为了两个部分 :

  • Safari 应用层 : 包含工具条按钮 , 扩展工具条 , 页面标签 , 页面窗口 , 上下文菜单等
  • 页面内容层 : 包含修改页面内容的 JavaScript 和 CSS

而这两部分不能直接调用对方的代码 , 需要通过给对方发送消息 , 再由对方的消息处理方法来调用所需的代码。 当然 , 不是每一个 Safari 扩展都需要做这样的消息调用 , 例如简单的"关闭网页"按钮扩展就不需要和页面内容层交互 , 也就不需要消息调用及代理等处理逻辑了。

Safari 扩展开发工具介绍

接下来我们来看一下 Apple 为我们提供的开发工具 , 不是 XCode 这样的大家伙 , 也不是让你从零开始完全手工编写所有的代码文件 , 部署脚本和打包程序。 Apple 在 Safari 5 里内嵌了一个叫做"扩展创建器"的工具来简化开发 / 打包及部署步骤。 打开 Safari, 选择"开发"菜单 , 再选择"显示扩展创建器"就能看到它了。

让我们拿本文中下面即将提供的"CloseOtherTabs"这个示例来分析一下扩展创建器里面的内容 :


图 9. 扩展创建器 第一部分

前面的三部分比较简单 , 分别是

1) 扩展信息 : 包括此扩展的显示名称 , 作者 , 描述等

2) 扩展详细信息 : 包含此扩展的唯一标识以及将来检查升级时所需的清单文件

3) 扩展版本。


图 10. 扩展创建器 第二部分

4) "扩展网站访问"是用来控制此扩展可访问哪些网址 , 可选的访问级别有"无", "部分"及"全部"三种 , 分别对应对所有网址均无权限 , 对指定的部分网址 ( 支持通配符 ) 具有权限 , 和对所有网址都有权限。

5) "扩展全局页面" 这个页面文件比较重要 , 全局页面顾名思义是个掌控全局的页面 , 但是它又比较特殊 , 位于 Safari 应用层而不是页面内容层 , 而且此页面不是用来显示给终端用户的。 如果你对 Safari 扩展中这两个层还有所印象的话 , 应该记得这两层是不能直接调用对方的 , 必须通过消息代理来间接调用。 那我们为什么要有这个全局页面呢 ? 简单的原因是这里面可以存储一些公共的代码从而避免多个代码副本 , 而深一层的原因是将代码放入全局页面有利于提高用户使用时的性能 ! 为什么会提升性能 ? 我们知道 , 在浏览器中我们可以开多个窗口 , 每个窗口又可以开多个标签页 , 每个标签页中才对应着你访问的网站。 如果你将一些比较耗时的 JavaScript 代码放入了工具条的扩展文件中 , 那么每开一个新窗口 , 这段代码都要载入一次。 而如果你将耗时的 JavaScript 代码放入了修改网页内容的嵌入脚本中 , 那么每开一个标签页 , 这段代码都会重新载入一次 , 无疑这将会极大的降低网页载入速度。 而将这些 JavaScript 代码放入全局页面 , 那么它只会被载入一次 , 以后再开新窗口 / 新标签页 , 都无需重新载入。

6) "扩展 Chrome" 在这里你能够创建你的工具栏 , 上下文关联菜单 , 以及工具栏上的按钮。 你可以随时点击”New Bar”或者”New Context Menu Item”来新增一个条目并填写相应信息。


图 11. 扩展创建器 第三部分

7) "加入的扩展内容" 这里包含的就是对"页面内容层"进行扩展的相应文件 (JavaScript/CSS) 了 , 我们可以在这里遍历页面的 DOM 树 , 修改其中的内容 , 改变页面的布局等等。

8) "扩展设置" 最后的这部分就是你想此扩展里使用的一些参数 , 方便用户进行个性化自定义。

那么 , 这么多的设置 , 扩展创建器最终将它们保存在了什么地方 ? 让我们看看这个"CloseOtherTabs"扩展的文件结构


图 12. "CloseOtherTabs"扩展的文件结构

真的非常简单 , 只有三个文件 :

1) global.html 包含当用户点击"关闭"按钮时所需的 JavaScript 处理代码

2) Info.plist 包含了上面扩展创建器中所有的参数设置

3) close.png 显示在工具栏中的"关闭"图标

实战 Safari 扩展的开发 / 打包 / 安装 / 发布

看到这里 , 也许你已经开始着急了 , 什么时候才开始开发我们的第一个 Safari 扩展啊 ! 别急 , 其实此时你已经具备了写一个简单 Safari 扩展所需的大部分知识。 让我们动手实现它吧 !

首先 , 描述一下这个扩展所实现的功能 : 我们将提供一个位于工具栏中的"关闭其他"按钮 , 用户点击了此按钮后会关闭除当前页面外的其他标签页。 当然 , Safari 浏览器其实已经提供了别的方式来完成这个功能 , 你可以按住"Alt"键 (Mac 上按"Option"键 ) 之后点击当前标签页的"x"图标也可关闭其他所有标签页。 在此 , 我们通过尝试写一个工具栏按钮的 Safari 扩展来实现相同的功能从而达到练手的目的。

开发 CloseOtherTabs 扩展

首先是打开 Safari 中的扩展创建器 , 点击左下角的"+"按钮并选择"新建扩展", 然后在弹出的窗口中为新扩展选择一个保存目录。 在这里我们把它命名为"CloseOtherTabs", 点击保存。 你将会发现在上一步选择的保存目录中新创建了一个叫"CloseOtherTabs.safariextension"的文件夹 , 里面只包含有一个含有基本信息的 Info.plist 文件 , 这里先暂且把它放在一边 , 等我们完成其他文件之后再来完善它。

接着是为这个扩展提供一个工具栏按钮图标 , 在此我们为它提供一个 11*11 像素的 png 文件 , 并将它保存在"CloseOtherTabs.safariextension"文件夹中。

最后 , 此扩展的重头戏来了 , 我们需要为它写一个全局页面 ( 为什么是全局页面而不是工具栏页面的原因前面已说明 , 这样可以减少不必要的反复加载从而提高性能 ), 并在里面实现所需的功能。 主要代码如下 :

 // Register for the validate and command events. 
 safari.application.addEventListener("command", performCommand, false); 
 safari.application.addEventListener("validate", validateCommand, false); 

 function performCommand(event) 
 { 
    if (event.command != "close-other-tabs") 
        return; 

    // return if there are no more tabs to close 
    if (event.target.browserWindow.tabs.length < 2) 
        return; 

    // Close others tab except the current one in the target's window. 
    var myTabs = event.target.browserWindow.tabs; 
    var currentTab = event.target.browserWindow.activeTab; 
   
    for (var i = 0; i < myTabs.length; ++i) { 
        var tab = myTabs[i]; 
       
        if (currentTab == tab){ 
            //do nothing for current tab 
        }else{ 
            tab.close(); 
        } 
    } 
 } 

 function validateCommand(event) 
 { 
    if (event.command !== "close-other-tabs") 
        return; 

    // Disable the button if there are only 1 tab available. 
    event.target.disabled = event.target.browserWindow.tabs.length < 2; 
 } 

 

从上面的代码可以看出 , 其实所需要完成的功能是很简单的。 首先是注册"command"和"validate"这两个事件 , 接着是提供对这两个事件的响应函数。 在此我们对这两个事件稍作解释。 当用户点击了工具栏中的按钮或者上下文菜单中的选项时将会触发"command"事件 , 我们需要在响应函数中首先判断是否是我们的控件触发了这个事件 , 然后再继续实现我们的业务逻辑 , 从而避免无效的劳动。 而"validate"事件比较有趣 , 它会在适当的时机触发 , 让你有机会对你的控件根据当前状态做一些修改。 例如 , 当目前窗口中只有一个标签页时 , 如果我们让"关闭其他"按钮仍然可以点击 , 会给用户带来一定的困扰 , 因为点击之后没有任何效果。 因此 , 适当的做法是根据当时的状态来禁止这个按钮 ( 变灰 , 不可点击 ), 从而提升用户体验。

我们将其命名为 global.html 并保存在 "CloseOtherTabs.safariextension" 文件夹中。 至此 , 此文件夹中已经包含了我们所需的所有文件。 现在让我们再回到 Info.plist 文件 , 更新相应的条目。 主要代码如下 :

    <key>Chrome</key> 
    <dict> 
        <key>Global Page</key> 
        <string>global.html</string> 
        <key>Toolbar Items</key> 
        <array> 
            <dict> 
                <key>Command</key> 
                <string>close-other-tabs</string> 
                <key>Identifier</key> 
                <string>close-other-tabs</string> 
                <key>Image</key> 
                <string>close.png</string> 
                <key>Label</key> 
                <string>CloseOtherTabs</string> 
                <key>Tool Tip</key> 
                <string>Close other tabs except current one</string> 
            </dict> 
        </array> 
    </dict> 

 

从这里可以看出 , Info.plist 在 Chrome 部分中指定了 global.html 和 close.pn 这两个文件 , 并且将 "close-other-tabs" 注册了 "Command" 事件 , 而我们在相应的事件响应函数中也是以此作为判断是否是来自我们控件的根据。

安装 / 打包 / 发布

完成了上述三个文件之后 , 我们的扩展就写完了 ! 下面来看一下如何安装吧。 依然是打开 Safari 中的扩展创建器 , 选中我们刚才创建的"CloseOtherTabs"扩展 , 点击右上角的"Install"按钮就完成安装了 , 不需要重新启动 Safari 浏览器即可立即生效。


图 13. 扩展安装界面

而此时右上角会有三个按钮"Uninstall"/"Reload"/"Build Package"。 点击"Uninstall"即可卸载此扩展 , 同样无需重启浏览器即可生效。 而"Reload"按钮则可以在我们修改了扩展源代码之后重新加载此扩展 , 可见在 Safari 上开发调试扩展还是挺方便的 , 不需要打包 / 卸载 / 重新部署这样繁琐的流程。 最后一个"Build Package"按钮则可以将我们的"CloseOtherTabs.safariextension"文件夹打包成一个 CloseOtherTabs.safariextz 文件 , 可以将这个文件分发给其他用户 (Windows/Mac 平台的用户均可安装 ), 用户双击这个文件即可自动安装。 需要注意的是 , 安装扩展的 Safari 浏览器只需要完成了在 2.1 中描述的启用扩展功能即可 , 无需安装我们在 2.2 中提到为开发扩展而准备的签名证书。 在本文撰写时 , Apple 也正在准备发布一个扩展中心 , 开发者可以将自己的扩展提交于他人分享。


图 14. 扩展卸载 / 刷新界面

好 , 至此我们这个"CloseOtherTabs"扩展已全部完成 , 这是个十分简单的扩展 , 描述了 Safari 扩展的基本框架和开发流程 , 但是还有许多功能我们还没有涉及到。 例如 , 如何编写一个上下文菜单扩展 , 如何编写一个额外的工具条扩展 , 如何编写一个修改网页内容的嵌入 JavaScript 扩展 , 如何编写一个修改网页布局 / 颜色 / 动态效果的扩展。 而更为重要的是 , 这些部分的扩展并不是独立存在的 , 有时候我们需要将它们结合起来才能完成一项功能 , 如何在它们之间进行消息传递 ? 要回答上述问题 , 敬请留意我们的下一篇文章 < 实战 Safari 扩展开发 - 进阶篇 >, 谢谢 !

下载示例代码:
http://www.ibm.com/developerworks/apps/download/index.jsp?contentid=578551&filename=CloseOtherTabs.zip&method=http&locale=zh_CN

加载中
返回顶部
顶部