├── 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 |
--------------------------------------------------------------------------------