![](/img/trans.png)
[英]Send message from app (popup.js) to JS (content.js) in Safari Web Extension (iOS 15)
[英]How to send a message (tokens) from an iOS App to its Safari Extension?
我嘗試在諸如此類的帖子中尋找解決方案, 其中人們遇到了非常相似的問題: How to send a message from iOS App to a Safari Extension?
我什至讀過這篇文章,其中作者解釋了如何使用SafariExtensionHandler
在選擇上下文菜單后將消息從瀏覽器發送到應用程序並返回到瀏覽器,但這並不是我想要的。
在應用程序中,用戶必須輸入 email 和密碼才能登錄他們的帳戶。 他們登錄后,我將他們的信息保存在UserDefaults
中,如下所示:
class AuthDataService {
{...}
URLSession.shared.dataTaskPublisher(for: urlRequest)
.tryMap { data, response -> Data in
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200,
let accessToken = httpResponse.value(forHTTPHeaderField: "Access-Token"),
let clientId = httpResponse.value(forHTTPHeaderField: "Client"),
let uid = httpResponse.value(forHTTPHeaderField: "Uid")
else {
throw CustomError.cannotExecuteRequest
}
let sharedDefaults = UserDefaults(suiteName: "group.com.MyCompany.MyProject")
sharedDefaults?.set(accessToken, forKey: "Access-Token")
sharedDefaults?.set(clientId, forKey: "Client")
sharedDefaults?.set(uid, forKey: "Uid")
return data
}
{...}
}
根據我對這篇文章的理解,我需要創建一個App Group,以便在iOS App和Safari Extension之間共享數據。 我將該組命名為: "group.com.MyCompany.MyProject"
(就像UserDefaults
中的 suiteName 一樣)。
用戶登錄時看到的屏幕是一個 SwiftUI 視圖,它有一個鏈接,將用戶帶到 Safari,這樣他們就可以自己打開擴展程序:
struct HomeView: View {
@EnvironmentObject var viewModel: AuthViewModel
var body: some View {
Link(destination: URL(string: "https://www.apple.com/")!) {
Text("Take me to Safari")
}
}
}
現在,我閱讀的所有文章都在談論如何通過 SafariWebExtensionHandler 的beginRequest(with:)
將數據從 Safari 擴展發送到 iOS 應用程序。 但是,每當用戶登錄應用程序或打開 Safari 擴展程序時,我都會嘗試在 UserDefaults 中發送令牌。
我嘗試從UserDefaults
中檢索數據,看看我是否至少可以在終端中讀取它,但調試器永遠無法print
語句:
import SafariServices
import os.log
let SFExtensionMessageKey = "message"
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
func readData() {
let sharedDefaults = UserDefaults(suiteName: "group.com.lever.clientTokens")
print(sharedDefaults?.object(forKey: "Access-Token")) //<-- This line never gets executed
}
func beginRequest(with context: NSExtensionContext) {
let item = context.inputItems[0] as! NSExtensionItem
let message = item.userInfo?[SFExtensionMessageKey]
os_log(.default, "Received message from browser.runtime.sendNativeMessage: %@", message as! CVarArg)
let response = NSExtensionItem()
response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ]
readData()
context.completeRequest(returningItems: [response], completionHandler: nil)
}
}
Apple 的這份文檔有一個名為“ Send messages from the app to JavaScript
部分,這幾乎是我想要做的。 該文檔甚至提到了SFSafariApplication.dispatchMessage(withName:toExtensionWithIdentifier:userInfo:completionHandler:)
理論上它會向 JavaScript 腳本發送一條消息,但它說它只適用於 macOS:
您不能將消息從包含 iOS 的應用程序發送到您的 web 擴展程序的 JavaScript 腳本。
這篇出色的 Medium 文章討論了使用來自 openai.com 的 API 從應用程序向 Safari 擴展發送 APIKey。 似乎它還使用SFSafariApplication
與SafariWebExtensionHandler
通信,但它又看起來只適用於 macOS。
我還閱讀了其他 Apple 文檔,認為它會有所幫助,但它只討論了將消息從 Safari 擴展的彈出窗口傳遞到網頁。
所以我的問題是:
在SafariWebExtensionHandler
中編寫代碼是否是將數據從 iOS 應用程序發送到我的 Safari 擴展程序的正確方法? 這個可以在iOS做嗎? 還是僅適用於 macOS?
我閱讀了一些其他文章,這些文章討論了如何使用 Resources 文件夾中的 JavaScript 文件來“收聽”更改。 但我對如何從我的應用程序發送這些更改以使 Safari 擴展程序能夠收聽它們感到有點困惑。
我想要實現的是,用戶在從 iOS 應用程序中的 HomeView 重定向后,已經登錄到 Safari 擴展,而不必再次登錄。
感謝您的寶貴時間和幫助!
雖然應用程序無法發起與擴展的連接,但支持另一個方向。 當擴展程序向應用程序發送數據時,您可以附加響應並將其發送回擴展程序。
我不確定為什么您使用SafariWebExtensionHandler
的示例不起作用。 看起來不錯。 也許問題出在 JS 方面。
import SafariServices
import os.log
extension String: Error {}
let SFExtensionMessageKey = "message"
class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling {
func beginRequest(with context: NSExtensionContext) {
let item = context.inputItems[0] as! NSExtensionItem
let data = item.userInfo?[SFExtensionMessageKey] as AnyObject?
guard let key = data?["key"] as? String else {
return
}
let response: [String: Any]
do {
switch(key) {
case "getToken":
os_log(.default, "handling getToken")
guard let sharedDefault = UserDefaults(suiteName: "group.com.lever.clientTokens") else {
throw "UserDefaults not found"
}
guard let tokenData = sharedDefault.data(forKey: "Access-Token") else {
throw "Access-Token not found"
}
guard let tokenString = String(data: tokenData, encoding: .utf8) else {
throw "tokenData could not be converted into string";
}
response = ["success": true, "resp": tokenString]
default:
throw "Invalid key"
}
} catch {
os_log(.error, "Error: %s", String(reflecting: error))
response = ["success": false, "resp": ["message": error.localizedDescription]]
}
let resp = NSExtensionItem()
resp.userInfo = [SFExtensionMessageKey: response]
context.completeRequest(returningItems: [resp], completionHandler: nil)
}
}
首先將"nativeMessaging"
添加到“manifest.json”中的"permissions"
。
async function getToken() {
const resp = await browser.runtime.sendNativeMessage("_", {
key: "getToken"
});
if (resp.success) {
return resp.resp
} else {
throw new Error(resp.message)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.