ForYouAndMe
[
](https://cocoapods.org/pods/ForYouAndMe))
[
](https://cocoapods.org/pods/ForYouAndMe))
[
](https://cocoapods.org/pods/ForYouAndMe))
Requirements
iOS 13.0+
Description
The ForYouAndMe project contains an Example Project to easily build and run an iOS app that implements the ForYouAndMe framework. Follow the instructions under Example Project paragraph to build and run it.
The ForYouAndMe framework is also available as an iOS CocoaPod library in order to use it in a new project created from scratch. Follow the instructions under Create a study app from scratch paragraph to build and run it.
Example Project
To run the example project:
-
clone the repo.
-
run
pod installfrom the Example directory. -
download your Firebase project
GoogleService-Info.plistfrom Firebase Console(follow instructions at https://firebase.google.com/docs/cloud-messaging/ios/client#upload_your_apns_authentication_key ) then move it under theExample/ForYouAndMefolder. -
open
ForYouAndMe.xcworkspace(not the .xcodeproj file!) with the latest version of XCode. -
in XCode select the
ForYouAndMeproject on the left panel and chooseSigning & Capabilitiestab and enter personal provisioning profile or chooseAutomatically manage signingand enterTeam -
On the
Signing & Capabilitiestab also ensure that your app Bundle Identifier matches with the created Firebase app id. -
Navigate - using Finder on Mac, or Windows Explorer on Windows - to
/Example/ForYouAndMefolder and rename theProjectInfo_sample.plisttoProjectInfo.plist. -
in XCode open
ProjectInfo.plistfile and fill the property values with the following:-
api_base_urlbase url of the server that provides your remote APIs(ex.: https://api.example.com). -
oauth_base_urlbase url of the server that handles your Oauth authentication against the supported integrations(ex.: https://oauth.example.com). -
study_ididentifier of your study as recorded on your server as thealiasof your study. -
pin_code_suffix(only needed in studies that use the pin login) pin code suffix needed for your study, or tononeif pin code is not supported for your study.
-
-
select the connected iPhone device or a simulator and run the app.
-
in XCode select the
ForYouAndMeproject on the left panel, chooseGeneraltab and, in theDisplay Namefield enter the app name you want to be displayed on the device.
Create a study app from scratch
The following instructions assume you want to install ForYouAndMe on a brand new project, created using the Storyboard option for the Interface setting and Swift as Language. Of course, this SDK is compatible with other initial settings, but you’ll have to change the project.
Create a new XCode project choosing App template, then fill the option as follows:
-
Product Name: name of the study project -
Team: name of your team defined on the Apple Developer Console -
Organizer Indentifier: your organisation identifier using the standard formatcom.company -
Bundle Identifier: it’s a read only field that shows the bundle id created concatenating theOrganizer Identifierand theProduct Name. IMPORTANT: this will be the unique identifier of the new app that will identify it on the App Store. -
Interface: selectStoryboard -
Language: selectSwift -
Use Core Data: uncheck it -
Include Tests: check it
Click on Next and choose the project location.
ForYouAndMe is available through CocoaPods. To install it follow these steps on terminal:
-
Install
CocoaPodsfollowing instructions on https://cocoapods.org/ -
Navigate to the project folder and run the command
pod init
A file called Podfile should have been generated.
3. Open the Podfile with XCode or another text editor and replace the content with the following lines:
platform :ios, '13.0'
use_frameworks!
# ignore all warnings from all pods
inhibit_all_warnings!
# Pods for project
def available_pods
pod 'ForYouAndMe'
end
target '<project_name>' do
available_pods
use_frameworks!
target '<test_project_name>' do
inherit! :search_paths
# Pods for testing
end
endReplace <project_name> with the name you entered on Product Name on the project creation step.
Replace <test_project_name> with the test project that has been created, its default name is <project_name>Tests where the <project_name> is the Product Name.
Save the modified file.
4. Run the command
pod install5. A <project_name>.xcworkspace file should have been generated under your project folder, open it with XCode.
Once you have installed ForYouAndMe, there are some additional steps to be done in order to configure your own study app:
Capabilities
Add the following Capabilities to your app:
-
Push Notifications
-
Access WiFi Information
Info.plist
Add or edit the following entries to your info.plist file:
-
UIViewControllerBasedStatusBarAppearanceset tofalse. -
UIUserInterfaceStyleset toLight. -
NSAppleMusicUsageDescriptionset to$(PRODUCT_NAME) uses Media Library during certain tasks. -
NSBluetoothAlwaysUsageDescriptionset to$(PRODUCT_NAME) uses Bluetooth to connect with wearables. -
NSBluetoothPeripheralUsageDescriptionset to$(PRODUCT_NAME) uses Bluetooth to connect with wearables. -
NSCalendarsUsageDescriptionset to$(PRODUCT_NAME) uses Calendar during certain tasks. -
NSCameraUsageDescriptionset to$(PRODUCT_NAME) captures photos and video during certain tasks. -
NSContactsUsageDescriptionset to$(PRODUCT_NAME) uses Contacts during certain tasks. -
NSLocationAlwaysAndWhenInUseUsageDescriptionset to$(PRODUCT_NAME) will use your location to verify information such as how far you travelled and the speed at which you travelled, as described in the informed consent. -
NSLocationWhenInUseUsageDescriptionset to$(PRODUCT_NAME) will use your location to verify information such as how far you travelled and the speed at which you travelled, as described in the informed consent. -
NSMicrophoneUsageDescriptionset to$(PRODUCT_NAME) records audio during certain tasks. -
NSMotionUsageDescriptionset to$(PRODUCT_NAME) will use your motion data for your active tasks. -
NSSpeechRecognitionUsageDescriptionset to$(PRODUCT_NAME) uses Speech Recognition during certain tasks. -
LSApplicationQueriesSchemesset an array of strings, containing:oura,fitbit,twitter,instagram,gcm-ciq
Below an example of the xml version of the above options:
...
<key>LSApplicationQueriesSchemes</key>
<array>
<string>oura</string>
<string>fitbit</string>
<string>twitter</string>
<string>instagram</string>
<string>gcm-ciq</string>
</array>
<key>NSAppleMusicUsageDescription</key>
<string>$(PRODUCT_NAME) uses Media Library during certain tasks.</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>$(PRODUCT_NAME) uses Bluetooth to connect with wearables.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>$(PRODUCT_NAME) uses Bluetooth to connect with wearables.</string>
<key>NSCalendarsUsageDescription</key>
<string>$(PRODUCT_NAME) uses Calendar during certain tasks.</string>
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) captures photos and video during certain tasks.</string>
<key>NSContactsUsageDescription</key>
<string>$(PRODUCT_NAME) uses Contacts during certain tasks.</string>
<key>NSHealthShareUsageDescription</key>
<string>$(PRODUCT_NAME) will use your health data for further analysis.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>$(PRODUCT_NAME) will use your location to verify information such as how far you travelled and the speed at which you travelled, as described in the informed consent.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>$(PRODUCT_NAME) will use your location to verify information such as how far you travelled and the speed at which you travelled, as described in the informed consent.</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) records audio during certain tasks.</string>
<key>NSMotionUsageDescription</key>
<string>$(PRODUCT_NAME) will use your motion data for your active tasks.</string>
<key>NSSpeechRecognitionUsageDescription</key>
<string>$(PRODUCT_NAME) uses Speech Recognition during certain tasks.</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
...Cleanup default files and settings
If you have installed ForYouAndMe on a brand new project, there are a few files and settings generated by Xcode (version 12.1 at the time of writing) that have to be fixed:
From the project
-
Remove
Main.storyboard. -
Remove
SceneDelegate.swift. -
Remove
ViewController.swift.
From the info.plist file
Remove the UIApplicationSceneManifest entry from info.plist.
In the General Tab
-
Set iOS 13.0 and iPhone .
-
Clear the
Main Interfacefield. -
Device Orientation:
Portrait,Landscape Left,Landscape Right.
In the AppDelegate class
-
Remove all methods under the
UISceneSession Lifecyclemark. -
Add an instance variable called
windowof typeUIWindow?using:var window: UIWindow?.
Project Info
Create a plist file called ProjectInfo.plist and add it to your project. Inside this file, add the following entries:
-
api_base_urlset to the base url of the server that provides your remote APIs. -
oauth_base_urlset to the base url of the server that handles your Oauth authentication against the supported integrations. -
study_idset to the identifier of your study as recorded on your server. -
pin_code_suffixset to the pin code suffix needed for your study, or tononeif pin code is not supported for your study.
How to customise a study app
Firebase
ForYouAndMe uses Firebase platform to track analytics, detect crashes and handle push notifications. Create a project on Firebase and add the resulting GoogleService-info.plist file to your project.
Then setup your Firebase project to handle push notifications by uploading the APNs Authentication Key of your app to your Firebase project Settings (see https://firebase.google.com/docs/cloud-messaging/ios/client#upload_your_apns_authentication_key for more details).
Study Video
You have to provide an introduction video for your app. This video format must be mp4. Name it StudyVideo.mp4 and add it to your project.
Images
ForYouAndMe requires that you provide a specific set of images to your default Assets.xcassets file. The images needed by the framework fall in two main categories: normal images and template images. While the first ones have no particular requirement, the second ones should be provided in grey scale as they will be used as template images and coloured by the framework according to the color palette of the current study.
Normal images list
image name | description |
|---|---|
back_button_primary | Button styled with primary color used for backward navigation typically located on page footers |
camera_switch | Button to switch front and rear camera during some tasks (e.g.: Video Diary) |
checkmark | Generic checkmark icon |
circular | Generic handle used in video player sliders |
clear_button | Clear icon for text fields |
clear_circular | Video player sliders' handle that will be used when the handle is disabled. Typically a transparent will do the trick. |
close_circle_button | Discard button for video diary |
edit | Edit button for text fields |
failure | Generic failure header image |
fitbit_icon | Fitbit device icon |
flash_off | Disabled flash icon for video record |
flash_on | Enabled flash icon for video record |
fyam_logo_generic | Generic logo image that should represent your organization |
fyam_logo_specific | Organization logo image specific of the current study |
health_icon | Health App permission icon |
garmin_icon | Garmin device icon |
instagram_icon | Instagram icon |
location_icon | Location permission icon |
main_logo | Current study logo |
next_button_primary | Button styled with primary color used for forward navigation typically located on page footers |
next_button_secondary_disabled | Button styled with secondary color in disabled mode, used on primary backgrounds |
next_button_secondary | Button styled with secondary color, used on primary backgrounds |
oura_icon | Oura device icon |
push_notification_icon | Push notification permission icon |
rescue_time_icon | Rescue time device icon |
star_empty | Empty rate image shown your data |
star_fill | Filled rate image shown your data |
twitter_icon | Twitter icon |
video_calendar | Calendar icon shown in video diary tasks |
video_pause | Pause button for video players |
video_play | Play button for video players |
video_record | Record button for video players |
video_recorded_feedback | Successful record icon shown in video diary tasks |
video_resume_record | Resume record button for video players |
video_time | Time icon for current record progress in video diary tasks |
Template images list
image name | description |
|---|---|
arrow_right | generic disclosure indicator |
back_button_navigation | generic back button used in navigation bars |
checkbox_filled | Generic filled checkbox icon |
checkbox_outline | Generic not filled checkbox icon |
close_button | Close button for modal pages |
contact_icon | Contacts page icon |
devices_icon | Your Apps and Devices page icon |
edit_small | Smaller edit button for text fields |
faq_icon | FAQ page icon |
filter_icon | Filter icon in Your Data |
permission_icon | Permission page icon |
radio_button_filled | Generic filled radio button icon |
radio_button_outline | Generic not filled radio button icon |
review_consent_icon | Review Consent page icon |
rewards_icon | Rewards summary page icon |
tab_feed | Feed tab icon |
tab_study_info | Study Info tab icon |
tab_task | Task tab icon |
tab_user_data | Your Data tab icon |
user_info_icon | Editable profile info page icon |
Framework AppDelegate setup
In your AppDelegate file, import the ForYouAndMe framework by including:
import ForYouAndMeAdd the following delegate method implementation:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return FYAMManager.orientationLock
}Lastly, in the application(_ application:, didFinishLaunchingWithOptions:) method delete all existing code and call the startup(withFontStyleMap:, showDefaultUserInfo:, checkResourcesAvailability:, enableLocationServices:) static method of the FYAMManager class and store the result in the previously created window variable.
This method takes three parameters:
-
fontStyleMap: a dictionary ofFontStyle->FontStyleData, whereFontStyleis an enum representing the palette of font styles used throughout the framework, andFontStyleDatais a struct that allows you to specify custom font, line spacing and uppercase flag for each font style. -
showDefaultUserInfo: whether or not to show a study-specific page that shows and allows to edit user's personal informations (will be removed in the future in favor of a more dynamic approach). -
appleWatchAlternativeIntegrations: list of Integrations (e.g.: Garmin, Fitbit, …) which are considered to be mutually exclusive with Apple Watch, regarding the data shown in Your Data. Specifically: if the user, during the Opt-In flow, has agreed to use the Apple Watch (thus she has granted the health permission), only Apple Watch data will be shown in the Your Data page, while all data coming from the integrations listed in this variable will be discarded. If the user has not agreed to use Apple Watch, data coming from Apple Watch will be discarded and all other data will be regularly shown. -
checkResourcesAvailability: whether or not font styles and images should be validated on startup to ensure that the framework has all the resources it needs. Default: false. -
enableLocationServices: whether or not to ask user location permission or show the relative permission in the permission page. Default: true. -
healthReadDataTypes: list of HealthDataType items that should be gathered via HealthKit and sent to the server. Note: this works only if HealthKit has been integrated (see later). Default: empty array.
Example:
var fontStyleMap: FontStyleMap = [:]
if let font = UIFont(name: "Helvetica", size: 24.0) {
fontStyleMap[.title] = FontStyleData(font: font, lineSpacing: 6.0, uppercase: false)
}
if let font = UIFont(name: "Helvetica", size: 20.0) {
fontStyleMap[.header2] = FontStyleData(font: font, lineSpacing: 6.0, uppercase: false)
}
if let font = UIFont(name: "Helvetica", size: 16.0) {
fontStyleMap[.paragraph] = FontStyleData(font: font, lineSpacing: 5.0, uppercase: false)
}
if let font = UIFont(name: "Helvetica", size: 13.0) {
fontStyleMap[.header3] = FontStyleData(font: font, lineSpacing: 3.0, uppercase: false)
}
if let font = UIFont(name: "Helvetica", size: 13.0) {
fontStyleMap[.menu] = FontStyleData(font: font, lineSpacing: 3.0, uppercase: true)
}
self.window = FYAMManager.startup(withFontStyleMap: fontStyleMap,
showDefaultUserInfo: true,
appleWatchAlternativeIntegrations: [.garmin, .fitbit],
checkResourcesAvailability: true,
enableLocationServices: false,
healthReadDataTypes: HealthDataType.allCases)
return trueBelow an example of how the AppDelegate file could looks like after the above steps:
import UIKit
import ForYouAndMe
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var fontStyleMap: FontStyleMap = [:]
if let font = UIFont(name: "Helvetica", size: 24.0) {
fontStyleMap[.title] = FontStyleData(font: font, lineSpacing: 6.0, uppercase: false)
}
if let font = UIFont(name: "Helvetica", size: 20.0) {
fontStyleMap[.header2] = FontStyleData(font: font, lineSpacing: 6.0, uppercase: false)
}
if let font = UIFont(name: "Helvetica", size: 16.0) {
fontStyleMap[.paragraph] = FontStyleData(font: font, lineSpacing: 5.0, uppercase: false)
}
if let font = UIFont(name: "Helvetica", size: 13.0) {
fontStyleMap[.header3] = FontStyleData(font: font, lineSpacing: 3.0, uppercase: false)
}
if let font = UIFont(name: "Helvetica", size: 13.0) {
fontStyleMap[.menu] = FontStyleData(font: font, lineSpacing: 3.0, uppercase: true)
}
self.window = FYAMManager.startup(withFontStyleMap: fontStyleMap,
showDefaultUserInfo: true,
appleWatchAlternativeIntegrations: [.garmin, .fitbit],
checkResourcesAvailability: true,
healthReadDataTypes: HealthDataType.allCases)
return true
}
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return FYAMManager.orientationLock
}
}Launch Screen (Optional)
Edit your default LaunchScreen.storyboard file to show a launch screen that fits your study.
HealthKit (Optional)
Currently data from user’s third party wearables are gathered through server-to-server scheduled operations. However Apple Watch cannot be accessed this way, so the app must take care of gathering data from the Health app and send them to the server.
If you want to include the use of Apple Watch in your study, use the following instructions:
-
Add the following entries to your Info.plist file:
-
NSHealthShareUsageDescriptionset to$(PRODUCT_NAME) will use your health data for further analysis(or something appropriate for your study). -
NSHealthUpdateUsageDescriptionset to$(PRODUCT_NAME) will update your health data based on your task results(actually, what you write here is irrelevant, since the purpose of the HealthKit implementation is just reading Health data. However, you need to add this key because otherwise you’ll get an error while uploading the app to AppStoreConnect, even if official Apple doc states that this description is needed only if you save data in the Health app).
-
-
Add the HealthKit capability to your project.
-
In AppDelegate, inside the
application(_ application:, didFinishLaunchingWithOptions:)method, provide thehealthReadDataTypesparameter to thestartupstatic method of theFYAMManagerclass. As value you’ll need to provide an array of cases of theHealthDataTypeenum, thus specifying what data you want to read from the Health app. -
Add the following code at the end of your PodFile:
post_install do |installer_representation|
installer_representation.pods_project.targets.each do |target|
if ['ForYouAndMe'].include? target.name
target.build_configurations.each do |config|
config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] = '$(inherited) HEALTHKIT'
end
end
end
endAuthor
LeonardoPasseri, [email protected]
License
ForYouAndMe is available under the MIT license. See the LICENSE file for more info.