1. SDKs
  2. React Native

1. Introduction

Our React Native library mirrors the functionality of our iOS and Android SDKs. It is a wrapper around the native SDKs, and it exposes the same methods and events. It is split into three parts: Core, Health and BLE Devices. They can be used interchangeably, but you need to install them separately. An example app can be found (here)[https://github.com/tryVital/vital-react-native/tree/main/example].

You can install the Core and Health SDK by using npm (BLE Devices coming soon):

2. Install your dependencies

npm install vital-core-react-native
npm install vital-health-react-native
npm install vital-devices-react-native

or

yarn add vital-core-react-native
yarn add vital-health-react-native
yarn add vital-devices-react-native

yarn install
cd ios && pod install

4. Configure your dependencies

You start by setting up the Core SDK. You need to configure it with your API key and the environment you want to use. You can find your API key in the Vital Dashboard. You can also enable logs by setting logsEnabled to true. You will need to chain the configuration according to the below order.

import { VitalCore } from "vital-core-react-native";

VitalCore.configure(VITAL_API_KEY, VITAL_ENVIRONMENT, VITAL_REGION, logsEnabled)
  .then(() => {
    // Core SDK is ready to use
  })
  .catch((error) => {
    // Something went wrong
  });

Be sure to do the configuration, before setting up the userId:

import { VitalCore } from "vital-core-react-native";

VitalCore.configure(VITAL_API_KEY, VITAL_ENVIRONMENT, VITAL_REGION, logsEnabled)
  .then(() => {
    // Core SDK is ready to use
    VitalCore.setUserId(userId);
  })
  .catch((error) => {
    // Something went wrong
  });

The Core SDK is now ready to use. You can now set up the HealthKit SDK and Devices SDK.

5. Health kit

You start by enabling HealthKit capabilities in your app. Please follow this guide. It should looks like this:

Don’t forget to add the NSHealthShareUsageDescription keys to your Info.plist file. Finally setting up the HealthKit SDK is just:

import { VitalHealth } from "vital-health-react-native";

// Configure HealthKit SDK
VitalHealth.configure(automaticConfiguration, numberOfDaysToPull, logsEnabled)
  .then(() => {
    // HealthKit SDK is ready to use
    VitalCore.setUserId(userId);
  })
  .catch((error) => {
    // Something went wrong
  });

If you set automaticConfiguration to true, the SDK will do everything on your behalf.

Before syncing data, you need to ask for permissions to the user. You do it by calling:

import { VitalHealth, VitalResource } from "vital-health-react-native";

// Configure HealthKit SDK
VitalHealth.configure(
  automaticConfiguration,
  numberOfDaysToPull,
  logsEnabled
).then(() => {
  // HealthKit SDK is ready to use
  VitalCore.setUserId(userId)
    .then(() => {
      VitalHealth.askForResources([
        VitalResource.Steps,
        VitalResource.Activity,
      ]);
    })
    .catch((error) => {
      // Something went wrong
    });
});

You can enable the SDK to deliver HealthKit data in background. This provides a more seamless experience, since the user doesn’t need to open your app to sync data. Start by enabling “Background Delivery” in the app capabilities:

You also need to do it inside your AppDelegate. Your didFinishLaunchingWithOptions should look like this:

#import "AppDelegate.h"
#import "VitalHealthKitConfiguration.h"

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  [VitalHealthKitConfiguration configureWithBackgroundDeliveryEnabled:true numberOfDaysToBackFill:90 enableLogs: true];

   // your code
}

If you do this, you don’t need to call VitalHealth.configure from your React Native code.

Finally, if you are logging out the user, please make sure you call:

import { VitalHealth } from "vital-health-react-native";

VitalHealth.cleanUp();

A full example of the app.js file can be seen below:

import React, { useEffect } from "react";
import { SafeAreaView, Text } from "react-native";
import { VitalCore } from "vital-core-react-native";
import { VitalHealth, VitalResource } from "vital-health-react-native";

const VITAL_API_KEY = "<API_KEY>";
const VITAL_ENVIRONMENT = "<sandbox | production>";
const VITAL_REGION = "<us | eu>";

const App = () => {
  useEffect(() => {
    VitalCore.configure(
      VITAL_API_KEY,
      VITAL_ENVIRONMENT,
      VITAL_REGION,
      true
    ).then(() => {
      VitalHealth.configure(true, 90, false).then(() => {
        VitalCore.setUserId("2c5879eb-7d99-468b-bb43-3fe0d71e93ba").then(() => {
          VitalHealth.askForResources([
            VitalResource.Steps,
            VitalResource.Activity,
          ]);
        });
      });
    });
  }, []);

  return (
    <SafeAreaView>
      <Text>Hello Vital React Native Implementiation</Text>
    </SafeAreaView>
  );
};

export default App;

6. Devices

