Advances in Networking, Part 2

Session 709 WWDC 2017

Learn about important improvements to URLSession. Find out how to use new URLSession APIs to better handle connectivity fluctuations, to schedule background session tasks, and to receive progress reports for session tasks. Plus, gain insights into valuable best practices, tips, and news about ongoing work with emerging network technologies.

[ Applause ]

Jeff Tu: Good afternoon, everyone.

I'd like to welcome to you part two to Advances in Networking, a continuation of the session from the past hour.

My name is Jeff Tu, and I'll be taking you through the first topic.

In this session we'll discuss new URLSession developer API and enhancements, networking best practices, and other important technology areas in networking.

Our first topic is new URLSession API.

But before that, I'd like to review the underlying API we'll be talking about, which is URLSession.

URLSession is an easy-to-use API for networking introduced in iOS 7 and OS X Mavericks.

URLSession supports networking protocols like HTTP/2; HTTP/1.1; FTP; and custom streams with an overall emphasis on URL loading.

If you provide it an HTTPS URL, it also automatically provides the encryption and decryption of data between you and the web server.

Last year we deprecated NSURLConnection API.

So we encourage any new app development to occur with URLSession.

For more information on URLSession, I encourage you to review past WWDC sessions and other online documentation.

Recall that there are different kinds of URLSession objects that you can create.

The basic object you can create is a default configuration URLSession object.

Default sessions have a behavior where a task either fetches a URL immediately; or if the device can't connect to the web server, fails immediately.

URL loads can fail because the device isn't connected to the Internet or if the server you're trying to reach happens to be down.

Those are just a couple of examples.

Background URLSession objects, on the other hand, don't have this immediate fetch or fail behavior but are scheduled out of process and continually monitored for network connectivity to the server.

There are more examples of a URLSession task failing because of bad connectivity.

You might have no Internet connection, you might be in a theatre with your device in Airplane Mode or it should be in Airplane Mode.

Perhaps you have a session object where you've disallowed cell usage but the user only has cell connectivity.

Or the server might only be accessible behind a VPN and the admin recently changed VPN access.

How do you as an app developer deal with a network load that fails?

In the past, we've advised you to use the SCNetworkReachability API to monitor when you might have connectivity again to the server.

Other approaches are polling every set period of time or depending on the user to tap or drag to refresh the UI.

The problem is that these approaches add complexity to your apps and aren't always effective.

SCNetworkReachability only tells you that you might be able to reach the server, not that you will.

You, our developers, have been asking for an easier solution.

Wouldn't it be easier to say, then, "Please fetch me this resource when the network is available"?

We're happy to tell you about a new feature that lets you do this.

We call this the URLSession Adaptable Connectivity API.

This [ Applause ]

This API is available now on all platforms.

By opting into this API, you tell URLSession that in the event that the task would fail because of a lack of connectivity that it should wait for a connection to the server instead of failing.

How do you opt in?

There's a new boolean property called waitsForConnectivity.

Set this to true, and then you get the new behavior.

I'd like to repeat what this property does.

You go from the default behavior of load it now or fail now if I can't connect to load it now, but if I can't and would have failed because of a lack of connectivity, try again when I get a real chance to talk to the server.

The API also waits when it encounters DNS failures as well since one network's DNS service might fail to resolve but another one may not.

Please note that this boolean is a no op for background sessions, as background URLSession objects get this behavior automatically.

We'll tell you later in this hour more about the differences.

You may be wondering, "Can my code get a notification if it's in this waiting state?"

You might want to have the app present other behavior while it's waiting to connect.

For example, having an offline browsing mode or a mode that operates when the user is only on cell.

If you would like to know when your app is in this waiting state, you can optionally implement the URLSession taskIsWaitingForConnectivity delegate method.

Note that this delegate method is only called if you've opted into the waitsForConnectivity property with a true value.

If you've done this, the delegate method itself will be called only one time or not at all if the task never had to wait.

We recommend that your apps always opt into the waitsForConnectivity property.

