目录

1. 定位服务开发步骤

1.1 指定应用权限

Android提供了两种位置权限: ACCESS_COARSE_LOCATION(粗略的位置权限) 和ACCESS_FINE_LOCATION(精确的位置权限)。 需要在Manifest文件中申请权限:

  1. <!--Fused Location-->
  2. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
  3. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

在Android Q版本中,如果您需要应用程序在后台执行时也具备持续定位能力,需要在Manifest文件中申请ACCESS_BACKGROUND_LOCATION权限:

  1. <!--Fused Location-->
  2. <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

1.2 使用定位服务类

为定位模块定义的Java类是RNFusedLocationModule,该类导出到React Native的名称是FusedLocation。

  1. import HMSLocation from 'react-native-hms-location';
  2. const FusedLocation = {
  3.    Native: HMSFusedLocation,
  4.    Data: LocationData,
  5.    Request: LocationRequest,
  6.    SettingsRequest: LocationSettingsRequest,
  7.    PriorityConstants: HMSFusedLocation.PriorityConstants,
  8.    Events: {
  9.        addFusedLocationEventListener,
  10.        removeFusedLocationEventListener,
  11.    },
  12. };

1.3 检查设备定位设置

设备的相关定位设置会影响华为定位服务的定位结果,例如位置开关选项处于关闭状态时,将无法获取到位置信息。 因此,建议您在持续获取位置信息之前,先检查设备设置是否满足定位条件。 华为定位服务提供了检查设备定位相关设置的能力。

当设置不满足定位需求时,将为您提供解决方案以提示用户打开对应的权限(HMS Core服务定位权限必须打开,Android Q版本中必须选择“始终允许”)。

您可以通过checkLocationSettings( locationSettingsRequest )方法获取定位设置。

locationSettingsRequest对象是方法的入参,包含三个属性:locationRequest、alwaysShow和needBle。

可通过如下代码创建locationRequest属性:

  1. const locationRequest = HMSLocation.FusedLocation.Request.configure({
  2.    id: 'e0048e' + Math.random() * 10000,
  3.    priority: HMSLocation.FusedLocation.PriorityConstants.PRIORITY_HIGH_ACCURACY,
  4.    interval: 3,
  5.    numUpdates: 10,
  6.    fastestInterval: 1000.0,
  7.    expirationTime: 200000.0,
  8.    expirationTimeDuration: 200000.0,
  9.    smallestDisplacement: 0.0,
  10.    maxWaitTime: 2000000.0,
  11.    needAddress: true,
  12.    language: 'en',
  13.    countryCode: 'en',
  14. }).build();

然后,可通过如下代码创建locationSettingsRequest对象:

  1. const locationSettingsRequest =
  2.      HMSLocation.FusedLocation.SettingsRequest.configure({
  3.          locationRequests: [locationRequest],
  4.          alwaysShow: false,
  5.          needBle: false,
  6.      }).build();

needBle属性表示是否需要开启BLE扫描。 取值包括true(需要)和false(不需要)。

alwaysShow属性表示继续使用app是否需要位置信息。 取值包括true(需要)和false(不需要)。

最后,调用checkLocationSettings()方法来回复定位设置。 该方法会返回一个响应。

  1. HMSLocation.FusedLocation.Native.checkLocationSettings(locationSettingsRequest)
  2.    .then(res => setLocationSettings(res))
  3.    .catch(ex => console.log("Error while getting location settings. " + ex))

1.4 获取最后的已知位置

使用华为定位服务API,您的应用程序可以获取设备最后的已知位置,大多情况下,该位置即为设备的当前位置。

调用getLastLocation()方法获取最后的已知位置的代码样例如下:

该方法无入参,会返回一个包含位置数据的响应。

  1. import HMSLocation from 'react-native-hms-location';
  2. const getLocation = useCallback(() => {
  3.    HMSLocation.FusedLocation.Native.getLastLocation()
  4.         .then(pos => setPosition(pos))
  5.         .catch(err => console.log('Failed to get last location', err));
  6.    }, []);
  7. return (
  8.     <View style={styles.spaceBetweenRow}>
  9.         <Text style={styles.sectionTitle}>Location Info</Text>
  10.         <Button title="Get last location" onPress={getLocation} />
  11.     </View>
  12. );

