Flex

AIR Native Extension - iOS iBeacon / BLE


先日 iBeaconのANEを作る機会があったので、その内容をつらつらと書いてみようと思います。
いや、Nativeで一通りやったのをANE化しただけなんですけどね。


ane-labにサンプルを上げてありますので、そっちも参考にして下さい。

iOS_iBeaconFirst

iOS_BLE

ANEの作り方は、Native Alertのトコ(1?3まであります)を順番に見といて下さい。
今回はNativeのコードと、platform.xmlの内容を貼っておきますね。言うまでもなくNatvieはARCです。



まずはiBeaconのObjective-C部分から。




[ iBeacon.h ]
---------------------------------------
//
//  iBeacon.h
//  iBeacon
//
//  Created by hoehoe on 2013/12/02.
//  Copyright (c) 2013年 hoehoe. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <Adobe AIR/Adobe AIR.h>
#import "BeaconController.h"

@interface iBeacon : NSObject
{
    BeaconController* _controller;
}

@property (nonatomic, strong) BeaconController* controller;

@end

[ EOF ]
---------------------------------------



[ iBeacon.m ]
---------------------------------------
//
//  iBeacon.m
//  iBeacon
//
//  Created by hoehoe on 2013/12/02.
//  Copyright (c) 2013年 hoehoe. All rights reserved.
//

#import "iBeacon.h"

@implementation iBeacon

iBeacon* me;
FREContext* context;

-(id)init
{
    if(self == nil){
        self = [super init];
    }
    self.controller = [[BeaconController alloc] init];
    self.controller.context = context;
    NSLog(@"init");
    return self;
}

-(void)startBeacon
{
    [self.controller start];
    NSLog(@"start");
}
-(void)stopBeacon
{
    [self.controller stop];
    NSLog(@"stop");
}

FREObject start(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {
    FREObject resultObj = NULL;
    [me startBeacon];
    return resultObj;
}


FREObject stop(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {
    FREObject resultObj = NULL;
    [me stopBeacon];
    return resultObj;
}

void contextFinalizer(FREContext ctx)
{
    return;
}

void contextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions)
{
    if(me == nil){
        context = ctx;
        me = [[iBeacon alloc] init];
    }
   
    *numFunctions = 2;
    FRENamedFunction*  func= (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * (*numFunctions));
   
    func[0].name = (const uint8_t*) "start";
    func[0].functionData = NULL;
    func[0].function = &start;

    func[1].name = (const uint8_t*) "stop";
    func[1].functionData = NULL;
    func[1].function = &stop;

    *functions = func;
}

void initializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer)
{
    *ctxInitializer = &contextInitializer;
    *ctxFinalizer = &contextFinalizer;
}

void finalizer(void** extData)
{
   
}

@end

[ EOF ]
---------------------------------------


特筆する部分は特にないですね。
FREContextと自身のインスタンスを広域で定義している点に注意してください。
FREContextは、iBeaconControllerクラスでも必要になるので、iBeaconControllerをインスタンス化したあとにセッ トしてます。
ここの処理内容は、スタートボタンを押した時とストップボタンを押したときの処理が書いてあるだけです。


で、こっちがiBeaconの本処理ですね。

[ BeaconController.h ]
---------------------------------------
//
//  BeaconController.h
//  iBeacon
//
//  Created by hoehoe on 2013/12/02.
//  Copyright (c) 2013年 hoehoe. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import <Adobe AIR/Adobe AIR.h>

@interface BeaconController : NSObject<CBPeripheralManagerDelegate, CLLocationManagerDelegate>
{
    FREContext* _context;
}
@property (strong, nonatomic) CLBeaconRegion *beaconRegion;
@property (strong, nonatomic) NSDictionary *beaconPeripheralData;
@property (strong, nonatomic) CBPeripheralManager *peripheralManager;
@property (strong, nonatomic) CLLocationManager *locationManager;
@property FREContext* context;

-(void)start;
-(void)stop;

@end
[ EOF ]
---------------------------------------



[ BeaconController.m ]
---------------------------------------
//
//  BeaconController.m
//  iBeacon
//
//  Created by hoehoe on 2013/12/02.
//  Copyright (c) 2013年 hoehoe. All rights reserved.
//

