小言_互联网的博客

程序员用10分钟写了个旅游管家APP,女友用了直呼贴心

326人阅读  评论(0)

呐,你知道吗? 听说樱花飘落的速度是秒速五厘米哦。

听到阿珍又念起这句经典台词,阿强,这个对自然界的花期不太敏感的程序员,也收到了“樱花开了”的讯号。

春天的樱花不能错过,赏樱是写进阿珍价值观的春日打卡动作。视频通话里,阿珍计划了一场远行——周末就回母校武大看樱花。但这一次,在外出差的阿强不能陪她一起去。

于是阿强,依然是拿出了自己吃饭的本事,将自己的周到关怀写进一个智能旅游管家APP,陪阿珍去武汉看樱花。即使不在身边,也要给她无微不至的出游体验:

  1. 出发行程不用记:出发前为她提醒出行时间,让她不再错过重要行程;
  2. 目的地天气早知道:根据目的地气象预报,提前给到出游装备和穿搭建议;
  3. 攻略玩法全推荐:让她省去做攻略的时间,抵达目的地,推送所需的游玩攻略和优惠政策……

以上管家式智能出行服务能力,有了华为情景感知服务(Awareness kit)的时间感知和天气感知能力、定位服务(Location Kit)的地理围栏能力,以及推送服务(Push kit)的加持,实现起来并不难。

效果示例

点击视频查看示例

原理解释

情景感知服务能感知用户当前的时间、位置、活动状态、耳机状态、天气状况、环境光、车载连接状态、信标连接状态等场景,并通过能常驻后台运行的围栏能力,并且可自由组合这些感知能力,建立组合围栏。

定位服务采用GNSS、Wi-Fi、基站等多途径的混合定位模式进行定位,能快速、精准获取位置信息,实现全球定位服务能力。

推送服务是华为为开发者提供的消息推送平台,建立了从云端到终端的消息推送通道。开发者通过集成Push Kit可以实时推送消息到用户终端。

代码实战

1、集成情景感知服务

 开发准备

情景感知服务的集成需如下3个关键步骤,可以参考华为开发者联盟的文档

1. AppGallery Connect配置

2.集成HMS Awareness SDK

3.配置混淆脚本

https://developer.huawei.com/consumer/cn/doc/development/HMS-Guides/awareness-preparation?ha_source=hms1

代码开发关键步骤

1、在Manifest指定权限:


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

2. 实现通过城市名获取天气信息:


  
  1. String city = edCity.getText().toString();
  2. if (city != null && !city.equals( "")) {
  3. WeatherPosition weatherPosition = new WeatherPosition();
  4. weatherPosition.setCity(city);
  5. //传入指明传入地址用的语言类型,例如“zh_CN”、“en_US”等,“语言码_国家码”的格式。
  6. weatherPosition.setLocale( "zh_CN");
  7. // 获取Awareness Kit的“Capture Client”,调用天气查询能力
  8. Awareness.getCaptureClient(getApplicationContext()).getWeatherByPosition(weatherPosition)
  9. .addOnSuccessListener( new OnSuccessListener<WeatherStatusResponse>() {
  10. @Override
  11. public void onSuccess(WeatherStatusResponse weatherStatusResponse) {
  12. // 处理返回的天气数据
  13. WeatherStatus weatherStatus = weatherStatusResponse.getWeatherStatus();
  14. WeatherSituation weatherSituation = weatherStatus.getWeatherSituation();
  15. Situation situation = weatherSituation.getSituation();
  16. String weather;
  17. // 将天气id与天气名称匹配
  18. weather = getApplicationContext().getResources().getStringArray(R. array.cnWeather)[situation.getCnWeatherId()];
  19. // 更新UI
  20. ((TextView) findViewById(R.id.tv_weather)).setText(weather);
  21. ((TextView) findViewById(R.id.tv_windDir)).setText(situation.getWindDir());
  22. ((TextView) findViewById(R.id.tv_windSpeed)).setText(situation.getWindSpeed() + " km/h");
  23. ((TextView) findViewById(R.id.tv_temperature)).setText(situation.getTemperatureC() + "℃");
  24. }
  25. }).addOnFailureListener( new OnFailureListener() {
  26. @Override
  27. public void onFailure( Exception e) {
  28. }
  29. });
  30. }

