如何在后台从附属手表应用程序启动主iOS应用程序?

13
Situation:
自从用户将他们的iOS升级到11和/或WatchOS升级到4以来,我们的iOS应用似乎在WatchOS应用启动时不会触发任何计划定时器。也许我们在从WatchOS应用程序启动我们的主应用程序时做错了什么。 Context & code:
我们的WatchOS应用程序是一个伴侣应用程序,允许用户通过按下按钮在后台启动/停止我们的iPhone应用程序。我们通过使用以下方式实现此目的:
func startMainApp() {
    guard WCSession.default().isReachable == true else {
        print("Watch is not reachable")
        return
    }

    var data = [String : AnyObject]()
    data[WatchActions.actionKey()] = NSNumber.init(value: WatchActions.startApp.rawValue as Int)

    WCSession.default().sendMessage(data, replyHandler: { (result: [String : Any]) in
        let resultNumber = result[WatchActions.resultKey()] as? NSNumber
        let resultBool = resultNumber!.boolValue
        if resultBool == true {
            self.setModeActivated()
        } else {
            self.setModeActivationFailed()
        }

    }) { (error: Error) in
        if (error as NSError).code != 7012 {
            print("start app error: \(error.localizedDescription)")
            self.setModeActivationFailed()
        }
    }
}

然后在我们的主应用程序中,我们收到该消息并启动我们的基础控制器:

func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
    if let actionNumber : NSNumber = message[WatchActions.actionKey()] as? NSNumber {
        if let watchAction : WatchActions = WatchActions(rawValue: actionNumber.intValue) {

            switch(watchAction) {
                case .isAppActive:
                    let result = BaseController.sharedInstance.sleepAndWakeUpController.isAwake()
                     replyHandler([WatchActions.resultKey() : NSNumber.init(value: result as Bool)])
                return

                case .startApp:
                    AudioController.sharedInstance().playActivatedSound()

                    let isRunningOnForeground = ApplicationStateHelper.isActive()
                    if isRunningOnForeground == false {
                        BaseController.sharedInstance.start(inBackground: true)
                    }
                    let result = true
                    replyHandler([WatchActions.resultKey() : NSNumber.init(value: result as Bool)])

                    DDLogInfo("[APPLE WATCH] [didReceiveMessage] [.startApp]")
                return
            }
        }
    }

    replyHandler([WatchActions.resultKey() : NSNumber.init(value: false as Bool)])
    return
}

一切似乎和以前一样,我们能够正确获取GPS位置并启动所有进程,但是启动的Timer对象没有触发。

在iOS 10上此方法完美运行,因此我怀疑这与iOS 11后台状态不同有关。然而,我无法找到任何相关文档。

额外信息:

  • 在iOS 10上,当我们以这种方式启动主应用程序时,该应用程序会在iPhone的多任务视图中可见。现在在iOS 11上,它在多任务视图中不可见,但它确实在后台运行。我成功看到我在后台安排的本地通知,我可以通过活动代码进行调试,并且当点击应用程序图标时,该应用立即可用。
  • 我们的WatchOS应用程序的部署目标为2.0
  • 通过连接设备的XCode进行调试,使用Debug-->Attach to PID or Name-->输入应用程序名称。然后从Apple Watch启动我们的应用程序并进行调试。
  • iOS 11.0.3上的WatchOS 4.0上可复制的iPhone 6

问题:从手表应用程序启动我们的主要应用程序的最佳方法是什么?iOS 11/WatchOS 4的后台状态是否有所改变?我能找到相关文档吗?这可能是iOS的一个错误吗?


你提到计时器不起作用,但是你分享的代码中没有一个计时器没有触发的例子。 - allenh
2个回答

6
我能提供的只是确认,这一行为确实从iOS 10到iOS 11发生了变化。我怀疑iOS 10(以及之前的版本?)上的行为是不正确的。即使开发人员已经依赖该行为(我很确定我在上一个watch项目中使用了这种行为),苹果也毫不犹豫地更改意外或被认为不正确的行为。
事实上,当由手表发送消息启动时, UIApplication 的状态为 background 。计时器不应在应用程序处于后台时运行,除非使用特定的后台执行模式/后台任务。这个事实是相当广为人知的,通常在iOS开发者职业生涯的早期就会遇到。从手表启动时计时器将在后台运行的事实,我可以推测是一个错误。
我不知道您使用计时器的原因,但您可以做的一件相当简单的事情是创建一个空的后台任务,在应用程序启动时获得更多时间。
var backgroundTask: UIBackgroundTaskIdentifier?
backgroundTask = UIApplication.shared.beginBackgroundTask(withName: "app Start Task", expirationHandler: {
    guard let task = backgroundTask else { return }
    UIApplication.shared.endBackgroundTask(task)
})

let timer = Timer(timeInterval: 1, repeats: true) { (timer) in
    print("Running")
}

如果您需要更加一致和长期运行的解决方案,您可能需要利用位置更新作为定时器当前工作的机会。还有其他许多后台模式可以追求。
您的问题总结:
Q:从手表应用程序启动我们的主应用程序的最佳方法是什么?
A:您提出的代码是启动配套应用程序的绝佳方法。
Q:在iOS 11 / WatchOS 4中是否有关于后台状态的变化?
A:特别是对于计时器方面,没有,不同的行为可能是一种修正。
Q:我能找到相关文档吗?
A:我不能。有时您可以从苹果工程师的论坛或通过您的开发者帐户的代码级支持问题中挤出这些信息,或者去WWDC。
Q:这可能是iOS的一个错误吗?
A:早期的行为很可能是错误的。

1
当应用程序关闭并且不在后台运行时,iOS 11不会跟踪位置,这不是iWatchOS 4和iOS 11的错误。
iOS 11对位置跟踪进行了更改。如果您的应用程序仅在前台使用位置(大多数应用程序都是这样的),则可能根本不需要更改任何内容。但是,如果它是那些整天持续跟踪用户位置的应用程序之一,则应该预留一些时间来更改跟踪方式并测试可能的使用方案。请参阅此文档链接: iOS 11中的位置跟踪更改
例如,让我们再考虑一下那两个应用程序;连续后台位置和重大位置变化监测应用程序。假设用户使用连续后台位置应用程序去跑步。他们会去跑步,回来后,他们会看到一直有实心箭头,并且当他们查看地图时,他们会看到他们所走的每一个弯道。当他们安装使用重大位置变化监测的应用程序时,他们会看到同样的事情,一个实心箭头。就用户而言,这个应用程序可能接收到与其跑步追踪应用程序相同的信息量。因此,如果用户误解了我们的信号,我们决定修正如何指示位置使用的最佳方式是调整它的表现方式。
watchOS可以访问iOS应用程序中发现的许多相同技术;但是,即使技术可用,您也可能无法像在iPhone上那样使用它。
不要为技术使用后台执行模式。通常,手表应用程序被视为前台应用程序;它们仅在用户与其界面之一交互时运行。因此,相应的WatchKit扩展无法利用大多数后台执行模式来执行任务。可能会帮助这份文档:利用iOS技术进行手表开发

我了解iOS 11中的权限更改。我们基于用户偏好跟踪用户位置,即“始终”或“在使用中”。但是,我认为这与我们在这里遇到的问题无关。我们的WatchOS应用程序仅限于前台应用程序,它只是一个开关,在您已经授予位置权限时在后台“打开”我们的应用程序。我自iOS 11以来看到的唯一变化是Timer不工作。位置更新似乎像往常一样。 - Thermometer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接