如何在打开地图时，自动移动相机到当前设备位置
======================

#### 问题现象

初始化地图时，会显示初始化配置的默认坐标位置，如何实现在打开地图时，相机视野自动移动到当前设备所在的坐标位置。

#### 背景知识

*   开发准备：使用地图服务，需要先[开通地图服务](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/map-config-agc#section16133115441516)。
*   [geoLocationManager.getCurrentLocation](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-geolocationmanager#geolocationmanagergetcurrentlocation-2)：获取当前设备所在位置。
*   [moveCamera](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/map-map-mapcomponentcontroller#section141021341974)：更新相机状态。

#### 解决方案

前提条件：使用地图服务，需要先[开通地图服务](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/map-config-agc#section16133115441516)；使用位置服务，需要声明位置权限“ohos.permission.LOCATION”、“ohos.permission.APPROXIMATELY\_LOCATION”，参见[在配置文件中声明权限](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/declare-permissions#在配置文件中声明权限)。

1.  在地图初始化完成的callback回调函数中，通过getCurrentLocation接口获取当前位置坐标，因为接口获取的是WGS84坐标，需使用convertCoordinateSync接口转换为GCJ02坐标提供给地图使用。
    
    await geoLocationManager.getCurrentLocation().then(async (location: geoLocationManager.Location) => {
      this.myLocationLatLng =
        await map.convertCoordinateSync(mapCommon.CoordinateType.WGS84, mapCommon.CoordinateType.GCJ02, location);
      this.mapController?.setMyLocationEnabled(true);
    }).catch((err: BusinessError) => {
      console.error(\`getCurrentLocationPosition failed, code: ${err.code}, message: ${err.message}\`);
    });
    
2.  将转换后的当前位置坐标，设置为相机的target位置参数，调用moveCamera接口，移动相机到当前位置。
    
    let cameraPosition: mapCommon.CameraPosition = {
      target: this.myLocationLatLng,
      zoom: 15
    };
    _// 新建CameraUpdate对象_
    let cameraUpdate: map.CameraUpdate = map.newCameraPosition(cameraPosition);
    _// 移动相机_
    this.mapController?.moveCamera(cameraUpdate);
    

实现效果：

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/d3/v3/z1wiK602T82_cDASAskdSA/zh-cn_image_0000002658913601.png?HW-CC-KV=V1&HW-CC-Date=20260709T134310Z&HW-CC-Expire=86400&HW-CC-Sign=F900ED5B51AC1EA84C39ADA43C82017791CFF4DFEC1C806E7F432F90F0982924 "点击放大")

完整示例参考如下：

import { abilityAccessCtrl, bundleManager, common, Permissions } from '@kit.AbilityKit';
import { BusinessError, AsyncCallback } from '@kit.BasicServicesKit';
import { MapComponent, mapCommon, map } from '@kit.MapKit';
import { geoLocationManager } from '@kit.LocationKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { preferences } from '@kit.ArkData';
import { UIContext } from '@ohos.arkui.UIContext';
import { display } from '@kit.ArkUI';

class PermissionsRequest {
 _ /\*\*_
   _\* 通用申请权限_
   _\*/_
  async commonRequestPermissions(context: UIContext, permissions: Array<Permissions>) {
    let isPermission: boolean = await this.checkPermissions(permissions);
    if (!isPermission) {
    _  //一次授权_
      let isDialogShown = await this.requestPermissions(context, permissions);
      if (isDialogShown !== true) {
     _   //二次授权_
        this.requestPermissionsOnSetting(context, permissions);
      }
    }
  }

  _/\*\*_
   _\* 校验应用是否被授权_
   _\*/_
  async checkPermissions(permissions: Array<Permissions>) {
    for (let permission of permissions) {
      let grantStatus: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permission);
      if (grantStatus !== abilityAccessCtrl.GrantStatus.PERMISSION\_GRANTED) {
        return false;
      }
    }
    return true;
  }

  async checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    let grantStatus: abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION\_DENIED;

   _ // 获取应用程序的accessTokenID_
    let tokenId: number = 0;
    try {
      let bundleInfo: bundleManager.BundleInfo =
        await bundleManager.getBundleInfoForSelf(bundleManager.BundleFlag.GET\_BUNDLE\_INFO\_WITH\_APPLICATION);
      let appInfo: bundleManager.ApplicationInfo = bundleInfo.appInfo;
      tokenId = appInfo.accessTokenId;
      grantStatus = await atManager.checkAccessToken(tokenId, permission);
    } catch (error) {
      let err: BusinessError = error as BusinessError;
      hilog.error(0x000, 'testTag', \`Failed to check access token  ${err.code}, message is ${err.message}\`);
    }
    return grantStatus;
  }

 _ /\*\*_
   _\* 申请用户授权_
   _\*/_
  async requestPermissions(context: UIContext, permissions: Array<Permissions>): Promise<boolean | undefined> {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    try {
      let data =
        await atManager.requestPermissionsFromUser(context.getHostContext() as common.UIAbilityContext, permissions);
      hilog.info(0x000, 'testTag', 'requestPermissions1 success', JSON.stringify(data));
      return data.dialogShownResults ? data.dialogShownResults\[0\] : undefined; // 返回请求是否有弹窗
    } catch (e) {
      hilog.error(0x000, 'testTag', \`requestPermissions1 err Code is ${e.code}, message is ${e.message}\`);
      return undefined;
    }
  }

  _/\*\*_
   _\* 2次申请用户授权_
   _\*/_
  requestPermissionsOnSetting(context: UIContext, permissions: Array<Permissions>) {
    let keyPerms = JSON.stringify(permissions);
    let store = preferences.getPreferencesSync(context.getHostContext(), { name: 'permsHasOnSetting' });
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    atManager.requestPermissionOnSetting(context.getHostContext(), permissions)
      .then((res: Array<abilityAccessCtrl.GrantStatus>) => {
        hilog.info(0x000, 'testTag', 'requestPermissions2 success', JSON.stringify(res));
        store.putSync(keyPerms, 1);
        store.flush();
      })
      .catch((err: BusinessError) => {
        hilog.info(0x000, 'testTag', 'requestPermissions2 err', JSON.stringify(err));
      });
  }
}

@Entry
@Component
struct MoveToMyLocation {
  private mapOptions?: mapCommon.MapOptions;
  private callback?: AsyncCallback<map.MapComponentController>;
  private mapController?: map.MapComponentController;
  private myLocationLatLng: mapCommon.LatLng = {
    latitude: 39.9,
    longitude: 116.4
  };
  @State mapHeight: number = 0;
  PermissionsRequest = new PermissionsRequest();

  async aboutToAppear() {
    let displayClass = display.getDefaultDisplaySync();
    this.mapHeight = this.getUIContext().px2vp(displayClass.height);
  _  // 地图初始化参数，设置地图中心点坐标及层级_
    this.mapOptions = {
      position: {
        target: {
          latitude: 39.9,
          longitude: 116.4
        },
        zoom: 10
      }
    };

   _ // 地图初始化的回调_
    this.callback = async (err, mapController) => {
      if (!err) {
     _   // 获取地图的控制器类，用来操作地图_
        this.mapController = mapController;
        let permissions: Array<Permissions> = \['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY\_LOCATION'\];
        await this.PermissionsRequest.commonRequestPermissions(this.getUIContext(), permissions);
        await geoLocationManager.getCurrentLocation().then(async (location: geoLocationManager.Location) => {
          this.myLocationLatLng =
            await map.convertCoordinateSync(mapCommon.CoordinateType.WGS84, mapCommon.CoordinateType.GCJ02, location);
          this.mapController?.setMyLocationEnabled(true);
        }).catch((err: BusinessError) => {
          console.error(\`getCurrentLocationPosition failed, code: ${err.code}, message: ${err.message}\`);
        });

        let cameraPosition: mapCommon.CameraPosition = {
          target: this.myLocationLatLng,
          zoom: 15
        };
       _ // 新建CameraUpdate对象_
        let cameraUpdate: map.CameraUpdate = map.newCameraPosition(cameraPosition);
       _ // 移动相机_
        this.mapController?.moveCamera(cameraUpdate);
      } else {
        console.error(\`Failed to initialize the map, code is：${err.code}, message is ${err.message}\`);
      }
    };
  }

  build() {
    Stack() {
    _  // 调用MapComponent组件初始化地图_
      MapComponent({ mapOptions: this.mapOptions, mapCallback: this.callback })
        .width('100%')
        .height(this.mapHeight)
        .expandSafeArea(\[SafeAreaType.SYSTEM\], \[SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM\]);
    }.height('100%');
  }
}