OneScript
基础

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访问受限,例如受“屏幕使用时间”限制。
authorizedOneScript 使用期间,脚本可以使用位置。

用户关闭“精确位置”时 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 运行的脚本中可用。

可用范围

APIApp操作扩展小组件
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。

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?

最后更新于

本页目录