You want full control over your apps user experience? No problem, the SDK provides all the tools you need to create a powerful UI for data source connections.
If your UX requires a custom data source connection flow, you can easily build such screen using the Thryve SDK helper methods.
Connect/disconnect web data sources
There are two web links you need to allow your users to connect and disconnect their web data sources, respectively. To obtain these, use the getConnectDataSourceUrl and getRevokeDataSourceUrl methods of the SDK and specify the dataSourceId for the data source, you want to connect/disconnect.
The following example shows usage of getConnectDataSourceUrl and getRevokeDataSourceUrl for connection/disconnection of Fitbit:
We recommend opening the link in an external browser and not a web view within your application. Web-views do not support social logins (e.g. Google, Facebook, or Apple sign-ins) that might be used by your end-users for certain data sources.
To make sure your user gets automatically forwarded back to your application after successfully connecting, make sure to specify a redirect URI using the redirect_uri parameter of the above SDK methods.
Connect/disconnect native data sources
Display only available native data source
Not all native data sources are available on all devices, either because they are not installed or set up by the end user. Therefore, make sure to use the isAvailable method of the SDK to only display the data source if the method returns true to avoid errors.
Connect and disconnect native data sources
Authorization of native data sources is happening on the operating system level. To make your users connect to Apple Health, Health Connect, or Samsung Health, simply call start for the corresponding source.
Ensure you have imported and configured the needed SDK modules.
The SDK will request access to the types specified in the config object and will take care of everything, and create the connection after authorization by the end-user.
To disconnect the data source, simply call stop and the SDK will not retrieve any data and no further data will be stored until start is called again for the user.
After calling stop the connection to your app will still appear active in Apple Health. Apple does not allow developers to revoke the connection, and only users can manually revoke access inside the Health app. The internal functionalities of the Thryve service, however, will make sure no new data is stored after stop is called until start is called again.
Obtain the correct connection status
To accurately display the connection status of data sources to users, use ThryveSDK.get().getUserInformation. This method returns a list of connectedSources their IDs. Additionally, connectedAt provides the timestamp of when the user connected to each data source.
Example of button states that change depending on information returned by getUserInformation
Use the retrieved information to update the interface. Modify button actions based on this data: allow users to disconnect from connected data sources and encourage them to connect to those that are not yet linked.
import UIKit
import ThryveSDK
import ThryveCommons
/**
Async function that fetches the connect‐URL for Fitbit via ThryveSDK and opens it in the default browser.
- Data Source ID: `1` is hardcoded for Fitbit. Change if you need to connect a different data source.
- Redirect URL: Specify your app’s custom URL scheme so the user can be sent back into the app after authorizing.
- You can find more info about setting up schema url on: `https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app`
*/
@MainActor
func connectFitbit() async {
// 1) Request the connect URL for Fitbit (dataSourceId = 1)
let response = await ThryveSDK.get().getConnectDataSourceUrl(
dataSourceId: 1,
redirectUrl: "showThryve://"
)
if let url = response.data {
// 2) Open the URL in Safari (or default browser)
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
// 3) Surface or log the error(s)
if let errors = response.errors {
for error in errors {
Logger.i { "Failed to connect \(providerName): \(error.errorMessage ?? "Unknown")" }
}
}
}
/**
Async function that fetches the revoke‐URL for Fitbit via ThryveSDK and opens it in the default browser.
- Data Source ID: `1` is hardcoded for Fitbit. Change if you need to disconnect a different data source.
- `requireUserAction`: If `true`, the user will see a confirmation prompt in the browser before revocation.
- Redirect URL: Specify your app’s custom URL scheme so the user can be sent back into the app after finishing the revocation flow.
- You can find more info about setting up schema url on: `https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app`
*/
@MainActor
func disconnectFitbit() async {
// 1) Request the revoke URL for Fitbit (dataSourceId = 1)
let response = await ThryveSDK.get().getRevokeDataSourceUrl(
dataSourceId: 1,
requireUserAction: false,
redirectUrl: "showThryve://"
)
if let url = response.data {
// 2) Open the URL in Safari (or default browser)
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
// 3) Surface or log the error(s)
if let errors = response.errors {
for error in errors {
Logger.i { "Failed to disconnect \(providerName): \(error.errorMessage ?? "Unknown")" }
}
}
}
import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.model.ThryveResponse
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// … your layout inflation, etc.
}
/**
* Async function that fetches the “connect” URL for Fitbit via ThryveSDK
* and opens it in the default browser.
*
* - dataSourceId = 1 (Fitbit). Change for other sources.
* - redirectUrl = "showThryve://" (your app’s deep‐link scheme).
*/
private fun connectWebDataSource(context: Context) {
// Launch a coroutine on the IO dispatcher so we don't get a NetworkOnMainThreadException
viewModelScope.launch(Dispatchers.IO) {
val response = thryveSDK.getConnectDataSourceUrl(
dataSourceId = 1, // Use the Id of the preferred Web data source
redirectUri = "showThryve://",
)
if (response.successful) {
val intent = Intent(Intent.ACTION_VIEW, response.data?.toUri()).apply {
if (context !is Activity) {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
}
// Switch to Main dispatcher for UI operations
withContext(Dispatchers.Main) {
try {
context.startActivity(intent)
} catch (e: ActivityNotFoundException) {
Log.e(TAG, "❌ No browser app to handle connect URL", e)
}
}
} else {
Log.e(TAG, "❌ Failed to retrieve connect URL: ${response.errors.joinToString()}")
return@launch
}
}
}
/**
* Async function that fetches the “revoke” URL for Fitbit via ThryveSDK
* and opens it in the default browser.
*
* - dataSourceId = 1 (Fitbit). Change for other sources.
* - requireUserAction = false (no confirmation prompt in browser).
* - redirectUrl = "showThryve://".
*/
private fun disconnectWebDataSource(context: Context) {
// Launch a coroutine on the IO dispatcher so we don't get a NetworkOnMainThreadException
viewModelScope.launch(Dispatchers.IO) {
val response = thryveSDK.getRevokeDataSourceUrl(
dataSourceId = 1,
requireUserAction = false,
redirectUri = "showThryve://"
)
}
}
if (response.successful) {
val intent = Intent(Intent.ACTION_VIEW, response.data?.toUri()).apply {
if (context !is Activity) {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
}
// Switch to Main dispatcher for UI operations
withContext(Dispatchers.Main) {
try {
context.startActivity(intent)
Log.i(TAG, "✅ Revoke URL launched for ${source.source}")
} catch (e: ActivityNotFoundException) {
Log.e(TAG, "❌ No browser app to handle revoke URL", e)
}
}
} else {
Log.e(TAG, "❌ Failed to retrieve revoke URL: ${response.errors.joinToString()}")
return@launch
}
}
}
}
// Assumes you have installed and linked:
// "thryve-sdk" and you import ThryveSDK from it.
// Also import Linking from 'react-native'.
import { ThryveSDK } from '@thryve/react-native-sdk-module';
import { Linking } from 'react-native';
/**
* Async function that fetches the "connect" URL for Fitbit via ThryveSDK
* and opens it in the default browser.
*
* - dataSourceId: 1 (Fitbit). Change for other sources.
* - redirectUrl: "showThryve://".
*/
export async function connectFitbit() {
const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
try {
const response = await sdk.getConnectDataSourceUrl(1, 'showThryve://');
if (response?.data) {
const url = response.data; // Should be a string or URL object
await Linking.openURL(url.toString());
} else {
console.error('❌ Failed to retrieve Fitbit connect URL:', response.errors);
// Optionally: // Optionally: Alert your users of each error in response.errors
}
} catch (err) {
console.error('❌ Unexpected error in connectFitbit():', err);
}
}
/**
* Async function that fetches the "revoke" URL for Fitbit via ThryveSDK
* and opens it in the default browser.
*
* - dataSourceId: 1 (Fitbit). Change for other sources.
* - requireUserAction: false (no confirmation prompt in browser).
* - redirectUrl: "showThryve://".
*/
export async function disconnectFitbit() {
const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
try {
const response = await sdk.getRevokeDataSourceUrl(1, false, 'showThryve://');
if (response?.data) {
const url = response.data;
await Linking.openURL(url.toString());
} else {
console.error('❌ Failed to retrieve Fitbit revoke URL:', response.errors);
// Optionally: Alert your users of each error in response.errors
}
} catch (err) {
console.error('❌ Unexpected error in disconnectFitbit():', err);
}
}
import 'package:flutter/material.dart';
import 'package:thryve_sdk/thryve_sdk.dart';
import 'package:url_launcher/url_launcher.dart';
/**
* Async function that fetches the "connect" URL for Fitbit via ThryveSDK
* and opens it in the default browser.
*
* - dataSourceId: 1 (Fitbit). Change for other sources.
* - redirectUrl: "showThryve://".
*/
Future<void> connectFitbit() async {
final sdk = ThryveSDK.getOrCreate();
final response = await sdk.getConnectDataSourceUrl(
dataSourceId: 1,
redirectUrl: 'showThryve://',
);
if (response is ThryveResponseSuccess<Uri>) {
final Uri url = response.value;
// Open the URL in the default browser
if (await canLaunchUrl(url)) {
await launchUrl(url);
} else {
debugPrint('⚠️ Could not launch URL: $url');
}
} else if (response is ThryveResponseFailure<Uri>) {
debugPrint('❌ Failed to retrieve Fitbit connect URL: ${response.error}');
} else {
debugPrint('❌ Unexpected response type for connectFitbit()');
}
}
/**
* Async function that fetches the "revoke" URL for Fitbit via ThryveSDK
* and opens it in the default browser.
*
* - dataSourceId: 1 (Fitbit). Change for other sources.
* - requireUserAction: false (no confirmation prompt in browser).
* - redirectUrl: "showThryve://".
*/
Future<void> disconnectFitbit() async {
final sdk = ThryveSDK.getOrCreate();
final response = await sdk.getRevokeDataSourceUrl(
dataSourceId: 1,
requireUserAction: false,
redirectUrl: 'showThryve://',
);
if (response is ThryveResponseSuccess<Uri>) {
final Uri url = response.value;
if (await canLaunchUrl(url)) {
await launchUrl(url);
} else {
debugPrint('⚠️ Could not launch URL: $url');
}
} else if (response is ThryveResponseFailure<Uri>) {
debugPrint('❌ Failed to retrieve Fitbit revoke URL: ${response.error}');
} else {
debugPrint('❌ Unexpected response type for disconnectFitbit()');
}
}
import UIKit
import ThryveCore
import HealthKit
import ThryveCommons
/**
Async function that starts Apple Health integration and requests authorization via ThryveSDK for a given set of HealthKit data types.
- `source`: Always use `.apple` for HealthKit.
- `types`: A `Set<AnyHashable>` of `ThryveAppleHealthConnectorDataType` values, e.g. `[.stepCount]`.
Passing `nil` will default to whatever types were configured in your ThryveSDK configuration object.
*/
@MainActor
func connectAppleHealth(types: Set<AnyHashable>? = nil) async {
// Passing `nil` here causes the SDK to request permissions for the types defined in its config.
let response: ThryveResponse<Bool> = await ThryveSDK.get().start(
dataSource: .apple,
dataTypes: types
)
if response.successful {
Logger .i { "✅ Apple Health integration started successfully (using configured types)." }
return
}
if let errors = response.errors {
for error in errors {
Logger.i { "Failed to start Apple Health: \(error.errorMessage ?? "Unknown")" }
}
}
}
/**
Async function that stops Apple Health integration via ThryveSDK.
- `source`: Always use `.apple` for HealthKit.
*/
@MainActor
func disconnectAppleHealth() async {
let response: ThryveResponse<Bool> = await ThryveSDK.get().stop(dataSource: .apple)
if response.successful {
Logger.i{ "✅ Apple Health integration stopped successfully." }
return
}
if let errors = response.errors {
for error in errors {
Logger.i { "Failed to stop Apple Health: \(error.errorMessage ?? "Unknown")" }
}
}
}