This is because even when you opt in, the task will still try to run immediately.

The task will only wait if it can't connect to the server.

There are rare exceptions to opting into the property, though.

For example, if you had a URLSession task whose purpose was to buy stock at market price, you'd want that to run now or fail now and not wait until you had an Internet connection.

I'd also like to mention that when you opt into waitsForConnectivity, the timeout interval for request timer starts only after you've connected to the server.

Timeout interval for resource, however, is always respected.

Let's summarize how we would use the API and then go through a code example.

The main thing is to opt into the waitsForConnectivity property.

You would create and resume the URLSessionTask as before.

If the device can't connect to the server, we'd call a delegate callback if you implemented it and only once.

All other URLSession methods are still called same as before.

Remember, though, that this API only has an effect for non-background sessions.

Let's go through a sample code.

First create a session configuration object and make one for default session type.

Opt into the waitsForConnectivity property.

Create the session object and set the URL you want to load.

Use the session object to create a task object.

And finally, resume the task to get it started.

Even with adaptable connectivity, your request may still fail for other reasons.

For example, you could connect to the server, but a new data center employee might unplug a server, cause the network connection to drop, and all your apps on your phone might disappear.

Or your device connects to the server and sends an HTTP request, but there's so much traffic that the request times out.

For situations like these, we'd like you to consult online resources that go into more detail on what you can do.

Retrying network loads in a tight loop, though, is almost always a bad idea.

You asked for a better way to load network resources.

Better than polling for network connectivity to the server and better than reachability API that won't guarantee a connection to the server.

Let URLSession do the work for you.

Opt into the waitsForConnectivity Adaptable Connectivity API.

If you opt in, the request will still run immediately with no performance penalty and only wait if you can't connect to the server.

Once it can connect, your URLSession task behaves just like it did before.

Continuing our theme of what's new, I'd like to pass the mic to my colleague, Jeff Jenkins.

[ Applause ]

Jeff Jenkins: Thanks, Jeff.

Well, good afternoon.

Hope you guys are having a great WWDC.

And I'm exciting to be here and thrilled to talk to you a little bit more about some enhancements we've made to the URLSessionTask API.

Now, first I want to spend a little bit of time talking about background URLSession.

We haven't talked a whole lot about it, so let me give you a little bit of background on that.

The background session URLSession API allows your application to perform networking even if your process, your application isn't running.

We monitor the system conditions, CPU, battery, all sorts of things to really find of right time to do your networking tasks.

Now, of course, if you implement various delegate methods, we're going to wake up your app and call those delegate callbacks so that you can handle that information.

And, of course, we're going to make sure your app is running when your task completes so that you can then process that data.

Now, one of the great use cases for background URLSession is taking advantage of another feature on the system, which is background app refresh.

Now, what this really does is allows your application to have the most current, the freshest data, right?

There's nothing more frustrating than pulling your device out, launching an app, and the first thing you're greeted with is some sort of spinner, right?

You're waiting for this application to start pulling down data.

You want that data right away.

You want to be able to get that data to your user so your user is excited and happy to use your app.

Background app refresh is a way to do this.

It's a way to tell the system that, "Hey, in the future I want to be able to be launched so that I can refresh my data so I have the most important information," maybe stock information, or weather forecast, other important things that your app does.

Now, this applies to applications, as well as watchOS complications.

And if you want to learn a little bit more in depth about background app refresh, you can go back to 2013 WWDC, as well as last year's 2016 WWDC and look at these sessions for more details.

So let's look at background app refresh in action; what is it really doing?

And to do that, we kind of need to look at the state of your application.

We're interested in three states here: A running state, suspended state, or a background state.

Now, with your app running, you're going to opt into background app refresh.

You're going to say, "In the future, run my app, make sure my app runs so that I can get the latest information."

And then your process could be suspended.

And in the future your process is now running, your app is now going to be able to ask for new data.

And like good developers, this app is using URLSession API.

In fact, it uses a background URLSession.

It creates a URLSession task and schedules this task to run and grab the data that your application needs.

