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

为现有应用添加Watch Extension:如何检测登录状态及传递登录数据

刚好之前做过类似的需求,给你梳理下Watch App和手机主应用同步登录状态、传递登录数据的靠谱方案,核心就是用苹果官方的WatchConnectivity框架,这是目前跨设备同步最稳定的方式:

一、先搞定WatchConnectivity的基础配置

不管是手机主应用还是Watch Extension,都得先把会话搭起来:

  • 两个target都要导入WatchConnectivity框架,并且确保Bundle ID符合关联规则(比如主应用是com.yourapp.main,Watch App是com.yourapp.main.watchkitapp,Extension是com.yourapp.main.watchkitapp.watchkitextension)。
  • 在手机端的AppDelegate/SceneDelegate,以及Watch端的ExtensionDelegate里,激活会话:

手机端代码示例:

import WatchConnectivity

class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {
    var session: WCSession?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        if WCSession.isSupported() {
            session = WCSession.default
            session?.delegate = self
            session?.activate()
        }
        return true
    }

    // 必须实现的代理方法,处理会话激活结果
    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
}

Watch端ExtensionDelegate代码示例:

import WatchConnectivity
import WatchKit

class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate {
    var session: WCSession?

    func applicationDidFinishLaunching() {
        if WCSession.isSupported() {
            session = WCSession.default
            session?.delegate = self
            session?.activate()
        }
    }

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
}
二、检查手机端的登录状态

有两种实用的方式,按需选:

  • 主动请求式:Watch App启动时,主动问手机端“用户登录了吗?”
    在Watch的界面控制器里发请求:

    import WatchConnectivity
    
    class MainInterfaceController: WKInterfaceController {
        override func awake(withContext context: Any?) {
            super.awake(withContext: context)
            // 先判断手机端是否可达
            if WCSession.default.isReachable {
                WCSession.default.sendMessage(["action": "check_login"], replyHandler: { response in
                    if let isLoggedIn = response["is_logged_in"] as? Bool {
                        if isLoggedIn {
                            // 跳转到登录后的界面
                        } else {
                            // 显示提示,让用户打开手机端登录
                        }
                    }
                }, errorHandler: { error in
                    print("请求登录状态失败:\(error.localizedDescription)")
                })
            }
        }
    }
    

    手机端的代理里处理这个请求:

    func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        if message["action"] as? String == "check_login" {
            // 从手机端的存储(比如Keychain/UserDefaults)拿登录状态
            let isLoggedIn = UserDefaults.standard.bool(forKey: "user_has_logged_in")
            replyHandler(["is_logged_in": isLoggedIn])
        }
    }
    
  • 被动同步式:手机端登录状态变了,主动推给Watch
    比如手机端登录成功后,直接发状态给Watch:

    // 手机端登录成功后调用这个方法
    func syncLoginStatusToWatch() {
        if WCSession.default.isReachable {
            WCSession.default.sendMessage(["is_logged_in": true], replyHandler: nil, errorHandler: nil)
        }
        // 用updateApplicationContext做持久化同步,即使Watch没启动,下次打开也能拿到最新状态
        do {
            try WCSession.default.updateApplicationContext(["is_logged_in": true])
        } catch {
            print("更新上下文失败:\(error)")
        }
    }
    

    Watch端监听上下文变化:

    func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
        if let isLoggedIn = applicationContext["is_logged_in"] as? Bool {
            // 更新Watch端的登录状态和界面
        }
    }
    
三、传递登录数据到Watch App

登录数据(比如token、用户ID)属于敏感信息,一定要用Keychain存储,同时通过WatchConnectivity传递:

  • 实时传递(sendMessage):手机端登录成功后立刻发数据

    // 手机端代码
    func sendLoginDataToWatch() {
        guard let token = KeychainManager.shared.getAuthToken(), 
              let userId = UserDefaults.standard.string(forKey: "user_id") else { return }
        
        let loginData = [
            "auth_token": token,
            "user_id": userId,
            "nickname": UserDefaults.standard.string(forKey: "user_nickname") ?? ""
        ]
        
        if WCSession.default.isReachable {
            WCSession.default.sendMessage(["login_data": loginData], replyHandler: { _ in
                print("登录数据已发送给Watch")
            }, errorHandler: { error in
                print("发送登录数据失败:\(error)")
            })
        }
    }
    

    Watch端接收并存储:

    func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
        if let loginData = message["login_data"] as? [String: Any] {
            // 敏感数据存Keychain,普通数据存UserDefaults
            if let token = loginData["auth_token"] as? String {
                WatchKeychainManager.shared.saveAuthToken(token)
            }
            if let userId = loginData["user_id"] as? String {
                UserDefaults.standard.set(userId, forKey: "watch_user_id")
            }
            // 更新界面到登录后状态
        }
    }
    
  • 持久化同步(updateApplicationContext):防止实时发送失败,保证Watch下次启动能拿到数据

    // 手机端代码
    func updateLoginContext() {
        guard let token = KeychainManager.shared.getAuthToken(), 
              let userId = UserDefaults.standard.string(forKey: "user_id") else { return }
        
        let context = [
            "is_logged_in": true,
            "auth_token": token,
            "user_id": userId
        ]
        
        do {
            try WCSession.default.updateApplicationContext(context)
        } catch {
            print("更新登录上下文失败:\(error)")
        }
    }
    

    Watch端启动时读取:

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)
        let currentContext = WCSession.default.applicationContext
        if let isLoggedIn = currentContext["is_logged_in"] as? Bool, isLoggedIn {
            if let token = currentContext["auth_token"] as? String {
                WatchKeychainManager.shared.saveAuthToken(token)
            }
            // 初始化登录后的逻辑
        }
    }
    
四、几个关键注意事项
  • 敏感数据(比如token)绝对不能用UserDefaults存储,一定要用Keychain,避免明文泄露。
  • 要处理会话不可达的情况(比如手机端没打开),这时候Watch端可以显示提示,引导用户打开手机应用完成登录。
  • 两个端的WCSession代理方法要完整实现,尤其是会话激活的方法,否则会话会无法正常工作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:09:07