1.5 持续获取位置信息

如果您希望应用可以持续获取设备位置,可以使用华为定位服务提供的requestLocationUpdatesWithCallback()和addFusedLocationEventListener ()接口。

首先需要创建一个locationRequest对象。具体创建方法请参见“定位设置”示例。 然后,调用requestLocationUpdatesWithCallback()方法。

该方法用于通过指定的Looper线程上的回调来请求位置更新,如果请求成功,则返回位置请求的ID。

  1. import HMSLocation from 'react-native-hms-location';
  2. const requestLocationUpdate = useCallback(() => {
  3.    const LocationRequest = HMSLocation.FusedLocation.Request.configure({
  4.        id: 'e0048e' + Math.random() * 10000,
  5.        /**
  6.        * other such properties
  7.        */
  8.    }).build();
  9.    HMSLocation.FusedLocation.Native
  10.    .requestLocationUpdatesWithCallback(LocationRequest)
  11.    .then(({ id }) => setLocationUpdateId(id))
  12.    .catch(ex => console.log("Exception while requestLocationUpdatesWithCallback "    + ex))
  13. }, []);

然后,为周期性位置更新添加事件监听器,该监听器包含一个定义的handler用来处理更新事件。

  1. const handleLocationUpdate = useCallback(location => {
  2.    console.log(location);
  3.    setPosition(location);
  4. }, []);
  5. const addFusedLocationEventListener = useCallback(() => {
  6.    requestLocationUpdate();
  7.    HMSLocation.FusedLocation.Events.addFusedLocationEventListener(
  8.        handleLocationUpdate,
  9.        );
  10.        setAutoUpdateEnabled(true);
  11. }, []);
  12. const removeFusedLocationEventListener = useCallback(() => {
  13.    HMSLocation.FusedLocation.Events.removeFusedLocationEventListener(
  14.        locationUpdateId,
  15.        handleLocationUpdate,
  16.        );
  17.        setAutoUpdateEnabled(false);
  18. }, [locationUpdateId]);

1.6 使用模拟位置信息功能

使用模拟位置信息功能,可打开“设置 -> 系统和更新 -> 开发人员选项 ->选择模拟位置信息应用”,选择要使用模拟位置的应用。 (如果没有发现“开发人员选项”,请打开“设置->关于手机->版本号”,连续点击“版本号”7次,“开发人员选项”会出现在“系统与更新”页面,再重复上述操作。) 示例代码如下:

可通过setMockMode( boolean )方法来开启或关闭模拟位置特性。

该方法的入参为boolean,表示是否开启或关闭模拟位置特性。

方法返回一个包含结果的响应。

  1. import HMSLocation from 'react-native-hms-location';
  2. const [lat, setLat] = useState("41.3");
  3. const [long, setLong] = useState("29.1");
  4. const enableMockLocation = () => {  
  5.    HMSLocation.FusedLocation.Native.setMockMode(true)
  6.           .then(res => console.log('Mock mode ', res))
  7.           .catch(err => console.log(err));
  8. };
  9. return (
  10.    <View style={styles.sectionContainer}>
  11.        <Button
  12.            title="Enable"
  13.            onPress={enableMockLocation}
  14.        />
  15.    </View>
  16. );

模拟位置的坐标可通过setMockLocation({ latitude, longitude })方法设置。

该方法入参为一个单一对象,包含经纬度属性。 此外,该方法返回一个响应消息。

  1. const setMockLocation = () => {
  2.    HMSLocation.FusedLocation.Native.setMockLocation(
  3.    {
  4.        latitude: parseFloat(lat),
  5.        longitude: parseFloat(long)
  6.    }
  7.    )
  8.     .then(res => { console.log('MOCK SET', res); })
  9.     .catch(err => { console.log(err); });
  10. };
  11. return (
  12.     <View style={styles.sectionContainer}>
  13.         <Button
  14.             title="Set"
  15.             onPress={setMockLocation}
  16.         />
  17.     </View>
  18. );