Now, your process could go away at this point, but then at some point URLSession is going to run your task and it's going to run it to completion hopefully if everything goes well.

And you're going to get the data.

So we're going to background launch your application and allow you to process that completed task and process that data that we've fetched for you.

And then at some point the user is going to launch your app, it's going to come foreground, and boom, they've got the freshest data there.

So this is great.

But we looked at this flow and said, "Hmm, maybe there's something we can do to help our developers improve their applications on our platforms."

And we think we can do something for you.

The first problem that we want to solve is we noticed there's an extra background launch that had to happen just for you to create the URLSession task.

And as we all know, anytime your process is launched, what does that do?

It impacts battery life, requires CPU burden.

So that's not necessarily great for the device if we're doing extraneous work, and we really don't need to be doing that.

The other problem we'd like to solve are stale network requests, right?

You're asking URLSession to do work.

And at some point in the future, that work is going to complete.

Well, what happens between when you ask for the work to be done and when it actually got done?

Maybe there was some change in context and that original request doesn't make sense anymore.

So we need to give you an opportunity to really, if there's a context change, let us know about that and get rid of these stale network requests.

Because there's nothing worse than getting data and going, "I can't do anything with it," and throw it away.

And the last problem we think we could help you with is helping us know how to best schedule your URLSession tasks.

When is the most optimal, best time in the system to be able to run your task so that we can get your data in the most efficient way for you to display that so that your users are excited and delighted by that data?

Let's look at what we did.

We're introducing the URLSessionTask scheduling API.

Now, this is available across all of our platforms.

It's available in the beta builds that you have received here at WWDC.

And we encourage you to take a deep look at this.

Now, what we've done first is we provided a new property.

This is a property on URLSessionTask object.

It is called earliestBeginDate.

And what you're going to do here is provide a date to us in the future when you want your task to be eligible for running.

I use that word eligible because it's important.

It doesn't mean that this is the point in time when your task will run, it will do networking; it's just telling the system, "I would like my task to be eligible so that it can run."

And we're still bound by system policies as to when we can make the networking happen for this task.

It's only applicable to background URLSessions and tasks built off of background URLSession.

Let's take a look at how this property in conjunction with other existing properties really allows you to do some fine-grain scheduling.

So you'll create a URLSessionTask and, of course, you'll call resume on it so that we know that this task can now be put into the queue so that work can happen.

You'll and at this point the task will be in a waiting state.

We're waiting for the earliestBeginDate to happen.

And as soon as that is hit, that task becomes eligible for running.

Now, you can use the existing timeoutIntervalForResource to really control how long your app is willing to wait for at that resource to get loaded, right?

You might set some amount of time to say, "After this point in time, this resource isn't interesting to me anymore."

And that interval of time covers from resume to when that timeout happens based on the value you place in timeoutIntervalForResource.

Now, I want to go back to the original background app refresh workflow that we looked at earlier.

Right? We noticed there was a couple of background launches that occurred.

But with this new API we're able to get rid of one of those.

So the way that your app will work is while your running, you're going to create a URLSessionTask; you'll opt into our new scheduling API by setting an earliestBeginDate; then your process can go to sleep.

We're going to complete the work for you.

And when that work is available, we're going to background launch you that one time and allow you to process the resulting data.

And then when the user brings your app to the foreground, boom, it's got the freshest, most current data.

And we've been able to solve that one problem of that additional background app launch.

And so it's better performing on the system, and we think that's great.

So that's problem number one solved.

Let's look at problem number two, the stale network fetches.

We want to give you an opportunity to alter future requests.

So you might have given us a request, but the context might change.

We've introduced a new delegate callback on a URLSessionTaskDelegate titled willBeginDelayedRequest.

With this delegate, you'll be able to be called at the moment when your task is about to start networking.

So it is you've told this that the task is eligible and the system now has decided yes, this is the right time to do the networking.

We're going to call this delegate method, if you implement it, and allow you to make some decisions about this task.

Now, this will only be called one, if you implement it; also, if you opt into the scheduling API by setting an earliestBeginDate.

