rntpc_react-native-amap-geolocation:基于 react-native-amap-geolocation 的 OpenHarmony 适配版,高德地图定位服务

基于 react-native-amap-geolocation 的 OpenHarmony 适配版,高德地图定位服务

分支4Tags7
文件最后提交记录最后更新时间
20 天前
20 天前
1 个月前
9 个月前
20 天前
4 个月前
2 个月前
10 个月前
20 天前
20 天前
20 天前
3 年前

模板版本:v0.4.2

react-native-amap-geolocation

本项目基于 react-native-amap-geolocation 开发。

该第三方库的仓库已迁移至 Gitcode,并支持直接从 npm 下载,新包名为:@react-native-ohos/react-native-amap-geolocation。各版本归属关系如下:

三方库名称 三方库版本(npm 地址) 发布信息 支持 RN 版本 Autolink 编译 API 版本 社区基线版本 源码地址
@react-native-ohos/react-native-amap-geolocation ~ 1.4.0 GitCode Releases 0.82./0.84. API12+ 1.2.3 master
@react-native-ohos/react-native-amap-geolocation ~ 1.3.0 GitCode Releases 0.77.* API12+ 1.2.3 br_rnoh0.77
@react-native-ohos/react-native-amap-geolocation ~ 1.2.4 GitCode Releases 0.72.* API12+ 1.2.3 br_rnoh0.72
@react-native-oh-tpl/react-native-amap-geolocation <= 1.2.3-0.0.5@deprecated GitHub Releases(deprecated) 0.72.* API12+ 1.2.3 sig

简介

一款基于高德 SDK 实现定位的 React Native 库。

1. 安装与使用

进入工程目录,并执行以下命令:

npm

npm install @react-native-ohos/react-native-amap-geolocation

yarn

yarn add @react-native-ohos/react-native-amap-geolocation

以下代码演示了该库的基本使用场景:

使用时,import 的库名保持不变。

import * as React from "react";
import {
    Button,
    Platform,
    ScrollView,
    StyleSheet,
    Text,
    View,
} from "react-native";
import {
    Geolocation, setInterval, addLocationListener,
    setGeoLanguage, setDistanceFilter, init, setNeedAddress, start,
    stop, setLocationTimeout, setOnceLocation, GeoLanguage
} from "react-native-amap-geolocation";


const style = StyleSheet.create({
    body: {
        padding: 16,
        paddingTop: Platform.OS === "ios" ? 48 : 16,
    },
    button: {
        flexDirection: "column",
        marginRight: 8,
        marginBottom: 5,
        marginTop: 5
    },
    result: {
        fontFamily: Platform.OS === "ios" ? "menlo" : "monospace",
    },
});

