UNPKG

react-native-healthkit-bridge

Version:

A comprehensive React Native bridge for Apple HealthKit with TypeScript support, advanced authorization, and flexible data queries

290 lines (244 loc) 9.44 kB
import { HealthKitBridge } from '../core/HealthKitBridge'; import { QuantityTypeIdentifier, CategoryTypeIdentifier, 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 { private bridge: HealthKitBridge; constructor() { this.bridge = new HealthKitBridge(); } /** * 📋 EXAMPLE 1: Check and Get Steps Data */ async getStepsData() { 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?.status !== 'sharingAuthorized') { console.log('🔄 Requesting authorization for steps...'); await this.bridge.requestSelectiveAuthorization([QuantityTypeIdentifier.StepCount] as any, []); // Check again const newAuthStatus = await this.bridge.getAuthorizationStatus([QuantityTypeIdentifier.StepCount]); if (newAuthStatus[0]?.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() { 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: any = {}; for (const metric of healthMetrics) { try { // 1. Check authorization const authStatus = await this.bridge.getAuthorizationStatus([metric.type]); const isAuthorized = authStatus[0]?.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: QuantityTypeIdentifier[]) { 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 as any, []); if (authSuccess) { console.log('✅ Authorization requested successfully!'); // Check again const newAuthStatus = await this.bridge.getAuthorizationStatus(notDeterminedTypes as any); 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(); * ``` */