# 百度定位 UTS-API 插件 - 全平台定位解决方案

> 基于百度地图定位SDK的uni-app x UTS原生插件，提供跨平台的原生级定位能力。

## 支持平台

| 平台 | 支持状态 |
|------|----------|
| Android | ✅ 支持 |
| iOS | ✅ 支持 |
| 鸿蒙 | ✅ 支持 |

## 功能特性

- 单次定位：获取当前位置，一次性返回定位结果
- 连续定位：持续监听位置变化，定时返回定位结果
- 后台定位：支持应用在后台时持续定位（需配置后台权限）
- 权限检测：自动检测定位权限状态，支持引导用户授权
- 坐标转换：支持多种坐标系（国测局GCJ02、百度BD09/BD09LL）
- 地址解析：支持逆地理编码，获取详细地址信息
- POI信息：获取周边兴趣点信息

## 快速开始

### 1. 引入插件

```uts
import {
  BMapLocationClient,
  LocationListener,
  LocationClientOption,
  Location,
  checkPermission,
  guideSettingPermission,
  Permission,
  setPrintLogStatus
} from "@/uni_modules/baidumap-location"
```

### 2. 配置隐私政策和鉴权

在使用定位功能前，必须先配置隐私政策和鉴权：

```uts
// 设置同意隐私政策（必须）
BMapLocationClient.setAgreePrivacy(true);

// 鉴权（使用百度开发者平台的AK）
BMapLocationClient.checkAuthKey('您的AK值').then((res) => {
  // 由于android和harmony的原生定位sdk不支持是否成功回调，所以此处仅做完成鉴权判断
  console.log('鉴权成功', res);
}).catch((err) => {
  console.error('鉴权失败', err);
});
```

### 3. 检查定位权限

```uts
// 检查权限状态
async function checkLocationPermission() {
  try {
    const status: Permission = await checkPermission();
    console.log('权限状态:', status.IS_GRANT); // 是否已授权
    console.log('是否为普通精度:', status.IS_REDUCED_ACCURACY);

    // 如果未授权，引导用户去设置
    if (!status.IS_GRANT) {
      guideSettingPermission();
    }
  } catch (e) {
    console.error("检查权限失败:", e)
  }
}
```

### 4. 创建定位客户端并设置监听

```uts
// 创建定位客户端
let locationClient: BMapLocationClient | null = null;

function initLocation() {
  locationClient = new BMapLocationClient();

  // 设置定位监听器
  const listener: LocationListener = {
    onReceiveLocation: (location: Location) => {
      console.log('收到定位结果:', location);

      // 处理定位数据
      console.log('经度:', location.longitude);
      console.log('纬度:', location.latitude);

      // 处理地址信息
      if (location.hasAddr && location.addr) {
        console.log('省份:', location.addr.province);
        console.log('城市:', location.addr.city);
        console.log('详细地址:', location.addr.address);
      }
    }
  };

  locationClient.setLocationListener(listener);
}
```

### 5. 单次定位

```uts
function handleSingleLocation() {
  if (locationClient) {
    locationClient.requestSingleLocation();
  }
}
```

### 6. 连续定位

```uts
// 开始连续定位
function startContinuousLocation() {
  if (locationClient) {
    locationClient.requestLocationUpdates();
  }
}

// 停止连续定位
function stopContinuousLocation() {
  if (locationClient) {
    locationClient.stopRequestLocationUpdates();
  }
}
```

### 7. 后台定位（仅Android/iOS）

```uts
// 开启后台定位
async function enableBackgroundLocation() {
  if (locationClient) {
    const success = await locationClient.enableLocInBackground();
    if (success) {
      console.log('后台定位已开启');
    }
  }
}

// 停止后台定位
function disableBackgroundLocation() {
  if (locationClient) {
    locationClient.disableLocInBackground();
  }
}
```

### 8. 销毁定位客户端

```uts
// 在页面卸载时调用
function destroyLocation() {
  if (locationClient) {
    locationClient.destroy();
    locationClient = null;
  }
}
```

