tracing
While Apple and Google work on a new cross-platform contact tracing API to help tackle the COVID-19 pandemic, we’re starting to see some countries release bespoke apps built using just the existing Bluetooth APIs on each platform.
尽管Apple和Google致力于开发新的跨平台联系人跟踪API以帮助解决COVID-19大流行,但我们开始看到一些国家/地区发布了仅在每个平台上使用现有的蓝牙API构建的定制应用程序。
What we’re quickly seeing in the media about these solutions is that the iOS app has some limitations while in the background (i.e. not the visible and active app), and as a result the creators of these apps are often recommending people leave the iOS app in the foreground, or that they work better if Android devices are nearby.
我们很快在媒体上看到有关这些解决方案的信息,即iOS应用在后台运行时有一些局限性(即不是可见和活动的应用),因此,这些应用的创建者经常建议人们离开iOS应用程序在前台,或者如果附近有Android设备,它们会更好地工作。
IMPORTANT: This post is not designed to call out any specific implementation by any country, nor should you as a reader be worried about downloading any of them! Although the general consensus is it’s better if countries used the Apple|Google framework, we should still use what is currently available until something potentially better is available.
重要提示:本帖子并非旨在呼吁任何国家/地区实施任何特定的实施方式,作为读者,您也不必担心会下载任何内容! 尽管一般的共识是,如果国家使用Apple | Google框架会更好,但我们仍应使用当前可用的框架,直到可能有更好的框架可用为止。
What we’re not really seeing in the media is a high level technical explanation of exactly why bespoke iOS Contact Tracing apps seem to be so ineffective while running in the background, and why Android doesn’t have the same limitations. I aim to cover exactly that in this post at a high level. You do not need to be a developer to read this post!
我们在媒体上真正看不到的是关于到底为什么定制的iOS Contact Tracing应用程序在后台运行时似乎如此无效的高水平技术说明,以及Android为何没有相同的限制。 我的目标是在更高层次上准确地介绍这一点。 您无需成为开发人员即可阅读此帖子!
TL;DR: It’s because of the way iOS restricts developers running apps in the background to protect privacy and battery life, which is very different from how Android allows apps to run in the background.
TL; DR:这是因为iOS限制开发人员在后台运行应用程序以保护隐私和电池寿命的方式,这与Android允许应用程序在后台运行的方式有很大不同。
I really recommend you read the whole post though, you’ll learn lots about how both iOS and Android work, and more specifics about why this means bespoke Contact Tracing apps have issues on iOS, and a whole bunch more interesting stuff!
我确实建议您阅读整篇文章,您将学到很多关于iOS和Android的工作原理,以及更多的详细信息,这意味着定制的Contact Tracing应用在iOS上存在问题,以及更多有趣的东西!
什么是联系人跟踪应用程序 (What is a Contact Tracing app)
Before I go any further, you might be wondering what a Contact Tracing app is actually for. In simple terms, it is designed to keep track of people you have been in close proximity to, and if any of those people are diagnosed with COVID-19, you can be notified so you can self-isolate or get tested, and other people you’ve been close to can do the same. For that to be effective, it needs to be installed on a lot of devices!
在进一步介绍之前,您可能想知道Contact Tracing应用程序的实际用途。 简而言之,它旨在跟踪您附近的人,如果其中任何人被诊断出患有COVID-19,则会通知您,以便您可以自我隔离或进行测试,以及其他人您已经接近可以做同样的事情。 为了使它有效,它需要安装在许多设备上!
Contact Tracing apps on iOS and Android use something called Bluetooth Low Energy (LE), which I’ll just call Bluetooth throughout this post. I’m writing this post as someone who’s developed and released two iOS apps that use Bluetooth while in the background reliably, and I’ve ported one of those apps to Android which has taught me a great deal about the differences between the two platforms when it comes to running the code reliably while the app is not the foreground (visible) app.
iOS和Android上的Contact Tracing应用程序使用一种称为Bluetooth Low Energy(LE)的东西 ,在本文中,我将其仅称为Bluetooth。 我正在写这篇文章的人是谁开发并发布了两个在后台可靠地使用蓝牙的iOS应用程序,并且已经将其中一个应用程序移植到了Android,这使我在这两个平台之间有很多不同之处当应用程序不是前台(可见)应用程序时,它涉及可靠地运行代码。
COMMENT: I can tell you straight off the bat, lots of people don’t like leaving apps running. Since my users don’t even like leaving my apps running in the iOS App Switcher, they definitely would not use my app if it meant leaving the app running in the foreground (so the app is visible) at all times!
评论:我可以立即告诉您,很多人不喜欢让应用程序运行。 由于我的用户甚至不想让我的应用程序在iOS App Switcher中运行,因此他们肯定不会使用我的应用程序,因为这意味着始终让该应用程序在前台运行(因此该应用程序可见)!
Now we know what a Contact Tracing app is, let’s talk about exactly why the creators of these apps are recommending that people leave their iOS apps running in the foreground to make them more reliable, and why it’s not a problem on Android.
现在我们知道了Contact Tracing应用程序是什么,让我们确切地讨论为什么这些应用程序的创建者建议人们让他们的iOS应用程序在前台运行以使其更加可靠,以及为什么这在Android上不是问题。
iOS应用生命周期 (The iOS App Lifecycle)
Let’s start with the basics, since understanding the general lifecycle of an iOS app is important before continuing.
让我们从基础开始,因为在继续之前了解iOS应用程序的一般生命周期很重要。
When we create an iOS app, by default it cannot run in the background at all, even when it’s showing in the iOS App Switcher. When you leave the app to go to the Home Screen, or a different app, the system “freezes” the app after a few seconds and puts it into what’s called a “suspended” state. At this point, the app is no longer in the foreground, and no longer the active app.
当我们创建一个iOS应用时,默认情况下, 即使它显示在iOS App Switcher中 ,它也根本无法在后台运行。 当您离开应用程序进入主屏幕或其他应用程序时,系统会在几秒钟后“冻结”该应用程序,并将其置于所谓的“ 暂停 ”状态。 此时,该应用程序不再位于前台,也不再处于活动状态。
NOTE: It’s important to understand, your app isn’t using any battery while in the suspended state. Even though it’s showing in the App Switcher, it’s not doing anything!
注意:请务必理解,处于挂起状态时,您的应用程序没有使用任何电池。 即使它显示在应用程序切换器中,也没有做任何事情!
While in the suspended state, if another app (or iOS itself!) needs more memory (RAM) then the suspended app can be terminated. As a user, you’d still see the app in the App Switcher, but it’s just an image of the last state of the UI before it was suspended.
处于挂起状态时,如果另一个应用程序(或iOS本身!)需要更多内存(RAM),则可以终止挂起的应用程序。 作为用户,您仍然会在App Switcher中看到该应用程序,但这只是 UI暂停前的最后状态 的 图像 。
Of course, things have changed since iPhone OS 1.0 and iOS apps can now perform certain tasks while in the background, including continuing to play audio like Spotify, track your location (with permission) like Strava, and also use Bluetooth (again, with permission), like Contact Tracing apps.
当然,事情已经发生了变化,因为iPhone OS 1.0和iOS应用程序现在可以在后台执行某些任务,包括继续播放Spotify之类的音频,跟踪Strava之类的位置信息(获得许可),以及再次使用蓝牙(获得许可) ),例如“联系人跟踪”应用。
For this to happen, when we’re making our iOS app we have to declare to the system (iOS) that our app wants to do certain tasks while in the background. We declare this by enabling one or more “background modes”.
为此,在制作iOS应用时,我们必须向系统(iOS)声明我们的应用要在后台执行某些任务。 我们通过启用一个或多个“ 背景模式 ”来声明这一点。
Once we enable a specific background mode, we can then use special APIs that allow these tasks to be carried out. Each background mode has different APIs and rules, and has a different impact on your device’s battery life. For this post, all we care about are the Bluetooth ones.
一旦启用了特定的后台模式,我们就可以使用特殊的API来执行这些任务。 每种后台模式都有不同的API和规则,并且对设备的电池寿命有不同的影响。 对于本文,我们所关心的只是蓝牙技术。
蓝牙LE后台模式 (The Bluetooth LE background modes)
To use Bluetooth in the background on iOS, we need to enable one (or both) of two different background modes for our app (more on the difference between them later).
要在iOS的后台使用蓝牙,我们需要为我们的应用启用两种不同背景模式中的一种(或两种)(稍后将详细介绍它们之间的区别)。
Once we’ve enabled the right background mode(s), our app can continue to use the relevant Bluetooth APIs while not the active app, however there are some really nuanced rules around how this works and what we’re able to do.
一旦启用了正确的后台模式,我们的应用程序就可以继续使用相关的蓝牙API,而不是活动的应用程序, 但是关于它的工作原理和我们可以做的事情, 存在一些非常细微的规则 。
But, before I can go into that, I need to explain to you the two different types of Bluetooth APIs that an iOS app can use! In Bluetooth LE, there is a concept of a Central and a Peripheral.
但是,在此之前,我需要向您解释iOS应用可以使用的两种不同类型的Bluetooth API! 在蓝牙LE中,有一个Central和Peripheral的概念。
A Central is typically something like a phone or laptop. You can think of this as the client.
中央通常类似于电话或笔记本电脑。 您可以将其视为客户 。
A Peripheral is typically something like a heart rate monitor, or some device like an electric skateboard. You can think of this as the server.
外围设备通常是诸如心率监视器之类的东西,或者是诸如电动滑板之类的设备。 您可以将其视为服务器 。
The Peripheral (or server) has data, and the Central (or client) wants to read that data. The Peripheral advertises itself, and the Central can scan for it, connect to it once it finds it, and read some data. The concept of advertising and scanning is important to remember for later in this post.
外围设备(或服务器)具有数据,而中央设备(或客户端)希望读取该数据。 外围设备会做广告 ,而Central可以扫描它,找到它就连接到它,并读取一些数据。 广告和扫描的概念对于在本文后面的内容中要记住很重要。
iOS and Android apps can act as both the Central and the Peripheral at the same time, which makes them (almost) perfect for use as a Contact Tracing app.
iOS和Android应用程序可以同时充当中央和外围设备在同一时间,这使他们(几乎)完善用作接触者追踪应用程序。
联系人跟踪应用程序如何使用Bluetooth LE (How Contact Tracing apps use Bluetooth LE)
At an extremely high level, the way a Contact Tracing app could work, is every iOS and Android device with the app installed allows the app to act as both a Central and a Peripheral.
在一个非常高的层次上,Contact Tracing应用程序的工作方式是,每个安装了该应用程序的iOS和Android设备都允许该应用程序同时充当Central和Peripheral。
This means each device simultaneously advertises itself to other devices to be discovered and connected to, as well as scans for other nearby devices to discover and connect to.
这意味着每个设备同时将自己通告给其他要发现并连接的设备,并扫描其他附近的设备以发现并连接。
When they discover each other, they can connect, transfer a small amount of data to identify that device, then use that information to be able to say those two devices have been near each other.
当他们发现彼此时,他们可以连接,传输少量数据以标识该设备,然后使用该信息来表示这两个设备彼此靠近。
NOTE: I’m not going to go into specifics about privacy or cryptography here, that’s a whole different topic!
注意:我在这里不打算讨论有关隐私或加密的细节,这是一个完全不同的主题!
For it to work well, this needs to happen regardless of whether a user is currently using your app in the foreground, whether they have the phone locked, or whether they’re just using another app.
为了使其正常运行,无论用户当前是否正在前台使用您的应用程序,是否已锁定电话或是否仅在使用其他应用程序,都需要进行此操作。
For that to happen in our iOS app, we’d need to enable the two background modes I mentioned earlier that allow the app to continue to use Bluetooth APIs as both a Central and a Peripheral while no longer the active app.
为此,在我们的iOS应用程序中,我们需要启用我前面提到的两种后台模式,以允许该应用程序继续将蓝牙API既用作中央应用程序又用作外围设备,而不再使用活动应用程序。
Once we have those enabled, if we start advertising as a Peripheral, and scanning for other Peripherals as a Central, that will continue to happen when our app is no longer the active app and our app is in the background.
启用这些功能后,如果我们开始以外围设备广告,然后以中心设备扫描其他外围设备,则当我们的应用程序不再是活动应用程序且我们的应用程序处于后台时 ,这种情况将继续发生 。
Even though we’ve now enabled the background modes and are advertising and scanning, our app will still enter the suspended state after a few seconds of being in the background. The system itself actually takes over the scanning and advertising, while our app is completely frozen.
即使我们现在已经启用了后台模式并且正在进行广告和扫描,但是我们的应用在进入后台几秒钟后仍会进入暂停状态 。 该系统本身实际上接管了扫描和广告工作 ,而我们的应用程序则完全冻结了。
NOTE: This is one of the reasons Bluetooth LE apps use such little power on your iPhone!
注意:这是Bluetooth LE应用程序在iPhone上使用如此低功耗的原因之一!
Only when a Bluetooth event happens (like discovering another Peripheral) will our app get resumed (unsuspended) in the background to handle the event, shortly becoming suspended again after a few seconds.
仅当发生蓝牙事件(例如发现另一个外围设备)时,我们的应用程序才会在后台恢复(未挂起)以处理该事件,几秒钟后不久便再次挂起。
The system will carry on doing this for us as long as our app is in the App Switcher (and the iOS device is not restarted), even if our app is terminated in the background to free up memory for another app by the system.
只要我们的应用程序位于应用程序切换器中(并且iOS设备未重新启动),系统就会继续为我们执行此操作, 即使我们的应用程序在后台终止也可以为系统释放另一个应用程序的内存 。
If a Bluetooth event arrives after our app is terminated by the system, our app is re-created so we can handle it, and then it will be suspended again.
如果蓝牙事件在我们的应用程序被系统终止后到来,则将重新创建我们的应用程序,以便我们进行处理,然后它将再次挂起。
This all happens in the background, so to a user it’s seamless and seems as though our app is doing all the work. This is the magic of background execution on iOS.
这一切都是在后台进行的,因此对用户而言是无缝的,似乎我们的应用程序正在完成所有工作。 这是在iOS上执行后台的魔力。
IMPORTANT: Up until iOS 13.4, if we remove our app from the App Switcher, the system will no longer advertise and scan on our behalf, and we’ll have to wait until the app is next launched by the user to start again.
重要信息:直到iOS 13.4,如果我们从应用切换器中删除我们的应用,系统将不再代表我们做广告和扫描,我们将不得不等到用户下一次启动该应用才能再次启动。
In iOS 13.4 that behaviour seems to have changed and it will continue to stay connected after removing the app from the App Switcher, but that change is undocumented and shouldn’t be relied on.
在iOS 13.4中,该行为似乎已更改,并且在从应用切换器中删除该应用后,它将继续保持连接状态,但是该更改未记录在文档中,因此不应依赖该更改。
所以有什么问题?! (So what’s the problem?!)
That all sounds great, right? Looking at the above, it seems like iOS will continue to do the work we need for us to create our bespoke Contact Tracing app!
听起来不错,对吗? 综上所述,似乎iOS将继续完成创建定制的Contact Tracing应用程序所需的工作!
So why do the creators of bespoke Contact Tracing apps recommend that people leave the iOS app in the foreground, or do other things to keep the app working reliably?
那么,为什么定制的“联系跟踪”应用程序的创建者为什么建议人们将iOS应用程序置于前台,或者做其他事情来保持该应用程序可靠运行呢?
Well, remember earlier I said that there are some really nuanced rules around how the iOS Bluetooth background modes work? This is where that comes in.
好吧,还记得我之前说过的有关iOS蓝牙背景模式如何工作的一些非常细微的规则吗? 这就是进来的地方。
后台的iOS外围设备 (iOS Peripherals in the background)
Let’s first talk about the Peripheral background mode, because this is the main issue.
首先让我们谈谈外围背景模式 ,因为这是主要问题。
When our app is in the background and we want to let the system take over advertising for our app, it will only allow us to advertise in a way that lets other iOS devices discover it.
当我们的应用程序处于后台并且希望让系统接管该应用程序的广告时, 它仅允许我们以 允许其他iOS设备发现它的方式 进行 广告 。
This means that other Android devices scanning for nearby devices cannot find an iOS device while the iOS app is in the background (although there is an undocumented way to do it, it’s never a good idea to rely on undocumented behaviour, especially when it comes to Bluetooth).
这意味着,其他正在扫描附近设备的Android设备在后台运行iOS应用程序时找不到iOS设备 (尽管有未记录的方式来执行此操作,但依靠未记录的行为绝不是一个好主意,尤其是当涉及到蓝牙)。
Additionally, I ran a test where I kept an iOS device locked with a simple Contact Tracing example app running in the background, after 30 minutes I installed the same app onto a different iOS device, and they couldn’t discover each other until I brought the app into the foreground on one of the devices.
此外,我进行了一项测试,将iOS设备锁定为在后台运行一个简单的Contact Tracing示例应用程序 ,在30分钟后,我将同一个应用程序安装到了另一台iOS设备上,直到我将它们带回之前,他们才发现彼此将应用程序放到其中一台设备的前台。
NOTE: During my testing, I also found occasions as well where an iOS device couldn’t discover another iOS device that was locked, until I just woke the screen while it was still locked. Sometimes that was less than 30 minutes.
注意:在测试期间,我还发现了一个iOS设备无法发现另一个被锁定的iOS设备的情况,直到我刚在仍被锁定的状态下唤醒了屏幕。 有时不到30分钟。
On iOS, Peripheral advertising performance while our app in the background can also be impacted based on whether the iOS device has other apps acting as a Peripheral as well. iOS decides the performance on our behalf, and it’s not something we have any control over.
在iOS上,基于iOS设备是否还有其他充当外围设备的应用程序,也可能会影响我们在后台运行应用程序时的外围设备广告效果。 iOS代表我们来决定性能 ,这不是我们可以控制的。
后台的iOS中心 (iOS Centrals in the background)
Let’s also talk about the Central background mode. While our iOS app is in the background, the system will likely slow down the rate of scanning for nearby devices to save battery.
让我们还讨论中央背景模式 。 当我们的iOS应用在后台运行时,系统可能会减慢扫描附近设备的速度,以节省电池电量。
Although this isn’t a dealbreaker, it will definitely reduce the usefulness of scanning for nearby Peripherals which may be missed because you walked past someone while it wasn’t actively scanning.
尽管这不是一个破坏性交易,但它肯定会降低扫描附近的外围设备的实用性,因为您在没有进行主动扫描的情况下走过某个人,可能会错过它。
Android上的Bluetooth LE (Bluetooth LE on Android)
Now that we’ve learnt the restrictions the iOS system has on developers using Bluetooth while in the background, and why they’re a problem for Contact Tracing apps, we can talk about why these aren’t problems on Android.
既然我们已经了解了iOS系统对在后台使用蓝牙的开发人员的限制,以及为什么它们对于Contact Tracing应用程序是个问题,我们可以讨论为什么这些在Android上不是问题。
The Android system has a very different approach when it comes to letting apps continue to operate while they’re not the “active” app. Instead of background modes like on iOS, Android uses something called “services” to allow us to continue to run code reliably while the app is not the active app.
当让应用程序不是“活动”应用程序时,Android系统采用了截然不同的方法。 不同于iOS上的后台模式,Android使用称为“ 服务 ”的东西来允许我们在该应用程序不是活动应用程序时继续可靠地运行代码。
Specifically, these are called “foreground services”, and to use them as developers we must show a user-visible notification in the Notification Drawer.
具体来说,这些称为“ 前台服务 ”,要使用它们作为开发人员,我们必须在Notification Drawer中 显示用户可见的通知 。
The user is always able to terminate these services if they wish, although to do so they might need to force-stop the app from within System Settings.
用户始终可以根据需要终止这些服务 ,尽管这样做可能需要从系统设置内强制停止该应用程序。
Unlike an iOS app, an Android app does not have to be in the “Recents” app list (the equivalent of the iOS App Switcher) for the service to continue to run.
不像iOS应用,Android应用程序不必在“ 最近通话 ”的应用程序列表(相当于iOS的应用程序切换器的)的服务继续运行。
When we create a service, we declare it to the system in our app’s manifest file (a file the system uses to know what your app can do), and then we are free to run whatever code we want in there, potentially indefinitely.
创建服务时,我们在应用程序的清单文件 (系统用来了解您的应用程序可以使用的文件)中将其声明给系统,然后我们可以自由地在其中无限期地运行我们想要的任何代码。
This makes it perfect for running long-running Bluetooth code, acting both as a Central and a Peripheral, with very few restrictions. Exactly what our Contact Tracing app needs!
这使它非常适合运行长时间运行的蓝牙代码(既作为中央设备又作为外围设备),并且几乎没有任何限制。 正是我们的“联系人跟踪”应用程序所需要的!
This is why Android Contact Tracing apps aren’t recommended to be kept in the foreground by their creators, because there’s no need.
这就是为什么不建议Android Contact Tracing应用程序的创建者将其保留在前台的原因,因为没有必要。
Additionally, the Android Bluetooth APIs give us more options for scanning for Peripherals, which allows for an (undocumented) workaround for scanning for iOS Bluetooth apps that are only meant to be discoverable by other iOS Bluetooth apps.
此外,Android蓝牙API为我们提供了更多扫描外围设备的选项,这为扫描iOS蓝牙应用程序提供了一种(未公开的)解决方法,该方法只能由其他iOS蓝牙应用程序发现。
NOTE: This workaround is quite technical, and it’s exactly what the smart developers who created the NHSX Contact Tracing Android app have done.
注意:此解决方法是非常技术性的,这正是创建NHSX Contact Tracing Android应用程序的精明开发人员所做的 。
It involves scanning for nearby devices with very specific data encoded in an undocumented way on iOS devices. Very clever!
它涉及扫描附近的设备,这些设备具有在iOS设备上以未记录的方式编码的非常特定的数据。 非常聪明!
The tradeoff for this freedom on Android, is that we run the risk of using more battery than is necessary, and the system can start to suggest to our users that our app is using more battery than it thinks we should be. Ultimately though, the Bluetooth code is still running the same as if the app was the active app.
在Android上实现这种自由的权衡是,我们冒着使用不必要的电池的风险,并且系统可以开始向我们的用户建议我们的应用正在使用的电池超出了我们的预期。 最终,蓝牙代码仍在运行,就像该应用程序是活动的应用程序一样。
Also, unlike iOS, you have significantly more control over whether to advertise and scan more aggressively for increased performance, or conservatively to reduce power consumption. This means our Android Contact Tracing app is far more likely to discover passers by in time if we choose to.
另外,与iOS不同,您可以更大程度地控制是更积极地进行广告宣传和扫描以提高性能,还是保守地降低功耗。 这意味着,如果我们愿意,我们的Android联系人跟踪应用程序更有可能及时发现路人。
Having worked with Bluetooth on both platforms, I can say there are pros and cons to each.
在两个平台上都使用过蓝牙之后,我可以说两者各有利弊。
iOS is clearly more restrictive, but the API and hardware is more stable, because Apple have full control over it all. Android gives us far more freedom and power, but the API is more difficult to get up and running with, and some older hardware just doesn’t work as well.
iOS显然更具限制性,但是API和硬件更加稳定,因为Apple可以完全控制所有这一切。 Android为我们提供了更大的自由度和功能,但是API很难启动和运行,并且某些较旧的硬件也无法正常工作。
NOTE: At the time of writing, the official Android documentation for getting started with Bluetooth LE uses deprecated APIs!
注意:在撰写本文时,有关蓝牙LE入门的官方Android文档使用了已弃用的API!
Ultimately, using the existing Bluetooth APIs available, Android apps are better at performing the role for a Contact Tracing app.
最终,使用可用的现有蓝牙API,Android应用程序将更好地扮演联系人跟踪应用程序的角色。
Apple | Google跨平台框架在iOS上有何不同? (How is the Apple|Google cross-platform framework different on iOS?)
The reason the Exposure Notification framework currently being built by Apple and Google is better on iOS than just using the existing Core Bluetooth APIs is because Apple can avoid the previously mentioned restrictions with apps using Bluetooth in the background.
由Apple和Google当前构建的Exposure Notification框架在iOS上比仅使用现有的Core Bluetooth API更好的原因是因为Apple可以避免在后台使用Bluetooth的应用程序遇到上述限制。
Because Apple are making the framework, they can automatically give the Exposure Notification framework priority on the system, ensure that it isn’t abused by developers, and balance power consumption correctly specifically for Contact Tracing.
因为Apple正在制作该框架,所以他们可以自动为系统提供Exposure Notification框架优先级,确保它不会被开发人员滥用,并专门针对Contact Tracing正确平衡功耗。
脚注 (Footnote)
I have validated my claims with online documentation and by writing and testing some sample code which you are welcome to download and nose about in if you want!
我已经通过在线文档以及编写和测试了一些示例代码验证了我的主张,如果需要,欢迎您下载并参考这些示例代码 !
I’m on Twitter if you want to ask me any questions about this post, or sample code. Alternatively, you can open an issue on GitHub and as a question there.
如果您想问我有关此帖子或示例代码的任何问题,请访问我的Twitter 。 或者,您可以在GitHub上打开一个问题,并在那里提问。
Some useful documentation if you want to read more on the APIs available:
如果您想阅读有关可用API的更多信息,请参考一些有用的文档:
Additionally, the NHSX team have open sourced their iOS and Android Contact Tracing apps and they’re a very good example of how to use Bluetooth on both platforms.
此外,NHSX团队开源了他们的iOS和Android Contact Tracing应用程序,它们是如何在两个平台上使用蓝牙的一个很好的例子。
Stay safe! ❤️
注意安全! ❤️
tracing