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

Capacitor iOS Geolocation watchPosition遇kCLErrorDomain错误1(权限已授权)

Capacitor Geolocation v1.3.1 定位问题解决方案

问题背景

使用Capacitor Geolocation v1.3.1版本,切换到watchPosition实现定位后,出现以下问题:

  • 偶尔返回位置为null或undefined,但设备上应用的定位图标处于激活状态
  • 回退使用getCurrentPosition函数,问题依然存在
  • watchPosition定期返回位置数据的同时,出现kCLErrorDomain错误1(网上标注为权限被拒绝,但实际仅在手机休眠模式下触发)
  • 尝试在watch回调中用try/catch处理,无法捕获该错误

需求:如何专门捕获该休眠导致的错误?是否需要清除watch并重启?

原钩子代码

const useCurrentPosition = (): GeoWatchPositionResult => {
  const [position, setPosition] = useState<Position>();
  const [watchId, setWatchId] = useState("");
  const [error, setError] = useState();

  const clearWatch = () => {
    if (watchId) {
      clearPosition({ id: watchId });
      setWatchId("");
    }
  };

  const startWatch = async () => {
    if (!watchId) {
      const id = await watchPosition(async (pos: Position | null, err) => {
        if (err) {
          setError(err);
        }
        if (pos) {
          setPosition(pos);
        } else {
          const newPosition = await getCurrentPosition();
          setPosition(newPosition);
        }
      });
      setWatchId(id);
    }
  };

  useEffect(() => {
    startWatch();

    return () => clearWatch();
  }, []);

  return { currentPosition: position, error };
};

尝试修改后的代码

const useCurrentPosition = (): GeoWatchPositionResult => {
  const [position, setPosition] = useState<Position>();
  const [watchId, setWatchId] = useState("");
  const [error, setError] = useState();

  const clearWatch = () => {
    if (watchId) {
      clearPosition({ id: watchId });
      setWatchId("");
    }
  };

  const startWatch = async () => {
    if (!watchId) {
      const id = await watchPosition(async (pos: Position | null, err) => {
       try {
        if (err) {
          setError(err);
        }
        if (pos) {
          setPosition(pos);
        } else {
          const newPosition = await getCurrentPosition();
          setPosition(newPosition);
        }
       } catch (ex) {
         await requestPermission();
         clearWatch();
         await startWatch();
       }
      });
      setWatchId(id);
    }
  };

  useEffect(() => {
    startWatch();

    return () => clearWatch();
  }, []);

  return { currentPosition: position, error };
};

解决方案

1. 专门捕获kCLErrorDomain错误1

watchPosition的错误是通过回调参数传递的,不是抛出的异常,所以try/catch无法捕获。需要直接判断错误对象的属性:

  • 检查err.code === 1(Capacitor Geolocation中,kCLErrorDomain错误1对应PositionError.PERMISSION_DENIED,但这里是休眠触发的假阳性)
  • 或者检查err.message是否包含kCLErrorDomain字符串,精准区分休眠场景

2. 错误处理逻辑

捕获到该错误后,无需请求权限(因为不是真的权限拒绝),正确的处理方式是:

  • 清除当前的watch实例
  • 延迟重启watch(避免频繁重启消耗资源)
  • 添加状态标记,避免重复触发重启逻辑

3. 优化后的代码示例

const useCurrentPosition = (): GeoWatchPositionResult => {
  const [position, setPosition] = useState<Position>();
  const [watchId, setWatchId] = useState("");
  const [error, setError] = useState();
  const [isRestarting, setIsRestarting] = useState(false); // 避免重复重启

  const clearWatch = () => {
    if (watchId) {
      clearPosition({ id: watchId });
      setWatchId("");
    }
  };

  const startWatch = async () => {
    if (!watchId && !isRestarting) {
      setIsRestarting(true);
      try {
        const id = await watchPosition(async (pos: Position | null, err) => {
          if (err) {
            setError(err);
            // 专门处理kCLErrorDomain错误1(休眠触发)
            if (err.code === 1 && err.message.includes("kCLErrorDomain")) {
              clearWatch();
              // 延迟2秒后重启watch,等待设备唤醒
              setTimeout(async () => {
                await startWatch();
              }, 2000);
              return;
            }
          }
          if (pos) {
            setPosition(pos);
          } else {
            // 位置为空时尝试获取当前位置,添加错误捕获
            try {
              const newPosition = await getCurrentPosition();
              setPosition(newPosition);
            } catch (getErr) {
              setError(getErr);
            }
          }
        });
        setWatchId(id);
      } finally {
        setIsRestarting(false);
      }
    }
  };

  useEffect(() => {
    startWatch();

    return () => clearWatch();
  }, []);

  return { currentPosition: position, error };
};

关键说明

  • 移除了无效的try/catch,改为直接判断回调中的err参数
  • 添加isRestarting状态防止watch重复启动
  • 针对休眠触发的错误1,做延迟重启处理,避免立即重启导致的无效循环
  • 对getCurrentPosition添加了单独的错误捕获,避免位置为空时的未处理异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 16:15:42