birkir / react-native-carplay

CarPlay with React Native
https://birkir.dev/react-native-carplay/
MIT License
628 stars 104 forks source link

Network data does not update on carplay screen when phone goes screen off #102

Closed vladamx closed 1 year ago

vladamx commented 1 year ago

Having an issue with carplay not being able to update network data when phone goes screen off.

When i wake the device carplay refreshes and everything works fine. This is happening only on real device. It works fine on simulator

Do you have any ideas as to why is this happening? Don't know where to look next

vladamx commented 1 year ago

It seems like timers do not work when phone is sleeping. I was using them for debouncing

tezqa commented 5 months ago

This issue can be resolved by using DispatchQueue to delay a JS function call.

- CarPlayManagerBridge.m

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface RCT_EXTERN_MODULE(CarPlayManager, RCTEventEmitter)

RCT_EXTERN_METHOD(supportedEvents)

RCT_EXTERN_METHOD(sleep: (NSString *) taskId
                  delayMs: (nonnull NSNumber *)delayMs
                  resolve: (RCTPromiseResolveBlock)resolve
                  reject: (RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(clearSleep: (NSString *) taskId)

+ (BOOL)requiresMainQueueSetup {
  return NO;
}

@end

- CarPlayManager.swift

@objc(CarPlayManager)
class CarPlayManager: RCTEventEmitter {
  var tasks: [String: DispatchWorkItem] = [:]

  override func supportedEvents() -> [String]! {
    return []
  }

  @objc(sleep:delayMs:resolve:reject:)
  public func sleep(taskId: String,
                         delayMs: NSNumber,
                         resolve: @escaping RCTPromiseResolveBlock,
                         reject: @escaping RCTPromiseRejectBlock) {
    let task = DispatchWorkItem {
      self.clearSleep(taskId: taskId)
      resolve(nil)
    }
    tasks[taskId] = task
    DispatchQueue.main.asyncAfter(deadline: .now() + delayMs.doubleValue / 1000, execute: task)
  }

  @objc(clearSleep:)
  public func clearSleep(taskId: String) {
    if let task = tasks[taskId], !task.isCancelled {
        task.cancel()
    }
    tasks.removeValue(forKey: taskId)
  }
}

- carplay.ts

let taskId: string | undefined;

async function nativeDebounce(delayMs: number) {
  if (taskId !== undefined) CarPlayManager.clearSleep(taskId);
  this.taskId = Math.round(Math.random() * 1000).toString();
  await CarPlayManager.sleep(taskId, delayMs);
  myFunc(); // This line won't execute if the task is cleared.
}