Author: Big Cat, iOS developer

Review:

LoneyIsError, R&D engineer of China Mobile (Suzhou) Software Technology Co., LTD

Damonwong, iOS developer, editor of veteran driver technology weekly, works in the technology department of tao department

Explore close interaction with third-party hardware based on Session 10165

At the launch in April 2021, The AirTag came out of nowhere, and mom never had to worry about me finding my keys again. UWB technology is also slowly coming into view. It’s not just official key rings anymore. Third-party hardware licensed devices will also be able to interact with Apple. This paper introduces apple’s update of the Nearby Interaction framework, which is mainly divided into three parts: First, take a quick look at how to use the Nearby Interaction framework before, then talk about the improvements of user access in iOS 15, and finally implement a simple demo based on the latest API.

A quick review of how to use the Nearby Interaction framework

class ViewController: UIViewController.NISessionDelegate {

    override func viewDidLoad(a) {
        super.viewDidLoad()
        let token = _token
        let niSession = NISession()
        niSession.delegate = self
        niSession.run(NINearbyPeerConfiguration(peerToken: token))
    }
    func session(_ session: NISession.didUpdate nearbyObjects: [NINearbyObject]){
        nearbyObjects.forEach { (niNearbyObject) in
            print(niNearbyObject.distance!);
            print(niNearbyObject.direction!); }}}Copy the code

How do you establish a connection between two phones? First create a NISessions instance, and then follow the NISessionDelegate protocol in your code. Pass a subclass of the NIConfiguration uration to the Session instance’s run function as a configuration object. If you want to make the connection between two iPhone, you can use NINearbyPeerConfiguration do parameter, but need to know each other in the initialization of NINearbyPeerConfiguration token, This token can be transferred over the network, and when you are ready for all this, Nearby Interaction will start providing a stream of NearbyObject updates to the program, with each update containing the distance and direction (optional) to Nearby devices. If you want to learn more about the library’s API, check out last year’s talk “Meet Nearby Interaction”.

Improvements on user permissions

When your App creates a NISession session for the first time in a new life cycle, a popup window will be displayed. The popup window looks like the picture below. However, since this permission is one-off, So in some cases it can also lead to multiple pop-ups.

Permissions have been improved on iOS 15 this year, as shown in the popup below. This is the new “Nearby Interaction” permission prompt in iOS 15. It looks similar, but differs from the previous permission granting process in the following ways:

  • Prompt timing: The system automatically displays permission prompt when the application runs NISession for the first time. So make sure that the time you run NISession is the same as the time the user wants to use this feature, so it’s easy for your users to understand why you need this permission.
  • Prompt options: Let’s take a closer look at the new options on the prompt. The new OK option grants your application permissions when the application is in use. Whether the user accepts or rejects your application’s request to use nearby interactions, the permission prompt is never displayed again.
  • New permission Settings location: Starting with iOS 15, apps using Nearby Interaction will appear in Settings. So if users change their minds, they can go to the Settings app and change the app’s Nearby Interaction access. Make sure you test for changes in permissions when developing your application.

Summarize the new Nearby Interaction user permissions model. After clicking Allow in the popup window, your application will get persistent permission to use Nearby Interaction during application use. The popover will display an instruction string, configured in info.plist. In this configuration, explain briefly the interesting capabilities that accessing nearby devices in your application can provide. After the first and last prompt, your app’s name and icon will appear in Settings, which means users can change your app’s permission status at any time. When an application does not have sufficient permissions to use Nearby Interaction, all features of NISessions fail. Therefore, if critical functionality in your application depends on access to nearby devices, be sure to explain this clearly to users and guide them to use Settings to turn on configuration permissions when appropriate.

Start with a simple requirement for the new API

New features without a business scenario are just a waste of time. Here’s how to use the Nearby Interaction API to work with third-party accessories, starting with a practical business scenario.

