Streaming is available in most browsers,
and in the Developer app.
-
Advances in Networking, Part 1
Keep up with new and evolving networking protocols and standards by leveraging the modern networking frameworks on all Apple platforms and following best practices for efficiency and performance. In this session, learn about Low Data Mode, Combine in URLSession, WebSocket, and improvements to network mobility.
Resources
Related Videos
WWDC23
WWDC21
WWDC20
WWDC19
-
Download
Welcome to Advances in Networking. My name is Joshua Graessley. My coworkers and I from Internet Technologies are excited to talk to you about a number of improvements we've made in the area of networking on our platforms this last year. In part one, we're going to talk about Low Data Mode. This is an exciting new feature where we can work together to help save our user's network data when it really matters. We'll talk about how you can write asynchronous-- very elegant asynchronous networking code using Combine in URLSession. We'll also cover WebSocket APIs. Last year, this was one of the number one things you requested in the labs and we're excited this year to be providing a solution. Finally, we'll talk about a number of mobility improvements and we'll talk about how we can work together to provide our users a more seamless experience as devices move from one network to another.
In part two, we'll cover a bunch of additional topics. That's at 5:00 today. I encourage you to come back and check that out. Now, before we dive into Low Data Mode, I want to take a minute to talk about networking APIs on our platform. The best networking APIs to use on our platform are URLSession and Network.framework. As you'll hear about in this session and in part two, there are a number of great improvements we've made and all of those improvements are available to your applications if you're using these frameworks.
If you're using sockets, you're not going to be able to take advantage of this. Unfortunately, sockets just doesn't have the richness that we require in order to provide this functionality at that layer. Now, if you're doing something like a VPN or a content filter, NetworkExtension framework is a great solution and we've made a number of improvements there as well that we'll be talking about tomorrow at 9:00 a.m. Now with that, I'd like to talk about Low Data Mode. Low Data Mode is a really exciting new feature in iOS 13.
I think the best way to introduce Low Data Mode is to have you think back to how you got here to WWDC. You probably got on an airplane to fly out to sunny San Jose. And on that airplane, there was probably a Wi-Fi network and that Wi-Fi network was probably kind of expensive of it may have been very congested and you may have been finding yourself wishing that you had some way to tell the applications and the system on your device that on this particular network it's really important to be very conservative in how you use network data. Low Data is all about solving that problem.
Low Data gives users an ability-- a preference to signal to your application and to the system that you really want to be very careful in how you use data on this network.
This can be set on a per Wi-Fi network based on SSID and a per cellular network based on SIM.
When the device is on a Low Data Mode network, this has two primary impacts. There's a change to the system policy and a change to your applications that have adopted Low Data Mode. For the system policy, we will defer any background discretionary tasks while we're on a Low Data Mode network. So, if you were on your airplane and you had Low Data Mode turned on, we would defer all of those background discretionary tasks. And when you get off the airplane and check into your hotel and you get onto the Wi-Fi network there that's potentially less congested or less expensive, then we'd let all those background tasks resume and carry on. Another change we make is that Background App Refresh is disabled. This helps us avoid allowing applications that are in the background that may have nothing to do with what the user is actually interested in from consuming network data. This gets us some pretty big wins, but we think some of the biggest wins are going to come from the changes that you're going to make in your applications to adopt Low Data Mode. So, I'd like to spend some time talking about the techniques that you can use. It all starts with looking into how your application is actually using network data. As you start to dig in, it's really important to keep in mind any time you can save data and there's no impact on the user experience, you should always do that. I know this seems kind of obvious, but you might be surprised about the ways that you can make optimizations that will reduce the amount of network data that you're using.
Now, once you've gotten through all of those low-hanging fruits where you can just get a win with no impact, then you're going to have to start making some decisions about tradeoffs.
In a lot of cases, you have the opportunity to use some more data and give a really great experience or use a little bit less data and give a still great but maybe not quite as great experience. And Low Data Mode is all about a way for the user to signal to your application that they'd really prefer that you save that data and go with the option that still gives a great experience, but maybe not quite as great. So, let's talk about some techniques you can use. The first one is to reduce image quality. If your application isn't all about images, by reducing image quality, you can save a lot of data and you can still let the user do what they're trying to do, but save data in the process.
You can reduce pre-fetching. Prefetching is a great technique for improving performance, but it has this downside that you may end up fetching resources that the user never needs. And in the event that they're really concerned about how much network data they're using, pre-fetching can actually be counterproductive.
So, when you're in Low Data Mode, you can use-- you can eliminate your pre-fetching, you can save that data. And the user may have to wait a little bit longer if they scroll that content into view to wait for it to load. You can synchronize less often. The data will be stale for a little bit longer, but you'll still have data. The user can still accomplish what they've set out to do, but over a long period of time you can actually get some pretty big savings through reduced rate of synchronization. You can mark background tasks as discretionary. You'd be surprised how many of the background tasks you're setting up don't really need to be done immediately. By marking a background task as discretionary, it gives the system a lot of flexibility in when it actually schedules that operation. As I had mentioned in-- previously-- when you're on the airplane, that gives the system the opportunity to put off that task until we get to a non-Low Data Mode network. Another great solution is to disable auto-play. This is really great because it doesn't prevent the user from playing the content that they're interested in, but it means the user doesn't have to pay for content that they really don't care about. That brings me to another really important point when you're choosing how you're going to implement Low Data Mode. Please don't block user-initiated work. Low Data Mode is all about telling the system to reduce the amount of network data that it uses, but to make sure that the user can still accomplish what they're setting out to do. As you're going through your application, you may realize that some of the operations you do do take a lot of network data and there's nothing you can do about that. It's great to reduce the amount of network data you're using for those operations any way you can, but we really don't want you to pop up a dialog that says are you sure you wanted to do this. I see you're in network data and this is going to use a lot of data. Don't second-guess the user. They've turned on Low Data Mode and they've asked your application to perform that operation. Go ahead and do that. So, let's talk a little bit about the APIs that your application can use to implement Low Data Mode.
We've added APIs to URLSession and Network.framework. The thing to keep in mind is that when a network is in Low Data Mode, the constrained property is going to be set on that network. So, all of the APIs that we provide are based on the constrained property. In URLSession, we've added a property called allowsConstrainedNetworkAccess. By default, this is set to true. Your applications are allowed to use Low Data Mode networks by default. You can set this to false to opt out. You can set this on URLSession requests as well as your URLSession configuration. With URLSession, we really encourage you to go ahead and try that large resource fetch or pre-fetch and set allowsConstrainedNetworkAccess to false. If you get a failure and the error has a network unavailable reason of constrained, that indicates the operation failed because you're in Low Data Mode and the right thing to do there is to turn around and perform your Low Data Mode operation. In the case of a large resource fetch, that would be fetching a smaller resource instead. In the case of a pre-fetch, just wait until the user actually needs the content. This has the added benefit of letting you take advantage of anything that may actually already be in the cache. Now, with Network.framework, you have a similar property called prohibitConstrainedPaths. You can set this to true to block your connections and other networking objects from using Low Data Mode networks.
With Network.framework you have another option, though. If you're going to connect to the same host whether you're in Low Data Mode or not, you can go ahead and establish that connection. And once the connection is established, you can get the current path and on the current path you can check to see if it's constrained and this will tell you whether or not this connection is established over a Low Data Mode network.
Now, if you go this route, it's really important to make sure that you handle path updates.
It's very possible that the constrained property can change over the lifetime of your connection.
So, I spent a lot of time talking about the constrained property and Low Data Mode. There are a few other properties that your application can use to make decisions about what to do on a given network. There is the expensive property, which we introduced in Network.framework last year and we're bringing to URLSession with the allowsExpensiveNetworkAccess property this year.
There's also checks for specific interface types, such as Cellular or Wi-Fi.
If you haven't adopted any of these things yet, you're in a great position to focus on adopting Low Data Mode and that's definitely the way to go. With Low Data Mode, which correlates to the constrained property, the user has control. They have a setting they control that with. Expensive, on the other hand, is a property that's set by the system and it's almost always set for cellular networks and it's also set for Wi-Fi networks when they're associated with a Personal Hotspot. You can also check for cellular, but that also is something that the user has no control over. So, if you're currently doing any checks based on cellular interfaces or expensive properties, it's a really great idea to move over to doing-- to using constrained and taking advantage of Low Data Mode. If you've looked at these options and you've decided that you still want to be making decisions based on whether something's expensive or cellular, we strongly encourage you to use expensive.
Expensive is a lot more flexible and in many ways it effectively futureproofs your application. Right now, cellular networks are almost always marked as expensive, but they may not be in the future and there are other interface types that may come around that may also be expensive. By using the expensive property, your application is going to do the right thing in the future with different interfaces. If you're checking for a specific interface such as cellular, you're not going to be able to take advantage of that. I'm really excited to see what you guys do adopting Low Data Mode. Thank you so much for your time. With that, I'd like to have Guoye come up to talk about Combine in URLSession. Thank you, Josh.
Good morning. I'm Guoye Zhang. I'm excited to tell you today about how we are supporting a new Swift framework, Combine in URLSession, and how you can use Combine to streamline your networking code.
Combine brings decorative asynchronous programming to Swift. To explain what it is, let me start with an example of building a responsive search field. So, search field publishes values whenever user types and sink here subscribes and receives a URL to start a search. In-between, we use the map operator to map the value into a URL.
Now, let's suppose I only want to start a search when there is enough content. We can use the filter operator.
The filter operator in this case drops all strings shorter than three characters.
Now we've eliminated the user's queries like a single H. However, the search still happens too frequently. What if I only want to search when user stops typing for a moment. We can use debounce operator. So, debounce delays the value and only forwards it when there is a significant delay, in this case 0.2 seconds.
However, with debounce, if user types something and deletes it, we might end up sending the same value down the chain and starting the same search over and over again. To solve this, we can add the removeDuplicates operator.
removeDuplicates remembers the last value received and only forwards a new value when it changes.
Now we have the final version of the search field by changing these powerful operators, your asynchronous code be linear and composable.
Combine processes values over time. It consists of publishers, operators, and subscribers.
The chain is driven by the request sent from the subscriber.
In response to the request, publisher sends value down the chain. This is how that pressure is handled by Combine. If you want to learn more, Introducing Combine session video will be available shortly and I encourage you to attend Combine in Practice sessions this afternoon. Networking is inherently asynchronous, that's why it's perfect to adopt Combine.
This year, we're introducing DataTaskPublisher in URLSession. It is a single value publisher and it works similarly to our existing closure based convenience methods, which means you can create it from a shared URLSession or from your own URLSession and receive authentication challenges and metrics on your delegate. This is the interface of DataTaskPublisher. It conforms to the publisher protocol. On success, it sends you a true pool of data and response. On failure, it sends you an URL error.
Now, let me give you a demo on how Combine works in URLSession.
So, for the purpose of this demo, I've disabled URL cache, so all the resources to fetch over the network. I've also used Network Link Conditioner to simulate a realistic 3G environment.
So, I am building this for a bar called PubSocket.
This app shows name, image, and item price of each item in the bar.
So, after listening to Josh's talk about Low Data Mode, I've decided to provide a high-resolution image and a low-resolution image for Low Data Mode. Right now I'm in Low Data Mode, so you see these black and white images.
And if I switch off Low Data Mode, these images are replaced with the high-resolution variant.
Let's see how this is currently implemented without Combine.
So the interface is built in UITableView and here we have the data source method cellForRowAt indexPath. In this method, we dequeue a reusable cell and configure the name and price of each item on the cell.
Then we start a URL request to fetch the high-resolution image and disable constrained network access.
pubSession here is the shared global session we use in PubSocket app and we use the pubSession to create a data task from the request.
When task finishes, we check to see if the status code is 200. OK. We convert the data into the image and put the image on the cell.
When task fails due to Low Data Mode, we create a new data task to fetch the low-resolution image.
And we do the same thing here. We check the status code, we convert the image, and put it on the cell.
Don't forget to resume these tasks.
So, as a networking engineer, I know the networking logic here is solid. I'm adhering to the best practice of not doing any pre-fetch acts. However, I'm not very happy with the current code because it has lots of duplications. We are checking the status code, converting the image twice. Also, you might have noticed I've made the very common mistake of capturing the cell and putting the image on the cell asynchronously.
The cell could have already been reused at this time by UIKit.
So, I'm going to show you the bug. I'm going to scroll down very quickly. Please pay attention to the last few items on the menu. As you can see, hot dog and drumstick have the wrong image being placed.
Let me do it again. I'm going to scroll up to the top. Please pay attention to the first few items.
Yeah, root beer and fries have the wrong image being placed on them before they are replaced with the correct one.
Now let's see how we can use Combine to fix all these issues.
First, let me delete this code to fetch.
Here we have the MenuItemTableViewCell class here. So, cell receives an image, so it's a good place to put a subscriber on it.
The subscriber here conforms to any cancelable protocol.
We can cancel the subscriber in prepare for reuse method. The cancellation happens immediately, which means we won't ever get the chance of any image being placed on the wrong cell.
Now let's go back to the TableView data source method, cellForRowAt indexPath.
We start by doing the same thing, create a URL request and fetch the high-resolution image and disable constrained network access. But instead of a data task, we create a data task publisher for the request.
Then we use the new tryCatch operator in Combine. The tryCatch operator catches the error produced by DataTaskPublisher and if the task failed because of Low Data Mode, we replace the publisher with the new publisher to fetch the low-resolution image.
Otherwise, we just rethrow the same error down the chain.
Next, let's use tryMap operator to handle the success case where we receive the data and the response. We check the status code and create an image from the data.
This map handles both high-resolution image and low-resolution image, eliminating the code duplication.
Finally, we replace the error with a placeholder image, switch the main queue, and use the assigned subscriber to put the image on the cell.
Now, this is pretty good. We've implemented the same logic with much shorter code and linear code.
But can we do more? There is one more operator I want to show you. It is called retry.
Imagine what you have to-- what you have to do before to support retry. You have to either call the data task creator recursively or maintain a state machine.
Now in Combine, I can just put retry operator right here before we replace the error.
So, retry catches the errors thrown here and it retries by restarting the chain of operators and fetches the image again. In this case, I'm just retrying once.
So, networking APIs on all platforms are designed to be very reliable, so in general you don't need to retry. However, your app might need to connect with some flaky server or meta boxes that gives you 500 server errors frequently. In this case, this tryMap operator will throw an invalid server response error, which can be caught by retry.
But please be aware that networking operation is very expensive; retry is no exception, so avoid retry if possible. If you have to retry, start with a very low number.
Also, please pay attention to the idempotence of your request.
In my app, downloading an image twice is fine, but if your app handles transaction like payment, blindly retrying could be very dangerous.
Now let me turn on Low Data Mode again.
And let's see the app running again.
As you can see, we fetched the low-resolution images just like before.
And if I turn off Low Data Mode, the same high-resolution images and we won't get any wrong images being placed on the cell.
OK. Let's go back to the slides.
To recap, I've just shown you how Combine can make your networking code concise, linear, and less error-prone. I've also shown you how composable these Combine operators are, that you can support retry by just adding one-off code. But please pay attention to use low retry count and only retry idempotent requests. Finally, I've shown you how you can use Combine with Low Data Mode without doing any pre-fetch checks.
Here is the code I extracted from my demo to do adaptive loading for Low Data Mode. It takes a regular URL and a low data URL and gives you back a publisher of data. First, we create a-- we create a request to fetch the regular URL and disable constrained network access. We use the URL-- we use the request to create a data task publisher.
Then, immediately then we handle the error caused by Low Data Mode and then we replace the publisher with a new publisher to fetch the low data URL. Next, we handle both success cases together, checking the status code and give the data back to you.
You can use this code as a starting point of Combine and Low Data Mode and customize this code to your needs.
I have to mention that some of the APIs are not available yet in current SDK. We are working on getting them into a future beta.
Next, I want to invite my colleague Jiten to talk about WebSocket. Thank you, Guoye. Good morning everyone. My name is Jiten Mehta and I'm excited to talk to you about the WebSocket protocol in Apple's networking frameworks new in iOS 13 and macOS Catalina.
In the past years, a large number of developers have asked us for the WebSocket protocol support in Apple's frameworks. In fact, it was the number one developer request from a networking survey that we conducted last year.
WebSocket allows bidirectional communication over a single HTTP connection.
This enables developers to write applications like chat, multiplayer games, and other real-time applications. WebSocket works over the well-known HTTP ports and is fully compatible with the existing web infrastructure, allowing you to connect to proxies, CDNs, and firewalls.
Historically, the WebSocket protocol has been available as a JavaScript API in web browsers, but looking at the benefits that WebSocket brings to web apps, we've decided to extend this API to our networking framework in addition to the existing JavaScript API already available in web views.
This enables you to use your existing web infrastructure and bring it to your native apps on Apple's platforms.
Before we talk about WebSocket, let's take a look at a common technique used today to enable bidirectional communication. Let's take a chat application as an example. When a client wants to receive a response from the server, it sends out a request.
The server responds with a 200 status code immediately, but it does not send out the response body because it doesn't have one at this point. Sometime in the future, once the server has a response ready for the client, it sends it out to the client. At which point, the client sends a new request, indicating that it wants to receive the next message.
This is known as long polling, but there are some disadvantages associated with long polling.
Both the end points when they want to send messages have to either send an HTTP request or an HTTP response, which is a lot of overhead.
Additionally, complexity has to be maintained at the server to enable long polling.
Let's see how WebSockets can solve this problem for us. As the first part of the first step of the WebSocket handshake, the client sends out a request to the server, indicating that it wants to upgrade this connection to WebSocket.
The server responds with the 101 switching protocol to response, at which point we have a bidirectional stream between the two end points. Both the end points are now free to send messages in either direction. They can send messages like data string or ping and pong frames without any HTTP overhead. URLSession is Apple's recommended API for HTTP. And this year we are excited to announce URLSessionWebSocketTask, a new API in the foundation framework. To create a WebSocket task, you can simply pass in the URL that you want to connect to and call resume. We will start the handshake and you need not worry about handling any of the status codes. The first part of the WebSocket handshake uses HTTP semantics, which means your URLSessionWebSocketTask will use your existing URLSession configuration objects. It will also use your network storages to do cookie and convention look ups and we will honor your delegates for any challenges.
Once you're connected, you can send data or string messages on the task.
You can also receive messages on the task by passing a completion handler, which will be called asynchronously once we receive the entire message from the server. The URLSession API for WebSockets is closer to the JavaScript API, which is based around complete messages and callbacks.
But some developers need more than this, like sever support or reading partial messages. And for that, we are excited to announce WebSocketSupport in Network.framework through the NWConnection and NWListener objects that give you both client and server support.
With this, you can have a message oriented transport protocol which can be extended for peer-to-peer communication.
You can also receive partial messages by specifying the minimum and maximum bytes for a give and receive operation. To add WebSockets to your network frame of objects, you can simply create a parameters object with TLS enabled on it. Next, create a websocketOptions and set it on the default protocol stack of the parameters.
Once you create the parameters, next you can pass in these parameters to the NWConnection constructor to create an NWConnection object. Or if you're looking to create a listener, just pass these parameters to the constructor of the listener.
The send and receive APIs remain unchanged from last year and you can continue using those to send and receive WebSocket messages.
Now, let's take a look at WebSockets in action. I'm going to build upon the application that Guoye just showed you, PubSocket, but I want to change the business model of PubSocket slightly. The price of items is now going to be dynamic and will change on demand. So, think about a stock market, but for food and drinks. So, on the left-hand side you see PubServer, which is the application that the bartender sees where they can edit the items or make changes to the price. On the right-hand side is the pub menu that we've already seen, which is the application that your clients or customers walking into the bar can see. The new feature with dynamic pricing is going to be called PubSocket+. So, see-- let's see how PubSocket+ works with our current implementation of server and client. Let's suppose the bartender wants to bump the price of root beer to $6.99. I click update.
And now the client has to pull down to refresh. And once they do that, they get the updated price of root beer. That's OK, but I'm sure we could do better than this. I want customers of PubSocket+ to have a seamless experience where they don't have to pull down to refresh and they can get the price changes live. Let's see how WebSockets can help us achieve this. Let's head over to Xcode and first I'm going to stop the server and the client. And let's head over to our server where I have an NWListener which is acting as my TCB server.
Here I have some parameters that I've created with TLS options set on them. First, I'm going to make a change here to create some WebSocket options and set it on the protocol stack of the parameters. This tells my server how to do a WebSocket handshake with clients that are trying to connect with it. The next change I would make on my server is in this function called sendPriceChanges. This function is meant to send out WebSocket messages to all the clients that are connected to it each time a price of an item changes on the server. Currently, I have a send implemented with default stream context. This means that the data that I pass to the send method is sent out as a bag of bytes on this TCB connection and it does not have any message framing. I'm going to change the context here and create a new context with some WebSocket metadata associated with it. Now, this tells my connection to send the data as WebSocket message frames. With these two changes, my server should be all set to send out WebSocket messages to my client. Now, let's see-- I can keep the server building while we head over to the client.
So, on the client side, I'm going to make changes to the function connect first; connect is going to connect to a new server and for that I'm going to use URLSessionWebSocketTask I'll simply pass in the URL to the task and then call resume so I can start doing the handshake. Once I'm connected, I'm going to call readMessage, which will receive a message back from the server. Now, let's see how readMessage should be implemented.
Inside readMessage, I'll call receive on the task and pass a completion block. On the success case, I'll update my UI with the price change and immediately after that I'll call readMessage again so I can read the next message coming back from the server. Once I make these two changes on the client, I should be all set to connect to my server and receive WebSocket messages.
So, let's run a new server and a client to see how they work. First I'm going to run my server. And now our new client reads PubSocket+, which has the new and improved WebSocket ability. Now, let's suppose it's happy hour and the bartender wants to reduce the price of root beer down to $1.99. So, let me make that change.
And I'm going to click update and then you can see on the client the price got updated without the client having to-- So, for those of you who missed it, I'm going to reduce the fries to go with that root beer-- now that's some happy hour. And once I click update, you'll see the price of fries change on the client without me having to pull down. And I'll do it once again and there the price of fries changes. So, that is WebSockets bidirectional communication without any HTTP overhead.
Some of you might be wondering what the Stats button on the top right is for. If I click that, here are some new statistics that we are collecting through our URLSession metrics API.
Additionally, at the bottom, RTT is the round-trip time between my client and my server that I'm calculating using pings and pongs in WebSockets. I'm currently using Network Link Conditioner to simulate a busy bar environment. You could use something like this to monitor the health of your connection between your client and server. If you are interested in knowing more about the new properties added to the metrics API or how to use Network Link Conditioner, please join us for the second networking session at 5:00 p.m. today. Now, let's head back to our slides.
Let's do a quick recap of PubSocket+. For our server, we used NWListener with WebSocket options set on the protocol stack. For a client, we used URLSessionWebSocketTask to connect to our server and read messages. For our transport, we used bidirectional WebSocket messages. And finally, the advantage of doing everything was bidirectional messaging with very little HTTP overhead. Let's review the APIs available for you to add WebSockets to your apps today.
WebKit gives you the ability to add WebSockets with the existing JavaScript API in your web apps and web views. New this year, URLSessionWebSocketTask built on top of Network.framework plugs into URLSession. It works with your existing URLSession configuration objects and offers automatic cookie and authentication support. It also offers a convenient way to measure round-trip time using ping and pong handling.
Also new this year, WebSocketSupport in Network.framework through the NWConnection and NWListener objects give you both client and server support.
It gives you direct access to complete and partial messages, including ping and pong frames. You can optionally set custom headers like cookies or other authentication headers through the websocketOptions object.
We are happy to be opening up this technology to all developers and we're excited to see what you do with this. Next, I would like to invite Christoph to talk about mobility improvements. Thank you, Jiten. Hello everyone. I am Christoph and I am going to show you what mobility improvements we did in iOS 13.
So, users are often experiencing this. When they are walking out of their home, when they are far away from their Wi-Fi access point, the signal of Wi-Fi gets worse and often the applications become slower because the networking becomes slower as well. Sometimes the applications completely fail. And so people have gotten used to this that when they are walking out of their home they just swipe up to the Control Center and turn off Wi-Fi.
Now, I am sure we have all experienced this, right? So, we want to change this. We believe that users should never have to turn off Wi-Fi when they are walking out of their home. We believe that your applications should just work even when Wi-Fi is in a very bad condition.
And I'm sure everybody here in this room wants to achieve the same goal. So, let me show you how we can get there.
This is the way we usually represent Wi-Fi. We have the Wi-Fi access point in the middle, concentric circles around it that show how the Wi-Fi signal is gradually fading away, getting weaker and weaker as the phone gets farther and farther away. In this kind of scenario, it would be very simple for a phone to decide whether to use Wi-Fi or switch over to cell. Right? Now, the problem is that this kind of representation of how Wi-Fi looks is actually very far away from reality. In reality, it looks more like this. You have the Wi-Fi access point in the middle and then a very spotty Wi-Fi signal around it. And the spottiness is because of the objects in the room are interfering with the signal. The house, the walls, everything is making the Wi-Fi signal a very uncertain indicator of the quality. And a tiny little movement of the phone could move the phone from a good position to a bad position. So, for the phone, it's really difficult to know whether Wi-Fi is still good or bad. It might still receive the beacons from the access point, but the signal might nevertheless be too low to actually send or receive any data. So, in this kind of environment, the phone needs to decide whether to use Wi-Fi or whether to use cell. It's this uncertainty around the Wi-Fi signal that is the whole challenge around mobility.
So, at Apple, we have been aware of this problem for quite a while and I will show you how in the past we have done many steps to improve this kind of scenario. All of it started back in iOS 7 with Siri.
In iOS 7, we introduced Multipath TCP for Siri. Multipath TCP allows to use Wi-Fi and cell at the same time. So, starting in iOS 7, whenever people are using Siri and walking out of their home, Multipath TCP will make sure that the traffic goes either Wi-Fi over cell, reducing the latency for Siri users and reducing the error rates.
We are seeing great results thank to Multipath TCP.
Now, a real end-to-end multipath protocol, like Multipath TCP, requires both the client and the server to be aware of it. Both need to work together, right? They need to work together to decide whether to send the traffic on Wi-Fi or on cell. And so we asked ourselves how can we improve mobility without having both the client and the server have to work together without requiring the need to modify the server configurations.
And the answer came two years later in iOS 9 with Wi-Fi Assist. Wi-Fi Assist handles mobility for all applications, for all flows, talking to any server. And the way it does it is by first starting on Wi-Fi and when the signal is bad and the connection doesn't, manages to get established quickly enough, we will just raise another connection over the cellular link. Since iOS 9, since we are-- since we introduced Wi-Fi Assist, all of your applications that are using the high-level APIs can benefit from Wi-Fi Assist and are having a much better experience when the user is mobile. And this works for any server talking to any servers on the internet.
Now, Wi-Fi Assist might still get stuck on Wi-Fi, if for example the connection managed to get established, but then the signal degraded afterwards. And those flows would then still be stuck. In order to handle those kind of scenarios better, one still needs real end-to-end multipath, the same way as we have it for Siri. So, after four years of experience with Multipath TCP for Siri, we decided to open up the API for every one of you. So, since iOS 11, you can start using the handover or interactive mode in URLSession or the Network.framework. So, when you are able to make sure that your servers are ready, you can enable Multipath TCP and get the same benefits as Siri.
So, in each of those releases, iOS 7, iOS 9, iOS 11, we focused on one specific area to improve mobility.
We focused on Multipath TCP, we focused on Siri, we focused on Wi-Fi Assist. And now comes iOS 13. And in iOS 13, we improved so many things they don't even fit on this slide anymore.
In iOS 13, the mobility improvements-- thank you. Thank you. In iOS 13, the mobility improvements go throughout the whole system. Many different frameworks, daemons, applications, from the firmware to the driver. Everything is now improved for mobility. And in this part of the session, I am going to talk about two of them; Wi-Fi Assist and Multipath Transports.
So, first up, Wi-Fi Assist. Traditionally, Wi-Fi assist has only been taking very limited amount of information into account to decide whether Wi-Fi is good enough. Now in iOS 13, we changed that.
We made it such that all components in the system are providing information into Wi-Fi Assist so that Wi-Fi Assist has a full cross-layer mobility detection. The lower layers, Wi-Fi and cell, are providing information about the signal quality in a much fine-- more fine-grained way than in iOS 12. And also, the higher-layer frameworks like Network.framework, URLSession, other daemons of the system, they are all providing information into Wi-Fi Assist about how their flows are making progress. All of this information going into Wi-Fi Assist will then allow it to detect whether we are in a mobility scenario or not and whether we should maybe start trying to use cell. So, all of this information, then Wi-Fi Assist is going to take its decisions and feeds it back into the system. It tells the lower layers, Wi-Fi and cell, to make efforts to improve the signal quality. And it also communicates to the other layers like Network.framework and URLSession to start recovering flows. All of this leads to a much improved flow recovery.
Now, even when a flow has already been established on Wi-Fi and has started to exchange data, if later on the signal quality is reducing, we are able to move the next request that would have been used on Wi-Fi, we are able to move that one over to cell. So, your applications should now much less be getting stuck on Wi-Fi. Now, the question for you, of course, is how can you get the benefits from Wi-Fi Assist? How can you get the benefits from all the improvements that we did in iOS 13? So, first of all, the way you can get them is by using the high-level APIs like URLSession and Network.framework. All of these APIs have been built with Wi-Fi Assist in mind and they are getting the full benefit from it. So, make sure that your applications are using those APIs. Next up, some of you are doing active interface management with APIs like SCNetworkReachability. You are maybe doing pre-flight checks to know where is your request going to end up on. Is it going to go on Wi-Fi or on cell? The problem with those pre-flight checks is that when you do it and the moment when you actually use the connection, the interface might have changed. Wi-Fi Assist might have decided to actually send your flow over to cell or Wi-Fi might have significantly improved. So, the pre-flight check is a very bad indicator of where your flow is going to end up on. So, we encourage you to rethink your usage of the pre-flight checks and come talk to us later in the labs about why you need it and we will work with you to find an alternative.
Now, if you still need to steer flows, for example, away from cell because, for example, the data transfer is way too big or the traffic is not critical for the user experience, you can use helpers like allowsExpensiveNetworkAccess and set them to false. That way, your request is not going to go on the cellular link.
So, this is Wi-Fi Assist and we made a lot of efforts to make it even better in iOS 13 and you can get the benefits by using the high-level APIs. This brings me to the next one, which is Multipath Transports.
Siri has been using it for quite a while now. We have opened up the API two years ago and we have encouraged you to look into your apps and see which of your flows might benefit the most from Multipath TCP. So, this year in iOS 13, we ran this well and looked into our own apps and decided to see which one is going to benefit from Multipath TCP. Which one is often used when mobile and has a very critical flow for the user experience that is hard to recover? Well, one application is Apple Maps. Most users, well, when they are getting their directions, they are walking out of their home and they are using search. So, in iOS 13, we enabled Multipath TCP for Apple Maps. Now, whenever you are walking out of the home and using Maps, looking up your directions, trying to search a restaurant, MP TCP will be used and move your flow over from Wi-Fi to cell. And since Monday, since the first beta, we have been enabling it and we are going to see a much better responsiveness for Apple Maps.
The next one where we are having a very critical user experience and that is also often used when walking out of the home is when you are streaming music. Right? When you are streaming music, you are downloading a large file full of music content and you don't want this music to stall. Because when it stalls, the user will be disrupted. So, since iOS 13, we enabled Multipath TCP for Apple Music. We are seeing much less music streaming stalls because MP TCP is now moving flows over to cell whenever we are getting close to stalling. And so the user is going to have a much better experience. Now, the thing about this, we have enabled it for Siri, Maps, and Music, and you can do this too. We recommend-- we encourage you to look into your applications. Which one is often used when walking out of the home? Which one has a very critical flow that is critical for the user experience and that is hard to recover? Those kind of flows, they are perfect for the multipath service type and you can choose them on handover or interactive in the URLSession and Network.framework.
Now, don't forget, if you do enter in multipath, it still requires both the client and the server to work together, so go and visit this URL to make sure that your servers are configured correctly.
So, this brings me to the end of the mobility part of this session.
If there is one thing that we want you to remember, it's that whenever a user is walking out of their home, he should not have a bad experience and turn off Wi-Fi. So, when you are developing your applications, when you are testing them and you are configuring a bad Wi-Fi network and you are walking out of the home while testing it, don't expect your applications to become slow, to fail, or your flows to basically-- to take forever. It should, in principle, just work. If it doesn't, make sure that those flows that have been failing are using the high-level APIs. These APIs are getting the full benefit from Wi-Fi Assist from all the improvements that we did in iOS 13. If you are doing active interface management, come talk to us in the lab or send us an Apple Bug Report. Tell us about your use case and we will work together with you to find an alternative so that you can avoid doing this active interface management and get the full benefits from Wi-Fi assist. And, finally, if you have flows that are still getting stuck on Wi-Fi and that are hard to recover, try to see if you can start using a multipath service type, get your servers ready, and get the same benefits as Apple Music, Maps, and Siri. So, this is the end of this part of the session. We have seen that with the Low Data Mode users can now turn on marked networks so that they reduce the data usage on those networks. We have exposed a new API so that your applications can benefit from it as well. If you are building a publisher subscriber style application, Combine in URLSession allows you to build you a very elegant app, the same way as Guoye has shown you today. Finally, WebSockets. It has been the most requested feature is making it into iOS 13 and so you can easily build two-way communications into your applications. And, in iOS 13, we did a huge push to improve the mobility for your applications so you can get the same benefits by using the high-level APIs. So, later this afternoon, there is a part two of the Advances in Networking session. You will be seeing more exciting new APIs that will benefit your applications. Tomorrow, for those among you that are developing on macOS, there are new APIs for network extensions, and we also have the lab at 9:00 a.m. starting at 9:00 a.m. tomorrow and you can come there to ask us questions and we will be very happy to help you out. So, this is the end. I hope you had fun and you enjoyed the session.
Thank you very much. [ Applause ]
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.