在 HarmonyOS 应用开发中,地图、定位与传感器能力是构建位置服务、运动健康、AR 导航等场景的基础。本文将从定位权限申请、位置获取、地图集成、传感器订阅四个维度展开,涵盖单次定位、持续跟踪、地图标注、加速度计与陀螺仪的实战用法。
HarmonyOS 的定位能力需要申请 ohos.permission.APPROXIMATELY_LOCATION(粗略位置)或 ohos.permission.LOCATION(精确位置)权限,前者精度约 5 公里,后者可达米级。
在 module.json5 中声明:
{
"module":{
"requestPermissions":[
{
"name":"ohos.permission.APPROXIMATELY_LOCATION",
"reason":"$string:location_reason",
"usedScene":{
"abilities":["EntryAbility"],
"when":"inuse"
}
},
{
"name":"ohos.permission.LOCATION"
}
]
}
}importabilityAccessCtrlfrom'@ohos.abilityAccessCtrl';
importbundleManagerfrom'@ohos.bundle.bundleManager';
asyncfunctionrequestLocationPermission():Promise<boolean>{
constatManager=abilityAccessCtrl.createAtManager();
constbundleFlags=bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION;
constbundleInfo=awaitbundleManager.getBundleInfoForSelf(bundleFlags);
consttokenID=bundleInfo.appInfo.accessTokenId;
constpermissions=['ohos.permission.APPROXIMATELY_LOCATION','ohos.permission.LOCATION'];
constgrantStatus=awaitatManager.requestPermissionsFromUser(getContext(),permissions);
returngrantStatus.authResults.every(result=>result===0);
}适用于签到、地址选择等场景:
importgeoLocationManagerfrom'@ohos.geoLocationManager';
asyncfunctiongetCurrentLocation(){
constrequest:geoLocationManager.CurrentLocationRequest={
priority:geoLocationManager.LocationRequestPriority.FIRST_FIX,
scenario:geoLocationManager.LocationRequestScenario.UNSET,
maxAccuracy:0
};
try{
constlocation=awaitgeoLocationManager.getCurrentLocation(request);
console.info(`当前位置: ${location.latitude}, ${location.longitude}`);
console.info(`精度: ${location.accuracy}m, 时间: ${location.time}`);
returnlocation;
}catch(err){
console.error(`定位失败: ${err.message}`);
returnnull;
}
}适用于导航、跑步轨迹记录:
letlocationRequest:geoLocationManager.LocationRequest={
priority:geoLocationManager.LocationRequestPriority.ACCURACY,
scenario:geoLocationManager.LocationRequestScenario.NAVIGATION,
timeInterval:1,// 1 秒上报一次
distanceInterval:10,// 移动 10 米上报
maxAccuracy:0
};
functionstartTracking(){
geoLocationManager.on('locationChange',locationRequest,(location)=>{
console.info(`实时位置: ${location.latitude}, ${location.longitude}`);
// 更新 UI 或保存轨迹点
});
}
functionstopTracking(){
geoLocationManager.off('locationChange');
}需要申请 ohos.permission.LOCATION_IN_BACKGROUND 并配置后台任务:
importbackgroundTaskManagerfrom'@ohos.resourceschedule.backgroundTaskManager';
asyncfunctionstartBackgroundLocation(){
awaitbackgroundTaskManager.startBackgroundRunning(getContext(),
backgroundTaskManager.BackgroundMode.LOCATION,
{notificationId:1,notificationContent:'正在记录运动轨迹'}
);
startTracking();
}
functionstopBackgroundLocation(){
stopTracking();
backgroundTaskManager.stopBackgroundRunning(getContext());
}HarmonyOS 推荐使用华为地图服务(Map Kit)显示地图、标注点位、绘制路线。
在 oh-package.json5 中添加:
{
"dependencies":{
"@hmscore/map-kit":"^1.0.0"
}
}importmapCommonfrom'@hmscore/map-kit';
@Entry
@Component
structMapPage{
privatemapController:mapCommon.MapComponentController=newmapCommon.MapComponentController();
build(){
Column(){
MapComponent({
mapOptions:{
position:{latitude:39.9042,longitude:116.4074},
zoom:12
},
mapCallback:(err,mapController)=>{
if(!err){
this.mapController=mapController;
}
}
})
.width('100%')
.height('100%')
}
}
}addMarker(){
constmarkerOptions:mapCommon.MarkerOptions={
position:{latitude:39.9042,longitude:116.4074},
title:'天安门',
snippet:'北京市中心'
};
this.mapController.addMarker(markerOptions);
}drawPolyline(points:Array<{latitude:number,longitude:number}>){
constpolylineOptions:mapCommon.PolylineOptions={
points:points,
color:0xFF0000FF,
width:5
};
this.mapController.addPolyline(polylineOptions);
}适用于计步、摇一摇、碰撞检测:
importsensorfrom'@ohos.sensor';
functionstartAccelerometer(){
sensor.on(sensor.SensorId.ACCELEROMETER,(data:sensor.AccelerometerResponse)=>{
console.info(`加速度: x=${data.x}, y=${data.y}, z=${data.z}`);
// 检测摇一摇:若 |x| > 15 或 |y| > 15 或 |z| > 15 触发
if(Math.abs(data.x)>15||Math.abs(data.y)>15||Math.abs(data.z)>15){
console.info('检测到摇一摇');
}
},{interval:100000000});// 100ms
}
functionstopAccelerometer(){
sensor.off(sensor.SensorId.ACCELEROMETER);
}适用于 VR、AR、手势识别:
functionstartGyroscope(){
sensor.on(sensor.SensorId.GYROSCOPE,(data:sensor.GyroscopeResponse)=>{
console.info(`角速度: x=${data.x}, y=${data.y}, z=${data.z}`);
},{interval:100000000});
}
functionstopGyroscope(){
sensor.off(sensor.SensorId.GYROSCOPE);
}适用于指南针、地图旋转:
functionstartOrientation(){
sensor.on(sensor.SensorId.ORIENTATION,(data:sensor.OrientationResponse)=>{
console.info(`方向角: alpha=${data.alpha}, beta=${data.beta}, gamma=${data.gamma}`);
// alpha: 0-360° (方位角), beta: -180-180° (俯仰角), gamma: -90-90° (翻滚角)
},{interval:200000000});
}
functionstopOrientation(){
sensor.off(sensor.SensorId.ORIENTATION);
}start/stop/getTrack 接口importgeoLocationManagerfrom'@ohos.geoLocationManager';
exportclassLocationService{
privatetrackPoints:Array<geoLocationManager.Location>=[];
privateisTracking=false;
start(){
if(this.isTracking)return;
this.isTracking=true;
this.trackPoints=[];
constrequest:geoLocationManager.LocationRequest={
priority:geoLocationManager.LocationRequestPriority.ACCURACY,
scenario:geoLocationManager.LocationRequestScenario.SPORT,
timeInterval:2,
distanceInterval:5
};
geoLocationManager.on('locationChange',request,(location)=>{
this.trackPoints.push(location);
console.info(`记录点位: ${location.latitude}, ${location.longitude}`);
});
}
stop(){
if(!this.isTracking)return;
geoLocationManager.off('locationChange');
this.isTracking=false;
}
getTrack(){
returnthis.trackPoints.map(p=>({latitude:p.latitude,longitude:p.longitude}));
}
getTotalDistance():number{
letdistance=0;
for(leti=1;i<this.trackPoints.length;i++){
distance+=this.calculateDistance(this.trackPoints[i-1],this.trackPoints[i]);
}
returndistance;
}
privatecalculateDistance(p1:geoLocationManager.Location,p2:geoLocationManager.Location):number{
constR=6371e3;// 地球半径(米)
constφ1=p1.latitude*Math.PI/180;
constφ2=p2.latitude*Math.PI/180;
constΔφ=(p2.latitude-p1.latitude)*Math.PI/180;
constΔλ=(p2.longitude-p1.longitude)*Math.PI/180;
consta=Math.sin(Δφ/2)*Math.sin(Δφ/2)+
Math.cos(φ1)*Math.cos(φ2)*Math.sin(Δλ/2)*Math.sin(Δλ/2);
constc=2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));
returnR*c;
}
}importmapCommonfrom'@hmscore/map-kit';
import{LocationService}from'./LocationService';
@Entry
@Component
structRunPage{
@StateisRunning:boolean=false;
@Statedistance:number=0;
@Stateduration:number=0;
privatelocationService=newLocationService();
privatemapController:mapCommon.MapComponentController|null=null;
privatetimer:number=-1;
build(){
Stack(){
MapComponent({
mapOptions:{zoom:15},
mapCallback:(err,controller)=>{
if(!err)this.mapController=controller;
}
})
.width('100%')
.height('100%')
Column(){
Text(`距离: ${(this.distance/1000).toFixed(2)} km`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
Text(`时长: ${Math.floor(this.duration/60)}:${(this.duration%60).toString().padStart(2,'0')}`)
.fontSize(18)
Button(this.isRunning?'结束':'开始')
.onClick(()=>this.toggleRun())
.margin({top:20})
}
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.End)
.width('100%')
.height('100%')
.padding(20)
}
}
toggleRun(){
if(this.isRunning){
this.locationService.stop();
clearInterval(this.timer);
consttrack=this.locationService.getTrack();
this.mapController?.addPolyline({points:track,color:0xFF0000FF,width:5});
this.distance=this.locationService.getTotalDistance();
}else{
this.locationService.start();
this.duration=0;
this.timer=setInterval(()=>{
this.duration++;
},1000);
}
this.isRunning=!this.isRunning;
}
}FIRST_FIX 优先级,获取后立即停止ACCURACY 优先级 + NAVIGATION 场景LOW_POWER 优先级 + 更大的 timeIntervalsensor.off() 停止订阅addPolyline,批量更新路线原因:未授予定位权限
解决:检查 requestPermissionsFromUser 返回值,引导用户手动开启
原因:未申请后台任务或通知未显示
解决:确保调用 startBackgroundRunning 并显示前台通知
原因:未设置 MapComponent 的点击回调
解决:在 mapCallback 中注册 onMarkerClick 监听器
原因:硬件噪声或采样率过高 解决:应用低通滤波器或卡尔曼滤波平滑数据
本文覆盖了 HarmonyOS 地图、定位与传感器能力的核心要点:
getCurrentLocation,连续跟踪用 on('locationChange'),后台场景需配合后台任务掌握这些能力后,你可以构建位置签到、运动轨迹、AR 导航、体感游戏等丰富的应用场景,为用户提供更智能的空间感知与交互体验。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。