Safari 浏览器插件(扩展)开发

Safari 浏览器插件(扩展)

前期准备

  1. http://developer.apple.com 开发者账号注册 需要 Apple ID
  2. Safari Extension 旧版文档 适用于 2018 年前, Safari 12版本之前,大部分接口不可再使用
  3. Safari App Extension 新版文档 旧版中关于与浏览器APP 相关的接口,改为通过 Swift 实现,适用于 Safari 12版本及后续版本
  4. 有关插入脚本或者样式的文档
  5. 有关 NSExtension: 控制访问权限的配置
  6. 上下文菜单与工具栏开发的文档
  7. safari 扩展的开发中需要用到一部分 Swift 语言,学会这篇文章Swift 学习记录中的内容就够用了

1. 创建项目及基本开发步骤

1. 创建 Safari 扩展应用

进入 Xcode 选择创建新项目,然后依次选择 macOS -> Safari Extension App

在这里插入图片描述
在这里插入图片描述

2. 创建 应用名称 及 上传应用 logo 不同像素都需要对应的图片

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3. 更新配置文件
  1. 大部分的开大及配置都在 [ExtensionName] Extension 文件夹下,也就是具有 script.js 的文件夹
  2. 这个文件夹中的 info.plist 就是对应 chrome 插件 manifest.json 的功能的一个配置文件但是是一个 XML 的文件格式 Xcode 会将其转换成一个UI界面来方便操作
  3. 其中 NSExtension 这个key 用来控制所有的访问权限,例如:什么站点可以插入脚本|样式;需不需要上下文菜单;需不需要工具栏功能等。
  4. 如图中的 SFSafariContentScript 用来配置(Array),需要插入到网站中的脚本,与 chrome 中 的 contentScript 对应,可以访问网站的 window 对象,可以操作其中的dom,网站中如果有 iframe 嵌套,那么每个 iframe 也都会被注入脚本。
  5. SFSafariToolbarItem 用来配置显示在Safari 工具栏中的控件
  6. SFSafariContextMenu 用来配置显示 上下文菜单
  7. SFSafariWebsiteAccess 用来配置 可以接入脚本的网站 默认是 Allowed Domains: *.webkit.org,如果要插入脚本到所有站点,则可以 Allowed Domains 删除,将 Level: All
    在这里插入图片描述
4. 扩展打包及调试

注意: 每次打包之前记得清空上次打包,否则浏览器中无法使用扩展

打包:

  1. 更改代码 cmd + c 保存
  2. shift + cmd + k 删除旧的 bundle
  3. cmd + b 重新打包
  4. Safari 中浏览变更

调试:

  1. cmd + , 进入 Safari 浏览器的偏好设置,在高级中勾选 “在菜单栏中显示开发菜单”
  2. 打开开发菜单,勾选最下边的 “允许未签名的扩展”
  3. cmd + , 再次进入 Safari 浏览器的偏好设置,点开扩展选项,可以在这里找到,我们刚刚打包后的扩展应用,将其选中即可在Safari 浏览器中使用
  4. 打开 Safari 浏览器在如上SFSafariWebsiteAccess配置中对应的网站,打开网页检查器,在“来源”选项卡下即可看到,我们插入的扩展脚本

在这里插入图片描述

  1. 插入脚本的日志在控制台就可查看,但是扩展的日志要麻烦一点,扩展的日志 NSLog 需要我们打开 Mac 自带的应用 “Console app” / “控制台” 然后筛选出进程名称为我们浏览器扩展名称的的日志,如图

在这里插入图片描述

5. 版本发布
  1. 前提是要有开发者的账号
  2. 选择 Product -> Archive
  3. 然后在弹窗中选中 Distribute App
  4. 可以选择 发布到 App Store Connect 也可以选择 Copy App 打包到本地,打包到本地的应用可以传给其他人测试用

2. 开发说明

1. 设置浏览器访问权限

在 Info.plist 文件中的 NSExtension > SFSafariWebsiteAccess 中指定可访问的网址和域,只有这里指定的站点可以在 扩展中使用 SFSafariPageProperties 对象

SFSafariWebsiteAccess 有两条配置 Level | Allowed Domains

  1. Level: All 所有网站都可访问 | None 不可通过注入脚本来访问 | Some 只有 Allowed Domains 中的域可以访问,这个时候如果不设置 Allowed Domains 则所有域都不可访问
  2. Allowed Domains: 允许访问的域的数组,配合 Level: Some 使用
2. 注入脚本与扩展之间的通信

关于 注入脚本 与页面内容间的通信请看 关于浏览器插件开发过程中注入脚本与页面内容间的通信

  1. 插入的脚本及样式直接在 NSExtension 中配置的文件地址指定的文件中开发即可,
  2. 脚本与浏览器扩展交互主要靠 postMessage 来实现
  3. 浏览器在 SFSafariExtensionHandler.swift 文件中处理接收的事件
  4. 脚本中可以正常使用 window document 对象,除此之外支持 safari 对象,它是 SafariAppExtensionNamespace 类的实例,提供了关于应用扩展的一些信息,并且支持注入脚本与扩展之间的通信
  5. safari.extension 是应用扩展的代理,用来检索扩展的信息,和向扩展发出消息
  6. safari.self 注入脚本的代理,用来响应来自扩展的消息