3. 实现定时提醒和进入目的地后,接受到推送的消息:
(1) 因为需要在应用被杀死时也能接受通知,需要注册静态广播:
在Manifest中:


  
  1. <receiver android:name=".BarrierReceiver">
  2. <intent-filter>
  3. <action android:name="com.test.awarenessdemo.TimeBarrierReceiver.BARRIER_RECEIVER_ACTION"/>
  4. </intent-filter>
  5. </receiver>

 在java代码中:


  
  1. Intent intent = new Intent();
  2. intent.setComponent( new ComponentName(MainActivity. this, BarrierReceiver. class));
  3. mPendingIntent = PendingIntent.getBroadcast( this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

(2) 定义时间Barrier(围栏)和其对应的标签Label,然后添加Barrier:


  
  1. // 获取输入的时间
  2. String timeHour = edTimeHour.getText().toString();
  3. String timeMinute = edTimeMinute.getText().toString();
  4. int hour = 0;
  5. int minute = 0;
  6. if (!timeHour.equals( "")) {
  7. hour = Integer.parseInt(timeHour);
  8. if (!timeMinute.equals( "")) {
  9. minute = Integer.parseInt(timeMinute);
  10. }
  11. }
  12. long oneHourMilliSecond = 60 * 60 * 1000L;
  13. long oneMinuteMilliSecond = 60 * 1000L;
  14. // 定义"duringPeriodOfDay"围栏,在指定时区的指定时间段内发送通知
  15. AwarenessBarrier periodOfDayBarrier = TimeBarrier.duringPeriodOfDay(TimeZone.getDefault(),
  16. // 这里设置的是提前2小时通知
  17. (hour - 2) * oneHourMilliSecond + minute * oneMinuteMilliSecond,
  18. hour * oneHourMilliSecond + minute * oneMinuteMilliSecond);
  19. String timeBarrierLabel = "period of day barrier laber";
  20. // 定义更新围栏的请求
  21. BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();
  22. BarrierUpdateRequest request = builder.addBarrier(timeBarrierLabel, periodOfDayBarrier, mPendingIntent).build();
  23. Awareness.getBarrierClient(getApplicationContext()).updateBarriers(request)
  24. .addOnSuccessListener( new OnSuccessListener< Void>() {
  25. @Override
  26. public void onSuccess( Void aVoid) {
  27. }
  28. })
  29. .addOnFailureListener( new OnFailureListener() {
  30. @Override
  31. public void onFailure( Exception e) {
  32. }
  33. });

(3) 定义地理Barrier(围栏)和其对应的标签Label,然后添加Barrier:


  
  1. if (city != null && !city.equals( "")) {
  2. //根据城市名称获取城市经纬度,这里是从内部文件中获取
  3. String data = cityMap.get(city);
  4. if (data != null){
  5. int flag = data.indexOf( ",");
  6. double latitude = Double.parseDouble(data.substring(flag+ 1));
  7. double longitude = Double.parseDouble(data.substring( 0,flag));
  8. double radius = 50;
  9. long timeOfDuration = 5000;
  10. // 定义"stay"围栏,在进入指定区域并驻留超过指定时间后触发围栏事件上报
  11. AwarenessBarrier stayBarrier = LocationBarrier.stay(latitude, longitude, radius, timeOfDuration);
  12. String stayBarrierLabel = "stay barrier label";
  13. // 定义更新围栏的请求
  14. BarrierUpdateRequest.Builder builder = new BarrierUpdateRequest.Builder();
  15. BarrierUpdateRequest request = builder.addBarrier(stayBarrierLabel, stayBarrier, mPendingIntent).build();
  16. Awareness.getBarrierClient(getApplicationContext()).updateBarriers(request)
  17. .addOnSuccessListener( new OnSuccessListener< Void>() {
  18. @Override
  19. public void onSuccess( Void aVoid) {
  20. }
  21. })
  22. .addOnFailureListener( new OnFailureListener() {
  23. @Override
  24. public void onFailure( Exception e) {
  25. }
  26. });
  27. }
  28. }

(4) 定义广播接收器,用于监听Barrier事件,收到事件后进行应用的业务处理:


  
  1. class BarrierReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. BarrierStatus barrierStatus = BarrierStatus.extract(intent);
  5. String label = barrierStatus.getBarrierLabel();
  6. int barrierPresentStatus = barrierStatus.getPresentStatus();
  7. String city = intent.getStringExtra( "city");
  8. switch (label) {
  9. case DURING_PERIOD_OF_DAT_BARRIER_LABEL:
  10. if (barrierPresentStatus == BarrierStatus. TRUE) {
  11. initNotification(context, "1", "time_channel", "行程提醒", "离出发还剩2小时");
  12. } else if (barrierPresentStatus == BarrierStatus. FALSE) {
  13. showToast(context, "It's not between ");
  14. } else {
  15. showToast(context, "The time status is unknown.");
  16. }
  17. break;
  18. case STAY_BARRIER_LABEL:
  19. if (barrierPresentStatus == BarrierStatus. TRUE) {
  20. initNotification(context, "2", "area_channel", "欢迎来到"+city, "查看旅行攻略");
  21. } else if (barrierPresentStatus == BarrierStatus. FALSE) {
  22. showToast(context, "You are not staying in the area set by locationBarrier" +
  23. " or the time of duration is not enough.");
  24. } else {
  25. showToast(context, "The location status is unknown.");
  26. }
  27. break;
  28. }
  29. }
  30. }

2、基于位置的信息推送

 开发准备

1. 在项目级gradle里添加华为maven仓
AndroidStudio项目级build.gradle文件,增量添加如下maven地址:


  
  1. buildscript {
  2. repositories {
  3. maven { url 'http://developer.huawei.com/repo/'}
  4. }
  5. dependencies {
  6. ...
  7. // 增加agcp配置。
  8. classpath 'com.huawei.agconnect:agcp:1.4.2.300'
  9. }
  10. }allprojects {
  11. repositories {
  12. maven { url 'http://developer.huawei.com/repo/'}
  13. }
  14. }

2. 在应用级的build.gradle里面加上SDK依赖


  
  1. dependencies {
  2. implementation 'com.huawei.hms:location:5.0.2.300'
  3. implementation 'com.huawei.hms:push: 5.0.2.301'
  4. }

关键步骤说明

 1.在AndroidManifest.xml文件里面声明系统权限
因华为定位服务采用GNSS、Wi-Fi、基站等多种混合定位模式进行定位,需要用到网络,精确的位置权限,粗略的位置权限,如果需要应用程序在后台执行时也具备持续定位能力,需要在Manifest文件中申请ACCESS_BACKGROUND_LOCATION权限:


  
  1. <uses-permission android:name="android.permission.INTERNET" />
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  3. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  4. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  5. <uses-permission android:name="android.permission.WAKE_LOCK" />
  6. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  7. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  8. <uses-permission android:name="com.huawei.hms.permission.ACTIVITY_RECOGNITION" />
  9. <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

注:由于ACCESS_FINE_LOCATION,WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE是危险的系统权限,因此,需要动态的申请这些权限。如果权限不足,Location Service将会拒绝为应用开启定位。

2. 创建触发围栏
先根据需要创建围栏\围栏组,填好相关参数。


  
  1. LocationSettingsRequest.Builder builders = new LocationSettingsRequest.Builder();
  2. builders.addLocationRequest(mLocationRequest);
  3. LocationSettingsRequest locationSettingsRequest = builders.build();
  4. // Before requesting location update, invoke checkLocationSettings to check device settings.
  5. Task<LocationSettingsResponse> locationSettingsResponseTasks = mSettingsClient.checkLocationSettings(locationSettingsRequest);
  6. locationSettingsResponseTasks.addOnSuccessListener( new OnSuccessListener<LocationSettingsResponse>() {
  7. @Override
  8. public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
  9. Log.i(TAG, "check location settings success");
  10. mFusedLocationProviderClient
  11. .requestLocationUpdates(mLocationRequest, mLocationCallbacks, Looper.getMainLooper())
  12. .addOnSuccessListener( new OnSuccessListener<Void>() {
  13. @Override
  14. public void onSuccess(Void aVoid) {
  15. LocationLog.i(TAG, "geoFence onSuccess");
  16. }
  17. })
  18. .addOnFailureListener( new OnFailureListener() {
  19. @Override
  20. public void onFailure(Exception e) {
  21. LocationLog.e(TAG,
  22. "geoFence onFailure:" + e.getMessage());
  23. }
  24. });
  25. }
  26. })

3. 设置触发推送通知
在GeoFenceBroadcastReceiver的onReceive接收到围栏触发成功提示后发送推送通知,在通知栏接收通知并展示。


  
  1. if (geofenceData != null) {
  2. int errorCode = geofenceData.getErrorCode();
  3. int conversion = geofenceData.getConversion();
  4. ArrayList<Geofence> list = (ArrayList<Geofence>) geofenceData.getConvertingGeofenceList();
  5. Location myLocation = geofenceData.getConvertingLocation();
  6. boolean status = geofenceData.isSuccess();
  7. sb.append( "errorcode: " + errorCode + next);
  8. sb.append( "conversion: " + conversion + next);
  9. if ( list != null) {
  10. for ( int i = 0; i < list.size(); i++) {
  11. sb.append( "geoFence id :" + list.get(i).getUniqueId() + next);
  12. }
  13. }
  14. if (myLocation != null) {
  15. sb.append( "location is :" + myLocation.getLongitude() + " " + myLocation.getLatitude() + next);
  16. }
  17. sb.append( "is successful :" + status);
  18. LocationLog.i(TAG, sb.toString());
  19. Toast.makeText(context, "" + sb.toString(), Toast.LENGTH_LONG).show();
  20. //
  21. new PushSendUtils().netSendMsg(sb.toString());
  22. }

注:此代码围栏创建成功后会触发两次回调,conversion:1和4,分别代表进入触发回调和驻留触发回调一次。代码中输入的Trigger输入7的含义表示回调包括所有情况,即进入、驻留、离开等各种情况。

 

>>访问华为开发者联盟官网,了解更多相关内容

>>获取开发指导文档

>>华为移动服务开源仓库地址:GitHubGitee

关注我们,第一时间了解华为移动服务最新技术资讯~


转载:https://blog.csdn.net/HUAWEI_HMSCore/article/details/114700315
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场