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
相关产品推荐
相关产品推荐

