Read the original article:Implement location functionality on a map
Requirement Description
The requirement is to obtain the user’s current location and display it on a map. The application should be able to request location permissions, retrieve the current position, convert the coordinates to the proper map format, and move the camera view to the user’s location on the map.
Background Knowledge
The MapComponent is a specialized map component provided by Huawei’s Map Service, allowing developers to customize and display a map within their application.
To use the Map Service:
- The application must be manually signed.
- The Map Service must be enabled in the AppGallery Connect (AGC) platform.
- Device location services must be turned on in the status bar.
Using location features also requires declaring the appropriate permissions in the module.json5 configuration file.
Implementation Steps
-
Enable Map Service
- Manually sign the app and enable the map service on the AGC platform.
-
Activate Device Location
- Turn on the “Location” function in the device status bar.
-
Declare Required Permissions
- Configure permissions for location access (
APPROXIMATELY_LOCATION,LOCATION, andLOCATION_IN_BACKGROUND) inmodule.json5.
- Configure permissions for location access (
-
Implement Permission Request Functions
- Check and request location permissions using the
checkAccessToken()andrequestPermissionsFromUser()APIs.
- Check and request location permissions using the
-
Implement Location Retrieval Function
- Use
geoLocationManager.getCurrentLocation()to get the current position. - Convert the coordinates from WGS-84 to GCJ-02 using
convertCoordinate(). - Move the map camera to the new position.
- Use
-
Integrate the MapComponent
- Initialize the map and enable the “My Location” layer and button.
- Set a custom marker icon for the user’s location.
- Automatically move the map camera to the current position.
Code Snippet / Configuration
"requestPermissions": [
{
"name": "ohos.permission.APPROXIMATELY_LOCATION", // Declare approximate location permission
"reason": "$string:app_name",
"usedScene": {
"when": "always"
}
},
{
"name": "ohos.permission.LOCATION", // Declare precise location permission
"reason": "$string:app_name",
"usedScene": {
"when": "always"
}
},
{
"name": "ohos.permission.LOCATION_IN_BACKGROUND", // Declare background location permission
"reason": "$string:app_name",
"usedScene": {
"when": "always"
}
}
]
// Verify if the app has location permission by calling checkAccessToken()
async checkPermission(): Promise<void> {
let applyResult: boolean = false;
const permissions: Array<Permissions> =
['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION', 'ohos.permission.INTERNET'];
for (let permission of permissions) {
let grantStatus: abilityAccessCtrl.GrantStatus = await this.checkAccessToken(permission);
if (grantStatus == abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
applyResult = true;
} else {
applyResult = false
}
}
if (!applyResult) {
this.requestPermissions();
} else {
// Enable My Location layer
this.mapController?.setMyLocationEnabled(true);
// Enable My Location button
this.mapController?.setMyLocationControlsEnabled(true);
}
}
// Request user authorization
requestPermissions(): void {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(getHostContext() as common.UIAbilityContext,
['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION', 'ohos.permission.INTERNET'])
.then((data: PermissionRequestResult) => {
// Enable My Location layer
this.mapController?.setMyLocationEnabled(true);
// Enable My Location button
this.mapController?.setMyLocationControlsEnabled(true);
})
.catch((err: BusinessError) => {
console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`)
})
}
// Get corresponding permissions
async checkAccessToken(permission: Permissions): Promise<abilityAccessCtrl.GrantStatus> {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
let grantStatus:
abilityAccessCtrl.GrantStatus = abilityAccessCtrl.GrantStatus.PERMISSION_DENIED;
// Get the app's 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;
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`Failed to get bundle info for self. Code is ${err.code},message is ${err.message}`)
}
// Verify if the app has been granted the permission
try {
grantStatus = await atManager.checkAccessToken(tokenId, permission);
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`Failed to check access token. Code is ${err.code}, message is ${err.message}`)
}
return grantStatus;
}
// Get current location and move the map camera
getMyLocation() {
geoLocationManager.getCurrentLocation().then(async (result) => {
console.info(`MapSignIn getMyLocation = ${JSON.stringify(result)}`);
let position: geoLocationManager.Location = {
"latitude": result.latitude,
"longitude": result.longitude,
"altitude": 0,
"accuracy": 0,
"speed": 0,
"timeStamp": 0,
"direction": 0,
"timeSinceBoot": 0
};
this.mapController?.setMyLocation(position)
// Create CameraUpdate object
let gcj02Position: mapCommon.LatLng = await this.convertCoordinate(result.latitude, result.longitude)
let latLng: mapCommon.LatLng = {
latitude: gcj02Position.latitude,
longitude: gcj02Position.longitude
}
let zoom = 17;
let cameraUpdate = map.newLatLng(latLng, zoom)
// Move the map camera with animation
this.mapController?.animateCamera(cameraUpdate, 1000);
})
}
// Convert WGS84 coordinates to GCJ02
async convertCoordinate(latitude: number, longitude: number): Promise<mapCommon.LatLng> {
let wgs84Position: mapCommon.LatLng = {
latitude: latitude,
longitude: longitude
}
let gcj02Postion: mapCommon.LatLng =
await map.convertCoordinate(mapCommon.CoordinateType.WGS84, mapCommon.CoordinateType.GCJ02, wgs84Position);
return gcj02Postion;
}
// Final integration with MapComponent
import { AsyncCallback, BusinessError } from '@kit.BasicServicesKit';
import { abilityAccessCtrl, bundleManager, common, PermissionRequestResult, Permissions } from '@kit.AbilityKit';
import { geoLocationManager } from '@kit.LocationKit';
import { map, MapComponent, mapCommon } from '@kit.MapKit';
@Entry
@Component
struct HuaweiMyLocationDemo {
private mapOption?: mapCommon.MapOptions;
private callback?: AsyncCallback<map.MapComponentController>
private TAG = 'HuaweiMyLocationDemo';
private mapController?: map.MapComponentController;
aboutToAppear(): void {
this.checkPermission();
// Initialize map options
this.mapOption = {
position: {
target: {
latitude: 39.9,
longitude: 116.4
},
zoom: 10
},
myLocationControlsEnabled: true,
scaleControlsEnabled: true,
};
// Map initialization callback
this.callback = async (err, mapController) => {
if (!err) {
this.mapController = mapController;
let cameraUpdate = map.zoomTo(18);
this.mapController?.moveCamera(cameraUpdate);
this.mapController?.setBuildingEnabled(true);
// Enable My Location features
this.mapController?.setMyLocationEnabled(true);
this.mapController?.setMyLocationControlsEnabled(true);
let style: mapCommon.MyLocationStyle = {
anchorU: 0.5,
anchorV: 0.5,
radiusFillColor: 0xffff0000,
// Custom location icon resource (replace with your own)
icon: $r("app.media.boy"),
};
await this.mapController.setMyLocationStyle(style);
// Initialize My Location
this.getMyLocation()
}
}
}
build() {
Stack() {
MapComponent({ mapOptions: this.mapOption, mapCallback: this.callback }).width('100%').height('100%');
}.height('100%')
}
}
Test Results
After implementing the code and running the application:
- The map is displayed correctly.
- When the “My Location” button is tapped, the map moves to the user’s current position.
- Location permissions are requested correctly when not yet granted.
- The custom location marker appears as defined in the resource file.
Limitations or Considerations
- The getCurrentLocation API returns coordinates in WGS-84, requiring conversion to GCJ-02 for correct map display.
- The map service requires manual signing and AGC configuration.
- The app must have network and location services enabled on the device.
- Users must explicitly grant permissions for location tracking.
Related Documents or Links
https://developer.huawei.com/consumer/en/doc/harmonyos-references/map-mapcomponent
Top comments (0)