You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何从Apple Watch直接在iPhone后台启动父应用?

如何从Apple Watch让iPhone父应用以后台模式启动?

你提到的Endomondo这类应用的场景确实很典型——Watch端点击触发后,iPhone父应用在后台自动启动并同步GPS数据。正如你所说,openParentApplication(_:reply:)早就被废弃了(仅支持watchOS 1),现在我们得用Watch Connectivity框架来实现这个需求,下面是具体的实现思路和步骤:

核心原理

Watch Connectivity框架里的sendMessage(_:replyHandler:errorHandler:)sendMessageData(_:replyHandler:errorHandler:)方法,是目前触发iPhone父应用后台启动的标准方式。这两个方法会强制唤醒处于后台(甚至未运行)的iPhone应用,让它处理来自Watch的消息,完美匹配你需要的场景。


具体实现步骤

1. 两端配置Watch Connectivity

首先要在Watch Extension和iPhone父应用中都完成WCSession的初始化:

iPhone端代码(比如AppDelegate)

import WatchConnectivity

class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 检查设备是否支持Watch Connectivity
        guard WCSession.isSupported() else { return true }
        
        let session = WCSession.default
        session.delegate = self
        session.activate()
        
        return true
    }

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

Watch Extension端代码(比如ExtensionDelegate)

import WatchConnectivity
import WatchKit

class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate {
    func applicationDidFinishLaunching() {
        guard WCSession.isSupported() else { return }
        
        let session = WCSession.default
        session.delegate = self
        session.activate()
    }

    func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {}
}

2. Watch端发送触发消息

在Watch端需要启动父应用的时机(比如点击“开始”按钮时),发送消息给iPhone:

// Watch端按钮点击事件里的代码
@IBAction func startButtonTapped() {
    guard WCSession.default.isReachable else {
        // 处理设备未连接的情况,比如提示用户
        print("iPhone未连接,请确保设备配对且蓝牙开启")
        return
    }
    
    // 发送自定义指令,告诉iPhone要执行什么操作
    let message = ["action": "startGPS"]
    WCSession.default.sendMessage(message, replyHandler: { replyData in
        // 处理iPhone返回的结果,比如GPS数据
        if let latitude = replyData["latitude"] as? Double,
           let longitude = replyData["longitude"] as? Double {
            print("收到GPS位置:\(latitude), \(longitude)")
            // 更新Watch界面
        }
    }, errorHandler: { error in
        print("发送消息失败:\(error.localizedDescription)")
    })
}

3. iPhone端处理消息并执行后台任务

在iPhone的WCSession代理中实现消息接收方法,这里可以执行后台操作(比如获取GPS),如果需要长时间运行,还要申请后台任务权限:

// iPhone端WCSession代理方法
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
    guard let action = message["action"] as? String, action == "startGPS" else {
        replyHandler(["error": "无效指令"])
        return
    }
    
    // 申请后台任务权限,避免操作被系统中断
    var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid
    backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "WatchTriggeredGPS", expirationHandler: {
        // 任务超时,结束后台任务
        UIApplication.shared.endBackgroundTask(backgroundTaskID)
        backgroundTaskID = .invalid
    })
    
    // 执行你的后台操作:比如获取当前GPS位置
    // 这里只是示例,实际需要用CoreLocation框架来获取真实位置
    let gpsData = [
        "latitude": 37.7749,
        "longitude": -122.4194
    ]
    
    // 将结果返回给Watch
    replyHandler(gpsData)
    
    // 结束后台任务
    UIApplication.shared.endBackgroundTask(backgroundTaskID)
    backgroundTaskID = .invalid
}

关键注意事项

  • 后台权限配置:如果你的父应用需要在后台获取GPS,必须在iPhone的Info.plist中添加UIBackgroundModes键,包含location值(对应“位置更新”后台模式)。
  • 可达性检查sendMessage要求Watch和iPhone处于蓝牙连接状态,如果设备断开,消息会失败。如果需要离线同步,可以用transferUserInfo(_:),但这个方法不会立即唤醒后台应用,只会在应用下次启动时处理数据。
  • 真机测试:Watch Connectivity的通讯在模拟器上可能不稳定,建议用真机配对测试。

内容的提问来源于stack exchange,提问作者Oskar Gusgård

火山引擎 最新活动