简体   繁体   English

iOS核心蓝牙状态保存和恢复问题

[英]iOS Core Bluetooth state Preservation and Restoration issues

I have a question regarding state Preservation and Restoration for Core Bluetooth on iOS 7. 我对iOS 7上的核心蓝牙的状态保存和恢复有疑问。

I can't seem to get it to work properly. 我似乎无法让它正常工作。 I have followed every guidline that apple mentions in their documentation for core bluetooth as well as the general documentation for state preservation. 我已经按照苹果在他们的核心蓝牙文档中提到的每个指导以及状态保存的一般文档。

For example here: Core Bluetooth Background Processing for iOS Apps and here: iOS State Preservation and Restoration 例如: iOS应用程序的核心蓝牙背景处理和此处: iOS状态保存和恢复

I can get the general state preservation to work on the device (for view controllers and objects etc.), but not for the bluetooth manager. 我可以让一般的状态保存在设备上工作(对于视图控制器和对象等),但不能用于蓝牙管理器。

As far as I know the cheklist look like this: 据我所知,cheklist看起来像这样:

  1. Opt in preservation and restoration when you allocate and initialize a central manager object by assigning a restoration identifier in the options dictionary for the key CBCentralManagerOptionRestoreIdentifierKey . 通过在密钥CBCentralManagerOptionRestoreIdentifierKey的选项字典中分配恢复标识符来分配和初始化中央管理器对象时,选择保留和恢复。

  2. Reinstantiate any central manager objects after your app is relaunched by the system. 在系统重新启动应用程序后,重新实例化任何中央管理器对象。 This is done in app delegate when the application:didFinishLaunchingWithOptions: is called. 应用程序:didFinishLaunchingWithOptions:被调用时,这在app delegate中完成。 Here I am supposed to look for the UIApplicationLaunchOptionsBluetoothCentralsKey in the options dictionary and then reinstatiate the CBManager with that key. 在这里,我应该在选项字典中查找UIApplicationLaunchOptionsBluetoothCentralsKey ,然后使用该密钥重新安排CBManager。 It is here where things go wrong since there are never any identifiers for that key, and thus I can not reinstatitate it. 在这里出现问题,因为该密钥从来没有任何标识符,因此我无法重新启用它。

  3. Implement the appropriate restoration delegate method. 实现适当的恢复委托方法。 I have done this step also, but since the manager is never re-instantiated I never receive this delegate callback. 我也做了这一步,但由于经理从未重新实例化,我从未收到过这个委托回调。

The app is working fine in the background and I have followed all the steps for that part as well. 该应用程序在后台工作正常,我也遵循该部分的所有步骤。

Now, having said all this, I am not entierly sure how to test this and that might be a part of the broblem. 现在,说了这么多,我并不确定如何测试这个,这可能是这个问题的一部分。 The way I do it now is to press the home button on the iOS device (actuall device) so that it puts the app into background and goes back to the home screen. 我现在这样做的方法是按下iOS设备上的主页按钮(执行设备),这样它就可以将应用程序置于后台并返回主屏幕。 While doing this I can tell that all the regular state preservation calls are acheived by looking at my log output. 在这样做时,我可以通过查看我的日志输出来判断所有常规状态保存调用是否实现。 After this i quit the app by pressing the stop button in Xcode to kill the background process. 在此之后,我通过按Xcode中的停止按钮退出应用程序以终止后台进程。 I now restart the app through Xcode and once again I can now see all the regular state preservation code being executed and the state gets restored on everything except the bluetooth manager. 我现在通过Xcode重新启动应用程序,现在我再次看到正在执行的所有常规状态保存代码,除了蓝牙管理器之外的所有状态都恢复状态。

