ScanUI - novars-jp/MaBeeeiOSSDK GitHub Wiki
概要
- MaBeeeDeviceのスキャン・接続をするサンプルプロジェクトです。
- samples配下のScanUI(Objective-C), ScanUISwift(Swift)がそれになります。言語は違いますが内容は全く同じです。
ライブラリのインポート
-
Embedded BinariesにMaBeee.frameworkをドラッグドロップして追加します。
-
ViewControllerにインポート宣言を追加します。
-
Objective-C
@import MaBeeeSDK;
- Swift
import MaBeeeSDK
UIの作成
1. Storyboard
- ScanボタンとSliderがある画面を作成します。
- Navigation Controllerを追加します。サンプルではRoot View ControllerのタイトルをScan View Controllerに変更してあります。
- ScanTableViewControllerクラスを作成して、Storyboard上のViewControllerに対応させます。
2. Scanボタン
- 実行してScanボタンを押すと、Navigation ControllerがModalで表示されるようにします。
- ScanボタンのTriggered Seguesのacionと、追加したNavigation Controllerを接続して、Present Modallyを選択します。
3. Slider
- こちらはFirstMaBeeeと同じようにViewControllerクラスに接続して、ソースを記述します。
Objective-C
- (IBAction)sliderValueChanged:(UISlider *)slider {
for (MaBeeeDevice *device in MaBeeeApp.instance.devices) {
device.pwmDuty = (int)(slider.value * 100);
}
}
Swift
@IBAction func sliderValueChanged(slider: UISlider) {
for device in MaBeeeApp.instance().devices() {
device.pwmDuty = Int32(slider.value * 100)
}
}
ScanTableViewController
- 作成してStoryboardに紐付けた新しいクラスです。このクラスでスキャン・接続などの説明をします。
1. Doneボタンの設置
- 本題に入る前に、Doneボタンを作成してScanTableViewControllerを閉じれるようにします。
Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(doneButtonPressed:)];
}
- (void)doneButtonPressed:(UIBarButtonItem *)doneButton {
[self dismissViewControllerAnimated:YES completion:NULL];
}
Swift
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done,
target: self,
action: #selector(doneButtonPressed))
}
func doneButtonPressed() {
self.dismissViewControllerAnimated(true, completion: nil)
}
スキャンの開始と停止
- スキャンの開始はMaBeeeAppクラスのstartScan関数で行ないます。コールバックを指定するとスキャンにヒットしたデバイスを引数に呼ばれます。
- スキャンの停止はMaBeeeAppクラスのstopScan関数で行ないます。
- ここではviewDidAppearでスキャン開始、viewWillDisappearでスキャンを停止します。
- 単純にヒットしたMaBeeeDeviceをコンソールに出力しています。
Objective-C
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[MaBeeeApp.instance startScan:^(NSArray<MaBeeeDevice *> *devices) {
NSLog(@"%@", devices);
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[MaBeeeApp.instance stopScan];
}
Swift
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
MaBeeeApp.instance().startScan({(devices: [MaBeeeDevice]?) in
print(devices)
})
}
override func viewWillDisappear(animated: Bool) {
super.viewDidAppear(animated)
MaBeeeApp.instance().stopScan()
}
実行
- この状態でビルド、実行してみます。
- iOSのBluetoothが有効になっているか確認してください。
- MaBeeeをセットしたおもちゃ等の電源がONになっているか確認してください。
- Scanボタンを押すと、作成したScanTableViewControllerが表示されます。
- コンソールに以下のようなログが出力されます。この例では2台スキャンにヒットしています。
// Objective-C
2016-08-22 16:58:28.653 ScanUI[2674:549912] (
"<MaBeeeDevice: 0x16d483d0>",
"<MaBeeeDevice: 0x16e5ba80>",
)
// Swift
[<MaBeeeDevice: 0x155b8240>, <MaBeeeDevice: 0x156b4b20>]
テーブルビューへの表示
- スキャンにヒットしたMaBeeeDeviceをテーブルビューに表示します。
1. メンバ変数の追加
- セルに表示するためにクラスのメンバ変数として、MaBeeeDeviceの配列を宣言します。
Objective-C
@interface ScanTableViewController ()
@property (nonatomic, strong) NSArray<MaBeeeDevice *> *devices;
@end
Swift
var maBeeeDevices:[MaBeeeDevice]?
2. MaBeeeDeviceの配列の保持
- viewDidAppearのstartScanのコールバックに、デバイスの保持とテーブルビューのリロードを追記します。
Objective-C
[MaBeoeeApp.instance startScan:^(NSArray<MaBeeeDevice *> *devices) {
NSLog(@"%@", devices);
self.devices = devices;
[self.tableView reloadData];
}];
Swift
MaBeeeApp.instance().startScan({(devices: [MaBeeeDevice]!) in
print(devices)
self.maBeeeDevices = devices
self.tableView.reloadData()
})
3. セルの表示
- numberOfRowsInSection, cellForRowAtIndexPathの2つの関数をoverrideします。
- numberOfRowsInSectionでは、保持しているMaBeeeDeviceの配列の要素数を返します。
- cellForRowAtIndexPathでは、MaBeeeDeviceを取得して、name, rssi, stateを整形してセルに表示しています。
- stateを文字列にするためにstateStringという関数を準備しました。
Objective-C
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.devices.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MaBeeeDeviceCell"];
MaBeeeDevice *device = self.devices[indexPath.row];
NSString *state = [self stateString:device];
cell.textLabel.text = [NSString stringWithFormat:@"%@, %d, %@", device.name, device.rssi, state];
return cell;
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let devices = maBeeeDevices {
return devices.count;
}
return 0;
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("MaBeeeDeviceCell", forIndexPath: indexPath)
if let device = maBeeeDevices?[indexPath.row] {
cell.textLabel?.text = String(format: "%@, %d, %@",
device.name,
device.rssi,
self.stateString(device.state))
}
return cell;
}
4. 実行
- ビルドして実行すると、以下のような画面が表示されます。
接続・切断・仕上げ
1. 接続
- セルをタップして、選択されたデバイスに接続できるようにします。
- didSelectRowAtIndexPath関数をoverrideします。
- MaBeeeDeviceを取得して、stateがDisconnectedの場合は接続、それ以外は切断します。
Objctive-C
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
MaBeeeDevice *device = self.devices[indexPath.row];
switch (device.state) {
case MaBeeeDeviceStateDisconnected:
[MaBeeeApp.instance connect:device];
break;
case MaBeeeDeviceStateConnecting:
[MaBeeeApp.instance disconnect:device];
break;
case MaBeeeDeviceStateConnected:
[MaBeeeApp.instance disconnect:device];
break;
}
}
Swift
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if let device = maBeeeDevices?[indexPath.row] {
switch (device.state) {
case .Disconnected:
MaBeeeApp.instance().connect(device)
case .Connecting:
MaBeeeApp.instance().disconnect(device)
case .Connected:
MaBeeeApp.instance().disconnect(device)
}
}
}
2. 仕上げ・通知の設定
- この状態でも動作しますが、接続の状態をすぐに反映するために、通知を受け取ってテーブルビューを更新するようにします。
- viewDidAppearでaddObserver、viewWillDisappearでremoveObserverを呼びます。
- この例では通知を受けた場合、無条件にテーブルビューをリロードしています。
Objective-C
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[MaBeeeApp.instance addObserver:self selector:@selector(receiveNotification:)];
[MaBeeeApp.instance startScan:^(NSArray<MaBeeeDevice *> *devices) {
NSLog(@"%@", devices);
self.devices = devices;
[self.tableView reloadData];
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[MaBeeeApp.instance removeObserver:self];
[MaBeeeApp.instance stopScan];
}
- (void)receiveNotification:(NSNotification *)notification {
[self.tableView reloadData];
}
Swift
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
MaBeeeApp.instance().addObserver(self, selector: #selector(receiveNotification(_:)))
MaBeeeApp.instance().startScan({(devices: [MaBeeeDevice]!) in
print(devices)
self.maBeeeDevices = devices
self.tableView.reloadData()
})
}
override func viewWillDisappear(animated: Bool) {
super.viewDidAppear(animated)
MaBeeeApp.instance().removeObserver(self)
MaBeeeApp.instance().stopScan()
}
func receiveNotification(notification: NSNotification) {
self.tableView.reloadData()
}
3. 実行
- 実行して、セルをタップすると接続して、以下のようにConnectedという表示になります。
- この状態でScanTableViewControllerを閉じて、スライダーを操作するとMaBeeeDeviceの出力が変更できます。
stateString関数
- MaBeeeDeviceをセルに表示するときに、MaBeeeDeviceのstateを文字列にする関数です。
- 必須ではありませんが、わかりやすくするために関数としました。
- あまり本題とは関係ないです。
Objective-C
- (NSString *)stateString:(MaBeeeDevice *)device {
NSString *stateString;
switch (device.state) {
case MaBeeeDeviceStateDisconnected:
stateString = @"Disconnected";
break;
case MaBeeeDeviceStateConnecting:
stateString = @"Connecting";
break;
case MaBeeeDeviceStateConnected:
stateString = @"Connected";
break;
}
return stateString;
}
Swift
func stateString(state: MaBeeeDeviceState) -> String {
var stateString: String
switch (state) {
case .Disconnected:
stateString = "Disconnected"
case .Connecting:
stateString = "Connecting"
case .Connected:
stateString = "Connected"
}
return stateString
}