闭包捕获变量引用而非权限状态,定位策略需综合系统开关、授权粒度、运行时上下文和用户偏好四类状态动态分支;策略函数应监听权限变更并支持fallback降级。

闭包本身不“捕获权限状态”,它捕获的是变量的引用或值。真正需要动态策略切换的,是定位逻辑对权限、系统定位开关、用户选择(如粗略/精确)、前台/后台场景等多维度状态的响应能力。把权限状态封装进闭包,只是组织代码的一种方式;关键在于状态判断链是否完整、可插拔、易扩展。
核心状态需明确分离
一个支持动态策略的定位函数,应基于以下几类状态做分支处理,而非只看“有没有 permission”:
- 系统级开关状态:手机整体定位功能是否开启(Android 的 Location Services / iOS 的 Location Services)。未开启时,即使有权限也无法获取位置。
- 应用级授权粒度:是仅授予“大致位置”(Approximate Location),还是“精确位置”(Precise Location),或是 Android 17+ 的单次按钮触发态。不同粒度决定调用哪个 API、传什么参数、返回坐标的精度预期。
-
运行时上下文:App 是否在前台?是否需要后台持续定位?这关系到是否要申请
ACCESS_BACKGROUND_LOCATION(Android Q+)或配置location后台模式(iOS)。 - 用户显式偏好:比如用户手动切换过城市、点击过“仅本次允许”、或在设置中降级了权限。这些行为应被记录并影响后续定位策略,而不是每次重新查权限。
用闭包封装策略选择逻辑
可以定义一个工厂函数,根据当前组合状态返回具体执行函数。闭包在这里的作用是“冻结”当时的判断结果,避免重复计算:
const createLocationStrategy = (permissionState, systemLocationOn, isForeground, userPreference) => {
// 闭包捕获全部输入状态
return async () => {
if (!systemLocationOn) {
throw new Error('系统定位已关闭,请前往设置开启');
}
if (permissionState === 'denied') {
throw new Error('定位权限已被拒绝');
}
if (permissionState === 'granted_coarse' || userPreference === 'approximate') {
return await getNetworkBasedLocation(); // 粗略定位,快、省电、低精度
}
if (permissionState === 'granted_precise' && isForeground) {
return await getGPSPreciseLocation(); // 前台高精度
}
if (permissionState === 'granted_precise' && !isForeground) {
return await getBackgroundLocation(); // 后台需额外权限和配置
}
throw new Error('未匹配定位策略');
};
};
// 使用示例:在页面加载时获取一次当前最合适的策略
const locate = createLocationStrategy(
store.permissionStatus, // 来自 Pinia 或全局状态
device.locationEnabled, // 封装好的系统级检测
app.isInForeground(), // 运行时上下文
user.settings.locationMode // 用户历史选择
);
locate().then(pos => console.log(pos));
权限状态需主动维护,不能只靠闭包“记住”
闭包捕获的是快照,但权限可能在运行中被用户手动修改。因此必须监听变化事件:
- Android:监听
onRequestPermissionsResult和onProviderDisabled/onProviderEnabled; - iOS:监听
CLLocationManager的didChangeAuthorization和didUpdateLocations中的错误码; - 小程序(uni-app):监听
onLocationChange及onMemoryWarning等生命周期,并在onShow时重新校验权限。
每次状态变更后,应刷新策略闭包或触发重新生成——即闭包不是一劳永逸的缓存,而是策略决策的“执行器”,其输入源必须保持新鲜。
策略可扩展:预留钩子与 fallback
真实业务中,策略常需叠加条件。例如:“若 GPS 不可用,则降级为网络定位;若网络也不通,则返回上次有效位置 + 时间戳”。可在闭包内嵌入 fallback 链:
return async () => {
try {
return await getGPSPreciseLocation();
} catch (e) {
if (e.code === 'TIMEOUT' || e.code === 'POSITION_UNAVAILABLE') {
return await getNetworkBasedLocation();
}
throw e;
}
};
也可将 fallback 行为本身作为策略参数传入,实现更高阶的组合,比如:createLocationStrategy(..., { fallback: 'cache_then_network' })。











