Peer-to-peer networking with CanIO on iOS
This document explains how you can use CanIO is your iOS app to directly detect new peers and communicate with them. Please note that CanIO also offers a simpler and quicker method of peer-to-peer networking through Shared Spaces.
The CanIOManager class
The CanIOManager singleton class is a central interface for interacting with CanIO services, and is used to initialize CanIO services and to send requests and responses. This class also defines a protocol called CanIOManagerDelegate, which defines a set of delegate methods which are called around various peer-related events.
Before using the CanIOManager class for communicatication with local peers, the startServices method should be called on the class' shared instance.
[[CanIOManager sharedManager] startServices];
Peer discovery through advertising and browsing
Discovery of other peers is facilitated through advertising and browsing - each peer advertises its existence to other peers so that it can be discovered, and browses for other peers to discover them.
Use the following methods to toggle advertising and browsing on or off:
[[CanIOManager sharedManager] startAdvertising];
[[CanIOManager sharedManager] stopAdvertising];
[[CanIOManager sharedManager] startDiscoveringPeers];
[[CanIOManager sharedManager] stopDiscoveringPeers];
Advertising and browsing should be toggled on and off in various parts of your app, depending on how your app uses peer-to-peer networking. It's possible for your app to only browse or advertise; An app that is only browsing will still be detected by the peers it detects, and an app that is only advertising will still detect peers that discover it.
When peers are discovered or lost, the didDiscoverPeer: and didLosePeer: delegate methods will be called.
- (void)canioManager:(CanIOManager *)manager didDiscoverPeer:(CanIOPeer *)peer;
- (void)canioManager:(CanIOManager *)manager didLosePeer:(CanIOPeer *)peer;
The CanIOPeer class
The CanIOPeer represents a detected local peer, and can be used to access information about the peer, and to send the peer requests and responses.
When a new peer is discovered, the CanIOPeer object will be passed through the delegate method. You can retain these peer objects in your own data structures for later use, but they are also accessible through CanIOManager's peers array:
CanIOManager *sharedManager = [CanIOManager sharedManager];
NSArray *peers = sharedManager.peers;
Peer profile info
Your app can supply a NSDictionary containing information about the local peer, and this information can be accessed by other peers who detect it. To supply this information, the canioManagerProfileForLocalPeer: delegate method is called, and your app should return the relevant NSDictionary:
- (NSDictionary *)canioManagerProfileForLocalPeer:(CanIOManager *)manager;
Once a peer has been detected, you can access CanIOPeer's profileInfo property to access this dictionary.
NSDictionary *otherPeerProfile = otherPeer.profileInfo;
Sending and receiving requests
CanIORequest and CanIOResponse objects are used to send data and receive data between peers. Each request or response can contain both key-object pairs in the form of an NSDictionary, and/or raw data in the form of NSData. These two formats used in conjuction should enable you to pass any sort of data between two peers.
An example of creating and sending a request:
CanIORequest *request = [[CanIORequest alloc] initWithData:data packetType:ABCRequestTypeMessage];
request.requestJSON[@"metadata"] = @{@"sender_name": name, @"message" : message}
[[CanIOManager sharedManger] sendRequest:request toPeer:peer];
Each request is created with the data it includes and a packet type which indicates to the receiver what kind of packet this is. After allocating the request, you can set the requestJSON object to set any key-objects pairs you would like to include in the request. The key-objects are encoded as JSON so the types set should be serialiable to JSON.
When you app receives a request, the following delegate method will be called:
- (void)canioManager:(CanIOManager *)manager didReceiveRequest:(CanIORequest *)request fromPeer:(CanIOPeer *)peer;
You can then access the request's data and requestJSON properties:
NSData *data = request.data;
NSDictionary *params = request.requestJSON;
Sending and receiving responses
CanIOResponses are identical to CanIORequests, but each CanIOResponse is directly connected to a CanIORequest. So if Peer A sends Peer B a request, and receives a response, he will also receive the original request to which the response is connected to. To send a response to a request:
CanIOResponse *response = [[CanIOResponse alloc] initWithData:data packetType:ABCResponseTypeMessageReceived forRequest:request];
request.requestJSON[@"metadata"] = @{@"status": @"received"}
[[CanIOManager sharedManager] sendResponse:response toPeer:peer];
When a response is received, the following delegate method will be called, which also includes the original request to which the response is connected to:
- (void)canioManager:(CanIOManager *)manager didReceiveResponse:(CanIOResponse *)response forRequest:(CanIORequest *)request;