class AmapGeoLocationDemo extends React.Component {
    state = {
        location: null, needAddressText: "setNeedAddress(false)",
        language: "setLanguage(chinese)", interval: "setInterval(默认2000)", onceText: "setOnceLocation(false) 设置单次定位",
        startText: "start 持续定位", timeoutText: "setLocationTimeout 设置请求定位超时时间",distanceText:"setDistanceFilter(0) 设置定位的最小更新距离"
    };
    watchId = 0;
    needAddress = true;
    currLanguage = GeoLanguage.ZH;
    currInterval = false;
    onceLocationJudge = false;
    timeout5000 = false;
    distanseJudge = true;
    init = () => {
        console.log("rn AMapLocationManagerImpl init");
        init("5f7389b845cbd89b1c32e24f526728f4").then(() => {
            console.log("rn AMapLocationManagerImpl init success");
        });

    };
    addLocationListener = () => {
        console.log("rn AMapLocationManagerImpl addLocationListener");
        addLocationListener((locationData) => {
            console.log("rn AMapLocationManagerImpl callback success:" + JSON.stringify(locationData, null, 2));
            let location = locationData;
            this.setState({ location: location });
        });
    };
    setDistanceFilter = () => {
        console.log("rn AMapLocationManagerImpl setDistanceFilter");
        this.distanseJudge = !this.distanseJudge;
        if (this.distanseJudge) {
            setDistanceFilter(0);
            this.setState({ distanceText: "setDistanceFilter(0) 设置定位的最小更新距离" });
        } else {
            setDistanceFilter(1);
            this.setState({ distanceText: "setDistanceFilter(1) 设置定位的最小更新距离" });
        }

    };
    setLocationTimeout = () => {
        console.log("rn AMapLocationManagerImpl setLocationTimeout");
        this.timeout5000 = !this.timeout5000;
        if (this.timeout5000) {
            setLocationTimeout(5000);
            this.setState({ timeoutText: "setLocationTimeout(5000) 设置请求定位超时时间" });
        } else {
            setLocationTimeout(10000);
            this.setState({ timeoutText: "setLocationTimeout(10000) 设置请求定位超时时间" });
        }
    };
    start = () => {
        console.log("rn AMapLocationManagerImpl start");
        start();
    };
    stop = () => {
        console.log("rn AMapLocationManagerImpl stop");
        stop();
    }
    onceLocation = () => {
        this.onceLocationJudge = !this.onceLocationJudge;
        if (this.onceLocationJudge) {
            setOnceLocation(true);
            this.setState({ onceText: "setOnceLocation(true) 设置单次定位", startText: "start 单次定位" });
        } else {
            setOnceLocation(false);
            this.setState({ onceText: "setOnceLocation(false) 设置单次定位", startText: "start 持续定位" });
        }
        console.log("rn AMapLocationManagerImpl current onceLocation:" + this.onceLocationJudge);
    };
    setInterval = () => {
        if (this.currInterval) {
            setInterval(2000);
            this.setState({ interval: "setInterval:2000" });
        } else {
            setInterval(10000);
            this.setState({ interval: "setInterval:10000" });
        }
        this.currInterval = !this.currInterval;
    }
    setNeedAddress = () => {
        this.needAddress = !this.needAddress;
        console.log("rn AMapLocationManagerImpl setNeedAddress:" + this.needAddress);
        if (this.needAddress) {
            setNeedAddress(true);
            this.setState({ needAddressText: "setNeedAddress(true)" });
        } else {
            setNeedAddress(false);
            this.setState({ needAddressText: "setNeedAddress(false)" });
        }
    }
    setLanguage = () => {
        // default = 0,chinese = 1, engilish=2;
        console.log("rn AMapLocationManagerImpl setLanguage");
        if (this.currLanguage == GeoLanguage.ZH) {
            this.currLanguage = GeoLanguage.EN;
            setGeoLanguage(GeoLanguage.EN);
            this.setState({ language: "setLanguage(engilish)" });
        } else {
            this.currLanguage = GeoLanguage.ZH;
            setGeoLanguage(GeoLanguage.ZH);
            this.setState({ language: "setLanguage(chinese)" });
        }

    }
    updateLocationState(location: any) {
    console.log("rn AMapLocationManagerImpl updateLocationState");
    if (location) {
        this.setState({ location: location });
        console.log(location);
    }
}
getCurrentPosition = () => {
    Geolocation.getCurrentPosition(
        (position) => this.updateLocationState(position),
        (error) => this.updateLocationState(error)
    );
};
watchPosition = () => {
    if (!this.watchId) {
        this.watchId = Geolocation.watchPosition(
            (position) => this.updateLocationState(position),
            (error) => this.updateLocationState(error)
        );
        console.log("rn AMapLocationManagerImpl watchPosition watchId:" + this.watchId);
    }
};
clearWatch = () => {
    if (this.watchId) {
        console.log("rn AMapLocationManagerImpl clearWatch watchId:" + this.watchId);
        Geolocation.clearWatch(this.watchId);
        this.watchId = 0;
    }
    stop();
    this.setState({ location: null });
};
render() {
    const location = this.state.location;
    const needAddressText = this.state.needAddressText;
    const language = this.state.language;
    const currInterval = this.state.interval;
    const onceText = this.state.onceText;
    const startText = this.state.startText;
    const timeoutText = this.state.timeoutText;
    const distanceText = this.state.distanceText;
    return (
        <ScrollView contentContainerStyle={style.body}>
        <View style={style.button}>
        <Button onPress={this.init} title="init 初始化接口" />
        </View>
        <View style={style.button}>
        <Button onPress={this.addLocationListener} title="addLocationListener 设置监听回调,原生接口不设置监听回调,text不会显示数据" />
        </View>
        <View style={style.button}>
        <Button onPress={this.setDistanceFilter} title={distanceText} />
        </View>
        <View style={style.button}>
        <Button onPress={this.setLocationTimeout} title={timeoutText} />
        </View>
        <View style={style.button}>
        <Button onPress={this.onceLocation} title={onceText} />
        </View>
        <View style={style.button}>
        <Button onPress={this.start} title={startText} />
        </View>
        <View style={style.button}>
        <Button onPress={this.stop} title="stop 结束持续定位" />
        </View>
        <View style={style.button}>
        <Button onPress={this.setInterval} title={currInterval} />
        </View>
        <View style={style.button}>
        <Button onPress={this.setNeedAddress} title={needAddressText} />
        </View>
        <View style={style.button}>
        <Button onPress={this.setLanguage} title={language} />
        </View>
        <View style={style.button}>
        <Button onPress={this.getCurrentPosition} title="Geolocation.getCurrentPosition 获取当前位置,相当于单次请求" />
        </View>
        <View style={style.button}>
        <Button onPress={this.watchPosition} title="Geolocation.watchPosition 开启持续定位" />
        </View>
        <View style={style.button}>
        <Button onPress={this.clearWatch} title="Geolocation.clearWatch 结束持续定位" />
        </View>
        <Text style={style.result}>{`${JSON.stringify(location, null, 2)}`}</Text>
    </ScrollView>
);
}

}

