暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

iOSStepCounter.mm 4.9KB

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