模拟位置属性开启并设置后,您的手机在尝试获取最后已知位置时应返回具体的位置数据

2 活动识别服务开发步骤

2.1 指定应用权限

在Android Q以下版本使用活动识别服务,需要在manifest文件中配置以下权限:

  1. <!--Activity Identification-->
  2. <uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" />

在Android Q及以上版本中,需要在Manifest文件中申请以下权限:

  1. <!--Activity Identification-->
  2. <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

2.2 使用活动识别类

为定位模块定义的Java类名称是RNActivityIdentificationModule,该类导出到React Native的名称是ActivityIdentification。

  1. import HMSLocation from 'react-native-hms-location';
  2. const ActivityIdentification = {
  3.    Native: HMSActivityIdentification,
  4.    ConversionInfo: ActivityConversionInfo,
  5.    ConversionData: ActivityConversionData,
  6.    ConversionRequest: ActivityConversionRequest,
  7.    ConversionResponse: ActivityConversionResponse,
  8.    IdData: ActivityIdentificationData,
  9.    IdResponse: ActivityIdentificationResponse,
  10.    Activities: HMSActivityIdentification.Activities,
  11.    ActivityConversions: HMSActivityIdentification.ActivityConversions,
  12.    Events: {
  13.        addActivityIdentificationEventListener,
  14.        removeActivityIdentificationEventListener,
  15.        addActivityConversionEventListener,
  16.        removeActivityConversionEventListener
  17.    }
  18. }

2.3 注册活动识别更新

使用活动识别服务,首先需要您注册活动识别更新来检测用户当前是步行、骑自行车或者静止等状态。

  1. import HMSLocation from 'react-native-hms-location';
  2. const [idReqCode, setIdReqCode] = useState();
  3. const createActivityIdentification = useCallback(() => {
  4.    HMSLocation.ActivityIdentification.Native
  5.    .createActivityIdentificationUpdates(2000)
  6.    .then(res => {
  7.        console.log(res);
  8.        setIdReqCode(res.requestCode);
  9.    })
  10.    .catch(err => console.log('ERROR: Activity identification failed', err));
  11. }, []);

该请求ID后续可以用来删除创建的活动识别更新。

  1. const removeActivityIdentification = useCallback(idReqCode => {
  2.    HMSLocation.ActivityIdentification.Native
  3.    .deleteActivityIdentificationUpdates(idReqCode)
  4.    .then(res => {
  5.        console.log(res);
  6.        setIdReqCode(null);
  7.    })
  8.    .catch(err =>
  9.    console.log('ERROR: Activity identification deletion failed', err));
  10. }, []);
  1. const [identificationSubscribed,
  2.    setIdentificationSubscribed] = useState(false);
  3. const handleActivityIdentification = useCallback(act => {
  4.    console.log('ACTIVITY : ', act);
  5.    setIdentificationResponse(act);
  6. }, []);
  7. const addActivityIdentificationEventListener = useCallback(() => {
  8.    HMSLocation.ActivityIdentification.Events
  9.    .addActivityIdentificationEventListener(
  10.    handleActivityIdentification,
  11.    );
  12.    setIdentificationSubscribed(true);
  13. }, []);

可以使用removeActivityIdentificationEventListener (handlerMethod)方法来移除定义的监听器。

该方法仅有一个入参,和上面方法的一样。

  1. const removeActivityIdentificationEventListener = useCallback(() => {
  2.    HMSLocation.ActivityIdentification.Events
  3.    .removeActivityIdentificationEventListener(
  4.        handleActivityIdentification,
  5.    );
  6.    setIdentificationSubscribed(false);
  7. }, []);
  8. return (
  9.    <View style={styles.centralizeContent}>
  10.    <Button
  11.        title={identificationSubscribed ? "Unsubscribe" : "Subscribe"}
  12.        onPress={() => {
  13.            if (identificationSubscribed) {
  14.                removeActivityIdentificationEventListener()
  15.            } else {
  16.                addActivityIdentificationEventListener()
  17.            }
  18.    }} />
  19. );

