react-native-healthkit-bridge
Version:
A comprehensive React Native bridge for Apple HealthKit with TypeScript support, advanced authorization, and flexible data queries
241 lines (240 loc) • 10.6 kB
JavaScript
import { HealthKitBridge } from '../core/HealthKitBridge';
import { QuantityTypeIdentifier, HealthKitUnit } from '../types/healthkit.types';
/**
* 📊 EXAMPLE: Complete Health Data Flow
*
* This example shows how to:
* 1. Check authorization for specific data
* 2. Request authorization only when needed
* 3. Fetch data only for authorized types
* 4. Handle errors and authorization status
*/
export class HealthDataWorkflowExample {
constructor() {
this.bridge = new HealthKitBridge();
}
/**
* 📋 EXAMPLE 1: Check and Get Steps Data
*/
async getStepsData() {
var _a;
console.log('👣 Checking steps data...');
try {
// 1. Check authorization
const authStatus = await this.bridge.getAuthorizationStatus([
QuantityTypeIdentifier.StepCount
]);
const stepsAuth = authStatus[0];
console.log('🔐 Authorization status for steps:', stepsAuth);
// 2. If not authorized, request
if ((stepsAuth === null || stepsAuth === void 0 ? void 0 : stepsAuth.status) !== 'sharingAuthorized') {
console.log('🔄 Requesting authorization for steps...');
await this.bridge.requestSelectiveAuthorization([QuantityTypeIdentifier.StepCount], []);
// Check again
const newAuthStatus = await this.bridge.getAuthorizationStatus([QuantityTypeIdentifier.StepCount]);
if (((_a = newAuthStatus[0]) === null || _a === void 0 ? void 0 : _a.status) !== 'sharingAuthorized') {
return { authorized: false, data: 0, message: 'Authorization denied for steps' };
}
}
// 3. Fetch data
console.log('✅ Steps authorized! Fetching data...');
const stepsData = await this.bridge.getQuantitySamplesForDays(QuantityTypeIdentifier.StepCount, HealthKitUnit.count, 7);
const totalSteps = stepsData.reduce((acc, item) => acc + (item.value || 0), 0);
console.log('👣 Total steps (7 days):', totalSteps);
return { authorized: true, data: totalSteps, message: 'Data retrieved successfully' };
}
catch (error) {
console.error('❌ Error getting steps data:', error);
return { authorized: false, data: 0, message: `Error: ${error}` };
}
}
/**
* 📋 EXAMPLE 2: Complete Flow for Multiple Types
*/
async getHealthDashboard() {
var _a;
console.log('📊 Loading health dashboard...');
const healthMetrics = [
{ type: QuantityTypeIdentifier.StepCount, unit: HealthKitUnit.count, name: 'Steps' },
{ type: QuantityTypeIdentifier.HeartRate, unit: HealthKitUnit.beatsPerMinute, name: 'Heart Rate' },
{ type: QuantityTypeIdentifier.ActiveEnergyBurned, unit: HealthKitUnit.kilocalories, name: 'Active Energy' },
{ type: QuantityTypeIdentifier.DistanceWalkingRunning, unit: HealthKitUnit.meters, name: 'Distance' },
{ type: QuantityTypeIdentifier.AppleExerciseTime, unit: HealthKitUnit.minutes, name: 'Exercise Time' }
];
const results = {};
for (const metric of healthMetrics) {
try {
// 1. Check authorization
const authStatus = await this.bridge.getAuthorizationStatus([metric.type]);
const isAuthorized = ((_a = authStatus[0]) === null || _a === void 0 ? void 0 : _a.status) === 'sharingAuthorized';
if (isAuthorized) {
console.log(`✅ ${metric.name} authorized, fetching data...`);
// 2. Fetch data
const data = await this.bridge.getQuantitySamplesForDays(metric.type, metric.unit, 1 // Today
);
const total = data.reduce((acc, item) => acc + (item.value || 0), 0);
results[metric.name] = {
authorized: true,
value: total,
unit: metric.unit,
message: 'Data retrieved successfully'
};
console.log(`📊 ${metric.name}: ${total} ${metric.unit}`);
}
else {
console.log(`❌ ${metric.name} not authorized`);
results[metric.name] = {
authorized: false,
value: 0,
unit: metric.unit,
message: 'Not authorized'
};
}
}
catch (error) {
console.error(`❌ Error fetching ${metric.name}:`, error);
results[metric.name] = {
authorized: false,
value: 0,
unit: metric.unit,
message: `Error: ${error}`
};
}
}
return results;
}
/**
* 📋 EXAMPLE 3: Check and Request Smart Authorization
*/
async requestAuthorizationForTypes(types) {
console.log('🔐 Checking authorization for types:', types);
try {
// 1. Check current status
const authStatus = await this.bridge.getAuthorizationStatus(types);
console.log('📋 Current status:', authStatus);
// 2. Separate by status
const authorizedTypes = authStatus
.filter(item => item.status === 'sharingAuthorized')
.map(item => item.identifier);
const deniedTypes = authStatus
.filter(item => item.status === 'sharingDenied')
.map(item => item.identifier);
const notDeterminedTypes = authStatus
.filter(item => item.status === 'notDetermined' || item.status === 'unknown')
.map(item => item.identifier);
console.log('✅ Already authorized:', authorizedTypes);
console.log('❌ Denied:', deniedTypes);
console.log('❓ Not determined:', notDeterminedTypes);
// 3. If there are denied types, show instructions
if (deniedTypes.length > 0) {
console.log('⚠️ Some types were denied. Go to Settings > Privacy > Health to authorize manually.');
}
// 4. Request authorization only for not determined types
if (notDeterminedTypes.length > 0) {
console.log('🔄 Requesting authorization for:', notDeterminedTypes);
const authSuccess = await this.bridge.requestSelectiveAuthorization(notDeterminedTypes, []);
if (authSuccess) {
console.log('✅ Authorization requested successfully!');
// Check again
const newAuthStatus = await this.bridge.getAuthorizationStatus(notDeterminedTypes);
const newlyAuthorized = newAuthStatus
.filter(item => item.status === 'sharingAuthorized')
.map(item => item.identifier);
console.log('🎉 New authorized types:', newlyAuthorized);
return {
success: true,
authorizedTypes: [...authorizedTypes, ...newlyAuthorized],
deniedTypes,
message: `Authorization granted for: ${newlyAuthorized.join(', ')}`
};
}
else {
console.log('❌ Failed to request authorization');
return {
success: false,
authorizedTypes,
deniedTypes,
message: 'Failed to request authorization'
};
}
}
// 5. If all are already authorized
return {
success: true,
authorizedTypes,
deniedTypes,
message: 'All types are already authorized'
};
}
catch (error) {
console.error('❌ Error checking authorization:', error);
return {
success: false,
authorizedTypes: [],
deniedTypes: [],
message: `Error: ${error}`
};
}
}
/**
* 📋 EXAMPLE 4: Complete Health Data Flow
*/
async getCompleteHealthData() {
console.log('🚀 Starting complete health data flow...');
try {
// 1. Define required types
const requiredTypes = [
QuantityTypeIdentifier.StepCount,
QuantityTypeIdentifier.HeartRate,
QuantityTypeIdentifier.ActiveEnergyBurned,
QuantityTypeIdentifier.DistanceWalkingRunning,
QuantityTypeIdentifier.AppleExerciseTime
];
// 2. Check and request authorization
const authResult = await this.requestAuthorizationForTypes(requiredTypes);
if (!authResult.success) {
console.log('❌ Authorization failed:', authResult.message);
return { success: false, data: null, message: authResult.message };
}
// 3. Fetch data for authorized types
const healthData = await this.getHealthDashboard();
console.log('🎉 Complete flow finished!');
console.log('📊 Health data:', healthData);
return {
success: true,
data: healthData,
message: 'Data loaded successfully'
};
}
catch (error) {
console.error('❌ Error in complete flow:', error);
return {
success: false,
data: null,
message: `Error: ${error}`
};
}
}
}
/**
* 📋 HOW TO USE:
*
* ```typescript
* const example = new HealthDataWorkflowExample();
*
* // Get steps data
* const stepsResult = await example.getStepsData();
*
* // Check and request authorization for specific types
* const authResult = await example.requestAuthorizationForTypes([
* QuantityTypeIdentifier.StepCount,
* QuantityTypeIdentifier.HeartRate
* ]);
*
* // Get complete dashboard
* const dashboardData = await example.getHealthDashboard();
*
* // Complete flow
* const completeResult = await example.getCompleteHealthData();
* ```
*/