And, again, this is only available on background URLSessions.

And as I mentioned, this is an optional delegate.

And I want to take a second here to have you really think about this because it's important, this delegate method.

As with all delegate methods, they're all opt into.

But this one will cause some interesting side effect that I'll show you in a minute.

You really need to think about, "Can my application determine context, the viability of a request in the future?"

Now, there's a completion handler that's passed to this delegate method.

And you need to give a disposition to URLSession.

You need to tell us does the original request, does it still make sense?

Go ahead and proceed.

Or maybe the context has changed enough and you need to make some modifications, maybe a different URL or maybe a header value's different and you want to go ahead and modify that request at this point in time right before the networking happens.

Or you might make the decision this request is just useless at this point, cancel.

We don't want to do stale requests.

So now if we go back to this workflow and we go back to my comment about really thinking about this delegate method, you will see that we're kind of back to that original workflow where there's two background launches in order to satisfy this URL task.

Right? But we have to stop and think about that.

What is more expensive, performing a stale network load or a mere application background launch?

It is way more expensive to the system to do stale loads, get all this data, and then decide I don't need it and pitch it.

Okay? So we want you to really think about this new delegate method and whether your application has the ability to really understand the viability of your requests in the future.

Hopefully that make sense to you.

Now, the third problem we want to solve is how do we schedule your request in a most optimal, most intelligent way in our system?

There's some information that in URLSession we just don't know about.

So we're providing a little bit of change to our API to allow you to explain to us some information about your requests and also about your responses.

We're giving you two properties, the first one is countOfBytes ClientExpectsToSend, and the second one is countOfBytes ClientExpectsToReceive.

We think you know more about your requests.

Maybe you have a stream body that you want to attach to a request, we don't know about that.

You probably know the size of that.

We don't know about your servers and the size of data your servers' shipping back.

We believe you have some insight to that.

And that will give us hints as how we can in a most optimal, intelligent way schedule your tasks.

If you don't know, well, then you can always specify NSURLSessionTransferSizeUnknown.

So that solves the third problem.

Let's take a look at how this new API works in code.

It's very easy to use.

First thing we're going to do is create a URLSession background configuration.

We're then going to create a session based on that configuration.

Once we have that, we're going to now generate a URLRequest, specify the URL we want to go to, maybe set a header value, something that makes sense for your task.

Again, this is just an example.

And now we're going to create a task that encapsulates that request on that session.

And we're going to opt into the new scheduling API by setting the earliestBeginDate property and give us a date.

In this example we say two hours from now I want this task to be eligible to be run.

And I'm also going to give some hints to URLSession and say, "This is a small request, there's no body, I've just set one header, maybe 80 bytes."

And then my server probably is going to send about a 2K response to this.

And with all URLSession tasks, make sure you call resume.

Now, how does the new delegate work?

Well, we decided I know context.

I can make some intelligent decisions about my networking tasks in the future.

So I've implemented willBeginDelayedRequest.

So in our example here what I've decided to do is to modify the request.

I'm going to take the original request, create a new updatedRequest.

I'm going to maybe change a value in the header that makes more sense now that this task is actually going to do some networking.

Time has passed, I have new information.

I put that information on that task.

And then I'm going to call the completionHandler and use a disposition of useNewRequest and passed it that new request.

If you take a look at our header file, you can see other dispositions available to you in this completionHandler call.

So let me recap the scheduling API that we're introducing here.

Background URLSession is an awesome API for doing networking that allows your application to not even be running and have this networking happen for you.

Our new scheduling API will allow you to delay your requests so that they can, you know, obtain and pull down the freshest information for your application.

And it's really we give you an opportunity to alter those things based on the context and the time at when the networking is actually going to happen.

The other part of this API change is to allow you to give hints to us so that we can be super intelligent and make these tasks run at the most optimal time on these devices.

Now, I'd like to turn the time over to Stuart Cheshire, an Apple distinguished engineer.

And thank you for your time.

[ Applause ]