2.4 注册活动转换更新

接口提供检测活动转换条件(进入,退出)的功能。 例如,需要检测用户从站立不动变为行走状态时:

  1. const conversionRequest =
  2.    HMSLocation.ActivityIdentification.ConversionRequest.configure([
  3.    // STILL
  4.    {
  5.        conversionType:
  6.        HMSLocation.ActivityIdentification
  7.        .ActivityConversions.ENTER_ACTIVITY_CONVERSION,
  8.        activityType:
  9.            HMSLocation.ActivityIdentification.Activities.STILL
  10.    },
  11.    // ON FOOT
  12.    {
  13.        conversionType:
  14.        HMSLocation.ActivityIdentification
  15.        .ActivityConversions.ENTER_ACTIVITY_CONVERSION,
  16.        activityType:
  17.            HMSLocation.ActivityIdentification.Activities.FOOT
  18.    }
  19. ]).build();

createActivityConversionUpdates方法返回一个包含发送请求的ID的响应。

  1. const createConversionUpdates = useCallback(conversionRequest => {
  2.    HMSLocation.ActivityIdentification
  3.    .Native.createActivityConversionUpdates(conversionRequest)
  4.    .then(res => {
  5.        console.log(res);
  6.        setConvReqCode(res.requestCode);
  7.    })
  8.    .catch(err =>
  9.    console.log('ERROR: Activity Conversion creation failed', err));
  10. }, []);

该ID后续可用来移除创建的转换更新。

  1. const deleteConversionUpdates = useCallback(convReqCode => {
  2.    HMSLocation.ActivityIdentification
  3.    .Native.deleteActivityConversionUpdates(convReqCode)
  4.    .then(res => {
  5.        console.log(res);
  6.        setConvReqCode(null);
  7.    })
  8.    .catch(err =>
  9.    console.log('ERROR: Activity Conversion deletion failed', err));
  10. }, []);

该方法的唯一入参是一个在发送活动识别事件时调用的handler方法。

  1. const [conversionSubscribed,
  2.    setConversionSubscribed] = useState(false);
  3. const handleActivityIdentification = useCallback(act => {
  4.    console.log('ACTIVITY : ', act);
  5.    setIdentificationResponse(act);
  6. }, []);
  7. const addActivityConversionEventListener = useCallback(() => {
  8.    HMSLocation.ActivityIdentification
  9.    .Events.addActivityConversionEventListener(
  10.    handleActivityConversion,
  11.    );
  12.    setConversionSubscribed(true);
  13. }, []);

你可以通过removeActivityConversionEventListener (handlerMethod)方法来移除定义的监听器。

该方法仅有一个入参,和上面方法的一样。

  1. const removeActivityConversionEventListener = useCallback(() => {
  2.    HMSLocation.ActivityIdentification
  3.    .Events.removeActivityConversionEventListener(
  4.        handleActivityConversion,
  5.    );
  6.    setConversionSubscribed(false);
  7. }, []);
  8. return (
  9.    <View style={styles.centralizeContent}>
  10.    <Button
  11.        title={identificationSubscribed ? "Unsubscribe" : "Subscribe"}
  12.        onPress={() => {
  13.            if (identificationSubscribed) {
  14.                addActivityConversionEventListener()
  15.            } else {
  16.                addActivityIdentificationEventListener()
  17.            }
  18.        }} />
  19.    </View>
  20. );

3 地理围栏服务开发步骤

3.1 指定应用权限

如果需要使用地理围栏服务API,需要在Manifest文件中申请ACCESS_FINE_LOCATION权限:

  1. <!--Geofence-->
  2. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

在Android Q版本中,需要在Manifest文件中申请ACCESS_BACKGROUND_LOCATION权限:

  1. <!--Geofence-->
  2. <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

3.2 使用地理围栏服务类