// 脚本中发出消息
safari.extension.dispatchMessage("CHANGE_SOMETHING", {key: 'value'}); // 第二个参数选填,但必须是 对象
// 脚本中接收消息
safari.self.addEventListener("message", function (event) {
  console.log(event.name); // 'CHANGE_SOMTHING_SUCCESS'
  console.log(event.message); // {myKey: myValue}
});
  1. 扩展处理插入脚本间的通信是在 SafariExtensionHandler.swift 文件中,其中 messageReceived 用来接收信息,page.page.dispatchMessageToScript 用来向插入的脚本发出信息
// extension 中接收消息
override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : Any]?) {
    // extension 中发出消息   
    page.dispatchMessageToScript(withName: "CHANGE_SOMTHING_SUCCESS", userInfo: ["myKey", "myValue"])
}
  1. 注入脚本中可以访问扩展包中的资源:在注入脚本中通过 safari.extension.baseURI 可以拿到一个关于当前扩展的资源地址,这个地址下的文件可以被脚本当做 URL 引用,例如:safari.extension.baseURI + 'ToolbarItemIcon.pdf' 可以拿到默认的工具栏图标
3. SFSafariExtensionHandler

一个 用于 Safari 扩展的事件处理类,其包含的详细方法可以查看 SFSafariExtensionHandling : SFSafariExtensionHandler 实现的协议,工具栏、上下文菜单、插入脚本等的事件处理都在这里,我们这里用到的就是 messageReceived 方法 。

4. SFSafariPage

可以通过 SFSafariExtensionHandler func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : Any]?) 方法的第二个参数 page 获得,page 表示当前接收信息的来源页面,page 就是 SFSafariPage 这个类的实现,SFSafariPage 具有以下方法

  1. dispatchMessageToScript(withName:userInfo:) 从 extension 向注入的脚本发送消息,withName: 消息名称,userInfo:传入的数据
  2. getPropertiesWithCompletionHandler 从page 页面获得网页的属性,网页的属性包括:isActive: 是否处于活动状态;title: 网页标题;url: 页面的 URL;usesPrivateBrowsing:是否使用了无痕窗口
  3. reload 触发 Safari 重载页面
5. SFSafariApplication

一个浏览器应用的代理,在 SFSafariExtensionHandler.swift 文件中可以直接访问,通过它可以访问活动的 Safari 窗口、打开新的窗口、更新窗口工具栏等,这个类是没有实例的, SFSafariApplication 文档

  1. getActiveWindow 回调的参数是一个 SFSafariWindow 对象,作用是获得活动的浏览器窗口
// 获得活动的窗口,然后打开新的tab 页面
SFSafariApplication.getActiveWindow(completionHandler: { activeWindow in
  activeWindow?.openTab(with: URL(string: "https://www.baidu.com")!, makeActiveIfPossible: true, completionHandler: { _ in NSLog("OPEN SUCCESS")})
})
  1. openWindow(with:completionHandler:) 用来打开一个新的浏览器窗口
6. SFSafariWindow

代理浏览器的窗口,可以用来打开 Tab 或者获取活动的Tab

  1. getActiveTab(completionHandler: @escaping (SFSafariTab?) -> Void) 获取活动的选项卡,回调的参数是 SFSafariTab
  2. openTab(with url: URL, makeActiveIfPossible activateTab: Bool, completionHandler: ((SFSafariTab?) -> Void)? = nil) 打开一个新的选项卡,第二个参数用来设定打开时激活这个选项卡,回调的参数是 SFSafariTab
7. SFSafariTab

代理浏览器的选项卡,可以用来获得选项卡下的页面对象

  1. getActivePage(completionHandler: @escaping (SFSafariPage?) -> Void)获取当前选项卡下活动的页面,回调的返回值是 SFSafariPage 可以通过他再与新打开页面的插入的脚本进行通信
  2. getPagesWithCompletionHandler(_ completionHandler: @escaping ([SFSafariPage]?) -> Void) 获得此选项卡下活动的页面及其他可能后台运行的页面
8. 如何在 extension 中存取数据
  1. 找到 SafariExtensionViewController.swift 这个文件,声明一个类的属 extensionState 作为数据的 state
  2. 然后在 SafariExtensionHandler.swift 中就可以通过 SafariExtensionViewController.shared.extensionState 来访问这个属性了,在浏览器打开的阶段这个属性会一直存在,可以通过他来作为临时存储
  3. 为什么不直接在 SafariExtensionHandler.swift 中做数据存储?: 经测试 SafariExtensionHandler.swift 中的变量在打开新页面都是新的,不能作为页面间的数据存储

在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值