Stuart Cheshire: Thank you, Jeff.

Now we're going to talk about enhancements in URLSession.

We have four things to cover, let's move through them.

Often you want to show a progress bar to indicate to the users how progress is being made.

And right now this is a little bit cumbersome.

There are four variables that you need to monitor with Key-value Observing.

And sometimes the countOfBytesExpectedToReceive or Send is not always available.

The good news now in iOS 11 is URLSessionTask has adopted the ProgressReporting protocol.

You can get a progress object from the URLSessionTask, and that gives you a variable fractionCompleted, which is a number in the range zero to one.

You can also provide strings to give more detail about what the operation is.

You can attach that progress object to a UIProgressView or an NSProgressIndicator to get an automatic progress bar.

You can also combine multiple progress objects into a parent progress object when you're performing multiple tasks, such as downloading a file, decompressing a file, and then handling the data.

So that makes your progress reporting much simpler.

The binding between a URLSessionTask and the progress object is bidirectional.

So if you suspend a URLSessionTask, that is the same as pausing the progress object.

If you pause the progress object, that is the same as suspending the URLSessionTask.

We now have support for the Brotli compression algorithm.

In tests this compresses about 15% better than gzip, which results in faster network access.

Like other new compression schemes, this is only used over encrypted connections to avoid confusing middle boxes that might not recognize this compression.

Because Safari uses URLSession, that's also means Safari gets the benefit of this new Brotli compression algorithm.

And many major websites have already announced support for Brotli in their web service.

Our next topic is the Public Suffix List.

The Public Suffix List is sometimes called the effective top-level domain list.

And this is important for determining where administrative boundaries occur in the namespace of the Internet.

One thing we don't want to allow is for a website to set a cookie on the com domain, which is then accessible to any other dot com company.

So you might be tempted to make a rule that you can't set cookies on top level domains, only on second level and lower.

But domains are named differently in different parts of the world.

In America, Apple.com and FileMaker.com are different companies.

But in Australia many, many companies are under com.au, and that doesn't make them all the same company.

So the Public Suffix List is a file of rules and patterns that tells software how to judge where administrative boundaries occur.

This is used for partitioning cookies, and it's used by the URLSession APIs.

And if you use the HTTPCookieStorage APIs directly, it's supported there, too.

We used to update this in software updates, but now with the more rapid progress in creating top level domains, we've changed to doing this over the air.

We could push a new list every two weeks if we wanted to.

URLSessionStreamTask is the API you would use if you just want a byte stream.

If you're not doing HTTP Style Gets but say you want to write a mail client, URLSessionStreamTask gives you a simple byte stream.

It supports upgrading to TLS with the STARTTLS option.

If you have existing code that is written using the old NSInputStream and NSOutputStream APIs, you can extract those objects from a URLSessionStreamTask to use your old code.

But for any new code you're writing, we strongly recommend that you use the new native URLSessionStreamTask APIs.

We announced this a couple of years ago at WWDC 2015.

What we have new for you now is automatic navigation of authenticating proxies.

If the proxy requires credentials, then we will automatically extract those from the key chain or promptly the user on your behalf.

So we've covered the enhancements for URLSession, let's move on.

[ Applause ]

Thank you.

Tips and hints that we've learned from our years helping developers.

Number one rule: Don't use BSD Sockets.

And by the same token, we encourage you not to embed libraries that are based on BSD Sockets.

Because we do lots of work, as you've been hearing today, to provide benefits to your applications.

We provide Wi-Fi Assist so that your application succeeds instead of failing when Wi-Fi isn't working.

We provide techniques to minimize CPU use and minimize battery use to give users longer battery life.

We have the ability to do tasks in the background when your application isn't even running.

And the third-party libraries just can't do anything when they're not in memory running.

And final bit of advice: Always try to use connect-by-name APIs as opposed to APIs where you resolve a name to an IP address and then connect to the address.

We talked earlier about the requirement for IPv6 support.

And the reason that almost all of your apps worked perfectly is because when you use connect-by-name APIs, you don't get involved with the IP addresses.

