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