Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Good morning.
Welcome to Session 709, "Cross
Platform Nearby Networking".
My name is Demijan, and
I'm a Software Engineer
in the Real-time
Networking Team at Apple.
Last year we introduced a new
framework called Multipeer
Connectivity in iOS,
which makes it really,
really easy to discover and
communicate with nearby devices.
Building a network with nearby
devices can be accomplished
with only a few lines of code.
Many, many apps have decided
to adopt Multipeer Connectivity
for their nearby
networking needs.
And some of the use cases we've
seen have really made us smile,
so I'd like to mention
some of them to you today.
First, iTranslate Voice:
iTranslate Voice is an app
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
First, iTranslate Voice:
iTranslate Voice is an app
that brings real-time
translation to iOS users.
They use Multipeer Connectivity
to connect multiple devices
together and enable people
who don't share a
common language
to communicate with each other.
One person speaks a
sentence into their device
in their language, and the other
person hears the translation
of that sentence on
the other device.
It's really, really cool.
Second example is an app
called Metronome Touch.
Metronome Touch synchronizes
multiple metronomes,
and a metronome is a tool
that musicians use to play
to the same beat or
follow the same tempo.
Now Metronome Touch uses
Multipeer Connectivity
to accurately synchronize
multiple iOS devices
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to accurately synchronize
multiple iOS devices
so that the metronome on each
device ticks in perfect sync.
And, third, FireChat,
FireChat brings nearby chatting
to our customers.
People who are nearby can now
communicate with each other even
when there is no internet
connection available.
This type of application
can be particularly useful
in environments, like subway
stations or airplanes,
for example, but
also in countries
with limited internet access.
We've seen many other use cases
for Multipeer Connectivity
and some of the prevalent ones
have been to exchange data,
such as files, and to
to-do lists for example,
and remote control
functionality.
Now throughout the year we've
heard a lot of good feedback
from you guys and we've
heard a lot of good ideas,
but one request that has come
up over and over again has been
to bring Multipeer
Connectivity to the Mac.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to bring Multipeer
Connectivity to the Mac.
So this year I'm
really happy to announce
that we're bringing
Multipeer Connectivity
to OS X starting with Yosemite.
From now on you will be able
to do cross-platform nearby
networking between iOS
and OS X devices just as easily
as you have been so far on iOS.
And the API is exactly the same,
so you should be
ready in no time.
All right, so let's talk
about the agenda for today.
First, I want to talk about
some basics so we set the stage
for the rest of the talk.
Then I will talk about
Multipeer Connectivity on OS X,
where I'll focus on some of
the specifics that are true
for development on OS X and
for the OS X experience.
Next, I will talk about
a few best practices.
And, finally, I'd like to cover
a few more advanced topics,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And, finally, I'd like to cover
a few more advanced topics,
namely custom discovery
and authentication.
So let's start with the basics.
Multipeer Connectivity supports
three wireless technologies
on iOS-Bluetooth, Infrastructure
Wi-Fi, and Peer-to-Peer Wi-Fi.
On OS X we will support
Ethernet, Infrastructure Wi-Fi,
and Peer-to-Peer Wi-Fi, as well.
So I'd like to talk about
Peer-to-Peer Wi-Fi for a moment.
Peer-to-Peer Wi-Fi
enables you to communicate
with other nearby devices
even if they're not connected
to the same access point,
or if they're not connected
to an access point at all.
So, many of you have wondered
which devices support
Peer-to-Peer networking.
So I'd like to talk
about that a bit.
Well, on iOS it's pretty simple.
If your iOS device has the new
Lightning Connector then it
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If your iOS device has the new
Lightning Connector then it
supports Peer-to-Peer Wi-Fi.
If it doesn't, it won't
support Peer-to-Peer Wi-Fi,
but on those devices you
can still use Bluetooth
and Infrastructure Wi-Fi.
For Macs, the story
is also pretty simple.
If you have a Mac that
was released in 2012
or later then it will have
support for Peer-to-Peer Wi-Fi.
Okay, so let's establish
some terminology
that we will use throughout
the rest of the talk.
First, nearby, by nearby I
will mean anything that is
within the range of supported
wireless technologies.
A peer, a peer will be a device,
either our own or
a nearby device.
An advertiser will be a device
that makes itself discoverable
to other devices nearby.
And the browser will be a
device that is searching
or discovering other
nearby devices.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
or discovering other
nearby devices.
Multipeer Connectivity
happens in two phases.
First, the discovery phase,
where the devices
discover each other
and establish a communication
session
by sending invitations
to each other.
Then when they're connected into
a session, the second phase,
called the session
phase, begins,
where they can exchange
data with each other.
So let's start with
the discovery phase.
The first approach
to discovery phase
that we support is UI-based
and it's the most simple one.
We have a browser
and an advertiser.
An advertiser has to
instantiate a peer ID object,
a session object, and an
advertiser assistant object.
It then starts by
calling the start method.
The browser similarly
instantiates a peer ID,
a session, and the
browser view controller.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It then presents the
browser view controller
to the user to start browsing.
The rest of the process will
be entirely user-driven,
and you will be notified when
the peers connect into a session
with the session delegate
method, peer:didChangeState,
where the state will be
specified as connected.
So that was the UI-based
approach.
The programmatic
approach requires you
to do a little bit more work,
but it gives you much
more flexibility.
So, again, we have a
browser and an advertiser.
The advertiser instantiates a
nearby service object instead
of an advertiser
assistant object.
And the browser instantiates a
nearby service browser object
instead of the browser
view controller.
The browser starts by calling
startBrowsingForPeers method,
and the advertiser starts by
calling startAdvertisingPeer.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and the advertiser starts by
calling startAdvertisingPeer.
So now both of them
are-the browser is browsing,
and the advertiser
is advertising.
When the browser discovers the
advertiser you will be notified
with a delegate method,
foundPeer.
At that time the browser
can send an invitation
to the advertiser by calling
the invitePeer method.
When the browser calls the
invitePeer method an invitation
will be sent out
to the advertiser,
and when the advertiser receives
the invitation you will be
notified with the did receive
invitation from peer method.
At that time, the advertiser
has to decide whether it wants
to accept or reject
the invitation.
And let's say it
accepts the invitation,
then a message will be
sent back to the browser,
and they will start
connecting into a session.
When they connect with
each other, again,
you will be notified
with the delegate method,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you will be notified
with the delegate method,
peer:DidChangeState, where
the state will be specified
as connected.
So this was the discovery phase.
Let's now cover the
session phase.
So in the session
phase we assume
that the nearby peers
are already connected
with each other, and now what
they want to do is they want
to exchange data
with each other.
Well, Multipeer Connectivity
supports three sets of APIs
for exchanging that
data-messages,
streaming, and resources.
Let's start with messages.
A message is a chunk of data
with well-defined boundaries.
If you want to send a message
you can use the sendData method,
where you will pass the
message as the first parameter,
encapsulated in an
NSData object.
You will also have to specify
an array of peers that you want
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You will also have to specify
an array of peers that you want
to receive the message.
When you receive a message
you will be notified
with a delegate method,
didReceiveData, which will pass
to you the message
and the sender.
Now if you want to send really
large amounts of data or data
without well-defined boundaries,
such as a live audio stream,
for example, then you might
be better served using our
streaming APIs.
And to start a stream
you can call the method,
startStreamWithName, which
will give you an NSOutputStream
object that you can use to
stream data to the recipient.
The recipient will be notified
where the delegate
method didReceiveStream,
and that method will give
it an NSInputStream object
that the recipient can use
to receive streaming data.
And, third, resources, we
support files and web URLs
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And, third, resources, we
support files and web URLs
to send as resources, and
you can send a resource
by using sendResourceAtURL
method, where you specify
that the URL method of the
resource you want to send
and you specify which peer
you want to send it to.
You will also have to pass
to the framework a
completion handler,
and that completion
handler will be called
when the resource has
finished transmitting
or if something went wrong
during the transmission.
Now the receiver, when it
starts receiving a resource,
will be notified with
a delegate method,
didStartReceiving
ResourceWithName,
and when the resource finishes
being received it will be
notified with a delegate method,
didFinishResourceWithName.
Okay, so in summary, we've
covered the discovery phase
and the session phase.
You can do UI-based discovery
or programmatic discovery,
which gives you a
bit more flexibility,
and in the session phase you
can use APIs to send data
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and in the session phase you
can use APIs to send data
where we support messages,
streaming and resources.
Much more in-depth information
about these topics can be seen
at our last year's
WWDC presentation,
which you can see online.
All right, let's proceed with
Multipeer Connectivity on OS X.
The good news is that the APIs
on OS X are exactly the same
as APIs on iOS, nevertheless,
there are some differences
that are different to the
OS X experience and I would
like to talk about those now.
Let's start with
UI-based discovery.
Imagine I have an app.
I have a Mac, which
is running an app
that uses Multipeer
Connectivity.
I want to see if
somebody is around,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I want to see if
somebody is around,
so I bring up the
browser view controller.
The browser's view controller
is presented as a modal sheet,
and in the lower left corner you
can see an activity indicator,
which indicates to us
that we're browsing.
Currently there is
no one nearby.
Let's then assume
that Gabe comes nearby
and Gabe is also running an app
that uses Multipeer
Connectivity.
Moments later, we'll see in
our UI that Gabe is nearby,
and if I want to invite
Gabe into a session I have
to press the Invite
button in the table view.
So I go ahead and do that.
When I do that, an invitation
will be sent out to Gabe.
And when Gabe receives the
invitation, we will present,
the framework will present an
alert that will notify Gabe
that I want to connect to him.
At this time Gabe needs
to decide whether he wants
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
At this time Gabe needs
to decide whether he wants
to accept or decline
the invitation.
So let's assume Gabe is
game and wants to accept,
and accepts the invitation,
so he clicks on Accept.
And an accept message
is sent back to me.
At that moment we
will start connecting,
and when we're finished
connecting it will say
so in the UI next to Gabe,
and I will be able to click
on the Done button, which
will dismiss the browser view
controller, and I
am connected to Gabe
and start exchanging
data with him.
So this was the flow for
UI discovery on Mac OS X.
Let's now see how you can
implement this in code.
Now, first, you have to
instantiate an advertiser,
and this is done much
the same, like on iOS.
First, you instantiate the
advertiser assistant object
and you start it.
Now for the
MCBrowserViewController on OS X,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
subclass is NSViewController,
unlike UIViewController in iOS.
Note that NSViewController
has seen substantial changes
in Yosemite, and you can see
or you can hear much more
about those changes in
the session, "Storyboards
and View Controllers".
So to set up the browser
view controller on OS X,
I have to instantiate it, and
I have to set the delegate.
Then I have to-then I present
the browser view controller
by using one of the new
NSViewController APIs,
presentViewControllerAsSheet,
and I pass the browser
view controller object.
Note that "self" here is a
subclass of an NSViewController.
We realize that you might be,
that your architecture might not
be based on NSViewControllers,
and in that case you might want
to present the view
controller using the
NSAppBeginSheet method.
Well, if you want to do
that you can do that,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Well, if you want to do
that you can do that,
but first you will have
to get an NSWindow object
for the browser view controller.
And you can do so by using
one of the new methods
on NS window called
windowWithContentViewController.
That method will give
you back an NS window
for the browser view
controller, and once you have
that NSWindow object you
can use the beginSheet API
to present the browser view
controller to the user.
When the user is done using
the browser, it will click
on either Done or Cancel button,
and when that happens you will
be notified via the delegate
methods,
browserViewControllerDidFinish
and browserView
ControllerWasCancelled,
respectively.
In those methods you'll have
the opportunity to react
to whatever action the user
has taken and you will have
to dismiss the browser
view controller
by using the
dismissViewController method.
Next, I want to talk
about entitlements.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Next, I want to talk
about entitlements.
If you are sandboxed, either
voluntarily or because you ship
on the app store you will have
to set entitlements
appropriately.
Multipeer Connectivity you
need support for both incoming
and outgoing connections,
so you'll have
to enable entitlements
for these operations.
If you don't do that, then
Multipeer Connectivity
on OS X just won't work,
so make sure you do that.
And that's really
everything that is different.
Everything else, like
programmatic discovery
and sending data, for instance,
is exactly the same as on iOS,
so you should be
ready in no time.
Okay, at this point I would
like to invite Eric on stage,
who will show you a demo.
>> Thanks, good morning,
everyone.
My name is Eric, and today I'd
like to show you a quick demo
of Multipeer Connectivity,
so let's switch over.
Great, so let's say
we're at a party
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Great, so let's say
we're at a party
and everyone is taking photos.
It would be really cool if we
could collect all those photos
onto a map and display them
on a really large screen
for everyone to see.
To simulate this
sort of application,
today we have two iOS devices.
Here I have a white
iPhone and a pink iPhone,
and we also have a Mac,
and we'll be using
Multipeer Connectivity
to connect them together.
And whenever the iOS devices
take photos they'll transmit
them over to the Mac.
So let's take a look
at this in more detail.
Over here we have the Mac app,
on the left-hand side
we'll have a photo roll,
where the new photos will
pop in, and over here
on the right-hand side
we'll have a larger view
of the latest photo that we got.
Down here in the corner we
have a little Browse button.
So let's get started.
I'll go ahead and click
on the Browse button.
So here's the browser
that we saw earlier.
Right now it's currently empty.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Right now it's currently empty.
When I launch the iPhone app
it will start advertising,
and the browser will
be able to discover it,
and it'll pop up in the list.
So I'll go ahead and do
that here, so there it is.
And I can go ahead and do
the same on the other iPhone.
Great, so now we have
both of the devices.
We can go ahead and
invite the white iPhone.
Over here I received the
invitation, so I'll go ahead
and tap Accept, and we
can see that it connected.
I'll do the same for the
pink iPhone, so invite it,
and over here I'll accept.
Great, so now both of the
devices are connected,
we can go ahead and
click on the Done button
to dismiss the browser, and we
can start taking some photos.
So I'll grab the white
iPhone, and let's see
if we can get a shot of
this camera right here.
Great, so it's sort of an
antique camera, I guess.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Great, so it's sort of an
antique camera, I guess.
Let's see that with the
phone, we can compare them.
So you can see how far
we've come with the cameras.
Here's let me switch over
to the pink iPhone phone,
and let me take a picture
of this little rabbit thing.
Great, let's see, maybe I can
take one of myself, and then,
let's see, we'll switch over.
Here's a little thing
of bismuth.
Great, okay, so let's see
if we can take a quick look
at what the iOS side looks like.
Okay, great, now that
was a quick demonstration
of cross-platform nearby
networking with Multipeer.
So let's talk a little bit
about how I built the demo.
On the iOS side, I took a piece
of sample code called AB Cam
that teaches you how
to use the camera.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Whenever we save
a new still image,
all we do is we take
the URL for the new file
and we use the sendResource
API we just saw,
and that sends it
over to the Mac side.
Over here on the Mac
side I took a piece
of sample code called
Image Browser
and it just teaches you how
to display a grid of
images, like this.
I added in Multipeer
Connectivity to bring
up the browser, and whenever we
receive a new resource we just
add that into the image
list's data source array.
So if you'd like to
learn more about how
to use Multipeer Connectivity
in your own apps we
hope you will check
out last year's iOS sample code,
it's called Multipeer
Group Chat.
And we're really looking
forward to seeing what sort
of new apps you guys
can come up with.
With that, I'd like to
hand it back to Demijan.
Thanks, everyone.
>> Thank you, Eric.
So Multipeer Connectivity
on OS X is much
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So Multipeer Connectivity
on OS X is much
like Multipeer Connectivity
on iOS.
In this section we've shown you
the UI-based discovery on OS X,
and we've told you which
entitlements you need to enable
to make Multipeer
Connectivity work in OS X apps.
Next I'd like to talk
about a few best practices
that we thought you
guys should be aware of.
So let's assume we have two
devices, a Mac and a phone,
and let's say the
Mac is advertising
and the iPhone is browsing.
Moments later the iPhone
will discover the Mac
and it will have a reference or
it will have its peerID object.
Then let's assume that for
some reason the Mac goes away.
For instance, the user
could have closed the lid
for some reason or the user
could have reset the system
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for some reason or the user
could have reset the system
because of a software update.
When the Mac comes back it will
instantiate a new peerID object
and a new advertiser, and
the iPhone will discover it,
but it will see a new
object for the peer,
which actually corresponds
to the same Mac.
So this can lead to many issues
because iPhone doesn't know
that these two objects actually
correspond to the same device.
So in order to circumvent
that problem, we recommend
that you reuse peerID objects.
After you've created
a peerID object
for the first time you can
store it in the user defaults,
so the next time you need it you
don't have to create a new one.
So if the Mac, when
it comes back,
reuses the first peerID object,
the iPhone won't be confused
and it will only have one
object that represents the Mac.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and it will only have one
object that represents the Mac.
Now let's see how you
guys can do this in code.
Once you've instantiated
the peerID object,
you'll need to store it
in the user defaults.
And to do so, you'll first have
to serialize the
peerID object using the
archivedDataWithRootObject
method.
Once the peer is serialized
into an NSData object you can
save it in the user defaults.
Later when you need to
de-serialize it and retrieve it
from the defaults
you'll first have
to de-serialize it using
unarchiveObjectWithData method,
and then when you have the
original peerID object you can
use it in your application.
Next auto inviting, many of
you have made applications
that both advertise and
browse at the same time,
and when a browser sees an
advertiser it immediately sends
an invitation.
Basically, what you want
to achieve with this is,
if you want to abstract
away the connection process
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if you want to abstract
away the connection process
from the user.
As soon as another user is
seen you want the devices
to connect to each other.
So let's assume we
have a Mac and a phone,
and both are browsing
and advertising.
So soon they will
discover each other,
and they will have a peerID
object of the other peer.
But now the question
is who will be the one
to send an invitation?
And here's where many
of you get confused.
So in order to solve this
problem you can use a
deterministic algorithm
that will on both sides come
to the same result so that
only one peer will be the one
to send an invitation.
Now there are many ways you
can do that, and one of them is
to use peer ID hash
values or hash value
of the peer ID object.
Since both sides have access to
the same two peer ID objects,
they will come to the
same determination as to
who has the higher hash value,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
who has the higher hash value,
and only one invitation
will be sent out.
Next I want to talk about
discovery info a little bit.
Multipeer Connectivity
uses Bonjour underneath
for discovery, and you have the
option to set additional data
for advertisers when
you instantiate them.
Now this additional data
is passed to the framework
in the form of an NSDictionary
that we call discoveryInfo,
and discoveryInfo is very useful
because it is made available
to the browsers when they
discover an advertiser.
So first thing I want to advise
is to keep discoveryInfo small,
this will make the discovery
experience much better
for your users.
Next both keys and values
in discoveryInfo must
be of type NSString.
If any key or any value in the
discoveryInfo dictionary is not
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If any key or any value in the
discoveryInfo dictionary is not
of type NSString, the
framework will complain
and throw an exception.
Also, you should know
that each key value pair
in the discoveryInfo dictionary
underneath gets formatted
in a Bonjour text record entry,
and each Bonjour text record
entry has a specific format,
which is shown in this slide.
First the key, followed by an
equal sign, and then the value.
Note that each text record
entry is limited to 256 bytes,
and if any key-value
pair when formatted
as a text record
exceeds 256 bytes,
the framework will complain
again and throw an exception.
For more details
on Discovery Info
and Bonjour text records
I'd like to refer you
to the Bonjour RFC, which can
be obtained at the link quoted
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the Bonjour RFC, which can
be obtained at the link quoted
at the bottom of this slide.
Okay, so now we're ready to
tackle on some advanced topics,
and I'd like to start
with custom discovery.
We've covered two approaches
to discovery so far.
The first one was UI-based,
and it's really simple.
All you have to do is
instantiate an advertiser,
instantiate a browser,
and everything else is
entirely user-driven.
Now this approach is
very simple to implement,
but the framework
gives you the UI,
so you don't have much
flexibility there.
If you want to design
your own framework,
you can use the programmatic
approach.
Now the programmatic
approach requires you
to do a little bit more work,
but you have much more
flexibility in terms
of how you define
the user experience.
So even given that we
have these two approaches,
we realize that there may be
some of you who have the need
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we realize that there may be
some of you who have the need
to have or to define the
discovery experience even more
or to customize it even more.
And for those, we
offer a third way,
which we call the
custom approach.
Now the custom approach might
be useful for those users
that operate in environments
that is not Bonjour friendly,
for instance, or you
may have the need
to exchange large amounts of
data during the discovery phase
and that data cannot fit in
the discoveryInfo dictionary.
So if you fit into one of those
categories you might find custom
discovery useful.
So let's go over custom
discovery in this section.
First, let me say that for
custom discovery you are
in full control of the discovery
process, so we will assume
that you will implement
a mechanism to discover
who is nearby and you will also
establish a one-to-one data link
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
who is nearby and you will also
establish a one-to-one data link
between nearby peers.
So this will be your job.
Now the goal for nearby
peers will be to connect
into a Multipeer session
where they can exchange data
with other peers on
a many-to-many basis.
So let's see how
they can do that.
Assuming that we've
discovered nearby peers
and we've established
a one-to-one data link
between them, let's see
what you have to do in order
to connect them into a session.
First, each peer will need to
instantiate a peerID object
and a session object, and then
it will have to-they will both
have to complete a
two-step process.
First, they will have to
exchange their peerID objects
over the one-to-one data link.
So, in order to do that,
they will first have
to serialize their peerID
object and pass them
over to the other peer.
Once the serialized ID object
is available they'll have
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Once the serialized ID object
is available they'll have
to de-serialize it, and at
that moment they'll have the
peerID object of the other peer.
Once the peerID object
is available they'll have
to generate nearby
connection data
by calling
nearbyConnectionDataForPeer
method.
When nearby connection data
becomes available they will have
to exchange that object much
like before with the other peer,
so this is the second step
of the process, and when both
of these objects are available
on the other side
you can connect them
into a session using
connectPeer:withConnectionData
method.
When they are done
connecting, much like before,
you will be notified
with a delegate method,
peer:didChangeState, and
the state will be specified
as connected.
Okay, so let's see how
we can do this in code.
Now serializing
and de-serializing can
be accomplished much
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and de-serializing can
be accomplished much
like we've described before
in the best practices section.
You can use, for serializing you
can use NSKeyedArchiver APIs,
and for de-serializing you can
use NSKeyedUnarchiver APIs.
So now that we've exchanged
the peerID objects we have
to generate connection data,
and to generate nearby
connection data you can use
nearbyConnectionData
withCompletionHandler method.
The framework, when it's done,
will call the completion
handler, where it will pass
to you the object that
contains nearby connection data.
Then you will have to send that
object over to the other side
and when all peers have both
objects for the peer they want
to connect with they can do
so by calling connectPeer
withNearbyConnectionData.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
In this method you also have the
opportunity to specify a timeout
in seconds, and this timeout
will let the framework know how
long you're willing to wait
until the peers successfully
connect in a session.
If for some reason you change
your mind during the connection
process you can cancel it
by calling cancelConnectPeer
method.
So in summary we've described
a fully customized discovery,
which you can use if you
can't use the UI-based
or the programmatic
approach for your needs.
It consists of a
two-step process.
First, you need to exchange the
peerID object, then you need
to exchange nearby connection
object, and when both
of these objects are available
for the other peer you can
connect it into a session.
Next up is authentication.
So some apps, for
instance, those that deal
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So some apps, for
instance, those that deal
with money transactions think
an app that enables people
to split a taxi cab
bill will have to rely
on properly implemented
security to provide safe
and trustworthy experience
to their users.
Multipeer Connectivity
gives you the option
of enabling encryption
and authentication
for providing security
to your users.
Now enabling encryption is
pretty easy, all you have
to do is set the flag when
you instantiate the session,
but in authentication it is
a little bit more involved.
So let's take a look
at how you can deal
with authentication
in this section.
If you want to provide
authentication
to your users you will have
to make sure that each one
of your users has
a digital identity,
and a digital identity consists
of a private key
and a certificate.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of a private key
and a certificate.
The users will use the private
key to sign their messages
and they will make their
certificate available
to other users so they can
verify if the signature is valid
and if they can trust
the sender.
In code, a digital
identity is represented
by a SecIdentityRef object.
The private key is represented
by a SecKeyRef object.
And the certificate
is represented
by a SecCertificateRef object.
There are multiple ways how
you can distribute digital
identities to your users.
Perhaps the best way is to
make identities available
on a trusted web server so that
the users can download them
from that trusted web
server from within the app.
Other ways include
e-mail attachments
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
or via a mobile device
management server.
For more detailed
information on this topic,
I'd like to refer you to the
Tech QA 1745, and the link
for this is also provided
at the bottom of this slide.
Now let's see how you can import
a digital identity in your code.
Usually the digital identity is
stored in a PKCS#12 data file,
and these files are
password-protected.
So the first thing you'll
need to do is get the password
for the file and store
it in a dictionary.
Next you will have to get
access to bytes in that file
by using dataWithContentsOfURL
method,
and once bytes are available you
can import the digital identity
by using SecPKCS12Import method.
This method will import the
digital identity from the bytes
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This method will import the
digital identity from the bytes
that we have from the file
and store it in an array.
So now you know what
a digital identity is,
how to distribute
it to your users,
and how to import
it in your apps.
Note that only certificate part
of your digital identity is
made available to other users,
and the other users can use
that certificate to verify
if you are really who
you claim you are,
and they can make a decision
if they want to trust you.
So let's look at how
they can verify this.
An end-user certificate
can be issued
by a trusted root certificate
authority or it can be issued
by an untrusted intermediate
certificate authority whose
certificate was issued by a
trusted certificate authority.
This hierarchy of
certificates that starts
with the end-user certificate
on the left and ends
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with the end-user certificate
on the left and ends
with the trusted
root certificate
on the right is often referred
to as the chain of trust.
Roughly speaking, when we
evaluate the chain of trust,
the following step-wise
procedure happens.
First, we inspect the
end user's certificate
and check if it's valid.
Let's assume it is, next,
we inspect the intermediate
certificate
and check if it's valid.
We also check if the end
user certificate was, indeed,
issued by the intermediate
certificate authority.
Say that checks out,
as well, finally,
we have to inspect
the root certificate,
and we check if it's valid.
We also check if the
intermediate certificate was,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We also check if the
intermediate certificate was,
indeed, issued by the
trusted certificate authority,
and if that checks out, as well,
then the chain of
trust is valid.
So in code when you
evaluate the chain of trust,
the first thing you'll have to
do is create a policy object.
This policy object will
govern how the chain
of trust is evaluated.
Then you will have to
create the chain of trust,
and once you have the chain
of trust you will
have to evaluate it.
So let's see how you
can do this in code.
First, we need to
create the policy,
and for our purposes we can use
SecPolicyCreateBasicX509 API,
which will create a
policy, an X509 policy
because we're dealing with
X509-type certificates.
Next, we have to
create the trust object
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Next, we have to
create the trust object
by using
SecTrustCreateWithCertificates
API, and we also have to
set anchor certificates.
By anchor certificates we
mean the root certificates
that can be trusted
by the system,
so we have to let the system
know which certificates can be
at the end of the
chain of trust.
Once that is established, we
can evaluate the chain of trust
by calling the SecTrustEvaluate
method,
and the result will be stored
in the second parameter.
Now if the result equals
kSecTrustUnspecified,
that means that the
chain of trust is valid.
So, with that, let's see how
you can set up authentication
in a Multipeer Connectivity
session.
You'll have to use the session
initializer initWithPeer
securityIdentity
encryption preference method.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
securityIdentity
encryption preference method.
And for the second parameter
securityIdentity you'll have
to pass an array, which
contains your digital identity
as the first parameter and
a chain of certificates
that validate your
identity as next elements.
When somebody tries to connect
to you, you will be notified
with the delegate method,
didReceiveCertificate,
where you will be passed
the chain of certificates
that represent the other peer.
At that time you will have to
decide whether you want to trust
that peer or whether you trust
that peer and whether you want
to proceed connecting to it.
At this moment you can use the
method for evaluating the chain
of trust that we discussed
a couple of slides ago.
And if you decide that the
chain of trust can be trusted,
is valid and can be trusted,
you can let the framework know
by calling the certificate
handler
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
by calling the certificate
handler
and passing it a Boolean,
so in this case a yes.
If you don't trust it
you can just pass it a no
and the framework will
reject the connection.
In summary, we've looked
at a bit more detail
about how you can
set up authentication
in your Multipeer
Connectivity apps.
We've looked at digital
identities
and we've described how
you can make them available
to your users and how you
can import them in your apps.
We've also looked at chains
of trust and how you can go
about evaluating them.
For more information, I
would like to refer you
to our Evangelist, Paul
Danbold, and you can check
out our documentation,
"Multipeer Connectivity
Framework Reference" guide.
And, as Eric mentioned,
we have some sample code
that you guys should check
out called MultipeerGroupChat.
We'll be available to
answer questions and hear
about your comments at
devforums.apple.com, as well.
There are a few related sessions
that I would like to call out.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
There are a few related sessions
that I would like to call out.
One is "What's New in
Foundation Networking",
and the other one is
"Storyboards and Controllers"
on OS X, where you can
hear more about what's new
with NSViewControllers
in Yosemite.
Thank you very much, everyone.
[ Applause ]