简体   繁体   English

当 WCSession 的 sendMessage 被触发时,iPhone 应用程序不会在后台唤醒

[英]iPhone app isn't waking in the background when WCSession's sendMessage is fired

I'm making an app for Apple Watch that needs to wake the iPhone's counterpart app which loads a site via a WKWebView, takes a snapshot, and sends the image back.我正在为 Apple Watch 制作一个应用程序,它需要唤醒 iPhone 的对应应用程序,该应用程序通过 WKWebView 加载网站,拍摄快照,然后将图像发回。

It works perfectly when the iPhone app is on-screen, intermittently when it's running in the background, but not at all when the app is completely closed.当 iPhone 应用程序在屏幕上时,它可以完美运行,当它在后台运行时,它会间歇性运行,但当应用程序完全关闭时,它根本无法运行。

Is there any way to get the iPhone app to wake up in the background with WCSession's sendMessage?有没有办法让 iPhone 应用程序在后台使用 WCSession 的 sendMessage 唤醒? I've read that it's meant to but I haven't been able to get it working.我读过它的意思,但我无法让它工作。 Is it because the iPhone app doesn't send a reply to the initial message sent by the watch (the file that the iPhone sends back has to wait for the WKWebView to finish loading, so it can't be sent back in replyHandler)?是不是因为iPhone app 没有回复watch 发送的初始消息(iPhone 发回的文件要等WKWebView 加载完成,所以不能在replyHandler 发回)? Is there a plist setting I forgot to toggle?是否有我忘记切换的 plist 设置?

The current workflow of this code is as follows:这段代码目前的工作流程如下:

  1. On the Apple Watch, the user taps a button which triggers the already activated WCSession's sendMessage function in ExtensionDelegate.在 Apple Watch 上,用户点击一个按钮,该按钮会触发 ExtensionDelegate 中已激活的 WCSession 的 sendMessage function。
  2. The iPhone app receives it using the WCSession that it activated in AppDelegate. iPhone 应用程序使用它在 AppDelegate 中激活的 WCSession 接收它。
  3. In didRecieve, the iPhone app feeds a URL into a WKWebView and starts loading it.在 didRecieve 中,iPhone 应用程序将 URL 提供给 WKWebView 并开始加载它。
  4. In WKWebView's didFinish function, it takes a snapshot of the site and sends it back to the watch with transferFile.在 WKWebView 的 didFinish function 中,它对站点进行快照并使用 transferFile 将其发送回手表。
  5. The watch receives the snapshot and passes it back to the right ViewController.手表接收快照并将其传递回正确的 ViewController。

All of these steps have been tested and verified to work while both apps are on-screen, but as soon as the iPhone enters the background or has its counterpart app closed, this workflow becomes very unstable.当两个应用程序都在屏幕上时,所有这些步骤都经过测试和验证可以正常工作,但是一旦 iPhone 进入后台或关闭其对应应用程序,此工作流程就会变得非常不稳定。

The relevant code is below:相关代码如下:

  1. After the user presses the button, the ViewController fires a notification to ExtensionDelegate with the information to transmit over WCSession.用户按下按钮后,ViewController 向 ExtensionDelegate 发送一个通知,其中包含要通过 WCSession 传输的信息。

ExtensionDelegate (sending the message): ExtensionDelegate(发送消息):

@objc func transmit(_ notification: Notification) {
        // The paired iPhone has to be connected via Bluetooth.
        if let session = session, session.isReachable {
            session.sendMessage(["SWTransmission": notification.userInfo as Any],
                replyHandler: { replyData in
                    // handle reply from iPhone app here
                    print(replyData)
                }, errorHandler: { error in
                    // catch any errors here
                    print(error)
            })
        } else {
            // when the iPhone is not connected via Bluetooth
        }
    }
  1. The iPhone app (should, but doesn't) wakes up and activates the WCSession: iPhone 应用程序(应该,但没有)唤醒并激活 WCSession:
fileprivate let session: WCSession? = WCSession.isSupported() ? WCSession.default : nil

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
       session?.delegate = self
       session?.activate()
       webView.navigationDelegate = self
       webView.scrollView.contentInsetAdjustmentBehavior = .never
        return true
    }
  1. The iPhone app receives the message in AppDelegate, and activates the WKWebView. iPhone 应用程序在 AppDelegate 中收到消息,并激活 WKWebView。 Note that there isn't a configured reply.请注意,没有配置的回复。 Could this be the cause of my issue?这可能是我的问题的原因吗?
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        
        DispatchQueue.main.async { [self] in
        let dictionary = message["SWTransmission"] as! [String: Any]
                let link = URL(string: dictionary["URL"] as! String)!
                let request = URLRequest(url: link)
                webView.frame = CGRect(x: 0, y: 0, width: Int(((dictionary["width"] as! Double) * 1.5)), height: dictionary["height"] as! Int)
                webView.load(request)
        }
    }
  1. [Still in AppDelegate] After the site is loaded, didFinish (should) gets activated, where it takes a snapshot and sends the file back to the watch via transferFile. [仍然在 AppDelegate 中] 网站加载后,didFinish(应该)被激活,它在那里拍摄快照并通过 transferFile 将文件发送回手表。