export default AmapGeoLocationDemo;

2. 依赖链接

是否支持 Autolink RN 框架版本
~ 1.4.0 0.82./0.84.
~ 1.3.0 0.77.*
~ 1.2.4 0.72.*
<= 1.2.3-0.0.5@deprecated 0.72.*

使用 Autolink 的工程,请按照该文档进行配置。Autolink 框架指导文档:https://gitcode.com/CPF-RN/ohos_react_native/blob/master/docs/zh-cn/Autolinking.md

如果您使用的版本支持 Autolink,并且工程已接入 Autolink,则可跳过 ManualLink 配置。

本步骤用于手动配置原生依赖项。

首先,请使用 DevEco Studio 打开项目中的 HarmonyOS 工程 harmony

2.1. 使用 Overrides 覆盖 RN SDK

为确保工程依赖同一版本的 RN SDK,需要在工程根目录的 oh-package.json5 中添加 overrides 字段,指定工程需要使用的 RN SDK 版本。可替换的版本既可以是具体版本号,也可以是模糊版本号,还可以是本地已存在的 HAR 包或源码目录。

关于该字段的作用,请参阅官方说明

{
  "overrides": {
    "@rnoh/react-native-openharmony" : "./react_native_openharmony.har" // Path to local har package
    // "@rnoh/react-native-openharmony" : "./react_native_openharmony" // Point to source code path
  }
}

2.2. 引入原生端代码

目前有两种方法:

  1. 通过 har 包引入(在 IDE 完善相关功能后该方法会被遗弃,目前首选此方法);
  2. 直接链接源码。

方法一:通过 har 包引入(推荐)

har 包位于三方库安装路径的 `harmony` 文件夹下。

打开 entry/oh-package.json5,添加以下依赖

"dependencies": {
    "@react-native-ohos/react-native-amap-geolocation": "file:../../node_modules/@react-native-ohos/react-native-amap-geolocation/harmony/amap_geolocation.har"
  }

点击右上角的 sync 按钮

或者在终端执行:

cd entry
ohpm install

方式二:直接链接源码