To start getting events from the VitalDevicesManager you need to create an event emitter. You can see the possible event types in the VitalDevicesEvents object.

const eventEmitter = new NativeEventEmitter(VitalDevicesNativeModule);

Now you can create the devices manager

const vitalDevicesManager = new VitalDevicesManager();

Star scanning by providing one of the supported device.

let omronM7 = VitalDevicesManager.supportedDevices[1];
vitalDevicesManager.scanForDevice(omronM7);

You need to acquire the required permission for bluetooth before you can call scanForDevice.

To receive the scanned events you need to listen to them using the above created listener.

eventEmitter.addListener(VitalDevicesEvents.scanEvent, (event) => {
  console.log(VitalDevicesEvents.scanEvent, event);
});

After you have scanned a device you can start reading from it.

vitalDevicesManager.readBloodPressure(event.id);

or

vitalDevicesManager.readGlucoseMeter(event.id);

The read results will arrive in the event lister too.

eventEmitter.addListener(
  VitalDevicesEvents.bloodPressureReadEvent,
  (event) => {}
);

or

eventEmitter.addListener(
  VitalDevicesEvents.glucoseMeterReadEvent,
  (event) => {}
);

After you are done reading from the device you need to call the scan method on the VitalDevicesManager to continuously receive reads.

7. Troubleshooting

For older React Native projects, you might see the following warnings when compiling:

ld: warning: Could not find or use auto-linked library 'swiftCoreFoundation'
ld: warning: Could not find or use auto-linked library 'swiftCompatibility50'
ld: warning: Could not find or use auto-linked library 'swiftObjectiveC'
ld: warning: Could not find or use auto-linked library 'swiftFoundation'
ld: warning: Could not find or use auto-linked library 'swiftsimd'
ld: warning: Could not find or use auto-linked library 'swiftDarwin'
ld: warning: Could not find or use auto-linked library 'swiftUIKit'
ld: warning: Could not find or use auto-linked library 'swiftCore'
ld: warning: Could not find or use auto-linked library 'swiftQuartzCore'
ld: warning: Could not find or use auto-linked library 'swiftCoreGraphics'
ld: warning: Could not find or use auto-linked library 'swiftPhotos'
ld: warning: Could not find or use auto-linked library 'swiftSwiftOnoneSupport'
ld: warning: Could not find or use auto-linked library 'swiftCoreImage'
ld: warning: Could not find or use auto-linked library 'swiftCompatibilityDynamicReplacements'
ld: warning: Could not find or use auto-linked library 'swiftMetal'
ld: warning: Could not find or use auto-linked library 'swiftDispatch'
ld: warning: Could not find or use auto-linked library 'swiftAVFoundation'
ld: warning: Could not find or use auto-linked library 'swiftCoreMedia'
ld: warning: Could not find or use auto-linked library 'swiftCoreAudio'
ld: warning: Could not find or use auto-linked library 'swiftCoreMIDI'
ld: warning: Could not find or use auto-linked library 'swiftCoreLocation'

These are followed by Swift related errors. You might need to do one, or more, of the following steps:

  1. [Reference] Go to your Podfile and add the following:
 post_install do |installer|
    react_native_post_install(installer)
    fix_library_search_paths(installer)
  end
end

def fix_library_search_paths(installer)
  def fix_config(config)
    lib_search_paths = config.build_settings["LIBRARY_SEARCH_PATHS"]
    if lib_search_paths
      if lib_search_paths.include?("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)") || lib_search_paths.include?("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
        # $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) causes problem with Xcode 12.5 + arm64 (Apple M1)
        # since the libraries there are only built for x86_64 and i386.
        lib_search_paths.delete("$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)")
        lib_search_paths.delete("\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"")
        if !(lib_search_paths.include?("$(SDKROOT)/usr/lib/swift") || lib_search_paths.include?("\"$(SDKROOT)/usr/lib/swift\""))
          # however, $(SDKROOT)/usr/lib/swift is required, at least if user is not running CocoaPods 1.11
          lib_search_paths.insert(0, "$(SDKROOT)/usr/lib/swift")
        end
      end
    end
  end

  projects = installer.aggregate_targets
    .map{ |t| t.user_project }
    .uniq{ |p| p.path }
    .push(installer.pods_project)

  projects.each do |project|
    project.build_configurations.each do |config|
      fix_config(config)
    end
    project.native_targets.each do |target|
      target.build_configurations.each do |config|
        fix_config(config)
      end
    end
    project.save()
  end
end

2.[Reference] In your project settings, modifiy Library Search Paths. Remove:

"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"

And add:

"$(SDKROOT)/usr/lib/swift"

3.[Reference] Add a single Swift file to the root of your project named File.swift with the following content:

import Foundation

When adding this file, Xcode will ask you if you would like a bridging header. Select Create Bridging Header.