#import "BeaconController.h"

@implementation BeaconController

@synthesize context = _context;

-(id)init
{
    if(self == nil){
        self = [super init];
    }
   
    [self initBeacon];
   
    self.beaconPeripheralData = [self.beaconRegion peripheralDataWithMeasuredPower:nil];
    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
                                                                     queue:nil
                                                                   options:nil];
   
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
   
    return self;
}

- (void)initBeacon {
    //UUIDはターミナル使ってuuidgenで生成してね
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:@"501797C5-1AEB-4CA3-8C3C-F7AAF5C0D396"];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
                                                                major:1
                                                                minor:1
                                                           identifier:@"com.chocbanana.myRegion"];
}


-(void)start
{
    [self.locationManager startMonitoringForRegion:self.beaconRegion];
}

-(void)stop{
    [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
}

-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
    if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
        NSLog(@"Powered On");
        [self.peripheralManager startAdvertising:self.beaconPeripheralData];
    } else if (peripheral.state == CBPeripheralManagerStatePoweredOff) {
        NSLog(@"Powered Off");
        [self.peripheralManager stopAdvertising];
    }
}

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
    [self.locationManager requestStateForRegion:self.beaconRegion];
}
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    switch (state) {
        case CLRegionStateInside:
            if ([region isMemberOfClass:[CLBeaconRegion class]] && [CLLocationManager isRangingAvailable]) {
                [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
            }
        case CLRegionStateOutside:
        case CLRegionStateUnknown:
            break;
            break;
           
        default:
            break;
    }
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}

-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
}

-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
    CLBeacon *beacon = [[CLBeacon alloc] init];
    beacon = [beacons lastObject];
   
    NSString* range = nil;
   
    if (beacon.proximity == CLProximityUnknown) {
        //NSLog(@"Unknown Proximity");
        range = @"おいぃ、どこだよ...。";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    } else if (beacon.proximity == CLProximityImmediate) {
        //NSLog(@"Immediate");
        range = @"近い!近い!近い!近い!近い!";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    } else if (beacon.proximity == CLProximityNear) {
        //NSLog(@"Near");
        range = @"近いよー。";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    } else if (beacon.proximity == CLProximityFar) {
        //NSLog(@"Far");
        range = @"遠いよー。";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    }
}

@end

[ EOF ]
---------------------------------------

Beaconを受信したら、FREDispatchStatusEventAsyncで戻しています。
AIR/SWC側で addEventListenerしておけば、Beaconの受信値を画面に表示出来ます。

で、iBeaconの問題点は、バックグラウンドでBeaconを送信出来ない...という仕様です。
まぁ、iOSデバイス的には受信がメインなのでしょうね。

あ、swc作る時のplatform.xmlはこちらになります。

[ platfrom.xml ]
---------------------------------------
<platform xmlns="http://ns.adobe.com/air/extension/4.0">
    <sdkVersion>7.0</sdkVersion>
    <linkerOptions>
        <option>-w</option>
        <option>-ios_version_min 7.0</option>
        <option>-L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc</option>
        <option>-larclite_iphoneos</option>
        <option>-framework UIKit</option>
        <option>-framework CoreLocation</option>
        <option>-framework CoreBluetooth</option>
    </linkerOptions>

</platform>

[ EOF ]
---------------------------------------

これで、Flash Builderでリリースビルドすると、iBeaconを受信するANEを組み込んだAIR for iOSのアプリケーションが出来上がりです。




続いてこのiBeacon受信アプリをBLE対応にしてみましょう。


Native部分をまた貼っておきます。


[ BeaconController.h ]
---------------------------------------
//
//  BeaconController.h
//  iBeaconfTest
//
//  Created by hoehoe on 2013/12/01.
//  Copyright (c) 2013年 Gigaworks. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import <Adobe AIR/Adobe AIR.h>