And if you're not involved with the IP address, you don't need to care whether it's v4 or v6, it just works.

Another question we often get is about the timeout values.

So I want to recap that.

The timeoutIntervalForResource is the time limit for fetching the entire resource.

By default, this is seven days.

If the entire resource has not been fetched by that time, it will fail.

timeoutIntervalForRequest is a timer that only starts once the transfer starts.

Once it starts, if your transfer stalls and ceases making progress for that time-out value, that when that timer will fire.

We have seen developers that take their old NSURLConnection code and convert it to the new URLSession code by mechanically making a URLSession for every old NSURLConnection they used to have.

This is very inefficient and wasteful.

For almost all of your apps what you want to have is just one URLSession, which can then have as many tasks as you want.

The only time you would want more than one URLSession is when you have groups of different operations that have radically different requirements.

And in that case you might create two different configuration objects and create two different URLSessions using those two configuration objects.

One example is private browsing in Safari where each private browsing window is its own separate URLSession so that it doesn't share cookies and other states with the other sessions.

Most apps can just have one statically-allocated URLSession, and that's fine.

But if you do allocate URLSessions dynamically, remember to clean up afterwards.

Either finish tasks and invalidate or invalidate and cancel.

But if you don't clean up, you'll leak memory.

We get developers asking us about convenience methods and delegate callbacks.

Delegate callbacks give you detailed step-by-step progress information on the state of your task.

The convenience methods, like the name suggests, are a quick and easy way of using the API.

With convenience methods you don't get all the intermediate delegate callbacks, you just get the final result reported to the completionHandler.

Don't mix and match both on the same URLSession, pick one style and be consistent.

If you're using the completionHandler, you will not get the delegate callbacks with two exceptions.

If networking is not currently available and the task is waiting for connectivity, you'll be notified of that in case you want to show some indication in your UI.

The other delegate method you may get notified is the didReceive AuthenticationChallenge.

So here's a summary of the options available to you.

Doing URLSessionTasks in your process with waits for connectivity as we recommend, the task will start immediately if it can; or if it can't, it will start at the first possible opportunity.

You also have the option of doing tasks in the background.

And you can do background discretionary tasks, which will wait until the best time in terms of battery power and Wi-Fi networking.

Now I have a couple of ongoing developments to talk about.

I'm sure many people in this room have heard about TLS 1.3.

TLS, Transport Layer Security is the protocol that encrypts your data on the network to prevent eavesdroppers from seeing it and perhaps as importantly to make sure that you have connected to the server you intended to connect to.

TLS 1.2 is very old at this stage.

It has a number of problems that have been discovered.

And TLS 1.3 is almost finished.

That standard is not quite finalized.

Apple is participating in that IETF working group, and we expect that to be finished by the end of this year.

In the meantime, we do have a draft implementation if you want to experiment with it right now.

And if you check out the security session from this Apple Developer Conference, you can learn how to experiment with that.

Another thing you may have heard of is QUIC.

QUIC is a new transport protocol designed to experiment with new ideas that are hard to do with TCP.

QUIC started out as an experiment by some Google engineers, and it was a very successful experiment.

They learned a lot.

Some ideas were good, some turned out not to work as well as they hoped.

Those engineers have taken those lessons they learned to the IETF.

We have formed a new working group to develop the IETF standard QUIC protocol.

Apple is also participating in that working group.

That is not nearly as far long as TLS is, but that is also making good progress.

Before we finish, one other thing we should talk about, Bonjour.

Fifteen year ago at this very convention center in San Jose, Steve Jobs announced Bonjour to the world.

And I got the opportunity to tell you all how it worked.

A lot has happened since then.

Since we launched it in 2004, we brought out Bonjour for Windows, for Linux.

We had Java APIs.

The next year Mac OS X 10.4 introduced wide-area Bonjour to complement the local multicast-based Bonjour that was in the original Mac OS 10.2 launch.

The same year the Linux community came out with a completely independent GPL-licensed implementation of Bonjour called Avahi.