### 9. 内部日志状态控制

// 获取当前插件日志状态
getPrintLogStatus()
// 设置是否输出插件内部日志
setPrintLogStatus(true);
```

## 配置参数详解

### LocationClientOption 定位配置

```uts
const config: LocationClientOption = {
  // 坐标类型: 'gcj02' | 'bd09' | 'bd09ll'
  coordType: 'bd09ll',

  // 定位时间间隔（秒），连续定位时有效
  timeInterval: 3,

  // 定位距离间隔（米），连续定位时有效
  distanceInterval: 0,

  // 是否需要地址信息
  isNeedAddress: true,

  // 定位模式: 0-高精度, 1-仅设备, 2-低功耗
  locationMode: 0,

  // 单次定位超时时间（毫秒）
  singleLocatingTimeout: 3000
};

locationClient?.setLocOption(config);
```

### 定位模式说明

| 值 | 模式 | 说明 |
|----|------|------|
| 0 | 高精度 | 同时使用网络定位和GNSS定位，优先返回最高精度的定位结果 |
| 1 | 仅设备 | 主要使用GNSS定位技术，超过30秒无法获取GNSS定位结果则使用网络定位 |
| 2 | 低功耗 | 主要使用基站定位和WLAN、蓝牙定位技术 |

### 坐标系说明

| 值 | 说明 |
|----|------|
| 'gcj02' | 国测局经纬度坐标系（火星坐标系） |
| 'bd09' | 百度墨卡托坐标系 |
| 'bd09ll' | 百度经纬度坐标系 |

## 数据类型说明

### Location 定位结果

```uts
interface Location {
  longitude: number;              // 经度
  latitude: number;               // 纬度
  coordType: CoordType | null;    // 坐标类型
  radius: number;                 // 定位精度（米）
  altitude: number;               // 海拔高度（米）
  speed: number;                  // 速度（米/秒）
  direction: number;              // 方向（度）
  time: string | null;            // 定位时间
  poiList: Array<Poi>;            // POI信息列表
  locStatusType: LocationStatusType;  // 定位状态类型
  locStatusTypeDescription: string | null;  // 定位状态描述
  addr: Address | null;           // 地址信息
  hasAddr: boolean;               // 是否有地址信息
  locationDescribe: string | null;  // 位置语义化信息
  locationId: string | null;      // 位置ID
  poiRegion: PoiRegion | null;   // POI区域信息
  // extraInfo: Map<string, string>; // 额外信息
}
```

### Address 地址信息

```uts
type Address = {
  country: string | null;         // 国家
  countryCode: string | null;     // 国家编码
  province: string | null;        // 省份
  city: string | null;            // 城市
  cityCode: string | null;        // 城市编码
  district: string | null;        // 区/县
  town: string | null;            // 镇
  street: string | null;          // 街道
  streetNumber: string | null;    // 街道号
  address: string | null;         // 详细地址
  adcode: string | null;          // 区域编码
}
```

### Poi POI信息

```uts
type Poi = {
  id: string;     // POI ID
  rank: number;   // 概率
  name: string;   // 名称
  tags: string;   // 类型
  addr: string;   // 地址
}
```

### PoiRegion POI区域信息

```uts
type PoiRegion = {
  name: string;              // 名称
  directionDesc: string;     // 位置关系
  tags: string;              // 类型
  uid: string | null;        // UID
  bid: string | null;        // BID
}
```

### Permission 权限状态

```uts
type Permission = {
  IS_GRANT: boolean;              // 是否已授权
  IS_REDUCED_ACCURACY: boolean;   // 是否为普通精度
}
```

### LocationStatusType 定位状态类型

```uts
type LocationStatusType = 0|1|2|3|4|5|6;
```

| 值 | 说明 |
|----|------|
| 0 | 未知错误 |
| 1 | 定位成功 |
| 2 | 无定位权限 |
| 3 | 鉴权失败 |
| 4 | 定位失败 |
| 5 | 网络异常 |

## 平台差异说明

### iOS 平台

- iOS 14+ 支持精度选择，可选择"精确位置"或"大致位置"
- 需要在 `Info.plist` 中配置定位权限描述：
  - `NSLocationWhenInUseUsageDescription`：使用期间定位
  - `NSLocationAlwaysUsageDescription`：始终定位（iOS 11及以下）
  - `NSLocationAlwaysAndWhenInUseUsageDescription`：始终定位（iOS 11+）
- iOS平台需要在页面卸载时调用 `destroy()` 方法，防止内存泄漏

### Android 平台

- 需要在 `AndroidManifest.xml` 中配置定位权限
- 后台定位需要前台服务通知
- 高版本Android需要动态请求权限

### 鸿蒙平台

- 需要在 `module.json5` 中配置定位权限
- 支持鸿蒙原生定位能力

## 权限配置

### Android（AndroidManifest.xml）

```xml
<!-- 定位权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 后台定位权限（如需要）-->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
```

### iOS（Info.plist）

```xml
<key>NSLocationWhenInUseUsageDescription</key>
<string>使用期间获取位置信息</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>始终获取位置信息</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>始终获取位置信息</string>
```

### 鸿蒙（module.json5）

```json
{
  "requestPermissions": [
    {
      "name": "ohos.permission.LOCATION",
      "reason": "需要获取设备位置信息"
    },
    {
      "name": "ohos.permission.APPROXIMATELY_LOCATION",
      "reason": "需要获取设备大致位置信息"
    }
  ]
}
```

## 注意事项

1. **隐私政策和鉴权必须在使用定位功能前完成**
2. **iOS平台**：需要在页面卸载时调用 `destroy()` 方法，防止内存泄漏
3. **后台定位**：需要在应用配置中添加相应权限，且注意耗电问题
4. **定位频率**：合理设置 `timeInterval` 和 `distanceInterval`，避免过于频繁的定位请求
5. **错误处理**：建议处理定位失败的情况，根据 `locStatusType` 判断失败原因

## 完整示例

```uts
<script setup lang="uts">
import { ref, onMounted, onUnmounted } from 'vue'
import {
  BMapLocationClient,
  LocationListener,
  Location,
  checkPermission,
  guideSettingPermission
} from "@/uni_modules/baidumap-location"