@interface BeaconController : NSObject<CBPeripheralManagerDelegate, CLLocationManagerDelegate, CBCentralManagerDelegate>
{
    NSString* kServiceUUID;
    NSString* kCharacteristicUUID;
    FREContext* context;
}
@property (strong, nonatomic) CLBeaconRegion *beaconRegion;
@property (strong, nonatomic) NSDictionary *beaconPeripheralData;
@property (strong, nonatomic) CBPeripheral *peripheral;
@property (strong, nonatomic) CBCentralManager *centralManager;
@property (strong, nonatomic) CLLocationManager *locationManager;

@property FREContext* context;

-(void)start;
-(void)stop;

@end

[ EOF ]
---------------------------------------

[ BeaconController.m ]
---------------------------------------
//
//  BeaconController.m
//  iBeaconfTest
//
//  Created by hoehoe on 2013/12/01.
//  Copyright (c) 2013年 Gigaworks. All rights reserved.
//

#import "BeaconController.h"

@implementation BeaconController

@synthesize context = _context;

-(id)init
{
    if(self == nil){
        self = [super init];
    }
   
    //uuidgenで生成して下さい。
    kServiceUUID = @"501797C5-1AEB-4CA3-8C3C-F7AAF5C0D396";
    kCharacteristicUUID = @"45077DB4-3DF6-40FC-ACF6-8212B8579C4B";
   
    [self initBeacon];
   
    self.beaconPeripheralData = [self.beaconRegion peripheralDataWithMeasuredPower:nil];
    //self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self
    //                                                                 queue:nil
    //                                                               options:nil];
   
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    [self initRegion];
   
   
    //self.sendPeripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];
    //[self initSendPeripheral];
   
    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBAdvertisementDataServiceUUIDsKey: [CBUUID UUIDWithString:kServiceUUID]}];
   
    return self;
}

- (void)initBeacon {
   
    NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:kServiceUUID];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid
                                                                major:1
                                                                minor:1
                                                           identifier:@"com.devfright.myRegion"];
}

- (void)initRegion {
    [self.locationManager startMonitoringForRegion:self.beaconRegion];
}

-(void)initSendPeripheral
{
    //NSLog(@"%@", NSStringFromSelector(_cmd));
   
    // Creates the characteristic UUID
    CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
    CBCharacteristic* characteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID properties:CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable];
   
   
    // Creates the service UUID
    CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
   
    // Creates the service and adds the characteristic to it
    CBMutableService* service = [[CBMutableService alloc] initWithType:serviceUUID primary:YES];
   
    // Sets the characteristics for this service
    [service setCharacteristics:@[characteristic]];
   
    // Publishes the service
    //[self.sendPeripheralManager addService:service];

}


-(void)start
{
    [self locationManager:self.locationManager didStartMonitoringForRegion:self.beaconRegion];
}

-(void)stop
{
    [self.locationManager stopMonitoringForRegion:self.beaconRegion];
}


-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
    if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
        NSLog(@"Powered On");
        //[self.peripheralManager startAdvertising:self.beaconPeripheralData];
        //[self.sendPeripheralManager startAdvertising:[self.beaconRegion peripheralDataWithMeasuredPower:nil]];
    } else if (peripheral.state == CBPeripheralManagerStatePoweredOff) {
        NSLog(@"Powered Off");
        //[self.peripheralManager stopAdvertising];
    }
}

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
}

-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    //[self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
}

-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
    NSLog(@"Catch Beacon...");
    CLBeacon *beacon = [[CLBeacon alloc] init];
    beacon = [beacons lastObject];
       
    NSString* range;
   
    if (beacon.proximity == CLProximityUnknown) {
        //NSLog(@"Unknown Proximity");
        range = @"どこですかー?";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    } else if (beacon.proximity == CLProximityImmediate) {
        //[self.bluetooth sendData];
        //NSLog(@"Immediate");
        range = @"近いっすよ?";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    } else if (beacon.proximity == CLProximityNear) {
        //[self.bluetooth sendData];
        //NSLog(@"Near");
        range = @"あ、いたいた";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    } else if (beacon.proximity == CLProximityFar) {
        NSLog(@"Far");
        range = @"あ、遠くにいるわ。";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    }
   
    //NSMutableDictionary* userInfo = [NSMutableDictionary dictionary];
    //[userInfo setValue:range forKey:@"range"];
    //NSNotification* n = [NSNotification notificationWithName:@"ToNotifyTheRange" object:self userInfo:userInfo];
    //[[NSNotificationCenter defaultCenter] postNotification:n];
}