If this is wrong, then please let me know. 如果这是错的,请告诉我。 But in all, I am very confused about this since it says in the Core Bluetooth docs that the preservation occurs only when " your app is relaunched by the system ". 但总的来说,我对此非常困惑,因为它在核心蓝牙文档中说,只有当“ 你的应用程序被系统重新启动 ”时才会进行保存。 What does that really mean? 那个的真实意义是什么? I also read a post on the Apple developer forum that since iOS 7 the OS will now never relaunch the app for any reason if the user kills the app manually which I am doing.. 我还在Apple开发者论坛上阅读了一篇文章,自从iOS 7以来,如果用户手动杀死我正在做的应用程序,操作系统现在永远不会以任何理由重新启动应用程序。

Any help regarding this would be much appreciated! 任何有关这方面的帮助将不胜感激!

/A /一种

When you click home button to send app to background, it it suspended, and can handle Bluetooth delegates and run in background for 10s, this feature could be realize by " add bluetooth central in background mode in info.plist", and do not use State Preservation & Restoration. 当您单击主页按钮将应用程序发送到后台时,它会暂停,并且可以处理蓝牙代表并在后台运行10秒,此功能可以通过“在info.plist中的后台模式中添加蓝牙中心”来实现,并且不使用国家保护与恢复。

If your app is terminated by IOS, due to memory pressure , it can't handle bluetooth delegates anymore. 如果您的应用程序被IOS终止,由于内存压力 ,它无法再处理蓝牙代表。 In this case, if you used State Preservation & Restoration, your app can be relaunched to background to run again, also for only 10s. 在这种情况下,如果您使用状态保存和恢复,您的应用程序可以重新启动到后台再次运行,也只有10秒。 After 10s, it would move to suspended state. 10秒后,它将进入暂停状态。 Only in this situation, CBCentralManager's willRestoreState can be triggered. 只有在这种情况下,才能触发CBCentralManager的willRestoreState。

You can add code 您可以添加代码

[kill(getpid(), SIGKILL);]

to a button action, when you click the button, your app will be terminated by IOS just like killed by memory pressure, and then "willRestoreState" will be triggered. 对于按钮操作,当您单击该按钮时,您的应用程序将被IOS终止,就像被内存压力杀死一样,然后将触发“willRestoreState”。

Good luck. 祝好运。

First, note that state preservation of view controllers has nothing to do with restoration of Core Bluetooth managers. 首先,请注意视图控制器的状态保留与核心蓝牙管理器的恢复无关。

Important : Restoration doesn't work for scanning, static characteristics and generally any use cases that do not generate connection related events. 重要说明 :恢复不适用于扫描,静态特征以及通常不会生成与连接相关的事件的任何用例。

Now the steps: 现在步骤:

  1. Make sure any of the following on the tested app: 确保测试的应用程序上的以下任何内容:
    • peripheral manager is advertising 外围经理是广告
    • peripheral manager has connected centrals 外围经理已连接中心
    • central is trying to connect to a peripheral 中央正在尝试连接外围设备
    • central is connected to some peripheral 中央连接到一些外围设备
  2. Use this app to kill your app: https://github.com/ddaddy/BackgroundKill (kudos to ddaddy, give a star on the repo) 使用此应用程序杀死您的应用程序: https//github.com/ddaddy/BackgroundKill (荣誉给ddaddy,在回购中给出一个明星)
    1. Switch to the killer app 切换到杀手级应用
    2. Start the killing process and wait until it is terminated by the system 启动查杀过程并等待它被系统终止
    3. You app is now killed 你的app现在被杀了
  3. Do some connection event 做一些连接事件
    • (Tested peripheral) subscribe to characteristics on the peripheral (经测试的外设)订阅外设上的特性
    • (Tested peripheral) start read requests on dynamic characteristics (经测试的外围设备)开始对动态特性的读取请求
    • (Tested central) make the connection request succeed (经过测试的中心)使连接请求成功
    • (Tested central) update subscribed characteristics on the peripheral (经测试的中心)更新外设上的订阅特征

Depending on what you want to test, consider the applicable points in the list. 根据您要测试的内容,请考虑列表中的适用点。 Use logging in your tested app and watch the logs in the organizer to see what happens over time. 在测试的应用程序中使用日志记录并在组织者中查看日志以查看随时间发生的情况。