A couple of years after that, Apple shipped Back to My Mac, which is built on the wide-area Bonjour capabilities introduced in 10.4.

And in 2009 we brought out the Bonjour Sleep Proxy, which let you get Back to Your Mac at Home, even when it was asleep to save power.

In the years since then, Android adopted with Bonjour with their own native APIs in 2012.

That was in API Level 16 for those of you paying attention.

And a couple of years ago, Windows 10 added their own native Bonjour support.

Now, I know a lot of people in this room are well aware of the history.

We know about the major OS vendors adopting Bonjour.

But something else happened that surprised even me: Bonjour started showing up in a lot of other places.

And I want to illustrate this with just a little personal anecdote.

I recently bought a new house.

And as part of the process of buying a new house, you often end up buying a bunch of new stuff.

And I started adding things to my home and connecting things to the network.

And I started finding a bunch of stuff showing up in Bonjour.

Now, I bought a new printer; it had Bonjour.

I bought some Access Network security cameras, they had Bonjour.

That didn't surprise me because we know printers and network cameras were among the first devices to adopt Bonjour.

But then I got a surround sound amplifier and it had Wi-Fi, and it had an embedded web server with Bonjour.

Now, you can set up the amplifier with the TV and the remote control, but naming the inputs with up, down, left, right on the remote control one character at a time is really tedious.

Being able to do this on my laptop or on my 27-inch iMac with a keyboard and a mouse is such a nicer way to set up a new piece of equipment.

I bought another amplifier from different company, it also had Bonjour.

I got solar panels on the roof of the house to save on the electricity bill, the inverter has Wi-Fi with an embedded web server advertised with Bonjour.

So now with one click, I can see a graph of how much power I've produced in the day.

My most recent purchase was an irrigation controller to control the sprinklers that water my lawn.

It has Wi-Fi with an embedded web server advertised with Bonjour.

Compared to trying to program your garden sprinkles with a two-digital LCD display and the plus minus buttons, this is such a glorious experience to see it all on my big iMac screen at the same time.

[ Applause ]

So thank you to all you device makers who are making these wonderful products.

For the app developers in the room, how does this affect you?

The IETF DNS Service Discovery Working Group continues to make progress.

We have new enhancements to do serve discovery on enterprise networks where multicast is not efficient and on new mesh network technologies that like Thread that don't support multicast well.

The good news for app developers is this is all completely transparent to your apps.

The APIs haven't changed because we anticipated these things even 15 years ago.

The only thing to remember is when you do a browse call and you get back a name, type, and domain, pay attention to all three.

You may be used to see the domain always being local, but now it may not be local.

So when you call resolve, make sure to pass the name, type, and domain you got from the browse call.

And for the device makers out there, don't forget to support link-local addressing.

Link-local addressing is the most reliable way to get to a device on the local network because if you can't configure it, you can't misconfigure it.

[ Laughter ]

So to wrap up, in part one we talked about ongoing progress in ECN.

It's now supported in clients and servers, the stage is set.

Any ISP can now see an immediate benefit for their customers by turning on ECN at the key bottleneck links.

Continue testing your apps on NAT64.

Mostly known use there, we're very happy everything is going smoothly.

We have a move to user space networking, which also doesn't change the APIs.

But you may notice when you're debugging and looking at stack traces, you may see symbols in the stack trace you're not used to.

You may see differences in CPU usage.

We wanted to you to be aware of that so it didn't surprise you.

We have new capabilities in the network extension framework.

And the big news, we have multipath TCP as used by Siri now available for your apps to use as well.

Thank you.

[ Applause ]

In part two, we covered some enhancements in URLSession, especially the waitsForConnectivity, which is really networking APIs done the way they always should have done.

When you ask us to do something, we should just do it, not bother you with silly error messages that it can't be done right now.

You ask us, we will do it when we can.

I gave some tips about best practices and news about ongoing developments.

You can get more information about this session on the web.

We have some other sessions we recommend you hear that you'll probably find interesting.

Thank you.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US