PWA转iOS原生应用:WebView认证用户关联Firebase Device Token问题
解决方案
针对你遇到的FCM令牌与WebView中认证用户关联的问题,这里提供两种安全可行的方案:
方案一:将FCM令牌注入WebView,通过前端JS提交后端(推荐)
这种方案复用你PWA中原有的令牌关联逻辑,只需在Swift端将令牌注入WebView,由前端利用已有的用户会话提交到后端。
步骤1:Swift端获取并注入FCM令牌
在WebView加载完成后,验证页面域名属于你的PWA,然后注入JS代码调用前端全局函数:
import WebKit import FirebaseMessaging class ViewController: UIViewController, WKNavigationDelegate, MessagingDelegate { var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() // 初始化WebView let config = WKWebViewConfiguration() webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self view.addSubview(webView) // 监听FCM令牌刷新 Messaging.messaging().delegate = self // 获取初始令牌 Messaging.messaging().token { token, error in if let token = token { UserDefaults.standard.set(token, forKey: "FCMToken") } } } // WebView加载完成后注入令牌 func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { guard let fcmToken = UserDefaults.standard.string(forKey: "FCMToken"), let url = webView.url, url.host == "your-pwa-domain.com" else { return } let injectJS = "window.registerFCMToken('\(fcmToken)');" webView.evaluateJavaScript(injectJS) { _, error in error.map { print("注入令牌失败: \($0.localizedDescription)") } } } // 令牌刷新时重新注入 func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { guard let token = fcmToken else { return } UserDefaults.standard.set(token, forKey: "FCMToken") if let currentUrl = webView?.url, currentUrl.host == "your-pwa-domain.com" { let injectJS = "window.registerFCMToken('\(token)');" webView.evaluateJavaScript(injectJS, completionHandler: nil) } } }
步骤2:前端PWA中接收令牌并提交后端
在你的PWA JS代码中定义全局函数,利用已认证的会话(Cookie)将令牌提交到后端:
// 全局函数,接收Swift注入的FCM令牌 window.registerFCMToken = function(token) { // 复用原有PWA的令牌提交逻辑,credentials: 'include'会自动带上用户会话Cookie fetch('/api/user/fcm-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token }), credentials: 'include' }).catch(err => console.error('令牌提交失败:', err)); };
方案二:Swift端获取WebView会话信息,直接调用后端API关联令牌
如果不想修改前端代码,可以在Swift端获取WebView中的用户会话Cookie,直接调用后端API完成令牌与用户的关联。
步骤1:Swift获取WebView会话Cookie
func getSessionCookie(completion: @escaping (String?) -> Void) { guard let pwaUrl = URL(string: "https://your-pwa-domain.com") else { completion(nil) return } WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in // 替换成你后端使用的会话Cookie名称 let sessionCookie = cookies.first { $0.name == "user_session_id" } completion(sessionCookie?.value) } }
步骤2:调用后端API关联令牌
在用户登录完成后(比如WebView跳转到登录成功页面时),执行关联逻辑:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { guard let url = webView.url, url.path == "/login/success" else { return } getSessionCookie { sessionId in guard let sessionId = sessionId, let fcmToken = UserDefaults.standard.string(forKey: "FCMToken") else { return } let apiUrl = URL(string: "https://your-api-domain.com/api/fcm/associate")! var request = URLRequest(url: apiUrl) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") // 根据后端认证方式设置头,比如Cookie或Authorization request.setValue("user_session_id=\(sessionId)", forHTTPHeaderField: "Cookie") let body = ["token": fcmToken] request.httpBody = try? JSONSerialization.data(withJSONObject: body) URLSession.shared.dataTask(with: request) { _, _, error in error.map { print("关联失败: \($0.localizedDescription)") } }.resume() } }
安全注意事项
- 无论哪种方案,都要验证WebView访问的域名,防止令牌注入到恶意页面
- 后端要校验提交请求的合法性,确保会话有效且属于当前用户
- FCM令牌可能会定期刷新,务必监听令牌更新事件并重新关联
内容的提问来源于stack exchange,提问作者O'Niel
相关产品推荐
相关产品推荐

