mcpField
A
add-geolocation

add-geolocation

github.com/microsoft开发1.1k127 次安装今天更新
代码仓库

关于 add-geolocation

用于通过 `@microsoft/power-apps-native-bglocation` 为原生应用添加持续或后台 GPS 跟踪的内部技能。它会验证 Dataverse 目标表及字段,再创建或更新 TypeScript 封装,不修改原生配置。

主要功能

  1. 01检查所需依赖与应用设置
  2. 02验证 Dataverse 表和映射字段
  3. 03创建或更新地理位置封装
  4. 04要求使用 MSAL 身份验证
  5. 05对变更执行类型检查

适用场景

  1. 01为原生应用添加后台 GPS 跟踪
  2. 02集成前验证位置上传目标
  3. 03复用或更新现有地理位置封装

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/microsoft/power-platform-skills --skill add-geolocation

安装后在 Claude Code 中输入/add-geolocation确认已加载。

详细介绍

共享说明:shared-instructions.md - 请先阅读。

工作目录: 在读取任何项目内容或执行任何命令之前,执行 native-artifact-compatibility.md Step 0。 继承 /add-native 解析出的绝对 working_dir;将每个 shell 调用和文件工具绑定到该目录,即使此辅助流程从其他目录启动也不例外。

添加地理位置

用于 /add-native geolocation、/add-native location-tracking、/add-native background-location、/add-native gps-tracking 和 /add-native @microsoft/power-apps-native-bglocation 的内部辅助流程。

仅将此流程用于通过原生持久化存储和内联 Dataverse 上传实现的连续/后台 GPS 跟踪。若只需读取一次前台坐标,请改用 /add-native location(expo-location)。

硬性规则:

  • 认证只能使用 MSAL。不得公开 OneAuth 或认证方式选择器。
  • 使用 geoService(dataSource, app_id) 和 BgLocationClient。
  • 不得使用 GeolocationExtension、HostingSDK、PCF、Launch URI 或 CordovaV2 桥接路径。
  • 不得安装软件包或修改原生配置。
  • 只有在验证 Dataverse 目标表及映射列之后,才能使用此控件。

1. 验证应用和软件包

cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
test -f app.config.js && test -f power.config.json && test -f package.json && test -d src || { echo "BLOCKED: working_dir is not an initialized app" >&2; exit 1; }
node -e "const p=require('./package.json'); const m='@microsoft/power-apps-native-bglocation'; if (!p.dependencies?.[m]) { console.error('MISSING: ' + m); process.exit(1); } console.log('OK: geolocation package present');"

如果任一检查失败,请停止。模板/应用必须已包含原生软件包。

2. 首先验证 Dataverse 目标表

此控件使用软件包默认的 Dataverse 实体集:

msdyn_locationrecords

不得询问用户表名,也不得自创自定义表。使用控件前,msdyn_locationrecords 必须已存在。

cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
ENV_JSON=$(node "${PLUGIN_ROOT}/scripts/resolve-environment.js" "$(node -e "console.log(require('./power.config.json').environmentId)")")
ENV_URL=$(node -e "const j=JSON.parse(process.argv[1]); process.stdout.write(j.environmentUrl || '')" "$ENV_JSON")

TABLE="msdyn_locationrecords"
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" "$ENV_URL" GET \
  "EntityDefinitions?\$filter=EntitySetName eq '$TABLE'&\$select=LogicalName,EntitySetName"

所需结果:

  • 返回一行:记录 LogicalName 并验证列。
  • value: [] 为空:停止。标记为 BLOCKED (target table missing)。不得创建表、不得转到 /add-dataverse,也不得报告控件可用。请告知用户运行地理位置控件的表预配/设置机制,然后重新运行 /add-native geolocation。
  • 认证/环境错误:停止。标记为 UNVERIFIED (target table not checked)。不得报告控件可用。

表存在时,验证每个映射列均存在:

cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
node "${PLUGIN_ROOT}/scripts/dataverse-request.js" "$ENV_URL" GET \
  "EntityDefinitions(LogicalName='<logicalName>')/Attributes?\$select=LogicalName,AttributeType"

软件包 README 中的默认 fieldMap 必需列:

msdyn_locationrecordid, msdyn_appid, msdyn_latitude, msdyn_longitude,
msdyn_altitude, msdyn_accuracy, msdyn_heading, msdyn_speed, msdyn_timestamp

如果任何启用的 fieldMap 列缺失,请停止。标记为 BLOCKED (target columns missing),并告知用户通过地理位置控件的表预配/设置机制修复控件表。

2a. 对照请求的制品

在执行任何写入或复用操作之前,针对地理位置对应项阅读并执行 native-artifact-compatibility.md 的步骤 1–3。继承 /add-native 当前的审批/模式;不得重复请求有效且范围明确的审批。 检查 src/native/geolocation.ts,确认其中包含所有请求的跟踪/状态/位置导出、GeoTrackingTarget、仅限 MSAL 的 geoService/BgLocationClient、必需的 connectionUrl/trackInBackground/persistAcrossRestarts、持久化存储和 Dataverse 同步。复用步骤 2 中已验证的 msdyn_locationrecords 列;单次定位或目标为其他表的封装器均不兼容。审批范围之外的不兼容制品应将 NEEDS_CONTEXT 返回给负责人,或在独立运行时询问;缺失表/列仍标记为 BLOCKED,绝不能报告控件可用。