Imagine that you define an area with A radius of 1.5 meters and another area with A radius of 3 meters around your device. You want to activate feature A when the user enters A larger area, and you want to activate feature B when the user enters A smaller area. How to use Nearby Interaction to achieve this function?

Part1 Ensure that data channels are available between hardware devices and programs

Nearby Interaction requires the ability to exchange data between hardware and applications. As to which technology is used to implement data exchange, it all depends on what capabilities the hardware devices have. Assume that the device already supports Bluetooth. Because you will be able to take advantage of existing Bluetooth capabilities for data exchange. If the hardware device is connected to the local network or the Internet, the network can be used for data exchange. The ability to transfer data between applications and accessories is a prerequisite for the next step.

Create NearbyAccessoryConfiguration range based on token

In the review above, we created NearbyPeerConfiguration when we started a session between two iphones. If you want to start with the hardware of the session, and need to create NearbyAccessoryConfiguration. This is the new NIConfiguration type in iOS 15. If you want to instantiate a NearbyAccessoryConfiguration. It needs to be provided with some configuration data, a specific data format that the system accepts to describe the device. But how do we get this configuration data, and what is this particular format? U1 compatible hardware devices (certified vendors) will know how to generate this configuration data on request. This means that your code running on the hardware device itself needs to generate this data and then send it to your application through the data channel in part1. The code is as follows:

    private func setupAccessory(_ configData: Data.name: String) {
        do {
            config = try NINearbyAccessoryConfiguration(data: configData)
        } catch let error {
            print("Bad config data from accessory \(name). Error: \(error)")
            return
        }
        / / save the token
        cacheToken(config!.accessoryDiscoveryToken,accessoryName:name)
    }
Copy the code

SetupAccessory is the tool method that I write in the application. This method should be called whenever I get configuration data from the hardware device. Now, I can use the received data to create NINearbyAccessoryConfiguration. Try to create this configuration in a DO /catch statement. The nice thing about this is that NIConfiguration’s init method throws an exception if the data is invalid. If the configuration object is successfully created, the data transmitted from the hardware is in the correct format. The ultimate goal of creating a configuration is to use it to run a session. Interacts with hardware devices.

Part3 Interacts with hardware devices

Now we are ready to interact with this hardware. To manage the interaction, you need to create an instance of NISession and set up its proxy. When starting the session, you need to pass in the Configuration created above in the run function of the NISession instance. Just as Nearby Interaction needs configuration data from hardware, hardware devices need configuration data from Nearby Interaction to know how to configure themselves. This data must be in shareable configuration Data mode. When you run a session using Configuration, Nearby Interaction will broker your application to provide shareable Configuration data. Just as we used the data channel to receive configuration data for the accessory, here we will again use the data channel to send shared configuration data back to the accessory. The code is as follows:

func session(_ session: NISession.didGenerateShareableConfigurationData: Data.for object: NINearbyObject) {
    // Get the data link from the tool method
    guard let conn = getConnection(object: object) else { return }
    // Send shared data
    conn.sendSharedableConfigurationData(data)
}
Copy the code

DidGenerateShareableConfigurationData is new in iOS 15 callback. This callback provides shareable configuration data and indicates which hardware device it should go to, which is useful when interacting with multiple hardware devices. Data should be sent to the hardware over the data channel as soon as possible. In general, managing data connections to different hardware can take many different forms, all depending on requirements. For simplicity, suppose that in my application I choose to keep a separate data connection for each accessory THAT I interact with. To make my code look neat, I define a utility function that returns me a connection based on the NearbyObject I gave it. Once I get a reference to the connection, I’ll use it to send shareable configuration data to the hardware device.

Part4 Timeout processing

If ShareableConfigurationData send fast enough, your session may timeout. The code is as follows:

