File size: 5,050 Bytes
18a519f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | #if defined(__APPLE__)
#include <TargetConditionals.h>
#if TARGET_OS_IOS
#include <CoreMotion/CoreMotion.h>
#define ENABLE_STEP_COUNTER_LOGGING 1
#if ENABLE_STEP_COUNTER_LOGGING
#define STEP_COUNTER_LOG(...) NSLog(@"StepCounter - %@", [NSString stringWithFormat: __VA_ARGS__])
#else
#define STEP_COUNTER_LOG(...) {}
#endif
class iOSStepCounterWrapper
{
public:
typedef void (*OnDataReceived) (int deviceId, int numberOfSteps);
struct iOSStepCounterCallbacks
{
OnDataReceived dataReceived;
};
iOSStepCounterWrapper()
{
m_Pedometer = nullptr;
m_Device = -1;
}
void Enable(int deviceId, iOSStepCounterCallbacks* callbacks)
{
if (IsEnabled())
{
STEP_COUNTER_LOG(@"Was already enabled?");
if (m_Device != deviceId)
STEP_COUNTER_LOG(@"Enabling with different device id? Expected %d, was %d. Are you creating more than one iOSStepCounter", m_Device, deviceId);
}
m_Pedometer = [[CMPedometer alloc]init];
m_Callbacks = *callbacks;
m_Device = deviceId;
[m_Pedometer startPedometerUpdatesFromDate: [NSDate date] withHandler:^(CMPedometerData * _Nullable pedometerData, NSError * _Nullable error)
{
// Note: We need to call our callback on the same thread the Unity scripting is operating
dispatch_async(dispatch_get_main_queue(), ^{
if (error != nil)
{
STEP_COUNTER_LOG(@"startPedometerUpdatesFromDate threw an error '%@', was it authorized?", [error localizedDescription]);
if (m_Device != -1)
Disable(m_Device);
return;
}
// Guard against situation where device was disabled, any event which are received after that, should be ignored.
if (m_Device == -1)
return;
m_Callbacks.dataReceived(m_Device, [pedometerData.numberOfSteps intValue]);
});
}];
}
bool Disable(int deviceId)
{
if (m_Pedometer == nullptr)
return false;
if (m_Device != deviceId)
STEP_COUNTER_LOG(@"Disabling with wrong device id, expected %d, was %d", m_Device, deviceId);
[m_Pedometer stopPedometerUpdates];
m_Pedometer = nullptr;
m_Device = -1;
return true;
}
bool IsEnabled() const
{
return m_Pedometer != nullptr;
}
private:
CMPedometer* m_Pedometer;
iOSStepCounterCallbacks m_Callbacks;
int m_Device;
};
static iOSStepCounterWrapper s_Wrapper;
static const int kResultSuccess = 1;
static const int kResultFailure = -1;
extern "C" int _iOSStepCounterIsAvailable()
{
return [CMPedometer isStepCountingAvailable] ? 1 : 0;
}
extern "C" int _iOSStepCounterGetAuthorizationStatus()
{
if (@available(iOS 11.0, *))
{
return (int)[CMPedometer authorizationStatus];
}
return 0;
}
extern "C" int _iOSStepCounterEnable(int deviceId, iOSStepCounterWrapper::iOSStepCounterCallbacks* callbacks, int sizeOfCallbacks)
{
if (sizeof(iOSStepCounterWrapper::iOSStepCounterCallbacks) != sizeOfCallbacks)
{
STEP_COUNTER_LOG(@"iOSStepCounterCallbacks size mismatch, expected %lu was %d", sizeof(iOSStepCounterWrapper::iOSStepCounterCallbacks), sizeOfCallbacks);
return kResultFailure;
}
if (_iOSStepCounterIsAvailable() == 0)
{
STEP_COUNTER_LOG(@"Step counting is not available");
return kResultFailure;
}
NSString* motionUsage = @"NSMotionUsageDescription";
if ([[NSBundle mainBundle] objectForInfoDictionaryKey: motionUsage] == nil)
{
STEP_COUNTER_LOG(@"%@ is missing in Info.plist, please enable Motion Usage in Input Settings", motionUsage);
return kResultFailure;
}
if (@available(iOS 11.0, *))
{
if ([CMPedometer authorizationStatus] == CMAuthorizationStatusRestricted)
{
STEP_COUNTER_LOG(@"Step Counter was restricted.");
return kResultFailure;
}
if ([CMPedometer authorizationStatus] == CMAuthorizationStatusDenied)
{
STEP_COUNTER_LOG(@"Step Counter was denied. Enable Motion & Fitness under app settings.");
return kResultFailure;
}
// Do nothing for Authorized and NotDetermined
}
// Note: After installation this function will prompt a dialog asking about Motion & Fitness authorization
// If user denies the prompt, there will be an error in startPedometerUpdatesFromDate callback
// The dialog only appears once, not sure how to trigger it again, besides reinstalling app
s_Wrapper.Enable(deviceId, callbacks);
return kResultSuccess;
}
extern "C" int _iOSStepCounterDisable(int deviceId)
{
return s_Wrapper.Disable(deviceId) ? kResultSuccess : kResultFailure;
}
extern "C" int _iOSStepCounterIsEnabled(int deviceId)
{
return s_Wrapper.IsEnabled() ? 1 : 0;
}
#endif
#endif
|