You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native iOS开启proximityMonitoringEnabled后setInterval停止运行求助

问题分析

当设备黑屏/锁屏后,移动端的JS线程会进入休眠状态,普通的setInterval会暂停执行,这就是你看不到定时器日志的原因。虽然InCallManager能维持通话活跃,但它默认不会阻止JS线程休眠。

解决方案

1. 基于时间戳计算通话时长(推荐)

放弃依赖定时器累加的方式,改用通话开始时间戳实时计算时长,这种方式不受锁屏影响,精度也更高。

代码示例:

import { useEffect, useRef, useState } from 'react';

// 定义你的CALL_STATE常量
const CALL_STATE = { CONNECTED: 'connected' };

function CallComponent({ callState, isVideo }) {
  const [callTime, setCallTime] = useState(0);
  const startTimeRef = useRef(null);
  const intervalRef = useRef(null);

  useEffect(() => {
    if (callState === CALL_STATE.CONNECTED && !isVideo) {
      // 记录通话开始的时间戳
      startTimeRef.current = Date.now();
      // 启动定时器实时计算时长
      if (!intervalRef.current) {
        intervalRef.current = setInterval(() => {
          if (startTimeRef.current) {
            const elapsedSeconds = Math.floor((Date.now() - startTimeRef.current) / 1000);
            setCallTime(elapsedSeconds);
          }
        }, 1000);
      }
    } else {
      // 通话结束/切换状态时清理定时器和时间戳
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
      startTimeRef.current = null;
      setCallTime(0);
    }

    // 组件卸载时清理资源
    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current);
    };
  }, [callState, isVideo]);

  useEffect(() => {
    console.log('calltime', callTime);
  }, [callTime]);

  return <div>通话时长:{callTime}秒</div>;
}

2. 使用后台定时器库(React Native 场景)

如果你的项目是React Native,可以用react-native-background-timer库实现后台运行的定时器,它能绕过系统锁屏后的JS线程休眠限制。

代码示例:

import BackgroundTimer from 'react-native-background-timer';
import { useEffect, useRef, useState } from 'react';

const CALL_STATE = { CONNECTED: 'connected' };

function CallComponent({ callState, isVideo }) {
  const [callTime, setCallTime] = useState(0);
  const intervalRef = useRef(null);

  useEffect(() => {
    if (callState === CALL_STATE.CONNECTED && !isVideo) {
      if (!intervalRef.current) {
        // 用后台定时器替代普通setInterval
        intervalRef.current = BackgroundTimer.setInterval(() => {
          setCallTime(prev => prev + 1);
        }, 1000);
      }
    } else {
      if (intervalRef.current) {
        BackgroundTimer.clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
      setCallTime(0);
    }

    return () => {
      if (intervalRef.current) BackgroundTimer.clearInterval(intervalRef.current);
    };
  }, [callState, isVideo]);

  useEffect(() => {
    console.log('calltime', callTime);
  }, [callTime]);

  return <div>通话时长:{callTime}秒</div>;
}

注意:后台定时器会增加设备功耗,务必在通话结束后立即清理。

3. 监听InCallManager唤醒事件恢复计时

利用InCallManager的唤醒事件(比如屏幕点亮、传感器触发),在设备从黑屏状态恢复时,重新计算并恢复计时:

代码示例:

import { useEffect, useRef, useState } from 'react';
import InCallManager from 'react-native-incall-manager';

const CALL_STATE = { CONNECTED: 'connected' };

function CallComponent({ callState, isVideo }) {
  const [callTime, setCallTime] = useState(0);
  const startTimeRef = useRef(null);
  const intervalRef = useRef(null);

  useEffect(() => {
    if (callState === CALL_STATE.CONNECTED && !isVideo) {
      startTimeRef.current = Date.now();
      startTimer();
    } else {
      stopTimer();
      startTimeRef.current = null;
      setCallTime(0);
    }

    // 监听设备唤醒事件
    const handleWake = () => {
      if (callState === CALL_STATE.CONNECTED && !isVideo && startTimeRef.current) {
        // 唤醒时重新计算已流逝的时长
        const elapsedSeconds = Math.floor((Date.now() - startTimeRef.current) / 1000);
        setCallTime(elapsedSeconds);
        // 如果定时器已停止,重启
        if (!intervalRef.current) startTimer();
      }
    };

    InCallManager.addEventListener('wake', handleWake);
    return () => {
      InCallManager.removeEventListener('wake', handleWake);
      stopTimer();
    };
  }, [callState, isVideo]);

  const startTimer = () => {
    intervalRef.current = setInterval(() => {
      setCallTime(prev => prev + 1);
    }, 1000);
  };

  const stopTimer = () => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
  };

  useEffect(() => {
    console.log('calltime', callTime);
  }, [callTime]);

  return <div>通话时长:{callTime}秒</div>;
}

内容的提问来源于stack exchange,提问作者famfamfam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 15:15:27