// デバイス発見時
// centralManager:didDiscoverPeripheral:advertisementData:RSSI:
// Invoked when the central manager discovers a peripheral while scanning.
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
   
    NSLog(@"RSSI: %d", [RSSI intValue]);
    int proximity = [RSSI intValue];
    NSString* range;
   
    if (proximity < -70){
        range = @"遠いよ。";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    }else if (proximity < -55){
        range = @"近いね。";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    }else if (proximity < 0){
        range = @"だから、近いってば!";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    }else{
        range = @"居ませんね。";
        FREDispatchStatusEventAsync (self.context, (uint8_t*)[range UTF8String], (uint8_t*)[@"OK" UTF8String]);
    }
   
    //NSMutableDictionary* userInfo = [NSMutableDictionary dictionary];
    //[userInfo setValue:range forKey:@"range"];
    //NSNotification* n = [NSNotification notificationWithName:@"ToNotifyTheRange" object:self userInfo:userInfo];
    //[[NSNotificationCenter defaultCenter] postNotification:n];

    if(self.peripheral != peripheral){
        self.peripheral = peripheral;
        NSLog(@"Connecting to pripheral %@", peripheral);
        NSLog(@"PeripheralName: %@", peripheral.name);
        // 発見されたデバイスに接続
        [self.centralManager connectPeripheral:peripheral options:nil];
    }

}

// ------------------------------
// CBCentralManagerDelegate
// ------------------------------

// Monitoring Connections with Peripherals

// centralManager:didConnectPeripheral:
// Invoked when a connection is successfully created with a peripheral.
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    NSLog(@"%@", peripheral.description);
   
    // Clears the data that we may already have
    //[self.data setLength:0];
    // Sets the peripheral delegate
    //[self.peripheral setDelegate:self];
    // Asks the peripheral to discover the service
    //[self.peripheral discoverServices:@[ [CBUUID UUIDWithString:kServiceUUID] ]];
}

// centralManager:didDisconnectPeripheral:error:
// Invoked when an existing connection with a peripheral is torn down.
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    if(error){
        NSLog(@"[error] %@", [error localizedDescription]);
        NSLog(@"[error] %@", [error localizedFailureReason]);
        NSLog(@"[error] %@", [error localizedRecoverySuggestion]);
    }else{
        NSLog(@"disconnect");
        //[self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
        //cancelPeripheralConnection
        //[self.centralManager];
    }
}

// centralManager:didFailToConnectPeripheral:error:
// Invoked when the central manager fails to create a connection with a peripheral.
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

// Discovering and Retrieving Peripherals


// centralManager:didRetrieveConnectedPeripherals:
// Invoked when the central manager retrieves a list of peripherals currently connected to the system.
- (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

// centralManager:didRetrievePeripherals:
// Invoked when the central manager retrieves a list of known peripherals.
- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

// Monitoring Changes to the Central Manager's State

// CBCentralManager が初期化されたり状態が変化した際に呼ばれるデリゲートメソッド
// centralManagerDidUpdateState:
// Invoked when the central manager's state is updated. (required)
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    switch (central.state) {
        case CBCentralManagerStatePoweredOn:
            NSLog(@"%d, CBCentralManagerStatePoweredOn", (int)central.state);
           
            [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}]; // NO だとダメ?
            break;
        case CBCentralManagerStatePoweredOff:
            NSLog(@"%d, CBCentralManagerStatePoweredOff", (int)central.state);
            break;
        case CBCentralManagerStateResetting:
            NSLog(@"%d, CBCentralManagerStateResetting", (int)central.state);
            break;
        case CBCentralManagerStateUnauthorized:
            NSLog(@"%d, CBCentralManagerStateUnauthorized", (int)central.state);
            break;
        case CBCentralManagerStateUnsupported:
            NSLog(@"%d, CBCentralManagerStateUnsupported", (int)central.state);
            break;
        case CBCentralManagerStateUnknown:
            NSLog(@"%d, CBCentralManagerStateUnknown", (int)central.state);
            break;
        default:
            break;
    }
}