3. 编写 src/native/geolocation.ts

根据步骤 2a 对 src/native/geolocation.ts 的决定执行:收到请求且文件缺失时创建;仅在兼容时原样复用;或只进行获批的范围内更新。保留自定义代码、导出和调用方;不得用示例覆盖。屏幕应导入此封装器,而不是直接导入软件包。

目标配置必须要求 README 中的两个跟踪标志:

  • trackInBackground: boolean
  • persistAcrossRestarts: boolean
// src/native/geolocation.ts
import {
  geoService,
  BgLocationClient,
  AuthMethod,
  ConnectionType,
} from '@microsoft/power-apps-native-bglocation';
import type {
  DataverseDataSource,
  LocationData,
  PermissionStatus,
} from '@microsoft/power-apps-native-bglocation';

export type { LocationData, PermissionStatus } from '@microsoft/power-apps-native-bglocation';

export type GeoTrackingTarget = Omit<DataverseDataSource, 'authMethod' | 'connectionType'>;

export type GeoResult<T> =
  | { ok: true; value: T }
  | {
      ok: false;
      reason: 'NATIVE_MODULE_MISSING' | 'PERMISSION_DENIED' | 'TRACKING_FAILED';
      message?: string;
    };

let activeClient: BgLocationClient | null = null;

function client(): BgLocationClient {
  return activeClient ?? new BgLocationClient();
}

function dataSource(target: GeoTrackingTarget): DataverseDataSource {
  return {
    ...target,
    authMethod: AuthMethod.MSAL,
    connectionType: ConnectionType.Dataverse,
  };
}

function fail(error: unknown): Extract<GeoResult<never>, { ok: false }> {
  const message = error instanceof Error ? error.message : String(error);
  if (/native|module|not.*link|undefined is not an object|null is not an object/i.test(message)) {
    return { ok: false, reason: 'NATIVE_MODULE_MISSING', message };
  }
  if (/permission|denied|authoriz|not granted/i.test(message)) {
    return { ok: false, reason: 'PERMISSION_DENIED', message };
  }
  return { ok: false, reason: 'TRACKING_FAILED', message };
}

export async function startTracking(
  app_id: string,
  target: GeoTrackingTarget,
): Promise<GeoResult<void>> {
  try {
    activeClient = geoService(dataSource(target), app_id);
    await activeClient.startTracking();
    return { ok: true, value: undefined };
  } catch (error) {
    activeClient = null;
    return fail(error);
  }
}

export async function stopTracking(): Promise<GeoResult<void>> {
  try {
    await client().stopTracking();
    activeClient = null;
    return { ok: true, value: undefined };
  } catch (error) {
    return fail(error);
  }
}

export async function isTracking(): Promise<GeoResult<boolean>> {
  try {
    return { ok: true, value: await client().isTracking() };
  } catch (error) {
    return fail(error);
  }
}

export async function getPermissionStatus(): Promise<GeoResult<PermissionStatus>> {
  try {
    return { ok: true, value: await client().getPermissionStatus() };
  } catch (error) {
    return fail(error);
  }
}

export async function getCurrentLocation(): Promise<GeoResult<LocationData>> {
  try {
    return { ok: true, value: await client().getCurrentLocation() };
  } catch (error) {
    return fail(error);
  }
}

4. 使用方式

面向所有者的集成指南;请勿在此辅助工具中编辑屏幕。

屏幕必须传入 connectionUrl、trackInBackground 和 persistAcrossRestarts。请勿传入 tableName 或 fieldMap;该控件使用默认的 msdyn_locationrecords 表和默认的 msdyn_* 字段映射。intervalMs、distanceFilterMeters 和 notification 为可选项。

const target: GeoTrackingTarget = {
  connectionUrl: 'https://org.crm.dynamics.com',
  trackInBackground: true,
  persistAcrossRestarts: false,
};

await startTracking('my-wrap-app', target);

5. 类型检查和摘要

cd -- '<working_dir>' || { echo "BLOCKED: cannot enter working_dir" >&2; exit 1; }
npx --no-install tsc --noEmit

完成类型检查后,执行共享兼容性契约的步骤 4。重新检查所有请求的跟踪 API/标志、MSAL 身份验证、持久化存储/同步和失败路径。仅类型检查成功并不足够;不要修复屏幕/生成的文件。只有在请求的工件契约、表 + 列以及 TypeScript 全部通过后,才返回共享兼容性结果,以及实际创建/更新/复用的路径,然后再报告:

Geolocation status : READY
Package present    : @microsoft/power-apps-native-bglocation
Wrapper            : src/native/geolocation.ts
Required config    : connectionUrl, trackInBackground, persistAcrossRestarts
Auth               : MSAL only
Target table       : <TABLE> verified
Native config      : not changed

如果表验证失败,请改为报告 BLOCKED 或 UNVERIFIED,不要将 memory-bank.md 更新为表示该控件已就绪。

评论

支持 Markdown