如需使用直接链接源码,请参考[直接链接源码说明](https://gitcode.com/CPF-RN/usage-docs/blob/master/zh-cn/link-source-code.md)

2.3. 配置 CMakeLists 并引入 AMapGeolocationPackage

如果使用的是 <= 1.2.3-0.0.5 版本,请跳过本章。

打开 entry/src/main/cpp/CMakeLists.txt,添加:

+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")

# RNOH_BEGIN: manual_package_linking_1
+ add_subdirectory("${OH_MODULES}/@react-native-ohos/react-native-amap-geolocation/src/main/cpp" ./amap_geolocation)
# RNOH_END: manual_package_linking_1

# RNOH_BEGIN: manual_package_linking_2
+ target_link_libraries(rnoh_app PUBLIC rnoh_amap_geolocation)
# RNOH_END: manual_package_linking_2

打开 entry/src/main/cpp/PackageProvider.cpp,添加:

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
+ #include "AMapGeolocationPackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
+       std::make_shared<AMapGeolocationPackage>(ctx),
    };
}

2.4. 在 ArkTS 侧引入 AMapGeolocationPackage

打开 entry/src/main/ets/RNPackagesFactory.ts,添加:

...
+  import {AMapGeolocationPackage} from '@react-native-ohos/react-native-amap-geolocation/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SamplePackage(ctx),
+   new AMapGeolocationPackage(ctx)
  ];
}

2.5. 运行

点击右上角的 sync 按钮

或者在终端执行:

cd entry
ohpm install

然后编译并运行即可。

3. 约束与限制

3.1. 兼容性

本文档内容已在以下环境中验证通过:

  1. RNOH: 0.72.96; SDK: HarmonyOS 6.0.0 Release SDK; IDE: DevEco Studio 6.0.0.858; ROM: 6.0.0.112;
  2. RNOH: 0.77.18; SDK: HarmonyOS 6.0.0 Release SDK; IDE: DevEco Studio 6.0.0.858; ROM: 6.0.0.112;
  3. RNOH:0.82.1; SDK: HarmonyOS 6.0.1 Release SDK; IDE: DevEco Studio 6.0.1 Release; ROM:6.0.0.120 SP7;
  4. RNOH:0.84.1; SDK: HarmonyOS 6.0.2 Release SDK; IDE: 6.0.2 Release; ROM:7.0.0.100 SP9;

3.2. 权限要求

在 entry 目录下的 module.json5 中添加权限

打开 entry/src/main/module.json5,添加:

...
"requestPermissions": [
  {
    "name": "ohos.permission.LOCATION",
    "reason": "$string:Access_Location",
    "usedScene": {
      "when":"inuse"
    }
  },
  {
    "name": "ohos.permission.APPROXIMATELY_LOCATION",
    "reason": "$string:Access_AppRoximatelyLocation",
    "usedScene": {
      "when":"inuse"
    }
  },
  {
    "name": "ohos.permission.INTERNET",
  }
]

在 entry 目录中配置位置权限的原因

打开 entry/src/main/resources/base/element/string.json,添加:

...
{
  "string": [
    {
      "name": "Access_Location",
      "value": "access Location"
    },
    {
      "name": "Access_AppRoximatelyLocation",
      "value": "access AppRoximatelyLocation"
    }
  ]
}

4. 属性

“平台”列表示该属性在原第三方库中支持的平台。

“HarmonyOS 支持情况”列中,“支持”表示 HarmonyOS 平台支持该属性;“不支持”表示不支持;“部分支持”表示部分支持。跨平台使用方法一致,效果与 iOS 或 Android 对齐。