为定位模块定义的Java类名称是RNGeofenceModule,该类导出到React Native的名称是Geofence。

  1. import HMSLocation from 'react-native-hms-location';
  2. const Geofence = {
  3.    Native: HMSGeofence,
  4.    Builder: GeofenceBuilder,
  5.    Data: GeofenceData,
  6.    Request: GeofenceRequest,
  7.    GeofenceRequestConstants: HMSGeofence.GeofenceRequestConstants,
  8.    GeofenceConstants: HMSGeofence.GeofenceConstants,
  9.    ErrorCodes: HMSGeofence.ErrorCodes,
  10.    Events: {
  11.        addGeofenceEventListener,
  12.        removeGeofenceEventListener
  13.    }
  14. };

3.3 创建并添加地理围栏

您可以先创建地理围栏实例,并构建添加地理围栏的请求。

createGeofenceList( geofences, conversions, coordinateType )

该方法具有三个入参:

- Geofences:待添加的地理围栏列表。

- Conversions:初始转换。

- Coordinate Type:坐标类型。

可以通过提供的builder来创建地理围栏实例,如下所示:

  1. const geofence1 = HMSLocation.Geofence.Builder.configure({
  2.    longitude: 42.0,
  3.    latitude: 29.0,
  4.    radius: 20.0,
  5.    uniqueId: 'e00322',
  6.    conversions: 1,
  7.    validContinueTime: 10000.0,
  8.    dwellDelayTime: 10,
  9.    notificationInterval: 1,
  10. }).build();

通过提供的builder创建一个geofenceRequest对象,如下所示:

  1. const geofenceRequest = HMSLocation.Geofence.Request.configure({
  2.    geofences: [geofence1, geofence2],
  3.    conversions: 1,
  4.    coordinate: 1,
  5. }).build();

最后,通过创建的请求对象调用createGeofenceList方法。该方法返回一个包含发送请求的ID的响应。

  1. const createGeofenceList = useCallback(() => {
  2.    HMSLocation.Geofence.Native.createGeofenceList(
  3.        geofenceRequest.geofences,
  4.        geofenceRequest.conversions,
  5.        geofenceRequest.coordinate,
  6.    )
  7.    .then(res => {
  8.        console.log(res);
  9.        setReqCode(parseInt(res.requestCode));
  10.    })
  11.    .catch(err => {
  12.        console.log(err);
  13.    });
  14. })

该ID后续可用来移除创建的转换更新。

  1. const deleteGeofenceList = useCallback(reqCode => {
  2.    HMSLocation.Geofence.Native.deleteGeofenceList(reqCode)
  3.    .then(res => {
  4.        console.log(res);
  5.        setReqCode(null);
  6.    })
  7.    .catch(err => console.log('ERROR: GeofenceList deletion failed', err))
  8. }, []);
  1. import HMSLocation from 'react-native-hms-location';
  2. const [geoSubscribed, setGeoSubscribed] = useState(false);
  3. const handleGeofenceEvent = useCallback(geo => {
  4.    console.log('GEOFENCE : ', geo);
  5.    setGeofenceResponse(geo);
  6. });
  7. const addGeofenceEventListener = useCallback(() => {
  8.    HMSLocation.Geofence.Events.addGeofenceEventListener(
  9.        handleGeofenceEvent,
  10.    );
  11.    setGeoSubscribed(true);
  12. }, []);

可以通过removeGeofenceEventListener ( handlerMethod )方法来移除定义的监听器。

该方法仅有一个入参,和上面方法的一样。

  1. const removeGeofenceEventListener = useCallback(() => {
  2.    HMSLocation.Geofence.Events.removeGeofenceEventListener(
  3.        handleGeofenceEvent,
  4.    )
  5.    setGeoSubscribed(false);
  6. })
  7. return (
  8.    <View style={styles.centralizeContent}>
  9.        <Button
  10.            title={geoSubscribed ? "Unsubscribe" : "Subscribe"}
  11.            onPress={() => {
  12.                if (geoSubscribed) {
  13.                    removeGeofenceEventListener()
  14.                } else {
  15.                    addGeofenceEventListener()
  16.                }
  17.        }} />
  18.    </View>
  19. );