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