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

概要

Bluetoothで通信をする1対1のゲームを作ろうと思い、テストとしてサンプルを作りました。その際に、以下の記事を参考にさせていただきました。
参考サイト
参考サイトではテキストのやり取りをしていますが、今回は数値のやり取りをすることに目標をおきました。また、タイトルには「Bluetooth」と書いてありますが、サンプルでは「Multipeer Connectivity」というライブラリを使用します。Multipeer Connectivityは、同じWi-Fiに接続されている端末同士でも通信できるので、Bluetoothをオンにしなくても通信することができるようです。(もちろんBluetoothでも通信できます)詳しい説明は割愛。

完成図

IMG_3409.PNG

作り方

1. 部品の配置

スクリーンショット 2017-04-15 17.27.03.png

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

2. 部品の接続

次に、LabelとButtonをoutlet, Action接続していきます。

スクリーンショット 2017-04-15 18.40.35.png

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

3. コードを書く

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

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にあげておきます。


『 Swift 』Article List