geolocation
获取设备位置与罗盘朝向、解析地址,并让用户在地图上选择地点。
geolocation 通过 Core Location 读取设备位置。一次性请求返回 Promise;持续更新是异步可迭代对象,用 break 或 AbortSignal 结束。依赖浏览器定位的库也可以使用标准 Web API navigator.geolocation。
import { geolocation } from "onescript";
const position = await geolocation.getPosition();
console.log(position.coords.latitude, position.coords.longitude);类型
interface Coordinate {
latitude: number;
longitude: number;
}
interface Position {
coords: {
latitude: number;
longitude: number;
accuracy: number; // 米
altitude: number | null; // 米
altitudeAccuracy: number | null;
heading: number | null; // 移动方向,相对正北的度数
speed: number | null; // 米/秒
};
timestamp: number; // Unix 毫秒
}
interface Heading {
magneticHeading: number; // 相对磁北的度数
trueHeading: number | null; // 相对真北的度数
accuracy: number | null; // 最大误差(度)
timestamp: number;
}
interface Placemark extends Coordinate {
name?: string;
fullAddress?: string; // 按地区习惯格式化,可能有多行
city?: string;
region?: string; // 国家或地区名称
regionCode?: string; // ISO 3166-1 代码,如 "CN"
timeZone?: string; // IANA 时区,如 "Asia/Shanghai"
}
interface GeolocationPermission {
status: "notDetermined" | "denied" | "restricted" | "authorized";
accuracy: "full" | "reduced";
widgetUpdates: boolean;
}
type LocationAccuracy = "navigation" | "best" | number;Position 与 Web 的 GeolocationPosition 结构相同,系统无法确定的值为 null。某个地点没有的地标字段会省略。
LocationAccuracy 设置期望精度:"best" 为默认值,即设备能提供的最佳精度;"navigation" 用于导航,耗电更多;数字表示以米为单位的期望精度。
授权
function geolocation.getPermission(): Promise<GeolocationPermission>;
function geolocation.requestPermission(options?: { fullAccuracy?: boolean }): Promise<GeolocationPermission>;getPosition 与 positions 首次调用时会申请“使用期间”授权,通常不需要自己申请。需要提前申请时调用 requestPermission;用户关闭了“精确位置”时,传入 fullAccuracy: true 可以申请一次临时精确定位。
status | 含义 |
|---|---|
notDetermined | 尚未询问用户。 |
denied | 用户拒绝了访问,或定位服务已关闭。 |
restricted | 访问受限,例如受“屏幕使用时间”限制。 |
authorized | OneScript 使用期间,脚本可以使用位置。 |
用户关闭“精确位置”时 accuracy 为 "reduced",位置是大致范围。widgetUpdates 表示小组件能否获取位置。
授权弹窗只能在 OneScript App 中出现。在操作扩展与小组件中,尚未决定的授权会抛出 LOCATION_CONTEXT_UNAVAILABLE;先在 App 中运行一次使用定位的脚本完成授权。
geolocation.getPosition
function geolocation.getPosition(options?: {
accuracy?: LocationAccuracy;
maximumAge?: number;
signal?: AbortSignal;
}): Promise<Position>;获取一次当前位置。
| 选项 | 说明 |
|---|---|
accuracy | 期望精度,默认 "best"。 |
maximumAge | 可接受的缓存位置的最长时间(毫秒)。默认 0,总是重新定位。 |
signal | 取消请求。超时可使用 AbortSignal.timeout(ms)。 |
const position = await geolocation.getPosition({
maximumAge: 5 * 60_000,
signal: AbortSignal.timeout(10_000)
});signal 中止时,Promise 以 signal.reason 拒绝。授权弹窗显示期间取消,要等用户做出选择后才生效。
小组件中建议使用 maximumAge:重新定位可能需要数秒,而小组件完成的时间有限。
geolocation.positions
function geolocation.positions(options?: {
accuracy?: LocationAccuracy;
distanceFilter?: number;
activityType?: "other" | "automotiveNavigation" | "fitness" | "otherNavigation" | "airborne";
signal?: AbortSignal;
}): AsyncIterable<Position>;持续接收位置更新,直到用 break 退出循环或 signal 中止。循环等待更新期间,脚本保持运行。
| 选项 | 说明 |
|---|---|
accuracy | 期望精度,默认 "best"。 |
distanceFilter | 产生新位置所需的最小移动距离(米),默认每次移动都更新。 |
activityType | 帮助 iOS 节省电量并提高精度,默认 "other"。 |
signal | 停止更新,循环随后抛出 signal.reason。 |
const track = [];
for await (const position of geolocation.positions({ distanceFilter: 10, activityType: "fitness" })) {
track.push(position.coords);
if (track.length === 100) break;
}即使循环体处理得比更新慢,也会交付每一个位置。循环期间定位授权被撤销时,循环抛出 LOCATION_PERMISSION_DENIED。
位置更新只在 OneScript 位于前台时进行。
朝向
function geolocation.getHeading(options?: { signal?: AbortSignal }): Promise<Heading>;
function geolocation.headings(options?: { filter?: number; signal?: AbortSignal }): AsyncIterable<Heading>;getHeading 返回当前罗盘朝向。headings 交付朝向变化;filter 为最小变化角度(度),默认每次变化都交付。朝向是当前状态,循环体处理较慢时会跳过中间值,只交付最新的朝向。
罗盘不需要定位授权;没有授权时 trueHeading 为 null。没有磁力计的设备(包括模拟器)会抛出 LOCATION_UNAVAILABLE。
for await (const heading of geolocation.headings({ filter: 5 })) {
console.log(Math.round(heading.trueHeading ?? heading.magneticHeading));
}地理编码
function geolocation.geocode(address: string, options?: { locale?: string }): Promise<Placemark[]>;
function geolocation.reverseGeocode(coordinate: Coordinate, options?: { locale?: string }): Promise<Placemark[]>;geocode 把地址解析为地标,reverseGeocode 把坐标解析为地标;没有匹配结果时都返回空数组。locale 是结果的语言(BCP 47),默认使用设备的首选语言。
const [place] = await geolocation.reverseGeocode(position.coords, { locale: "zh-Hans" });
console.log(place?.city, place?.region);
const results = await geolocation.geocode("北京市东城区景山前街 4 号");地理编码是 Apple 提供的网络服务,有频率限制。失败或请求过多时,Promise 以 LOCATION_GEOCODE_FAILED 拒绝。
geolocation.pick
function geolocation.pick(options?: { initial?: Coordinate }): Promise<Coordinate | null>;显示地图,用户拖动地图使图钉对准位置或搜索地点后点“完成”。返回所选坐标,用户取消时为 null。initial 设置地图的初始位置,默认为当前位置。
const place = await geolocation.pick();
if (place) {
const [placemark] = await geolocation.reverseGeocode(place);
console.log(placemark?.name);
}pick 只在 OneScript App 运行的脚本中可用。
可用范围
| API | App | 操作扩展 | 小组件 |
|---|---|---|---|
getPermission | ✓ | ✓ | ✓ |
requestPermission | ✓ | 仅限授权已决定时 | 仅限授权已决定时 |
getPosition | ✓ | 已授权时 ✓ | 已授权时 ✓ |
positions、getHeading、headings | ✓ | ✓ | 意义不大:widget.show 后小组件即结束 |
geocode、reverseGeocode | ✓ | ✓ | ✓ |
pick | ✓ | — | — |
错误
错误带有 code 属性:
code | 含义 |
|---|---|
LOCATION_PERMISSION_DENIED | 定位访问被拒绝或受限,或小组件不允许使用位置。 |
LOCATION_UNAVAILABLE | 无法确定位置或朝向,或设备没有罗盘。 |
LOCATION_CONTEXT_UNAVAILABLE | 当前环境不支持该操作,例如在 App 之外弹出授权。 |
LOCATION_GEOCODE_FAILED | 地理编码失败。 |
参数无效时抛出 TypeError。
navigator.geolocation
Web Geolocation API 以 navigator.geolocation 提供,使用浏览器定位的 npm 包无需修改即可工作。getCurrentPosition、watchPosition 与 clearWatch 支持标准的 enableHighAccuracy、timeout 与 maximumAge 选项;错误为 GeolocationPositionError,code 为 PERMISSION_DENIED(1)、POSITION_UNAVAILABLE(2)与 TIMEOUT(3)。
const id = navigator.geolocation.watchPosition(
position => console.log(position.coords.latitude),
error => console.error(error.code, error.message),
{ enableHighAccuracy: true, timeout: 10_000 }
);
// 清除 watch 之前脚本保持运行。
setTimeout(() => navigator.geolocation.clearWatch(id), 60_000);navigator.permissions.query({ name: "geolocation" }) 返回 "granted"、"denied" 或 "prompt",返回的状态对象不会派发 change 事件。
How is this guide?
最后更新于