BluetoothをもちいたiOS同士の通信


# 概要
Bluetoothで通信をする1対1のゲームを作ろうと思い、テストとしてサンプルを作りました。その際に、以下の記事を参考にさせていただきました。
[参考サイト](http://radar.oreilly.com/2014/09/multipeer-connectivity-on-ios-8-with-swift.html)
参考サイトではテキストのやり取りをしていますが、今回は数値のやり取りをすることに目標をおきました。また、タイトルには**「Bluetooth」**と書いてありますが、サンプルでは**「Multipeer Connectivity」**というライブラリを使用します。Multipeer Connectivityは、同じWi-Fiに接続されている端末同士でも通信できるので、Bluetoothをオンにしなくても通信することができるようです。（もちろんBluetoothでも通信できます）詳しい説明は割愛。
## 完成図

![IMG_3409.PNG](https://qiita-image-store.s3.amazonaws.com/0/173720/4dbecab2-80f6-3b58-91f6-4ea07ca6d966.png)

#作り方
##1. 部品の配置

![スクリーンショット 2017-04-15 17.27.03.png](https://qiita-image-store.s3.amazonaws.com/0/173720/0fe11581-a1fc-b803-66bf-94ad79efe2b1.png)

ざっとこんなかんじに配置します。青と赤の枠はベタ塗りのラベルを後ろに置いてあるだけなので、特に意味はありません。

##2. 部品の接続
次に、LabelとButtonをoutlet, Action接続していきます。

![スクリーンショット 2017-04-15 18.40.35.png](https://qiita-image-store.s3.amazonaws.com/0/173720/2f7f3483-548d-0419-c525-1df53b31fda2.png)

それぞれの部品を接続すると、このようになると思います。

##3. コードを書く
最後にコードを書いていきます。と言ってもほとんど参考サイトのコピペです。違うところは、自分の数値をNSData型へ変換して相手の端末に投げているところ。相手の端末から送られてきたNSDataをInt型へ変換して、ラベルを更新する関数へ投げているところです。

```swift:ViewController.swift
import UIKit
import MultipeerConnectivity

class ViewController: UIViewController, MCBrowserViewControllerDelegate,
	MCSessionDelegate, UITextFieldDelegate {

	let serviceType = "LCOC-Chat"
	
	var browser : MCBrowserViewController!
	var assistant : MCAdvertiserAssistant!
	var session : MCSession!
	var peerID: MCPeerID!
	
	var p1num : Int = 0
	
	@IBOutlet weak var player1Label: UILabel!
	@IBOutlet weak var player2Label: UILabel!
	
	
	override func viewDidLoad() {
		super.viewDidLoad()
		
		self.peerID = MCPeerID(displayName: UIDevice.current.name)
		self.session = MCSession(peer: peerID)
		self.session.delegate = self
		
		// create the browser viewcontroller with a unique service name
		self.browser = MCBrowserViewController(serviceType:serviceType,
		                                       session:self.session)
		self.browser.delegate = self;
		self.assistant = MCAdvertiserAssistant(serviceType:serviceType,
		                                       discoveryInfo:nil, session:self.session)
		
		// tell the assistant to start advertising our fabulous chat
		self.assistant.start()
	}
	
	
	// プラスボタン
	@IBAction func plusBtn(_ sender: Any) {
		// プラス
		p1num += 1
		// NSDataへInt型のp1numを変換
		let data = NSData(bytes: &p1num, length: MemoryLayout<NSInteger>.size)
		// 相手へ送信
		do {
			try self.session.send(data as Data, toPeers: self.session.connectedPeers, with: MCSessionSendDataMode.unreliable)
		} catch {
			print(error)
		}
		player1Label.text = String(p1num)
	}
	
	// マイナスボタン
	@IBAction func minusBtn(_ sender: Any) {
		p1num -= 1
		let data = NSData(bytes: &p1num, length: MemoryLayout<NSInteger>.size)
		do {
			try self.session.send(data as Data, toPeers: self.session.connectedPeers, with: MCSessionSendDataMode.unreliable)
		} catch {
			print(error)
		}
		player1Label.text = String(p1num)
	}
	
	
	// ラベルの更新
	func updateLabel(num : Int, fromPeer peerID: MCPeerID) {
		
		// peerが自分のものでない時ラベルの更新
		switch peerID {
		case self.peerID:
			break
		default:
			player2Label.text = String(num)
		}
		
	}
	
	@IBAction func showBrowser(sender: UIButton) {
		// Show the browser view controller
		self.present(self.browser, animated: true, completion: nil)
	}
	
	func browserViewControllerDidFinish(
		_ browserViewController: MCBrowserViewController)  {
		// Called when the browser view controller is dismissed (ie the Done
		// button was tapped)
		
		self.dismiss(animated: true, completion: nil)
	}
	
	func browserViewControllerWasCancelled(
		_ browserViewController: MCBrowserViewController)  {
		// Called when the browser view controller is cancelled
		
		self.dismiss(animated: true, completion: nil)
	}
	
	// 相手からNSDataが送られてきたとき
	func session(_ session: MCSession, didReceive data: Data,
	             fromPeer peerID: MCPeerID)  {
		DispatchQueue.main.async() {
			let data = NSData(data: data)
			var player2num : NSInteger = 0
			data.getBytes(&player2num, length: data.length)
			// ラベルの更新
			self.updateLabel(num: player2num, fromPeer: peerID)
		}
	}
	
	// The following methods do nothing, but the MCSessionDelegate protocol
	// requires that we implement them.
	func session(_ session: MCSession,
	             didStartReceivingResourceWithName resourceName: String,
	             fromPeer peerID: MCPeerID, with progress: Progress)  {
		
		// Called when a peer starts sending a file to us
	}
	
	func session(_ session: MCSession,
	             didFinishReceivingResourceWithName resourceName: String,
	             fromPeer peerID: MCPeerID,
	             at localURL: URL, withError error: Error?)  {
		// Called when a file has finished transferring from another peer
	}
	
	func session(_ session: MCSession, didReceive stream: InputStream,
	             withName streamName: String, fromPeer peerID: MCPeerID)  {
		// Called when a peer establishes a stream with us
	}
	
	func session(_ session: MCSession, peer peerID: MCPeerID,
	             didChange state: MCSessionState)  {
		// Called when a connected peer changes state (for example, goes offline)
		
	}
}
```

#使い方
- 実行して「Browser」ボタンを押すと、接続可能な端末が表示される
- 任意の端末を選択すると、相手の端末に接続の許可を求めるアラートが出てくるので、「Accept」ボタンを押す
- 接続が完了したら、「Done」ボタンを押して元の画面に戻る
- 「+」ボタン「-」ボタンを押すと、相手側でも数値の変化が見られる

#まとめ
BluetoothをもちいてiOS端末同士で通信をしました。端末同士がやり取りするデータはNSDataなので、他にもいろいろなデータをやり取りすることができるようです。
注意点は、デバックには実機を使わないといけないところです。つまり今回のサンプルを動かすには、iPhoneが2台必要です。
今回作ったプロジェクトを[Github](https://github.com/tomoyukiHAYAKAWA/MultipeerSample)にあげておきます。