macOSX开发之Safari App Extension初探
Safari App Extension简介
什么是Safari App Extension
Safari App Extension,即Safari浏览器应用拓展。它是苹果新推出的一种Safari扩展开发技术,最低支持Safari10.0,主要由三个部分组成分别是:
Safari App Axtension: 扩展app本身,使用JS、CSS等前端脚本语言。主要功能是包括两方面:
- 在插件运行之前注入js和css代码到当前的Safari浏览器页面,进而实现对页面的增删改查等功能
- 调用Safari提供的JS API接口与Containing app进行交互通信。
Containing App: 扩展app的容器,属于Native App。主要功能包括四方面:
- 配置和加载扩展app
- 与扩展app进行通信
- 提供可在Safari工具栏显示的原生界面
- 与Host App进行交互通信和共享数据
Host App: 主程序,也属于Native App。主要功能包括三方面:
- 加载Containing App
- 与Containing app通信交互
- 发布Safari App Extension到Apple App Store
结合上述的分析,Safari App Extension可使用两种组合的形式发布产品。一种是三个部分的App同时存在;另外一种是Host App只是作为发布工具,仅在第一次打开并完成扩展app安装之后就不再需要,因为安装好的扩展可在Safari->偏好设置->扩展中找到。
与 Safari Extension 的异同
Safari App Extension和Safari Extension的名称很相似,以至于在最开始研究的时候,我错以为二者是同一个东西,结果瞎忙活的一天才发现自己南辕北辙。不过,二者确实存在一些相似的地方。苹果的这篇官方文档具体介绍了如何将Safari Extension转换为Safari App Extension。简单来说,二者共同点在于js和css代码是完全可以复用的,不同的地方是Safari Extension的配置、开发以及发布平台都是基于Safari浏览器,而Safari App Extension则是基于Xcode,且产品发布平台是Apple App Store。
创建一个Safari App Extension
创建
因为Safari App Extension是以插件(plugin)的形式存在于Host App中的,因此需要首先创建一个Host App,也就是普通的Mac OSX的应用程序。然后再添加一个Safari App Extension的Target即可。
配置info.plist
Safari App Extension在被加载之前,Safari浏览器会通过读取info.plist文件以获得扩展的一些基本信息。
NSExtension,包括:
NSExtensionPointIdentifier:定值,必须是com.apple.Safari.extension,表示Safari扩展
NSExtensionPrincipalClass:扩展的核心类名,默认是SafariExtensionHandler类,里面一些部分实现了NSExtensionRequestHandling和SFSafariExtensionHandling协议,作为与Safari扩展通信和交互的接口。
SFSafariContentScript:用于指定注入的js脚本,以数组的形式表示,在扩展加载之前注入Safari浏览器当前的tab页。缺省值是只有一个文件script.js,也可以注入多个js文件,注入顺序依据数组中的顺序。
SFSafariToolbarItem:用于配置Safari扩展在工具栏中按钮的类型、图片以及tooltip等。按钮类型包括comman、popover等。
SFSafariWebsiteAccess:包括Allowed Domains和Level两个属性,分别表示允许访问的网站域名列表和网页访问权限。其中Level可以是Some和All,分别表示部分访问和无限制访问。
NSHumanReadableDescription
顾名思义,用于向用户阐述扩展基本功能的文字描述。在Safari浏览器的扩展管理器中选择某个插件就会显示对于的描述。
运行
这里有一个坑,如果是Xcode中运行Host App并不会加载包含于其中的Safari App Extension,解决办法是编辑Safari App Extension的scheme,指定可执行文件为Host App,再编译运行即可。此外,如果是双击的方式打开某个已经编译好的Host App也会自动加载其中的扩展插件。然后在Safari->Preference->Extensions中可看到对应的扩展。值得注意的是,如果扩展插件不是从Apple App Store中下载的,那么是不能正常加载的,即便App在本地已经打包签名也一样。解决方法是勾选Safari Menu->Develop->Allow Unsigend Extensions即可。
调试
Safari App Extension调试有两个值得注意的地方,第一,因为扩展插件是依附于Host App运行的,因为Xcode默认激活的是Host App进程,因此想要设置断点调试扩展插件,需要手动激活扩展进程。步骤是:在通过Xcode编译运行扩展进程之后,进入Safari Menu->Debug->Attach to process,选择对应的扩展进程。第二,在扩展插件中添加的NSLog调试信息不能在Xcode的终端输出,只能在电脑的控制台中查看。但是,lldb可以正常使用和输出。更多细节参考这篇博客
附录
一个关于Safari App Extensions的Demo:GitHub Demo
苹果2016年WWDC关于Safari App Extensions的介绍:Extending your App with Safari App Extensions WWDC 2016