// centralManager:willRestoreState:
// Invoked when the central manager is about to be restored by the system.
- (void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)dict
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

@end

[ EOF ]
---------------------------------------


前のと違うのはCBCentralManagerDelegateを追加実装している点です。
CBCentralManagerDelegateでBLEを受信出来るようにしました。

で、もう1つ、BLEの送信を出来るようにしましょう。

[ MyBLESend.h ]
---------------------------------------
//
//  MyBLESend.h
//  CoreBluetoothTest
//
//  Created by hoehoe on 2013/11/30.
//  Copyright (c) 2013年 Gigaworks. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>

@interface MyBLESend : NSObject<CBPeripheralManagerDelegate>
{
    NSString *kServiceUUID;
    NSString *kCharacteristicUUID;
}

@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
@property (nonatomic, strong) CBCharacteristic *characteristic;
@property (nonatomic, strong) CBMutableService *service;


-(void)setupService;
-(void)stopService;


// ------------------------------
// CBPeripheralManagerDelegate
// ------------------------------

// Monitoring Changes to the Peripheral Manager's State

// peripheralManagerDidUpdateState:
// Invoked when the peripheral manager's state is updated. (required)
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral;

// peripheralManager:willRestoreState:
// Invoked when the peripheral manager is about to be restored by the system.
- (void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary *)dict;

// Adding Services

// peripheralManager:didAddService:error:
// Invoked when you publish a service, and any of its associated characteristics and characteristic descriptors, to the local Generic Attribute Profile (GATT) database.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error;

// Advertising Peripheral Data

// peripheralManagerDidStartAdvertising:error:
// Invoked when you start advertising the local peripheral device's data.
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error;

// Monitoring Subscriptions to Characteristic Values

// peripheralManager:central:didSubscribeToCharacteristic:
// Invoked when a remote central device subscribes to a characteristic's value.
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic;

// peripheralManager:central:didUnsubscribeFromCharacteristic:
// Invoked when a remote central device unsubscribes from a characteristic's value.
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic;

// peripheralManagerIsReadyToUpdateSubscribers:
// Invoked when a local peripheral device is again ready to send characteristic value updates. (required)
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral;

// Receiving Read and Write Requests

// peripheralManager:didReceiveReadRequest:
// Invoked when a local peripheral device receives an Attribute Protocol (ATT) read request for a characteristic that has a dynamic value.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request;

// peripheralManager:didReceiveWriteRequests:
// Invoked when a local peripheral device receives an Attribute Protocol (ATT) write request for a characteristic that has a dynamic value.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests;

@end

[ EOF ]
---------------------------------------

[ MyBLESend.m ]
---------------------------------------
//
//  MyBLESend.m
//  CoreBluetoothTest
//
//  Created by hoehoe on 2013/11/30.
//  Copyright (c) 2013年 Gigaworks. All rights reserved.
//

#import "MyBLESend.h"

@implementation MyBLESend

- (id)init
{
    // Do any additional setup after loading the view, typically from a nib.
    if(self == nil){
        self = [super init];
    }
   
    //uuidgenで生成したものを使用します。
    kServiceUUID = @"501797C5-1AEB-4CA3-8C3C-F7AAF5C0D396";
    kCharacteristicUUID = @"45077DB4-3DF6-40FC-ACF6-8212B8579C4B";
   
    self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:@{CBAdvertisementDataServiceUUIDsKey:[CBUUID UUIDWithString:kServiceUUID]}];
    return self;
}


- (void)setupService
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
   
    // Creates the characteristic UUID
    CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
    NSLog(@"[characteristicUUID.description] %@", characteristicUUID.description);
   
   
    uint battery_level = 39;
    NSData *dataBatteryLevel = [NSData dataWithBytes:&battery_level length:sizeof(battery_level)];
    NSData* value = [NSData dataWithBytes:&dataBatteryLevel length:sizeof(dataBatteryLevel)];
    self.characteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID properties:CBCharacteristicPropertyRead value:value permissions:CBAttributePermissionsReadable];
   
   
    // Creates the service UUID
    CBUUID *serviceUUID = [CBUUID UUIDWithString:kServiceUUID];
   
    // Creates the service and adds the characteristic to it
    self.service = [[CBMutableService alloc] initWithType:serviceUUID primary:YES];
   
    // Sets the characteristics for this service
    [self.service setCharacteristics:@[self.characteristic]];
   
    // Publishes the service
    [self.peripheralManager addService:self.service];
}
-(void)stopService
{
    [self.peripheralManager stopAdvertising];
}

