├── mac-ble-peripheral-objc-cli.xcodeproj ├── project.xcworkspace │ ├── xcshareddata │ │ └── WorkspaceSettings.xcsettings │ └── contents.xcworkspacedata └── project.pbxproj ├── .gitignore ├── mac-ble-peripheral-objc-cli ├── manager.h ├── PrefixHeader.pch ├── main.m └── manager.m └── README.md /mac-ble-peripheral-objc-cli.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /mac-ble-peripheral-objc-cli.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | 20 | #CocoaPods 21 | Pods 22 | -------------------------------------------------------------------------------- /mac-ble-peripheral-objc-cli/manager.h: -------------------------------------------------------------------------------- 1 | // 2 | // Manager.h 3 | // mac-ble 4 | // 5 | // Created by Itamar Hassin on 12/25/17. 6 | // Copyright © 2017 Itamar Hassin. All rights reserved. 7 | // 8 | 9 | #import 10 | @import CoreBluetooth; 11 | 12 | @interface Manager : NSObject 13 | 14 | - (Boolean) running; 15 | - (void) advertize; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /mac-ble-peripheral-objc-cli/PrefixHeader.pch: -------------------------------------------------------------------------------- 1 | // 2 | // PrefixHeader.pch 3 | // BLEPeripheral 4 | // 5 | // Created by Itamar Hassin on 1/7/18. 6 | // Copyright © 2018 Sandeep Mistry. All rights reserved. 7 | // 8 | 9 | #ifndef PrefixHeader_pch 10 | #define PrefixHeader_pch 11 | 12 | // Include any system framework and library headers here that should be included in all compilation units. 13 | // You will also need to set the Prefix Header build setting of one or more of your targets to reference this file. 14 | 15 | #endif /* PrefixHeader_pch */ 16 | -------------------------------------------------------------------------------- /mac-ble-peripheral-objc-cli/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // mac-ble 4 | // 5 | // Created by Itamar Hassin on 12/25/17. 6 | // Copyright © 2017 Itamar Hassin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "manager.h" 12 | 13 | int main(int argc, const char * argv[]) { 14 | @autoreleasepool { 15 | Manager *manager = [[Manager alloc] init]; 16 | 17 | NSRunLoop *runLoop = NSRunLoop.currentRunLoop; 18 | NSDate *distantFuture = NSDate.distantFuture; 19 | while([manager running] && [runLoop runMode:NSDefaultRunLoopMode beforeDate:distantFuture]) { 20 | [manager advertize]; 21 | } 22 | 23 | } 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /mac-ble-peripheral-objc-cli/manager.m: -------------------------------------------------------------------------------- 1 | // 2 | // manager.m 3 | // 4 | // Created by Itamar Hassin on 12/25/17. 5 | // Copyright © 2017 Itamar Hassin. All rights reserved. 6 | // 7 | #import "manager.h" 8 | 9 | @interface Manager () 10 | @end 11 | 12 | @implementation Manager 13 | { 14 | CBPeripheralManager *_peripheralManager; 15 | Boolean _running; 16 | NSString *_peripheralData; 17 | CBUUID *_charUUID; 18 | CBUUID *_myUUID; 19 | } 20 | 21 | - (id) init 22 | { 23 | self = [super init]; 24 | if (self) 25 | { 26 | _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; 27 | _running = true; 28 | _peripheralData = [NSString stringWithFormat:@"ItaBaby"]; 29 | 30 | _charUUID = [CBUUID UUIDWithString:@"DDCA9B49-A6F5-462F-A89A-C2144083CA7F"]; 31 | _myUUID = [CBUUID UUIDWithString:@"BD0F6577-4A38-4D71-AF1B-4E8F57708080"]; 32 | } 33 | return self; 34 | } 35 | 36 | // Method called whenever BT state changes. 37 | - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral 38 | { 39 | CBManagerState state = [peripheral state]; 40 | 41 | NSString *string = @"Unknown state"; 42 | 43 | switch(state) 44 | { 45 | case CBManagerStatePoweredOff: 46 | string = @"CoreBluetooth BLE hardware is powered off."; 47 | break; 48 | 49 | case CBManagerStatePoweredOn: 50 | string = @"CoreBluetooth BLE hardware is powered on and ready."; 51 | break; 52 | 53 | case CBManagerStateUnauthorized: 54 | string = @"CoreBluetooth BLE state is unauthorized."; 55 | break; 56 | 57 | case CBManagerStateUnknown: 58 | string = @"CoreBluetooth BLE state is unknown."; 59 | break; 60 | 61 | case CBManagerStateUnsupported: 62 | string = @"CoreBluetooth BLE hardware is unsupported on this platform."; 63 | break; 64 | 65 | default: 66 | break; 67 | } 68 | NSLog(@"%@", string); 69 | } 70 | 71 | - (void) advertize 72 | { 73 | if(_peripheralManager.isAdvertising) 74 | { 75 | return; 76 | } 77 | 78 | CBMutableService *service; 79 | service = [[CBMutableService alloc] initWithType:_myUUID primary:YES]; 80 | 81 | CBMutableCharacteristic *myCharacteristic = [[CBMutableCharacteristic alloc] 82 | initWithType:_charUUID properties:CBCharacteristicPropertyRead|CBCharacteristicPropertyIndicate|CBCharacteristicPropertyWriteWithoutResponse value:nil permissions:CBAttributePermissionsReadable|CBAttributePermissionsWriteable]; 83 | service.characteristics = @[myCharacteristic]; 84 | [_peripheralManager addService:service]; 85 | 86 | [_peripheralManager startAdvertising:@{ 87 | CBAdvertisementDataLocalNameKey: @"ITAMAR-MAC-BOOK-PRO", 88 | CBAdvertisementDataServiceUUIDsKey: @[_myUUID] 89 | }]; 90 | } 91 | 92 | - (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error 93 | { 94 | NSLog(@"peripheralManagerDidStartAdvertising: %@", peripheral.description); 95 | if (error) { 96 | NSLog(@"Error advertising: %@", [error localizedDescription]); 97 | } 98 | } 99 | 100 | - (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error 101 | { 102 | NSLog(@"peripheralManagerDidAddService: %@ %@", service, error); 103 | if (error) { 104 | NSLog(@"Error publishing service: %@", [error localizedDescription]); 105 | } 106 | } 107 | 108 | - (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request 109 | { 110 | if ([request.characteristic.UUID isEqual:_charUUID]) { 111 | request.value = [_peripheralData dataUsingEncoding:NSUTF8StringEncoding]; 112 | [peripheral respondToRequest:request withResult:CBATTErrorSuccess]; 113 | NSLog(@"didReceiveReadRequest: %@ %@. Returning %@", request.central, request.characteristic.UUID, _peripheralData); 114 | } else 115 | { 116 | NSLog(@"didReceiveReadRequest: %@ %@. Ignoring!", request.central, request.characteristic.UUID); 117 | } 118 | } 119 | 120 | - (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests 121 | { 122 | CBATTRequest *request = requests[0]; 123 | if ([request.characteristic.UUID isEqual:_charUUID]) { 124 | _peripheralData =[NSString stringWithUTF8String:[request.value bytes]]; 125 | NSLog(@"didReceiveWriteRequest: Wrote: %@", _peripheralData); 126 | } else 127 | { 128 | NSLog(@"didReceiveWriteRequest: %@ %@. Ignoring!", request.central, request.characteristic.UUID); 129 | } 130 | } 131 | 132 | - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic 133 | { 134 | NSLog(@"didSubscribeToCharacteristic"); 135 | } 136 | 137 | - (Boolean) running 138 | { 139 | return(_running); 140 | } 141 | 142 | @end 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is a demonstration of my experimentation with running a Bluetooth LE peripheral on my Mac, as a proof of concept and part of my endeavour to learn about BLE. 4 | Hopefully you will find it useful for the same reasons, or maybe will help kickstart your next BLE peripheral implementation. 5 | 6 | # Protocol flow 7 | 8 | Without going too deeply into the BLE stack's protocol, a subject for entire books, here's the flow for this command-line POC: 9 | 10 | - Set up a run-loop that allocates CPU to our routines 11 | - Start up Mac OS X BLE service 12 | - Set up a service and associated characteristic of the POC 13 | - Start advertizing the service 14 | - Handle incoming I/O requests 15 | 16 | # Implementation 17 | 18 | ## Set up a run-loop that allocates CPU to our routines 19 | 20 | I did not want to be distracted by coding a UI for this POC, so I chose to implement this POC as a command-line-tool. 21 | This means we need to give ourselves CPU time using a loop in [main.m](https://github.com/ihassin/mac-ble-peripheral-objc-cli/blob/master/mac-ble-peripheral-objc-cli/main.m): 22 | 23 | ``` 24 | while([manager running] && [runLoop runMode:NSDefaultRunLoopMode beforeDate:distantFuture]) { 25 | [manager advertize]; 26 | } 27 | ``` 28 | 29 | Without this loop, nothing will work. 30 | 31 | ## Start up Mac OS X BLE service 32 | 33 | By instantiating CBPeripheralManager, Mac OS loads and starts the BLE framework, allowing us to interact with it as a peripheral. 34 | 35 | This is done in the constructor of [manager.m](https://github.com/ihassin/mac-ble-peripheral-objc-cli/blob/master/mac-ble-peripheral-objc-cli/manager.m): 36 | ``` 37 | _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil]; 38 | ``` 39 | 40 | ## Set up a service and associated characteristic of the POC 41 | 42 | To serve data, we need to create a service that will be advertised to potential clients. 43 | Doing so is a matter of creating a characteristic, which will expose the peripheral's data, and adding it to a service that clients can look for. 44 | Both these objects (service and characteristic) need a UUID to distinguish them from other vendors and their services. 45 | I used the Mac's built-in UUID generator (uuidgen) to create both for the POC and assigned them to instance variables: 46 | 47 | ``` 48 | _charUUID = [CBUUID UUIDWithString:@"DDCA9B49-A6F5-462F-A89A-C2144083CA7F"]; 49 | _myUUID = [CBUUID UUIDWithString:@"BD0F6577-4A38-4D71-AF1B-4E8F57708080"]; 50 | ``` 51 | 52 | I wanted to be able to read and write the data value of the peripheral, to test out those functions, and used the following flags when creating the characteristic: 53 | ```text 54 | CBMutableCharacteristic *myCharacteristic = [[CBMutableCharacteristic alloc] 55 | initWithType:_charUUID properties:CBCharacteristicPropertyRead|CBCharacteristicPropertyIndicate|CBCharacteristicPropertyWriteWithoutResponse value:nil permissions:CBAttributePermissionsReadable|CBAttributePermissionsWriteable]; 56 | ``` 57 | 58 | An important point is _not_ to set the initial value (see value:nil); if you set the initial value, it's taken as a static characteristic, and writes won't be routed to our callback. 59 | 60 | After adding the characteristic to the service, we add the service to the list of services the peripheral supports to the manager object, putting us in a state where we can adverise: 61 | 62 | ## Start advertising the service 63 | 64 | To have Centrals connect to our Peripheral, it needs to adverise itself: 65 | 66 | ``` 67 | [_peripheralManager startAdvertising:@{ 68 | CBAdvertisementDataLocalNameKey: @"ITAMAR-MAC-BOOK-PRO", 69 | CBAdvertisementDataServiceUUIDsKey: @[_myUUID] 70 | }]; 71 | ``` 72 | 73 | The name 'ITAMAR-MAC-BOOK-PRO' is the one your Bluetooth scanner might display. I used [BLE Scanner](https://itunes.apple.com/us/app/ble-scanner-4-0/id1221763603?mt=8). 74 | 75 | ## Handle incoming I/O requests 76 | 77 | At this stage, your scanner should pick up the device (your mac) and service (itamar etc). 78 | Characteristics can be read or written only if the Central is connected to them. This is not _pairing_, but _connecting_. 79 | Once connected, your scanner can read the value exposed by querying the specific charactersitic's UUID, which, in our case, is 80 | ``` 81 | DDCA9B49-A6F5-462F-A89A-C2144083CA7F 82 | ``` 83 | 84 | Reading, as well as writing, will trigger our callbacks to be called by CBPeripheralManager: 85 | 86 | Read callback: 87 | 88 | ```text 89 | - (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request 90 | { 91 | if ([request.characteristic.UUID isEqual:_charUUID]) { 92 | request.value = [_peripheralData dataUsingEncoding:NSUTF8StringEncoding]; 93 | [peripheral respondToRequest:request withResult:CBATTErrorSuccess]; 94 | NSLog(@"didReceiveReadRequest: %@ %@. Returning %@", request.central, request.characteristic.UUID, _peripheralData); 95 | } else 96 | { 97 | NSLog(@"didReceiveReadRequest: %@ %@. Ignoring!", request.central, request.characteristic.UUID); 98 | } 99 | } 100 | ``` 101 | 102 | Write callback: 103 | ``` 104 | - (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests 105 | { 106 | CBATTRequest *request = requests[0]; 107 | if ([request.characteristic.UUID isEqual:_charUUID]) { 108 | _peripheralData =[NSString stringWithUTF8String:[request.value bytes]]; 109 | NSLog(@"didReceiveWriteRequest: Wrote: %@", _peripheralData); 110 | } else 111 | { 112 | NSLog(@"didReceiveWriteRequest: %@ %@. Ignoring!", request.central, request.characteristic.UUID); 113 | } 114 | } 115 | ``` 116 | 117 | In this POC, I do some basic checking and handle the request, but most of the code is to translate NSData to NSString and vice versa. 118 | 119 | # Access the example 120 | 121 | Please feel free to use, fork and improve this snippet, posted on [github](https://github.com/ihassin/mac-ble-peripheral-objc-cli). 122 | 123 | I hope you find the example useful! 124 | 125 | Happy hacking! 126 | 127 | -------------------------------------------------------------------------------- /mac-ble-peripheral-objc-cli.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6A53C802200BA525005FD0D2 /* manager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A53C801200BA525005FD0D2 /* manager.m */; }; 11 | 6A53C804200BB307005FD0D2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6A53C803200BB307005FD0D2 /* main.m */; }; 12 | 6ABC5ABC200D894A0009D82E /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 6ABC5ABB200D894A0009D82E /* README.md */; }; 13 | 6ACE3A6F2002DE9D007B850C /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6ACE3A6E2002DE9D007B850C /* CoreBluetooth.framework */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXContainerItemProxy section */ 17 | AFE86AA1181EB226001E1827 /* PBXContainerItemProxy */ = { 18 | isa = PBXContainerItemProxy; 19 | containerPortal = AFE86A74181EB226001E1827 /* Project object */; 20 | proxyType = 1; 21 | remoteGlobalIDString = AFE86A7B181EB226001E1827; 22 | remoteInfo = BLEPeripheral; 23 | }; 24 | /* End PBXContainerItemProxy section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 6A53C800200BA442005FD0D2 /* manager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = manager.h; sourceTree = ""; }; 28 | 6A53C801200BA525005FD0D2 /* manager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = manager.m; sourceTree = ""; }; 29 | 6A53C803200BB307005FD0D2 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = "mac-ble-peripheral-objc-cli/main.m"; sourceTree = ""; }; 30 | 6ABC5ABB200D894A0009D82E /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 31 | 6ACE3A6E2002DE9D007B850C /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; }; 32 | 6ACE3A702002E3D9007B850C /* PrefixHeader.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PrefixHeader.pch; sourceTree = ""; }; 33 | AFE86A7C181EB226001E1827 /* mac-ble-peripheral-objc-cli.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "mac-ble-peripheral-objc-cli.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | AFE86A9D181EB226001E1827 /* mac-ble-peripheral-objc-cliTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "mac-ble-peripheral-objc-cliTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | AFE86A79181EB226001E1827 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | 6ACE3A6F2002DE9D007B850C /* CoreBluetooth.framework in Frameworks */, 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | AFE86A9A181EB226001E1827 /* Frameworks */ = { 47 | isa = PBXFrameworksBuildPhase; 48 | buildActionMask = 2147483647; 49 | files = ( 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXFrameworksBuildPhase section */ 54 | 55 | /* Begin PBXGroup section */ 56 | AFE86A73181EB226001E1827 = { 57 | isa = PBXGroup; 58 | children = ( 59 | 6ABC5ABB200D894A0009D82E /* README.md */, 60 | 6A53C803200BB307005FD0D2 /* main.m */, 61 | AFE86A85181EB226001E1827 /* mac-ble-peripheral-objc-cli */, 62 | AFE86A7E181EB226001E1827 /* Frameworks */, 63 | AFE86A7D181EB226001E1827 /* Products */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | AFE86A7D181EB226001E1827 /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | AFE86A7C181EB226001E1827 /* mac-ble-peripheral-objc-cli.app */, 71 | AFE86A9D181EB226001E1827 /* mac-ble-peripheral-objc-cliTests.xctest */, 72 | ); 73 | name = Products; 74 | sourceTree = ""; 75 | }; 76 | AFE86A7E181EB226001E1827 /* Frameworks */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 6ACE3A6E2002DE9D007B850C /* CoreBluetooth.framework */, 80 | ); 81 | name = Frameworks; 82 | sourceTree = ""; 83 | }; 84 | AFE86A85181EB226001E1827 /* mac-ble-peripheral-objc-cli */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 6ACE3A702002E3D9007B850C /* PrefixHeader.pch */, 88 | 6A53C800200BA442005FD0D2 /* manager.h */, 89 | 6A53C801200BA525005FD0D2 /* manager.m */, 90 | ); 91 | path = "mac-ble-peripheral-objc-cli"; 92 | sourceTree = ""; 93 | }; 94 | /* End PBXGroup section */ 95 | 96 | /* Begin PBXNativeTarget section */ 97 | AFE86A7B181EB226001E1827 /* mac-ble-peripheral-objc-cli */ = { 98 | isa = PBXNativeTarget; 99 | buildConfigurationList = AFE86AAD181EB226001E1827 /* Build configuration list for PBXNativeTarget "mac-ble-peripheral-objc-cli" */; 100 | buildPhases = ( 101 | AFE86A78181EB226001E1827 /* Sources */, 102 | AFE86A79181EB226001E1827 /* Frameworks */, 103 | AFE86A7A181EB226001E1827 /* Resources */, 104 | ); 105 | buildRules = ( 106 | ); 107 | dependencies = ( 108 | ); 109 | name = "mac-ble-peripheral-objc-cli"; 110 | productName = BLEPeripheral; 111 | productReference = AFE86A7C181EB226001E1827 /* mac-ble-peripheral-objc-cli.app */; 112 | productType = "com.apple.product-type.application"; 113 | }; 114 | AFE86A9C181EB226001E1827 /* mac-ble-peripheral-objc-cliTests */ = { 115 | isa = PBXNativeTarget; 116 | buildConfigurationList = AFE86AB0181EB226001E1827 /* Build configuration list for PBXNativeTarget "mac-ble-peripheral-objc-cliTests" */; 117 | buildPhases = ( 118 | AFE86A99181EB226001E1827 /* Sources */, 119 | AFE86A9A181EB226001E1827 /* Frameworks */, 120 | AFE86A9B181EB226001E1827 /* Resources */, 121 | ); 122 | buildRules = ( 123 | ); 124 | dependencies = ( 125 | AFE86AA2181EB226001E1827 /* PBXTargetDependency */, 126 | ); 127 | name = "mac-ble-peripheral-objc-cliTests"; 128 | productName = BLEPeripheralTests; 129 | productReference = AFE86A9D181EB226001E1827 /* mac-ble-peripheral-objc-cliTests.xctest */; 130 | productType = "com.apple.product-type.bundle.unit-test"; 131 | }; 132 | /* End PBXNativeTarget section */ 133 | 134 | /* Begin PBXProject section */ 135 | AFE86A74181EB226001E1827 /* Project object */ = { 136 | isa = PBXProject; 137 | attributes = { 138 | CLASSPREFIX = BP; 139 | LastUpgradeCheck = 0920; 140 | ORGANIZATIONNAME = "Sandeep Mistry"; 141 | TargetAttributes = { 142 | AFE86A9C181EB226001E1827 = { 143 | TestTargetID = AFE86A7B181EB226001E1827; 144 | }; 145 | }; 146 | }; 147 | buildConfigurationList = AFE86A77181EB226001E1827 /* Build configuration list for PBXProject "mac-ble-peripheral-objc-cli" */; 148 | compatibilityVersion = "Xcode 3.2"; 149 | developmentRegion = English; 150 | hasScannedForEncodings = 0; 151 | knownRegions = ( 152 | en, 153 | Base, 154 | ); 155 | mainGroup = AFE86A73181EB226001E1827; 156 | productRefGroup = AFE86A7D181EB226001E1827 /* Products */; 157 | projectDirPath = ""; 158 | projectRoot = ""; 159 | targets = ( 160 | AFE86A7B181EB226001E1827 /* mac-ble-peripheral-objc-cli */, 161 | AFE86A9C181EB226001E1827 /* mac-ble-peripheral-objc-cliTests */, 162 | ); 163 | }; 164 | /* End PBXProject section */ 165 | 166 | /* Begin PBXResourcesBuildPhase section */ 167 | AFE86A7A181EB226001E1827 /* Resources */ = { 168 | isa = PBXResourcesBuildPhase; 169 | buildActionMask = 2147483647; 170 | files = ( 171 | 6ABC5ABC200D894A0009D82E /* README.md in Resources */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | AFE86A9B181EB226001E1827 /* Resources */ = { 176 | isa = PBXResourcesBuildPhase; 177 | buildActionMask = 2147483647; 178 | files = ( 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXResourcesBuildPhase section */ 183 | 184 | /* Begin PBXSourcesBuildPhase section */ 185 | AFE86A78181EB226001E1827 /* Sources */ = { 186 | isa = PBXSourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | 6A53C804200BB307005FD0D2 /* main.m in Sources */, 190 | 6A53C802200BA525005FD0D2 /* manager.m in Sources */, 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | }; 194 | AFE86A99181EB226001E1827 /* Sources */ = { 195 | isa = PBXSourcesBuildPhase; 196 | buildActionMask = 2147483647; 197 | files = ( 198 | ); 199 | runOnlyForDeploymentPostprocessing = 0; 200 | }; 201 | /* End PBXSourcesBuildPhase section */ 202 | 203 | /* Begin PBXTargetDependency section */ 204 | AFE86AA2181EB226001E1827 /* PBXTargetDependency */ = { 205 | isa = PBXTargetDependency; 206 | target = AFE86A7B181EB226001E1827 /* mac-ble-peripheral-objc-cli */; 207 | targetProxy = AFE86AA1181EB226001E1827 /* PBXContainerItemProxy */; 208 | }; 209 | /* End PBXTargetDependency section */ 210 | 211 | /* Begin XCBuildConfiguration section */ 212 | AFE86AAB181EB226001E1827 /* Debug */ = { 213 | isa = XCBuildConfiguration; 214 | buildSettings = { 215 | ALWAYS_SEARCH_USER_PATHS = NO; 216 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 217 | CLANG_CXX_LIBRARY = "libc++"; 218 | CLANG_ENABLE_MODULE_DEBUGGING = NO; 219 | CLANG_ENABLE_OBJC_ARC = YES; 220 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 221 | CLANG_WARN_BOOL_CONVERSION = YES; 222 | CLANG_WARN_COMMA = YES; 223 | CLANG_WARN_CONSTANT_CONVERSION = YES; 224 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 225 | CLANG_WARN_EMPTY_BODY = YES; 226 | CLANG_WARN_ENUM_CONVERSION = YES; 227 | CLANG_WARN_INFINITE_RECURSION = YES; 228 | CLANG_WARN_INT_CONVERSION = YES; 229 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 230 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 231 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 232 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 233 | CLANG_WARN_STRICT_PROTOTYPES = YES; 234 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 235 | CLANG_WARN_UNREACHABLE_CODE = YES; 236 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 237 | COPY_PHASE_STRIP = NO; 238 | ENABLE_STRICT_OBJC_MSGSEND = YES; 239 | ENABLE_TESTABILITY = YES; 240 | GCC_C_LANGUAGE_STANDARD = gnu99; 241 | GCC_DYNAMIC_NO_PIC = NO; 242 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 243 | GCC_NO_COMMON_BLOCKS = YES; 244 | GCC_OPTIMIZATION_LEVEL = 0; 245 | GCC_PREPROCESSOR_DEFINITIONS = ( 246 | "DEBUG=1", 247 | "$(inherited)", 248 | ); 249 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 250 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 251 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 252 | GCC_WARN_UNDECLARED_SELECTOR = YES; 253 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 254 | GCC_WARN_UNUSED_FUNCTION = YES; 255 | GCC_WARN_UNUSED_VARIABLE = YES; 256 | MACOSX_DEPLOYMENT_TARGET = 10.9; 257 | ONLY_ACTIVE_ARCH = YES; 258 | OTHER_LDFLAGS = "-ObjC"; 259 | PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; 260 | SDKROOT = macosx; 261 | SHARED_PRECOMPS_DIR = ./PrefixHeader.pch; 262 | }; 263 | name = Debug; 264 | }; 265 | AFE86AAC181EB226001E1827 /* Release */ = { 266 | isa = XCBuildConfiguration; 267 | buildSettings = { 268 | ALWAYS_SEARCH_USER_PATHS = NO; 269 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 270 | CLANG_CXX_LIBRARY = "libc++"; 271 | CLANG_ENABLE_MODULE_DEBUGGING = NO; 272 | CLANG_ENABLE_OBJC_ARC = YES; 273 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 274 | CLANG_WARN_BOOL_CONVERSION = YES; 275 | CLANG_WARN_COMMA = YES; 276 | CLANG_WARN_CONSTANT_CONVERSION = YES; 277 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 278 | CLANG_WARN_EMPTY_BODY = YES; 279 | CLANG_WARN_ENUM_CONVERSION = YES; 280 | CLANG_WARN_INFINITE_RECURSION = YES; 281 | CLANG_WARN_INT_CONVERSION = YES; 282 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 283 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 285 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 286 | CLANG_WARN_STRICT_PROTOTYPES = YES; 287 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 288 | CLANG_WARN_UNREACHABLE_CODE = YES; 289 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 290 | COPY_PHASE_STRIP = YES; 291 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 292 | ENABLE_NS_ASSERTIONS = NO; 293 | ENABLE_STRICT_OBJC_MSGSEND = YES; 294 | GCC_C_LANGUAGE_STANDARD = gnu99; 295 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 296 | GCC_NO_COMMON_BLOCKS = YES; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | MACOSX_DEPLOYMENT_TARGET = 10.9; 304 | OTHER_LDFLAGS = "-ObjC"; 305 | PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO; 306 | SDKROOT = macosx; 307 | SHARED_PRECOMPS_DIR = ""; 308 | }; 309 | name = Release; 310 | }; 311 | AFE86AAE181EB226001E1827 /* Debug */ = { 312 | isa = XCBuildConfiguration; 313 | buildSettings = { 314 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 315 | CLANG_ENABLE_MODULES = YES; 316 | COMBINE_HIDPI_IMAGES = YES; 317 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 318 | GCC_PREFIX_HEADER = ""; 319 | INFOPLIST_FILE = ""; 320 | MACOSX_DEPLOYMENT_TARGET = 10.13; 321 | PRODUCT_BUNDLE_IDENTIFIER = "ca.sandeepmistry.${PRODUCT_NAME:rfc1034identifier}"; 322 | PRODUCT_NAME = "$(TARGET_NAME)"; 323 | WRAPPER_EXTENSION = app; 324 | }; 325 | name = Debug; 326 | }; 327 | AFE86AAF181EB226001E1827 /* Release */ = { 328 | isa = XCBuildConfiguration; 329 | buildSettings = { 330 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 331 | CLANG_ENABLE_MODULES = YES; 332 | COMBINE_HIDPI_IMAGES = YES; 333 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 334 | GCC_PREFIX_HEADER = ""; 335 | INFOPLIST_FILE = ""; 336 | MACOSX_DEPLOYMENT_TARGET = 10.13; 337 | PRODUCT_BUNDLE_IDENTIFIER = "ca.sandeepmistry.${PRODUCT_NAME:rfc1034identifier}"; 338 | PRODUCT_NAME = "$(TARGET_NAME)"; 339 | WRAPPER_EXTENSION = app; 340 | }; 341 | name = Release; 342 | }; 343 | AFE86AB1181EB226001E1827 /* Debug */ = { 344 | isa = XCBuildConfiguration; 345 | buildSettings = { 346 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/BLEPeripheral.app/Contents/MacOS/BLEPeripheral"; 347 | COMBINE_HIDPI_IMAGES = YES; 348 | FRAMEWORK_SEARCH_PATHS = ( 349 | "$(DEVELOPER_FRAMEWORKS_DIR)", 350 | "$(inherited)", 351 | ); 352 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 353 | GCC_PREFIX_HEADER = "BLEPeripheral/BLEPeripheral-Prefix.pch"; 354 | GCC_PREPROCESSOR_DEFINITIONS = ( 355 | "DEBUG=1", 356 | "$(inherited)", 357 | ); 358 | INFOPLIST_FILE = "BLEPeripheralTests/BLEPeripheralTests-Info.plist"; 359 | PRODUCT_BUNDLE_IDENTIFIER = "ca.sandeepmistry.${PRODUCT_NAME:rfc1034identifier}"; 360 | PRODUCT_NAME = "$(TARGET_NAME)"; 361 | TEST_HOST = "$(BUNDLE_LOADER)"; 362 | WRAPPER_EXTENSION = xctest; 363 | }; 364 | name = Debug; 365 | }; 366 | AFE86AB2181EB226001E1827 /* Release */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/BLEPeripheral.app/Contents/MacOS/BLEPeripheral"; 370 | COMBINE_HIDPI_IMAGES = YES; 371 | FRAMEWORK_SEARCH_PATHS = ( 372 | "$(DEVELOPER_FRAMEWORKS_DIR)", 373 | "$(inherited)", 374 | ); 375 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 376 | GCC_PREFIX_HEADER = "BLEPeripheral/BLEPeripheral-Prefix.pch"; 377 | INFOPLIST_FILE = "BLEPeripheralTests/BLEPeripheralTests-Info.plist"; 378 | PRODUCT_BUNDLE_IDENTIFIER = "ca.sandeepmistry.${PRODUCT_NAME:rfc1034identifier}"; 379 | PRODUCT_NAME = "$(TARGET_NAME)"; 380 | TEST_HOST = "$(BUNDLE_LOADER)"; 381 | WRAPPER_EXTENSION = xctest; 382 | }; 383 | name = Release; 384 | }; 385 | /* End XCBuildConfiguration section */ 386 | 387 | /* Begin XCConfigurationList section */ 388 | AFE86A77181EB226001E1827 /* Build configuration list for PBXProject "mac-ble-peripheral-objc-cli" */ = { 389 | isa = XCConfigurationList; 390 | buildConfigurations = ( 391 | AFE86AAB181EB226001E1827 /* Debug */, 392 | AFE86AAC181EB226001E1827 /* Release */, 393 | ); 394 | defaultConfigurationIsVisible = 0; 395 | defaultConfigurationName = Release; 396 | }; 397 | AFE86AAD181EB226001E1827 /* Build configuration list for PBXNativeTarget "mac-ble-peripheral-objc-cli" */ = { 398 | isa = XCConfigurationList; 399 | buildConfigurations = ( 400 | AFE86AAE181EB226001E1827 /* Debug */, 401 | AFE86AAF181EB226001E1827 /* Release */, 402 | ); 403 | defaultConfigurationIsVisible = 0; 404 | defaultConfigurationName = Release; 405 | }; 406 | AFE86AB0181EB226001E1827 /* Build configuration list for PBXNativeTarget "mac-ble-peripheral-objc-cliTests" */ = { 407 | isa = XCConfigurationList; 408 | buildConfigurations = ( 409 | AFE86AB1181EB226001E1827 /* Debug */, 410 | AFE86AB2181EB226001E1827 /* Release */, 411 | ); 412 | defaultConfigurationIsVisible = 0; 413 | defaultConfigurationName = Release; 414 | }; 415 | /* End XCConfigurationList section */ 416 | }; 417 | rootObject = AFE86A74181EB226001E1827 /* Project object */; 418 | } 419 | --------------------------------------------------------------------------------