add-geolocation について
`@microsoft/power-apps-native-bglocation` を使って、ネイティブアプリに継続的またはバックグラウンドの GPS 追跡を追加する内部スキルです。Dataverse の対象テーブルと列を検証し、ネイティブ設定を変更せず TypeScript ラッパーを作成・更新します。
主な機能
- 01必要なパッケージとアプリ設定の確認
- 02Dataverse テーブルとマッピング列の検証
- 03位置情報ラッパーの作成・更新
- 04MSAL 認証の必須化
- 05変更内容の型チェック
活用シーン
- 01ネイティブアプリへのバックグラウンド GPS 追跡追加
- 02位置情報の送信先を統合前に検証
- 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を引き継ぎ、このヘルパーが別のディレクトリから起動した場合でも、すべてのシェル呼び出しとファイルツールをそのディレクトリにバインドしてください。
位置情報の追加
/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"
必須の結果:
- 1行が返された場合:
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列が1つでも欠けている場合は停止してください。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を書き込む
src/native/geolocation.tsについてステップ2aの判断を適用してください。要求されていてファイルがない場合は作成し、互換性がある場合に限り変更せず再利用するか、承認された範囲の更新のみを行ってください。
カスタムコード、エクスポート、呼び出し元を保持し、例で上書きしないでください。画面からはパッケージを直接ではなく、このラッパーをインポートします。
対象の構成では、READMEに記載された次の2つの追跡フラグを必須にしてください。
trackInBackground: booleanpersistAcrossRestarts: 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 を更新しないでください。