我正在编写一个 Apple Watch 应用程序,有时我需要获取有关从用户当前位置到特定地点的步行或驾驶距离的信息。
正如 Apple 在其Apple Watch Programming Guide中所建议的那样,我通过openParentApplication
从 Apple Watch 调用并handleWatchKitExtensionRequest
在 iOS 应用程序端实现该功能,将所有艰苦的工作委派给 iOS 应用程序。因此,iOS 应用负责:1) 使用 MapKit 计算到目的地的路线,以及 2) 将获取的距离和预期时间返回给 Apple Watch。
这个操作是通过 MapKit 进行的MKDirectionsRequest
,它往往是“慢”的(比如 1 或 2 秒)。如果我直接在 iOS 应用程序中使用相同的参数测试我的代码,那么一切正常:我得到了预期的时间和距离响应。但是,在 Apple Watch 应用程序内部,回调(reply
的参数openParentApplication
)永远不会被调用,并且设备永远不会取回它的信息。
更新 1:由更新 3 替换。
更新 2:实际上,我一开始怀疑没有超时,但它似乎只有在 iOS 应用程序在 iPhone 上的前台运行时才有效。如果我尝试从 Apple Watch 应用程序运行查询而不接触 iPhone 模拟器上的任何东西(即:应用程序在后台被唤醒),那么什么也不会发生。只要我在 iPhone 模拟器上点击我的应用程序图标,将其放在最前面,Apple Watch 就会收到回复。
更新 3:根据 Duncan 的要求,以下是所涉及的完整代码,重点是丢失执行路径的位置:
(在课堂上WatchHelper
)
var callback: (([NSObject : AnyObject]!) -> Void)?
func handleWatchKitExtensionRequest(userInfo: [NSObject : AnyObject]!, reply: (([NSObject : AnyObject]!) -> Void)!) {
// Create results and callback object for this request
results = [NSObject: AnyObject]()
callback = reply
// Process request
if let op = userInfo["op"] as String? {
switch op {
case AppHelper.getStationDistanceOp:
if let uic = userInfo["uic"] as Int? {
if let transitType = userInfo["transit_type"] as Int? {
let transportType: MKDirectionsTransportType = ((transitType == WTTripTransitType.Car.rawValue) ? .Automobile : .Walking)
if let loc = DatabaseHelper.getStationLocationFromUIC(uic) {
// The following API call is asynchronous, so results and reply contexts have to be saved to allow the callback to get called later
LocationHelper.sharedInstance.delegate = self
LocationHelper.sharedInstance.routeFromCurrentLocationToLocation(loc, withTransportType: transportType)
}
}
}
case ... // Other switch cases here
default:
NSLog("Invalid operation specified: \(op)")
}
} else {
NSLog("No operation specified")
}
}
func didReceiveRouteToStation(distance: CLLocationDistance, expectedTime: NSTimeInterval) {
// Route information has been been received, archive it and notify caller
results!["results"] = ["distance": distance, "expectedTime": expectedTime]
// Invoke the callback function with the received results
callback!(results)
}
(在课堂上LocationHelper
)
func routeFromCurrentLocationToLocation(destination: CLLocation, withTransportType transportType: MKDirectionsTransportType) {
// Calculate directions using MapKit
let currentLocation = MKMapItem.mapItemForCurrentLocation()
var request = MKDirectionsRequest()
request.setSource(currentLocation)
request.setDestination(MKMapItem(placemark: MKPlacemark(coordinate: destination.coordinate, addressDictionary: nil)))
request.requestsAlternateRoutes = false
request.transportType = transportType
let directions = MKDirections(request: request)
directions.calculateDirectionsWithCompletionHandler({ (response, error) -> Void in
// This is the MapKit directions calculation completion handler
// Problem is: execution never reaches this completion block when called from the Apple Watch app
if response != nil {
if response.routes.count > 0 {
self.delegate?.didReceiveRouteToStation?(response.routes[0].distance, expectedTime: response.routes[0].expectedTravelTime)
}
}
})
}
更新 4:iOS 应用程序显然设置为能够在后台接收位置更新,如下面的屏幕截图所示:
所以现在的问题变成了:有没有办法“强制”MKDirectionsRequest
在后台发生?