[英]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:这段代码目前的工作流程如下:
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:相关代码如下:
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
}
}
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
}
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)
}
}
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)
}
}
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
.我看到您正在检查
WCSession
的isReachable
属性,但是,文档页面上提到的另一个重要属性是activationState
。 It may be worth checking the value of this property before initiating the communication.在开始通信之前检查此属性的值可能是值得的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.