You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在本地将Safari分享扩展的信息回传至网页?

可靠实现Safari分享扩展响应回传网页的方案

针对网页通过Web Share API向Safari分享扩展传递带自定义请求的文件,并需要将扩展响应(如JSON数据)回传网页的需求,以下是经过验证的可行方案,解决你之前尝试WebRTC、localhost端口方案失败的问题:

方案1:App Groups + 扩展注入脚本(iOS专属,稳定性最高)

利用iOS的App Groups跨进程数据共享能力,结合Safari扩展的内容脚本注入机制实现回传:

  1. 配置App Groups:在开发者后台为你的Safari扩展开启App Groups权限,Xcode中在扩展的Info.plist添加com.apple.security.application-groups字段,填入专属的Group ID(如group.com.yourcompany.shareext)。
  2. 网页端处理:
    • 生成唯一requestID(如UUID),通过Web Share API分享文件时,将requestID和自定义请求内容放入text字段一起发送。
    • 监听自定义事件safariExtensionResponse,等待扩展的响应。
  3. Safari扩展端处理:
    • 接收分享内容,解析出requestID,处理完成后将响应数据存入App Groups对应的UserDefaults,键名可设为response_${requestID}。
    • 扩展后台脚本定时扫描UserDefaults中的待处理响应,通过内容脚本向匹配的网页发送消息。
  4. 内容脚本注入:在扩展Info.plist中配置NSExtensionContentScript,指定注入目标网页的脚本,负责将扩展传来的响应触发网页的自定义事件。

代码示例

扩展端(Swift)

let appGroupID = "group.com.yourcompany.shareext"
guard let defaults = UserDefaults(suiteName: appGroupID),
      let requestID = "从分享文本中解析出的requestID" else { return }

let response = ["status": "success", "data": "处理后的结果"]
defaults.set(response, forKey: "response_\(requestID)")
defaults.synchronize()

扩展后台脚本(JavaScript)

// 定时拉取待处理响应
setInterval(() => {
  safari.extension.dispatchMessage("fetchPendingResponses", {});
}, 1000);

// 接收原生层传来的响应,分发给对应网页
safari.extension.addEventListener("message", (event) => {
  if (event.name === "pendingResponses") {
    const responses = event.message;
    safari.application.browserWindows.forEach(window => {
      window.tabs.forEach(tab => {
        if (tab.page) {
          tab.page.dispatchMessage("deliverResponse", responses);
        }
      });
    });
  }
});

网页注入脚本(JavaScript)

// 监听扩展消息,触发网页自定义事件
safari.self.addEventListener("message", (event) => {
  if (event.name === "deliverResponse") {
    window.dispatchEvent(new CustomEvent("safariExtensionResponse", {
      detail: event.message
    }));
  }
});

网页主脚本(JavaScript)

const requestID = crypto.randomUUID();
// 发起分享
const shareData = {
  files: [yourFile],
  text: JSON.stringify({ requestID, customRequest: "你的自定义请求内容" })
};
navigator.share(shareData);

// 监听响应
window.addEventListener("safariExtensionResponse", (e) => {
  const matchedResponse = e.detail.find(res => res.requestID === requestID);
  if (matchedResponse) {
    console.log("收到扩展响应:", matchedResponse.data);
    // 清理已处理的响应
    safari.extension.dispatchMessage("clearResponse", { requestID });
  }
});

方案2:自定义URL Scheme跳转回传(跨iOS/Android)

通过自定义URL Scheme将响应数据作为参数跳转回网页,适合需要跨平台兼容的场景:

  1. 网页端处理:
    • 生成requestID,分享时携带该ID和请求内容。
    • 页面加载和可见性恢复时,检查URL参数中的响应数据。
  2. Safari扩展端处理:
    • 处理完成后,将响应JSON编码为URL安全字符串,通过自定义Scheme(如yourapp://share-response)拼接参数,调用SFSafariApplication.openURL跳转回网页。
  3. 网页端解析响应:解析URL参数中的响应数据,处理后清除URL参数避免重复触发。

代码示例

扩展端(Swift)

let requestID = "解析到的requestID"
let responseDict = ["result": "success", "data": "处理结果"]
guard let jsonData = try? JSONSerialization.data(withJSONObject: responseDict),
      let jsonString = String(data: jsonData, encoding: .utf8),
      let encodedData = jsonString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
      let url = URL(string: "yourapp://share-response?requestID=\(requestID)&data=\(encodedData)") else { return }

SFSafariApplication.open(url)

网页端(JavaScript)

// 解析URL中的响应数据
function processExtensionResponse() {
  const params = new URLSearchParams(window.location.search);
  const requestID = params.get("requestID");
  const data = params.get("data");
  
  if (requestID && data) {
    const response = JSON.parse(decodeURIComponent(data));
    console.log("收到响应:", response);
    // 清除URL参数,避免刷新重复处理
    window.history.replaceState({}, document.title, window.location.pathname);
  }
}

// 页面加载和恢复可见时检查
window.addEventListener("load", processExtensionResponse);
document.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "visible") processExtensionResponse();
});

// 发起分享
const requestID = crypto.randomUUID();
const shareData = {
  files: [yourFile],
  text: JSON.stringify({ requestID, customRequest: "你的请求内容" })
};
navigator.share(shareData);

方案3:共享容器文件存储(iOS,适合大体积响应)

当响应数据体积较大时,使用App Groups共享容器存储文件替代UserDefaults:

  1. 配置App Groups后,获取共享容器路径:FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupID)。
  2. 扩展处理完成后,将响应JSON写入以requestID命名的文件。
  3. 通过注入脚本读取共享容器中的文件,将内容传递给网页主脚本。

内容的提问来源于stack exchange,提问作者k06a

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 04:25:39