// ------------------------------
// CBPeripheralManagerDelegate
// ------------------------------

// Monitoring Changes to the Peripheral Manager's State

// CBPeripheralManager が初期化されたり状態が変化した際に呼ばれるデリゲートメソッド
// peripheralManagerDidUpdateState:
// Invoked when the peripheral manager's state is updated. (required)
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    switch (peripheral.state) {
        case CBPeripheralManagerStatePoweredOn:
            NSLog(@"%d, CBPeripheralManagerStatePoweredOn", (int)peripheral.state);
            // PowerOn なら,デバイスのセッティングを開始する.
            [self setupService];
            break;
        case CBPeripheralManagerStatePoweredOff:
            NSLog(@"%d, CBPeripheralManagerStatePoweredOff", (int)peripheral.state);
            [self.peripheralManager stopAdvertising];
            break;
        case CBPeripheralManagerStateResetting:
            NSLog(@"%d, CBPeripheralManagerStatePoweredOn", (int)peripheral.state);
            break;
        case CBPeripheralManagerStateUnauthorized:
            NSLog(@"%d, CBPeripheralManagerStatePoweredOn", (int)peripheral.state);
            break;
        case CBPeripheralManagerStateUnsupported:
            NSLog(@"%d, CBPeripheralManagerStatePoweredOn", (int)peripheral.state);
            break;
        case CBPeripheralManagerStateUnknown:
            NSLog(@"%d, CBPeripheralManagerStatePoweredOn", (int)peripheral.state);
            break;
        default:
            break;
    }
}

// peripheralManager:willRestoreState:
// Invoked when the peripheral manager is about to be restored by the system.
- (void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary *)dict
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

// Adding Services

// peripheralManager:didAddService:error:
// Invoked when you publish a service, and any of its associated characteristics and characteristic descriptors, to the local Generic Attribute Profile (GATT) database.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
   
    if(error){
        NSLog(@"[error] %@", [error localizedDescription]);
    }else{
        // Starts advertising the service
        [self.peripheralManager startAdvertising:@{CBAdvertisementDataLocalNameKey : @"mokyu", CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:kServiceUUID]] }];
        NSLog(@"start advertising");
    }
}

// Advertising Peripheral Data

// peripheralManagerDidStartAdvertising:error:
// Invoked when you start advertising the local peripheral device's data.
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    if(error){
        NSLog(@"[error] %@", [error localizedDescription]);
    }else{
        NSLog(@"no error");
    }
}

// Monitoring Subscriptions to Characteristic Values

// peripheralManager:central:didSubscribeToCharacteristic:
// Invoked when a remote central device subscribes to a characteristic's value.
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

// peripheralManager:central:didUnsubscribeFromCharacteristic:
// Invoked when a remote central device unsubscribes from a characteristic's value.
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

// peripheralManagerIsReadyToUpdateSubscribers:
// Invoked when a local peripheral device is again ready to send characteristic value updates. (required)
- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

// Receiving Read and Write Requests

// peripheralManager:didReceiveReadRequest:
// Invoked when a local peripheral device receives an Attribute Protocol (ATT) read request for a characteristic that has a dynamic value.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

// peripheralManager:didReceiveWriteRequests:
// Invoked when a local peripheral device receives an Attribute Protocol (ATT) write request for a characteristic that has a dynamic value.
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
    NSLog(@"Receive data...");
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

@end

[ EOF ]
---------------------------------------


これで、BLEの送信部分を実装出来ました。

今回はiBeaconとBLE(の受信)を混ぜましたが、iBeacon部分を除外すれば、BLEのみの送受信ANEも出来ます。
色々やってみると面白いです。Androidは受信のみ対応らしいので、iOSから送信してあげて、Androidで受信ということも出来ると思います。

お疲れさまでした。


このページの先頭へ