func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            
            webView.takeSnapshot(with: nil) { [self] (image, error) in
                
                let filename = getDocumentsDirectory().appendingPathComponent("webImage.jpg")
                if let data = image!.jpegData(compressionQuality: 0.8) {
                    try? data.write(to: filename)
                }
                
                self.session?.transferFile(filename, metadata: nil)
                
            }
        }
  1. The Apple Watch receives the file in ExtensionDelegate and sends it back to the relevant ViewController: Apple Watch 在 ExtensionDelegate 中接收文件并将其发送回相关的 ViewController:
func session(_ session: WCSession, didReceive file: WCSessionFile) {
        DispatchQueue.main.async { [self] in
            do {
                NotificationCenter.default.post(name: NSNotification.Name("openSite"), object: nil, userInfo: ["imageURL": file.fileURL] as [String: Any])
            } catch {
                print(error)
            }
        }
    }

Thank you very much for your help!非常感谢您的帮助!

I do not have experience working on WatchOS, but I took a look at the documentation for WCSession and it seems that what you are observing exactly matches the expected behaviour.我没有在 WatchOS 上工作的经验,但我查看了WCSession的文档,看来您观察到的内容与预期行为完全匹配。

You mention你提到

"It works perfectly when the iPhone app is on-screen, intermittently when it's running in the background, but not at all when the app is completely closed" “当 iPhone 应用程序在屏幕上时,它可以完美运行,当它在后台运行时,它会间歇性地运行,但当应用程序完全关闭时,它根本无法运行”

The Apple documentation for WCSession states WCSession 的 Apple 文档说明

When both session objects are active, the two processes can communicate immediately by sending messages back and forth.当 session 对象都处于活动状态时,两个进程可以通过来回发送消息立即进行通信。 When only one session is active, the active session may still send updates and transfer files, but those transfers happen opportunistically in the background.当只有一个 session 处于活动状态时,活动的 session 可能仍会发送更新和传输文件,但这些传输会在后台随机发生。

These two align perfectly.这两个完美对齐。 When the app is on-screen, both session objects are apparently active, and as per your observation under this scenario you see the communication happening everytime.当应用程序在屏幕上时,两个 session 对象显然都处于活动状态,并且根据您在这种情况下的观察,您每次都会看到通信发生。 When the app is in background, the session object on the app side appears to be not active, and the transfer would take place 'opportunistically', which is in-line with you observation that the communication occurs intermittently.当应用程序在后台时,应用程序端的 session object 似乎未激活,传输将“随机”发生,这与您观察到的通信间歇性发生一致。 When the the app is completely closed, it cannot be launched by the system under any circumstance as far as I know, and this is also in-line with your observation that in-this situation the communication never happens.当应用程序完全关闭时,据我所知在任何情况下都无法被系统启动,这也符合您的观察,即在这种情况下不会发生通信。

Unless you've already read through the WCSession documentation, I would suggest that you go through it.除非您已经通读了WCSession文档,否则我建议您通读 go。 I see that you are checking for WCSession 's isReachable property, however, another important property that is mentioned on the documentation page is activationState .我看到您正在检查WCSessionisReachable属性,但是,文档页面上提到的另一个重要属性是activationState It may be worth checking the value of this property before initiating the communication.在开始通信之前检查此属性的值可能是值得的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 WatchOS WCSession sendMessage的调试和状态恢复问题唤醒了被杀死的iPhone应用程序 - Debugging and state restoration concerns of WatchOS WCSession sendMessage waking killed iPhone app WatchOS2 WCSession sendMessage不会在后台唤醒iPhone - WatchOS2 WCSession sendMessage doesn't wake iPhone on background WCSession sendMessage何时无法在后台唤醒iOS应用? - When does WCSession sendMessage fail to wake iOS app in background? WCSession didReceiveUserInfo被调用,但iPhone应用程序停止后台活动 - WCSession didReceiveUserInfo gets called but iPhone app stops background activity 当watchOS应用程序使用HKWorkoutSession在后台运行时如何使WCSession可访问 - How to make WCSession reachable when the watchOS app is running in background with HKWorkoutSession 通过sendMessage唤醒父IOS应用程序不起作用 - waking up parent IOS app through sendMessage not working WatchConnectivity WCSession.sendMessage的性能 - Performance of WatchConnectivity WCSession.sendMessage 无需唤醒即可将数据发送到iPhone App - Send data to iPhone App without waking it up 从后台唤醒应用程序一定时间? - Waking up an app from background by a time interval? 当从背景唤醒应用程序时,voip推和常规推送之间的区别 - Difference between voip push and regular push when waking app from background
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM