草庐IT

如何通过华为定位API精准获取用户所在地理位置?

华为开发者论坛 2023-03-28 原文
我们在外出旅行时,通常需要在酒店App中预订酒店。那么,在酒店App中是如何获取用户地理位置信息从而实现 “附近的酒店”的功能查找?为此,我开发了一款名为Hotel Booking的应用。

本文中,我将集成定位服务,并介绍如何使用getLastlocation和getLocationWithAddress方法、如何使用回调方法,以及如何在Flutter中将数据存储到应用中的Shared Preferences。

 

  • 定位服务

定位服务帮助开发者的应用快速准确地获取用户的位置,并通过GPS、Wi-Fi以及基站定位能力来扩展其全球定位能力。

融合定位:提供一套简单易用的API,以便您基于GPS、Wi-Fi以及基站位置数据来快速获取用户设备位置。

活动识别:通过加速度传感器、蜂窝网络信息以及磁力仪等识别用户的活动状态,帮助您根据用户行为调整应用。

地理围栏:您可以通过API来设置一个感兴趣的区域,以便在特定的动作(例如离开、进入或者逗留在该区域)发生时,您的应用可以接收到通知。

 

软件要求

1.     Android Studio 3.X

2.     JDK 1.8及以上

3.     SDK Platform 19及以上

4.     Gradle 4.6及以上

集成步骤

1.     在AppGallery Connect中注册华为开发者账号

2.     参考“创建您的AGC项目”和“在项目下添加应用”章节创建应用。

3.     根据当前位置来设置数据处理位置。

4.     开通所需服务:华为定位服务。

5.     生成签名证书指纹。

6.     配置签名证书指纹。

7.     将您的agconnect-services.json文件拷贝到您的应用级根目录下。

重要:添加应用时,输入的应用包名应与您的Flutter项目包名一致。

注意:下载agconnect-services.json文件前,确保已开启所需的HMS服务。

开发流程

在Android Studio中创建应用。

1.     创建Flutter项目。

2.     添加编译依赖。

a)         应用级Gradle依赖:

 

在项目中选择“Android > app > build.gradle”。 apply plugin: 'com.android.application' apply plugin: 'com.huawei.agconnect'  

b)         项目级Gradle依赖:

 

maven {url 'https://developer.huawei.com/repo/'} classpath 'com.huawei.agconnect:agcp:1.4.1.300'  

在AndroidManifest.xml文件中添加如下权限:

 

<uses-permission android:name="android.permission.INTERNET" />  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />  <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />  <uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" />  

3.     参考链接下载所需的跨平台插件。

4.     完成上述所有步骤后,在pubspec.yaml文件中添加对所需的HMS服务对应的Flutter插件的依赖。您可在pub.dev中找到最新版本的插件。

 

dependencies:    flutter:      sdk: flutter    shared_preferences: ^0.5.12+4    bottom_navy_bar: ^5.6.0    cupertino_icons: ^1.0.0    provider: ^4.3.3   huawei_location:    path: ../huawei_location/    flutter:    uses-material-design: true    assets:      - assets/images/  

5.     添加后,执行flutter pub get命令。至此,所有的插件已准备就绪。

6.     打开main.dart文件来创建UI和业务逻辑。

 

集成定位服务

权限

首先,应用需要有访问位置数据和物理数据的权限。

创建PermissionHandler实例,并调用initState()方法来初始化实例。

 

final PermissionHandler permissionHandler; @override  void initState() {  permissionHandler = PermissionHandler(); super.initState();  }  

检查权限

调用hasLocationPermission()方法来检查设备是否有所需的权限。

 

void hasPermission() async {    try {      final bool status = await permissionHandler.hasLocationPermission();      if(status == true){      showToast("Has permission: $status");      }else{        requestPermission();      }    } on PlatformException catch (e) {      showToast(e.toString());    }  }  

如果设备没有所需权限,调用requestLocationPermission()方法来申请相关权限。

 

void requestPermission() async {    try {      final bool status = await permissionHandler.requestLocationPermission();      showToast("Is permission granted");    } on PlatformException catch (e) {      showToast(e.toString());    }  }  

 

  • 融合定位

使用init()方法创建FusedLocationPrvoiderClient实例,然后使用该实例调用定位API。

 

final FusedLocationProviderClient locationService   @override  void initState() {  locationService = FusedLocationProviderClient(); super.initState();  }  

位置更新事件

调用onLocationData()方法来侦听位置更新事件。

 

StreamSubscription<Location> streamSubscription  @override  void initState() {  streamSubscription = locationService.onLocationData.listen((location) {});super.initState();  }  

getLastLocation()

 

void getLastLocation() async {    try {      Location location = await locationService.getLastLocation();      setState(() {        lastlocation = location.toString();        print("print: " + lastlocation);      });    } catch (e) {      setState(() {        print("error: " + e.toString());      });    }  }  

getLastLocationWithAddress()

创建LocationRequest实例,并设置相关参数。

 

final LocationRequest locationRequest; locationRequest = LocationRequest()    ..needAddress = true    ..interval = 5000;   void _getLastLocationWithAddress() async {    try {      HWLocation location =          await locationService.getLastLocationWithAddress(locationRequest);      setState(() {        String street = location.street;        String city = location.city;        String countryname = location.countryName;        currentAddress = '$street' + ',' + '$city' + ' , ' + '$countryname';        print("res: $location");      });      showToast(currentAddress);    } on PlatformException catch (e) {      showToast(e.toString());    }  }  

通过Callback进行位置更新

创建LocationCallback实例,并在initstate()中创建回调函数。

 

LocationCallback locationCallback; @override  void initState() {    locationCallback = LocationCallback(      onLocationResult: _onCallbackResult,      onLocationAvailability: _onCallbackResult,    );    super.initState();  }   void requestLocationUpdatesCallback() async {    if (_callbackId == null) {      try {        final int callbackId = await locationService.requestLocationUpdatesExCb(            locationRequest, locationCallback);        _callbackId = callbackId;      } on PlatformException catch (e) {        showToast(e.toString());      }    } else {      showToast("Already requested location updates.");    }  }    void onCallbackResult(result) {    print(result.toString());    showToast(result.toString());  }  

我创建了一个Helper类,用于通过Shared Preferences在本地存储用户登录信息。

 

class StorageUtil {    static StorageUtil _storageUtil;    static SharedPreferences _preferences;      static Future<StorageUtil> getInstance() async {      if (_storageUtil == null) {        var secureStorage = StorageUtil._();        await secureStorage._init();        _storageUtil = secureStorage;      }      return _storageUtil;    }      StorageUtil._();      Future _init() async {      _preferences = await SharedPreferences.getInstance();    }      // get string    static String getString(String key) {      if (_preferences == null) return null;      String result = _preferences.getString(key) ?? null;      print('result,$result');      return result;    }      // put string    static Future<void> putString(String key, String value) {      if (_preferences == null) return null;      print('result $value');      return _preferences.setString(key, value);    }  }  

结果

温馨提示

1.     请下载最新版本的HMS服务Flutter插件。

2.     如需使用模拟位置功能,需要在AndroidManifest.xml文件中添加相关权限。

3.     如需更新插件,可点击pug get按钮。

 

欲了解HMS Core更多详情,请参阅:
>>华为开发者联盟官网

>>获取开发指导文档
>>参与开发者讨论请到CSDN社区或者Reddit社区
>>下载demo和示例代码请到Github或者Gitee
>>解决集成问题请到Stack Overflow

原文链接:developer.huawei.com/consumer/cn…

原作者:胡椒

有关如何通过华为定位API精准获取用户所在地理位置?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  8. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  9. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  10. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

随机推荐