Safari扩展打开弹窗时执行本地Swift代码的实现方案咨询
可行性结论
该需求完全可实现。Safari App Extension 原生支持Swift代码作为扩展逻辑层,不需要将弹出窗口的业务逻辑全部写入传统的script.js文件。
具体实现步骤
- 利用系统提供的弹出窗口生命周期回调执行Swift代码
你不需要在JS侧写任何业务触发逻辑,直接在扩展默认生成的、继承自SFSafariExtensionHandler的Swift类中,重写系统自带的生命周期方法:
这个回调由系统原生触发,完全不依赖JS执行,是最贴合你需求的实现方式。override func popoverWillShow(in window: SFSafariWindow) { // 这个方法会在用户点击扩展图标、弹出窗口即将展示时自动触发 // 你需要执行的所有本地Swift业务代码直接写在这里即可 } - 薄JS桥接层配置
Safari扩展的弹出窗口本身由WebKit视图承载,你还是需要保留最基础的HTML/CSS/JS文件作为UI载体,但JS文件里不需要写任何业务逻辑,只需要保留和原生层通信的桥接代码即可:当Swift侧逻辑执行完成后,调用消息分发方法把执行结果回传给JS,JS只负责把数据渲染到弹出页UI上,不做任何逻辑处理。 - 逻辑执行结果回传示例
如果你需要把Swift代码的执行结果展示在弹出窗口,可以在拿到当前弹出页实例后,通过dispatchMessageToScript方法把结果推给前端:
对应JS侧只需要写监听代码即可:override func popoverWillShow(in window: SFSafariWindow) { // 执行你的本地Swift业务逻辑 let result = yourCustomSwiftBusinessLogic() // 拿到当前弹出页的控制器,回传结果给前端渲染 window.getPopoverViewController { popoverVC in popoverVC?.dispatchMessageToScript(withName: "loadResult", userInfo: ["data": result]) } }safari.self.addEventListener("message", function(event) { if (event.name === "loadResult") { // 仅做UI渲染,不处理业务逻辑 document.getElementById("content").innerText = event.message.data } })
权限配置说明
activeTab权限配置
两种配置方式二选一即可:- 可视化配置:在Xcode中选中扩展Target,找到Safari Extension配置项,将Website Access的Access级别设置为
Active Tab - 手动配置:打开扩展的
Info.plist,找到NSExtension->NSExtensionAttributes->SFSafariWebsiteAccess节点,将Level字段值设为ActiveTab
配置完成后,你可以在Swift代码中直接通过SFSafariWindow.getActiveTab方法拿到当前激活标签页实例,执行页面信息读取、脚本注入等操作。
- 可视化配置:在Xcode中选中扩展Target,找到Safari Extension配置项,将Website Access的Access级别设置为
cookies权限配置
同样两种配置方式:- 可视化配置:在上述Safari Extension配置页中,勾选
Cookies and website data选项 - 手动配置:在
SFSafariWebsiteAccess节点下添加布尔类型字段CanReadCookies,值设为YES
配置完成后,你既可以在Swift侧通过SFSafariPage的相关API获取页面上下文的Cookie,也可以直接通过HTTPCookieStorage.shared读取对应域名下的持久化Cookie,不需要依赖JS调用Cookie相关API。
- 可视化配置:在上述Safari Extension配置页中,勾选
注意:不要尝试完全删除JS/HTML文件用纯Swift渲染弹出窗口,Safari扩展的弹出窗口强制要求Web内容作为UI载体,你只需要把JS的逻辑压缩到最薄的UI渲染层即可,所有业务逻辑都可以放在Swift侧执行。
内容的提问来源于stack exchange,提问作者0xFR
相关产品推荐
相关产品推荐

