【Unity】iOSのヘルスケアの歩数を取得するプラグイン

UnityからiOSのヘルスケアへアクセスしたかったのでプラグインを調べました。

objective-c
stepCount.mm
~~~
#import <HealthKit/HealthKit.h>

@interface StepCounter : NSObject
@property (nonatomic, strong) HKHealthStore *healthStore;
@end

@implementation StepCounter

- (instancetype)init {
    self = [super init];
    if (self) {
        self.healthStore = [[HKHealthStore alloc] init];
    }
    return self;
}

- (void)requestAuthorization {
    HKObjectType *stepType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
    NSSet *typesToShare = nil;
    NSSet *typesToRead = [NSSet setWithObject:stepType];
    [self.healthStore requestAuthorizationToShareTypes:typesToShare readTypes:typesToRead completion:^(BOOL success, NSError *error) {
        if (success) {
            NSLog(@"Authorization succeeded");
        } else {
            NSLog(@"Authorization failed");
        }
    }];
}

- (void)getStepCount:(void (^)(NSInteger))completionHandler {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *interval = [[NSDateComponents alloc] init];
    interval.day = 1;

    NSDate *endDate = [NSDate date];
    NSDate *startDate = [calendar dateByAddingComponents:interval toDate:endDate options:0];

    HKQuantityType *stepType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
    NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionStrictStartDate];

    HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:stepType predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:nil resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
        if (error) {
            NSLog(@"An error occurred while executing the step count query: %@", error.localizedDescription);
            completionHandler(0);
            return;
        }

        NSInteger stepCount = 0;
        for (HKQuantitySample *result in results) {
            HKQuantity *quantity = result.quantity;
            HKUnit *countUnit = [HKUnit countUnit];
            double count = [quantity doubleValueForUnit:countUnit];
            stepCount += count;
        }

        completionHandler(stepCount);
    }];

    [self.healthStore executeQuery:query];
}

@end
~~~



Unity
~~~
using UnityEngine;
using System.Runtime.InteropServices;

public class StepCounter : MonoBehaviour
{
    [DllImport("__Internal")]
    private static extern void requestAuthorization();

    [DllImport("__Internal")]
    private static extern void getStepCount(System.IntPtr completionHandler);

    private void Start()
    {
        requestAuthorization();
    }

    private void OnGUI()
    {
        if (GUILayout.Button("Get Step Count"))
        {
            getStepCount(Marshal.GetFunctionPointerForDelegate(new StepCountCompletionHandler(OnStepCountReceived)));
        }
    }

    private void OnStepCountReceived(int stepCount)
    {
        Debug.Log("Step count: " + stepCount);
    }

    private delegate void StepCountCompletionHandler(int stepCount);
}
~~~


このスクリプトは、UnityでiOSプラグインを呼び出す方法を示しています。
requestAuthorizationメソッドを使用して、HealthKitへのアクセス許可をリクエストし、getStepCountメソッドを使用して、指定された期間内のステップ数を取得します。

getStepCountメソッドには、System.IntPtr型のcompletionHandler引数があります。この引数には、ステップ数を受け取った後に実行するコールバック関数のポインタが指定されます。Marshal.GetFunctionPointerForDelegateメソッドを使用して、C#デリゲートを関数ポインタに変換します。このコールバック関数は、OnStepCountReceivedメソッドで定義されています。

このスクリプトは、ボタンをクリックすることでステップ数を取得し、OnStepCountReceivedメソッドを呼び出して、取得したステップ数をログに出力します。