killapp/Assets/Plugins/iOS/UnityBluetoothLE.mm
“虞渠成” cec4f941ec debug
2026-06-22 14:57:16 +08:00

1364 lines
47 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// UnityBluetoothLE.h
// Unity-iPhone
//
// Created by Tony Pitman on 03/05/2014.
//
//
#import "UnityBluetoothLE.h"
const char _messageDelimeter = '~';
extern "C" {
UnityBluetoothLE *_unityBluetoothLE = nil;
void _iOSBluetoothLELogString (NSString *message) {
NSLog (message);
}
void _iOSBluetoothLELog (char *message) {
_iOSBluetoothLELogString ([NSString stringWithFormat:@"%s", message]);
}
void _iOSBluetoothLEInitialize (BOOL asCentral, BOOL asPeripheral) {
_unityBluetoothLE = [UnityBluetoothLE new];
[_unityBluetoothLE initialize:asCentral asPeripheral:asPeripheral];
}
void _iOSBluetoothLEDeInitialize () {
if (_unityBluetoothLE != nil) {
[_unityBluetoothLE deInitialize];
[_unityBluetoothLE release];
_unityBluetoothLE = nil;
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", "DeInitialized");
}
}
void _iOSBluetoothLEPauseMessages (BOOL pause) {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE pauseMessages:pause];
}
void _iOSBluetoothLEScanForPeripheralsWithServices (char *serviceUUIDsStringRaw, bool allowDuplicates, bool rssiOnly, bool clearPeripheralList, int recordType) {
if (_unityBluetoothLE != nil)
{
_unityBluetoothLE._rssiOnly = rssiOnly;
NSMutableArray *actualUUIDs = nil;
if (serviceUUIDsStringRaw != nil)
{
NSString *serviceUUIDsString = [NSString stringWithFormat:@"%s", serviceUUIDsStringRaw];
NSArray *serviceUUIDs = [serviceUUIDsString componentsSeparatedByString:@"|"];
if (serviceUUIDs.count > 0)
{
actualUUIDs = [[NSMutableArray alloc] init];
for (NSString* sUUID in serviceUUIDs)
[actualUUIDs addObject:[CBUUID UUIDWithString:sUUID]];
}
}
NSDictionary *options = nil;
if (allowDuplicates)
options = @{ CBCentralManagerScanOptionAllowDuplicatesKey: @YES };
[_unityBluetoothLE scanForPeripheralsWithServices:actualUUIDs options:options clearPeripheralList:clearPeripheralList recordType:recordType];
}
}
void _iOSBluetoothLEStopScan () {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE stopScan];
}
void _iOSBluetoothLERetrieveListOfPeripheralsWithServices (char *serviceUUIDsStringRaw) {
if (_unityBluetoothLE != nil)
{
NSMutableArray *actualUUIDs = nil;
if (serviceUUIDsStringRaw != nil)
{
NSString *serviceUUIDsString = [NSString stringWithFormat:@"%s", serviceUUIDsStringRaw];
NSArray *serviceUUIDs = [serviceUUIDsString componentsSeparatedByString:@"|"];
if (serviceUUIDs.count > 0)
{
actualUUIDs = [[NSMutableArray alloc] init];
for (NSString* sUUID in serviceUUIDs)
[actualUUIDs addObject:[CBUUID UUIDWithString:sUUID]];
}
}
[_unityBluetoothLE retrieveListOfPeripheralsWithServices:actualUUIDs];
}
}
void _iOSBluetoothLEConnectToPeripheral (char *name) {
if (_unityBluetoothLE && name != nil)
[_unityBluetoothLE connectToPeripheral:[NSString stringWithFormat:@"%s", name]];
}
void _iOSBluetoothLEDisconnectPeripheral (char *name) {
if (_unityBluetoothLE && name != nil)
[_unityBluetoothLE disconnectPeripheral:[NSString stringWithFormat:@"%s", name]];
}
void _iOSBluetoothLEReadCharacteristic (char *name, char *service, char *characteristic) {
if (_unityBluetoothLE && name != nil && service != nil && characteristic != nil)
[_unityBluetoothLE readCharacteristic:[NSString stringWithFormat:@"%s", name] service:[NSString stringWithFormat:@"%s", service] characteristic:[NSString stringWithFormat:@"%s", characteristic]];
}
void _iOSBluetoothLEWriteCharacteristic (char *name, char *service, char *characteristic, unsigned char *data, int length, BOOL withResponse) {
if (_unityBluetoothLE && name != nil && service != nil && characteristic != nil && data != nil && length > 0)
[_unityBluetoothLE writeCharacteristic:[NSString stringWithFormat:@"%s", name] service:[NSString stringWithFormat:@"%s", service] characteristic:[NSString stringWithFormat:@"%s", characteristic] data:[NSData dataWithBytes:data length:length] withResponse:withResponse];
}
void _iOSBluetoothLESubscribeCharacteristic (char *name, char *service, char *characteristic) {
if (_unityBluetoothLE && name != nil && service != nil && characteristic != nil)
[_unityBluetoothLE subscribeCharacteristic:[NSString stringWithFormat:@"%s", name] service:[NSString stringWithFormat:@"%s", service] characteristic:[NSString stringWithFormat:@"%s", characteristic]];
}
void _iOSBluetoothLEUnSubscribeCharacteristic (char *name, char *service, char *characteristic) {
if (_unityBluetoothLE && name != nil && service != nil && characteristic != nil)
[_unityBluetoothLE unsubscribeCharacteristic:[NSString stringWithFormat:@"%s", name] service:[NSString stringWithFormat:@"%s", service] characteristic:[NSString stringWithFormat:@"%s", characteristic]];
}
void _iOSBluetoothLEDisconnectAll () {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE disconnectAll];
}
void _iOSBluetoothLERequestMtu (char *name, int mtu) {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE requestMtu:[NSString stringWithFormat:@"%s", name] mtu:mtu];
}
void _iOSBluetoothLEReadRSSI (char *name) {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE readRSSI:[NSString stringWithFormat:@"%s", name]];
}
#if !TARGET_OS_TV
void _iOSBluetoothLEScanForBeacons (char *proximityUUIDsStringRaw) {
if (_unityBluetoothLE != nil)
{
NSMutableArray *actualUUIDs = nil;
if (proximityUUIDsStringRaw != nil)
{
NSString *proximityUUIDsString = [NSString stringWithFormat:@"%s", proximityUUIDsStringRaw];
NSArray *proximityUUIDs = [proximityUUIDsString componentsSeparatedByString:@"|"];
if (proximityUUIDs.count > 0)
{
NSMutableArray<CLBeaconRegion *> *beaconRegions = [[NSMutableArray<CLBeaconRegion *> alloc] init];
for (NSString* sUUID in proximityUUIDs)
{
NSArray *parts = [sUUID componentsSeparatedByString:@":"];
if (parts.count == 2)
{
if (@available(iOS 13.0, *)) {
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithUUID:[[NSUUID alloc] initWithUUIDString:parts[0]] identifier:parts[1]];
[beaconRegions addObject:beaconRegion];
} else {
CLBeaconRegion *beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:parts[0]] identifier:parts[1]];
[beaconRegions addObject:beaconRegion];
}
[_unityBluetoothLE scanForBeacons:beaconRegions];
}
else
{
NSString *message = [NSString stringWithFormat:@"Error~iBeacon Scanning missing identifiers"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
}
else
{
NSString *message = [NSString stringWithFormat:@"Error~iBeacon Scanning requires proximity UUIDs"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
else
{
NSString *message = [NSString stringWithFormat:@"Error~iBeacon Scanning requires proximity UUIDs"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
}
void _iOSBluetoothLEStopBeaconScan () {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE stopBeaconScan];
}
void _iOSBluetoothLEPeripheralName (char *newName) {
if (_unityBluetoothLE != nil && newName != nil)
[_unityBluetoothLE peripheralName:[[NSString alloc] initWithUTF8String:newName]];
}
void _iOSBluetoothLECreateService (char *uuid, BOOL primary) {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE createService:[NSString stringWithFormat:@"%s", uuid] primary:primary];
}
void _iOSBluetoothLERemoveService (char *uuid) {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE removeService:[NSString stringWithFormat:@"%s", uuid]];
}
void _iOSBluetoothLERemoveServices () {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE removeServices];
}
void _iOSBluetoothLECreateCharacteristic (char *uuid, int properties, int permissions, unsigned char *data, int length) {
if (_unityBluetoothLE != nil) {
NSData *value = nil;
if (data != nil)
value = [[NSData alloc] initWithBytes:data length:length];
[_unityBluetoothLE createCharacteristic:[NSString stringWithFormat:@"%s", uuid] properties:properties permissions:permissions value:value];
}
}
void _iOSBluetoothLERemoveCharacteristic (char *uuid) {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE removeCharacteristic:[NSString stringWithFormat:@"%s", uuid]];
}
void _iOSBluetoothLERemoveCharacteristics () {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE removeCharacteristics];
}
void _iOSBluetoothLEStartAdvertising () {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE startAdvertising];
}
void _iOSBluetoothLEStopAdvertising () {
if (_unityBluetoothLE != nil)
[_unityBluetoothLE stopAdvertising];
}
void _iOSBluetoothLEUpdateCharacteristicValue (char *uuid, unsigned char *data, int length) {
if (_unityBluetoothLE != nil) {
NSData *value = nil;
if (data != nil)
value = [[NSData alloc] initWithBytes:data length:length];
[_unityBluetoothLE updateCharacteristicValue:[NSString stringWithFormat:@"%s", uuid] value:value];
}
}
#endif
}
@implementation UnityBluetoothLE
@synthesize _peripherals;
@synthesize _rssiOnly;
- (void)initialize:(BOOL)asCentral asPeripheral:(BOOL)asPeripheral
{
_mtu = 20;
_isPaused = FALSE;
_isInitializing = TRUE;
_centralManager = nil;
#if !TARGET_OS_TV
_peripheralManager = nil;
_services = nil;
_characteristics = nil;
_allCharacteristics = nil;
#endif
if (asCentral)
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
#if !TARGET_OS_TV
if (asPeripheral)
_peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
_services = [[NSMutableDictionary alloc] init];
_characteristics = [[NSMutableDictionary alloc] init];
_allCharacteristics = [[NSMutableDictionary alloc] init];
#endif
_peripherals = [[NSMutableDictionary alloc] init];
}
- (void)deInitialize
{
if (_backgroundMessages != nil)
{
for (UnityMessage *message in _backgroundMessages)
{
if (message != nil)
{
[message deInitialize];
[message release];
}
}
[_backgroundMessages release];
_backgroundMessages = nil;
}
#if !TARGET_OS_TV
if (_peripheralManager != nil)
[self stopAdvertising];
[self removeCharacteristics];
[self removeServices];
#endif
if (_centralManager != nil)
[self stopScan];
[_peripherals removeAllObjects];
}
- (void)pauseMessages:(BOOL)isPaused
{
if (isPaused != _isPaused) {
if (_backgroundMessages == nil)
_backgroundMessages = [[NSMutableArray alloc] init];
_isPaused = isPaused;
// if we are not paused now since we know we changed state
// that means we were paused so we need to pump the saved
// messages to Unity
if (isPaused) {
if (_backgroundMessages != nil) {
for (UnityMessage *message in _backgroundMessages) {
if (message != nil) {
[message sendUnityMessage];
[message deInitialize];
[message release];
}
}
[_backgroundMessages removeAllObjects];
}
}
}
}
#if !TARGET_OS_TV
- (void)createService:(NSString *)uuid primary:(BOOL)primary
{
CBUUID *cbuuid = [CBUUID UUIDWithString:uuid];
CBMutableService *service = [[CBMutableService alloc] initWithType:cbuuid primary:primary];
NSMutableArray *characteristics = [[NSMutableArray alloc] init];
NSEnumerator *enumerator = [_characteristics keyEnumerator];
id key;
while ((key = [enumerator nextObject]))
{
CBCharacteristic *characteristic = [_characteristics objectForKey:key];
[_characteristics removeObjectForKey:key];
[characteristics addObject:characteristic];
[_allCharacteristics setObject:characteristic forKey:[characteristic UUID]];
}
[_characteristics removeAllObjects];
service.characteristics = characteristics;
[_services setObject:service forKey:cbuuid];
if (_peripheralManager != nil)
{
[_peripheralManager addService:service];
}
}
- (void)removeService:(NSString *)uuid
{
if (_services != nil)
{
if (_peripheralManager != nil)
{
CBMutableService *service = [_services objectForKey:uuid];
if (service != nil)
[_peripheralManager removeService:service];
}
[_services removeObjectForKey:uuid];
}
}
- (void)removeServices
{
if (_services != nil)
{
[_services removeAllObjects];
if (_peripheralManager != nil)
[_peripheralManager removeAllServices];
}
if (_allCharacteristics != nil)
[_allCharacteristics removeAllObjects];
}
- (void)peripheralName:(NSString *)newName
{
_peripheralName = newName;
}
- (void)createCharacteristic:(NSString *)uuid properties:(CBCharacteristicProperties)properties permissions:(CBAttributePermissions)permissions value:(NSData *)value
{
CBUUID *cbuuid = [CBUUID UUIDWithString:uuid];
CBCharacteristic *characteristic = [[CBMutableCharacteristic alloc] initWithType:cbuuid properties:properties value:value permissions:permissions];
[_characteristics setObject:characteristic forKey:cbuuid];
}
- (void)removeCharacteristic:(NSString *)uuid
{
if (_characteristics != nil)
[_characteristics removeObjectForKey:uuid];
}
- (void)removeCharacteristics
{
if (_characteristics != nil)
[_characteristics removeAllObjects];
}
- (void)startAdvertising
{
if (_peripheralManager != nil && _services != nil)
{
NSMutableArray *services = [[NSMutableArray alloc] init];
NSEnumerator *enumerator = [_services keyEnumerator];
id key;
while ((key = [enumerator nextObject]))
{
CBMutableService *service = [_services objectForKey:key];
[services addObject:service.UUID];
}
if (_peripheralName == nil)
_peripheralName = @"";
[_peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : services, CBAdvertisementDataLocalNameKey : _peripheralName }];
}
}
- (void)stopAdvertising
{
if (_peripheralManager != nil)
{
[_peripheralManager stopAdvertising];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", "StoppedAdvertising");
}
}
- (void)updateCharacteristicValue:(NSString *)uuid value:(NSData *)value
{
if (_allCharacteristics != nil)
{
CBUUID *cbuuid = [CBUUID UUIDWithString:uuid];
CBMutableCharacteristic *characteristic = [_allCharacteristics objectForKey:cbuuid];
if (characteristic != nil)
{
characteristic.value = value;
if (_peripheralManager != nil)
[_peripheralManager updateValue:value forCharacteristic:characteristic onSubscribedCentrals:nil];
}
}
}
- (void)requestMtu:(NSString *)name mtu:(int)mtu
{
_mtu = mtu;
NSString *message = [NSString stringWithFormat:@"MtuChanged~%@~%d", name, _mtu];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
}
- (void)scanForBeacons:(NSArray<CLBeaconRegion *>*)beaconRegions
{
if ([CLLocationManager isRangingAvailable])
{
_locationManager = [CLLocationManager new];
_locationManager.delegate = self;
[_locationManager requestWhenInUseAuthorization];
for (CLBeaconRegion *region in beaconRegions)
[_locationManager startRangingBeaconsInRegion:region];
}
else
{
NSString *message = [NSString stringWithFormat:@"Error~iBeacon Ranging is not available"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
- (void) stopBeaconScan
{
if (_locationManager != nil)
{
for (CLBeaconRegion *region in _locationManager.rangedRegions)
[_locationManager stopRangingBeaconsInRegion:region];
[_locationManager release];
_locationManager = nil;
}
}
// beacon delegate implementation
- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region
{
NSString *message;
for (CLBeacon *beacon in beacons)
{
message = [NSString stringWithFormat:@"DiscoveredBeacon~%@~%ld~%ld~%ld~%ld~%ld", [beacon.proximityUUID.UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""], beacon.major.longValue, beacon.minor.longValue, (long)beacon.rssi, (long)0, (long)beacon.proximity];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
}
}
#endif
// central delegate implementation
- (void)scanForPeripheralsWithServices:(NSArray *)serviceUUIDs options:(NSDictionary *)options clearPeripheralList:(BOOL)clearPeripheralList recordType:(int)recordType
{
if (_centralManager != nil)
{
recordType = recordType;
if (clearPeripheralList && _peripherals != nil)
[_peripherals removeAllObjects];
[_centralManager scanForPeripheralsWithServices:serviceUUIDs options:options];
}
}
- (void) stopScan
{
if (_centralManager != nil)
[_centralManager stopScan];
}
- (void)retrieveListOfPeripheralsWithServices:(NSArray *)serviceUUIDs
{
if (_centralManager != nil)
{
if (_peripherals != nil)
[_peripherals removeAllObjects];
NSArray * list = [_centralManager retrieveConnectedPeripheralsWithServices:serviceUUIDs];
if (list != nil)
{
for (int i = 0; i < list.count; ++i)
{
CBPeripheral *peripheral = [list objectAtIndex:i];
if (peripheral != nil)
{
NSString *identifier = [[peripheral identifier] UUIDString];
NSString *name = [peripheral name];
NSString *message = [NSString stringWithFormat:@"RetrievedConnectedPeripheral~%@~%@", identifier, name];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
[_peripherals setObject:peripheral forKey:identifier];
}
}
}
}
}
- (void)connectToPeripheral:(NSString *)name
{
if (_peripherals != nil && name != nil)
{
CBPeripheral *peripheral = [_peripherals objectForKey:name];
if (peripheral != nil)
[_centralManager connectPeripheral:peripheral options:nil];
}
}
- (void)disconnectAll
{
if (_peripherals != nil && [_peripherals count] > 0)
{
NSArray* keys = [_peripherals allKeys];
for(NSString* key in keys)
{
CBPeripheral *peripheral = [_peripherals objectForKey:key];
if (peripheral != nil)
[_centralManager cancelPeripheralConnection:peripheral];
}
}
}
- (void)disconnectPeripheral:(NSString *)name
{
if (_peripherals != nil && name != nil)
{
CBPeripheral *peripheral = [_peripherals objectForKey:name];
if (peripheral != nil)
{
[_centralManager cancelPeripheralConnection:peripheral];
}
}
}
- (void)readRSSI:(NSString *)name
{
if (_peripherals != nil && name != nil)
{
CBPeripheral *peripheral = [_peripherals objectForKey:name];
if (peripheral != nil)
{
[peripheral readRSSI];
}
}
}
- (CBCharacteristic *)getCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString
{
CBCharacteristic *returnCharacteristic = nil;
if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil)
{
CBPeripheral *peripheral = [_peripherals objectForKey:name];
if (peripheral != nil)
{
CBUUID *serviceUUID = [CBUUID UUIDWithString:serviceString];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:characteristicString];
for (CBService *service in peripheral.services)
{
if ([service.UUID isEqual:serviceUUID])
{
for (CBCharacteristic *characteristic in service.characteristics)
{
if ([characteristic.UUID isEqual:characteristicUUID])
{
returnCharacteristic = characteristic;
}
}
}
}
}
}
return returnCharacteristic;
}
- (void)readCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString
{
if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil)
{
CBPeripheral *peripheral = [_peripherals objectForKey:name];
if (peripheral != nil)
{
CBCharacteristic *characteristic = [_unityBluetoothLE getCharacteristic:name service:serviceString characteristic:characteristicString];
if (characteristic != nil)
[peripheral readValueForCharacteristic:characteristic];
}
}
}
- (void)writeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString data:(NSData *)data withResponse:(BOOL)withResponse
{
if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil && data != nil)
{
CBPeripheral *peripheral = [_peripherals objectForKey:name];
if (peripheral != nil)
{
CBCharacteristic *characteristic = [_unityBluetoothLE getCharacteristic:name service:serviceString characteristic:characteristicString];
if (characteristic != nil)
{
CBCharacteristicWriteType type = CBCharacteristicWriteWithoutResponse;
if (withResponse)
type = CBCharacteristicWriteWithResponse;
[self writeCharactersticBytes:peripheral characteristic:characteristic data:data withResponse:type];
}
}
}
}
- (void)subscribeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString
{
if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil)
{
CBPeripheral *peripheral = [_peripherals objectForKey:name];
if (peripheral != nil)
{
CBCharacteristic *characteristic = [_unityBluetoothLE getCharacteristic:name service:serviceString characteristic:characteristicString];
if (characteristic != nil)
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
}
- (void)unsubscribeCharacteristic:(NSString *)name service:(NSString *)serviceString characteristic:(NSString *)characteristicString
{
if (name != nil && serviceString != nil && characteristicString != nil && _peripherals != nil)
{
CBPeripheral *peripheral = [_peripherals objectForKey:name];
if (peripheral != nil)
{
CBCharacteristic *characteristic = [_unityBluetoothLE getCharacteristic:name service:serviceString characteristic:characteristicString];
if (characteristic != nil)
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
}
}
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
switch (central.state)
{
case CBCentralManagerStateUnsupported:
{
NSLog(@"Central State: Unsupported");
NSString *message = [NSString stringWithFormat:@"Error~Bluetooth LE Not Supported"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
} break;
case CBCentralManagerStateUnauthorized:
{
NSLog(@"Central State: Unauthorized");
NSString *message = [NSString stringWithFormat:@"Error~Bluetooth LE Not Authorized"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
} break;
case CBCentralManagerStatePoweredOff:
{
NSLog(@"Central State: Powered Off");
NSString *message = [NSString stringWithFormat:@"Error~Bluetooth LE Powered Off"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
} break;
case CBCentralManagerStatePoweredOn:
{
NSLog(@"Central State: Powered On");
if (_isInitializing)
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", "Initialized");
_isInitializing = FALSE;
} break;
case CBCentralManagerStateUnknown:
{
NSLog(@"Central State: Unknown");
NSString *message = [NSString stringWithFormat:@"Error~Bluetooth LE Unknown"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
} break;
default:
{
}
}
}
- (void)centralManager:(CBCentralManager *)central didRetrievePeripherals:(NSArray *)peripherals
{
}
- (void)centralManager:(CBCentralManager *)central didRetrieveConnectedPeripherals:(NSArray *)peripherals
{
}
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
if (_peripherals != nil && peripheral != nil)
{
NSString *name = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if (name == nil)
name = peripheral.name;
if (name == nil)
name = @"No Name";
if (name != nil)
{
NSString *identifier = nil;
NSString *foundPeripheral = [self findPeripheralName:peripheral];
if (foundPeripheral == nil)
identifier = [[peripheral identifier] UUIDString];
else
identifier = foundPeripheral;
NSString *message = nil;
// 始终发送5字段消息格式确保 C# 层 DiscoveredPeripheralWithAdvertisingInfoAction 始终被调用
NSString *dataBase64 = @"";
if (advertisementData != nil && [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey] != nil)
{
NSData* bytes = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey];
dataBase64 = [UnityBluetoothLE base64StringFromData:bytes length:bytes.length];
}
message = [NSString stringWithFormat:@"DiscoveredPeripheral~%@~%@~%@~%@", identifier, name, RSSI, dataBase64];
if (message != nil)
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
[_peripherals setObject:peripheral forKey:identifier];
}
}
}
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
if (_peripherals != nil)
{
NSString *foundPeripheral = [self findPeripheralName:peripheral];
if (foundPeripheral != nil)
{
NSString *message = [NSString stringWithFormat:@"DisconnectedPeripheral~%@", foundPeripheral];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
}
}
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSString *foundPeripheral = [self findPeripheralName:peripheral];
if (foundPeripheral != nil)
{
NSString *message = [NSString stringWithFormat:@"ConnectedPeripheral~%@", foundPeripheral];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
peripheral.delegate = self;
[peripheral discoverServices:nil];
}
}
- (CBPeripheral *) findPeripheralInList:(CBPeripheral*)peripheral
{
CBPeripheral *foundPeripheral = nil;
NSEnumerator *enumerator = [_peripherals keyEnumerator];
id key;
while ((key = [enumerator nextObject]))
{
CBPeripheral *tempPeripheral = [_peripherals objectForKey:key];
if ([tempPeripheral isEqual:peripheral])
{
foundPeripheral = tempPeripheral;
break;
}
}
return foundPeripheral;
}
- (NSString *) findPeripheralName:(CBPeripheral*)peripheral
{
NSString *foundPeripheral = nil;
NSEnumerator *enumerator = [_peripherals keyEnumerator];
id key;
while ((key = [enumerator nextObject]))
{
CBPeripheral *tempPeripheral = [_peripherals objectForKey:key];
if ([tempPeripheral isEqual:peripheral])
{
foundPeripheral = key;
break;
}
}
return foundPeripheral;
}
// central peripheral delegate implementation
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
NSString *foundPeripheral = [self findPeripheralName:peripheral];
if (foundPeripheral != nil)
{
for (CBService *service in peripheral.services)
{
NSString *message = [NSString stringWithFormat:@"DiscoveredService~%@~%@", foundPeripheral, [service UUID]];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
[peripheral discoverCharacteristics:nil forService:service];
}
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
NSString *foundPeripheral = [self findPeripheralName:peripheral];
if (foundPeripheral != nil)
{
for (CBCharacteristic *characteristic in service.characteristics)
{
NSString *message = [NSString stringWithFormat:@"DiscoveredCharacteristic~%@~%@~%@", foundPeripheral, [service UUID], [characteristic UUID]];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
}
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
NSString *foundPeripheral = [self findPeripheralName:peripheral];
if (foundPeripheral != nil)
{
if (characteristic.value != nil)
{
NSString *message = [NSString stringWithFormat:@"DidUpdateValueForCharacteristic~%@~%@~%@", foundPeripheral, [characteristic UUID], [UnityBluetoothLE base64StringFromData:characteristic.value length:characteristic.value.length]];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
//NSString *message = [UnityBluetoothLE base64StringFromData:characteristic.value length:characteristic.value.length];
//UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothData", [message UTF8String] );
}
}
}
}
- (void)writeCharactersticBytesReset
{
_writeCharacteristicBytes = nil;
_writeCharacteristicLength = 0;
_writeCharacteristicPosition = 0;
_writeCharacteristicBytesToWrite = 0;
_writeCharacteristicWithResponse = CBCharacteristicWriteWithResponse;
_writeCharacteristicRetries = 3;
}
- (void)writeCharactersticBytes:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic data:(NSData *)data withResponse:(CBCharacteristicWriteType)withResponse
{
if (_writeCharacteristicBytes == nil && (_mtu == 0 || data.length > _mtu))
{
_writeCharacteristicLength = data.length;
_writeCharacteristicBytes = (unsigned char*)malloc(_writeCharacteristicLength);
memcpy(_writeCharacteristicBytes, [data bytes], _writeCharacteristicLength);
_writeCharacteristicPosition = 0;
_writeCharacteristicWithResponse = withResponse;
if (_mtu == 0)
_writeCharacteristicBytesToWrite = _writeCharacteristicLength;
else
_writeCharacteristicBytesToWrite = _mtu;
}
NSLog(@"write characteristic block");
if (_writeCharacteristicBytes != nil)
{
NSMutableData *newData = [NSMutableData dataWithCapacity:_writeCharacteristicBytesToWrite];
[newData appendBytes:&_writeCharacteristicBytes[_writeCharacteristicPosition] length:_writeCharacteristicBytesToWrite];
data = newData;
NSLog(@"data: %@", data);
}
NSLog(@"writing %ld bytes, %ld with response", data.length, withResponse);
[peripheral writeValue:data forCharacteristic:characteristic type:withResponse];
if (withResponse == CBCharacteristicWriteWithoutResponse)
{
double delayInSeconds = 0.01;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self writeNextPacket:peripheral characteristic:characteristic];
});
}
}
- (void)writeNextPacket:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic
{
if (_writeCharacteristicLength > _writeCharacteristicPosition + _writeCharacteristicBytesToWrite)
{
_writeCharacteristicPosition += _writeCharacteristicBytesToWrite;
if (_writeCharacteristicPosition + _writeCharacteristicBytesToWrite > _writeCharacteristicLength)
_writeCharacteristicBytesToWrite = _writeCharacteristicLength - _writeCharacteristicPosition;
NSMutableData *data = [NSMutableData dataWithCapacity:_writeCharacteristicLength];
[data appendBytes:_writeCharacteristicBytes length:_writeCharacteristicLength];
[self writeCharactersticBytes:peripheral characteristic:characteristic data:data withResponse:_writeCharacteristicWithResponse];
}
else
{
[self writeCharactersticBytesReset];
NSString *message = [NSString stringWithFormat:@"DidWriteCharacteristic~%@", characteristic.UUID];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
NSLog(@"%ld bytes written, %ld position, %ld length, %ld with response", _writeCharacteristicBytesToWrite, _writeCharacteristicPosition, _writeCharacteristicLength, _writeCharacteristicWithResponse);
if (_writeCharacteristicBytesToWrite > 0)
{
[self writeNextPacket:peripheral characteristic:characteristic];
}
else
{
NSString *message = [NSString stringWithFormat:@"DidWriteCharacteristic~%@", characteristic.UUID];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
NSString *foundPeripheral = [self findPeripheralName:peripheral];
if (foundPeripheral != nil)
{
NSString *message = [NSString stringWithFormat:@"DidUpdateNotificationStateForCharacteristic~%@~%@", foundPeripheral, characteristic.UUID];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
}
- (void)peripheral:(CBPeripheral *) peripheral didReadRSSI:(NSNumber *)RSSI error:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
NSString *foundPeripheral = [self findPeripheralName:peripheral];
if (foundPeripheral != nil)
{
NSString *message = [NSString stringWithFormat:@"DidReadRSSI~%@~%@", foundPeripheral, RSSI];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
}
#if !TARGET_OS_TV
// peripheral manager delegate implementation
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
{
_iOSBluetoothLELogString ([NSString stringWithFormat:@"Peripheral State Update: %d", (int)peripheral.state]);
if (_isInitializing && peripheral.state == CBPeripheralManagerStatePoweredOn)
{
_isInitializing = FALSE;
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", "Initialized");
}
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
NSString *message = [NSString stringWithFormat:@"ServiceAdded~%@", service.UUID];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
{
if (error)
{
NSString *message = [NSString stringWithFormat:@"Error~%@", error.description];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
NSString *message = [NSString stringWithFormat:@"StartedAdvertising"];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
{
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request
{
BOOL success = FALSE;
if (_peripheralManager != nil)
{
CBMutableCharacteristic *characteristic = [_allCharacteristics objectForKey:request.characteristic.UUID];
if (characteristic != nil)
{
request.value = [characteristic.value subdataWithRange:NSMakeRange(request.offset, characteristic.value.length - request.offset)];
[_peripheralManager respondToRequest:request withResult:CBATTErrorSuccess];
success = TRUE;
}
}
if (!success)
[_peripheralManager respondToRequest:request withResult:CBATTErrorAttributeNotFound];
}
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
BOOL success = FALSE;
if (_peripheralManager != nil)
{
for (int i = 0; i < requests.count; ++i)
{
CBATTRequest *request = [requests objectAtIndex:i];
if (request != nil)
{
CBMutableCharacteristic *characteristic = [_allCharacteristics objectForKey:request.characteristic.UUID];
if (characteristic != nil)
{
characteristic.value = request.value;
NSString *message = [NSString stringWithFormat:@"PeripheralReceivedWriteData~%@~%@", [characteristic UUID], [UnityBluetoothLE base64StringFromData:characteristic.value length:characteristic.value.length]];
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String]);
success = TRUE;
}
else
{
success = FALSE;
break;
}
}
else
{
success = FALSE;
break;
}
}
}
if (success)
[_peripheralManager respondToRequest:[requests objectAtIndex:0] withResult:CBATTErrorSuccess];
else
[_peripheralManager respondToRequest:[requests objectAtIndex:0] withResult:CBATTErrorAttributeNotFound];
}
#endif
- (void)sendUnityMessage:(BOOL)isString message:(NSString *)message
{
if (_isPaused) {
if (_backgroundMessages != nil) {
UnityMessage *unitymessage = [[UnityMessage alloc] init];
if (unitymessage != nil) {
[unitymessage initialize:isString message:message];
[_backgroundMessages addObject:unitymessage];
}
}
}
else {
if (isString)
{
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [message UTF8String] );
}
else
{
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothData", [message UTF8String] );
}
}
}
static char base64EncodingTable[64] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
+ (NSString *) base64StringFromData: (NSData *)data length: (int)length
{
unsigned long ixtext, lentext;
long ctremaining;
unsigned char input[3], output[4];
short i, charsonline = 0, ctcopy;
const unsigned char *raw;
NSMutableString *result;
lentext = [data length];
if (lentext < 1)
return @"";
result = [NSMutableString stringWithCapacity: lentext];
raw = (const unsigned char *)[data bytes];
ixtext = 0;
while (true) {
ctremaining = lentext - ixtext;
if (ctremaining <= 0)
break;
for (i = 0; i < 3; i++) {
unsigned long ix = ixtext + i;
if (ix < lentext)
input[i] = raw[ix];
else
input[i] = 0;
}
output[0] = (input[0] & 0xFC) >> 2;
output[1] = ((input[0] & 0x03) << 4) | ((input[1] & 0xF0) >> 4);
output[2] = ((input[1] & 0x0F) << 2) | ((input[2] & 0xC0) >> 6);
output[3] = input[2] & 0x3F;
ctcopy = 4;
switch (ctremaining) {
case 1:
ctcopy = 2;
break;
case 2:
ctcopy = 3;
break;
}
for (i = 0; i < ctcopy; i++)
[result appendString: [NSString stringWithFormat: @"%c", base64EncodingTable[output[i]]]];
for (i = ctcopy; i < 4; i++)
[result appendString: @"="];
ixtext += 3;
charsonline += 4;
if ((length > 0) && (charsonline >= length))
charsonline = 0;
}
return result;
}
#pragma mark Internal
@end
@implementation UnityMessage
- (void)initialize:(BOOL)isString message:(NSString *)message
{
_isString = isString;
_message = [message copy];
}
- (void)deInitialize
{
if (_message != nil)
[_message release];
_message = nil;
}
- (void)sendUnityMessage
{
if (_message != nil) {
if (_isString)
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothMessage", [_message UTF8String] );
else
UnitySendMessage ("BluetoothLEReceiver", "OnBluetoothData", [_message UTF8String] );
}
}
@end