Compare commits

...

1 Commits

Author SHA1 Message Date
Pariece McKinney 9b1153da04 Public release 2.2.16 2024-04-25 17:09:00 -04:00
62 changed files with 731 additions and 218 deletions
+92
View File
@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeAudioData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypePhotosorVideos</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeSensitiveInfo</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeHealth</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypePreciseLocation</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
</array>
</dict>
</plist>
+22
View File
@@ -260,6 +260,28 @@ types of steps supported by the *ResearchKit framework* in the first tab, and di
results of the last completed task in the second tab. The third tab shows some examples from the *Charts module*.
App Store Submissions
-----------------------------
For apps that dont use ResearchKits HealthKit features:
If you are looking to submit your app with ResearchKit to the App Store, you can compile out unnecessary references to HealthKit in your app by editing the following project file:
`ResearchKit/Configuration/ResearchKit/ResearchKit-Shared.xcconfig`
And changing
`ORK_FEATURE_HEALTHKIT_AUTHORIZATION=1`
To
`ORK_FEATURE_HEALTHKIT_AUTHORIZATION=0`
With this change, the embedded ResearchKit framework in your app will not contain any HealthKit related functionality or any references to HealthKit API that might trigger AppStore review to require HealthKit entries in your apps Info.plist.
Similarly, if you would like to compile out references to CoreLocation. In the same `ResearchKit-Shared.xcconfig`
And changing
`ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=1`
To
`ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=0`
Also please ensure that your `info.plist` does not have any HealthKit privacy messages
Similarly, if you would like to use the ResearchKits HealthKit features. Make sure to enable the HealthKit Entitlement
License<a name="license"></a>
=======
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'ResearchKit'
s.version = '2.2.15'
s.version = '2.2.16'
s.summary = 'ResearchKit is an open source software framework that makes it easy to create apps for medical research or for other research projects.'
s.homepage = 'https://www.github.com/ResearchKit/ResearchKit'
s.documentation_url = 'http://researchkit.github.io/docs/'
+37 -23
View File
@@ -22,7 +22,7 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
00B1F7852241503900D022FE /* Speech.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B1F7842241503900D022FE /* Speech.framework */; };
00B1F7852241503900D022FE /* Speech.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00B1F7842241503900D022FE /* Speech.framework */; settings = {ATTRIBUTES = (Required, ); }; };
00C2668A2302244300337E0B /* ORKCustomStepViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 00C266882302244300337E0B /* ORKCustomStepViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
00C2668B2302244300337E0B /* ORKCustomStepViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C266892302244300337E0B /* ORKCustomStepViewController.m */; };
00C2668E23022CD400337E0B /* ORKCustomStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 00C2668C23022CD400337E0B /* ORKCustomStep.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -41,6 +41,9 @@
03BD9EA4253E62A0008ADBE1 /* ORKBundleAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 03BD9EA2253E62A0008ADBE1 /* ORKBundleAsset.m */; };
03EDD58024CA6B1D006245E9 /* ORKNotificationPermissionType.h in Headers */ = {isa = PBXBuildFile; fileRef = 03EDD57E24CA6B1D006245E9 /* ORKNotificationPermissionType.h */; settings = {ATTRIBUTES = (Public, ); }; };
03EDD58124CA6B1D006245E9 /* ORKNotificationPermissionType.m in Sources */ = {isa = PBXBuildFile; fileRef = 03EDD57F24CA6B1D006245E9 /* ORKNotificationPermissionType.m */; };
0B0EF9C92B8FB87600E2A97B /* ResearchKitTests-Shared.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 0B0EF9C72B8FB87600E2A97B /* ResearchKitTests-Shared.xcconfig */; };
0B0EF9CA2B8FB87600E2A97B /* ResearchKitTests-Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 0B0EF9C82B8FB87600E2A97B /* ResearchKitTests-Debug.xcconfig */; };
0B4D0F982BC87AB100DCB8B2 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 0B4D0F972BC87AB100DCB8B2 /* PrivacyInfo.xcprivacy */; };
0B59A6BF28C1738D005035B4 /* ORKPickerTestDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B59A6BE28C1738D005035B4 /* ORKPickerTestDelegate.m */; };
0B6CD14329119C7F004BC4A0 /* ORKNormalizedReactionTimeStimulusView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BAF9797291088EE00EF138A /* ORKNormalizedReactionTimeStimulusView.h */; };
0B6CD14429119CBA004BC4A0 /* ORKNormalizedReactionTimeContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BAF9798291088EE00EF138A /* ORKNormalizedReactionTimeContentView.h */; };
@@ -199,6 +202,9 @@
2E80C1AA1FA2AA8D00399A0C /* ORKStreamingAudioRecorder.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E80C1A91FA2AA8D00399A0C /* ORKStreamingAudioRecorder.m */; };
2EBFE11D1AE1B32D00CB8254 /* ORKUIViewAccessibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EBFE11C1AE1B32D00CB8254 /* ORKUIViewAccessibilityTests.m */; };
2EBFE1201AE1B74100CB8254 /* ORKVoiceEngineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EBFE11F1AE1B74100CB8254 /* ORKVoiceEngineTests.m */; };
3C13A8A52BACDCD8006CB592 /* ORKTouchAbilityTouchTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 511B8AAC293A767C00049947 /* ORKTouchAbilityTouchTracker.h */; };
3C7AEDCC29A72F83009EED4A /* CLLocationManager+ResearchKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C7AEDCA29A72F83009EED4A /* CLLocationManager+ResearchKit.h */; settings = {ATTRIBUTES = (Private, ); }; };
3C7AEDCD29A72F83009EED4A /* CLLocationManager+ResearchKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C7AEDCB29A72F83009EED4A /* CLLocationManager+ResearchKit.m */; };
51198769245CA50D004FC2C7 /* ORKUSDZModelManagerScene.h in Headers */ = {isa = PBXBuildFile; fileRef = 51198767245CA50D004FC2C7 /* ORKUSDZModelManagerScene.h */; };
5119876A245CA50D004FC2C7 /* ORKUSDZModelManagerScene.m in Sources */ = {isa = PBXBuildFile; fileRef = 51198768245CA50D004FC2C7 /* ORKUSDZModelManagerScene.m */; };
5119879B245FC33C004FC2C7 /* ORK3DModelManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 51198799245FC33C004FC2C7 /* ORK3DModelManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -225,7 +231,6 @@
511B8AA8293A764900049947 /* ORKTouchAbilityTrial.m in Sources */ = {isa = PBXBuildFile; fileRef = 511B8AA6293A764900049947 /* ORKTouchAbilityTrial.m */; };
511B8AAA293A766300049947 /* ORKTouchAbilityTrial_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 511B8AA9293A766300049947 /* ORKTouchAbilityTrial_Internal.h */; };
511B8AAD293A767C00049947 /* ORKTouchAbilityTouchTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 511B8AAB293A767C00049947 /* ORKTouchAbilityTouchTracker.m */; };
511B8AAE293A767C00049947 /* ORKTouchAbilityTouchTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 511B8AAC293A767C00049947 /* ORKTouchAbilityTouchTracker.h */; };
511B8AB1293A76A100049947 /* ORKTouchAbilityTapStep.m in Sources */ = {isa = PBXBuildFile; fileRef = 511B8AAF293A76A100049947 /* ORKTouchAbilityTapStep.m */; };
511B8AB2293A76A100049947 /* ORKTouchAbilityTapStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 511B8AB0293A76A100049947 /* ORKTouchAbilityTapStep.h */; settings = {ATTRIBUTES = (Private, ); }; };
511B8AB5293A76B200049947 /* ORKTouchAbilityTapStepViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 511B8AB3293A76B200049947 /* ORKTouchAbilityTapStepViewController.m */; };
@@ -760,7 +765,6 @@
B1A860F61A9693C400EA57B7 /* consent_06@3x.m4v in Resources */ = {isa = PBXBuildFile; fileRef = B1A860E81A9693C400EA57B7 /* consent_06@3x.m4v */; };
B1A860F71A9693C400EA57B7 /* consent_07@3x.m4v in Resources */ = {isa = PBXBuildFile; fileRef = B1A860E91A9693C400EA57B7 /* consent_07@3x.m4v */; };
B1C0F4E41A9BA65F0022C153 /* ResearchKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = B1C0F4E11A9BA65F0022C153 /* ResearchKit.strings */; };
B1C7955E1A9FBF04007279BA /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1C7955D1A9FBF04007279BA /* HealthKit.framework */; settings = {ATTRIBUTES = (Required, ); }; };
B8760F2B1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = B8760F291AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.h */; };
B8760F2C1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = B8760F2A1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.m */; };
BA0AA6941EAEC0B600671ACE /* ORKStroopContentView.h in Headers */ = {isa = PBXBuildFile; fileRef = BA0AA68E1EAEC0B600671ACE /* ORKStroopContentView.h */; };
@@ -1046,6 +1050,9 @@
03EDD57E24CA6B1D006245E9 /* ORKNotificationPermissionType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ORKNotificationPermissionType.h; sourceTree = "<group>"; };
03EDD57F24CA6B1D006245E9 /* ORKNotificationPermissionType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ORKNotificationPermissionType.m; sourceTree = "<group>"; };
05F3765923C797930068E166 /* ResearchKit.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = ResearchKit.xctestplan; sourceTree = "<group>"; };
0B0EF9C72B8FB87600E2A97B /* ResearchKitTests-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "ResearchKitTests-Shared.xcconfig"; sourceTree = "<group>"; };
0B0EF9C82B8FB87600E2A97B /* ResearchKitTests-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "ResearchKitTests-Debug.xcconfig"; sourceTree = "<group>"; };
0B4D0F972BC87AB100DCB8B2 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
0B59A6BD28C1738D005035B4 /* ORKPickerTestDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ORKPickerTestDelegate.h; sourceTree = "<group>"; };
0B59A6BE28C1738D005035B4 /* ORKPickerTestDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ORKPickerTestDelegate.m; sourceTree = "<group>"; };
0B7D32E92AE6F8040071C576 /* ORKQuestionStepViewController+TestingSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ORKQuestionStepViewController+TestingSupport.h"; sourceTree = "<group>"; };
@@ -1208,6 +1215,8 @@
2EBFE11C1AE1B32D00CB8254 /* ORKUIViewAccessibilityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKUIViewAccessibilityTests.m; sourceTree = "<group>"; };
2EBFE11E1AE1B68800CB8254 /* ORKVoiceEngine_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ORKVoiceEngine_Internal.h; sourceTree = "<group>"; };
2EBFE11F1AE1B74100CB8254 /* ORKVoiceEngineTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKVoiceEngineTests.m; sourceTree = "<group>"; };
3C7AEDCA29A72F83009EED4A /* CLLocationManager+ResearchKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CLLocationManager+ResearchKit.h"; sourceTree = "<group>"; };
3C7AEDCB29A72F83009EED4A /* CLLocationManager+ResearchKit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CLLocationManager+ResearchKit.m"; sourceTree = "<group>"; };
51198767245CA50D004FC2C7 /* ORKUSDZModelManagerScene.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ORKUSDZModelManagerScene.h; sourceTree = "<group>"; };
51198768245CA50D004FC2C7 /* ORKUSDZModelManagerScene.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ORKUSDZModelManagerScene.m; sourceTree = "<group>"; };
51198799245FC33C004FC2C7 /* ORK3DModelManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ORK3DModelManager.h; sourceTree = "<group>"; };
@@ -1819,7 +1828,6 @@
B1B34A061AA10EE4005FAD66 /* ar */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; name = ar; path = ar.lproj/ResearchKit.strings; sourceTree = "<group>"; };
B1C0F4E21A9BA65F0022C153 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ResearchKit.strings; sourceTree = "<group>"; };
B1C1DE4F196F541F00F75544 /* ResearchKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResearchKit.h; sourceTree = "<group>"; };
B1C7955D1A9FBF04007279BA /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };
B8760F291AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKScaleRangeDescriptionLabel.h; sourceTree = "<group>"; };
B8760F2A1AFBEFB0007FA16F /* ORKScaleRangeDescriptionLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ORKScaleRangeDescriptionLabel.m; sourceTree = "<group>"; };
BA0AA68E1EAEC0B600671ACE /* ORKStroopContentView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ORKStroopContentView.h; sourceTree = "<group>"; };
@@ -2079,7 +2087,6 @@
buildActionMask = 2147483647;
files = (
00B1F7852241503900D022FE /* Speech.framework in Frameworks */,
B1C7955E1A9FBF04007279BA /* HealthKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2097,6 +2104,16 @@
name = "Custom Step";
sourceTree = "<group>";
};
0B0EF9C62B8FB87600E2A97B /* ResearchKitTests */ = {
isa = PBXGroup;
children = (
0B0EF9C72B8FB87600E2A97B /* ResearchKitTests-Shared.xcconfig */,
0B0EF9C82B8FB87600E2A97B /* ResearchKitTests-Debug.xcconfig */,
);
name = ResearchKitTests;
path = ResearchKit/Configuration/ResearchKitTests;
sourceTree = SOURCE_ROOT;
};
0BAF947D2910887D00EF138A /* Shake */ = {
isa = PBXGroup;
children = (
@@ -2375,6 +2392,8 @@
5D04885525F19A7A0006C68B /* ORKDevice.h */,
5D04885B25F1B3AB0006C68B /* ORKDevice_Private.h */,
5D04885625F19A7A0006C68B /* ORKDevice.m */,
3C7AEDCA29A72F83009EED4A /* CLLocationManager+ResearchKit.h */,
3C7AEDCB29A72F83009EED4A /* CLLocationManager+ResearchKit.m */,
);
name = Utilities;
sourceTree = "<group>";
@@ -2493,6 +2512,7 @@
3FFF18341829DB1D00167070 = {
isa = PBXGroup;
children = (
0B4D0F972BC87AB100DCB8B2 /* PrivacyInfo.xcprivacy */,
05F3765923C797930068E166 /* ResearchKit.xctestplan */,
168EEAAE230B6F9E003FD2FA /* scripts */,
B11DF3B21AA109C8009E76D2 /* docs */,
@@ -2516,7 +2536,6 @@
isa = PBXGroup;
children = (
00B1F7842241503900D022FE /* Speech.framework */,
B1C7955D1A9FBF04007279BA /* HealthKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -2872,21 +2891,6 @@
name = "HealthKit Permission Type";
sourceTree = "<group>";
};
51EAFC10289B116300CFA3EB /* Configuration */ = {
isa = PBXGroup;
children = (
51EAFC11289B117500CFA3EB /* ResearchKit */,
);
path = Configuration;
sourceTree = "<group>";
};
51EAFC11289B117500CFA3EB /* ResearchKit */ = {
isa = PBXGroup;
children = (
);
path = ResearchKit;
sourceTree = "<group>";
};
5D000EC02620F27100E5442A /* Configuration */ = {
isa = PBXGroup;
children = (
@@ -2898,6 +2902,7 @@
5D000EC12620F27100E5442A /* ResearchKit */ = {
isa = PBXGroup;
children = (
0B0EF9C62B8FB87600E2A97B /* ResearchKitTests */,
5D000EC22620F27100E5442A /* ResearchKit-Debug.xcconfig */,
5D000EC42620F27100E5442A /* ResearchKit-Shared.xcconfig */,
511A78992950D7030011D85D /* ResearchKit-Release.xcconfig */,
@@ -3042,7 +3047,6 @@
B1C1DE4F196F541F00F75544 /* ResearchKit.h */,
BC94EF2F1E962F7400143081 /* ORKDeprecated.h */,
BC94EF301E962F7400143081 /* ORKDeprecated.m */,
51EAFC10289B116300CFA3EB /* Configuration */,
86C40B511A8D7C5B00081FAC /* Common */,
86C40AF91A8D7C5B00081FAC /* Active Tasks */,
259E76FB1AFFAEAC0070F786 /* Charts */,
@@ -4312,6 +4316,7 @@
BCB6E65B1B7D534C000D5B34 /* ORKDiscreteGraphChartView.h in Headers */,
86C40D8E1A8D7C5C00081FAC /* ORKStep.h in Headers */,
511987C72463316E004FC2C7 /* ORKRequestPermissionsStepViewController.h in Headers */,
3C7AEDCC29A72F83009EED4A /* CLLocationManager+ResearchKit.h in Headers */,
618DA04E1A93D0D600E63AA8 /* ORKAccessibility.h in Headers */,
BA6E1EB6209E9A3F00DA9D55 /* ORKPDFViewerStepView_Internal.h in Headers */,
BAC6F1A922AF535100E31C22 /* ORKTaskReviewViewController.h in Headers */,
@@ -4603,6 +4608,7 @@
511B8AB6293A76B200049947 /* ORKTouchAbilityTapStepViewController.h in Headers */,
D458520A1AF6CCFA00A2DE13 /* ORKImageCaptureCameraPreviewView.h in Headers */,
D44239791AF17F5100559D96 /* ORKImageCaptureStep.h in Headers */,
3C13A8A52BACDCD8006CB592 /* ORKTouchAbilityTouchTracker.h in Headers */,
511B8AF9293A78BB00049947 /* ORKTouchAbilityScrollStep.h in Headers */,
86C40CB21A8D7C5C00081FAC /* ORKRecorder_Private.h in Headers */,
BCD192E71B81243900FCC08A /* ORKPieChartLegendView.h in Headers */,
@@ -4895,6 +4901,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0B0EF9CA2B8FB87600E2A97B /* ResearchKitTests-Debug.xcconfig in Resources */,
0B0EF9C92B8FB87600E2A97B /* ResearchKitTests-Shared.xcconfig in Resources */,
22ED1848285290250052406B /* ORKAudiometryTestData.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -4921,6 +4929,7 @@
2246E5152749350300261D5A /* frequency_dBSPL_AIRPODSV3.plist in Resources */,
B1A860F31A9693C400EA57B7 /* consent_03@3x.m4v in Resources */,
B1A860F11A9693C400EA57B7 /* consent_01@3x.m4v in Resources */,
0B4D0F982BC87AB100DCB8B2 /* PrivacyInfo.xcprivacy in Resources */,
E26E32D722E75FBF004F42EC /* Window.wav in Resources */,
62DF9F4728CA87DE00D13018 /* frequency_dBSPL_AIRPODSPROV2.plist in Resources */,
B1A860F71A9693C400EA57B7 /* consent_07@3x.m4v in Resources */,
@@ -5026,7 +5035,6 @@
714151D0225C4A23002CA33B /* ORKPasscodeViewControllerTests.swift in Sources */,
0324C1D825439E1800BBE77B /* ORKVideoInstructionStepViewControllerTests.swift in Sources */,
14E79040226A5F72009D8083 /* ORKStepViewControllerHelpers.swift in Sources */,
0BC803602B1578D500618E4F /* ORKTextChoiceAnswerFormat+FormStepViewControllerAdditions.m in Sources */,
86D348021AC161B0006DB02B /* ORKRecorderTests.m in Sources */,
1490DCFC224D4867003FEEDA /* ORKEnvironmentSPLMeterResultTests.swift in Sources */,
7141EA2222EFBC0C00650145 /* ORKLoggingTests.m in Sources */,
@@ -5203,6 +5211,7 @@
BA8C067922EEB84B00ACDE6B /* ORKPlaybackButton.m in Sources */,
86C40C401A8D7C5C00081FAC /* ORKSpatialSpanMemoryContentView.m in Sources */,
511B8B12293A796600049947 /* ORKTouchAbilityPinchContentView.m in Sources */,
3C7AEDCD29A72F83009EED4A /* CLLocationManager+ResearchKit.m in Sources */,
BAC6F1AA22AF535100E31C22 /* ORKTaskReviewViewController.m in Sources */,
BCB6E6671B7D535F000D5B34 /* ORKXAxisView.m in Sources */,
00C2668B2302244300337E0B /* ORKCustomStepViewController.m in Sources */,
@@ -5561,6 +5570,7 @@
};
86CC8EA41AC09332001CCD89 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 0B0EF9C82B8FB87600E2A97B /* ResearchKitTests-Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ADDRESS_SANITIZER_CONTAINER_OVERFLOW = YES;
@@ -5569,6 +5579,10 @@
COPY_PHASE_STRIP = NO;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"$(ORK_GCC_PREPROCESSOR_DEFINITIONS)",
);
INFOPLIST_FILE = ResearchKitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
@@ -28,8 +28,10 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKDefines.h"
@import HealthKit;
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
NS_ASSUME_NONNULL_BEGIN
@@ -60,3 +62,5 @@ typedef NS_OPTIONS(NSInteger, ORKSampleJSONOptions) {
@end
NS_ASSUME_NONNULL_END
#endif
@@ -45,7 +45,7 @@ static NSString *const HKUnitKey = @"unit";
static NSString *const HKCorrelatedObjectsKey = @"objects";
// static NSString *const HKSourceIdentifierKey = @"sourceBundleIdentifier";
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@implementation HKSample (ORKJSONDictionary)
- (NSMutableDictionary *)ork_JSONMutableDictionaryWithOptions:(ORKSampleJSONOptions)options unit:(HKUnit *)unit {
@@ -167,3 +167,4 @@ static NSString *const HKCorrelatedObjectsKey = @"objects";
}
@end
#endif // ORK_FEATURE_HEALTHKIT_AUTHORIZATION
-1
View File
@@ -30,7 +30,6 @@
@import UIKit;
@import HealthKit;
#import <ResearchKit/ORKStep.h>
+2
View File
@@ -165,6 +165,7 @@
(self.shouldUseNextAsSkipButton == castObject.shouldUseNextAsSkipButton));
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (NSSet<HKObjectType *> *)requestedHealthKitTypesForReading {
NSMutableSet<HKObjectType *> *set = [NSMutableSet set];
for (ORKRecorderConfiguration *config in self.recorderConfigurations) {
@@ -175,6 +176,7 @@
}
return set;
}
#endif
- (ORKPermissionMask)requestedPermissions {
ORKPermissionMask mask = [super requestedPermissions];
@@ -33,7 +33,7 @@
#import <ResearchKit/ORKRecorder.h>
#import <Availability.h>
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
NS_ASSUME_NONNULL_BEGIN
/**
@@ -68,5 +68,5 @@ API_AVAILABLE(ios(12.0))
@end
#endif
NS_ASSUME_NONNULL_END
#endif
@@ -39,6 +39,7 @@
#import "ORKRecorder_Internal.h"
#import "HKSample+ORKJSONDictionary.h"
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@interface ORKHealthClinicalTypeRecorder () {
ORKDataLogger *_logger;
@@ -234,3 +235,4 @@
@end
#endif
#endif
@@ -49,6 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
The `ORKHealthQuantityTypeRecorder` class represents a recorder for collecting real time sample data from HealthKit, such as heart rate, during
an active task.
*/
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
ORK_CLASS_AVAILABLE
@interface ORKHealthQuantityTypeRecorder : ORKRecorder
@@ -76,5 +77,5 @@ ORK_CLASS_AVAILABLE
outputDirectory:(nullable NSURL *)outputDirectory NS_DESIGNATED_INITIALIZER;
@end
#endif
NS_ASSUME_NONNULL_END
@@ -36,7 +36,7 @@
#import "ORKRecorder_Internal.h"
#import "HKSample+ORKJSONDictionary.h"
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@interface ORKHealthQuantityTypeRecorder () {
ORKDataLogger *_logger;
BOOL _isRecording;
@@ -368,3 +368,4 @@ static const NSInteger _HealthAnchoredQueryLimit = 100;
}
@end
#endif
+15 -13
View File
@@ -37,6 +37,8 @@
#import "CLLocation+ORKJSONDictionary.h"
#import <ResearchKit/CLLocationManager+ResearchKit.h>
#import <CoreLocation/CoreLocation.h>
@@ -93,25 +95,25 @@
}
self.locationManager = [self createLocationManager];
CLAuthorizationStatus status = kCLAuthorizationStatusNotDetermined;
if (@available(iOS 14.0, *)) {
status = self.locationManager.authorizationStatus;
} else {
status = [CLLocationManager authorizationStatus];
}
if (status == kCLAuthorizationStatusRestricted || status == kCLAuthorizationStatusNotDetermined) {
[self.locationManager requestWhenInUseAuthorization];
self.locationManager.delegate = self;
BOOL locationManagerAuthRequestsAllowed = YES;
if ([CLLocationManager authorizationStatus] <= kCLAuthorizationStatusDenied) {
locationManagerAuthRequestsAllowed = [self.locationManager ork_requestWhenInUseAuthorization];
}
self.uptime = [NSProcessInfo processInfo].systemUptime;
[self.locationManager startUpdatingLocation];
[self.locationManager ork_startUpdatingLocation];
if (locationManagerAuthRequestsAllowed == NO) {
// If we weren't able to perform auth requests, then ResearchKit was compiled with auth requests disabled
// We won't be getting any callbacks about location changes, so might as well stop recording
[self stop];
}
}
- (void)doStopRecording {
[self.locationManager stopUpdatingLocation];
[self.locationManager ork_stopUpdatingLocation];
self.locationManager.delegate = nil;
self.locationManager = nil;
}
@@ -31,9 +31,9 @@
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import "ORKNormalizedReactionTimeStimulusView.h"
#import "ORKRoundTappingButton.h"
#import <ResearchKit/ORKCustomStepView_Internal.h>
#import <ResearchKit/ORKNormalizedReactionTimeStimulusView.h>
#import <ResearchKit/ORKRoundTappingButton.h>
NS_ASSUME_NONNULL_BEGIN
@@ -31,7 +31,7 @@
@import UIKit;
#import "ORKCustomStepView_Internal.h"
#import <ResearchKit/ORKCustomStepView_Internal.h>
NS_ASSUME_NONNULL_BEGIN
@@ -31,8 +31,8 @@
@import UIKit;
#import "ORKDefines.h"
#import "ORKActiveStepViewController.h"
#import <ResearchKit/ORKDefines.h>
#import <ResearchKit/ORKActiveStepViewController.h>
NS_ASSUME_NONNULL_BEGIN
+9 -2
View File
@@ -31,10 +31,13 @@
@import UIKit;
@import HealthKit;
#import <ResearchKit/ORKDefines.h>
#import <Availability.h>
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
NS_ASSUME_NONNULL_BEGIN
@@ -106,7 +109,9 @@ ORK_CLASS_AVAILABLE
If your recorder requires or would benefit from read access to HealthKit at
runtime during the task, return the appropriate set of `HKSampleType` objects.
*/
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (nullable NSSet<HKObjectType *> *)requestedHealthKitTypesForReading;
#endif
@end
@@ -355,6 +360,8 @@ ORK_CLASS_AVAILABLE
of an `ORKActiveStep` object, include that step in a task, and present it with
a task view controller.
*/
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
ORK_CLASS_AVAILABLE
@interface ORKHealthQuantityTypeRecorderConfiguration : ORKRecorderConfiguration
@@ -433,7 +440,7 @@ API_AVAILABLE(ios(12.0))
@end
#endif
#endif
/**
The `ORKStreamingAudioRecorderConfiguration` class represents a configuration that records streaming
audio data during an active step.
+3
View File
@@ -89,9 +89,12 @@
return nil;
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (NSSet<HKObjectType *> *)requestedHealthKitTypesForReading {
return nil;
}
#endif
- (ORKPermissionMask)requestedPermissionMask {
return ORKPermissionNone;
}
@@ -0,0 +1,54 @@
/*
Copyright (c) 2023, Apple Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import <CoreLocation/CLLocationManager.h>
NS_ASSUME_NONNULL_BEGIN
@interface CLLocationManager (ResearchKit)
/**
These categories on CLLocationManager provide ResearchKit code with a common way of requesting authorization that can be disabled by
an Xcode build setting. Callers don't have to add compile-time conditional #if blocks. Instead callers should interpret return value of YES to mean
the authorization request was made, and NO to mean the ResearchKit binary was built with CLLocationManager authorization request calls
compiled out.
The impetus for this approach was to prevent apps using ResearchKit, but not ResearchKit's CoreLocation-powered features, from needlessly
defining an NSLocationWhenInUseUsageDescription Info.plist entry to silence build errors.
*/
- (BOOL)ork_requestWhenInUseAuthorization;
- (BOOL)ork_requestAlwaysAuthorization;
- (void)ork_startUpdatingLocation;
- (void)ork_stopUpdatingLocation;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,71 @@
/*
Copyright (c) 2023, Apple Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors
may be used to endorse or promote products derived from this software without
specific prior written permission. No license is granted to the trademarks of
the copyright holders even if such marks are included in this software.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "CLLocationManager+ResearchKit.h"
#import "ORKDefines.h"
@implementation CLLocationManager (ResearchKit)
- (BOOL)ork_requestWhenInUseAuthorization {
#if ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION
[self requestWhenInUseAuthorization];
return YES;
#else
return NO;
#endif
}
- (BOOL)ork_requestAlwaysAuthorization {
#if ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION
[self requestAlwaysAuthorization];
return YES;
#else
return NO;
#endif
}
- (void)ork_startUpdatingLocation {
#if ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION
[self startUpdatingLocation];
#else
// noop
#endif
}
- (void)ork_stopUpdatingLocation {
#if ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION
[self stopUpdatingLocation];
#else
// noop
#endif
}
@end
+17 -2
View File
@@ -43,7 +43,10 @@
#import "ORKHealthAnswerFormat.h"
#endif
@import HealthKit;
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
@import MapKit;
@import Contacts;
@@ -93,6 +96,7 @@ static NSNumberFormatterStyle ORKNumberFormattingStyleConvert(ORKNumberFormattin
NSMutableDictionary *_unitsTable;
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@synthesize healthStore=_healthStore;
+ (instancetype)sourceWithHealthStore:(HKHealthStore *)healthStore {
@@ -201,8 +205,10 @@ static NSNumberFormatterStyle ORKNumberFormattingStyleConvert(ORKNumberFormattin
[healthStore executeQuery:sampleQuery];
});
}
#endif // ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (void)fetchDefaultValueForAnswerFormat:(ORKAnswerFormat *)answerFormat handler:(void(^)(id defaultValue, NSError *error))handler {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
HKObjectType *objectType = [answerFormat healthKitObjectType];
BOOL handled = NO;
if (objectType) {
@@ -223,8 +229,13 @@ static NSNumberFormatterStyle ORKNumberFormattingStyleConvert(ORKNumberFormattin
if (!handled) {
handler(nil, nil);
}
#else
handler(nil, nil);
#endif
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (HKUnit *)defaultHealthKitUnitForAnswerFormat:(ORKAnswerFormat *)answerFormat {
__block HKUnit *unit = [answerFormat healthKitUnit];
HKObjectType *objectType = [answerFormat healthKitObjectType];
@@ -267,9 +278,11 @@ static NSNumberFormatterStyle ORKNumberFormattingStyleConvert(ORKNumberFormattin
}
}
#endif // ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@end
#endif
#endif // TARGET_OS_IOS
#pragma mark - ORKAnswerFormat
@@ -552,6 +565,7 @@ static NSNumberFormatterStyle ORKNumberFormattingStyleConvert(ORKNumberFormattin
return NO;
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (HKObjectType *)healthKitObjectType {
return nil;
}
@@ -571,6 +585,7 @@ static NSNumberFormatterStyle ORKNumberFormattingStyleConvert(ORKNumberFormattin
- (void)setHealthKitUserUnit:(HKUnit *)unit {
}
#endif
- (ORKQuestionType)questionType {
return ORKQuestionTypeNone;
+19 -5
View File
@@ -29,18 +29,28 @@
*/
@import HealthKit;
#import "ORKAnswerFormat_Private.h"
#import <ResearchKit/ORKDefines.h>
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
#import <ResearchKit/ORKAnswerFormat_Private.h>
#import "ORKChoiceAnswerFormatHelper.h"
@class ORKChoiceAnswerFormatHelper;
NS_ASSUME_NONNULL_BEGIN
BOOL ORKIsAnswerEmpty(_Nullable id answer);
#if TARGET_OS_IOS
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
NSString *ORKHKBiologicalSexString(HKBiologicalSex biologicalSex);
NSString *ORKHKBloodTypeString(HKBloodType bloodType);
#endif
#endif // ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#endif // TARGET_OS_IOS
NSString *ORKQuestionTypeString(ORKQuestionType questionType);
// Need to mark these as designated initializers to avoid warnings once we designate the others.
@@ -80,6 +90,7 @@ ORK_DESIGNATE_CODING_AND_SERIALIZATION_INITIALIZERS(ORKTextChoice)
#if TARGET_OS_IOS
- (BOOL)isHealthKitAnswerFormat;
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (nullable HKObjectType *)healthKitObjectType;
- (nullable HKObjectType *)healthKitObjectTypeForAuthorization;
@@ -87,6 +98,7 @@ ORK_DESIGNATE_CODING_AND_SERIALIZATION_INITIALIZERS(ORKTextChoice)
@property (nonatomic, strong, nullable) HKUnit *healthKitUserUnit;
#endif
#endif
- (nullable NSString *)localizedInvalidValueStringWithAnswerString:(nullable NSString *)text;
@@ -248,15 +260,17 @@ NSArray<Class> *ORKAllowableValueClasses(void);
@interface ORKAnswerDefaultSource : NSObject
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
+ (instancetype)sourceWithHealthStore:(HKHealthStore *)healthStore;
- (instancetype)initWithHealthStore:(HKHealthStore *)healthStore NS_DESIGNATED_INITIALIZER;
- (nullable HKUnit *)defaultHealthKitUnitForAnswerFormat:(ORKAnswerFormat *)answerFormat;
- (void)updateHealthKitUnitForAnswerFormat:(ORKAnswerFormat *)answerFormat force:(BOOL)force;
@property (nonatomic, strong, readonly, nullable) HKHealthStore *healthStore;
#endif
- (void)fetchDefaultValueForAnswerFormat:(nullable ORKAnswerFormat *)answerFormat handler:(void(^)(id defaultValue, NSError *error))handler;
- (nullable HKUnit *)defaultHealthKitUnitForAnswerFormat:(ORKAnswerFormat *)answerFormat;
- (void)updateHealthKitUnitForAnswerFormat:(ORKAnswerFormat *)answerFormat force:(BOOL)force;
@end
+1 -1
View File
@@ -30,10 +30,10 @@
@import UIKit;
#import "ORKDefaultFont.h"
#import "ORKDefines.h"
NS_ASSUME_NONNULL_BEGIN
/**
+7 -2
View File
@@ -30,9 +30,12 @@
#import <Foundation/Foundation.h>
#import <HealthKit/HealthKit.h>
#import <ResearchKit/ORKDefines.h>
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
NS_ASSUME_NONNULL_BEGIN
@@ -85,6 +88,8 @@ ORK_CLASS_AVAILABLE
It cannot be initiated directly.
Use `addHealthCollectorWithSampleType:`to add one to a `ORKDataCollectionManager`.
*/
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
ORK_CLASS_AVAILABLE
@interface ORKHealthCollector : ORKCollector
@@ -146,7 +151,7 @@ ORK_CLASS_AVAILABLE
@property (copy, readonly) HKQueryAnchor *lastAnchor;
@end
#endif
/**
ORKHealthCollector collects CMMotionActivity.
+2 -2
View File
@@ -112,7 +112,7 @@ static NSString *const ItemIdentifierFormatWithTwoPlaceholders = @"org.researchk
@end
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@implementation ORKHealthCollector : ORKCollector
- (instancetype)initWithSampleType:(HKSampleType*)sampleType unit:(HKUnit*)unit startDate:(NSDate*)startDate {
@@ -288,7 +288,7 @@ static NSString *const ItemIdentifierFormatWithTwoPlaceholders = @"org.researchk
}
@end
#endif
@implementation ORKMotionActivityCollector : ORKCollector
+2 -1
View File
@@ -44,6 +44,7 @@
@end
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@protocol ORKHealthCollectable <NSObject>
- (HKSampleType *)sampleType;
@@ -71,7 +72,7 @@
@property (copy) HKQueryAnchor *lastAnchor;
@end
#endif
@interface ORKMotionActivityCollector()
@@ -60,6 +60,7 @@ NS_ASSUME_NONNULL_BEGIN
If NO is returned or this method is not implemented, the manager will stop the collection for the collector and repeat this same collection next time,
until the data is accepted.
*/
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (BOOL)healthCollector:(ORKHealthCollector *)collector didCollectSamples:(NSArray<HKSample *> *)samples;
/**
@@ -73,7 +74,7 @@ NS_ASSUME_NONNULL_BEGIN
until the data is accepted.
*/
- (BOOL)healthCorrelationCollector:(ORKHealthCorrelationCollector *)collector didCollectCorrelations:(NSArray<HKCorrelation *> *)correlations;
#endif
/**
Method for delivering the collected motion activities.
@@ -145,6 +146,7 @@ ORK_CLASS_AVAILABLE
@return Initiated health collector.
*/
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (ORKHealthCollector *)addHealthCollectorWithSampleType:(HKSampleType *)sampleType
unit:(HKUnit *)unit
startDate:(NSDate *)startDate
@@ -166,6 +168,7 @@ ORK_CLASS_AVAILABLE
units:(NSArray<HKUnit *> *)units
startDate:(NSDate *)startDate
error:(NSError * _Nullable *)error;
#endif
/**
Add a collector for motion activity.
+12 -3
View File
@@ -33,8 +33,10 @@
#import "ORKCollector_Internal.h"
#import "ORKOperation.h"
#import "ORKHelpers_Internal.h"
#import <HealthKit/HealthKit.h>
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
// The file names for persisting the state of our collectors
static NSString *const ORKDataCollectionPersistenceFileNamev1 = @".dataCollection.ork.data"; // pre-secureCoding
@@ -45,9 +47,11 @@ static NSString *const ORKDataCollectionPersistenceFileNamev2 = @".dataCollecti
NSOperationQueue *_operationQueue;
NSString * _Nonnull _managedDirectory;
NSArray<ORKCollector *> *_collectors;
HKHealthStore *_healthStore;
CMMotionActivityManager *_activityManager;
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
HKHealthStore *_healthStore;
NSMutableArray<HKObserverQueryCompletionHandler> *_completionHandlers;
#endif
}
- (instancetype)initWithPersistenceDirectoryURL:(NSURL *)directoryURL {
@@ -119,12 +123,14 @@ static inline void dispatch_sync_if_not_on_queue(dispatch_queue_t queue, dispatc
});
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (HKHealthStore *)healthStore {
if (!_healthStore && [HKHealthStore isHealthDataAvailable]){
_healthStore = [[HKHealthStore alloc] init];
}
return _healthStore;
}
#endif
- (CMMotionActivityManager *)activityManager {
if (!_activityManager && [CMMotionActivityManager isActivityAvailable]) {
@@ -183,6 +189,7 @@ static inline void dispatch_sync_if_not_on_queue(dispatch_queue_t queue, dispatc
_collectors = [collectors copy];
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (ORKHealthCollector *)addHealthCollectorWithSampleType:(HKSampleType*)sampleType unit:(HKUnit *)unit startDate:(NSDate *)startDate error:(NSError**)error {
if (!sampleType) {
@@ -235,6 +242,7 @@ static inline void dispatch_sync_if_not_on_queue(dispatch_queue_t queue, dispatc
return healthCorrelationCollector;
}
#endif
- (ORKMotionActivityCollector *)addMotionActivityCollectorWithStartDate:(NSDate *)startDate
error:(NSError* __autoreleasing *)error {
@@ -336,11 +344,12 @@ static inline void dispatch_sync_if_not_on_queue(dispatch_queue_t queue, dispatc
[_delegate dataCollectionManagerDidCompleteCollection:self];
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
for (HKObserverQueryCompletionHandler handler in _completionHandlers) {
handler();
}
[_completionHandlers removeAllObjects];
#endif
return NO;
}];
}];
@@ -32,10 +32,11 @@
#import "ORKDataCollectionManager.h"
#import <CoreMotion/CoreMotion.h>
@interface ORKDataCollectionManager ()
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@property (nonatomic, strong, readonly) HKHealthStore *healthStore;
#endif
@property (nonatomic, strong, readonly) CMMotionActivityManager *activityManager;
+2 -1
View File
@@ -181,6 +181,7 @@
}
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (NSSet<HKObjectType *> *)requestedHealthKitTypesForReading {
NSMutableSet<HKObjectType *> *healthTypes = [NSMutableSet set];
@@ -194,7 +195,7 @@
return healthTypes.count ? healthTypes : nil;
}
#endif
@end
@@ -335,7 +335,10 @@ static const NSTimeInterval DelayBeforeAutoScroll = 0.25;
}
- (instancetype)ORKFormStepViewController_initWithResult:(ORKResult *)result {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
_defaultSource = [ORKAnswerDefaultSource sourceWithHealthStore:[HKHealthStore new]];
#endif
if (result) {
NSAssert([result isKindOfClass:[ORKStepResult class]], @"Expect a ORKStepResult instance");
@@ -377,6 +380,7 @@ static const NSTimeInterval DelayBeforeAutoScroll = 0.25;
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self updateAnsweredSections];
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
NSMutableSet *types = [NSMutableSet set];
for (ORKFormItem *item in [self formItems]) {
ORKAnswerFormat *format = [item answerFormat];
@@ -404,7 +408,7 @@ static const NSTimeInterval DelayBeforeAutoScroll = 0.25;
if (!refreshDefaultsPending) {
[self refreshDefaults];
}
#endif
// Reset skipped flag - result can now be non-empty
_skipped = NO;
@@ -491,6 +495,8 @@ static const NSTimeInterval DelayBeforeAutoScroll = 0.25;
}
- (void)refreshDefaults {
// defaults only come from HealthKit
NSArray *formItems = [self formItems];
ORKAnswerDefaultSource *source = _defaultSource;
ORKWeakTypeOf(self) weakSelf = self;
@@ -516,10 +522,7 @@ static const NSTimeInterval DelayBeforeAutoScroll = 0.25;
ORKStrongTypeOf(weakSelf) strongSelf = weakSelf;
[strongSelf updateDefaults:defaults];
});
});
});
}
- (void)removeAnswerForIdentifier:(NSString *)identifier {
+7 -2
View File
@@ -28,10 +28,12 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
@import HealthKit;
#import <ResearchKit/ORKAnswerFormat.h>
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
NS_ASSUME_NONNULL_BEGIN
typedef NSString *ORKBiologicalSexIdentifier NS_STRING_ENUM;
@@ -62,6 +64,8 @@ ORK_EXTERN ORKBloodTypeIdentifier const ORKBloodTypeIdentifierONegative;
You can use the HealthKit characteristic answer format to let users autofill information, such as their blood type or date of birth.
*/
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
ORK_CLASS_AVAILABLE
@interface ORKHealthKitCharacteristicTypeAnswerFormat : ORKAnswerFormat
@@ -213,6 +217,7 @@ included in the question result generated by form items or question steps
- (NSString *)localizedUnitString;
@end
#endif
NS_ASSUME_NONNULL_END
+2 -1
View File
@@ -28,7 +28,6 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ORKHealthAnswerFormat.h"
#import "ORKAnswerFormat_Internal.h"
@@ -38,6 +37,7 @@
#import "ORKQuestionResult_Private.h"
#import "ORKResult.h"
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#pragma mark - ORKHealthAnswerFormat
@@ -420,3 +420,4 @@ NSString *ORKHKBloodTypeString(HKBloodType bloodType) {
}
@end
#endif
@@ -32,7 +32,10 @@
#import "ORKHealthKitPermissionType.h"
#import "ORKHelpers_Internal.h"
#import "ORKRequestPermissionView.h"
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
static NSString *const Symbol = @"heart.fill";
static uint32_t const IconTintColor = 0xFF5E5E;
@@ -77,6 +80,8 @@ static uint32_t const IconTintColor = 0xFF5E5E;
}
- (void)checkHealthKitAuthorizationStatus {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
if (![HKHealthStore isHealthDataAvailable]) {
[self setState:ORKRequestPermissionsButtonStateNotSupported canContinue:YES];
return;
@@ -107,9 +112,12 @@ static uint32_t const IconTintColor = 0xFF5E5E;
} else {
[self setState:ORKRequestPermissionsButtonStateDefault canContinue:NO];
}
#endif // ORK_FEATURE_HEALTHKIT_AUTHORIZATION
}
- (void)requestPermissionButtonPressed {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
[[HKHealthStore new] requestAuthorizationToShareTypes:_sampleTypesToWrite readTypes:_objectTypesToRead completion:^(BOOL success, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
@@ -121,6 +129,7 @@ static uint32_t const IconTintColor = 0xFF5E5E;
[self setState:ORKRequestPermissionsButtonStateConnected canContinue:YES];
});
}];
#endif // ORK_FEATURE_HEALTHKIT_AUTHORIZATION
}
- (void)setState:(ORKRequestPermissionsButtonState)state canContinue:(BOOL)canContinue {
@@ -29,8 +29,10 @@
*/
#import <Foundation/Foundation.h>
#import "ORKOperation.h"
#import "ORKDefines.h"
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@class ORKDataCollectionManager;
@@ -47,3 +49,4 @@
- (instancetype)initWithCollector:(ORKCollector<ORKHealthCollectable> *)collector mananger:(ORKDataCollectionManager *)manager;
@end
#endif
@@ -35,6 +35,7 @@
#import "ORKCollector_Internal.h"
#import "ORKDataCollectionManager_Internal.h"
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
static NSUInteger const QueryLimitSize = 1000;
@@ -245,3 +246,4 @@ static NSUInteger const QueryLimitSize = 1000;
}
@end
#endif
@@ -33,7 +33,8 @@
#import "ORKHelpers_Internal.h"
#import "ORKRequestPermissionButton.h"
@import CoreLocation;
#import <CoreLocation/CLLocationManagerDelegate.h>
#import <ResearchKit/CLLocationManager+ResearchKit.h>
static NSString *const Symbol = @"location.circle";
static const uint32_t IconLightTintColor = 0x50C878;
@@ -114,7 +115,11 @@ static const uint32_t IconDarkTintColor = 0x00A36C;
// Request for always permission.
- (void)requestPermissionButtonPressed {
[self.locationManager requestAlwaysAuthorization];
BOOL requestWasDelivered = [self.locationManager ork_requestAlwaysAuthorization];
// if the auth request was not delivered, that means ResearchKit was built with CoreLocation requests disabled
// Presenting the location permission step in this case is probably programmer error
NSAssert(requestWasDelivered, @"Tried to invoke -[CLLocationManager requestAlwaysAuthorization] but ResearchKit was compiled with CoreLocation authorization requests disabled. This is a programmer error. Check build settings for ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION");
}
- (void)setState:(ORKRequestPermissionsButtonState)state canContinue:(BOOL)canContinue {
@@ -48,8 +48,9 @@
#import "ORKHelpers_Internal.h"
#import "ORKSkin.h"
@import MapKit;
#import <ResearchKit/CLLocationManager+ResearchKit.h>
@import MapKit;
static const NSString *FormattedAddressLines = @"FormattedAddressLines";
@@ -294,7 +295,7 @@ static const NSString *FormattedAddressLines = @"FormattedAddressLines";
_locationManager.delegate = self;
}
if (status == kCLAuthorizationStatusNotDetermined) {
[_locationManager requestWhenInUseAuthorization];
[_locationManager ork_requestWhenInUseAuthorization];
}
}
}
@@ -441,8 +442,10 @@ static const NSString *FormattedAddressLines = @"FormattedAddressLines";
# pragma mark CLLocationManagerDelegate
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) {
[self loadCurrentLocationIfNecessary];
}
}
#pragma mark MKMapViewDelegate
@@ -149,10 +149,10 @@ void ORKStepArrayAddStep(NSMutableArray *array, ORKStep *step) {
@implementation ORKOrderedTask (ORKMakeTaskUtilities)
+ (NSArray<ORKRecorderConfiguration*>*)makeRecorderConfigurationsWithOptions:(ORKPredefinedTaskOption)options {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
HKUnit *bpmUnit = [[HKUnit countUnit] unitDividedByUnit:[HKUnit minuteUnit]];
HKQuantityType *heartRateType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
#endif
NSMutableArray<ORKRecorderConfiguration*> *recorderConfigurations = [NSMutableArray arrayWithCapacity:5];
if (!(ORKPredefinedTaskOptionExcludePedometer & options)) {
@@ -169,10 +169,13 @@ void ORKStepArrayAddStep(NSMutableArray *array, ORKStep *step) {
if (!(ORKPredefinedTaskOptionExcludeLocation & options)) {
[recorderConfigurations addObject:[[ORKLocationRecorderConfiguration alloc] initWithIdentifier:ORKLocationRecorderIdentifier]];
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
if (!(ORKPredefinedTaskOptionExcludeHeartRate & options)) {
[recorderConfigurations addObject:[[ORKHealthQuantityTypeRecorderConfiguration alloc] initWithIdentifier:ORKHeartRateRecorderIdentifier
healthQuantityType:heartRateType unit:bpmUnit]];
}
#endif
return [recorderConfigurations copy];
}
+2
View File
@@ -80,12 +80,14 @@
return ORKPermissionNone;
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (NSSet<HKObjectType *> *)requestedHealthKitTypesForReading {
if ([self.pageTask respondsToSelector:@selector(requestedHealthKitTypesForReading)]) {
return [self.pageTask requestedHealthKitTypesForReading];
}
return nil;
}
#endif
#pragma mark - NSCopying
+3 -1
View File
@@ -30,11 +30,13 @@
#import <ResearchKit/ORKResult.h>
@import CoreLocation;
#import <CoreLocation/CLLocation.h>
@import Contacts;
NS_ASSUME_NONNULL_BEGIN
@class CLCircularRegion;
@class ORKQuestionStep;
@class ORKFormItem;
@class ORKFormStep;
+6
View File
@@ -39,6 +39,10 @@
#import "ORKLearnMoreItem.h"
#endif
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
#if TARGET_OS_IOS
ORKQuestionStepPresentationStyle const ORKQuestionStepPresentationStyleDefault = @"default";
ORKQuestionStepPresentationStyle const ORKQuestionStepPresentationStylePlatter = @"platter";
@@ -110,10 +114,12 @@ ORKQuestionStepPresentationStyle const ORKQuestionStepPresentationStylePlatter =
return [impliedAnswerFormat isKindOfClass:[ORKTextAnswerFormat class]] && ![(ORKTextAnswerFormat *)impliedAnswerFormat multipleLines];
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (NSSet<HKObjectType *> *)requestedHealthKitTypesForReading {
HKObjectType *objType = [[self answerFormat] healthKitObjectTypeForAuthorization];
return (objType != nil) ? [NSSet setWithObject:objType] : nil;
}
#endif
#endif
@@ -146,7 +146,9 @@ static const NSTimeInterval DelayBeforeAutoScroll = 0.25;
- (instancetype)initWithStep:(ORKStep *)step {
self = [super initWithStep:step];
if (self) {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
_defaultSource = [ORKAnswerDefaultSource sourceWithHealthStore:[HKHealthStore new]];
#endif
}
return self;
}
@@ -452,8 +454,10 @@ static const NSTimeInterval DelayBeforeAutoScroll = 0.25;
}
- (void)requestAndRefreshDefaults {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
NSMutableSet *types = [NSMutableSet set];
ORKAnswerFormat *format = [[self questionStep] answerFormat];
HKObjectType *objType = [format healthKitObjectTypeForAuthorization];
if (objType) {
[types addObject:objType];
@@ -476,6 +480,10 @@ static const NSTimeInterval DelayBeforeAutoScroll = 0.25;
if (!scheduledRefresh) {
[self refreshDefaults];
}
#endif
if (_tableView) {
[_tableView reloadData];
}
}
- (void)dealloc {
+8 -1
View File
@@ -30,7 +30,12 @@
@import Foundation;
@import HealthKit;
#import <ResearchKit/ORKDefines.h>
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
#import <ResearchKit/ORKTypes.h>
@@ -245,6 +250,7 @@ requests access to these HealthKit types.
See also: `requestedHealthKitTypesForWriting`.
*/
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
@property (nonatomic, copy, readonly, nullable) NSSet<HKObjectType *> *requestedHealthKitTypesForReading;
/**
@@ -257,6 +263,7 @@ requests access to these HealthKit types.
See also: `requestedHealthKitTypesForReading`.
*/
@property (nonatomic, copy, readonly, nullable) NSSet<HKObjectType *> *requestedHealthKitTypesForWriting;
#endif
/**
The set of permissions requested by the task.
+39 -32
View File
@@ -61,7 +61,8 @@
@import AVFoundation;
@import CoreMotion;
#import <CoreLocation/CoreLocation.h>
#import <CoreLocation/CLLocationManagerDelegate.h>
#import <ResearchKit/CLLocationManager+ResearchKit.h>
typedef void (^_ORKLocationAuthorizationRequestHandler)(BOOL success);
@@ -100,28 +101,22 @@ typedef void (^_ORKLocationAuthorizationRequestHandler)(BOOL success);
}
_started = YES;
NSString *allowedWhenInUse = (NSString *)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"];
NSString *allowedAlways = (NSString *)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"];
NSString *whenInUseKey = (NSString *)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"];
NSString *alwaysKey = (NSString *)[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"];
if (_manager) {
CLAuthorizationStatus status = kCLAuthorizationStatusNotDetermined;
if (@available(iOS 14.0, *)) {
status = _manager.authorizationStatus;
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if ((status == kCLAuthorizationStatusNotDetermined) && (whenInUseKey || alwaysKey)) {
BOOL requestWasDelivered = YES;
if (alwaysKey) {
requestWasDelivered = [_manager ork_requestAlwaysAuthorization];
} else {
status = [CLLocationManager authorizationStatus];
requestWasDelivered = [_manager ork_requestWhenInUseAuthorization];
}
if ((status == kCLAuthorizationStatusNotDetermined) && (allowedWhenInUse || allowedAlways)) {
if (allowedAlways) {
[_manager requestAlwaysAuthorization];
} else {
[_manager requestWhenInUseAuthorization];
}
} else {
[self finishWithResult:(status != kCLAuthorizationStatusDenied)];
if (requestWasDelivered == NO) {
[self finishWithResult:NO];
}
} else {
[self finishWithResult:(status != kCLAuthorizationStatusDenied)];
}
}
@@ -132,18 +127,10 @@ typedef void (^_ORKLocationAuthorizationRequestHandler)(BOOL success);
}
}
- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager {
CLAuthorizationStatus status = kCLAuthorizationStatusNotDetermined;
if (@available(iOS 14.0, *)) {
status = manager.authorizationStatus;
} else {
status = [CLLocationManager authorizationStatus];
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (_handler && _started && status != kCLAuthorizationStatusNotDetermined) {
[self finishWithResult:(status != kCLAuthorizationStatusDenied)];
}
if (_started && status != kCLAuthorizationStatusNotDetermined) {
[self finishWithResult:(status != kCLAuthorizationStatusDenied)];
}
}
@end
@@ -340,16 +327,24 @@ static NSString *const _ChildNavigationControllerRestorationKey = @"childNavigat
writeTypes:(NSSet *)writeTypes
handler:(void (^)(void))handler {
NSParameterAssert(handler != nil);
if ((![HKHealthStore isHealthDataAvailable]) || (!readTypes && !writeTypes)) {
BOOL needsHealthKitAuthRequest = NO;
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
needsHealthKitAuthRequest = ([HKHealthStore isHealthDataAvailable]);
needsHealthKitAuthRequest = needsHealthKitAuthRequest && ((readTypes != nil) || (writeTypes != nil));
#endif
if (needsHealthKitAuthRequest == NO) {
_requestedHealthTypesForRead = nil;
_requestedHealthTypesForWrite = nil;
handler();
dispatch_async(dispatch_get_main_queue(), handler);
return;
}
_requestedHealthTypesForRead = readTypes;
_requestedHealthTypesForWrite = writeTypes;
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
__block HKHealthStore *healthStore = [HKHealthStore new];
[healthStore requestAuthorizationToShareTypes:writeTypes readTypes:readTypes completion:^(BOOL success, NSError *error) {
ORK_Log_Error("Health access: error=%@", error);
@@ -358,6 +353,7 @@ static NSString *const _ChildNavigationControllerRestorationKey = @"childNavigat
// Clear self-ref.
healthStore = nil;
}];
#endif
}
- (void)requestPedometerAccessWithHandler:(void (^)(BOOL success))handler {
@@ -443,6 +439,7 @@ static NSString *const _ChildNavigationControllerRestorationKey = @"childNavigat
return;
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
NSSet *readTypes = nil;
if ([self.task respondsToSelector:@selector(requestedHealthKitTypesForReading)]) {
readTypes = [self.task requestedHealthKitTypesForReading];
@@ -452,6 +449,7 @@ static NSString *const _ChildNavigationControllerRestorationKey = @"childNavigat
if ([self.task respondsToSelector:@selector(requestedHealthKitTypesForWriting)]) {
writeTypes = [self.task requestedHealthKitTypesForWriting];
}
#endif
ORKPermissionMask permissions = [self desiredPermissions];
@@ -459,12 +457,14 @@ static NSString *const _ChildNavigationControllerRestorationKey = @"childNavigat
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
ORK_Log_Debug("Requesting health access");
[self requestHealthStoreAccessWithReadTypes:readTypes
writeTypes:writeTypes
handler:^{
dispatch_semaphore_signal(semaphore);
}];
#endif
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (permissions & ORKPermissionCoreMotionAccelerometer) {
@@ -1585,8 +1585,15 @@ static NSString *const _ORKProgressMode = @"progressMode";
}
if ([_task respondsToSelector:@selector(stepWithIdentifier:)]) {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
_requestedHealthTypesForRead = [coder decodeObjectOfClasses:[NSSet setWithArray:@[NSSet.self, HKObjectType.self]] forKey:_ORKRequestedHealthTypesForReadRestoreKey];
_requestedHealthTypesForWrite = [coder decodeObjectOfClasses:[NSSet setWithArray:@[NSSet.self, HKObjectType.self]] forKey:_ORKRequestedHealthTypesForWriteRestoreKey];
#else
_requestedHealthTypesForRead = nil;
_requestedHealthTypesForWrite = nil;
#endif
_presentedDate = [coder decodeObjectOfClass:[NSDate class] forKey:_ORKPresentedDate];
_lastBeginningInstructionStepIdentifier = [coder decodeObjectOfClass:[NSString class] forKey:_ORKLastBeginningInstructionStepIdentifierKey];
@@ -32,7 +32,10 @@
#import <ResearchKit/ORKTaskViewController_Private.h>
#import <ResearchKit/ORKReviewStepViewController.h>
#import <ResearchKit/ORKActiveStep_Internal.h>
@import HealthKit;
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#import <HealthKit/HealthKit.h>
#endif
NS_ASSUME_NONNULL_BEGIN
+4 -1
View File
@@ -130,7 +130,7 @@
if(choiceOther.textViewStartsHidden) {
if(choiceCell.textView.text.length <= 0) {
shouldHideTextView = choiceCell.isSelected == NO;
shouldHideTextView = (choiceCell.isCellSelected == NO);
}
}
@@ -170,6 +170,9 @@
if ([textChoice isKindOfClass:[ORKTextChoiceOther class]] && [touchedCell isKindOfClass:[ORKChoiceOtherViewCell class]]) {
ORKTextChoiceOther *otherTextChoice = (ORKTextChoiceOther *)textChoice;
ORKChoiceOtherViewCell *touchedOtherCell = (ORKChoiceOtherViewCell *)touchedCell;
if (otherTextChoice.textViewInputOptional || touchedOtherCell.textView.text.length > 0) {
[touchedOtherCell setCellSelected:YES highlight:NO];
}
[self updateTextViewForChoiceOtherCell:touchedOtherCell withTextChoiceOther:otherTextChoice];
if (!otherTextChoice.textViewInputOptional && otherTextChoice.textViewText.length <= 0) {
return;
-1
View File
@@ -79,7 +79,6 @@ struct TextChoiceView: View {
var dividerPadding: CGFloat = 20
dividerPadding += (imageWidth + 16)
return dividerPadding
}
@@ -25,16 +25,43 @@ SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited)
SYSTEM_HEADER_SEARCH_PATHS = $(inherited)
CLANG_STATIC_ANALYZER_MODE = deep
ORK_FRAMEWORK_VERSION_NUMBER = 2.2.15
ORK_FRAMEWORK_VERSION_NUMBER = 2.2.16
ORK_FRAMEWORK_BUILD_NUMBER = $(ORK_FRAMEWORK_BUILD_NUMBER_CI_$(CI)) // ORK_FRAMEWORK_BUILD_NUMBER_CI_TRUE or ORK_FRAMEWORK_BUILD_NUMBER_CI_
ORK_FRAMEWORK_BUILD_NUMBER_CI_TRUE = $(CI_BUILD_NUMBER)
ORK_FRAMEWORK_BUILD_NUMBER_CI_FALSE = $(ORK_FRAMEWORK_VERSION_NUMBER) // When not building in CI, assume build and version number are the same
ORK_FRAMEWORK_BUILD_NUMBER_CI_ = $(ORK_FRAMEWORK_BUILD_NUMBER_CI_FALSE)
// Control whether ResearchKit compiles out CLLocationManager calls that would request authorization for location
// ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=0 compiles out the feature
// ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=1 compiles RK with the feature intact
ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS = $(ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS_$(ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION))
ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS_0 = ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=0
ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS_1 = ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=1
// Some CLLocationManager API calls would trigger authorization to use location. The presence of those
// API calls in ResearchKit **at compile time** mean apps that link ResearchKit also need Info.plist entries
// for NSLocationAlwaysAndWhenInUseUsageDescription and NSLocationWhenInUseUsageDescription.
// If your app doesn't use ORKLocationRecorder and doesn't specify these Info.plist strings, disable
// ResearchKit's CLLocationManager authorization
ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION = 1
// Some HealthKit API calls used within the framework require your app to disclose using HealthKit and provide a reason during app store review.
// If your app does not use HealthKit or any of the ResearchKit HealthKit APIs, disable ResearchKit's HealthKit authorization.
ORK_FEATURE_HEALTHKIT_AUTHORIZATION = 1
// GCC Preprocessor definitions
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC = $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_$(ORK_FEATURE_HEALTHKIT_AUTHORIZATION))
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_0 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION=0
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_1 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION=1
// Swift active compilation conditions
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT = $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_$(ORK_FEATURE_HEALTHKIT_AUTHORIZATION))
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_0 =
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_1 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#include? "samples/ORKCatalog/ResearchKit-Shared.xcconfig"
#include? "../xcconfig/ResearchKit-Shared.xcconfig"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) $(ORK_GCC_PREPROCESSOR_DEFINITIONS)
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) GLES_SILENCE_DEPRECATION=1 $(ORK_GCC_PREPROCESSOR_DEFINITIONS) $(ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS) $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC)
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT)
@@ -0,0 +1,8 @@
//
// ResearchKitTests-Debug.xcconfig
//
#include "ResearchKitTests-Shared.xcconfig"
SWIFT_OBJC_BRIDGING_HEADER = ResearchKitTests/ResearchKitTests-Bridging-Header.h
@@ -0,0 +1,46 @@
//
// ResearchKitTests-Shared.xcconfig
//
CLANG_CXX_LANGUAGE_STANDARD = gnu++0x
GCC_C_LANGUAGE_STANDARD = gnu99
GCC_WARN_SHADOW = NO
INFOPLIST_FILE = ResearchKitTests/Info.plist
LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
PRODUCT_BUNDLE_IDENTIFIER = org.researchkit.$(PRODUCT_NAME:rfc1034identifier)
PRODUCT_NAME = $(TARGET_NAME)
SWIFT_VERSION = 5.0
// Control whether ResearchKitTests expect CLLocationManager calls requesting authorization for location
// ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=0 compiles out the feature
// ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=1 compiles RK with the feature intact
ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS = $(ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS_$(ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION))
ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS_0 = ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=0
ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS_1 = ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=1
// Some CLLocationManager API calls would trigger authorization to use location. The presence of those
// API calls in ResearchKit **at compile time** mean apps that link ResearchKit also need Info.plist entries
// for NSLocationAlwaysAndWhenInUseUsageDescription and NSLocationWhenInUseUsageDescription.
// If your app doesn't use ORKLocationRecorder and doesn't specify these Info.plist strings, disable
// ResearchKit's CLLocationManager authorization
ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION = 1
// Some HealthKit API calls used within the framework require your app to disclose using HealthKit and provide a reason during app store review.
// If your app does not use HealthKit or any of the ResearchKit HealthKit APIs, disable ResearchKit's HealthKit authorization.
ORK_FEATURE_HEALTHKIT_AUTHORIZATION = 1
// GCC Preprocessor definitions
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC = $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_$(ORK_FEATURE_HEALTHKIT_AUTHORIZATION))
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_0 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION=0
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_1 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION=1
// Swift active compilation conditions
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT = $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_$(ORK_FEATURE_HEALTHKIT_AUTHORIZATION))
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_0 =
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_1 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION
#include? "../xcconfig/ResearchKit-Shared.xcconfig"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) GLES_SILENCE_DEPRECATION=1 $(ORK_GCC_PREPROCESSOR_DEFINITIONS) $(ORK_FEATURE_CLLOCATIONMANAGER_DEFINITIONS) $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC)
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT)
@@ -183,3 +183,6 @@
#import <ResearchKit/ORKLearnMoreView.h>
#import <ResearchKit/ORKBodyContainerView.h>
// Class extensions
#import <ResearchKit/CLLocationManager+ResearchKit.h>
-1
View File
@@ -65,7 +65,6 @@
#import <ResearchKit/ORKRequestPermissionsStep.h>
#import <ResearchKit/ORK3DModelStep.h>
#import <ResearchKit/ORKTask.h>
#import <ResearchKit/ORKOrderedTask.h>
#import <ResearchKit/ORKOrderedTask+ORKPredefinedActiveTask.h>
+2
View File
@@ -1509,6 +1509,7 @@
XCTAssertEqual([[[answerFormat textChoices] objectAtIndex:1] value], [NSNumber numberWithInteger:2]);
}
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (void)testHealthKitCharacteristicTypeAnswerFormat {
HKCharacteristicType *biologicalSex = [HKCharacteristicType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBiologicalSex];
@@ -1596,6 +1597,7 @@
XCTAssertEqual([answerFormat numericAnswerStyle], ORKNumericAnswerStyleInteger);
XCTAssertEqual([answerFormat quantityType], calories);
}
#endif
- (void)testDateAnswerFormat {
+2 -1
View File
@@ -42,6 +42,7 @@
@implementation ORKHKSampleTests
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
- (void)testHKSampleSerialization {
NSDate *d1 = [NSDate dateWithTimeIntervalSinceReferenceDate:0];
NSDate *d2 = [NSDate dateWithTimeInterval:10 sinceDate:d1];
@@ -107,5 +108,5 @@
XCTAssertTrue([dict[@"objects"] containsObject:dd], @"");
XCTAssertTrue([dict[@"objects"] containsObject:ds], @"");
}
#endif
@end
@@ -30,7 +30,7 @@
import XCTest
import ResearchKit.Private
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
final class ORKHealthKitQuestionStepViewControllerTests: XCTestCase {
var testController: ORKStepViewController!
var step: ORKStep!
@@ -131,4 +131,4 @@ extension ORKHealthKitQuestionStepViewControllerTests: ORKStepViewControllerDele
return true
}
}
#endif
+21 -2
View File
@@ -431,8 +431,26 @@ static const NSInteger kNumberOfSamples = 5;
}
[recorder stop];
[self checkResult];
// when location features are compiled out, make sure that the "ork_" wrapper functions are
// returning false, but don't bother doing the checkResult step
#if !ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION
// when location auth is 0, the [recorder start] earlier immediately stops, which zeros
// the locationManager property. So we would expect currentLocationManager == nil
XCTAssertNil(currentLocationManager, @"ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION=0: expected recorder's location manager to be nil");
// make a one-time-use locationManager that we test ork_ wrappers with
{
CLLocationManager *locationManager = [(ORKMockLocationRecorder *)recorder createLocationManager];
XCTAssertNotNil(locationManager);
XCTAssertFalse([locationManager ork_requestWhenInUseAuthorization]);
XCTAssertFalse([locationManager ork_requestAlwaysAuthorization]);
}
#else
[self checkResult];
#endif // ORK_FEATURE_CLLOCATIONMANAGER_AUTHORIZATION
for (NSDictionary *sample in _items) {
XCTAssertTrue(ork_doubleEqual(altitude, ((NSNumber *)sample[@"altitude"]).doubleValue), @"");
@@ -621,7 +639,7 @@ static const NSInteger kNumberOfSamples = 5;
}
- (void)testHealthQuantityTypeRecorder {
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
HKUnit *bpmUnit = [[HKUnit countUnit] unitDividedByUnit:[HKUnit minuteUnit]];
HKQuantityType *hbQuantityType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
ORKHealthQuantityTypeRecorderConfiguration *recorderConfiguration = [[ORKHealthQuantityTypeRecorderConfiguration alloc] initWithIdentifier:@"healtQuantityTypeRecorder" healthQuantityType:hbQuantityType unit:bpmUnit];
@@ -629,6 +647,7 @@ static const NSInteger kNumberOfSamples = 5;
ORKHealthQuantityTypeRecorder *recorder = (ORKHealthQuantityTypeRecorder *)[self createRecorder:recorderConfiguration];
XCTAssertTrue([recorder isKindOfClass:recorderClass], @"");
#endif
}
@end
+4 -2
View File
@@ -204,13 +204,14 @@
// create the task as if we were to present it
ORKTaskViewController *taskViewController = [[ORKTaskViewController alloc] initWithTask:task taskRunUUID:nil];
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
// Trigger requestHealth access to fill in the read/write types ivars
NSSet *readTypes = [NSSet setWithObjects:[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate], nil];
NSSet *writeTypes = [NSSet setWithObjects:[HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierBloating], nil];
[taskViewController requestHealthStoreAccessWithReadTypes:readTypes writeTypes:writeTypes handler:^(){
// intentionally left empty
}];
#endif
// viewWillAppear fills in the _managedStepIdentifiers in the taskViewController
[taskViewController viewWillAppear:false];
@@ -244,10 +245,11 @@
ORKResultTestsHelper *taskDelegate = [[ORKResultTestsHelper alloc] init];
ORKTaskViewController *taskViewController = [[ORKTaskViewController alloc] initWithTask:task restorationData:encodedTaskViewControllerData delegate:taskDelegate error:nil];
#if ORK_FEATURE_HEALTHKIT_AUTHORIZATION
// confirm the read/write HK type info made it across the encode/decode bridge
XCTAssertEqualObjects([taskViewController requestedHealthTypesForRead], [NSSet setWithObject:[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]]);
XCTAssertEqualObjects([taskViewController requestedHealthTypesForWrite], [NSSet setWithObject:[HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierBloating]]);
#endif
ORKStepResult *stepResult = (ORKStepResult *)[[[taskViewController result] results] firstObject];
NSArray<ORKQuestionResult*> *questionResults = (NSArray<ORKQuestionResult*> *)[stepResult results];
XCTAssertEqual([questionResults count], 3);
@@ -9,12 +9,12 @@
/* Begin PBXBuildFile section */
03F7FD9F23959DD500432EF6 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F7FD9E23959DD500432EF6 /* SceneDelegate.swift */; };
0B6CB32728B577640092E993 /* Bundle+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B6CB32628B577640092E993 /* Bundle+Extensions.swift */; };
0BF63B3D2BC0977A00546F58 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BF63B3C2BC0977A00546F58 /* HealthKit.framework */; };
3C39E45E2950EFAD00BD96F6 /* ORKCatalog-Shared.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 3C39E45D2950EFAD00BD96F6 /* ORKCatalog-Shared.xcconfig */; };
3E39B9FB1ABF682D00C2ABE5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3E39B9F91ABF682D00C2ABE5 /* Main.storyboard */; };
3E39B9FE1ABF683700C2ABE5 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3E39B9FC1ABF683700C2ABE5 /* LaunchScreen.xib */; };
3E39BA001ABF683F00C2ABE5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3E39B9FF1ABF683F00C2ABE5 /* Images.xcassets */; };
3ED967B81AC13D37007E2D83 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ED967BA1AC13D37007E2D83 /* Localizable.strings */; };
863CCD821ACF545E009FD3B4 /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 863CCD811ACF545E009FD3B4 /* HealthKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
86B89AA51AB2C0A5001626A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86B89A9C1AB2C0A5001626A4 /* AppDelegate.swift */; };
9622283924F04DBF0056E74D /* TaskScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9622283824F04DBF0056E74D /* TaskScreen.swift */; };
9622283B24F04DFE0056E74D /* CommonElements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9622283A24F04DFE0056E74D /* CommonElements.swift */; };
@@ -60,6 +60,7 @@
/* Begin PBXFileReference section */
03F7FD9E23959DD500432EF6 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
0B6CB32628B577640092E993 /* Bundle+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Extensions.swift"; sourceTree = "<group>"; };
0BF63B3C2BC0977A00546F58 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };
246DF9FF1BEADFDF00591E9A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
246DFA021BEAE01700591E9A /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
246DFA031BEAE02100591E9A /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -104,7 +105,6 @@
3E39B9FD1ABF683700C2ABE5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
3E39B9FF1ABF683F00C2ABE5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
3ED967B91AC13D37007E2D83 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
863CCD811ACF545E009FD3B4 /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; };
863CCD831ACF545E009FD3B4 /* ORKCatalog.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = ORKCatalog.entitlements; sourceTree = "<group>"; };
869230BE1AAA890A00BFE11B /* ORKCatalog.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ORKCatalog.app; sourceTree = BUILT_PRODUCTS_DIR; };
86B89A981AB2C0A5001626A4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -135,7 +135,7 @@
buildActionMask = 2147483647;
files = (
BC2A3CD91C58F1CA00DA64B7 /* ResearchKit.framework in Frameworks */,
863CCD821ACF545E009FD3B4 /* HealthKit.framework in Frameworks */,
0BF63B3D2BC0977A00546F58 /* HealthKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -254,8 +254,8 @@
BC2A3C9E1C58E81500DA64B7 /* Frameworks */ = {
isa = PBXGroup;
children = (
0BF63B3C2BC0977A00546F58 /* HealthKit.framework */,
BC2A3CD81C58F1CA00DA64B7 /* ResearchKit.framework */,
863CCD811ACF545E009FD3B4 /* HealthKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -2,7 +2,7 @@
// ORKCatalog-Shared.xcconfig
//
ORK_CATALOG_VERSION_NUMBER = 2.2.15
ORK_CATALOG_VERSION_NUMBER = 2.2.16
ORK_CATALOG_BUILD_NUMBER = $(ORK_CATALOG_BUILD_NUMBER_CI_$(CI)) // ORK_CATALOG_BUILD_NUMBER_CI_TRUE or ORK_CATALOG_BUILD_NUMBER_CI_
ORK_CATALOG_BUILD_NUMBER_CI_TRUE = $(CI_BUILD_NUMBER) // if CI_BUILD_NUMBER is defined (presumably by CI) just use it
@@ -15,3 +15,19 @@ ORK_CATALOG_BUNDLE_ID = $(ORK_CATALOG_BUNDLE_ID_CI_$(USE_CI)) // ORK_CATALOG_BUN
ORK_CATALOG_BUNDLE_ID_CI_TRUE = $(USE_CI_BUNDLE_ID)$(ORK_CATALOG_CI_BUNDLE_ID_SUFFIX) // if CI_BUNDLE_ID is defined (presumably by CI) just use it, allow appending an optional suffix
ORK_CATALOG_BUNDLE_ID_CI_FALSE = $(ORK_CATALOG_BUNDLE_ID_BASE) // when not in CI, use the Base bundle ID
ORK_CATALOG_BUNDLE_ID_CI_ = $(ORK_CATALOG_BUNDLE_ID_CI_FALSE)
ORK_FEATURE_HEALTHKIT_AUTHORIZATION = 1
// GCC Preprocessor definitions
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC = $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_$(ORK_FEATURE_HEALTHKIT_AUTHORIZATION))
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_0 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION=0
ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC_1 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION=1
// Swift active compilation conditions
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT = $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_$(ORK_FEATURE_HEALTHKIT_AUTHORIZATION))
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_0 =
ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT_1 = ORK_FEATURE_HEALTHKIT_AUTHORIZATION
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_GCC)
SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(inherited) $(ORK_FEATURE_HEALTHKIT_DEFINITIONS_SWIFT)
@@ -2,7 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.healthkit</key>
<true/>
<key>com.apple.developer.healthkit</key>
<true/>
</dict>
</plist>
@@ -140,7 +140,7 @@ enum TaskListRow: Int, CustomStringConvertible {
/// Returns an array of all the task list row enum cases.
static var sections: [ TaskListRowSection ] {
let defaultSections = [
var defaultSections = [
TaskListRowSection(title: "Surveys", rows:
[
.form,
@@ -261,10 +261,8 @@ enum TaskListRow: Int, CustomStringConvertible {
case .weightQuestion:
return NSLocalizedString("Weight Question", comment: "")
case .healthQuantity:
return NSLocalizedString("Health Quantity Question", comment: "")
case .imageChoiceQuestion:
return NSLocalizedString("Image Choice Question", comment: "")
@@ -1190,7 +1188,7 @@ enum TaskListRow: Int, CustomStringConvertible {
let step3NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.heightQuestionStep3) + "NonOptional", title: NSLocalizedString("Height", comment: ""), question: exampleQuestionText, answer: answerFormat3)
step3NonOptional.text = "USC system (Non Optional)"
step3NonOptional.isOptional = false
let answerFormat4 = ORKHealthKitQuantityTypeAnswerFormat(quantityType: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.height)!, unit: HKUnit.meterUnit(with: .centi), style: .decimal)
let step4 = ORKQuestionStep(identifier: String(describing: Identifier.heightQuestionStep4), title: NSLocalizedString("Height", comment: ""), question: exampleQuestionText, answer: answerFormat4)
@@ -1207,80 +1205,78 @@ enum TaskListRow: Int, CustomStringConvertible {
/// This task demonstrates a question asking for the user weight.
private var weightQuestionTask: ORKTask {
let answerFormat1 = ORKAnswerFormat.weightAnswerFormat()
let step1 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep1), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat1)
step1.text = "Local system, default precision"
let step1NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep1) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat1)
step1NonOptional.text = "Local system, default precision (nonOptional)"
step1NonOptional.isOptional = false
let answerFormat2 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric)
let step2 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep2), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat2)
step2.text = "Metric system, default precision"
let step2NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep2) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat2)
step2NonOptional.text = "Metric system, default precision (nonOptional)"
step2NonOptional.isOptional = false
let answerFormat3 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric, numericPrecision: ORKNumericPrecision.low, minimumValue: ORKDoubleDefaultValue, maximumValue: ORKDoubleDefaultValue, defaultValue: ORKDoubleDefaultValue)
let step3 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep3), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat3)
step3.text = "Metric system, low precision"
let step1 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep1), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat1)
step1.text = "Local system, default precision"
let step1NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep1) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat1)
step1NonOptional.text = "Local system, default precision (nonOptional)"
step1NonOptional.isOptional = false
let answerFormat2 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric)
let step2 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep2), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat2)
step2.text = "Metric system, default precision"
let step2NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep2) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat2)
step2NonOptional.text = "Metric system, default precision (nonOptional)"
step2NonOptional.isOptional = false
let answerFormat3 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric, numericPrecision: ORKNumericPrecision.low, minimumValue: ORKDoubleDefaultValue, maximumValue: ORKDoubleDefaultValue, defaultValue: ORKDoubleDefaultValue)
let step3 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep3), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat3)
step3.text = "Metric system, low precision"
let step3NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep3) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat3)
step3NonOptional.text = "Metric system, low precision (nonOptional)"
step3NonOptional.isOptional = false
let answerFormat4 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric, numericPrecision: ORKNumericPrecision.high, minimumValue: 20.0, maximumValue: 100.0, defaultValue: 45.50)
let step4 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep4), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat4)
step4.text = "Metric system, high precision"
let step3NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep3) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat3)
step3NonOptional.text = "Metric system, low precision (nonOptional)"
step3NonOptional.isOptional = false
let answerFormat4 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.metric, numericPrecision: ORKNumericPrecision.high, minimumValue: 20.0, maximumValue: 100.0, defaultValue: 45.50)
let step4 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep4), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat4)
step4.text = "Metric system, high precision"
let step4NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep4) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat4)
step4NonOptional.text = "Metric system, high precision (nonOptional)"
step4NonOptional.isOptional = false
let answerFormat5 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.USC)
let step5 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep5), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat5)
step5.text = "USC system, default precision"
let step5NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep5) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat5)
step5NonOptional.text = "USC system, default precision (nonOptional)"
step5NonOptional.isOptional = false
let answerFormat6 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.USC, numericPrecision: ORKNumericPrecision.high, minimumValue: 50.0, maximumValue: 150.0, defaultValue: 100.0)
let step6 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep6), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat6)
step6.text = "USC system, high precision"
let step4NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep4) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat4)
step4NonOptional.text = "Metric system, high precision (nonOptional)"
step4NonOptional.isOptional = false
let answerFormat5 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.USC)
let step5 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep5), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat5)
step5.text = "USC system, default precision"
let step5NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep5) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat5)
step5NonOptional.text = "USC system, default precision (nonOptional)"
step5NonOptional.isOptional = false
let answerFormat6 = ORKAnswerFormat.weightAnswerFormat(with: ORKMeasurementSystem.USC, numericPrecision: ORKNumericPrecision.high, minimumValue: 50.0, maximumValue: 150.0, defaultValue: 100.0)
let step6 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep6), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat6)
step6.text = "USC system, high precision"
let step6NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep6) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat6)
step6NonOptional.text = "USC system, high precision (nonOptional)"
step6NonOptional.isOptional = false
let step6NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep6) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat6)
step6NonOptional.text = "USC system, high precision (nonOptional)"
step6NonOptional.isOptional = false
let answerFormat7 = ORKHealthKitQuantityTypeAnswerFormat(quantityType: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bodyMass)!, unit: HKUnit.gramUnit(with: .kilo), style: .decimal)
let step7 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep7), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat7)
step7.text = "HealthKit, body mass"
let answerFormat7 = ORKHealthKitQuantityTypeAnswerFormat(quantityType: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.bodyMass)!, unit: HKUnit.gramUnit(with: .kilo), style: .decimal)
let step7NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep7) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat7)
step7NonOptional.text = "HealthKit, body mass (nonOptional)"
step7NonOptional.isOptional = false
let step7 = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep7), title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat7)
step7.text = "HealthKit, body mass"
let step7NonOptional = ORKQuestionStep(identifier: String(describing: Identifier.weightQuestionStep7) + "NonOptional", title: NSLocalizedString("Weight", comment: ""), question: exampleQuestionText, answer: answerFormat7)
step7NonOptional.text = "HealthKit, body mass (nonOptional)"
step7NonOptional.isOptional = false
return ORKOrderedTask(identifier: String(describing: Identifier.weightQuestionTask), steps: [step1, step1NonOptional, step2, step2NonOptional, step3, step3NonOptional, step4, step4NonOptional, step5, step5NonOptional, step6, step6NonOptional, step7NonOptional, step7])
return ORKOrderedTask(identifier: String(describing: Identifier.weightQuestionTask), steps: [step1, step1NonOptional, step2, step2NonOptional, step3, step3NonOptional, step4, step4NonOptional, step5, step5NonOptional, step6, step6NonOptional, step7NonOptional, step7])
}
private var healthQuantityTypeTask: ORKTask {
let heartRateHealthKitQuantityTypeAnswerFormat = ORKHealthKitQuantityTypeAnswerFormat(quantityType: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!, unit: nil, style: .decimal)
let heartRateQuestion = ORKQuestionStep(identifier: String(describing: Identifier.healthQuantityQuestion1), title: NSLocalizedString("Heart Rate", comment: ""), question: "What is your Heart Rate?", answer: heartRateHealthKitQuantityTypeAnswerFormat)
@@ -1705,6 +1701,7 @@ enum TaskListRow: Int, CustomStringConvertible {
let notificationsPermissionType = ORKNotificationPermissionType(authorizationOptions: [.alert, .badge, .sound])
let motionActivityPermissionType = ORKMotionActivityPermissionType()
let locationPermissionType = ORKLocationPermissionType()
let healthKitTypesToWrite: Set<HKSampleType> = [
HKObjectType.quantityType(forIdentifier: .bodyMassIndex)!,
@@ -1719,11 +1716,9 @@ enum TaskListRow: Int, CustomStringConvertible {
let healthKitPermissionType = ORKHealthKitPermissionType(sampleTypesToWrite: healthKitTypesToWrite,
objectTypesToRead: healthKitTypesToRead)
let locationPermissionType = ORKLocationPermissionType()
let requestPermissionsStep = ORKRequestPermissionsStep(
identifier: String(describing: Identifier.requestPermissionsStep),
permissionTypes: [notificationsPermissionType, motionActivityPermissionType, healthKitPermissionType, locationPermissionType])
identifier: String(describing: Identifier.requestPermissionsStep),
permissionTypes: [notificationsPermissionType, motionActivityPermissionType, healthKitPermissionType, locationPermissionType])
requestPermissionsStep.title = "Health Data Request"
requestPermissionsStep.text = "Please review the health data types below and enable sharing to contribute to the study."