├── DSBluetooth ├── image │ └── struct.png ├── DSBluetooth │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── 绑定.imageset │ │ │ ├── 绑定@2x.png │ │ │ └── Contents.json │ │ ├── 连接.imageset │ │ │ ├── 连接@2x.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── BindViewController.h │ ├── ViewController.h │ ├── ConnectViewController.h │ ├── AppDelegate.h │ ├── Other │ │ ├── DSSettingCell.h │ │ ├── DSSettingDataSource.h │ │ ├── DSSettingItem.m │ │ ├── DSSettingItem.h │ │ ├── DSSettingCell.m │ │ ├── DSSettingDataSource.m │ │ ├── UIView+Toast.h │ │ └── UIView+Toast.m │ ├── main.m │ ├── DSBluetooth │ │ ├── DSCallback.m │ │ ├── DSBluetoothConfig.h │ │ ├── DSBluetoothConfig.m │ │ ├── DSCallback.h │ │ ├── DSBluetooth.h │ │ └── DSBluetooth.m │ ├── Info.plist │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ ├── AppDelegate.m │ ├── ViewController.m │ ├── BindViewController.m │ └── ConnectViewController.m ├── DSBluetooth.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── project.pbxproj ├── DSBluetoothTests │ ├── Info.plist │ └── DSBluetoothTests.m └── DSBluetoothUITests │ ├── Info.plist │ └── DSBluetoothUITests.m ├── LICENSE ├── .gitignore └── README.md /DSBluetooth/image/struct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloAda/DSBluetooth/HEAD/DSBluetooth/image/struct.png -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Assets.xcassets/绑定.imageset/绑定@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloAda/DSBluetooth/HEAD/DSBluetooth/DSBluetooth/Assets.xcassets/绑定.imageset/绑定@2x.png -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Assets.xcassets/连接.imageset/连接@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/helloAda/DSBluetooth/HEAD/DSBluetooth/DSBluetooth/Assets.xcassets/连接.imageset/连接@2x.png -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/BindViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // BindViewController.h 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/5/7. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BindViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/4/9. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/ConnectViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ConnectViewController.h 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/5/7. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ConnectViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/4/9. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Other/DSSettingCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DSSettingCell.h 3 | // DSSettingDataSource 4 | // 5 | // Created by HelloAda on 2018/4/24. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DSSettingItem.h" 11 | 12 | @interface DSSettingCell : UITableViewCell 13 | 14 | @property (nonatomic, strong) DSSettingItem *item; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/4/9. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Assets.xcassets/绑定.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "绑定@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Assets.xcassets/连接.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "连接@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Other/DSSettingDataSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // DSSettingDataSource.h 3 | // DSSettingDataSource 4 | // 5 | // Created by HelloAda on 2018/4/24. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "DSSettingCell.h" 12 | 13 | @interface DSSettingDataSource : NSObject 14 | 15 | //初始化 16 | - (instancetype)initWithItems:(NSArray *)items; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/DSBluetooth/DSCallback.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSCallback.m 3 | // 4 | // 5 | // Created by HelloAda on 2018/4/2. 6 | // Copyright © 2018年 黄铭达. All rights reserved. 7 | // 8 | 9 | #import "DSCallback.h" 10 | 11 | @implementation DSCallback 12 | 13 | - (instancetype)init 14 | { 15 | self = [super init]; 16 | if (self) { 17 | [self setFilterDiscoverPeripherals:^(CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) { 18 | if (peripheral.name) { 19 | return YES; 20 | } 21 | return NO; 22 | }]; 23 | } 24 | return self; 25 | } 26 | @end 27 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetoothTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetoothUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Other/DSSettingItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSSettingItem.m 3 | // DSSettingDataSource 4 | // 5 | // Created by HelloAda on 2018/4/24. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import "DSSettingItem.h" 10 | 11 | @implementation DSSettingItem 12 | 13 | + (instancetype)itemWithTitle:(NSString *)title icon:(NSString *)icon type:(DSSettingItemType)type { 14 | return [self itemWithTitle:title icon:icon detial:@"" type:type]; 15 | } 16 | 17 | + (instancetype)itemWithTitle:(NSString *)title icon:(NSString *)icon detial:(NSString *)detial type:(DSSettingItemType)type { 18 | DSSettingItem *item = [[DSSettingItem alloc] init]; 19 | item.title = title; 20 | item.icon = icon; 21 | item.type = type; 22 | item.details = detial; 23 | return item; 24 | } 25 | @end 26 | 27 | @implementation DSSettingItems 28 | 29 | - (instancetype)init 30 | { 31 | self = [super init]; 32 | if (self) { 33 | _items = [[NSMutableArray alloc] init]; 34 | } 35 | return self; 36 | } 37 | @end 38 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetoothTests/DSBluetoothTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSBluetoothTests.m 3 | // DSBluetoothTests 4 | // 5 | // Created by HelloAda on 2018/4/9. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DSBluetoothTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation DSBluetoothTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 黄铭达 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /DSBluetooth/DSBluetoothUITests/DSBluetoothUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSBluetoothUITests.m 3 | // DSBluetoothUITests 4 | // 5 | // Created by HelloAda on 2018/4/9. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DSBluetoothUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation DSBluetoothUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | *.DS_Store 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/Preview.html 54 | fastlane/screenshots 55 | fastlane/test_output 56 | 57 | # Code Injection 58 | # 59 | # After new code Injection tools there's a generated folder /iOSInjectionProject 60 | # https://github.com/johnno1962/injectionforxcode 61 | 62 | iOSInjectionProject/ 63 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/DSBluetooth/DSBluetoothConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // DSBluetoothConfig.h 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/4/12. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DSBluetoothConfig : NSObject 12 | 13 | /** 14 | 扫描设备Services参数 15 | scanForPeripheralsWithServices:options: 16 | */ 17 | @property (nonatomic, strong) NSArray *scanForPeripheralsServices; 18 | 19 | /** 20 | 扫描设备options参数 21 | scanForPeripheralsWithServices:options: 22 | */ 23 | @property (nonatomic, strong) NSDictionary *scanForPeripheralsOptions; 24 | 25 | /** 26 | 连接设备option参数 27 | connectPeripheral:options:nil 28 | */ 29 | @property (nonatomic, strong) NSDictionary *connectPeripheralOptions; 30 | 31 | /** 32 | 设备发现指定服务 33 | discoverServices: 34 | */ 35 | @property (nonatomic, strong) NSArray *discoverServices; 36 | 37 | /** 38 | 服务发现指定特征 39 | discoverCharacteristics:forService: 40 | */ 41 | @property (nonatomic, strong) NSArray *discoverCharacteristics; 42 | 43 | #pragma mark --- 初始化方法 --- 44 | 45 | - (instancetype)initWithScanForPeripheralsServices:(NSArray *)scanForPeripheralsServices 46 | discoverServices:(NSArray *)discoverServices 47 | discoverCharacteristics:(NSArray *)discoverCharacteristics; 48 | 49 | - (instancetype)initWithScanForPeripheralsServices:(NSArray *)scanForPeripheralsServices 50 | scanForPeripheralsOptions:(NSDictionary *)scanForPeripheralsOptions 51 | connectPeripheralOptions:(NSDictionary *)connectPeripheralOptions 52 | discoverServices:(NSArray *)discoverServices 53 | discoverCharacteristics:(NSArray *)discoverCharacteristics; 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/DSBluetooth/DSBluetoothConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSBluetoothConfig.m 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/4/12. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import "DSBluetoothConfig.h" 10 | 11 | @implementation DSBluetoothConfig 12 | 13 | - (instancetype)init 14 | { 15 | self = [super init]; 16 | if (self) { 17 | _scanForPeripheralsServices = nil; 18 | _scanForPeripheralsOptions = nil; 19 | _connectPeripheralOptions = nil; 20 | _discoverServices = nil; 21 | _discoverCharacteristics = nil; 22 | } 23 | return self; 24 | } 25 | 26 | 27 | - (instancetype)initWithScanForPeripheralsServices:(NSArray *)scanForPeripheralsServices discoverServices:(NSArray *)discoverServices discoverCharacteristics:(NSArray *)discoverCharacteristics { 28 | self = [self initWithScanForPeripheralsServices:scanForPeripheralsServices scanForPeripheralsOptions:nil connectPeripheralOptions:nil discoverServices:discoverServices discoverCharacteristics:discoverCharacteristics]; 29 | return self; 30 | } 31 | 32 | - (instancetype)initWithScanForPeripheralsServices:(NSArray *)scanForPeripheralsServices scanForPeripheralsOptions:(NSDictionary *)scanForPeripheralsOptions connectPeripheralOptions:(NSDictionary *)connectPeripheralOptions discoverServices:(NSArray *)discoverServices discoverCharacteristics:(NSArray *)discoverCharacteristics { 33 | self = [super init]; 34 | if (self) { 35 | self.scanForPeripheralsServices = scanForPeripheralsServices; 36 | self.scanForPeripheralsOptions = scanForPeripheralsOptions; 37 | self.connectPeripheralOptions = connectPeripheralOptions; 38 | self.discoverServices = discoverServices; 39 | self.discoverCharacteristics = discoverCharacteristics; 40 | } 41 | return self; 42 | } 43 | @end 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 前言 2 | 3 | 写这个库主要是因为`CoreBluetooth`的回调在多个页面的时候不好处理,虽然改用Block形式也是代码量没太多减少,但是逻辑相对来说比较清晰点。 4 | 另外由于时间有限,这个库目前只限于手机作为`Central`端,BLE设备作为`Peripheral`端的一对一的使用,欢迎大家一起完善更多功能。 5 | 如果你才刚接触蓝牙,可以看看[这篇文章](http://helloada.cn/2018/05/05/ios-corebluetooth/),至少能理解与蓝牙交互的整个过程。 6 | 7 | 8 | 9 | ### 简单使用 10 | 11 | 一般来说,在项目中都需要先绑定一个设备然后下次使用的时候,直接能够连接这个设备,就不必在手动选择了。 12 | ``` 13 | DSBluetooth *bluetooth = [DSBluetooth bluetooth]; 14 |    [bluetooth discoverPeripheralWithIdentifier:@"identifier" block:^(CBCentralManager *central, CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) { 15 |    //扫描到设备 to do 绑定等。 16 |    }]; 17 | 18 | //如果有需要配置则要先初始化,然后在开始扫描 19 | //   DSBluetoothConfig *config = [DSBluetoothConfig alloc] initWithScanForPeripheralsServices:nil discoverServices:nil discoverCharacteristics:nil 20 | // [bluetooth configWithIdentifier:@"identifier" config:config]; 21 | 22 |    //切换到这个标记下的Block 23 | [bluetooth switchIdentifier:@"identifier"]; 24 | [bluetooth startScan]; 25 | NSLog(@"标记@"identifier" ,开始扫描"); 26 | 27 | ``` 28 | 29 | 绑定之后连接,就只需要使用这个方法。 30 | ``` 31 | DSBluetooth *bluetooth = [DSBluetooth bluetooth]; 32 | /* 33 | 便利连接 如果有绑定了就直接使用这个比较方便,否则就需要在discoverPeripheralWithIdentifier:block:里面自己调用连接的方法。这里就简单演示一下。 34 | */ 35 | [bluetooth convenientConnectWithIdentifier:@"identifier" filterRules:^BOOL(CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) { 36 |    //筛选 37 |   } success:^{ 38 |      //成功 39 |    } fail:^{ 40 |    //失败 41 |    }]; 42 | [bluetooth switchIdentifier:@"identifier"]; 43 | [bluetooth startScan]; 44 | NSLog(@"标记@"identifier" ,开始扫描"); 45 | ``` 46 | 47 | 更多的使用可以下载Demo进行了解,每个方法都有注释。 48 | 在多个界面使用的时候,只需要添加这个界面独有的identifier在切换过去,这样就解决了多个界面使用的问题,每个标记对应一个独立的callblock。 49 | 50 | ### 大致结构 51 | ![结构](https://github.com/helloAda/DSBluetooth/blob/master/DSBluetooth/image/struct.png) 52 | 53 | 54 | #### 如果觉得对你有帮助,欢迎`Star` 55 | 56 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Other/DSSettingItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // DSSettingItem.h 3 | // DSSettingDataSource 4 | // 5 | // Created by HelloAda on 2018/4/24. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSInteger, DSSettingItemType) { 12 | DSSettingItemTypeDetial, // 显示详情在右边 13 | DSSettingItemTypeArrow, // 显示箭头 14 | DSSettingItemTypeSwitch // 显示Switch 15 | }; 16 | 17 | //Switch回调 18 | typedef void(^SwitchClickBlock)(BOOL on); 19 | 20 | //Cell回调 21 | typedef void(^DidSelectBlock)(void); 22 | 23 | 24 | //每个Cell的数据模型 25 | @interface DSSettingItem : NSObject 26 | 27 | //图标 只支持本地的。 28 | @property (nonatomic, copy) NSString *icon; 29 | 30 | //标题 31 | @property (nonatomic, copy) NSString *title; 32 | 33 | //详情 只有在Detial类型才有效 34 | @property (nonatomic, copy) NSString *details; 35 | 36 | //Cell类型 37 | @property (nonatomic, assign) DSSettingItemType type; 38 | 39 | // 点击Switch事件 40 | @property (nonatomic, copy) SwitchClickBlock switchClick; 41 | 42 | // 点击Cell事件 43 | @property (nonatomic, copy) DidSelectBlock didSelectBlock; 44 | 45 | //Switch状态 默认NO 46 | @property (nonatomic, assign) BOOL isSwitchOn; 47 | 48 | /** 49 | 初始化方法 50 | 51 | @param title 标题 52 | @param icon 图片名称 53 | @param detial 详情(只在Detial类型下才有用) 54 | @param type 类型 55 | @return 实例 56 | */ 57 | + (instancetype)itemWithTitle:(NSString *)title icon:(NSString *)icon detial:(NSString *)detial type:(DSSettingItemType)type; 58 | 59 | //初始化方法 60 | + (instancetype)itemWithTitle:(NSString *)title icon:(NSString *)icon type:(DSSettingItemType)type; 61 | 62 | @end 63 | 64 | 65 | 66 | 67 | //一组Cell的数据模型 68 | @interface DSSettingItems : NSObject 69 | 70 | //Cell模型集合 71 | @property (nonatomic, strong) NSMutableArray *items; 72 | 73 | //组头标题 TableView为Group才有效 74 | @property (nonatomic, copy) NSString *headTitle; 75 | //组尾标题 TableView为Group才有效 76 | @property (nonatomic, copy) NSString *footTitle; 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Other/DSSettingCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSSettingCell.m 3 | // DSSettingDataSource 4 | // 5 | // Created by HelloAda on 2018/4/24. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import "DSSettingCell.h" 10 | 11 | @interface DSSettingCell () 12 | 13 | //switch按钮 14 | @property (nonatomic, strong) UISwitch *switchBtn; 15 | 16 | @end 17 | 18 | @implementation DSSettingCell 19 | 20 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 21 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 22 | if (self) { 23 | self.selectionStyle = UITableViewCellSelectionStyleNone; 24 | } 25 | return self; 26 | } 27 | 28 | - (void)setItem:(DSSettingItem *)item { 29 | _item = item; 30 | self.imageView.image = [UIImage imageNamed:item.icon]; 31 | self.textLabel.text = item.title; 32 | 33 | 34 | switch (item.type) { 35 | case DSSettingItemTypeArrow: { 36 | self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 37 | self.detailTextLabel.text = @""; 38 | self.accessoryView = nil; 39 | } 40 | break; 41 | case DSSettingItemTypeDetial: { 42 | self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 43 | self.detailTextLabel.text = item.details; 44 | self.accessoryView = nil; 45 | } 46 | break; 47 | case DSSettingItemTypeSwitch: { 48 | if (!_switchBtn) { 49 | _switchBtn = [[UISwitch alloc] init]; 50 | _switchBtn.on = item.isSwitchOn; 51 | [_switchBtn addTarget:self action:@selector(switchClickEvent:) forControlEvents:UIControlEventTouchUpInside]; 52 | self.accessoryType = UITableViewCellAccessoryNone; 53 | self.detailTextLabel.text = @""; 54 | self.accessoryView = _switchBtn; 55 | } 56 | } 57 | break; 58 | default: 59 | break; 60 | } 61 | 62 | } 63 | 64 | #pragma mark --- Switch 响应事件 --- 65 | - (void)switchClickEvent:(UISwitch *)switchBtn { 66 | if (self.item.switchClick) { 67 | self.item.switchClick(switchBtn.on); 68 | } 69 | } 70 | @end 71 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/4/9. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | ViewController *vc = [[ViewController alloc] init]; 20 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; 21 | self.window.rootViewController = nav; 22 | return YES; 23 | } 24 | 25 | 26 | - (void)applicationWillResignActive:(UIApplication *)application { 27 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 28 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 29 | } 30 | 31 | 32 | - (void)applicationDidEnterBackground:(UIApplication *)application { 33 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | } 36 | 37 | 38 | - (void)applicationWillEnterForeground:(UIApplication *)application { 39 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 40 | } 41 | 42 | 43 | - (void)applicationDidBecomeActive:(UIApplication *)application { 44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 45 | } 46 | 47 | 48 | - (void)applicationWillTerminate:(UIApplication *)application { 49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 50 | } 51 | 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/4/9. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "DSSettingDataSource.h" 11 | #import "BindViewController.h" 12 | #import "ConnectViewController.h" 13 | #import "DSBluetooth.h" 14 | #import "UIView+Toast.h" 15 | 16 | @interface ViewController () 17 | 18 | @property (nonatomic, strong) UITableView *tableView; 19 | @property (nonatomic, strong) DSSettingDataSource *dataSource; 20 | @property (nonatomic, strong) NSMutableArray *array; 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | [self setupUI]; 28 | } 29 | 30 | 31 | - (void)setupUI { 32 | self.title = @"DSBluetoothDemo"; 33 | self.view.backgroundColor = [UIColor whiteColor]; 34 | _array = [[NSMutableArray alloc] init]; 35 | 36 | { 37 | DSSettingItem *item = [DSSettingItem itemWithTitle:@"绑定设备" icon:@"绑定" type:DSSettingItemTypeArrow]; 38 | item.didSelectBlock = ^{ 39 | if ([DSBluetooth bluetooth].bluetoothIsPoweredOn) { 40 | BindViewController *vc = [[BindViewController alloc] init]; 41 | [self.navigationController pushViewController:vc animated:YES]; 42 | } else { 43 | [self.view makeToast:@"蓝牙未打开" duration:2 position:CSToastPositionCenter]; 44 | } 45 | }; 46 | [_array addObject:item]; 47 | } 48 | { 49 | DSSettingItem *item = [DSSettingItem itemWithTitle:@"连接设备" icon:@"连接" type:DSSettingItemTypeArrow]; 50 | item.didSelectBlock = ^{ 51 | if ([DSBluetooth bluetooth].bluetoothIsPoweredOn) { 52 | ConnectViewController *vc = [[ConnectViewController alloc] init]; 53 | [self.navigationController pushViewController:vc animated:YES]; 54 | } else { 55 | [self.view makeToast:@"蓝牙未打开" duration:2 position:CSToastPositionCenter]; 56 | } 57 | 58 | }; 59 | [_array addObject:item]; 60 | 61 | } 62 | _dataSource = [[DSSettingDataSource alloc] initWithItems:_array]; 63 | 64 | self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 65 | self.tableView.dataSource = _dataSource; 66 | self.tableView.delegate = _dataSource; 67 | [self.view addSubview:self.tableView]; 68 | } 69 | @end 70 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Other/DSSettingDataSource.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSSettingDataSource.m 3 | // DSSettingDataSource 4 | // 5 | // Created by HelloAda on 2018/4/24. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import "DSSettingDataSource.h" 10 | @interface DSSettingDataSource () 11 | 12 | @property (nonatomic, strong) NSArray *items; 13 | 14 | @end 15 | 16 | static NSString *identifier = @"settingCellID"; 17 | 18 | @implementation DSSettingDataSource 19 | 20 | 21 | - (instancetype)initWithItems:(NSArray *)items{ 22 | self = [super init]; 23 | if (self) { 24 | self.items = items; 25 | } 26 | return self; 27 | } 28 | 29 | #pragma mark --- 私有方法 --- 30 | 31 | - (id)itemAtIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableView { 32 | if (tableView.style == UITableViewStyleGrouped) { 33 | DSSettingItems *items = self.items[indexPath.section]; 34 | return items.items[indexPath.row]; 35 | } else { 36 | return self.items[indexPath.row]; 37 | } 38 | } 39 | 40 | 41 | #pragma mark --- UITableViewDataSource 42 | 43 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 44 | if (tableView.style == UITableViewStyleGrouped) { 45 | DSSettingItems *items = self.items[section]; 46 | return items.items.count; 47 | } else { 48 | return self.items.count; 49 | } 50 | } 51 | 52 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 53 | if (tableView.style == UITableViewStyleGrouped) { 54 | return self.items.count; 55 | } else { 56 | return 1; 57 | } 58 | } 59 | 60 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 61 | id item = [self itemAtIndexPath:indexPath tableView:tableView]; 62 | DSSettingCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 63 | if (!cell) { 64 | cell = [[DSSettingCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier]; 65 | } 66 | [cell setItem:item]; 67 | return cell; 68 | } 69 | 70 | #pragma mark --- UITableViewDelegate 71 | 72 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 73 | DSSettingItem *item = [self itemAtIndexPath:indexPath tableView:tableView]; 74 | if (item.didSelectBlock) { 75 | item.didSelectBlock(); 76 | } 77 | } 78 | 79 | 80 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 81 | if (tableView.style == UITableViewStyleGrouped) { 82 | DSSettingItems *items = self.items[section]; 83 | return items.headTitle; 84 | } 85 | return nil; 86 | } 87 | 88 | - (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { 89 | if (tableView.style == UITableViewStyleGrouped) { 90 | DSSettingItems *items = self.items[section]; 91 | return items.footTitle; 92 | } 93 | return nil; 94 | } 95 | @end 96 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/DSBluetooth/DSCallback.h: -------------------------------------------------------------------------------- 1 | // 2 | // DSCallback.h 3 | // 4 | // 5 | // Created by HelloAda on 2018/4/2. 6 | // Copyright © 2018年 黄铭达. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "DSBluetoothConfig.h" 12 | 13 | //蓝牙状态改变 14 | typedef void(^DSCentralManagerStateChange)(CBCentralManager *central); 15 | //扫描到外设 16 | typedef void(^DSDiscoverPeripheralBlock)(CBCentralManager *central, CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI); 17 | //外设连接成功 18 | typedef void(^DSConnectPeripheralBlock)(CBCentralManager *central, CBPeripheral *peripheral); 19 | //外设连接失败 20 | typedef void(^DSFailConnectPeripheralBlock)(CBCentralManager *central, CBPeripheral *peripheral, NSError *error); 21 | //外设连接断开 22 | typedef void(^DSDisconnectPeripheralBlock)(CBCentralManager *central, CBPeripheral *peripheral, NSError *error); 23 | //发现外设服务 24 | typedef void(^DSPeripheralDiscoverServices)(CBPeripheral *peripheral, NSError *error); 25 | //发现外设特征 26 | typedef void(^DSServicesDiscoverCharacteristics)(CBPeripheral *peripheral, CBService *service, NSError *error); 27 | //发现特征描述 28 | typedef void(^DSCharacteristicsDiscoverDescriptor)(CBPeripheral *peripheral, CBCharacteristic *characteristic, NSError *error); 29 | //写入数据在特征时回调(有response才有) 30 | typedef void(^DSWriteValueForCharacteristic)(CBPeripheral *peripheral, CBCharacteristic *characteristic, NSError *error); 31 | //收到特征传来的数据(基本可以说这是唯一拿数据的回调) 32 | typedef void(^DSUpdateValueForCharacteristic)(CBPeripheral *peripheral, CBCharacteristic *characteristic, NSError *error); 33 | //筛选发现到的peripherals规则 34 | typedef BOOL(^DSFilterDiscoverPeripherals)(CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI); 35 | //筛选需要连接的peripherals规则 36 | typedef BOOL(^DSFilterConnectPeripherals)(CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI); 37 | //超时处理 38 | typedef void(^DSTimeoutHandlingBlock)(CBPeripheral *peripheral); 39 | 40 | //便利连接回调 41 | typedef void(^DSConvenientConnectSuccess)(void); 42 | typedef void(^DSConvenientConnectFail)(void); 43 | 44 | //////////////////////////////////////////////////// 45 | 46 | @interface DSCallback : NSObject 47 | 48 | //蓝牙扫描,连接的参数配置 49 | @property (nonatomic, strong) DSBluetoothConfig *config; 50 | /* 51 | 连接后是否直接获取Characteristic 默认为NO 52 | convenientConnectWithIdentifier: filterRules: success: fail: 这个方法里面会设置为YES 53 | */ 54 | @property (nonatomic, assign) BOOL convenientConnect; 55 | 56 | 57 | //// 这些都是为了持有block然后去回调中执行 ///// 58 | 59 | @property (nonatomic, copy) DSCentralManagerStateChange centralManagerStateChange; 60 | @property (nonatomic, copy) DSDiscoverPeripheralBlock discoverPeripheralBlock; 61 | @property (nonatomic, copy) DSConnectPeripheralBlock connectPeripheralBlock; 62 | @property (nonatomic, copy) DSFailConnectPeripheralBlock failConnectPeripheralBlock; 63 | @property (nonatomic, copy) DSDisconnectPeripheralBlock disconnectPeripheralBlock; 64 | @property (nonatomic, copy) DSPeripheralDiscoverServices peripheralDiscoverServices; 65 | @property (nonatomic, copy) DSServicesDiscoverCharacteristics servicesDiscoverCharacteristics; 66 | @property (nonatomic, copy) DSCharacteristicsDiscoverDescriptor characteristicsDiscoverDescriptor; 67 | @property (nonatomic, copy) DSWriteValueForCharacteristic writeValueForCharacteristic; 68 | @property (nonatomic, copy) DSUpdateValueForCharacteristic updateValueForCharacteristic; 69 | @property (nonatomic, copy) DSConvenientConnectSuccess convenientConnectSuccess; 70 | @property (nonatomic, copy) DSConvenientConnectFail convenientConnectFail; 71 | @property (nonatomic, copy) DSFilterDiscoverPeripherals filterDiscoverPeripherals; 72 | @property (nonatomic, copy) DSFilterConnectPeripherals filterConnectPeripherals; 73 | @property (nonatomic, copy) DSTimeoutHandlingBlock timeoutHandlingBlock; 74 | //// 这些都是为了持有block然后去回调中执行 ///// 75 | @end 76 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/BindViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // BindViewController.m 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/5/7. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import "BindViewController.h" 10 | #import "DSBluetooth.h" 11 | #import "UIView+Toast.h" 12 | #define BindVCIdentifier @"BindVcIdentifier" 13 | 14 | @interface BindViewController () 15 | 16 | @property (nonatomic, strong) UITableView *tableView; 17 | @property (nonatomic, strong) NSMutableArray *array; 18 | @property (nonatomic, assign) NSInteger tag; 19 | @end 20 | 21 | @implementation BindViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | _array = [[NSMutableArray alloc] init]; 26 | 27 | self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 28 | self.tableView.dataSource = self; 29 | self.tableView.delegate = self; 30 | [self.view addSubview:self.tableView]; 31 | 32 | [self setupBluetooth]; 33 | } 34 | 35 | - (void)setupBluetooth { 36 | __weak typeof(self) wself = self; 37 | DSBluetooth *bluetooth = [DSBluetooth bluetooth]; 38 | 39 | [bluetooth discoverPeripheralWithIdentifier:BindVCIdentifier block:^(CBCentralManager *central, CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) { 40 | if (peripheral.name) { 41 | wself.tag = 0; 42 | for (NSDictionary *dic in self.array) { 43 | if ([dic objectForKey:@"device"] == peripheral) { 44 | wself.tag = 1; 45 | NSInteger i = [self.array indexOfObject:dic]; 46 | [wself.array replaceObjectAtIndex:i withObject:@{@"rssi" : RSSI ,@"device": peripheral}]; 47 | break; 48 | } 49 | } 50 | if (!(wself.tag)) { 51 | [wself.array addObject:@{@"rssi" : RSSI ,@"device": peripheral}]; 52 | } 53 | [wself.tableView reloadData]; 54 | } 55 | }]; 56 | 57 | //如果有需要配置则要先初始化,然后在开始扫描 58 | // DSBluetoothConfig *config = [DSBluetoothConfig alloc] initWithScanForPeripheralsServices:<#(NSArray *)#> discoverServices:<#(NSArray *)#> discoverCharacteristics:<#(NSArray *)#> 59 | // [bluetooth configWithIdentifier:BindVCIdentifier config:config]; 60 | 61 | //切换到该标示下的Block 62 | [bluetooth switchIdentifier:BindVCIdentifier]; 63 | [bluetooth startScan]; 64 | NSLog(@"标记%@ ,开始扫描", BindVCIdentifier); 65 | } 66 | 67 | 68 | 69 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 70 | return self.array.count; 71 | } 72 | 73 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 74 | { 75 | NSMutableDictionary *dic = self.array[indexPath.row]; 76 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 77 | if (!cell) { 78 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"]; 79 | } 80 | 81 | NSString *deviceName = [(CBPeripheral *)[dic objectForKey:@"device"] name]; 82 | NSInteger rssi = [[dic objectForKey:@"rssi"] integerValue]; 83 | cell.textLabel.text = [NSString stringWithFormat:@"%@,信号:%ld",deviceName,(long)rssi]; 84 | cell.detailTextLabel.text = [(CBPeripheral *)[dic objectForKey:@"device"] description]; 85 | return cell; 86 | } 87 | 88 | 89 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 90 | CBPeripheral *peripheral = [self.array[indexPath.row] objectForKey:@"device"]; 91 | [[NSUserDefaults standardUserDefaults] setObject:peripheral.identifier.UUIDString forKey:@"deviceIdentifier"]; 92 | [[DSBluetooth bluetooth] stopScan]; 93 | [self.view makeToast:@"绑定成功" duration:2 position:CSToastPositionCenter]; 94 | } 95 | @end 96 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/ConnectViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ConnectViewController.m 3 | // DSBluetooth 4 | // 5 | // Created by HelloAda on 2018/5/7. 6 | // Copyright © 2018年 HelloAda. All rights reserved. 7 | // 8 | 9 | #import "ConnectViewController.h" 10 | #import "DSBluetooth.h" 11 | #import "UIView+Toast.h" 12 | 13 | #define ConnectVCIdentifier @"ConnectVCIdentifier" 14 | @interface ConnectViewController () 15 | 16 | @property (nonatomic, strong) UITableView *tableView; 17 | @property (nonatomic, strong) NSMutableArray *array; 18 | @end 19 | 20 | @implementation ConnectViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | if (![[NSUserDefaults standardUserDefaults] objectForKey:@"deviceIdentifier"]) { 25 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"请先绑定设备" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil]; 26 | [alert show]; 27 | } else { 28 | [self setupUI]; 29 | [self setupBluetooth]; 30 | } 31 | } 32 | 33 | 34 | - (void)setupBluetooth { 35 | __weak typeof(self) wself = self; 36 | DSBluetooth *bluetooth = [DSBluetooth bluetooth]; 37 | 38 | /* 39 | 便利连接 如果有绑定了就直接使用这个比较方便,否则就需要在discoverPeripheralWithIdentifier:block:里面自己调用连接的方法。这里就简单演示一下。 40 | */ 41 | [bluetooth convenientConnectWithIdentifier:ConnectVCIdentifier filterRules:^BOOL(CBPeripheral *peripheral, NSDictionary *advertisementData, NSNumber *RSSI) { 42 | if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"deviceIdentifier"] isEqualToString:peripheral.identifier.UUIDString]) { 43 | return YES; 44 | } 45 | return NO; 46 | } success:^{ 47 | [wself.view hideToastActivity]; 48 | [wself.view makeToast:@"连接成功" duration:2 position:CSToastPositionCenter]; 49 | [wself.tableView reloadData]; 50 | 51 | } fail:^{ 52 | [wself.view hideToastActivity]; 53 | [wself.view makeToast:@"连接失败" duration:2 position:CSToastPositionCenter]; 54 | }]; 55 | 56 | [bluetooth servicesDiscoverCharacteristicsWithIdentifier:ConnectVCIdentifier block:^(CBPeripheral *peripheral, CBService *service, NSError *error) { 57 | //一般连接上之后,不会使用这个回调 ,可以通过findCharacteristicFormUUIDString这个方法获取到需要的特征,这里只是为了显示。 58 | NSString *serviceUUID = service.UUID.UUIDString; 59 | NSDictionary *dic = @{serviceUUID : service.characteristics}; 60 | [wself.array addObject:dic]; 61 | }]; 62 | 63 | //如果有需要配置则要先初始化,然后在开始扫描 64 | // DSBluetoothConfig *config = [DSBluetoothConfig alloc] initWithScanForPeripheralsServices:<#(NSArray *)#> discoverServices:<#(NSArray *)#> discoverCharacteristics:<#(NSArray *)#> 65 | // [bluetooth configWithIdentifier:ConnectVCIdentifier config:config]; 66 | 67 | //切换到该标示下的Block 68 | [bluetooth switchIdentifier:ConnectVCIdentifier]; 69 | [bluetooth startScan]; 70 | [self.view makeToastActivity:CSToastPositionCenter]; 71 | NSLog(@"标记%@ ,开始扫描", ConnectVCIdentifier); 72 | } 73 | 74 | 75 | - (void)setupUI { 76 | _array = [[NSMutableArray alloc] init]; 77 | 78 | self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; 79 | self.tableView.dataSource = self; 80 | self.tableView.delegate = self; 81 | [self.view addSubview:self.tableView]; 82 | } 83 | 84 | 85 | 86 | #pragma mark --- tableVeiw 87 | 88 | 89 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 90 | 91 | return self.array.count; 92 | } 93 | 94 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 95 | return [[self.array[section] allValues].firstObject count]; 96 | } 97 | 98 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 99 | CBCharacteristic *characteristic = [self.array[indexPath.section] allValues].firstObject[indexPath.row]; 100 | NSString *cellIdentifier = @"characteristicCell"; 101 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier]; 102 | if (!cell) 103 | { 104 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier]; 105 | } 106 | 107 | cell.textLabel.text = [NSString stringWithFormat:@"%@",characteristic.UUID]; 108 | cell.detailTextLabel.text = characteristic.description; 109 | return cell; 110 | } 111 | 112 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 113 | return [self.array[section] allKeys].firstObject; 114 | } 115 | 116 | #pragma mark -- UIAlertViewDelegate 117 | 118 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 119 | [self.navigationController popViewControllerAnimated:YES]; 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/DSBluetooth/DSBluetooth.h: -------------------------------------------------------------------------------- 1 | // 2 | // DSBluetooth.h 3 | // DSBluetooth 4 | // 5 | // Created by 黄铭达 on 2017/9/27. 6 | // Copyright © 2017年 黄铭达. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DSCallback.h" 11 | 12 | //通知 13 | //蓝牙状态改变时的通知 14 | extern NSNotificationName const DSBluetoothNotificationCentralManagerDidUpdateState; 15 | 16 | //默认标记 17 | #define kDEFAULT_IDENTIFIER @"DSBluetoothDefaultIdentifier" 18 | 19 | @interface DSBluetooth : NSObject 20 | 21 | #pragma mark --- 回调方法 只在单一界面处理 就可以使用这个--- 22 | 23 | //便利连接 24 | - (void)convenientConnectFilterRules:(DSFilterConnectPeripherals)filterRules success:(DSConvenientConnectSuccess)success fail:(DSConvenientConnectFail)fail; 25 | 26 | //蓝牙扫描,连接时的配置参数 详见DSBluetoothConfig 27 | - (void)config:(DSBluetoothConfig *)config; 28 | 29 | //蓝牙状态改变 30 | - (void)centralManagerStateChange:(DSCentralManagerStateChange)block; 31 | 32 | //搜索外设,搜索到外设回调 33 | - (void)discoverPeripheralBlock:(DSDiscoverPeripheralBlock)block; 34 | 35 | //外设连接成功 36 | - (void)connectPeripheralBlock:(DSConnectPeripheralBlock)block; 37 | 38 | //外设连接失败 39 | - (void)failConnectPeripheralBlock:(DSFailConnectPeripheralBlock)block; 40 | 41 | //外设连接断开 42 | - (void)disconnectPeripheralBlock:(DSDisconnectPeripheralBlock)block; 43 | 44 | //发现外设服务 45 | - (void)peripheralDiscoverServices:(DSPeripheralDiscoverServices)block; 46 | 47 | //发现外设特征 48 | - (void)servicesDiscoverCharacteristics:(DSServicesDiscoverCharacteristics)block; 49 | 50 | //发现特征描述 51 | - (void)characteristicsDiscoverDescriptorBlock:(DSCharacteristicsDiscoverDescriptor)block; 52 | 53 | //写入数据到特征 54 | - (void)writeValueForCharacteristic:(DSWriteValueForCharacteristic)block; 55 | 56 | //接收到特征数据 57 | - (void)updateValueForCharacteristic:(DSUpdateValueForCharacteristic)block; 58 | 59 | //筛选发现到的peripherals规则 60 | - (void)filterOnDiscoverPeripherals:(DSFilterDiscoverPeripherals)block; 61 | 62 | //便利连接超时处理 63 | - (void)timeoutHandingBlock:(DSTimeoutHandlingBlock)block; 64 | #pragma mark --- 带标记的回调方法 适用于在不同界面使用 --- 65 | 66 | /** 67 | 便利连接,自动连接到筛选出来的peripheral,并且获取所有Characteristic 68 | 69 | @param identifier block实例的标记 70 | @param filterRules 筛选peripherals的规则 71 | @param success 连接成功 72 | @param fail 连接失败 73 | */ 74 | - (void)convenientConnectWithIdentifier:(NSString *)identifier filterRules:(DSFilterConnectPeripherals)filterRules success:(DSConvenientConnectSuccess)success fail:(DSConvenientConnectFail)fail; 75 | 76 | //蓝牙扫描,连接时的配置参数 详见DSBluetoothConfig 77 | - (void)configWithIdentifier:(NSString *)identifier config:(DSBluetoothConfig *)config; 78 | 79 | //蓝牙状态改变 80 | - (void)centralManagerStateChangeWithIdentifier:(NSString *)identifier block:(DSCentralManagerStateChange)block; 81 | 82 | //搜索外设,搜索到外设回调 83 | - (void)discoverPeripheralWithIdentifier:(NSString *)identifier block:(DSDiscoverPeripheralBlock)block; 84 | 85 | //外设连接成功 86 | - (void)connectPeripheralWithIdentifier:(NSString *)identifier block:(DSConnectPeripheralBlock)block; 87 | 88 | //外设连接失败 89 | - (void)failConnectPeripheralWithIdentifier:(NSString *)identifier block:(DSFailConnectPeripheralBlock)block; 90 | 91 | //外设连接断开 92 | - (void)disconnectPeripheralWithIdentifier:(NSString *)identifier block:(DSDisconnectPeripheralBlock)block; 93 | 94 | //发现外设服务 95 | - (void)peripheralDiscoverServicesWithIdentifier:(NSString *)identifier block:(DSPeripheralDiscoverServices)block; 96 | 97 | //发现外设特征 98 | - (void)servicesDiscoverCharacteristicsWithIdentifier:(NSString *)identifier block:(DSServicesDiscoverCharacteristics)block; 99 | 100 | //发现特征描述 101 | - (void)characteristicsDiscoverDescriptorWithIdentifier:(NSString *)identifier block:(DSCharacteristicsDiscoverDescriptor)block; 102 | 103 | //写入数据到特征 104 | - (void)writeValueForCharacteristicWithIdentifier:(NSString *)identifier block:(DSWriteValueForCharacteristic)block; 105 | 106 | //接收到特征数据 107 | - (void)updateValueForCharacteristicWithIdentifier:(NSString *)identifier block:(DSUpdateValueForCharacteristic)block; 108 | 109 | //筛选发现到的peripherals规则 110 | - (void)filterOnDiscoverPeripheralsWithIdentifier:(NSString *)idebtifier block:(DSFilterDiscoverPeripherals)block; 111 | 112 | //便利连接超时处理 113 | - (void)timeoutHandingWithIdentifier:(NSString *)idebtifier block:(DSTimeoutHandlingBlock)block; 114 | 115 | #pragma mark -- 标记切换用于查找回调block -- 116 | 117 | //标记切换 118 | - (void)switchIdentifier:(NSString *)identifier; 119 | 120 | #pragma mark -- 基本方法 -- 121 | 122 | //单例 123 | + (instancetype)bluetooth; 124 | 125 | //开始扫描 126 | - (void)startScan; 127 | 128 | //停止扫描 129 | - (void)stopScan; 130 | 131 | //连接外设 132 | - (void)connectPeripheral:(CBPeripheral *)peripheral; 133 | 134 | //主动断开当前外设连接 135 | - (void)cancelPeripheralConnect; 136 | 137 | //写入数据到特征值 138 | - (void)writeData:(NSData *)data characteristic:(CBCharacteristic *)characteristic WithResponse:(BOOL)yesOrNo; 139 | 140 | //读取特征值 141 | - (void)readCharacteristic:(CBCharacteristic *)Characteristic; 142 | 143 | //监听特征值 144 | - (void)listenForNotification:(BOOL)isNotify characteristic:(CBCharacteristic *)characteristic; 145 | 146 | //找到对应特征值 147 | - (CBCharacteristic *)findCharacteristicFormUUIDString:(NSString *)UUIDString; 148 | 149 | // 外设的特征值 150 | - (NSMutableArray *)characteristics; 151 | 152 | //蓝牙是否可用 153 | - (BOOL)bluetoothIsPoweredOn; 154 | 155 | //蓝牙管理类 156 | - (CBCentralManager *)centralManager; 157 | 158 | //当前连接设备 159 | - (CBPeripheral *)peripheral; 160 | 161 | //扫描发现的设备集合 连接后清空 162 | - (NSMutableArray *)discoverPeripherals; 163 | @end 164 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Other/UIView+Toast.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Toast.h 3 | // Toast 4 | // 5 | // Copyright (c) 2011-2016 Charles Scalesse. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to 12 | // permit persons to whom the Software is furnished to do so, subject to 13 | // the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | #import 27 | 28 | extern const NSString * CSToastPositionTop; 29 | extern const NSString * CSToastPositionCenter; 30 | extern const NSString * CSToastPositionBottom; 31 | 32 | @class CSToastStyle; 33 | 34 | /** 35 | Toast is an Objective-C category that adds toast notifications to the UIView 36 | object class. It is intended to be simple, lightweight, and easy to use. Most 37 | toast notifications can be triggered with a single line of code. 38 | 39 | The `makeToast:` methods create a new view and then display it as toast. 40 | 41 | The `showToast:` methods display any view as toast. 42 | 43 | */ 44 | @interface UIView (Toast) 45 | 46 | /** 47 | Creates and presents a new toast view with a message and displays it with the 48 | default duration and position. Styled using the shared style. 49 | 50 | @param message The message to be displayed 51 | */ 52 | - (void)makeToast:(NSString *)message; 53 | 54 | /** 55 | Creates and presents a new toast view with a message. Duration and position 56 | can be set explicitly. Styled using the shared style. 57 | 58 | @param message The message to be displayed 59 | @param duration The toast duration 60 | @param position The toast's center point. Can be one of the predefined CSToastPosition 61 | constants or a `CGPoint` wrapped in an `NSValue` object. 62 | */ 63 | - (void)makeToast:(NSString *)message 64 | duration:(NSTimeInterval)duration 65 | position:(id)position; 66 | 67 | /** 68 | Creates and presents a new toast view with a message. Duration, position, and 69 | style can be set explicitly. 70 | 71 | @param message The message to be displayed 72 | @param duration The toast duration 73 | @param position The toast's center point. Can be one of the predefined CSToastPosition 74 | constants or a `CGPoint` wrapped in an `NSValue` object. 75 | @param style The style. The shared style will be used when nil 76 | */ 77 | - (void)makeToast:(NSString *)message 78 | duration:(NSTimeInterval)duration 79 | position:(id)position 80 | style:(CSToastStyle *)style; 81 | 82 | /** 83 | Creates and presents a new toast view with a message, title, and image. Duration, 84 | position, and style can be set explicitly. The completion block executes when the 85 | toast view completes. `didTap` will be `YES` if the toast view was dismissed from 86 | a tap. 87 | 88 | @param message The message to be displayed 89 | @param duration The toast duration 90 | @param position The toast's center point. Can be one of the predefined CSToastPosition 91 | constants or a `CGPoint` wrapped in an `NSValue` object. 92 | @param title The title 93 | @param image The image 94 | @param style The style. The shared style will be used when nil 95 | @param completion The completion block, executed after the toast view disappears. 96 | didTap will be `YES` if the toast view was dismissed from a tap. 97 | */ 98 | - (void)makeToast:(NSString *)message 99 | duration:(NSTimeInterval)duration 100 | position:(id)position 101 | title:(NSString *)title 102 | image:(UIImage *)image 103 | style:(CSToastStyle *)style 104 | completion:(void(^)(BOOL didTap))completion; 105 | 106 | /** 107 | Creates a new toast view with any combination of message, title, and image. 108 | The look and feel is configured via the style. Unlike the `makeToast:` methods, 109 | this method does not present the toast view automatically. One of the showToast: 110 | methods must be used to present the resulting view. 111 | 112 | @warning if message, title, and image are all nil, this method will return nil. 113 | 114 | @param message The message to be displayed 115 | @param title The title 116 | @param image The image 117 | @param style The style. The shared style will be used when nil 118 | @return The newly created toast view 119 | */ 120 | - (UIView *)toastViewForMessage:(NSString *)message 121 | title:(NSString *)title 122 | image:(UIImage *)image 123 | style:(CSToastStyle *)style; 124 | 125 | /** 126 | Dismisses all active toast views. Any toast that is currently being displayed on the 127 | screen is considered active. 128 | 129 | @warning this does not clear toast views that are currently waiting in the queue. The next queued 130 | toast will appear immediately after `hideToasts` completes the dismissal animation. 131 | 132 | */ 133 | - (void)hideToasts; 134 | 135 | /** 136 | Dismisses an active toast view. 137 | 138 | @param toast The active toast view to dismiss. Any toast that is currently being displayed 139 | on the screen is considered active. 140 | 141 | @warning this does not clear a toast view that is currently waiting in the queue. 142 | 143 | */ 144 | - (void)hideToast:(UIView *)toast; 145 | 146 | /** 147 | Creates and displays a new toast activity indicator view at a specified position. 148 | 149 | @warning Only one toast activity indicator view can be presented per superview. Subsequent 150 | calls to `makeToastActivity:` will be ignored until hideToastActivity is called. 151 | 152 | @warning `makeToastActivity:` works independently of the showToast: methods. Toast activity 153 | views can be presented and dismissed while toast views are being displayed. `makeToastActivity:` 154 | has no effect on the queueing behavior of the showToast: methods. 155 | 156 | @param position The toast's center point. Can be one of the predefined CSToastPosition 157 | constants or a `CGPoint` wrapped in an `NSValue` object. 158 | */ 159 | - (void)makeToastActivity:(id)position; 160 | 161 | /** 162 | Dismisses the active toast activity indicator view. 163 | */ 164 | - (void)hideToastActivity; 165 | 166 | /** 167 | Displays any view as toast using the default duration and position. 168 | 169 | @param toast The view to be displayed as toast 170 | */ 171 | - (void)showToast:(UIView *)toast; 172 | 173 | /** 174 | Displays any view as toast at a provided position and duration. The completion block 175 | executes when the toast view completes. `didTap` will be `YES` if the toast view was 176 | dismissed from a tap. 177 | 178 | @param toast The view to be displayed as toast 179 | @param duration The notification duration 180 | @param position The toast's center point. Can be one of the predefined CSToastPosition 181 | constants or a `CGPoint` wrapped in an `NSValue` object. 182 | @param completion The completion block, executed after the toast view disappears. 183 | didTap will be `YES` if the toast view was dismissed from a tap. 184 | */ 185 | - (void)showToast:(UIView *)toast 186 | duration:(NSTimeInterval)duration 187 | position:(id)position 188 | completion:(void(^)(BOOL didTap))completion; 189 | 190 | @end 191 | 192 | /** 193 | `CSToastStyle` instances define the look and feel for toast views created via the 194 | `makeToast:` methods as well for toast views created directly with 195 | `toastViewForMessage:title:image:style:`. 196 | 197 | @warning `CSToastStyle` offers relatively simple styling options for the default 198 | toast view. If you require a toast view with more complex UI, it probably makes more 199 | sense to create your own custom UIView subclass and present it with the `showToast:` 200 | methods. 201 | */ 202 | @interface CSToastStyle : NSObject 203 | 204 | /** 205 | The background color. Default is `[UIColor blackColor]` at 80% opacity. 206 | */ 207 | @property (strong, nonatomic) UIColor *backgroundColor; 208 | 209 | /** 210 | The title color. Default is `[UIColor whiteColor]`. 211 | */ 212 | @property (strong, nonatomic) UIColor *titleColor; 213 | 214 | /** 215 | The message color. Default is `[UIColor whiteColor]`. 216 | */ 217 | @property (strong, nonatomic) UIColor *messageColor; 218 | 219 | /** 220 | A percentage value from 0.0 to 1.0, representing the maximum width of the toast 221 | view relative to it's superview. Default is 0.8 (80% of the superview's width). 222 | */ 223 | @property (assign, nonatomic) CGFloat maxWidthPercentage; 224 | 225 | /** 226 | A percentage value from 0.0 to 1.0, representing the maximum height of the toast 227 | view relative to it's superview. Default is 0.8 (80% of the superview's height). 228 | */ 229 | @property (assign, nonatomic) CGFloat maxHeightPercentage; 230 | 231 | /** 232 | The spacing from the horizontal edge of the toast view to the content. When an image 233 | is present, this is also used as the padding between the image and the text. 234 | Default is 10.0. 235 | */ 236 | @property (assign, nonatomic) CGFloat horizontalPadding; 237 | 238 | /** 239 | The spacing from the vertical edge of the toast view to the content. When a title 240 | is present, this is also used as the padding between the title and the message. 241 | Default is 10.0. 242 | */ 243 | @property (assign, nonatomic) CGFloat verticalPadding; 244 | 245 | /** 246 | The corner radius. Default is 10.0. 247 | */ 248 | @property (assign, nonatomic) CGFloat cornerRadius; 249 | 250 | /** 251 | The title font. Default is `[UIFont boldSystemFontOfSize:16.0]`. 252 | */ 253 | @property (strong, nonatomic) UIFont *titleFont; 254 | 255 | /** 256 | The message font. Default is `[UIFont systemFontOfSize:16.0]`. 257 | */ 258 | @property (strong, nonatomic) UIFont *messageFont; 259 | 260 | /** 261 | The title text alignment. Default is `NSTextAlignmentLeft`. 262 | */ 263 | @property (assign, nonatomic) NSTextAlignment titleAlignment; 264 | 265 | /** 266 | The message text alignment. Default is `NSTextAlignmentLeft`. 267 | */ 268 | @property (assign, nonatomic) NSTextAlignment messageAlignment; 269 | 270 | /** 271 | The maximum number of lines for the title. The default is 0 (no limit). 272 | */ 273 | @property (assign, nonatomic) NSInteger titleNumberOfLines; 274 | 275 | /** 276 | The maximum number of lines for the message. The default is 0 (no limit). 277 | */ 278 | @property (assign, nonatomic) NSInteger messageNumberOfLines; 279 | 280 | /** 281 | Enable or disable a shadow on the toast view. Default is `NO`. 282 | */ 283 | @property (assign, nonatomic) BOOL displayShadow; 284 | 285 | /** 286 | The shadow color. Default is `[UIColor blackColor]`. 287 | */ 288 | @property (strong, nonatomic) UIColor *shadowColor; 289 | 290 | /** 291 | A value from 0.0 to 1.0, representing the opacity of the shadow. 292 | Default is 0.8 (80% opacity). 293 | */ 294 | @property (assign, nonatomic) CGFloat shadowOpacity; 295 | 296 | /** 297 | The shadow radius. Default is 6.0. 298 | */ 299 | @property (assign, nonatomic) CGFloat shadowRadius; 300 | 301 | /** 302 | The shadow offset. The default is `CGSizeMake(4.0, 4.0)`. 303 | */ 304 | @property (assign, nonatomic) CGSize shadowOffset; 305 | 306 | /** 307 | The image size. The default is `CGSizeMake(80.0, 80.0)`. 308 | */ 309 | @property (assign, nonatomic) CGSize imageSize; 310 | 311 | /** 312 | The size of the toast activity view when `makeToastActivity:` is called. 313 | Default is `CGSizeMake(100.0, 100.0)`. 314 | */ 315 | @property (assign, nonatomic) CGSize activitySize; 316 | 317 | /** 318 | The fade in/out animation duration. Default is 0.2. 319 | */ 320 | @property (assign, nonatomic) NSTimeInterval fadeDuration; 321 | 322 | /** 323 | Creates a new instance of `CSToastStyle` with all the default values set. 324 | */ 325 | - (instancetype)initWithDefaultStyle NS_DESIGNATED_INITIALIZER; 326 | 327 | /** 328 | @warning Only the designated initializer should be used to create 329 | an instance of `CSToastStyle`. 330 | */ 331 | - (instancetype)init NS_UNAVAILABLE; 332 | 333 | @end 334 | 335 | /** 336 | `CSToastManager` provides general configuration options for all toast 337 | notifications. Backed by a singleton instance. 338 | */ 339 | @interface CSToastManager : NSObject 340 | 341 | /** 342 | Sets the shared style on the singleton. The shared style is used whenever 343 | a `makeToast:` method (or `toastViewForMessage:title:image:style:`) is called 344 | with with a nil style. By default, this is set to `CSToastStyle`'s default 345 | style. 346 | 347 | @param sharedStyle the shared style 348 | */ 349 | + (void)setSharedStyle:(CSToastStyle *)sharedStyle; 350 | 351 | /** 352 | Gets the shared style from the singlton. By default, this is 353 | `CSToastStyle`'s default style. 354 | 355 | @return the shared style 356 | */ 357 | + (CSToastStyle *)sharedStyle; 358 | 359 | /** 360 | Enables or disables tap to dismiss on toast views. Default is `YES`. 361 | 362 | @param tapToDismissEnabled YES or NO 363 | */ 364 | + (void)setTapToDismissEnabled:(BOOL)tapToDismissEnabled; 365 | 366 | /** 367 | Returns `YES` if tap to dismiss is enabled, otherwise `NO`. 368 | Default is `YES`. 369 | 370 | @return BOOL YES or NO 371 | */ 372 | + (BOOL)isTapToDismissEnabled; 373 | 374 | /** 375 | Enables or disables queueing behavior for toast views. When `YES`, 376 | toast views will appear one after the other. When `NO`, multiple Toast 377 | views will appear at the same time (potentially overlapping depending 378 | on their positions). This has no effect on the toast activity view, 379 | which operates independently of normal toast views. Default is `YES`. 380 | 381 | @param queueEnabled YES or NO 382 | */ 383 | + (void)setQueueEnabled:(BOOL)queueEnabled; 384 | 385 | /** 386 | Returns `YES` if the queue is enabled, otherwise `NO`. 387 | Default is `YES`. 388 | 389 | @return BOOL 390 | */ 391 | + (BOOL)isQueueEnabled; 392 | 393 | /** 394 | Sets the default duration. Used for the `makeToast:` and 395 | `showToast:` methods that don't require an explicit duration. 396 | Default is 3.0. 397 | 398 | @param duration The toast duration 399 | */ 400 | + (void)setDefaultDuration:(NSTimeInterval)duration; 401 | 402 | /** 403 | Returns the default duration. Default is 3.0. 404 | 405 | @return duration The toast duration 406 | */ 407 | + (NSTimeInterval)defaultDuration; 408 | 409 | /** 410 | Sets the default position. Used for the `makeToast:` and 411 | `showToast:` methods that don't require an explicit position. 412 | Default is `CSToastPositionBottom`. 413 | 414 | @param position The default center point. Can be one of the predefined 415 | CSToastPosition constants or a `CGPoint` wrapped in an `NSValue` object. 416 | */ 417 | + (void)setDefaultPosition:(id)position; 418 | 419 | /** 420 | Returns the default toast position. Default is `CSToastPositionBottom`. 421 | 422 | @return position The default center point. Will be one of the predefined 423 | CSToastPosition constants or a `CGPoint` wrapped in an `NSValue` object. 424 | */ 425 | + (id)defaultPosition; 426 | 427 | @end 428 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/DSBluetooth/DSBluetooth.m: -------------------------------------------------------------------------------- 1 | // 2 | // DSBluetooth.m 3 | // DSBluetooth 4 | // 5 | // Created by 黄铭达 on 2017/9/27. 6 | // Copyright © 2017年 黄铭达. All rights reserved. 7 | // 8 | 9 | #import "DSBluetooth.h" 10 | 11 | NSNotificationName const DSBluetoothNotificationCentralManagerDidUpdateState = @"DSBluetoothNotificationCentralManagerDidUpdateState"; 12 | 13 | @interface DSBluetooth () 14 | { 15 | NSInteger numOfServices; // 服务的数量,用来判断特征是否全部加载完成 16 | NSMutableArray *discoverPeripherals; //发现的设备 -- 这里如果没有强引用peripheral会被释放 17 | } 18 | 19 | //主设备 (该项目为手机) 20 | @property (nonatomic, strong) CBCentralManager *centralManager; 21 | //外设 22 | @property (nonatomic, strong) CBPeripheral *peripheral; 23 | //外设的特征值 24 | @property (nonatomic, strong) NSMutableArray *characteristics; 25 | //标记 用来标记该使用哪个DSCallback实例去回调block 26 | @property (nonatomic, strong) NSMutableDictionary *identifiers; 27 | // 当前的标记 28 | @property (nonatomic, copy) NSString *currentIdentifier; 29 | //定时器 默认10s 30 | @property (nonatomic, strong) NSTimer *timer; 31 | @end 32 | 33 | @implementation DSBluetooth 34 | 35 | + (instancetype)bluetooth { 36 | static DSBluetooth *instance; 37 | static dispatch_once_t onceToken; 38 | dispatch_once(&onceToken, ^{ 39 | instance = [[DSBluetooth alloc] init]; 40 | }); 41 | return instance; 42 | } 43 | 44 | - (instancetype)init 45 | { 46 | self = [super init]; 47 | if (self) { 48 | _centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil]; 49 | _characteristics = [[NSMutableArray alloc] init]; 50 | 51 | //构建默认标记的回调对象 52 | _identifiers = [[NSMutableDictionary alloc] init]; 53 | _currentIdentifier = kDEFAULT_IDENTIFIER; 54 | DSCallback *defaultCallback = [[DSCallback alloc] init]; 55 | [_identifiers setObject:defaultCallback forKey:_currentIdentifier]; 56 | 57 | discoverPeripherals = [[NSMutableArray alloc] init]; 58 | } 59 | return self; 60 | } 61 | 62 | #pragma mark ----- 对外接口 ----- 63 | 64 | - (void)startScan { 65 | NSArray *services = [self currentCallback].config.scanForPeripheralsServices; 66 | NSDictionary *options = [self currentCallback].config.scanForPeripheralsOptions; 67 | [self.centralManager scanForPeripheralsWithServices:services options:options]; 68 | } 69 | 70 | - (void)stopScan { 71 | [self.centralManager stopScan]; 72 | } 73 | 74 | - (void)connectPeripheral:(CBPeripheral *)peripheral { 75 | NSDictionary *options = [self currentCallback].config.connectPeripheralOptions; 76 | [self.centralManager connectPeripheral:peripheral options:options]; 77 | } 78 | 79 | - (void)cancelPeripheralConnect { 80 | if (self.peripheral) { 81 | [self.centralManager cancelPeripheralConnection:self.peripheral]; 82 | } 83 | } 84 | 85 | - (void)writeData:(NSData *)data characteristic:(CBCharacteristic *)characteristic WithResponse:(BOOL)yesOrNo { 86 | if (!self.peripheral || !characteristic) return; 87 | if (yesOrNo) { 88 | [self.peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse]; 89 | } else { 90 | [self.peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse]; 91 | } 92 | } 93 | 94 | - (void)readCharacteristic:(CBCharacteristic *)characteristic { 95 | if (self.peripheral && characteristic) { 96 | [self.peripheral readValueForCharacteristic:characteristic]; 97 | } 98 | } 99 | 100 | - (void)listenForNotification:(BOOL)isNotify characteristic:(CBCharacteristic *)characteristic { 101 | if (self.peripheral && characteristic) { 102 | [self.peripheral setNotifyValue:isNotify forCharacteristic:characteristic]; 103 | } 104 | } 105 | 106 | - (CBCharacteristic *)findCharacteristicFormUUIDString:(NSString *)UUIDString { 107 | for (CBCharacteristic *c in self.characteristics) { 108 | if ([c.UUID.UUIDString isEqualToString:UUIDString]) { 109 | return c; 110 | } 111 | } 112 | return nil; 113 | } 114 | 115 | - (NSMutableArray *)characteristics { 116 | return _characteristics; 117 | } 118 | 119 | - (BOOL)bluetoothIsPoweredOn { 120 | if (self.centralManager.state == CBCentralManagerStatePoweredOn) { 121 | return YES; 122 | } 123 | return NO; 124 | } 125 | 126 | - (CBCentralManager *)centralManager { 127 | return _centralManager; 128 | } 129 | 130 | - (CBPeripheral *)peripheral { 131 | return _peripheral; 132 | } 133 | 134 | - (NSMutableArray *)discoverPeripherals { 135 | return discoverPeripherals; 136 | } 137 | 138 | #pragma mark --- CBCentralManagerDelegate 主设备相关代理 139 | 140 | //蓝牙状态改变时 141 | - (void)centralManagerDidUpdateState:(CBCentralManager *)central { 142 | 143 | NSNotification *notification = [NSNotification notificationWithName:DSBluetoothNotificationCentralManagerDidUpdateState object:@{@"central" : central}]; 144 | [[NSNotificationCenter defaultCenter] postNotification:notification]; 145 | 146 | if ([self currentCallback].centralManagerStateChange) { 147 | [self currentCallback].centralManagerStateChange(central); 148 | } 149 | } 150 | 151 | /** 152 | 发现外设回调 153 | 154 | @param central 蓝牙管理对象 155 | @param peripheral 外设 156 | @param advertisementData 外设携带信息 157 | @param RSSI 外设信号强度 158 | */ 159 | - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { 160 | 161 | //需要强引用 否则会被释放掉 162 | if (![discoverPeripherals containsObject:peripheral]) { 163 | [discoverPeripherals addObject:peripheral]; 164 | } 165 | //扫描发现设备callback 166 | if ([[self currentCallback] filterDiscoverPeripherals]) { 167 | if([[self currentCallback] filterDiscoverPeripherals](peripheral, advertisementData, RSSI)) { 168 | if ([self currentCallback].discoverPeripheralBlock) { 169 | [self currentCallback].discoverPeripheralBlock(central,peripheral,advertisementData,RSSI); 170 | } 171 | } 172 | } 173 | 174 | //便利连接处理 175 | if ([[self currentCallback] filterConnectPeripherals]) { 176 | if([[self currentCallback] filterConnectPeripherals](peripheral, advertisementData, RSSI)) { 177 | [self connectPeripheral:peripheral]; 178 | //判断超时 179 | _timer = [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(timeoutHandling:) userInfo:nil repeats:NO]; 180 | } 181 | } 182 | 183 | 184 | } 185 | 186 | //设备连接成功 187 | - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { 188 | [_timer invalidate];//停止超时判断 189 | [self stopScan]; 190 | self.peripheral = peripheral; 191 | self.peripheral.delegate = self; 192 | //已经强引用了需要的设备 可以移除了 193 | [discoverPeripherals removeAllObjects]; 194 | if ([self currentCallback].connectPeripheralBlock) { 195 | [self currentCallback].connectPeripheralBlock(central, peripheral); 196 | } 197 | if ([self currentCallback].convenientConnect) { 198 | //寻找服务 199 | NSArray *services = [self currentCallback].config.discoverServices; 200 | [self.peripheral discoverServices:services]; 201 | } 202 | } 203 | 204 | //设备连接失败 205 | - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { 206 | if ([self currentCallback].failConnectPeripheralBlock) { 207 | [self currentCallback].failConnectPeripheralBlock(central, peripheral, error); 208 | } 209 | if ([self currentCallback].convenientConnect && [self callback].convenientConnectFail) { 210 | [self currentCallback].convenientConnectFail(); 211 | } 212 | } 213 | 214 | //断开链接时(主动断开||其他因素断开) 215 | - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { 216 | self.peripheral = nil; 217 | [_characteristics removeAllObjects]; 218 | if ([self currentCallback].disconnectPeripheralBlock) { 219 | [self currentCallback].disconnectPeripheralBlock(central, peripheral, error); 220 | } 221 | } 222 | 223 | 224 | /////////////////////////////////////////////////////////////////////// 225 | 226 | 227 | #pragma mark --- CBPeripheralDelegate 外设相关代理 228 | 229 | //发现外设的服务 230 | - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error { 231 | if ([self currentCallback].peripheralDiscoverServices) { 232 | [self currentCallback].peripheralDiscoverServices(peripheral, error); 233 | } 234 | if ([self currentCallback].convenientConnect) { 235 | numOfServices = peripheral.services.count; 236 | for (CBService *service in peripheral.services) { 237 | //寻找该服务下特征 238 | NSArray *characteristics = [self currentCallback].config.discoverCharacteristics; 239 | [self.peripheral discoverCharacteristics:characteristics forService:service]; 240 | } 241 | } 242 | } 243 | 244 | //发现外设的特征 245 | - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { 246 | if ([self currentCallback].servicesDiscoverCharacteristics) { 247 | [self currentCallback].servicesDiscoverCharacteristics(peripheral, service, error); 248 | } 249 | if ([self currentCallback].convenientConnect) { 250 | numOfServices--; 251 | //将搜索到的特征加入特征数组,提供给后续使用 252 | for (CBCharacteristic *characteristic in service.characteristics) { 253 | [self.characteristics addObject:characteristic]; 254 | } 255 | //每个服务下的特征都加载完毕了 256 | if (numOfServices == 0 && [self currentCallback].convenientConnectSuccess) { 257 | [self currentCallback].convenientConnectSuccess(); 258 | } 259 | } 260 | } 261 | 262 | //发现Characteristics的Descriptors 263 | - (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error { 264 | if ([self currentCallback].characteristicsDiscoverDescriptor) { 265 | [self currentCallback].characteristicsDiscoverDescriptor(peripheral, characteristic, error); 266 | } 267 | } 268 | 269 | //写入数据到特征时回调 270 | - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { 271 | if ([self currentCallback].writeValueForCharacteristic) { 272 | [self currentCallback].writeValueForCharacteristic(peripheral, characteristic, error); 273 | } 274 | } 275 | 276 | //外设特征数据改变时会回调这个方法(蓝牙传过来的数据都会走这里) 277 | - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { 278 | if ([self currentCallback].updateValueForCharacteristic) { 279 | [self currentCallback].updateValueForCharacteristic(peripheral, characteristic, error); 280 | } 281 | } 282 | 283 | 284 | #pragma mark --- 回调方法 只在单一界面处理 就可以使用这个--- 285 | 286 | //便利连接 287 | - (void)convenientConnectFilterRules:(DSFilterConnectPeripherals)filterRules success:(DSConvenientConnectSuccess)success fail:(DSConvenientConnectFail)fail { 288 | [self callback].filterConnectPeripherals = filterRules; 289 | [self callback].convenientConnectSuccess = success; 290 | [self callback].convenientConnectFail = fail; 291 | [self callback].convenientConnect = YES; 292 | } 293 | 294 | //蓝牙扫描,连接时的配置参数 详见DSBluetoothConfig 295 | - (void)config:(DSBluetoothConfig *)config { 296 | [self callback].config = config; 297 | } 298 | //蓝牙状态改变 299 | - (void)centralManagerStateChange:(DSCentralManagerStateChange)block { 300 | [self callback].centralManagerStateChange = block; 301 | } 302 | 303 | //搜索到外设 304 | - (void)discoverPeripheralBlock:(DSDiscoverPeripheralBlock)block { 305 | [self callback].discoverPeripheralBlock = block; 306 | } 307 | 308 | //外设连接成功 309 | - (void)connectPeripheralBlock:(DSConnectPeripheralBlock)block { 310 | [self callback].connectPeripheralBlock = block; 311 | } 312 | 313 | //外设连接失败 314 | - (void)failConnectPeripheralBlock:(DSFailConnectPeripheralBlock)block { 315 | [self callback].failConnectPeripheralBlock = block; 316 | } 317 | 318 | //外设连接断开 319 | - (void)disconnectPeripheralBlock:(DSDisconnectPeripheralBlock)block { 320 | [self callback].disconnectPeripheralBlock = block; 321 | } 322 | 323 | //发现外设服务 324 | - (void)peripheralDiscoverServices:(DSPeripheralDiscoverServices)block { 325 | [self callback].peripheralDiscoverServices = block; 326 | } 327 | 328 | //发现外设特征 329 | - (void)servicesDiscoverCharacteristics:(DSServicesDiscoverCharacteristics)block { 330 | [self callback].servicesDiscoverCharacteristics = block; 331 | } 332 | 333 | //发现特征描述 334 | 335 | - (void)characteristicsDiscoverDescriptorBlock:(DSCharacteristicsDiscoverDescriptor)block { 336 | [self callback].characteristicsDiscoverDescriptor = block; 337 | } 338 | 339 | //写入数据到特征 340 | - (void)writeValueForCharacteristic:(DSWriteValueForCharacteristic)block { 341 | [self callback].writeValueForCharacteristic = block; 342 | } 343 | 344 | //接收到特征数据 345 | - (void)updateValueForCharacteristic:(DSUpdateValueForCharacteristic)block { 346 | [self callback].updateValueForCharacteristic = block; 347 | } 348 | 349 | //筛选发现到的peripherals规则 350 | - (void)filterOnDiscoverPeripherals:(DSFilterDiscoverPeripherals)block { 351 | [self callback].filterDiscoverPeripherals = block; 352 | } 353 | 354 | - (void)timeoutHandingBlock:(DSTimeoutHandlingBlock)block { 355 | [self callback].timeoutHandlingBlock = block; 356 | } 357 | 358 | #pragma mark --- 带标记的回调方法 适用于在不同界面使用 --- 359 | 360 | //便利连接 361 | - (void)convenientConnectWithIdentifier:(NSString *)identifier filterRules:(DSFilterConnectPeripherals)filterRules success:(DSConvenientConnectSuccess)success fail:(DSConvenientConnectFail)fail { 362 | [self callbackWithIdentifier:identifier].filterConnectPeripherals = filterRules; 363 | [self callbackWithIdentifier:identifier].convenientConnectSuccess = success; 364 | [self callbackWithIdentifier:identifier].convenientConnectFail = fail; 365 | [self callbackWithIdentifier:identifier].convenientConnect = YES; 366 | } 367 | 368 | //蓝牙扫描,连接时的配置参数 369 | - (void)configWithIdentifier:(NSString *)identifier config:(DSBluetoothConfig *)config { 370 | [self callbackWithIdentifier:identifier].config = config; 371 | } 372 | 373 | //蓝牙状态改变 374 | - (void)centralManagerStateChangeWithIdentifier:(NSString *)identifier block:(DSCentralManagerStateChange)block { 375 | [self callbackWithIdentifier:identifier].centralManagerStateChange = block; 376 | } 377 | 378 | //搜索外设,搜索到外设回调 379 | - (void)discoverPeripheralWithIdentifier:(NSString *)identifier block:(DSDiscoverPeripheralBlock)block { 380 | [self callbackWithIdentifier:identifier].discoverPeripheralBlock = block; 381 | } 382 | 383 | //外设连接成功 384 | - (void)connectPeripheralWithIdentifier:(NSString *)identifier block:(DSConnectPeripheralBlock)block { 385 | [self callbackWithIdentifier:identifier].connectPeripheralBlock = block; 386 | } 387 | 388 | //外设连接失败 389 | - (void)failConnectPeripheralWithIdentifier:(NSString *)identifier block:(DSFailConnectPeripheralBlock)block { 390 | [self callbackWithIdentifier:identifier].failConnectPeripheralBlock = block; 391 | } 392 | 393 | //外设连接断开 394 | - (void)disconnectPeripheralWithIdentifier:(NSString *)identifier block:(DSDisconnectPeripheralBlock)block { 395 | [self callbackWithIdentifier:identifier].disconnectPeripheralBlock = block; 396 | } 397 | 398 | //发现外设服务 399 | - (void)peripheralDiscoverServicesWithIdentifier:(NSString *)identifier block:(DSPeripheralDiscoverServices)block { 400 | [self callbackWithIdentifier:identifier].peripheralDiscoverServices = block; 401 | } 402 | 403 | //发现外设特征 404 | - (void)servicesDiscoverCharacteristicsWithIdentifier:(NSString *)identifier block:(DSServicesDiscoverCharacteristics)block { 405 | [self callbackWithIdentifier:identifier].servicesDiscoverCharacteristics = block; 406 | } 407 | 408 | //发现特征描述 409 | - (void)characteristicsDiscoverDescriptorWithIdentifier:(NSString *)identifier block:(DSCharacteristicsDiscoverDescriptor)block { 410 | [self callbackWithIdentifier:identifier].characteristicsDiscoverDescriptor = block; 411 | 412 | } 413 | 414 | //写入数据到特征 415 | - (void)writeValueForCharacteristicWithIdentifier:(NSString *)identifier block:(DSWriteValueForCharacteristic)block { 416 | [self callbackWithIdentifier:identifier].writeValueForCharacteristic = block; 417 | } 418 | 419 | //接收到特征数据 420 | - (void)updateValueForCharacteristicWithIdentifier:(NSString *)identifier block:(DSUpdateValueForCharacteristic)block { 421 | [self callbackWithIdentifier:identifier].updateValueForCharacteristic = block; 422 | } 423 | 424 | //筛选发现到的peripherals规则 425 | - (void)filterOnDiscoverPeripheralsWithIdentifier:(NSString *)idebtifier block:(DSFilterDiscoverPeripherals)block { 426 | [self callbackWithIdentifier:idebtifier].filterDiscoverPeripherals = block; 427 | } 428 | 429 | //超时处理 430 | - (void)timeoutHandingWithIdentifier:(NSString *)idebtifier block:(DSTimeoutHandlingBlock)block { 431 | [self callbackWithIdentifier:idebtifier].timeoutHandlingBlock = block; 432 | } 433 | #pragma mark -- 标记切换 查找回调block -- 434 | 435 | - (void)switchIdentifier:(NSString *)identifier { 436 | if (identifier) { 437 | if ([_identifiers objectForKey:identifier]) { 438 | //切换成功 439 | _currentIdentifier = identifier; 440 | } else { 441 | //没有对应的标记 442 | } 443 | } else { 444 | //传nil则切换到默认标记 445 | _currentIdentifier = kDEFAULT_IDENTIFIER; 446 | } 447 | } 448 | 449 | //默认标记对应的callback 450 | - (DSCallback *)callback { 451 | DSCallback *callback = [_identifiers objectForKey:kDEFAULT_IDENTIFIER]; 452 | return callback; 453 | } 454 | 455 | //找到当前标记对应的callback 456 | - (DSCallback *)currentCallback { 457 | DSCallback *callback = [_identifiers objectForKey:_currentIdentifier]; 458 | return callback; 459 | } 460 | 461 | //找到标记对应的callback 没有则新增 462 | - (DSCallback *)callbackWithIdentifier:(NSString *)identifier { 463 | DSCallback *callback = [_identifiers objectForKey:identifier]; 464 | if (!callback) { 465 | callback = [[DSCallback alloc] init]; 466 | [_identifiers setObject:callback forKey:identifier]; 467 | } 468 | return callback; 469 | } 470 | 471 | #pragma mark --- 超时处理 472 | 473 | - (void)timeoutHandling:(CBPeripheral *)perioheral { 474 | [_timer invalidate]; 475 | [self stopScan]; 476 | [self currentCallback].timeoutHandlingBlock(perioheral); 477 | } 478 | @end 479 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth/Other/UIView+Toast.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Toast.m 3 | // Toast 4 | // 5 | // Copyright (c) 2011-2016 Charles Scalesse. 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the 9 | // "Software"), to deal in the Software without restriction, including 10 | // without limitation the rights to use, copy, modify, merge, publish, 11 | // distribute, sublicense, and/or sell copies of the Software, and to 12 | // permit persons to whom the Software is furnished to do so, subject to 13 | // the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included 16 | // in all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | #import "UIView+Toast.h" 27 | #import 28 | #import 29 | 30 | NSString * CSToastPositionTop = @"CSToastPositionTop"; 31 | NSString * CSToastPositionCenter = @"CSToastPositionCenter"; 32 | NSString * CSToastPositionBottom = @"CSToastPositionBottom"; 33 | 34 | // Keys for values associated with toast views 35 | static const NSString * CSToastTimerKey = @"CSToastTimerKey"; 36 | static const NSString * CSToastDurationKey = @"CSToastDurationKey"; 37 | static const NSString * CSToastPositionKey = @"CSToastPositionKey"; 38 | static const NSString * CSToastCompletionKey = @"CSToastCompletionKey"; 39 | 40 | // Keys for values associated with self 41 | static const NSString * CSToastActiveKey = @"CSToastActiveKey"; 42 | static const NSString * CSToastActivityViewKey = @"CSToastActivityViewKey"; 43 | static const NSString * CSToastQueueKey = @"CSToastQueueKey"; 44 | 45 | @interface UIView (ToastPrivate) 46 | 47 | /** 48 | These private methods are being prefixed with "cs_" to reduce the likelihood of non-obvious 49 | naming conflicts with other UIView methods. 50 | 51 | @discussion Should the public API also use the cs_ prefix? Technically it should, but it 52 | results in code that is less legible. The current public method names seem unlikely to cause 53 | conflicts so I think we should favor the cleaner API for now. 54 | */ 55 | - (void)cs_showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position; 56 | - (void)cs_hideToast:(UIView *)toast; 57 | - (void)cs_hideToast:(UIView *)toast fromTap:(BOOL)fromTap; 58 | - (void)cs_toastTimerDidFinish:(NSTimer *)timer; 59 | - (void)cs_handleToastTapped:(UITapGestureRecognizer *)recognizer; 60 | - (CGPoint)cs_centerPointForPosition:(id)position withToast:(UIView *)toast; 61 | - (NSMutableArray *)cs_toastQueue; 62 | 63 | @end 64 | 65 | @implementation UIView (Toast) 66 | 67 | #pragma mark - Make Toast Methods 68 | 69 | - (void)makeToast:(NSString *)message { 70 | [self makeToast:message duration:[CSToastManager defaultDuration] position:[CSToastManager defaultPosition] style:nil]; 71 | } 72 | 73 | - (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position { 74 | [self makeToast:message duration:duration position:position style:nil]; 75 | } 76 | 77 | - (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position style:(CSToastStyle *)style { 78 | UIView *toast = [self toastViewForMessage:message title:nil image:nil style:style]; 79 | [self showToast:toast duration:duration position:position completion:nil]; 80 | } 81 | 82 | - (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position title:(NSString *)title image:(UIImage *)image style:(CSToastStyle *)style completion:(void(^)(BOOL didTap))completion { 83 | UIView *toast = [self toastViewForMessage:message title:title image:image style:style]; 84 | [self showToast:toast duration:duration position:position completion:completion]; 85 | } 86 | 87 | #pragma mark - Show Toast Methods 88 | 89 | - (void)showToast:(UIView *)toast { 90 | [self showToast:toast duration:[CSToastManager defaultDuration] position:[CSToastManager defaultPosition] completion:nil]; 91 | } 92 | 93 | - (void)showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position completion:(void(^)(BOOL didTap))completion { 94 | // sanity 95 | if (toast == nil) return; 96 | 97 | // store the completion block on the toast view 98 | objc_setAssociatedObject(toast, &CSToastCompletionKey, completion, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 99 | 100 | if ([CSToastManager isQueueEnabled] && [self.cs_activeToasts count] > 0) { 101 | // we're about to queue this toast view so we need to store the duration and position as well 102 | objc_setAssociatedObject(toast, &CSToastDurationKey, @(duration), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 103 | objc_setAssociatedObject(toast, &CSToastPositionKey, position, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 104 | 105 | // enqueue 106 | [self.cs_toastQueue addObject:toast]; 107 | } else { 108 | // present 109 | [self cs_showToast:toast duration:duration position:position]; 110 | } 111 | } 112 | 113 | #pragma mark - Hide Toast Method 114 | 115 | - (void)hideToasts { 116 | for (UIView *toast in [self cs_activeToasts]) { 117 | [self hideToast:toast]; 118 | } 119 | } 120 | 121 | - (void)hideToast:(UIView *)toast { 122 | // sanity 123 | if (!toast || ![[self cs_activeToasts] containsObject:toast]) return; 124 | 125 | NSTimer *timer = (NSTimer *)objc_getAssociatedObject(toast, &CSToastTimerKey); 126 | [timer invalidate]; 127 | 128 | [self cs_hideToast:toast]; 129 | } 130 | 131 | #pragma mark - Private Show/Hide Methods 132 | 133 | - (void)cs_showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position { 134 | toast.center = [self cs_centerPointForPosition:position withToast:toast]; 135 | toast.alpha = 0.0; 136 | 137 | if ([CSToastManager isTapToDismissEnabled]) { 138 | UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cs_handleToastTapped:)]; 139 | [toast addGestureRecognizer:recognizer]; 140 | toast.userInteractionEnabled = YES; 141 | toast.exclusiveTouch = YES; 142 | } 143 | 144 | [[self cs_activeToasts] addObject:toast]; 145 | 146 | [self addSubview:toast]; 147 | 148 | [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration] 149 | delay:0.0 150 | options:(UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction) 151 | animations:^{ 152 | toast.alpha = 1.0; 153 | } completion:^(BOOL finished) { 154 | NSTimer *timer = [NSTimer timerWithTimeInterval:duration target:self selector:@selector(cs_toastTimerDidFinish:) userInfo:toast repeats:NO]; 155 | [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 156 | objc_setAssociatedObject(toast, &CSToastTimerKey, timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 157 | }]; 158 | } 159 | 160 | - (void)cs_hideToast:(UIView *)toast { 161 | [self cs_hideToast:toast fromTap:NO]; 162 | } 163 | 164 | - (void)cs_hideToast:(UIView *)toast fromTap:(BOOL)fromTap { 165 | [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration] 166 | delay:0.0 167 | options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState) 168 | animations:^{ 169 | toast.alpha = 0.0; 170 | } completion:^(BOOL finished) { 171 | [toast removeFromSuperview]; 172 | 173 | // remove 174 | [[self cs_activeToasts] removeObject:toast]; 175 | 176 | // execute the completion block, if necessary 177 | void (^completion)(BOOL didTap) = objc_getAssociatedObject(toast, &CSToastCompletionKey); 178 | if (completion) { 179 | completion(fromTap); 180 | } 181 | 182 | if ([self.cs_toastQueue count] > 0) { 183 | // dequeue 184 | UIView *nextToast = [[self cs_toastQueue] firstObject]; 185 | [[self cs_toastQueue] removeObjectAtIndex:0]; 186 | 187 | // present the next toast 188 | NSTimeInterval duration = [objc_getAssociatedObject(nextToast, &CSToastDurationKey) doubleValue]; 189 | id position = objc_getAssociatedObject(nextToast, &CSToastPositionKey); 190 | [self cs_showToast:nextToast duration:duration position:position]; 191 | } 192 | }]; 193 | } 194 | 195 | #pragma mark - View Construction 196 | 197 | - (UIView *)toastViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image style:(CSToastStyle *)style { 198 | // sanity 199 | if(message == nil && title == nil && image == nil) return nil; 200 | 201 | // default to the shared style 202 | if (style == nil) { 203 | style = [CSToastManager sharedStyle]; 204 | } 205 | 206 | // dynamically build a toast view with any combination of message, title, & image 207 | UILabel *messageLabel = nil; 208 | UILabel *titleLabel = nil; 209 | UIImageView *imageView = nil; 210 | 211 | UIView *wrapperView = [[UIView alloc] init]; 212 | wrapperView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); 213 | wrapperView.layer.cornerRadius = style.cornerRadius; 214 | 215 | if (style.displayShadow) { 216 | wrapperView.layer.shadowColor = style.shadowColor.CGColor; 217 | wrapperView.layer.shadowOpacity = style.shadowOpacity; 218 | wrapperView.layer.shadowRadius = style.shadowRadius; 219 | wrapperView.layer.shadowOffset = style.shadowOffset; 220 | } 221 | 222 | wrapperView.backgroundColor = style.backgroundColor; 223 | 224 | if(image != nil) { 225 | imageView = [[UIImageView alloc] initWithImage:image]; 226 | imageView.contentMode = UIViewContentModeScaleAspectFit; 227 | imageView.frame = CGRectMake(style.horizontalPadding, style.verticalPadding, style.imageSize.width, style.imageSize.height); 228 | } 229 | 230 | CGRect imageRect = CGRectZero; 231 | 232 | if(imageView != nil) { 233 | imageRect.origin.x = style.horizontalPadding; 234 | imageRect.origin.y = style.verticalPadding; 235 | imageRect.size.width = imageView.bounds.size.width; 236 | imageRect.size.height = imageView.bounds.size.height; 237 | } 238 | 239 | if (title != nil) { 240 | titleLabel = [[UILabel alloc] init]; 241 | titleLabel.numberOfLines = style.titleNumberOfLines; 242 | titleLabel.font = style.titleFont; 243 | titleLabel.textAlignment = style.titleAlignment; 244 | titleLabel.lineBreakMode = NSLineBreakByTruncatingTail; 245 | titleLabel.textColor = style.titleColor; 246 | titleLabel.backgroundColor = [UIColor clearColor]; 247 | titleLabel.alpha = 1.0; 248 | titleLabel.text = title; 249 | 250 | // size the title label according to the length of the text 251 | CGSize maxSizeTitle = CGSizeMake((self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, self.bounds.size.height * style.maxHeightPercentage); 252 | CGSize expectedSizeTitle = [titleLabel sizeThatFits:maxSizeTitle]; 253 | // UILabel can return a size larger than the max size when the number of lines is 1 254 | expectedSizeTitle = CGSizeMake(MIN(maxSizeTitle.width, expectedSizeTitle.width), MIN(maxSizeTitle.height, expectedSizeTitle.height)); 255 | titleLabel.frame = CGRectMake(0.0, 0.0, expectedSizeTitle.width, expectedSizeTitle.height); 256 | } 257 | 258 | if (message != nil) { 259 | messageLabel = [[UILabel alloc] init]; 260 | messageLabel.numberOfLines = style.messageNumberOfLines; 261 | messageLabel.font = style.messageFont; 262 | messageLabel.textAlignment = style.messageAlignment; 263 | messageLabel.lineBreakMode = NSLineBreakByTruncatingTail; 264 | messageLabel.textColor = style.messageColor; 265 | messageLabel.backgroundColor = [UIColor clearColor]; 266 | messageLabel.alpha = 1.0; 267 | messageLabel.text = message; 268 | 269 | CGSize maxSizeMessage = CGSizeMake((self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, self.bounds.size.height * style.maxHeightPercentage); 270 | CGSize expectedSizeMessage = [messageLabel sizeThatFits:maxSizeMessage]; 271 | // UILabel can return a size larger than the max size when the number of lines is 1 272 | expectedSizeMessage = CGSizeMake(MIN(maxSizeMessage.width, expectedSizeMessage.width), MIN(maxSizeMessage.height, expectedSizeMessage.height)); 273 | messageLabel.frame = CGRectMake(0.0, 0.0, expectedSizeMessage.width, expectedSizeMessage.height); 274 | } 275 | 276 | CGRect titleRect = CGRectZero; 277 | 278 | if(titleLabel != nil) { 279 | titleRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding; 280 | titleRect.origin.y = style.verticalPadding; 281 | titleRect.size.width = titleLabel.bounds.size.width; 282 | titleRect.size.height = titleLabel.bounds.size.height; 283 | } 284 | 285 | CGRect messageRect = CGRectZero; 286 | 287 | if(messageLabel != nil) { 288 | messageRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding; 289 | messageRect.origin.y = titleRect.origin.y + titleRect.size.height + style.verticalPadding; 290 | messageRect.size.width = messageLabel.bounds.size.width; 291 | messageRect.size.height = messageLabel.bounds.size.height; 292 | } 293 | 294 | CGFloat longerWidth = MAX(titleRect.size.width, messageRect.size.width); 295 | CGFloat longerX = MAX(titleRect.origin.x, messageRect.origin.x); 296 | 297 | // Wrapper width uses the longerWidth or the image width, whatever is larger. Same logic applies to the wrapper height. 298 | CGFloat wrapperWidth = MAX((imageRect.size.width + (style.horizontalPadding * 2.0)), (longerX + longerWidth + style.horizontalPadding)); 299 | CGFloat wrapperHeight = MAX((messageRect.origin.y + messageRect.size.height + style.verticalPadding), (imageRect.size.height + (style.verticalPadding * 2.0))); 300 | 301 | wrapperView.frame = CGRectMake(0.0, 0.0, wrapperWidth, wrapperHeight); 302 | 303 | if(titleLabel != nil) { 304 | titleLabel.frame = titleRect; 305 | [wrapperView addSubview:titleLabel]; 306 | } 307 | 308 | if(messageLabel != nil) { 309 | messageLabel.frame = messageRect; 310 | [wrapperView addSubview:messageLabel]; 311 | } 312 | 313 | if(imageView != nil) { 314 | [wrapperView addSubview:imageView]; 315 | } 316 | 317 | return wrapperView; 318 | } 319 | 320 | #pragma mark - Storage 321 | 322 | - (NSMutableArray *)cs_activeToasts { 323 | NSMutableArray *cs_activeToasts = objc_getAssociatedObject(self, &CSToastActiveKey); 324 | if (cs_activeToasts == nil) { 325 | cs_activeToasts = [[NSMutableArray alloc] init]; 326 | objc_setAssociatedObject(self, &CSToastActiveKey, cs_activeToasts, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 327 | } 328 | return cs_activeToasts; 329 | } 330 | 331 | - (NSMutableArray *)cs_toastQueue { 332 | NSMutableArray *cs_toastQueue = objc_getAssociatedObject(self, &CSToastQueueKey); 333 | if (cs_toastQueue == nil) { 334 | cs_toastQueue = [[NSMutableArray alloc] init]; 335 | objc_setAssociatedObject(self, &CSToastQueueKey, cs_toastQueue, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 336 | } 337 | return cs_toastQueue; 338 | } 339 | 340 | #pragma mark - Events 341 | 342 | - (void)cs_toastTimerDidFinish:(NSTimer *)timer { 343 | [self cs_hideToast:(UIView *)timer.userInfo]; 344 | } 345 | 346 | - (void)cs_handleToastTapped:(UITapGestureRecognizer *)recognizer { 347 | UIView *toast = recognizer.view; 348 | NSTimer *timer = (NSTimer *)objc_getAssociatedObject(toast, &CSToastTimerKey); 349 | [timer invalidate]; 350 | 351 | [self cs_hideToast:toast fromTap:YES]; 352 | } 353 | 354 | #pragma mark - Activity Methods 355 | 356 | - (void)makeToastActivity:(id)position { 357 | // sanity 358 | UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey); 359 | if (existingActivityView != nil) return; 360 | 361 | CSToastStyle *style = [CSToastManager sharedStyle]; 362 | 363 | UIView *activityView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, style.activitySize.width, style.activitySize.height)]; 364 | activityView.center = [self cs_centerPointForPosition:position withToast:activityView]; 365 | activityView.backgroundColor = style.backgroundColor; 366 | activityView.alpha = 0.0; 367 | activityView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); 368 | activityView.layer.cornerRadius = style.cornerRadius; 369 | 370 | if (style.displayShadow) { 371 | activityView.layer.shadowColor = style.shadowColor.CGColor; 372 | activityView.layer.shadowOpacity = style.shadowOpacity; 373 | activityView.layer.shadowRadius = style.shadowRadius; 374 | activityView.layer.shadowOffset = style.shadowOffset; 375 | } 376 | 377 | UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 378 | activityIndicatorView.center = CGPointMake(activityView.bounds.size.width / 2, activityView.bounds.size.height / 2); 379 | [activityView addSubview:activityIndicatorView]; 380 | [activityIndicatorView startAnimating]; 381 | 382 | // associate the activity view with self 383 | objc_setAssociatedObject (self, &CSToastActivityViewKey, activityView, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 384 | 385 | [self addSubview:activityView]; 386 | 387 | [UIView animateWithDuration:style.fadeDuration 388 | delay:0.0 389 | options:UIViewAnimationOptionCurveEaseOut 390 | animations:^{ 391 | activityView.alpha = 1.0; 392 | } completion:nil]; 393 | } 394 | 395 | - (void)hideToastActivity { 396 | UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey); 397 | if (existingActivityView != nil) { 398 | [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration] 399 | delay:0.0 400 | options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState) 401 | animations:^{ 402 | existingActivityView.alpha = 0.0; 403 | } completion:^(BOOL finished) { 404 | [existingActivityView removeFromSuperview]; 405 | objc_setAssociatedObject (self, &CSToastActivityViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 406 | }]; 407 | } 408 | } 409 | 410 | #pragma mark - Helpers 411 | 412 | - (CGPoint)cs_centerPointForPosition:(id)point withToast:(UIView *)toast { 413 | CSToastStyle *style = [CSToastManager sharedStyle]; 414 | 415 | if([point isKindOfClass:[NSString class]]) { 416 | if([point caseInsensitiveCompare:CSToastPositionTop] == NSOrderedSame) { 417 | return CGPointMake(self.bounds.size.width/2, (toast.frame.size.height / 2) + style.verticalPadding); 418 | } else if([point caseInsensitiveCompare:CSToastPositionCenter] == NSOrderedSame) { 419 | return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2); 420 | } 421 | } else if ([point isKindOfClass:[NSValue class]]) { 422 | return [point CGPointValue]; 423 | } 424 | 425 | // default to bottom 426 | return CGPointMake(self.bounds.size.width/2, (self.bounds.size.height - (toast.frame.size.height / 2)) - style.verticalPadding); 427 | } 428 | 429 | @end 430 | 431 | @implementation CSToastStyle 432 | 433 | #pragma mark - Constructors 434 | 435 | - (instancetype)initWithDefaultStyle { 436 | self = [super init]; 437 | if (self) { 438 | self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; 439 | self.titleColor = [UIColor whiteColor]; 440 | self.messageColor = [UIColor whiteColor]; 441 | self.maxWidthPercentage = 0.8; 442 | self.maxHeightPercentage = 0.8; 443 | self.horizontalPadding = 10.0; 444 | self.verticalPadding = 10.0; 445 | self.cornerRadius = 10.0; 446 | self.titleFont = [UIFont boldSystemFontOfSize:16.0]; 447 | self.messageFont = [UIFont systemFontOfSize:16.0]; 448 | self.titleAlignment = NSTextAlignmentLeft; 449 | self.messageAlignment = NSTextAlignmentLeft; 450 | self.titleNumberOfLines = 0; 451 | self.messageNumberOfLines = 0; 452 | self.displayShadow = NO; 453 | self.shadowOpacity = 0.8; 454 | self.shadowRadius = 6.0; 455 | self.shadowOffset = CGSizeMake(4.0, 4.0); 456 | self.imageSize = CGSizeMake(80.0, 80.0); 457 | self.activitySize = CGSizeMake(100.0, 100.0); 458 | self.fadeDuration = 0.2; 459 | } 460 | return self; 461 | } 462 | 463 | - (void)setMaxWidthPercentage:(CGFloat)maxWidthPercentage { 464 | _maxWidthPercentage = MAX(MIN(maxWidthPercentage, 1.0), 0.0); 465 | } 466 | 467 | - (void)setMaxHeightPercentage:(CGFloat)maxHeightPercentage { 468 | _maxHeightPercentage = MAX(MIN(maxHeightPercentage, 1.0), 0.0); 469 | } 470 | 471 | - (instancetype)init NS_UNAVAILABLE { 472 | return nil; 473 | } 474 | 475 | @end 476 | 477 | @interface CSToastManager () 478 | 479 | @property (strong, nonatomic) CSToastStyle *sharedStyle; 480 | @property (assign, nonatomic, getter=isTapToDismissEnabled) BOOL tapToDismissEnabled; 481 | @property (assign, nonatomic, getter=isQueueEnabled) BOOL queueEnabled; 482 | @property (assign, nonatomic) NSTimeInterval defaultDuration; 483 | @property (strong, nonatomic) id defaultPosition; 484 | 485 | @end 486 | 487 | @implementation CSToastManager 488 | 489 | #pragma mark - Constructors 490 | 491 | + (instancetype)sharedManager { 492 | static CSToastManager *_sharedManager = nil; 493 | static dispatch_once_t oncePredicate; 494 | dispatch_once(&oncePredicate, ^{ 495 | _sharedManager = [[self alloc] init]; 496 | }); 497 | 498 | return _sharedManager; 499 | } 500 | 501 | - (instancetype)init { 502 | self = [super init]; 503 | if (self) { 504 | self.sharedStyle = [[CSToastStyle alloc] initWithDefaultStyle]; 505 | self.tapToDismissEnabled = YES; 506 | self.queueEnabled = YES; 507 | self.defaultDuration = 3.0; 508 | self.defaultPosition = CSToastPositionBottom; 509 | } 510 | return self; 511 | } 512 | 513 | #pragma mark - Singleton Methods 514 | 515 | + (void)setSharedStyle:(CSToastStyle *)sharedStyle { 516 | [[self sharedManager] setSharedStyle:sharedStyle]; 517 | } 518 | 519 | + (CSToastStyle *)sharedStyle { 520 | return [[self sharedManager] sharedStyle]; 521 | } 522 | 523 | + (void)setTapToDismissEnabled:(BOOL)tapToDismissEnabled { 524 | [[self sharedManager] setTapToDismissEnabled:tapToDismissEnabled]; 525 | } 526 | 527 | + (BOOL)isTapToDismissEnabled { 528 | return [[self sharedManager] isTapToDismissEnabled]; 529 | } 530 | 531 | + (void)setQueueEnabled:(BOOL)queueEnabled { 532 | [[self sharedManager] setQueueEnabled:queueEnabled]; 533 | } 534 | 535 | + (BOOL)isQueueEnabled { 536 | return [[self sharedManager] isQueueEnabled]; 537 | } 538 | 539 | + (void)setDefaultDuration:(NSTimeInterval)duration { 540 | [[self sharedManager] setDefaultDuration:duration]; 541 | } 542 | 543 | + (NSTimeInterval)defaultDuration { 544 | return [[self sharedManager] defaultDuration]; 545 | } 546 | 547 | + (void)setDefaultPosition:(id)position { 548 | if ([position isKindOfClass:[NSString class]] || [position isKindOfClass:[NSValue class]]) { 549 | [[self sharedManager] setDefaultPosition:position]; 550 | } 551 | } 552 | 553 | + (id)defaultPosition { 554 | return [[self sharedManager] defaultPosition]; 555 | } 556 | 557 | @end 558 | -------------------------------------------------------------------------------- /DSBluetooth/DSBluetooth.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0E1FCFDE207B5F84000037CC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E1FCFDD207B5F84000037CC /* AppDelegate.m */; }; 11 | 0E1FCFE1207B5F84000037CC /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E1FCFE0207B5F84000037CC /* ViewController.m */; }; 12 | 0E1FCFE4207B5F84000037CC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1FCFE2207B5F84000037CC /* Main.storyboard */; }; 13 | 0E1FCFE6207B5F87000037CC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E1FCFE5207B5F87000037CC /* Assets.xcassets */; }; 14 | 0E1FCFE9207B5F87000037CC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1FCFE7207B5F87000037CC /* LaunchScreen.storyboard */; }; 15 | 0E1FCFEC207B5F87000037CC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E1FCFEB207B5F87000037CC /* main.m */; }; 16 | 0E1FCFF6207B5F87000037CC /* DSBluetoothTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E1FCFF5207B5F87000037CC /* DSBluetoothTests.m */; }; 17 | 0E1FD001207B5F87000037CC /* DSBluetoothUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E1FD000207B5F87000037CC /* DSBluetoothUITests.m */; }; 18 | 0E1FD015207B5FD6000037CC /* DSBluetooth.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E1FD013207B5FD6000037CC /* DSBluetooth.m */; }; 19 | 0E1FD016207B5FD6000037CC /* DSCallback.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E1FD014207B5FD6000037CC /* DSCallback.m */; }; 20 | 0E45EDAD209FEC7B0049EF58 /* DSSettingDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E45EDAA209FEC7B0049EF58 /* DSSettingDataSource.m */; }; 21 | 0E45EDAE209FEC7B0049EF58 /* DSSettingItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E45EDAB209FEC7B0049EF58 /* DSSettingItem.m */; }; 22 | 0E45EDAF209FEC7B0049EF58 /* DSSettingCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E45EDAC209FEC7B0049EF58 /* DSSettingCell.m */; }; 23 | 0E45EDB2209FEE880049EF58 /* BindViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E45EDB1209FEE880049EF58 /* BindViewController.m */; }; 24 | 0E45EDB5209FEE9F0049EF58 /* ConnectViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E45EDB4209FEE9F0049EF58 /* ConnectViewController.m */; }; 25 | 0E45EDB8209FF66F0049EF58 /* UIView+Toast.m in Sources */ = {isa = PBXBuildFile; fileRef = 0E45EDB7209FF66E0049EF58 /* UIView+Toast.m */; }; 26 | 0EB71E74207EEF7E00013D58 /* DSBluetoothConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 0EB71E73207EEF7E00013D58 /* DSBluetoothConfig.m */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 0E1FCFF2207B5F87000037CC /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 0E1FCFD1207B5F84000037CC /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 0E1FCFD8207B5F84000037CC; 35 | remoteInfo = DSBluetooth; 36 | }; 37 | 0E1FCFFD207B5F87000037CC /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = 0E1FCFD1207B5F84000037CC /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = 0E1FCFD8207B5F84000037CC; 42 | remoteInfo = DSBluetooth; 43 | }; 44 | /* End PBXContainerItemProxy section */ 45 | 46 | /* Begin PBXFileReference section */ 47 | 0E1FCFD9207B5F84000037CC /* DSBluetooth.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DSBluetooth.app; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 0E1FCFDC207B5F84000037CC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 49 | 0E1FCFDD207B5F84000037CC /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 50 | 0E1FCFDF207B5F84000037CC /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 51 | 0E1FCFE0207B5F84000037CC /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 52 | 0E1FCFE3207B5F84000037CC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 0E1FCFE5207B5F87000037CC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 0E1FCFE8207B5F87000037CC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 0E1FCFEA207B5F87000037CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 0E1FCFEB207B5F87000037CC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 57 | 0E1FCFF1207B5F87000037CC /* DSBluetoothTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DSBluetoothTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 0E1FCFF5207B5F87000037CC /* DSBluetoothTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSBluetoothTests.m; sourceTree = ""; }; 59 | 0E1FCFF7207B5F87000037CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 60 | 0E1FCFFC207B5F87000037CC /* DSBluetoothUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DSBluetoothUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 0E1FD000207B5F87000037CC /* DSBluetoothUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSBluetoothUITests.m; sourceTree = ""; }; 62 | 0E1FD002207B5F87000037CC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | 0E1FD011207B5FD5000037CC /* DSCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DSCallback.h; sourceTree = ""; }; 64 | 0E1FD012207B5FD5000037CC /* DSBluetooth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DSBluetooth.h; sourceTree = ""; }; 65 | 0E1FD013207B5FD6000037CC /* DSBluetooth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DSBluetooth.m; sourceTree = ""; }; 66 | 0E1FD014207B5FD6000037CC /* DSCallback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DSCallback.m; sourceTree = ""; }; 67 | 0E45EDA7209FEC7A0049EF58 /* DSSettingItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DSSettingItem.h; sourceTree = ""; }; 68 | 0E45EDA8209FEC7A0049EF58 /* DSSettingCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DSSettingCell.h; sourceTree = ""; }; 69 | 0E45EDA9209FEC7A0049EF58 /* DSSettingDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DSSettingDataSource.h; sourceTree = ""; }; 70 | 0E45EDAA209FEC7B0049EF58 /* DSSettingDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DSSettingDataSource.m; sourceTree = ""; }; 71 | 0E45EDAB209FEC7B0049EF58 /* DSSettingItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DSSettingItem.m; sourceTree = ""; }; 72 | 0E45EDAC209FEC7B0049EF58 /* DSSettingCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DSSettingCell.m; sourceTree = ""; }; 73 | 0E45EDB0209FEE880049EF58 /* BindViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BindViewController.h; sourceTree = ""; }; 74 | 0E45EDB1209FEE880049EF58 /* BindViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BindViewController.m; sourceTree = ""; }; 75 | 0E45EDB3209FEE9F0049EF58 /* ConnectViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConnectViewController.h; sourceTree = ""; }; 76 | 0E45EDB4209FEE9F0049EF58 /* ConnectViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ConnectViewController.m; sourceTree = ""; }; 77 | 0E45EDB6209FF66E0049EF58 /* UIView+Toast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Toast.h"; sourceTree = ""; }; 78 | 0E45EDB7209FF66E0049EF58 /* UIView+Toast.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Toast.m"; sourceTree = ""; }; 79 | 0EB71E72207EEF7E00013D58 /* DSBluetoothConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DSBluetoothConfig.h; sourceTree = ""; }; 80 | 0EB71E73207EEF7E00013D58 /* DSBluetoothConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DSBluetoothConfig.m; sourceTree = ""; }; 81 | /* End PBXFileReference section */ 82 | 83 | /* Begin PBXFrameworksBuildPhase section */ 84 | 0E1FCFD6207B5F84000037CC /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | 0E1FCFEE207B5F87000037CC /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | 0E1FCFF9207B5F87000037CC /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | /* End PBXFrameworksBuildPhase section */ 106 | 107 | /* Begin PBXGroup section */ 108 | 0E1FCFD0207B5F84000037CC = { 109 | isa = PBXGroup; 110 | children = ( 111 | 0E1FCFDB207B5F84000037CC /* DSBluetooth */, 112 | 0E1FCFF4207B5F87000037CC /* DSBluetoothTests */, 113 | 0E1FCFFF207B5F87000037CC /* DSBluetoothUITests */, 114 | 0E1FCFDA207B5F84000037CC /* Products */, 115 | ); 116 | sourceTree = ""; 117 | }; 118 | 0E1FCFDA207B5F84000037CC /* Products */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 0E1FCFD9207B5F84000037CC /* DSBluetooth.app */, 122 | 0E1FCFF1207B5F87000037CC /* DSBluetoothTests.xctest */, 123 | 0E1FCFFC207B5F87000037CC /* DSBluetoothUITests.xctest */, 124 | ); 125 | name = Products; 126 | sourceTree = ""; 127 | }; 128 | 0E1FCFDB207B5F84000037CC /* DSBluetooth */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 0E1FD010207B5FBF000037CC /* DSBluetooth */, 132 | 0E1FCFDC207B5F84000037CC /* AppDelegate.h */, 133 | 0E1FCFDD207B5F84000037CC /* AppDelegate.m */, 134 | 0E1FCFDF207B5F84000037CC /* ViewController.h */, 135 | 0E1FCFE0207B5F84000037CC /* ViewController.m */, 136 | 0E45EDB0209FEE880049EF58 /* BindViewController.h */, 137 | 0E45EDB1209FEE880049EF58 /* BindViewController.m */, 138 | 0E45EDB3209FEE9F0049EF58 /* ConnectViewController.h */, 139 | 0E45EDB4209FEE9F0049EF58 /* ConnectViewController.m */, 140 | 0E45EDA6209FEC6B0049EF58 /* Other */, 141 | 0E1FCFE2207B5F84000037CC /* Main.storyboard */, 142 | 0E1FCFE5207B5F87000037CC /* Assets.xcassets */, 143 | 0E1FCFE7207B5F87000037CC /* LaunchScreen.storyboard */, 144 | 0E1FCFEA207B5F87000037CC /* Info.plist */, 145 | 0E1FCFEB207B5F87000037CC /* main.m */, 146 | ); 147 | path = DSBluetooth; 148 | sourceTree = ""; 149 | }; 150 | 0E1FCFF4207B5F87000037CC /* DSBluetoothTests */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 0E1FCFF5207B5F87000037CC /* DSBluetoothTests.m */, 154 | 0E1FCFF7207B5F87000037CC /* Info.plist */, 155 | ); 156 | path = DSBluetoothTests; 157 | sourceTree = ""; 158 | }; 159 | 0E1FCFFF207B5F87000037CC /* DSBluetoothUITests */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 0E1FD000207B5F87000037CC /* DSBluetoothUITests.m */, 163 | 0E1FD002207B5F87000037CC /* Info.plist */, 164 | ); 165 | path = DSBluetoothUITests; 166 | sourceTree = ""; 167 | }; 168 | 0E1FD010207B5FBF000037CC /* DSBluetooth */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 0E1FD012207B5FD5000037CC /* DSBluetooth.h */, 172 | 0E1FD013207B5FD6000037CC /* DSBluetooth.m */, 173 | 0E1FD011207B5FD5000037CC /* DSCallback.h */, 174 | 0E1FD014207B5FD6000037CC /* DSCallback.m */, 175 | 0EB71E72207EEF7E00013D58 /* DSBluetoothConfig.h */, 176 | 0EB71E73207EEF7E00013D58 /* DSBluetoothConfig.m */, 177 | ); 178 | path = DSBluetooth; 179 | sourceTree = ""; 180 | }; 181 | 0E45EDA6209FEC6B0049EF58 /* Other */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | 0E45EDB6209FF66E0049EF58 /* UIView+Toast.h */, 185 | 0E45EDB7209FF66E0049EF58 /* UIView+Toast.m */, 186 | 0E45EDA8209FEC7A0049EF58 /* DSSettingCell.h */, 187 | 0E45EDAC209FEC7B0049EF58 /* DSSettingCell.m */, 188 | 0E45EDA9209FEC7A0049EF58 /* DSSettingDataSource.h */, 189 | 0E45EDAA209FEC7B0049EF58 /* DSSettingDataSource.m */, 190 | 0E45EDA7209FEC7A0049EF58 /* DSSettingItem.h */, 191 | 0E45EDAB209FEC7B0049EF58 /* DSSettingItem.m */, 192 | ); 193 | path = Other; 194 | sourceTree = ""; 195 | }; 196 | /* End PBXGroup section */ 197 | 198 | /* Begin PBXNativeTarget section */ 199 | 0E1FCFD8207B5F84000037CC /* DSBluetooth */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = 0E1FD005207B5F87000037CC /* Build configuration list for PBXNativeTarget "DSBluetooth" */; 202 | buildPhases = ( 203 | 0E1FCFD5207B5F84000037CC /* Sources */, 204 | 0E1FCFD6207B5F84000037CC /* Frameworks */, 205 | 0E1FCFD7207B5F84000037CC /* Resources */, 206 | ); 207 | buildRules = ( 208 | ); 209 | dependencies = ( 210 | ); 211 | name = DSBluetooth; 212 | productName = DSBluetooth; 213 | productReference = 0E1FCFD9207B5F84000037CC /* DSBluetooth.app */; 214 | productType = "com.apple.product-type.application"; 215 | }; 216 | 0E1FCFF0207B5F87000037CC /* DSBluetoothTests */ = { 217 | isa = PBXNativeTarget; 218 | buildConfigurationList = 0E1FD008207B5F87000037CC /* Build configuration list for PBXNativeTarget "DSBluetoothTests" */; 219 | buildPhases = ( 220 | 0E1FCFED207B5F87000037CC /* Sources */, 221 | 0E1FCFEE207B5F87000037CC /* Frameworks */, 222 | 0E1FCFEF207B5F87000037CC /* Resources */, 223 | ); 224 | buildRules = ( 225 | ); 226 | dependencies = ( 227 | 0E1FCFF3207B5F87000037CC /* PBXTargetDependency */, 228 | ); 229 | name = DSBluetoothTests; 230 | productName = DSBluetoothTests; 231 | productReference = 0E1FCFF1207B5F87000037CC /* DSBluetoothTests.xctest */; 232 | productType = "com.apple.product-type.bundle.unit-test"; 233 | }; 234 | 0E1FCFFB207B5F87000037CC /* DSBluetoothUITests */ = { 235 | isa = PBXNativeTarget; 236 | buildConfigurationList = 0E1FD00B207B5F87000037CC /* Build configuration list for PBXNativeTarget "DSBluetoothUITests" */; 237 | buildPhases = ( 238 | 0E1FCFF8207B5F87000037CC /* Sources */, 239 | 0E1FCFF9207B5F87000037CC /* Frameworks */, 240 | 0E1FCFFA207B5F87000037CC /* Resources */, 241 | ); 242 | buildRules = ( 243 | ); 244 | dependencies = ( 245 | 0E1FCFFE207B5F87000037CC /* PBXTargetDependency */, 246 | ); 247 | name = DSBluetoothUITests; 248 | productName = DSBluetoothUITests; 249 | productReference = 0E1FCFFC207B5F87000037CC /* DSBluetoothUITests.xctest */; 250 | productType = "com.apple.product-type.bundle.ui-testing"; 251 | }; 252 | /* End PBXNativeTarget section */ 253 | 254 | /* Begin PBXProject section */ 255 | 0E1FCFD1207B5F84000037CC /* Project object */ = { 256 | isa = PBXProject; 257 | attributes = { 258 | LastUpgradeCheck = 0930; 259 | ORGANIZATIONNAME = HelloAda; 260 | TargetAttributes = { 261 | 0E1FCFD8207B5F84000037CC = { 262 | CreatedOnToolsVersion = 9.3; 263 | }; 264 | 0E1FCFF0207B5F87000037CC = { 265 | CreatedOnToolsVersion = 9.3; 266 | TestTargetID = 0E1FCFD8207B5F84000037CC; 267 | }; 268 | 0E1FCFFB207B5F87000037CC = { 269 | CreatedOnToolsVersion = 9.3; 270 | TestTargetID = 0E1FCFD8207B5F84000037CC; 271 | }; 272 | }; 273 | }; 274 | buildConfigurationList = 0E1FCFD4207B5F84000037CC /* Build configuration list for PBXProject "DSBluetooth" */; 275 | compatibilityVersion = "Xcode 9.3"; 276 | developmentRegion = en; 277 | hasScannedForEncodings = 0; 278 | knownRegions = ( 279 | en, 280 | Base, 281 | ); 282 | mainGroup = 0E1FCFD0207B5F84000037CC; 283 | productRefGroup = 0E1FCFDA207B5F84000037CC /* Products */; 284 | projectDirPath = ""; 285 | projectRoot = ""; 286 | targets = ( 287 | 0E1FCFD8207B5F84000037CC /* DSBluetooth */, 288 | 0E1FCFF0207B5F87000037CC /* DSBluetoothTests */, 289 | 0E1FCFFB207B5F87000037CC /* DSBluetoothUITests */, 290 | ); 291 | }; 292 | /* End PBXProject section */ 293 | 294 | /* Begin PBXResourcesBuildPhase section */ 295 | 0E1FCFD7207B5F84000037CC /* Resources */ = { 296 | isa = PBXResourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | 0E1FCFE9207B5F87000037CC /* LaunchScreen.storyboard in Resources */, 300 | 0E1FCFE6207B5F87000037CC /* Assets.xcassets in Resources */, 301 | 0E1FCFE4207B5F84000037CC /* Main.storyboard in Resources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | 0E1FCFEF207B5F87000037CC /* Resources */ = { 306 | isa = PBXResourcesBuildPhase; 307 | buildActionMask = 2147483647; 308 | files = ( 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | 0E1FCFFA207B5F87000037CC /* Resources */ = { 313 | isa = PBXResourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | ); 317 | runOnlyForDeploymentPostprocessing = 0; 318 | }; 319 | /* End PBXResourcesBuildPhase section */ 320 | 321 | /* Begin PBXSourcesBuildPhase section */ 322 | 0E1FCFD5207B5F84000037CC /* Sources */ = { 323 | isa = PBXSourcesBuildPhase; 324 | buildActionMask = 2147483647; 325 | files = ( 326 | 0E45EDB8209FF66F0049EF58 /* UIView+Toast.m in Sources */, 327 | 0E45EDAD209FEC7B0049EF58 /* DSSettingDataSource.m in Sources */, 328 | 0E1FCFE1207B5F84000037CC /* ViewController.m in Sources */, 329 | 0E1FD015207B5FD6000037CC /* DSBluetooth.m in Sources */, 330 | 0E45EDB2209FEE880049EF58 /* BindViewController.m in Sources */, 331 | 0E1FCFEC207B5F87000037CC /* main.m in Sources */, 332 | 0EB71E74207EEF7E00013D58 /* DSBluetoothConfig.m in Sources */, 333 | 0E1FD016207B5FD6000037CC /* DSCallback.m in Sources */, 334 | 0E45EDAF209FEC7B0049EF58 /* DSSettingCell.m in Sources */, 335 | 0E45EDB5209FEE9F0049EF58 /* ConnectViewController.m in Sources */, 336 | 0E45EDAE209FEC7B0049EF58 /* DSSettingItem.m in Sources */, 337 | 0E1FCFDE207B5F84000037CC /* AppDelegate.m in Sources */, 338 | ); 339 | runOnlyForDeploymentPostprocessing = 0; 340 | }; 341 | 0E1FCFED207B5F87000037CC /* Sources */ = { 342 | isa = PBXSourcesBuildPhase; 343 | buildActionMask = 2147483647; 344 | files = ( 345 | 0E1FCFF6207B5F87000037CC /* DSBluetoothTests.m in Sources */, 346 | ); 347 | runOnlyForDeploymentPostprocessing = 0; 348 | }; 349 | 0E1FCFF8207B5F87000037CC /* Sources */ = { 350 | isa = PBXSourcesBuildPhase; 351 | buildActionMask = 2147483647; 352 | files = ( 353 | 0E1FD001207B5F87000037CC /* DSBluetoothUITests.m in Sources */, 354 | ); 355 | runOnlyForDeploymentPostprocessing = 0; 356 | }; 357 | /* End PBXSourcesBuildPhase section */ 358 | 359 | /* Begin PBXTargetDependency section */ 360 | 0E1FCFF3207B5F87000037CC /* PBXTargetDependency */ = { 361 | isa = PBXTargetDependency; 362 | target = 0E1FCFD8207B5F84000037CC /* DSBluetooth */; 363 | targetProxy = 0E1FCFF2207B5F87000037CC /* PBXContainerItemProxy */; 364 | }; 365 | 0E1FCFFE207B5F87000037CC /* PBXTargetDependency */ = { 366 | isa = PBXTargetDependency; 367 | target = 0E1FCFD8207B5F84000037CC /* DSBluetooth */; 368 | targetProxy = 0E1FCFFD207B5F87000037CC /* PBXContainerItemProxy */; 369 | }; 370 | /* End PBXTargetDependency section */ 371 | 372 | /* Begin PBXVariantGroup section */ 373 | 0E1FCFE2207B5F84000037CC /* Main.storyboard */ = { 374 | isa = PBXVariantGroup; 375 | children = ( 376 | 0E1FCFE3207B5F84000037CC /* Base */, 377 | ); 378 | name = Main.storyboard; 379 | sourceTree = ""; 380 | }; 381 | 0E1FCFE7207B5F87000037CC /* LaunchScreen.storyboard */ = { 382 | isa = PBXVariantGroup; 383 | children = ( 384 | 0E1FCFE8207B5F87000037CC /* Base */, 385 | ); 386 | name = LaunchScreen.storyboard; 387 | sourceTree = ""; 388 | }; 389 | /* End PBXVariantGroup section */ 390 | 391 | /* Begin XCBuildConfiguration section */ 392 | 0E1FD003207B5F87000037CC /* Debug */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | ALWAYS_SEARCH_USER_PATHS = NO; 396 | CLANG_ANALYZER_NONNULL = YES; 397 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 398 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 399 | CLANG_CXX_LIBRARY = "libc++"; 400 | CLANG_ENABLE_MODULES = YES; 401 | CLANG_ENABLE_OBJC_ARC = YES; 402 | CLANG_ENABLE_OBJC_WEAK = YES; 403 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 404 | CLANG_WARN_BOOL_CONVERSION = YES; 405 | CLANG_WARN_COMMA = YES; 406 | CLANG_WARN_CONSTANT_CONVERSION = YES; 407 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 408 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 409 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 410 | CLANG_WARN_EMPTY_BODY = YES; 411 | CLANG_WARN_ENUM_CONVERSION = YES; 412 | CLANG_WARN_INFINITE_RECURSION = YES; 413 | CLANG_WARN_INT_CONVERSION = YES; 414 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 415 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 416 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 417 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 418 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 419 | CLANG_WARN_STRICT_PROTOTYPES = YES; 420 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 421 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 422 | CLANG_WARN_UNREACHABLE_CODE = YES; 423 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 424 | CODE_SIGN_IDENTITY = "iPhone Developer"; 425 | COPY_PHASE_STRIP = NO; 426 | DEBUG_INFORMATION_FORMAT = dwarf; 427 | ENABLE_STRICT_OBJC_MSGSEND = YES; 428 | ENABLE_TESTABILITY = YES; 429 | GCC_C_LANGUAGE_STANDARD = gnu11; 430 | GCC_DYNAMIC_NO_PIC = NO; 431 | GCC_NO_COMMON_BLOCKS = YES; 432 | GCC_OPTIMIZATION_LEVEL = 0; 433 | GCC_PREPROCESSOR_DEFINITIONS = ( 434 | "DEBUG=1", 435 | "$(inherited)", 436 | ); 437 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 438 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 439 | GCC_WARN_UNDECLARED_SELECTOR = YES; 440 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 441 | GCC_WARN_UNUSED_FUNCTION = YES; 442 | GCC_WARN_UNUSED_VARIABLE = YES; 443 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 444 | MTL_ENABLE_DEBUG_INFO = YES; 445 | ONLY_ACTIVE_ARCH = YES; 446 | SDKROOT = iphoneos; 447 | }; 448 | name = Debug; 449 | }; 450 | 0E1FD004207B5F87000037CC /* Release */ = { 451 | isa = XCBuildConfiguration; 452 | buildSettings = { 453 | ALWAYS_SEARCH_USER_PATHS = NO; 454 | CLANG_ANALYZER_NONNULL = YES; 455 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 457 | CLANG_CXX_LIBRARY = "libc++"; 458 | CLANG_ENABLE_MODULES = YES; 459 | CLANG_ENABLE_OBJC_ARC = YES; 460 | CLANG_ENABLE_OBJC_WEAK = YES; 461 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 462 | CLANG_WARN_BOOL_CONVERSION = YES; 463 | CLANG_WARN_COMMA = YES; 464 | CLANG_WARN_CONSTANT_CONVERSION = YES; 465 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 466 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 467 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 468 | CLANG_WARN_EMPTY_BODY = YES; 469 | CLANG_WARN_ENUM_CONVERSION = YES; 470 | CLANG_WARN_INFINITE_RECURSION = YES; 471 | CLANG_WARN_INT_CONVERSION = YES; 472 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 473 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 474 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 475 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 476 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 477 | CLANG_WARN_STRICT_PROTOTYPES = YES; 478 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 479 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 480 | CLANG_WARN_UNREACHABLE_CODE = YES; 481 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 482 | CODE_SIGN_IDENTITY = "iPhone Developer"; 483 | COPY_PHASE_STRIP = NO; 484 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 485 | ENABLE_NS_ASSERTIONS = NO; 486 | ENABLE_STRICT_OBJC_MSGSEND = YES; 487 | GCC_C_LANGUAGE_STANDARD = gnu11; 488 | GCC_NO_COMMON_BLOCKS = YES; 489 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 490 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 491 | GCC_WARN_UNDECLARED_SELECTOR = YES; 492 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 493 | GCC_WARN_UNUSED_FUNCTION = YES; 494 | GCC_WARN_UNUSED_VARIABLE = YES; 495 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 496 | MTL_ENABLE_DEBUG_INFO = NO; 497 | SDKROOT = iphoneos; 498 | VALIDATE_PRODUCT = YES; 499 | }; 500 | name = Release; 501 | }; 502 | 0E1FD006207B5F87000037CC /* Debug */ = { 503 | isa = XCBuildConfiguration; 504 | buildSettings = { 505 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 506 | CODE_SIGN_STYLE = Automatic; 507 | DEVELOPMENT_TEAM = M3WM4WM6Y4; 508 | INFOPLIST_FILE = DSBluetooth/Info.plist; 509 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 510 | LD_RUNPATH_SEARCH_PATHS = ( 511 | "$(inherited)", 512 | "@executable_path/Frameworks", 513 | ); 514 | PRODUCT_BUNDLE_IDENTIFIER = "---.DSBluetooth"; 515 | PRODUCT_NAME = "$(TARGET_NAME)"; 516 | TARGETED_DEVICE_FAMILY = "1,2"; 517 | }; 518 | name = Debug; 519 | }; 520 | 0E1FD007207B5F87000037CC /* Release */ = { 521 | isa = XCBuildConfiguration; 522 | buildSettings = { 523 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 524 | CODE_SIGN_STYLE = Automatic; 525 | DEVELOPMENT_TEAM = M3WM4WM6Y4; 526 | INFOPLIST_FILE = DSBluetooth/Info.plist; 527 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 528 | LD_RUNPATH_SEARCH_PATHS = ( 529 | "$(inherited)", 530 | "@executable_path/Frameworks", 531 | ); 532 | PRODUCT_BUNDLE_IDENTIFIER = "---.DSBluetooth"; 533 | PRODUCT_NAME = "$(TARGET_NAME)"; 534 | TARGETED_DEVICE_FAMILY = "1,2"; 535 | }; 536 | name = Release; 537 | }; 538 | 0E1FD009207B5F87000037CC /* Debug */ = { 539 | isa = XCBuildConfiguration; 540 | buildSettings = { 541 | BUNDLE_LOADER = "$(TEST_HOST)"; 542 | CODE_SIGN_STYLE = Automatic; 543 | INFOPLIST_FILE = DSBluetoothTests/Info.plist; 544 | LD_RUNPATH_SEARCH_PATHS = ( 545 | "$(inherited)", 546 | "@executable_path/Frameworks", 547 | "@loader_path/Frameworks", 548 | ); 549 | PRODUCT_BUNDLE_IDENTIFIER = "---.DSBluetoothTests"; 550 | PRODUCT_NAME = "$(TARGET_NAME)"; 551 | TARGETED_DEVICE_FAMILY = "1,2"; 552 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DSBluetooth.app/DSBluetooth"; 553 | }; 554 | name = Debug; 555 | }; 556 | 0E1FD00A207B5F87000037CC /* Release */ = { 557 | isa = XCBuildConfiguration; 558 | buildSettings = { 559 | BUNDLE_LOADER = "$(TEST_HOST)"; 560 | CODE_SIGN_STYLE = Automatic; 561 | INFOPLIST_FILE = DSBluetoothTests/Info.plist; 562 | LD_RUNPATH_SEARCH_PATHS = ( 563 | "$(inherited)", 564 | "@executable_path/Frameworks", 565 | "@loader_path/Frameworks", 566 | ); 567 | PRODUCT_BUNDLE_IDENTIFIER = "---.DSBluetoothTests"; 568 | PRODUCT_NAME = "$(TARGET_NAME)"; 569 | TARGETED_DEVICE_FAMILY = "1,2"; 570 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/DSBluetooth.app/DSBluetooth"; 571 | }; 572 | name = Release; 573 | }; 574 | 0E1FD00C207B5F87000037CC /* Debug */ = { 575 | isa = XCBuildConfiguration; 576 | buildSettings = { 577 | CODE_SIGN_STYLE = Automatic; 578 | INFOPLIST_FILE = DSBluetoothUITests/Info.plist; 579 | LD_RUNPATH_SEARCH_PATHS = ( 580 | "$(inherited)", 581 | "@executable_path/Frameworks", 582 | "@loader_path/Frameworks", 583 | ); 584 | PRODUCT_BUNDLE_IDENTIFIER = "---.DSBluetoothUITests"; 585 | PRODUCT_NAME = "$(TARGET_NAME)"; 586 | TARGETED_DEVICE_FAMILY = "1,2"; 587 | TEST_TARGET_NAME = DSBluetooth; 588 | }; 589 | name = Debug; 590 | }; 591 | 0E1FD00D207B5F87000037CC /* Release */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | CODE_SIGN_STYLE = Automatic; 595 | INFOPLIST_FILE = DSBluetoothUITests/Info.plist; 596 | LD_RUNPATH_SEARCH_PATHS = ( 597 | "$(inherited)", 598 | "@executable_path/Frameworks", 599 | "@loader_path/Frameworks", 600 | ); 601 | PRODUCT_BUNDLE_IDENTIFIER = "---.DSBluetoothUITests"; 602 | PRODUCT_NAME = "$(TARGET_NAME)"; 603 | TARGETED_DEVICE_FAMILY = "1,2"; 604 | TEST_TARGET_NAME = DSBluetooth; 605 | }; 606 | name = Release; 607 | }; 608 | /* End XCBuildConfiguration section */ 609 | 610 | /* Begin XCConfigurationList section */ 611 | 0E1FCFD4207B5F84000037CC /* Build configuration list for PBXProject "DSBluetooth" */ = { 612 | isa = XCConfigurationList; 613 | buildConfigurations = ( 614 | 0E1FD003207B5F87000037CC /* Debug */, 615 | 0E1FD004207B5F87000037CC /* Release */, 616 | ); 617 | defaultConfigurationIsVisible = 0; 618 | defaultConfigurationName = Release; 619 | }; 620 | 0E1FD005207B5F87000037CC /* Build configuration list for PBXNativeTarget "DSBluetooth" */ = { 621 | isa = XCConfigurationList; 622 | buildConfigurations = ( 623 | 0E1FD006207B5F87000037CC /* Debug */, 624 | 0E1FD007207B5F87000037CC /* Release */, 625 | ); 626 | defaultConfigurationIsVisible = 0; 627 | defaultConfigurationName = Release; 628 | }; 629 | 0E1FD008207B5F87000037CC /* Build configuration list for PBXNativeTarget "DSBluetoothTests" */ = { 630 | isa = XCConfigurationList; 631 | buildConfigurations = ( 632 | 0E1FD009207B5F87000037CC /* Debug */, 633 | 0E1FD00A207B5F87000037CC /* Release */, 634 | ); 635 | defaultConfigurationIsVisible = 0; 636 | defaultConfigurationName = Release; 637 | }; 638 | 0E1FD00B207B5F87000037CC /* Build configuration list for PBXNativeTarget "DSBluetoothUITests" */ = { 639 | isa = XCConfigurationList; 640 | buildConfigurations = ( 641 | 0E1FD00C207B5F87000037CC /* Debug */, 642 | 0E1FD00D207B5F87000037CC /* Release */, 643 | ); 644 | defaultConfigurationIsVisible = 0; 645 | defaultConfigurationName = Release; 646 | }; 647 | /* End XCConfigurationList section */ 648 | }; 649 | rootObject = 0E1FCFD1207B5F84000037CC /* Project object */; 650 | } 651 | --------------------------------------------------------------------------------