名称 描述 类型 是否必填 平台 HarmonyOS 支持情况
init 初始化 SDK(参数为字符串 key) Promise iOS/Android 支持
addLocationListener 添加定位监听函数 EmitterSubscription iOS/Android 支持
isStarted 获取当前是否正在定位的状态(受平台限制,单次定位模式下返回 false) boolean Android 支持
setAllowsBackgroundLocationUpdates 设置是否允许后台定位 void iOS 不支持
setDesiredAccuracy 设置期望的定位精度(米) void iOS 不支持
setDistanceFilter 设置定位的最小更新距离(米) void iOS 支持
setGeoLanguage 设置逆地理信息的语言,当前支持中文和英文 void iOS/Android 支持
setGpsFirst 设置首次定位时是否等待卫星定位结果 void Android 不支持
setGpsFirstTimeout 设置优先返回卫星定位信息时等待卫星定位结果的超时时间(毫秒) void Android 不支持
setHttpTimeout 设置联网超时时间(毫秒) void Android 不支持
setInterval 设置发起定位请求的时间间隔(毫秒),默认 2000,最小值为 1000 void Android 支持
setLocatingWithReGeocode 设置连续定位时是否返回逆地理编码信息 void iOS 不支持
setLocationCacheEnable 设置是否启用缓存策略 void Android 支持
setLocationMode 设置定位模式(参数为字符串枚举值) void Android 支持
setLocationPurpose 设置定位场景 void Android 不支持
setLocationTimeout 指定单次定位超时时间(秒) void iOS 支持
setMockEnable 设置是否允许模拟位置 void Android 不支持
setNeedAddress 设置是否返回地址信息,默认返回地址信息 void Android 支持
setOnceLocation 设置是否单次定位 void Android 支持
setOnceLocationLatest 设置定位时是否等待 WiFi 列表刷新 void Android 不支持
setOpenAlwaysScanWifi 设置是否开启 WiFi 始终扫描 void Android 不支持
setPausesLocationUpdatesAutomatically 指定定位是否会被系统自动暂停 void iOS 不支持
setReGeocodeTimeout 指定单次定位逆地理编码超时时间(秒),最小值为 2 秒。注意:需在单次定位请求前设置。 void iOS 不支持
setSensorEnable 设置是否使用设备传感器 void Android 不支持
setWifiScan 设置是否允许调用 WiFi 刷新 void Android 不支持
start 开始持续定位 void iOS/Android 支持
stop 停止持续定位 void iOS/Android 支持
GeoLanguage 逆地理信息语言枚举常量:ZH = 中文(1),EN = 英文(2) GeoLanguage.ZH/GeoLanguage.EN iOS/Android 支持
Geolocation.getCurrentPosition 获取当前位置信息 void iOS/Android 支持
Geolocation.watchPosition 注册监听器以进行持续定位 number iOS/Android 支持
Geolocation.clearWatch 移除位置监听 void iOS/Android 支持

setLocationMode 定位模式枚举值

setLocationMode(mode)mode 参数支持以下三个枚举值,对应不同的定位优先级:

枚举值 含义 鸿蒙映射(LocationRequestPriority)
LocationMode.Battery_Saving 低功耗模式,仅使用网络定位(依赖基站、WLAN、蓝牙) LOW_POWER
LocationMode.Device_Sensors 仅设备模式,以 GNSS 卫星定位为主,精度优先 ACCURACY
LocationMode.Hight_Accuracy 高精度模式,同时使用 GNSS 定位和网络定位,优先返回首次定位结果(默认值) FIRST_FIX

修改定位模式后,需重新调用 `start()` 才能生效。

5. 遗留问题

6. 目录结构

/rntpc_react-native-amap-geolocation  # 项目根目录
├── harmony              # 鸿蒙适配代码
│    └─ amap_geolocation.har       # har包
│    └─ amap_geolocation                  # 鸿蒙适配核心代码
│          └─ Index.ets    # 鸿蒙适配代码入口    
│          └─ src/main/ets  
│              └─ AMapGeolocationModule  # TurboModule接口 
├── src                  # RN代码
│    └─ index.js  # 入口文件 
│    └─ NativeRNAMapGeolocation.ts 桥接TurboModule
├── README_en.md           # 英文安装使用方法    
├── README.md   # 中文安装使用方法                    

7. 贡献代码

使用过程中如发现任何问题,都可以提交 Issue,当然,也非常欢迎提交 PR

8. 开源协议

本项目基于 The MIT License (MIT) ,请自由地享受并参与开源。

项目介绍

基于 react-native-amap-geolocation 的 OpenHarmony 适配版,高德地图定位服务

定制我的领域