I was able to get this working with scanning in the background (along with connecting and transmitting data). 我能够在后台进行扫描(连同和传输数据)。 There are important difference between how your app was terminated and if iOS will preserve and restore your Core Bluetooth Manager. 您的应用终止方式与iOS将保留和恢复您的Core Bluetooth Manager之间存在重大差异。

Adding "App communicates using CoreBluetooth" to "Required background modes" in Info.plist covers most situations. 在Info.plist中将“App使用CoreBluetooth进行通信”添加到“所需的后台模式”涵盖了大多数情况。 Your central manager will continue to work in the background — either when the user presses the home button or locks the phone (or both). 您的中央管理员将继续在后台工作 - 无论是当用户按下主页按钮还是锁定电话(或两者)。 However you will never get the "willRestoreState" delegate call in these scenarios as your central manager is still being handled by your application (it's still in memory). 但是,在这些情况下,您永远不会获得“willRestoreState”委托调用,因为您的中央管理器仍由您的应用程序处理(它仍在内存中)。

Preservation and restoration only comes into effect in one scenario — your app was terminated by iOS due to memory constraints. 保存和恢复仅在一种情况下生效 - 由于内存限制,您的应用程序已被iOS终止。 The easiest way to force this for testing it to load 3-4 memory intensive games while your app is in the background. 当你的应用程序在后台运行时,最简单的方法是强制测试它以加载3-4个内存密集型游戏。 If you review the device console, you're waiting for this message: 如果您查看设备控制台,则表示您正在等待此消息:

"Apr  4 13:16:47 Michaels-iPhone SpringBoard[58] <Warning>: Application 'UIKitApplication:com.oculeve.TearBud[0x6df4]' was killed by jetsam.”

iOS will take over you central manager at this point. iOS此时将接管您的中央管理员。 If it was scanning, it will continue scanning, if it was connect to a peripheral, it will continue to be connected. 如果是扫描,它将继续扫描,如果它连接到外围设备,它将继续连接。 In the event that you receive a central manager delegate call (didDiscoverPeripheral, didUpdateValueForCharacteristic) iOS will launch your application again in the background. 如果您收到中央管理员委托调用(didDiscoverPeripheral,didUpdateValueForCharacteristic),iOS将在后台再次启动您的应用程序。 At this point you will get the willRestoreState delegate call . 此时,您将获得willRestoreState委托调用 At this point your app is back in memory and will work as describe above. 此时,您的应用程序将返回内存,并将按上述方式工作。 Note that you need may need to do some restoration in willRestoreState if you were connected to a device. 请注意,如果您连接到设备,则可能需要在willRestoreState中进行一些恢复。 This is all covered in the WWDC 2013 Core Bluetooth video demo. WWDC 2013核心蓝牙视频演示中对此进行了全面介绍。

The kicker seems to be that restoration/preservation does not work if you manually close the app from the system tray (swiping up on your app). 如果您从系统托盘手动关闭应用程序(在应用程序上向上滑动),那么启动似乎是恢复/保存不起作用 I'm assuming Apple's reasoning for that is in this case the user is explicitly closing the app and all Bluetooth communication should cease. 我假设Apple的推理是在这种情况下,用户明确关闭应用程序,所有蓝牙通信应该停止。 This is also true is the user restarts their phone. 用户重启手机也是如此。 I'm assuming this is because a restart is basically equal to swiping up to close all the apps in the system tray. 我假设这是因为重启基本等于向上滑动以关闭系统托盘中的所有应用程序。 If you get to this point, you can only reconnect once the user opens your application again. 如果到了这一步,只有在用户再次打开您的应用程序后才能重新连接。

Something to point out is that just because your app is in the system tray doesn't mean it's in memory. 需要指出的是,仅仅因为你的应用程序在系统托盘中并不意味着它在内存中。

Why Apple doesn't just tell you this in the documentation is beyond me. 为什么Apple不会在文档中告诉您这一点超出我的范围。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM