├── .gitignore ├── screenshot ├── off.png ├── on.png ├── func1.png ├── func2.png └── cocoapods.png ├── skoal-example ├── skoal-example │ ├── skoal-example-Bridging-Header.h │ ├── skoal-example.entitlements │ ├── Info.plist │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── AppDelegate.swift │ └── ViewController.swift ├── skoal-example.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcuserdata │ │ │ └── BANYAN.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ ├── xcuserdata │ │ └── BANYAN.xcuserdatad │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── project.pbxproj ├── skoal-exampleTests │ ├── Info.plist │ └── skoal_exampleTests.swift └── skoal-exampleUITests │ ├── Info.plist │ └── skoal_exampleUITests.swift ├── LICENSE ├── README.md └── skoal ├── skoal.h └── skoal.m /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | skoal/.DS_Store 4 | 5 | .swift-version 6 | -------------------------------------------------------------------------------- /screenshot/off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apdevzhang/HealthKitUsageDemo/HEAD/screenshot/off.png -------------------------------------------------------------------------------- /screenshot/on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apdevzhang/HealthKitUsageDemo/HEAD/screenshot/on.png -------------------------------------------------------------------------------- /screenshot/func1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apdevzhang/HealthKitUsageDemo/HEAD/screenshot/func1.png -------------------------------------------------------------------------------- /screenshot/func2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apdevzhang/HealthKitUsageDemo/HEAD/screenshot/func2.png -------------------------------------------------------------------------------- /screenshot/cocoapods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apdevzhang/HealthKitUsageDemo/HEAD/screenshot/cocoapods.png -------------------------------------------------------------------------------- /skoal-example/skoal-example/skoal-example-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "skoal.h" 6 | -------------------------------------------------------------------------------- /skoal-example/skoal-example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /skoal-example/skoal-example.xcodeproj/project.xcworkspace/xcuserdata/BANYAN.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apdevzhang/HealthKitUsageDemo/HEAD/skoal-example/skoal-example.xcodeproj/project.xcworkspace/xcuserdata/BANYAN.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /skoal-example/skoal-example/skoal-example.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.healthkit 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /skoal-example/skoal-example.xcodeproj/xcuserdata/BANYAN.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | skoal-example.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /skoal-example/skoal-exampleTests/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 | -------------------------------------------------------------------------------- /skoal-example/skoal-exampleUITests/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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 BANYAN 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. 22 | -------------------------------------------------------------------------------- /skoal-example/skoal-exampleTests/skoal_exampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // skoal_exampleTests.swift 3 | // skoal-exampleTests 4 | // 5 | // Created by BANYAN on 2017/11/17. 6 | // Copyright © 2017年 skoal. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import skoal_example 11 | 12 | class skoal_exampleTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /skoal-example/skoal-exampleUITests/skoal_exampleUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // skoal_exampleUITests.swift 3 | // skoal-exampleUITests 4 | // 5 | // Created by BANYAN on 2017/11/17. 6 | // Copyright © 2017年 skoal. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class skoal_exampleUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // 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. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /skoal-example/skoal-example/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 | NSHealthShareUsageDescription 24 | 25 | NSHealthUpdateUsageDescription 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /skoal-example/skoal-example/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 | -------------------------------------------------------------------------------- /skoal-example/skoal-example/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 | -------------------------------------------------------------------------------- /skoal-example/skoal-example/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 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /skoal-example/skoal-example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // skoal-example 4 | // 5 | // Created by BANYAN on 2017/11/17. 6 | // Copyright © 2017年 skoal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // 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. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # skoal 2 | ![License](https://img.shields.io/badge/License-MIT-orange.svg)  3 | ![Platform](https://img.shields.io/badge/Platform-iOS-yellowgreen.svg)  4 | ![Support](https://img.shields.io/badge/Support-iOS%208%2B-lightgrey.svg)  5 | ![Cocoapods](https://img.shields.io/badge/cocoapods-support-red.svg)  6 | ![Language](https://img.shields.io/badge/language-Objective--C-B9D3EE.svg)  7 | ![Language](https://img.shields.io/badge/language-Swift-red.svg)  8 | 9 | ##   Skoal is a healthkit based library that supports reading and writing healthstore properties 10 | 11 | ## Supported Properties 12 | | Sample | HealthKit Identifier Type | Read | Write | 13 | |--------------|-----------------------------|----------|-----------| 14 | | StepCount | HKQuantityTypeIdentifierStepCount | ✓ | ✓ | 15 | | Height | HKQuantityTypeIdentifierHeight | ✓ | ✓ | 16 | | BodyMass | HKQuantityTypeIdentifierBodyMass | ✓ | ✓ || 17 | | BodyMassIndex | HKQuantityTypeIdentifierBodyMassIndex | ✓ | ✓ | 18 | | DistanceWalkingRunning | HKQuantityTypeIdentifierDistanceWalkingRunning | ✓ | ✓ | 19 | | FlightsClimbed | HKQuantityTypeIdentifierFlightsClimbed | ✓ | ✓ | 20 | | RespiratoryRate | HKQuantityTypeIdentifierRespiratoryRate | ✓ | ✓ | 21 | | DietaryEnergyConsumed | HKQuantityTypeIdentifierDietaryEnergyConsumed | ✓ | ✓ | 22 | | OxygenSaturation | HKQuantityTypeIdentifierOxygenSaturation | ✓ | | 23 | | BodyTemperature | HKQuantityTypeIdentifierBodyTemperature | ✓ | ✓ | 24 | | BloodGlucose | HKQuantityTypeIdentifierBloodGlucose | ✓ | ✓ | 25 | | BloodPressureSystolic | HKQuantityTypeIdentifierBloodPressureSystolic | ✓ | ✓ | 26 | | BloodPressureDiastolic | HKQuantityTypeIdentifierBloodPressureDiastolic | ✓ | ✓ | 27 | | StandHour | HKCategoryTypeIdentifierAppleStandHour | ✓ | | 28 | | BiologicalSex | biologicalSexWithError | ✓ | | 29 | | DateOfBirth | dateOfBirthComponentsWithError | ✓ | | 30 | | BloodType | bloodTypeWithError | ✓ | | 31 | | FitzpatrickSkin | fitzpatrickSkinTypeWithError | ✓ | | 32 | | SleepAnalysis | HKCategoryTypeIdentifierSleepAnalysis | ✓ | | 33 | | MenstrualFlow | HKCategoryTypeIdentifierMenstrualFlow | ✓ | | 34 | | IntermenstrualBleeding | HKCategoryTypeIdentifierIntermenstrualBleeding | ✓ | | 35 | | SexualActivity | HKCategoryTypeIdentifierSexualActivity | ✓ | | 36 | 37 | ## License 38 | `skoal`use [__MIT license__][1] 39 | 40 | ## Usage 41 | - [You should get HealthKit privacy permission before you use 'skoal'](#index1) 42 | - [See the function by preview below](#index2) 43 | - [Start the project to see the example](./skoal-example) 44 | 45 | 46 | - Objective-C 47 | ``` 48 | [[skoal sharedInstance]requestHealthPermissionWithBlock:^(HealthStorePermissionResponse permissionResponse) { 49 | if (permissionResponse == HealthStorePermissionResponseError) { 50 | DLog(@"请求权限失败"); 51 | }else{ 52 | DLog(@"请求权限成功"); 53 | } 54 | }]; 55 | ``` 56 | - Swift 57 | ``` 58 | skoal.sharedInstance().requestHealthPermission { (response: HealthStorePermissionResponse) in 59 | if response == HealthStorePermissionResponse.error { 60 | print("请求失败") 61 | } else { 62 | print("请求成功") 63 | } 64 | } 65 | ``` 66 | 67 | 68 | func preview1 | func preview2 69 | ---------------|--------------- 70 | ![screenshot/func1.png](screenshot/func1.png) | ![screenshot/func2.png](screenshot/func2.png) 71 | 72 | 73 | [1]: https://github.com/GREENBANYAN/skoal/blob/master/LICENSE "MIT License" 74 | -------------------------------------------------------------------------------- /skoal/skoal.h: -------------------------------------------------------------------------------- 1 | // skoal.h 2 | // 3 | // Copyright (c) 2017 BANYAN 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import 24 | #import 25 | #import 26 | 27 | ///------------------------- 28 | #pragma mark - DEBUG 29 | ///------------------------- 30 | #ifdef DEBUG 31 | #define DLog(FORMAT, ...) fprintf(stderr, "%s [Line %zd]\t%s\n", [[[NSString stringWithUTF8String: __FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat: FORMAT, ## __VA_ARGS__] UTF8String]); 32 | #else 33 | #define DLog(FORMAT, ...) nil 34 | #endif 35 | 36 | 37 | typedef NS_ENUM(NSUInteger,HealthStorePermissionResponse) { 38 | HealthStorePermissionResponseError = 0, 39 | HealthStorePermissionResponseSuccess 40 | }; 41 | 42 | typedef void (^HealthStorePermissionResponseBlock)(HealthStorePermissionResponse permissionResponse); 43 | 44 | @interface skoal : NSObject 45 | @property (nonatomic,copy) HealthStorePermissionResponseBlock permissionResponseBlock; 46 | @property (nonatomic,strong) HKHealthStore *store; 47 | 48 | +(instancetype)sharedInstance; 49 | 50 | ///------------------------- 51 | #pragma mark - AccessPermission(获取权限) 52 | ///------------------------- 53 | -(void)requestHealthPermissionWithBlock:(HealthStorePermissionResponseBlock)block; 54 | 55 | 56 | ///------------------------- 57 | #pragma mark - StepCount(步数) 58 | ///------------------------- 59 | -(void)readStepCountFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 60 | -(void)readStepCountFromHealthStoreWithStartTime:(NSString *)startTime endTime:(NSString *)endTime completion:(void(^)(double value,NSError *error))completion; 61 | -(void)writeStepCountToHealthStoreWithUnit:(double)setpCount completion:(void(^)(BOOL response))completion; 62 | -(void)writeStepCountToHealthStoreWithUnit:(double)setpCount startTime:(NSString *)startTime endTime:(NSString *)endTime completion:(void(^)(BOOL response))completion; 63 | 64 | 65 | ///------------------------- 66 | #pragma mark - Height(身高) 67 | ///------------------------- 68 | -(void)readHeightFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 69 | -(void)writeHeightToHealthStoreWithUnit:(double)Height completion:(void(^)(BOOL response))completion; 70 | 71 | 72 | ///------------------------- 73 | #pragma mark - BodyMass(体重) 74 | ///------------------------- 75 | -(void)readBodyMassFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; /// kg 76 | -(void)writeBodyMassToHealthStoreWithUnit:(double)bodyMass completion:(void(^)(BOOL response))completion; 77 | 78 | 79 | ///------------------------- 80 | #pragma mark - BodyMassIndex(身体质量指数) 81 | ///------------------------- 82 | -(void)readBodyMassIndexFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 83 | -(void)writeBodyMassIndexToHealthStoreWithUnit:(double)bodyMassIndex completion:(void(^)(BOOL response))completion; 84 | 85 | 86 | ///------------------------- 87 | #pragma mark - DistanceWalkingRunning(步行+跑步距离) 88 | ///------------------------- 89 | -(void)readDistanceWalkingRunningFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 90 | -(void)writeDistanceWalkingRunningToHealthStoreWithUnit:(double)distanceWalkingRunning completion:(void(^)(BOOL response))completion; 91 | 92 | 93 | ///------------------------- 94 | #pragma mark - FlightsClimbed(以爬楼层) 95 | ///------------------------- 96 | -(void)readFlightsClimbedFromHealthStoreWithCompletion:(void(^)(NSInteger value,NSError *error))completion; 97 | -(void)writeFlightsClimbedToHealthStoreWithUnit:(NSInteger)flightsClimbed completion:(void(^)(BOOL response))completion; 98 | 99 | 100 | ///------------------------- 101 | #pragma mark - RespiratoryRate(呼吸速率) 102 | ///------------------------- 103 | -(void)readRespiratoryRateFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 104 | -(void)writeRespiratoryRateToHealthStoreWithUnit:(double)respiratoryRate completion:(void(^)(BOOL response))completion; 105 | 106 | 107 | ///------------------------- 108 | #pragma mark - DietaryEnergyConsumed(膳食能量消耗) 109 | ///------------------------- 110 | -(void)readDietaryEnergyConsumedFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 111 | -(void)writeDietaryEnergyConsumedToHealthStoreWithUnit:(double)dietaryEnergyConsumed completion:(void(^)(BOOL response))completion; 112 | 113 | 114 | ///------------------------- 115 | #pragma mark - OxygenSaturation(血氧饱和度) 116 | ///------------------------- 117 | -(void)readOxygenSaturationFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 118 | 119 | 120 | ///------------------------- 121 | #pragma mark - BodyTemperature(体温) 122 | ///------------------------- 123 | -(void)readBodyTemperatureFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 124 | -(void)writeBodyTemperatureToHealthStoreWithUnit:(double)bodyTemperature completion:(void(^)(BOOL response))completion; 125 | 126 | 127 | ///------------------------- 128 | #pragma mark - BloodGlucose(血糖) 129 | ///------------------------- 130 | -(void)readBloodGlucoseFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; /// mg/dl 131 | -(void)writeBloodGlucoseToHealthStoreWithUnit:(double)bloodGlucose completion:(void(^)(BOOL response))completion; 132 | 133 | ///------------------------- 134 | #pragma mark - BloodPressure(血压) 135 | ///------------------------- 136 | -(void)readBloodPressureSystolicFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 137 | -(void)writeBloodPressureSystolicToHealthStoreWithUnit:(double)bloodPressureSystolic completion:(void(^)(BOOL response))completion; 138 | -(void)readBloodPressureDiastolicFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 139 | -(void)writeBloodPressureDiastolicToHealthStoreWithUnit:(double)bloodPressureDiastolic completion:(void(^)(BOOL response))completion; 140 | 141 | 142 | ///------------------------- 143 | #pragma mark - StandHour(站立小时) 144 | ///------------------------- 145 | -(void)readStandHourFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 146 | 147 | 148 | ///------------------------- 149 | #pragma mark - BiologicalSex(性别) 150 | ///------------------------- 151 | -(void)readBiologicalSexFromHealthStoreWithCompletion:(void(^)(NSString *sex,NSError *error))completion; 152 | 153 | 154 | ///------------------------- 155 | #pragma mark - DateOfBirth(出生日期) 156 | ///------------------------- 157 | -(void)readDateOfBirthFromHealthStoreWithCompletion:(void(^)(NSDate *date,NSError *error))completion; 158 | 159 | 160 | ///------------------------- 161 | #pragma mark - BloodType(血型) 162 | ///------------------------- 163 | -(void)readBloodTypeFromHealthStoreWithCompletion:(void(^)(NSString *bloodType,NSError *error))completion; 164 | 165 | 166 | ///------------------------- 167 | #pragma mark - FitzpatrickSkin(日光反应型皮肤类型) 168 | ///------------------------- 169 | -(void)readFitzpatrickSkinFromHealthStoreWithCompletion:(void(^)(NSString *skinType,NSError *error))completion; 170 | 171 | 172 | ///------------------------- 173 | #pragma mark - SleepAnalysis(睡眠分析) 174 | ///------------------------- 175 | -(void)readSleepAnalysisFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 176 | 177 | 178 | ///------------------------- 179 | #pragma mark - MenstrualFlow(月经) 180 | ///------------------------- 181 | -(void)readMenstrualFlowFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 182 | 183 | 184 | ///------------------------- 185 | #pragma mark - IntermenstrualBleeding(点滴出血) 186 | ///------------------------- 187 | -(void)readIntermenstrualBleedingFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 188 | 189 | 190 | ///------------------------- 191 | #pragma mark - SexualActivity(性行为) 192 | ///------------------------- 193 | -(void)readSexualActivityFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 194 | 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /skoal-example/skoal-example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // skoal-example 4 | // 5 | // Created by BANYAN on 2017/11/17. 6 | // Copyright © 2017年 skoal. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource { 12 | 13 | let permission: [String] = ["请求权限"] 14 | let setpCount: [String] = ["读取当天总步数","读取一定时间段内的步数","写入当天总步数","写入一定时间段的步数"] 15 | let height: [String] = ["读取身高","写入身高"] 16 | let bodyMass: [String] = ["读取体重","写入体重"] 17 | let bodyMassIndex: [String] = ["读取身体质量指数","写入身体质量指数"] 18 | let distanceWalkingRunning: [String] = ["读取步行加跑步距离","写入步行加跑步距离"] 19 | let flightsClimbed: [String] = ["读取当天以爬楼层","写入当天以爬楼层"] 20 | let respiratoryRate: [String] = ["读取呼吸速率","写入呼吸速率"] 21 | let dietaryEnergyConsumed: [String] = ["读取膳食能量消耗","写入膳食能量消耗"] 22 | let oxygenSaturation: [String] = ["血氧饱和度"] 23 | let bodyTemperature: [String] = ["读取体温","写入体温"] 24 | let bloodGlucose: [String] = ["读取血糖","写入血糖"] 25 | let bloodPressure: [String] = ["读取血压收缩压","写入血压收缩压","读取血压舒张压","写入血压舒张压"] 26 | let standHour: [String] = ["读取当天站立小时"] 27 | let biologicalSex: [String] = ["读取性别"] 28 | let dateOfBirth: [String] = ["读取出生日期"] 29 | let bloodType: [String] = ["读取血型"] 30 | let fitzpatrickSkin: [String] = ["日光反应型皮肤类型"] 31 | let sleepAnalysis: [String] = ["读取睡眠分析"] 32 | let menstrualFlow: [String] = ["读取最近一次月经"] 33 | let intermenstrualBleeding: [String] = ["读取点滴出血"] 34 | let sexualActivity: [String] = ["读取最近一次性行为"] 35 | 36 | var alertText: String = String() 37 | 38 | var _tableView: UITableView! 39 | 40 | override func viewDidLoad() { 41 | super.viewDidLoad() 42 | 43 | self.view.backgroundColor = UIColor.white 44 | 45 | initUI() 46 | } 47 | 48 | 49 | ///------------------------- 50 | /// Objective-C请求权限示例 51 | ///------------------------- 52 | // [[skoal sharedInstance]requestHealthPermissionWithBlock:^(HealthStorePermissionResponse permissionResponse) { 53 | // if (permissionResponse == HealthStorePermissionResponseError) { 54 | // DLog(@"请求权限失败"); 55 | // }else{ 56 | // DLog(@"请求权限成功"); 57 | // } 58 | // }]; 59 | 60 | //MARK:UI 61 | func initUI() { 62 | _tableView = UITableView.init(frame:CGRect.init(x:0,y:0,width:self.view.frame.size.width,height:self.view.frame.size.height),style:UITableViewStyle.plain) 63 | _tableView.delegate = self 64 | _tableView.dataSource = self 65 | _tableView.showsVerticalScrollIndicator = false 66 | _tableView.tableFooterView = UIView.init() 67 | self.view.addSubview(_tableView) 68 | _tableView.register(UITableViewCell().classForCoder, forCellReuseIdentifier: "cellId") 69 | } 70 | 71 | //MARK:UITbleviewDelegate,UITableViewDataSource 72 | func numberOfSections(in tableView: UITableView) -> Int { 73 | return 22 74 | } 75 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 76 | switch section { 77 | case 0: 78 | return 1 79 | case 1: 80 | return 4 81 | case 2: 82 | return 2 83 | case 3: 84 | return 2 85 | case 4: 86 | return 2 87 | case 5: 88 | return 2 89 | case 6: 90 | return 2 91 | case 7: 92 | return 2 93 | case 8: 94 | return 2 95 | case 9: 96 | return 1 97 | case 10: 98 | return 2 99 | case 11: 100 | return 2 101 | case 12: 102 | return 4 103 | case 13: 104 | return 1 105 | case 14: 106 | return 1 107 | case 15: 108 | return 1 109 | case 16: 110 | return 1 111 | case 17: 112 | return 1 113 | case 18: 114 | return 1 115 | case 19: 116 | return 1 117 | case 20: 118 | return 1 119 | case 21: 120 | return 1 121 | default: 122 | return 0 123 | } 124 | } 125 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 126 | return 40 127 | } 128 | func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 129 | switch section { 130 | case 0: 131 | return "获取权限" 132 | case 1: 133 | return "步数" 134 | case 2: 135 | return "身高" 136 | case 3: 137 | return "体重" 138 | case 4: 139 | return "身体质量指数" 140 | case 5: 141 | return "步行+跑步距离" 142 | case 6: 143 | return "以爬楼层" 144 | case 7: 145 | return "呼吸速率" 146 | case 8: 147 | return "膳食能量消耗" 148 | case 9: 149 | return "血氧饱和度" 150 | case 10: 151 | return "体温" 152 | case 11: 153 | return "血糖" 154 | case 12: 155 | return "血压" 156 | case 13: 157 | return "站立小时" 158 | case 14: 159 | return "性别" 160 | case 15: 161 | return "出生日期" 162 | case 16: 163 | return "血型" 164 | case 17: 165 | return "日光反应型皮肤类型" 166 | case 18: 167 | return "睡眠分析" 168 | case 19: 169 | return "月经" 170 | case 20: 171 | return "点滴出血" 172 | case 21: 173 | return "性行为" 174 | default: 175 | return "" 176 | } 177 | } 178 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{ 179 | let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) 180 | 181 | if indexPath.section == 0 { 182 | cell.textLabel!.text = permission[indexPath.row] 183 | } else if indexPath.section == 1 { 184 | cell.textLabel!.text = setpCount[indexPath.row] 185 | } else if indexPath.section == 2 { 186 | cell.textLabel!.text = height[indexPath.row] 187 | } else if indexPath.section == 3 { 188 | cell.textLabel!.text = bodyMass[indexPath.row] 189 | } else if indexPath.section == 4 { 190 | cell.textLabel!.text = bodyMassIndex[indexPath.row] 191 | } else if indexPath.section == 5 { 192 | cell.textLabel!.text = distanceWalkingRunning[indexPath.row] 193 | } else if indexPath.section == 6 { 194 | cell.textLabel!.text = flightsClimbed[indexPath.row] 195 | } else if indexPath.section == 7 { 196 | cell.textLabel!.text = respiratoryRate[indexPath.row] 197 | } else if indexPath.section == 8 { 198 | cell.textLabel!.text = dietaryEnergyConsumed[indexPath.row] 199 | } else if indexPath.section == 9 { 200 | cell.textLabel!.text = oxygenSaturation[indexPath.row] 201 | } else if indexPath.section == 10 { 202 | cell.textLabel!.text = bodyTemperature[indexPath.row] 203 | } else if indexPath.section == 11 { 204 | cell.textLabel!.text = bloodGlucose[indexPath.row] 205 | } else if indexPath.section == 12 { 206 | cell.textLabel!.text = bloodPressure[indexPath.row] 207 | } else if indexPath.section == 13 { 208 | cell.textLabel!.text = standHour[indexPath.row] 209 | } else if indexPath.section == 14 { 210 | cell.textLabel!.text = biologicalSex[indexPath.row] 211 | } else if indexPath.section == 15 { 212 | cell.textLabel!.text = dateOfBirth[indexPath.row] 213 | } else if indexPath.section == 16 { 214 | cell.textLabel!.text = bloodType[indexPath.row] 215 | } else if indexPath.section == 17 { 216 | cell.textLabel!.text = fitzpatrickSkin[indexPath.row] 217 | } else if indexPath.section == 18 { 218 | cell.textLabel!.text = sleepAnalysis[indexPath.row] 219 | } else if indexPath.section == 19 { 220 | cell.textLabel!.text = menstrualFlow[indexPath.row] 221 | } else if indexPath.section == 20 { 222 | cell.textLabel!.text = intermenstrualBleeding[indexPath.row] 223 | } else if indexPath.section == 21 { 224 | cell.textLabel!.text = sexualActivity[indexPath.row] 225 | } 226 | 227 | cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 12) 228 | cell.textLabel?.textColor = UIColor.lightGray 229 | cell.selectionStyle = UITableViewCellSelectionStyle.default 230 | cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator 231 | 232 | return cell 233 | } 234 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 235 | switch indexPath.section { 236 | case 0: // AccessPermission(获取权限) 237 | if indexPath.row == 0 { 238 | skoal.sharedInstance().requestHealthPermission { (response: HealthStorePermissionResponse) in 239 | if response == HealthStorePermissionResponse.error { 240 | print("请求失败") 241 | } else { 242 | print("请求成功") 243 | } 244 | } 245 | } 246 | case 1: // StepCount(步数) 247 | if indexPath.row == 0 { 248 | skoal.sharedInstance().readStepCountFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 249 | print("\(value)\n\(error.debugDescription)") 250 | }) 251 | } else if indexPath.row == 1 { 252 | skoal.sharedInstance().readStepCountFromHealthStore(withStartTime: "2017-11-17 08:00", endTime: "2017-11-17 10:00", completion: { (_ value: Double, _ error: Error?) in 253 | print("\(value)\n\(error.debugDescription)") 254 | }) 255 | } else if indexPath.row == 2 { 256 | skoal.sharedInstance().writeStepCountToHealthStore(withUnit: 888, completion: { (_ response: Bool) in 257 | print(response) 258 | }) 259 | } else if indexPath.row == 3 { 260 | skoal.sharedInstance().writeStepCountToHealthStore(withUnit: 888, startTime: "2017-11-17 11:00", endTime: "2017-11-17 12:00", completion: { (_ response: Bool) in 261 | print(response) 262 | }) 263 | } 264 | case 2: // Height(身高) 265 | if indexPath.row == 0 { 266 | skoal.sharedInstance().readHeightFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 267 | print("\(value)\n\(error.debugDescription)") 268 | }) 269 | } else if indexPath.row == 1 { 270 | skoal.sharedInstance().writeHeightToHealthStore(withUnit: 1.80, completion: { (_ response: Bool) in 271 | print(response) 272 | }) 273 | } 274 | case 3: // BodyMass(体重) 275 | if indexPath.row == 0 { 276 | skoal.sharedInstance().readBodyMassFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 277 | print("\(value)\n\(error.debugDescription)") 278 | }) 279 | } else if indexPath.row == 1 { 280 | skoal.sharedInstance().writeBodyMassToHealthStore(withUnit: 70, completion: { (_ response: Bool) in 281 | print(response) 282 | }) 283 | } 284 | case 4: // BodyMassIndex(身体质量指数) 285 | if indexPath.row == 0 { 286 | skoal.sharedInstance().readBodyMassIndexFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 287 | print("\(value)\n\(error.debugDescription)") 288 | }) 289 | } else if indexPath.row == 1 { 290 | skoal.sharedInstance().writeBodyMassIndexToHealthStore(withUnit: 22, completion: { (_ response: Bool) in 291 | print(response) 292 | }) 293 | } 294 | case 5: // DistanceWalkingRunning(步行+跑步距离) 295 | if indexPath.row == 0 { 296 | skoal.sharedInstance().readDistanceWalkingRunningFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 297 | print("\(value)\n\(error.debugDescription)") 298 | }) 299 | } else if indexPath.row == 1 { 300 | skoal.sharedInstance().writeDistanceWalkingRunningToHealthStore(withUnit: 20.0, completion: { (_ response: Bool) in 301 | print(response) 302 | }) 303 | } 304 | case 6: //FlightsClimbed(以爬楼层) 305 | if indexPath.row == 0 { 306 | skoal.sharedInstance().readFlightsClimbedFromHealthStore(completion: { (_ flightsClimbed: NSInteger, _ error: Error?) in 307 | print("\(flightsClimbed)\n\(error.debugDescription)") 308 | }) 309 | } else if indexPath.row == 1 { 310 | skoal.sharedInstance().writeFlightsClimbedToHealthStore(withUnit: 23, completion: { (_ response: Bool) in 311 | print(response) 312 | }) 313 | } 314 | case 7: // RespiratoryRate(呼吸速率) 315 | if indexPath.row == 0 { 316 | skoal.sharedInstance().readRespiratoryRateFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 317 | print("\(value)\n\(error.debugDescription)") 318 | }) 319 | } else if indexPath.row == 1 { 320 | skoal.sharedInstance().writeRespiratoryRateToHealthStore(withUnit: 20.0, completion: { (_ response: Bool) in 321 | print(response) 322 | }) 323 | } 324 | case 8: // DietaryEnergyConsumed(膳食能量消耗) 325 | if indexPath.row == 0 { 326 | skoal.sharedInstance().readDietaryEnergyConsumedFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 327 | print("\(value)\n\(error.debugDescription)") 328 | }) 329 | } else if indexPath.row == 1 { 330 | skoal.sharedInstance().writeDietaryEnergyConsumedToHealthStore(withUnit: 22.2, completion: { (_ response: Bool) in 331 | print(response) 332 | }) 333 | } 334 | case 9: // OxygenSaturation(血氧饱和度) 335 | if indexPath.row == 0 { 336 | skoal.sharedInstance().readOxygenSaturationFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 337 | print("\(value)\n\(error.debugDescription)") 338 | }) 339 | } 340 | case 10: // BodyTemperature(体温) 341 | if indexPath.row == 0 { 342 | skoal.sharedInstance().readBodyTemperatureFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 343 | print("\(value)\n\(error.debugDescription)") 344 | }) 345 | } else if indexPath.row == 1 { 346 | skoal.sharedInstance().writeBodyTemperatureToHealthStore(withUnit: 35.0, completion: { (_ response: Bool) in 347 | print(response) 348 | }) 349 | } 350 | case 11: // BloodGlucose(血糖) 351 | if indexPath.row == 0 { 352 | skoal.sharedInstance().readBloodGlucoseFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 353 | print("\(value)\n\(error.debugDescription)") 354 | }) 355 | } else if indexPath.row == 1 { 356 | skoal.sharedInstance().writeBloodGlucoseToHealthStore(withUnit: 16.0, completion: { (_ response: Bool) in 357 | print(response) 358 | }) 359 | } 360 | case 12: // BloodPressure(血压) 361 | if indexPath.row == 0 { 362 | skoal.sharedInstance().readBloodPressureSystolicFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 363 | print("\(value)\n\(error.debugDescription)") 364 | }) 365 | } else if indexPath.row == 1 { 366 | skoal.sharedInstance().writeBloodPressureSystolicToHealthStore(withUnit: 65.0, completion: { (_ response: Bool) in 367 | print(response) 368 | }) 369 | } else if indexPath.row == 2 { 370 | skoal.sharedInstance().readBloodPressureDiastolicFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 371 | print("\(value)\n\(error.debugDescription)") 372 | }) 373 | } else if indexPath.row == 3 { 374 | skoal.sharedInstance().writeBloodPressureDiastolicToHealthStore(withUnit: 77.0, completion: { (_ response: Bool) in 375 | print(response) 376 | }) 377 | } 378 | case 13: // StandHour(站立小时) 379 | if indexPath.row == 0 { 380 | skoal.sharedInstance().readStandHourFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 381 | print("\(value)\n\(error.debugDescription)") 382 | }) 383 | } 384 | case 14: // BiologicalSex(性别) 385 | if indexPath.row == 0 { 386 | skoal.sharedInstance().readBiologicalSexFromHealthStore(completion: { (_ biologicalSex: String!, _ error: Error?) in 387 | print("\(biologicalSex)\n\(error.debugDescription)") 388 | }) 389 | } 390 | case 15: // DateOfBirth(出生日期) 391 | if indexPath.row == 0 { 392 | skoal.sharedInstance().readDateOfBirthFromHealthStore(completion: { (_ date: Date!, _ error: Error?) in 393 | print("\(date)\n\(error.debugDescription)") 394 | }) 395 | } 396 | case 16: // BloodType(血型) 397 | if indexPath.row == 0 { 398 | skoal.sharedInstance().readBloodTypeFromHealthStore(completion: { (_ bloodType: String!, _ error: Error?) in 399 | print("\(bloodType)\n\(error.debugDescription)") 400 | }) 401 | } 402 | case 17: // FitzpatrickSkin(日光反应型皮肤类型) 403 | if indexPath.row == 0 { 404 | skoal.sharedInstance().readFitzpatrickSkinFromHealthStore(completion: { (_ skinType: String!, _ error: Error?) in 405 | print("\(skinType)\n\(error.debugDescription)") 406 | }) 407 | } 408 | case 18: // SleepAnalysis(睡眠分析) 409 | if indexPath.row == 0 { 410 | skoal.sharedInstance().readSleepAnalysisFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 411 | print("\(value)\n\(error.debugDescription)") 412 | }) 413 | } 414 | case 19: // MenstrualFlow(月经) 415 | if indexPath.row == 0 { 416 | skoal.sharedInstance().readMenstrualFlowFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 417 | print("\(value)\n\(error.debugDescription)") 418 | }) 419 | } 420 | case 20: // IntermenstrualBleeding(点滴出血) 421 | if indexPath.row == 0 { 422 | skoal.sharedInstance().readIntermenstrualBleedingFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 423 | print("\(value)\n\(error.debugDescription)") 424 | }) 425 | } 426 | case 21: // SexualActivity(性行为) 427 | if indexPath.row == 0 { 428 | skoal.sharedInstance().readSexualActivityFromHealthStore(completion: { (_ value: Double, _ error: Error?) in 429 | print("\(value)\n\(error.debugDescription)") 430 | }) 431 | } 432 | default: 433 | print("") 434 | } 435 | _tableView.reloadData() 436 | } 437 | 438 | override func didReceiveMemoryWarning() { 439 | super.didReceiveMemoryWarning() 440 | // Dispose of any resources that can be recreated. 441 | } 442 | 443 | 444 | } 445 | 446 | -------------------------------------------------------------------------------- /skoal-example/skoal-example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 23DE147A1FBEB52A0010E36B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23DE14791FBEB52A0010E36B /* AppDelegate.swift */; }; 11 | 23DE147F1FBEB52A0010E36B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 23DE147D1FBEB52A0010E36B /* Main.storyboard */; }; 12 | 23DE14811FBEB52B0010E36B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 23DE14801FBEB52B0010E36B /* Assets.xcassets */; }; 13 | 23DE14841FBEB52B0010E36B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 23DE14821FBEB52B0010E36B /* LaunchScreen.storyboard */; }; 14 | 23DE148F1FBEB52B0010E36B /* skoal_exampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23DE148E1FBEB52B0010E36B /* skoal_exampleTests.swift */; }; 15 | 23DE149A1FBEB52B0010E36B /* skoal_exampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23DE14991FBEB52B0010E36B /* skoal_exampleUITests.swift */; }; 16 | 23DE14AC1FBEB5580010E36B /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23DE14AB1FBEB5580010E36B /* ViewController.swift */; }; 17 | 23DE14B71FBEB5F70010E36B /* skoal.m in Sources */ = {isa = PBXBuildFile; fileRef = 23DE14B61FBEB5F70010E36B /* skoal.m */; }; 18 | 23DE14BD1FBEB6EA0010E36B /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 23DE14BC1FBEB6EA0010E36B /* HealthKit.framework */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 23DE148B1FBEB52B0010E36B /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 23DE146E1FBEB52A0010E36B /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 23DE14751FBEB52A0010E36B; 27 | remoteInfo = "skoal-example"; 28 | }; 29 | 23DE14961FBEB52B0010E36B /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 23DE146E1FBEB52A0010E36B /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 23DE14751FBEB52A0010E36B; 34 | remoteInfo = "skoal-example"; 35 | }; 36 | /* End PBXContainerItemProxy section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 23DE14761FBEB52A0010E36B /* skoal-example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "skoal-example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 23DE14791FBEB52A0010E36B /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 41 | 23DE147E1FBEB52A0010E36B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 23DE14801FBEB52B0010E36B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 23DE14831FBEB52B0010E36B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 23DE14851FBEB52B0010E36B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | 23DE148A1FBEB52B0010E36B /* skoal-exampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "skoal-exampleTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 23DE148E1FBEB52B0010E36B /* skoal_exampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = skoal_exampleTests.swift; sourceTree = ""; }; 47 | 23DE14901FBEB52B0010E36B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 23DE14951FBEB52B0010E36B /* skoal-exampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "skoal-exampleUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 23DE14991FBEB52B0010E36B /* skoal_exampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = skoal_exampleUITests.swift; sourceTree = ""; }; 50 | 23DE149B1FBEB52B0010E36B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | 23DE14AB1FBEB5580010E36B /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 52 | 23DE14B01FBEB5EB0010E36B /* skoal-example-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "skoal-example-Bridging-Header.h"; sourceTree = ""; }; 53 | 23DE14B51FBEB5F70010E36B /* skoal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = skoal.h; sourceTree = ""; }; 54 | 23DE14B61FBEB5F70010E36B /* skoal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = skoal.m; sourceTree = ""; }; 55 | 23DE14BB1FBEB6C00010E36B /* skoal-example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "skoal-example.entitlements"; sourceTree = ""; }; 56 | 23DE14BC1FBEB6EA0010E36B /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | 23DE14731FBEB52A0010E36B /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | 23DE14BD1FBEB6EA0010E36B /* HealthKit.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | 23DE14871FBEB52B0010E36B /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | 23DE14921FBEB52B0010E36B /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXFrameworksBuildPhase section */ 83 | 84 | /* Begin PBXGroup section */ 85 | 23DE146D1FBEB52A0010E36B = { 86 | isa = PBXGroup; 87 | children = ( 88 | 23DE14B41FBEB5F70010E36B /* skoal */, 89 | 23DE14781FBEB52A0010E36B /* skoal-example */, 90 | 23DE148D1FBEB52B0010E36B /* skoal-exampleTests */, 91 | 23DE14981FBEB52B0010E36B /* skoal-exampleUITests */, 92 | 23DE14771FBEB52A0010E36B /* Products */, 93 | 23DE14B81FBEB6C00010E36B /* Frameworks */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | 23DE14771FBEB52A0010E36B /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 23DE14761FBEB52A0010E36B /* skoal-example.app */, 101 | 23DE148A1FBEB52B0010E36B /* skoal-exampleTests.xctest */, 102 | 23DE14951FBEB52B0010E36B /* skoal-exampleUITests.xctest */, 103 | ); 104 | name = Products; 105 | sourceTree = ""; 106 | }; 107 | 23DE14781FBEB52A0010E36B /* skoal-example */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 23DE14BB1FBEB6C00010E36B /* skoal-example.entitlements */, 111 | 23DE14791FBEB52A0010E36B /* AppDelegate.swift */, 112 | 23DE14AB1FBEB5580010E36B /* ViewController.swift */, 113 | 23DE147D1FBEB52A0010E36B /* Main.storyboard */, 114 | 23DE14801FBEB52B0010E36B /* Assets.xcassets */, 115 | 23DE14821FBEB52B0010E36B /* LaunchScreen.storyboard */, 116 | 23DE14851FBEB52B0010E36B /* Info.plist */, 117 | 23DE14B01FBEB5EB0010E36B /* skoal-example-Bridging-Header.h */, 118 | ); 119 | path = "skoal-example"; 120 | sourceTree = ""; 121 | }; 122 | 23DE148D1FBEB52B0010E36B /* skoal-exampleTests */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 23DE148E1FBEB52B0010E36B /* skoal_exampleTests.swift */, 126 | 23DE14901FBEB52B0010E36B /* Info.plist */, 127 | ); 128 | path = "skoal-exampleTests"; 129 | sourceTree = ""; 130 | }; 131 | 23DE14981FBEB52B0010E36B /* skoal-exampleUITests */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 23DE14991FBEB52B0010E36B /* skoal_exampleUITests.swift */, 135 | 23DE149B1FBEB52B0010E36B /* Info.plist */, 136 | ); 137 | path = "skoal-exampleUITests"; 138 | sourceTree = ""; 139 | }; 140 | 23DE14B41FBEB5F70010E36B /* skoal */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 23DE14B51FBEB5F70010E36B /* skoal.h */, 144 | 23DE14B61FBEB5F70010E36B /* skoal.m */, 145 | ); 146 | name = skoal; 147 | path = ../skoal; 148 | sourceTree = ""; 149 | }; 150 | 23DE14B81FBEB6C00010E36B /* Frameworks */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 23DE14BC1FBEB6EA0010E36B /* HealthKit.framework */, 154 | ); 155 | name = Frameworks; 156 | sourceTree = ""; 157 | }; 158 | /* End PBXGroup section */ 159 | 160 | /* Begin PBXNativeTarget section */ 161 | 23DE14751FBEB52A0010E36B /* skoal-example */ = { 162 | isa = PBXNativeTarget; 163 | buildConfigurationList = 23DE149E1FBEB52B0010E36B /* Build configuration list for PBXNativeTarget "skoal-example" */; 164 | buildPhases = ( 165 | 23DE14721FBEB52A0010E36B /* Sources */, 166 | 23DE14731FBEB52A0010E36B /* Frameworks */, 167 | 23DE14741FBEB52A0010E36B /* Resources */, 168 | ); 169 | buildRules = ( 170 | ); 171 | dependencies = ( 172 | ); 173 | name = "skoal-example"; 174 | productName = "skoal-example"; 175 | productReference = 23DE14761FBEB52A0010E36B /* skoal-example.app */; 176 | productType = "com.apple.product-type.application"; 177 | }; 178 | 23DE14891FBEB52B0010E36B /* skoal-exampleTests */ = { 179 | isa = PBXNativeTarget; 180 | buildConfigurationList = 23DE14A11FBEB52B0010E36B /* Build configuration list for PBXNativeTarget "skoal-exampleTests" */; 181 | buildPhases = ( 182 | 23DE14861FBEB52B0010E36B /* Sources */, 183 | 23DE14871FBEB52B0010E36B /* Frameworks */, 184 | 23DE14881FBEB52B0010E36B /* Resources */, 185 | ); 186 | buildRules = ( 187 | ); 188 | dependencies = ( 189 | 23DE148C1FBEB52B0010E36B /* PBXTargetDependency */, 190 | ); 191 | name = "skoal-exampleTests"; 192 | productName = "skoal-exampleTests"; 193 | productReference = 23DE148A1FBEB52B0010E36B /* skoal-exampleTests.xctest */; 194 | productType = "com.apple.product-type.bundle.unit-test"; 195 | }; 196 | 23DE14941FBEB52B0010E36B /* skoal-exampleUITests */ = { 197 | isa = PBXNativeTarget; 198 | buildConfigurationList = 23DE14A41FBEB52B0010E36B /* Build configuration list for PBXNativeTarget "skoal-exampleUITests" */; 199 | buildPhases = ( 200 | 23DE14911FBEB52B0010E36B /* Sources */, 201 | 23DE14921FBEB52B0010E36B /* Frameworks */, 202 | 23DE14931FBEB52B0010E36B /* Resources */, 203 | ); 204 | buildRules = ( 205 | ); 206 | dependencies = ( 207 | 23DE14971FBEB52B0010E36B /* PBXTargetDependency */, 208 | ); 209 | name = "skoal-exampleUITests"; 210 | productName = "skoal-exampleUITests"; 211 | productReference = 23DE14951FBEB52B0010E36B /* skoal-exampleUITests.xctest */; 212 | productType = "com.apple.product-type.bundle.ui-testing"; 213 | }; 214 | /* End PBXNativeTarget section */ 215 | 216 | /* Begin PBXProject section */ 217 | 23DE146E1FBEB52A0010E36B /* Project object */ = { 218 | isa = PBXProject; 219 | attributes = { 220 | LastSwiftUpdateCheck = 0910; 221 | LastUpgradeCheck = 0910; 222 | ORGANIZATIONNAME = skoal; 223 | TargetAttributes = { 224 | 23DE14751FBEB52A0010E36B = { 225 | CreatedOnToolsVersion = 9.1; 226 | LastSwiftMigration = 0910; 227 | ProvisioningStyle = Automatic; 228 | SystemCapabilities = { 229 | com.apple.HealthKit = { 230 | enabled = 1; 231 | }; 232 | }; 233 | }; 234 | 23DE14891FBEB52B0010E36B = { 235 | CreatedOnToolsVersion = 9.1; 236 | ProvisioningStyle = Automatic; 237 | TestTargetID = 23DE14751FBEB52A0010E36B; 238 | }; 239 | 23DE14941FBEB52B0010E36B = { 240 | CreatedOnToolsVersion = 9.1; 241 | ProvisioningStyle = Automatic; 242 | TestTargetID = 23DE14751FBEB52A0010E36B; 243 | }; 244 | }; 245 | }; 246 | buildConfigurationList = 23DE14711FBEB52A0010E36B /* Build configuration list for PBXProject "skoal-example" */; 247 | compatibilityVersion = "Xcode 8.0"; 248 | developmentRegion = en; 249 | hasScannedForEncodings = 0; 250 | knownRegions = ( 251 | en, 252 | Base, 253 | ); 254 | mainGroup = 23DE146D1FBEB52A0010E36B; 255 | productRefGroup = 23DE14771FBEB52A0010E36B /* Products */; 256 | projectDirPath = ""; 257 | projectRoot = ""; 258 | targets = ( 259 | 23DE14751FBEB52A0010E36B /* skoal-example */, 260 | 23DE14891FBEB52B0010E36B /* skoal-exampleTests */, 261 | 23DE14941FBEB52B0010E36B /* skoal-exampleUITests */, 262 | ); 263 | }; 264 | /* End PBXProject section */ 265 | 266 | /* Begin PBXResourcesBuildPhase section */ 267 | 23DE14741FBEB52A0010E36B /* Resources */ = { 268 | isa = PBXResourcesBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | 23DE14841FBEB52B0010E36B /* LaunchScreen.storyboard in Resources */, 272 | 23DE14811FBEB52B0010E36B /* Assets.xcassets in Resources */, 273 | 23DE147F1FBEB52A0010E36B /* Main.storyboard in Resources */, 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | }; 277 | 23DE14881FBEB52B0010E36B /* Resources */ = { 278 | isa = PBXResourcesBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | 23DE14931FBEB52B0010E36B /* Resources */ = { 285 | isa = PBXResourcesBuildPhase; 286 | buildActionMask = 2147483647; 287 | files = ( 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | }; 291 | /* End PBXResourcesBuildPhase section */ 292 | 293 | /* Begin PBXSourcesBuildPhase section */ 294 | 23DE14721FBEB52A0010E36B /* Sources */ = { 295 | isa = PBXSourcesBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | 23DE14B71FBEB5F70010E36B /* skoal.m in Sources */, 299 | 23DE14AC1FBEB5580010E36B /* ViewController.swift in Sources */, 300 | 23DE147A1FBEB52A0010E36B /* AppDelegate.swift in Sources */, 301 | ); 302 | runOnlyForDeploymentPostprocessing = 0; 303 | }; 304 | 23DE14861FBEB52B0010E36B /* Sources */ = { 305 | isa = PBXSourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | 23DE148F1FBEB52B0010E36B /* skoal_exampleTests.swift in Sources */, 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | 23DE14911FBEB52B0010E36B /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | 23DE149A1FBEB52B0010E36B /* skoal_exampleUITests.swift in Sources */, 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | }; 320 | /* End PBXSourcesBuildPhase section */ 321 | 322 | /* Begin PBXTargetDependency section */ 323 | 23DE148C1FBEB52B0010E36B /* PBXTargetDependency */ = { 324 | isa = PBXTargetDependency; 325 | target = 23DE14751FBEB52A0010E36B /* skoal-example */; 326 | targetProxy = 23DE148B1FBEB52B0010E36B /* PBXContainerItemProxy */; 327 | }; 328 | 23DE14971FBEB52B0010E36B /* PBXTargetDependency */ = { 329 | isa = PBXTargetDependency; 330 | target = 23DE14751FBEB52A0010E36B /* skoal-example */; 331 | targetProxy = 23DE14961FBEB52B0010E36B /* PBXContainerItemProxy */; 332 | }; 333 | /* End PBXTargetDependency section */ 334 | 335 | /* Begin PBXVariantGroup section */ 336 | 23DE147D1FBEB52A0010E36B /* Main.storyboard */ = { 337 | isa = PBXVariantGroup; 338 | children = ( 339 | 23DE147E1FBEB52A0010E36B /* Base */, 340 | ); 341 | name = Main.storyboard; 342 | sourceTree = ""; 343 | }; 344 | 23DE14821FBEB52B0010E36B /* LaunchScreen.storyboard */ = { 345 | isa = PBXVariantGroup; 346 | children = ( 347 | 23DE14831FBEB52B0010E36B /* Base */, 348 | ); 349 | name = LaunchScreen.storyboard; 350 | sourceTree = ""; 351 | }; 352 | /* End PBXVariantGroup section */ 353 | 354 | /* Begin XCBuildConfiguration section */ 355 | 23DE149C1FBEB52B0010E36B /* Debug */ = { 356 | isa = XCBuildConfiguration; 357 | buildSettings = { 358 | ALWAYS_SEARCH_USER_PATHS = NO; 359 | CLANG_ANALYZER_NONNULL = YES; 360 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 361 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 362 | CLANG_CXX_LIBRARY = "libc++"; 363 | CLANG_ENABLE_MODULES = YES; 364 | CLANG_ENABLE_OBJC_ARC = YES; 365 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 366 | CLANG_WARN_BOOL_CONVERSION = YES; 367 | CLANG_WARN_COMMA = YES; 368 | CLANG_WARN_CONSTANT_CONVERSION = YES; 369 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 370 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 371 | CLANG_WARN_EMPTY_BODY = YES; 372 | CLANG_WARN_ENUM_CONVERSION = YES; 373 | CLANG_WARN_INFINITE_RECURSION = YES; 374 | CLANG_WARN_INT_CONVERSION = YES; 375 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 376 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 377 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 378 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 379 | CLANG_WARN_STRICT_PROTOTYPES = YES; 380 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 381 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 382 | CLANG_WARN_UNREACHABLE_CODE = YES; 383 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 384 | CODE_SIGN_IDENTITY = "iPhone Developer"; 385 | COPY_PHASE_STRIP = NO; 386 | DEBUG_INFORMATION_FORMAT = dwarf; 387 | ENABLE_STRICT_OBJC_MSGSEND = YES; 388 | ENABLE_TESTABILITY = YES; 389 | GCC_C_LANGUAGE_STANDARD = gnu11; 390 | GCC_DYNAMIC_NO_PIC = NO; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_OPTIMIZATION_LEVEL = 0; 393 | GCC_PREPROCESSOR_DEFINITIONS = ( 394 | "DEBUG=1", 395 | "$(inherited)", 396 | ); 397 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 398 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 399 | GCC_WARN_UNDECLARED_SELECTOR = YES; 400 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 401 | GCC_WARN_UNUSED_FUNCTION = YES; 402 | GCC_WARN_UNUSED_VARIABLE = YES; 403 | IPHONEOS_DEPLOYMENT_TARGET = 11.1; 404 | MTL_ENABLE_DEBUG_INFO = YES; 405 | ONLY_ACTIVE_ARCH = YES; 406 | SDKROOT = iphoneos; 407 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 408 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 409 | }; 410 | name = Debug; 411 | }; 412 | 23DE149D1FBEB52B0010E36B /* Release */ = { 413 | isa = XCBuildConfiguration; 414 | buildSettings = { 415 | ALWAYS_SEARCH_USER_PATHS = NO; 416 | CLANG_ANALYZER_NONNULL = YES; 417 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 418 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 419 | CLANG_CXX_LIBRARY = "libc++"; 420 | CLANG_ENABLE_MODULES = YES; 421 | CLANG_ENABLE_OBJC_ARC = YES; 422 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 423 | CLANG_WARN_BOOL_CONVERSION = YES; 424 | CLANG_WARN_COMMA = YES; 425 | CLANG_WARN_CONSTANT_CONVERSION = YES; 426 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 427 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 428 | CLANG_WARN_EMPTY_BODY = YES; 429 | CLANG_WARN_ENUM_CONVERSION = YES; 430 | CLANG_WARN_INFINITE_RECURSION = YES; 431 | CLANG_WARN_INT_CONVERSION = YES; 432 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 433 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 434 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 435 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 436 | CLANG_WARN_STRICT_PROTOTYPES = YES; 437 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 438 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 439 | CLANG_WARN_UNREACHABLE_CODE = YES; 440 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 441 | CODE_SIGN_IDENTITY = "iPhone Developer"; 442 | COPY_PHASE_STRIP = NO; 443 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 444 | ENABLE_NS_ASSERTIONS = NO; 445 | ENABLE_STRICT_OBJC_MSGSEND = YES; 446 | GCC_C_LANGUAGE_STANDARD = gnu11; 447 | GCC_NO_COMMON_BLOCKS = YES; 448 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 449 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 450 | GCC_WARN_UNDECLARED_SELECTOR = YES; 451 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 452 | GCC_WARN_UNUSED_FUNCTION = YES; 453 | GCC_WARN_UNUSED_VARIABLE = YES; 454 | IPHONEOS_DEPLOYMENT_TARGET = 11.1; 455 | MTL_ENABLE_DEBUG_INFO = NO; 456 | SDKROOT = iphoneos; 457 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 458 | VALIDATE_PRODUCT = YES; 459 | }; 460 | name = Release; 461 | }; 462 | 23DE149F1FBEB52B0010E36B /* Debug */ = { 463 | isa = XCBuildConfiguration; 464 | buildSettings = { 465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 466 | CLANG_ENABLE_MODULES = YES; 467 | CODE_SIGN_ENTITLEMENTS = "skoal-example/skoal-example.entitlements"; 468 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 469 | CODE_SIGN_STYLE = Automatic; 470 | DEVELOPMENT_TEAM = 49BQNS38WU; 471 | INFOPLIST_FILE = "skoal-example/Info.plist"; 472 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 473 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 474 | PRODUCT_BUNDLE_IDENTIFIER = "com.BANYAN.skoal-example"; 475 | PRODUCT_NAME = "$(TARGET_NAME)"; 476 | PROVISIONING_PROFILE_SPECIFIER = ""; 477 | SWIFT_OBJC_BRIDGING_HEADER = "skoal-example/skoal-example-Bridging-Header.h"; 478 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 479 | SWIFT_VERSION = 4.0; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | }; 482 | name = Debug; 483 | }; 484 | 23DE14A01FBEB52B0010E36B /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 488 | CLANG_ENABLE_MODULES = YES; 489 | CODE_SIGN_ENTITLEMENTS = "skoal-example/skoal-example.entitlements"; 490 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 491 | CODE_SIGN_STYLE = Automatic; 492 | DEVELOPMENT_TEAM = 49BQNS38WU; 493 | INFOPLIST_FILE = "skoal-example/Info.plist"; 494 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 495 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 496 | PRODUCT_BUNDLE_IDENTIFIER = "com.BANYAN.skoal-example"; 497 | PRODUCT_NAME = "$(TARGET_NAME)"; 498 | PROVISIONING_PROFILE_SPECIFIER = ""; 499 | SWIFT_OBJC_BRIDGING_HEADER = "skoal-example/skoal-example-Bridging-Header.h"; 500 | SWIFT_VERSION = 4.0; 501 | TARGETED_DEVICE_FAMILY = "1,2"; 502 | }; 503 | name = Release; 504 | }; 505 | 23DE14A21FBEB52B0010E36B /* Debug */ = { 506 | isa = XCBuildConfiguration; 507 | buildSettings = { 508 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 509 | BUNDLE_LOADER = "$(TEST_HOST)"; 510 | CODE_SIGN_STYLE = Automatic; 511 | INFOPLIST_FILE = "skoal-exampleTests/Info.plist"; 512 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 513 | PRODUCT_BUNDLE_IDENTIFIER = "BANYAN.skoal-exampleTests"; 514 | PRODUCT_NAME = "$(TARGET_NAME)"; 515 | SWIFT_VERSION = 4.0; 516 | TARGETED_DEVICE_FAMILY = "1,2"; 517 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/skoal-example.app/skoal-example"; 518 | }; 519 | name = Debug; 520 | }; 521 | 23DE14A31FBEB52B0010E36B /* Release */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 525 | BUNDLE_LOADER = "$(TEST_HOST)"; 526 | CODE_SIGN_STYLE = Automatic; 527 | INFOPLIST_FILE = "skoal-exampleTests/Info.plist"; 528 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 529 | PRODUCT_BUNDLE_IDENTIFIER = "BANYAN.skoal-exampleTests"; 530 | PRODUCT_NAME = "$(TARGET_NAME)"; 531 | SWIFT_VERSION = 4.0; 532 | TARGETED_DEVICE_FAMILY = "1,2"; 533 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/skoal-example.app/skoal-example"; 534 | }; 535 | name = Release; 536 | }; 537 | 23DE14A51FBEB52B0010E36B /* Debug */ = { 538 | isa = XCBuildConfiguration; 539 | buildSettings = { 540 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 541 | CODE_SIGN_STYLE = Automatic; 542 | INFOPLIST_FILE = "skoal-exampleUITests/Info.plist"; 543 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 544 | PRODUCT_BUNDLE_IDENTIFIER = "BANYAN.skoal-exampleUITests"; 545 | PRODUCT_NAME = "$(TARGET_NAME)"; 546 | SWIFT_VERSION = 4.0; 547 | TARGETED_DEVICE_FAMILY = "1,2"; 548 | TEST_TARGET_NAME = "skoal-example"; 549 | }; 550 | name = Debug; 551 | }; 552 | 23DE14A61FBEB52B0010E36B /* Release */ = { 553 | isa = XCBuildConfiguration; 554 | buildSettings = { 555 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 556 | CODE_SIGN_STYLE = Automatic; 557 | INFOPLIST_FILE = "skoal-exampleUITests/Info.plist"; 558 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 559 | PRODUCT_BUNDLE_IDENTIFIER = "BANYAN.skoal-exampleUITests"; 560 | PRODUCT_NAME = "$(TARGET_NAME)"; 561 | SWIFT_VERSION = 4.0; 562 | TARGETED_DEVICE_FAMILY = "1,2"; 563 | TEST_TARGET_NAME = "skoal-example"; 564 | }; 565 | name = Release; 566 | }; 567 | /* End XCBuildConfiguration section */ 568 | 569 | /* Begin XCConfigurationList section */ 570 | 23DE14711FBEB52A0010E36B /* Build configuration list for PBXProject "skoal-example" */ = { 571 | isa = XCConfigurationList; 572 | buildConfigurations = ( 573 | 23DE149C1FBEB52B0010E36B /* Debug */, 574 | 23DE149D1FBEB52B0010E36B /* Release */, 575 | ); 576 | defaultConfigurationIsVisible = 0; 577 | defaultConfigurationName = Release; 578 | }; 579 | 23DE149E1FBEB52B0010E36B /* Build configuration list for PBXNativeTarget "skoal-example" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | 23DE149F1FBEB52B0010E36B /* Debug */, 583 | 23DE14A01FBEB52B0010E36B /* Release */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | 23DE14A11FBEB52B0010E36B /* Build configuration list for PBXNativeTarget "skoal-exampleTests" */ = { 589 | isa = XCConfigurationList; 590 | buildConfigurations = ( 591 | 23DE14A21FBEB52B0010E36B /* Debug */, 592 | 23DE14A31FBEB52B0010E36B /* Release */, 593 | ); 594 | defaultConfigurationIsVisible = 0; 595 | defaultConfigurationName = Release; 596 | }; 597 | 23DE14A41FBEB52B0010E36B /* Build configuration list for PBXNativeTarget "skoal-exampleUITests" */ = { 598 | isa = XCConfigurationList; 599 | buildConfigurations = ( 600 | 23DE14A51FBEB52B0010E36B /* Debug */, 601 | 23DE14A61FBEB52B0010E36B /* Release */, 602 | ); 603 | defaultConfigurationIsVisible = 0; 604 | defaultConfigurationName = Release; 605 | }; 606 | /* End XCConfigurationList section */ 607 | }; 608 | rootObject = 23DE146E1FBEB52A0010E36B /* Project object */; 609 | } 610 | -------------------------------------------------------------------------------- /skoal/skoal.m: -------------------------------------------------------------------------------- 1 | // skoal.m 2 | // 3 | // Copyright (c) 2017 BANYAN 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import "skoal.h" 24 | 25 | static skoal *_instance = nil; 26 | 27 | @implementation skoal 28 | 29 | +(instancetype)sharedInstance{ 30 | static dispatch_once_t onceToken; 31 | dispatch_once(&onceToken, ^{ 32 | _instance = [[self alloc] init]; 33 | }); 34 | return _instance; 35 | } 36 | +(instancetype)allocWithZone:(struct _NSZone *)zone{ 37 | static dispatch_once_t onceToken; 38 | dispatch_once(&onceToken, ^{ 39 | _instance = [super allocWithZone:zone]; 40 | }); 41 | return _instance; 42 | } 43 | +(instancetype)copyWithZone:(nullable NSZone *)zone{ 44 | return _instance; 45 | } 46 | 47 | -(instancetype)init{ 48 | if (self = [super init]) { 49 | self.store = [[HKHealthStore alloc] init]; 50 | } 51 | return self; 52 | } 53 | 54 | 55 | ///------------------------- 56 | #pragma mark - 获取权限 57 | ///------------------------- 58 | -(void)requestHealthPermissionWithBlock:(HealthStorePermissionResponseBlock)block 59 | { 60 | if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 8.0) { 61 | if (![HKHealthStore isHealthDataAvailable]) { 62 | DLog(@"skoal:该设备不支持HealthKit"); 63 | }else{ 64 | HKHealthStore *store = [[HKHealthStore alloc] init]; 65 | NSSet *readObjectTypes = [self readObjectTypes]; 66 | NSSet *writeObjectTypes = [self writeObjectTypes]; 67 | [store requestAuthorizationToShareTypes:writeObjectTypes readTypes:readObjectTypes completion:^(BOOL success, NSError * _Nullable error) { 68 | if (success == YES) { 69 | block(HealthStorePermissionResponseSuccess); 70 | }else{ 71 | block(HealthStorePermissionResponseError); 72 | } 73 | }]; 74 | } 75 | }else{ 76 | DLog(@"skoal:HealthKit暂不支持iOS8以下系统,请更新你的系统。"); 77 | } 78 | } 79 | 80 | 81 | ///------------------------- 82 | #pragma mark - 步数 83 | ///------------------------- 84 | -(void)readStepCountFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion; 85 | { 86 | HKSampleType *stepCountType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; 87 | 88 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 89 | 90 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 91 | 92 | NSPredicate *predicate = [self predicateSampleByToday]; 93 | 94 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:stepCountType predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 95 | 96 | double sum = 0; 97 | for (HKQuantitySample *sample in results) { 98 | sum += [[[NSString stringWithFormat:@"%@",sample.quantity] componentsSeparatedByString:@" "][0] doubleValue]; 99 | } 100 | 101 | completion(sum,error); 102 | }]; 103 | 104 | [self.store executeQuery:query]; 105 | } 106 | -(void)readStepCountFromHealthStoreWithStartTime:(NSString *)startTime endTime:(NSString *)endTime completion:(void(^)(double value,NSError *error))completion 107 | { 108 | HKSampleType *stepCountType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; 109 | 110 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 111 | 112 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 113 | 114 | NSPredicate *predicate = [self predicateSampleByPeriodOfTimeWithStartTime:startTime endTime:endTime]; 115 | 116 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:stepCountType predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 117 | 118 | double sum = 0; 119 | for (HKQuantitySample *sample in results) { 120 | sum += [[[NSString stringWithFormat:@"%@",sample.quantity] componentsSeparatedByString:@" "][0] doubleValue]; 121 | } 122 | 123 | completion(sum,error); 124 | }]; 125 | 126 | [self.store executeQuery:query]; 127 | } 128 | -(void)writeStepCountToHealthStoreWithUnit:(double)setpCount completion:(void(^)(BOOL response))completion 129 | { 130 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; 131 | 132 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit countUnit] doubleValue:setpCount]; 133 | 134 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 135 | 136 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 137 | if (success) { 138 | completion(YES); 139 | }else { 140 | completion(NO); 141 | } 142 | }]; 143 | } 144 | -(void)writeStepCountToHealthStoreWithUnit:(double)setpCount startTime:(NSString *)startTime endTime:(NSString *)endTime completion:(void(^)(BOOL response))completion 145 | { 146 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; 147 | 148 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit countUnit] doubleValue:setpCount]; 149 | 150 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 151 | [formatter setDateFormat:@"yyyy-MM-dd HH:mm"]; 152 | formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]; 153 | 154 | NSDate *newStartDate = [formatter dateFromString:startTime]; 155 | NSDate *newEndDate = [formatter dateFromString:endTime]; 156 | 157 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:newStartDate endDate:newEndDate metadata:nil]; 158 | 159 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 160 | if (success) { 161 | completion(YES); 162 | }else { 163 | completion(NO); 164 | } 165 | }]; 166 | } 167 | 168 | 169 | ///------------------------- 170 | #pragma mark - 身高 171 | ///------------------------- 172 | -(void)readHeightFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 173 | { 174 | HKSampleType *heightType = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight]; 175 | 176 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 177 | 178 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 179 | 180 | NSPredicate *predicate = [self predicateSampleByLatestData]; 181 | 182 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:heightType predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 183 | 184 | double height = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 185 | 186 | completion(height,error); 187 | }]; 188 | 189 | [self.store executeQuery:query]; 190 | } 191 | -(void)writeHeightToHealthStoreWithUnit:(double)Height completion:(void(^)(BOOL response))completion 192 | { 193 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight]; 194 | 195 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit meterUnit] doubleValue:Height]; 196 | 197 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 198 | 199 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 200 | if (success) { 201 | completion(YES); 202 | }else { 203 | completion(NO); 204 | } 205 | }]; 206 | } 207 | 208 | 209 | ///------------------------- 210 | #pragma mark - 体重 211 | ///------------------------- 212 | -(void)readBodyMassFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 213 | { 214 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; 215 | 216 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 217 | 218 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 219 | 220 | NSPredicate *predicate = [self predicateSampleByLatestData]; 221 | 222 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 223 | 224 | double bodyMass = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 225 | 226 | completion(bodyMass,error); 227 | }]; 228 | 229 | [self.store executeQuery:query]; 230 | } 231 | -(void)writeBodyMassToHealthStoreWithUnit:(double)bodyMass completion:(void(^)(BOOL response))completion 232 | { 233 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; 234 | 235 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit gramUnit] doubleValue:bodyMass * 1000]; 236 | 237 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 238 | 239 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 240 | if (success) { 241 | completion(YES); 242 | }else { 243 | completion(NO); 244 | } 245 | }]; 246 | } 247 | 248 | 249 | ///------------------------- 250 | #pragma mark - 身体质量指数 251 | ///------------------------- 252 | -(void)readBodyMassIndexFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 253 | { 254 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMassIndex]; 255 | 256 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 257 | 258 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 259 | 260 | NSPredicate *predicate = [self predicateSampleByLatestData]; 261 | 262 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 263 | 264 | double bodyMassIndex = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 265 | 266 | completion(bodyMassIndex,error); 267 | }]; 268 | 269 | [self.store executeQuery:query]; 270 | } 271 | -(void)writeBodyMassIndexToHealthStoreWithUnit:(double)bodyMassIndex completion:(void(^)(BOOL response))completion 272 | { 273 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMassIndex]; 274 | 275 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit countUnit] doubleValue:bodyMassIndex]; 276 | 277 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 278 | 279 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 280 | if (success) { 281 | completion(YES); 282 | }else { 283 | completion(NO); 284 | } 285 | }]; 286 | } 287 | 288 | 289 | ///------------------------- 290 | #pragma mark - 步行&跑步距离 291 | ///------------------------- 292 | -(void)readDistanceWalkingRunningFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 293 | { 294 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; 295 | 296 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 297 | 298 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 299 | 300 | NSPredicate *predicate = [self predicateSampleByToday]; 301 | 302 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 303 | 304 | double distanceWalkingRunning = 0; 305 | for (HKQuantitySample *sample in results) { 306 | distanceWalkingRunning += [[[NSString stringWithFormat:@"%@",sample.quantity] componentsSeparatedByString:@" "][0] doubleValue]; 307 | } 308 | 309 | completion(distanceWalkingRunning / 1000,error); 310 | }]; 311 | 312 | [self.store executeQuery:query]; 313 | } 314 | -(void)writeDistanceWalkingRunningToHealthStoreWithUnit:(double)distanceWalkingRunning completion:(void(^)(BOOL response))completion 315 | { 316 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; 317 | 318 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit meterUnit] doubleValue:distanceWalkingRunning * 1000]; 319 | 320 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 321 | 322 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 323 | if (success) { 324 | completion(YES); 325 | }else { 326 | completion(NO); 327 | } 328 | }]; 329 | } 330 | 331 | 332 | ///------------------------- 333 | #pragma mark - 以爬楼层 334 | ///------------------------- 335 | -(void)readFlightsClimbedFromHealthStoreWithCompletion:(void(^)(NSInteger value,NSError *error))completion 336 | { 337 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed]; 338 | 339 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 340 | 341 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 342 | 343 | NSPredicate *predicate = [self predicateSampleByToday]; 344 | 345 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 346 | 347 | double flightsClimbed = 0; 348 | for (HKQuantitySample *sample in results) { 349 | flightsClimbed += [[[NSString stringWithFormat:@"%@",sample.quantity] componentsSeparatedByString:@" "][0] doubleValue]; 350 | } 351 | 352 | completion(flightsClimbed,error); 353 | }]; 354 | 355 | [self.store executeQuery:query]; 356 | } 357 | -(void)writeFlightsClimbedToHealthStoreWithUnit:(NSInteger)flightsClimbed completion:(void(^)(BOOL response))completion; 358 | { 359 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed]; 360 | 361 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit countUnit] doubleValue:flightsClimbed]; 362 | 363 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 364 | 365 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 366 | if (success) { 367 | completion(YES); 368 | }else { 369 | completion(NO); 370 | } 371 | }]; 372 | } 373 | 374 | 375 | ///------------------------- 376 | #pragma mark - 呼吸速率 377 | ///------------------------- 378 | -(void)readRespiratoryRateFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 379 | { 380 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierRespiratoryRate]; 381 | 382 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 383 | 384 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 385 | 386 | NSPredicate *predicate = [self predicateSampleByLatestData]; 387 | 388 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 389 | 390 | double respiratoryRate = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 391 | 392 | completion(respiratoryRate,error); 393 | }]; 394 | 395 | [self.store executeQuery:query]; 396 | } 397 | -(void)writeRespiratoryRateToHealthStoreWithUnit:(double)respiratoryRate completion:(void(^)(BOOL response))completion 398 | { 399 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRespiratoryRate]; 400 | 401 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit unitFromString:@"count/min"] doubleValue:respiratoryRate]; 402 | 403 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 404 | 405 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 406 | if (success) { 407 | completion(YES); 408 | }else { 409 | completion(NO); 410 | } 411 | }]; 412 | } 413 | 414 | 415 | ///------------------------- 416 | #pragma mark - DietaryEnergyConsumed(膳食能量消耗) 417 | ///------------------------- 418 | -(void)readDietaryEnergyConsumedFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 419 | { 420 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryEnergyConsumed]; 421 | 422 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 423 | 424 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 425 | 426 | NSPredicate *predicate = [self predicateSampleByLatestData]; 427 | 428 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 429 | 430 | double dietaryEnergyConsumed = 0; 431 | for (HKQuantitySample *sample in results) { 432 | dietaryEnergyConsumed += [[[NSString stringWithFormat:@"%@",sample.quantity] componentsSeparatedByString:@" "][0] doubleValue]; 433 | } 434 | 435 | completion(dietaryEnergyConsumed,error); 436 | }]; 437 | 438 | [self.store executeQuery:query]; 439 | } 440 | -(void)writeDietaryEnergyConsumedToHealthStoreWithUnit:(double)dietaryEnergyConsumed completion:(void(^)(BOOL response))completion 441 | { 442 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryEnergyConsumed]; 443 | 444 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit kilocalorieUnit] doubleValue:dietaryEnergyConsumed]; 445 | 446 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 447 | 448 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 449 | if (success) { 450 | completion(YES); 451 | }else { 452 | completion(NO); 453 | } 454 | }]; 455 | } 456 | 457 | 458 | ///------------------------- 459 | #pragma mark - OxygenSaturation(血氧饱和度) 460 | ///------------------------- 461 | -(void)readOxygenSaturationFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 462 | { 463 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierOxygenSaturation]; 464 | 465 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 466 | 467 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 468 | 469 | NSPredicate *predicate = [self predicateSampleByLatestData]; 470 | 471 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 472 | 473 | double oxygenSaturation = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 474 | 475 | completion(oxygenSaturation,error); 476 | }]; 477 | 478 | [self.store executeQuery:query]; 479 | } 480 | 481 | 482 | ///------------------------- 483 | #pragma mark - BodyTemperature(体温) 484 | ///------------------------- 485 | -(void)readBodyTemperatureFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 486 | { 487 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature]; 488 | 489 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 490 | 491 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 492 | 493 | NSPredicate *predicate = [self predicateSampleByLatestData]; 494 | 495 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 496 | 497 | double bodyTemperature = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 498 | 499 | completion(bodyTemperature,error); 500 | }]; 501 | 502 | [self.store executeQuery:query]; 503 | } 504 | -(void)writeBodyTemperatureToHealthStoreWithUnit:(double)bodyTemperature completion:(void(^)(BOOL response))completion 505 | { 506 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature]; 507 | 508 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit degreeCelsiusUnit] doubleValue:bodyTemperature]; 509 | 510 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 511 | 512 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 513 | if (success) { 514 | completion(YES); 515 | }else { 516 | completion(NO); 517 | } 518 | }]; 519 | } 520 | 521 | 522 | ///------------------------- 523 | #pragma mark - BloodGlucose(血糖) 524 | ///------------------------- 525 | -(void)readBloodGlucoseFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 526 | { 527 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodGlucose]; 528 | 529 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 530 | 531 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 532 | 533 | NSPredicate *predicate = [self predicateSampleByLatestData]; 534 | 535 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 536 | 537 | double bloodGlucose = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 538 | 539 | completion(bloodGlucose,error); 540 | }]; 541 | 542 | [self.store executeQuery:query]; 543 | } 544 | -(void)writeBloodGlucoseToHealthStoreWithUnit:(double)bloodGlucose completion:(void(^)(BOOL response))completion 545 | { 546 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodGlucose]; 547 | 548 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit unitFromString:@"mg/dl"] doubleValue:bloodGlucose]; 549 | 550 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 551 | 552 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 553 | if (success) { 554 | completion(YES); 555 | }else { 556 | completion(NO); 557 | } 558 | }]; 559 | } 560 | 561 | 562 | ///------------------------- 563 | #pragma mark - BloodPressure(血压) 564 | ///------------------------- 565 | -(void)readBloodPressureSystolicFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 566 | { 567 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic]; 568 | 569 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 570 | 571 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 572 | 573 | NSPredicate *predicate = [self predicateSampleByLatestData]; 574 | 575 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 576 | 577 | double bloodPressureSystolic = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 578 | 579 | completion(bloodPressureSystolic,error); 580 | }]; 581 | 582 | [self.store executeQuery:query]; 583 | } 584 | -(void)writeBloodPressureSystolicToHealthStoreWithUnit:(double)bloodPressureSystolic completion:(void(^)(BOOL response))completion 585 | { 586 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic]; 587 | 588 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit millimeterOfMercuryUnit] doubleValue:bloodPressureSystolic]; 589 | 590 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 591 | 592 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 593 | if (success) { 594 | completion(YES); 595 | }else { 596 | completion(NO); 597 | } 598 | }]; 599 | } 600 | -(void)readBloodPressureDiastolicFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 601 | { 602 | HKSampleType *type = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureDiastolic]; 603 | 604 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 605 | 606 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 607 | 608 | NSPredicate *predicate = [self predicateSampleByLatestData]; 609 | 610 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 611 | 612 | double bloodPressureDiastolic = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 613 | 614 | completion(bloodPressureDiastolic,error); 615 | }]; 616 | 617 | [self.store executeQuery:query]; 618 | } 619 | -(void)writeBloodPressureDiastolicToHealthStoreWithUnit:(double)bloodPressureDiastolic completion:(void(^)(BOOL response))completion 620 | { 621 | HKQuantityType *type = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureDiastolic]; 622 | 623 | HKQuantity *quantity = [HKQuantity quantityWithUnit:[HKUnit millimeterOfMercuryUnit] doubleValue:bloodPressureDiastolic]; 624 | 625 | HKQuantitySample *sample = [HKQuantitySample quantitySampleWithType:type quantity:quantity startDate:[NSDate date] endDate:[NSDate date] metadata:nil]; 626 | 627 | [self.store saveObject:sample withCompletion:^(BOOL success, NSError *error) { 628 | if (success) { 629 | completion(YES); 630 | }else { 631 | completion(NO); 632 | } 633 | }]; 634 | } 635 | 636 | 637 | ///------------------------- 638 | #pragma mark - StandHour(站立小时) 639 | ///------------------------- 640 | -(void)readStandHourFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 641 | { 642 | HKSampleType *type = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierAppleStandHour]; 643 | 644 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 645 | 646 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 647 | 648 | NSPredicate *predicate = [self predicateSampleByToday]; 649 | 650 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 651 | 652 | double sum = 0; 653 | for (HKQuantitySample *sample in results) { 654 | sum += [[[NSString stringWithFormat:@"%@",sample.quantity] componentsSeparatedByString:@" "][0] doubleValue]; 655 | } 656 | 657 | completion(sum,error); 658 | }]; 659 | 660 | [self.store executeQuery:query]; 661 | } 662 | 663 | 664 | ///------------------------- 665 | #pragma mark - BiologicalSex(性别) 666 | ///------------------------- 667 | -(void)readBiologicalSexFromHealthStoreWithCompletion:(void(^)(NSString *sex,NSError *error))completion 668 | { 669 | NSError *error = nil; 670 | HKBiologicalSexObject *sexObject = [self.store biologicalSexWithError:&error]; 671 | 672 | NSString *sex = nil; 673 | switch (sexObject.biologicalSex) { 674 | case HKBiologicalSexNotSet: 675 | sex = @"未设置"; 676 | break; 677 | case HKBiologicalSexMale: 678 | sex = @"女性"; 679 | break; 680 | case HKBiologicalSexFemale: 681 | sex = @"男性"; 682 | break; 683 | case HKBiologicalSexOther: 684 | sex = @"其它"; 685 | break; 686 | default: 687 | break; 688 | } 689 | completion(sex,error); 690 | } 691 | 692 | 693 | ///------------------------- 694 | #pragma mark - DateOfBirth(出生日期) 695 | ///------------------------- 696 | -(void)readDateOfBirthFromHealthStoreWithCompletion:(void(^)(NSDate *date,NSError *error))completion 697 | { 698 | NSError *error = nil; 699 | NSDateComponents *components = [self.store dateOfBirthComponentsWithError:&error]; 700 | 701 | NSCalendar *calendar = [NSCalendar currentCalendar]; 702 | 703 | NSDate *date = [calendar dateFromComponents:components]; 704 | 705 | NSTimeZone *zone = [NSTimeZone systemTimeZone]; 706 | 707 | NSTimeInterval interval = [zone secondsFromGMTForDate:date]; 708 | 709 | NSDate *dateOfBrith = [date dateByAddingTimeInterval:interval]; 710 | 711 | completion(dateOfBrith,error); 712 | } 713 | 714 | 715 | ///------------------------- 716 | #pragma mark - BloodType(血型) 717 | ///------------------------- 718 | -(void)readBloodTypeFromHealthStoreWithCompletion:(void(^)(NSString *bloodType,NSError *error))completion 719 | { 720 | NSError *error = nil; 721 | HKBloodTypeObject *bloodTypeObject = [self.store bloodTypeWithError:&error]; 722 | 723 | NSString *type = nil; 724 | switch (bloodTypeObject.bloodType) { 725 | case HKBloodTypeNotSet: 726 | type = @"未设置"; 727 | break; 728 | case HKBloodTypeAPositive: 729 | type = @"A型血阳性"; 730 | break; 731 | case HKBloodTypeANegative: 732 | type = @"A型血阴性"; 733 | break; 734 | case HKBloodTypeBPositive: 735 | type = @"B型血阳性"; 736 | break; 737 | case HKBloodTypeBNegative: 738 | type = @"B型血阴性"; 739 | break; 740 | case HKBloodTypeABPositive: 741 | type = @"AB型血阳性"; 742 | break; 743 | case HKBloodTypeABNegative: 744 | type = @"AB型血阴性"; 745 | break; 746 | case HKBloodTypeOPositive: 747 | type = @"O型血阳性"; 748 | break; 749 | case HKBloodTypeONegative: 750 | type = @"O型血阴性"; 751 | break; 752 | default: 753 | break; 754 | } 755 | completion(type,error); 756 | } 757 | 758 | 759 | ///------------------------- 760 | #pragma mark - FitzpatrickSkin(日光反应型皮肤类型) 761 | ///------------------------- 762 | -(void)readFitzpatrickSkinFromHealthStoreWithCompletion:(void(^)(NSString *skinType,NSError *error))completion 763 | { 764 | NSError *error = nil; 765 | HKFitzpatrickSkinTypeObject *skinTypeObject = [self.store fitzpatrickSkinTypeWithError:&error]; 766 | 767 | NSString *type = nil; 768 | switch (skinTypeObject.skinType) { 769 | case HKFitzpatrickSkinTypeNotSet: 770 | type = @"未设置"; 771 | break; 772 | case HKFitzpatrickSkinTypeI: 773 | type = @"I型"; 774 | break; 775 | case HKFitzpatrickSkinTypeII: 776 | type = @"II型"; 777 | break; 778 | case HKFitzpatrickSkinTypeIII: 779 | type = @"III型"; 780 | break; 781 | case HKFitzpatrickSkinTypeIV: 782 | type = @"IV型"; 783 | break; 784 | case HKFitzpatrickSkinTypeV: 785 | type = @"V型"; 786 | break; 787 | case HKFitzpatrickSkinTypeVI: 788 | type = @"VI型"; 789 | break; 790 | default: 791 | break; 792 | } 793 | completion(type,error); 794 | } 795 | 796 | 797 | ///------------------------- 798 | #pragma mark - SleepAnalysis(睡眠分析) 799 | ///------------------------- 800 | -(void)readSleepAnalysisFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 801 | { 802 | HKSampleType *type = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis]; 803 | 804 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 805 | 806 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 807 | 808 | NSPredicate *predicate = [self predicateSampleByToday]; 809 | 810 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 811 | 812 | double sleepAnalysis = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 813 | 814 | completion(sleepAnalysis,error); 815 | }]; 816 | 817 | [self.store executeQuery:query]; 818 | } 819 | 820 | 821 | ///------------------------- 822 | #pragma mark - MenstrualFlow(月经) 823 | ///------------------------- 824 | -(void)readMenstrualFlowFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 825 | { 826 | HKSampleType *type = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierMenstrualFlow]; 827 | 828 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 829 | 830 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 831 | 832 | NSPredicate *predicate = [self predicateSampleByToday]; 833 | 834 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 835 | 836 | double menstrualFlow = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 837 | 838 | completion(menstrualFlow,error); 839 | }]; 840 | 841 | [self.store executeQuery:query]; 842 | } 843 | 844 | 845 | ///------------------------- 846 | #pragma mark - IntermenstrualBleeding(点滴出血) 847 | ///------------------------- 848 | -(void)readIntermenstrualBleedingFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 849 | { 850 | HKSampleType *type = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierIntermenstrualBleeding]; 851 | 852 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 853 | 854 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 855 | 856 | NSPredicate *predicate = [self predicateSampleByToday]; 857 | 858 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 859 | 860 | double intermenstrualBleeding = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 861 | 862 | completion(intermenstrualBleeding,error); 863 | }]; 864 | 865 | [self.store executeQuery:query]; 866 | } 867 | 868 | 869 | ///------------------------- 870 | #pragma mark - SexualActivity(性行为) 871 | ///------------------------- 872 | -(void)readSexualActivityFromHealthStoreWithCompletion:(void(^)(double value,NSError *error))completion 873 | { 874 | HKSampleType *type = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSexualActivity]; 875 | 876 | NSSortDescriptor *startSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO]; 877 | 878 | NSSortDescriptor *endSort = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO]; 879 | 880 | NSPredicate *predicate = [self predicateSampleByToday]; 881 | 882 | HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:type predicate:predicate limit:0 sortDescriptors:@[startSort,endSort] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) { 883 | 884 | double sexualActivity = [[[NSString stringWithFormat:@"%@",results.firstObject] componentsSeparatedByString:@" "][0] doubleValue]; 885 | 886 | completion(sexualActivity,error); 887 | }]; 888 | 889 | [self.store executeQuery:query]; 890 | } 891 | 892 | 893 | ///------------------------- 894 | #pragma mark - 谓词样本 895 | ///------------------------- 896 | -(NSPredicate *)predicateSampleByToday //predicate sample is the day data(谓词样本为当天数据) 897 | { 898 | NSCalendar *calendar = [NSCalendar currentCalendar]; 899 | 900 | NSDate *dateNow = [NSDate date]; 901 | 902 | NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:dateNow]; 903 | [components setHour:0]; 904 | [components setMinute:0]; 905 | [components setSecond:0]; 906 | 907 | NSDate *startDate = [calendar dateFromComponents:components]; 908 | NSDate *endDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:1 toDate:startDate options:0]; 909 | 910 | NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:(HKQueryOptionNone)]; 911 | 912 | return predicate; 913 | } 914 | -(NSPredicate *)predicateSampleByLatestData //predicate sample is the latest data(谓词样本为最新数据) 915 | { 916 | NSCalendar *calendar = [NSCalendar currentCalendar]; 917 | 918 | NSDate *dateNow = [NSDate date]; 919 | 920 | NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:dateNow]; 921 | [components setHour:0]; 922 | [components setMinute:0]; 923 | [components setSecond:0]; 924 | 925 | NSDate *startDate = [calendar dateFromComponents:components]; 926 | NSDate *endDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:1 toDate:startDate options:0]; 927 | 928 | NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:0 endDate:endDate options:(HKQueryOptionNone)]; 929 | 930 | return predicate; 931 | } 932 | -(NSPredicate *)predicateSampleByPeriodOfTimeWithStartTime:(NSString *)startTime endTime:(NSString *)endTime //predicate sample is time period data(谓词样本为时间段数据) 933 | { 934 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 935 | [formatter setDateFormat:@"yyyy-MM-dd HH:mm"]; 936 | formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]; 937 | 938 | NSDate *newStartDate = [formatter dateFromString:startTime]; 939 | NSDate *newEndDate = [formatter dateFromString:endTime]; 940 | 941 | NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:newStartDate endDate:newEndDate options:(HKQueryOptionNone)]; 942 | 943 | return predicate; 944 | } 945 | 946 | 947 | ///------------------------- 948 | #pragma mark - 权限集合 949 | ///------------------------- 950 | -(NSSet *)readObjectTypes ///读权限集合 951 | { 952 | HKQuantityType *Height = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight]; //身高 953 | 954 | HKQuantityType *BodyMass = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; //体重 955 | 956 | HKQuantityType *BodyMassIndex= [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMassIndex]; //身体质量指数 957 | 958 | HKQuantityType *StepCount = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; //步数 959 | 960 | HKQuantityType *DistanceWalkingRunning= [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; //步行 + 跑步距离 961 | 962 | HKObjectType *FlightsClimbed = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed]; //已爬楼层 963 | 964 | HKQuantityType *RespiratoryRate = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRespiratoryRate]; //呼吸速率 965 | 966 | HKQuantityType *DietaryEnergyConsumed = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryEnergyConsumed]; //膳食能量消耗 967 | 968 | HKQuantityType *OxygenSaturation = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierOxygenSaturation]; //血氧饱和度 969 | 970 | HKQuantityType *BodyTemperature = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature]; //体温 971 | 972 | HKQuantityType *BloodGlucose = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodGlucose]; //血糖 973 | 974 | HKQuantityType *BloodPressureSystolic = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic]; //血压收缩压 975 | 976 | HKQuantityType *BloodPressureDiastolic = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureDiastolic]; //血压舒张压 977 | 978 | HKCategoryType *StandHour = [HKCategoryType categoryTypeForIdentifier:HKCategoryTypeIdentifierAppleStandHour]; //站立小时 979 | 980 | HKObjectType *ActivitySummary = [HKObjectType activitySummaryType]; //健身记录 981 | 982 | HKObjectType *BiologicalSex = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBiologicalSex]; //性别 983 | 984 | HKObjectType *DateOfBirth = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierDateOfBirth]; //出生日期 985 | 986 | HKObjectType *BloodType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBloodType]; //血型 987 | 988 | HKObjectType *FitzpatrickSkin = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierFitzpatrickSkinType]; //日光反应型皮肤类型 989 | 990 | HKObjectType *SleepAnalysis = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis]; //睡眠分析 991 | 992 | HKObjectType *MenstrualFlow = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierMenstrualFlow]; //月经 993 | 994 | HKObjectType *IntermenstrualBleeding = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierIntermenstrualBleeding]; //点滴出血 995 | 996 | HKObjectType *SexualActivity = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSexualActivity]; //性行为 997 | 998 | return [NSSet setWithObjects:Height, 999 | BodyMass, 1000 | BodyMassIndex, 1001 | StepCount, 1002 | DistanceWalkingRunning, 1003 | FlightsClimbed, 1004 | RespiratoryRate, 1005 | DietaryEnergyConsumed, 1006 | OxygenSaturation, 1007 | BodyTemperature, 1008 | BloodGlucose, 1009 | BloodPressureSystolic, 1010 | BloodPressureDiastolic, 1011 | StandHour, 1012 | ActivitySummary, 1013 | BiologicalSex, 1014 | DateOfBirth, 1015 | BloodType, 1016 | FitzpatrickSkin, 1017 | SleepAnalysis, 1018 | MenstrualFlow, 1019 | IntermenstrualBleeding, 1020 | SexualActivity, 1021 | nil]; 1022 | } 1023 | -(NSSet *)writeObjectTypes ///写权限集合 1024 | { 1025 | HKQuantityType *Height = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight]; //身高 1026 | 1027 | HKQuantityType *BodyMass = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; //体重 1028 | 1029 | HKQuantityType *BodyMassIndex= [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMassIndex]; //身体质量指数 1030 | 1031 | HKQuantityType *StepCount = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; //步数 1032 | 1033 | HKQuantityType *DistanceWalkingRunning= [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; //步行 + 跑步距离 1034 | 1035 | HKObjectType *FlightsClimbed = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed]; //已爬楼层 1036 | 1037 | HKQuantityType *RespiratoryRate = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRespiratoryRate]; //呼吸速率 1038 | 1039 | HKQuantityType *DietaryEnergyConsumed = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryEnergyConsumed]; //膳食能量消耗 1040 | 1041 | HKQuantityType *OxygenSaturation = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierOxygenSaturation]; //血氧饱和度 1042 | 1043 | HKQuantityType *BodyTemperature = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature]; //体温 1044 | 1045 | HKQuantityType *BloodGlucose = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodGlucose]; //血糖 1046 | 1047 | HKQuantityType *BloodPressureSystolic = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic]; //血压收缩压 1048 | 1049 | HKQuantityType *BloodPressureDiastolic = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureDiastolic]; //血压舒张压 1050 | 1051 | HKObjectType *SleepAnalysis = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis]; //睡眠分析 1052 | 1053 | HKObjectType *MenstrualFlow = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierMenstrualFlow]; //月经 1054 | 1055 | HKObjectType *IntermenstrualBleeding = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierIntermenstrualBleeding]; //点滴出血 1056 | 1057 | HKObjectType *SexualActivity = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSexualActivity]; //性行为 1058 | 1059 | return [NSSet setWithObjects:Height, 1060 | BodyMass, 1061 | BodyMassIndex, 1062 | StepCount, 1063 | DistanceWalkingRunning, 1064 | FlightsClimbed, 1065 | RespiratoryRate, 1066 | DietaryEnergyConsumed, 1067 | OxygenSaturation, 1068 | BodyTemperature, 1069 | BloodGlucose, 1070 | BloodPressureSystolic, 1071 | BloodPressureDiastolic, 1072 | SleepAnalysis, 1073 | MenstrualFlow, 1074 | IntermenstrualBleeding, 1075 | SexualActivity, 1076 | nil]; 1077 | } 1078 | 1079 | @end 1080 | --------------------------------------------------------------------------------