func session(_ session: NISession.didRemove nearbyObjects: [NINearbyObject].reason: NINearbyObject.RemovalReason) {
    // Proceed only after timeout
    guard reason = = .timeout else { return } 
    // Obtain the hardware device
    guard let accessory = nearbyObjects.first else { return }
    // Whether the config is still valid should be retried
    if shouldRetryWithCachedConfig(accessory) {
        if let config = session.configuration {
            session.run(config)
        }
    }
}
Copy the code

Session timeouts with hardware are returned to the application through didRemove’s proxy. When Nearby Interaction gives me the didRemove callback, I will first check the reason for the removal. If the cause is timeout, and I’m pretty sure the hardware device is probably still around, try reconnecting. To determine whether this attachment should go into the retry process, I defined a helper function with specialized logic to help me make this decision. Questions such as “How many times have I tried without success?” That’s the case. “Or” Does the accessory notify me that it has stopped? Or other similar problems can be part of this decision function. If I decide to retry, all I have to do is run the session again with the same configuration. Keep in mind that the cache configuration remains in effect only if the session on the hardware device is not terminated. If the session terminates, the connection needs to be re-established. Keep in mind that a session on a hardware device is something that the code running on the device must manage and can be done in a number of different ways, all depending on the application scenario.

Part5 deals with data updates

Upon receipt of shareable configuration data, the uWB hardware on the accessory will immediately start running in the appropriate configuration to interact with NISession in the application. If the accessory and the iPhone running the application are close to each other, the session will start providing a NearbyObject update stream for your application, which contains the distance and direction to the hardware. You can even interact with multiple hardware devices at the same time by creating and running sessions for each piece of hardware. Depending on the hardware function on the accessory, you can also get equivalent adjacent updates in the code running on the accessory. Once you get NearbyObject updates from the framework, what do you do with them? As A reminder, we want to build an experience where the application and accessory enable feature A when the user enters A larger area and feature B when the user enters A smaller area around the accessory. The code is as follows:

func session(_ session: NISession.didUpdate nearbyObjects: [NINearbyObject]){
    guard let accessory = nearbyObjects.first else { return }
    guard let distance = accessory.distance else { return }
    let smoothedDistance = getSmoothedDistance(distance)

    if smoothedDistance < 1.5 {
        doA(smoothedDistance);
    } else if smoothedDistance < 3.0 {
        doB(smoothedDistance)
    }
}
Copy the code

The code shows how to do this using the NearbyObject update in an iOS application. While a session between the application and the hardware is running, updates about the hardware are called back via didUpdate. First, I’ll get a reference to a nearby object that the framework provides for us. Next, I’ll create a local variable with a distance to the object, which the framework provides in meters from the hardware. The next thing I want to do is feed this data to a utility function in my application called getSmoothedDistance. I defined this function in my application to help me guard against various exceptions that handle distance. For example, when the user suddenly moves, or when they happen to stand on the boundary between regions. Finally, I can check if the user’s distance from the accessory exceeds my predefined threshold. To enable Function A or Function B depending on the current distance.

conclusion

Nearby Interaction, which on iOS 14 is only mobile to mobile, is extended to mobile to third-party hardware on iOS 15. The capabilities of the Nearby Interaction framework have been continuously enhanced. In the future, smart furniture, AR/MR, indoor positioning, wallet, subway ticket check should have a wide range of applications.

Pay attention to our

We are the Veteran Driver Tech Weekly, a tech newsletter that continues to pursue premium iOS content. Welcome to follow.

Focus on politeness, focus on[Old Driver Technology Weekly], reply “2021” and get the internal reference of 2017/2018/2019/2020

Support the author

I recommend the WWDC21 Insider column, which contains 102 articles about WWDC21 and is the source of this article. If you are interested in the rest of the content, please click the link to read more

WWDC internal reference series is led by the old driver organization of high-quality original content series. We’ve been doing it for a couple of years, and it’s been good. It is mainly for the annual WWDC content, do a selection, and call on a group of front-line Internet iOS developers, combined with their actual development experience, Apple documents and video content to do a second creation.