const locationDes = ref<string>('')
const isLocating = ref<boolean>(false)
let locationClient: BMapLocationClient | null = null

// 初始化定位
function initLocation() {
  BMapLocationClient.setAgreePrivacy(true)
  BMapLocationClient.checkAuthKey('您的AK值')

  locationClient = new BMapLocationClient()

  const listener: LocationListener = {
    onReceiveLocation: (location: Location) => {
      isLocating.value = false
      locationDes.value = `经度：${location.longitude}\n纬度：${location.latitude}`

      if (location.hasAddr && location.addr) {
        locationDes.value += `\n地址：${location.addr.address}`
      }
    }
  }

  locationClient.setLocationListener(listener)
}

// 单次定位
function handleSingleLocation() {
  if (locationClient) {
    isLocating.value = true
    locationClient.requestSingleLocation()
  }
}

onMounted(() => {
  initLocation()
})

onUnmounted(() => {
  if (locationClient) {
    locationClient.destroy()
    locationClient = null
  }
})
</script>

<template>
  <view>
    <button @click="handleSingleLocation">
      {{ isLocating ? '定位中...' : '开始定位' }}
    </button>
    <text>{{ locationDes }}</text>
  </view>
</template>
```

## 官方开发文档

- [百度定位SDK Android文档](https://lbsyun.baidu.com/index.php?title=android-locsdk)
- [百度定位SDK iOS文档](https://lbsyun.baidu.com/index.php?title=ios-locsdk)
- [百度定位SDK Harmony文档](https://lbsyun.baidu.com/faq/api?title=harmonylocsdk)
