项目背景
电动车因骑行方便、节省时间等优势,成为我们日常出行的交通工具之一,国内电动车的需求数据庞大且逐年攀升。然而电动车频繁被盗也不是新闻了,不仅给用户带来烦恼,也给警务工作增加负担。如何制定一套提升用户体验又能兼顾高安全性的出行品类解决方案,是我们主要思考研究的方向。
为了提升及改善日常出行品类的用户体验,让手机成为电动车钥匙无感解锁,我们想到可利用蓝牙靠近发现的特性,采用无钥匙解锁控车作为主要功能,实现设备快速连接。但是常见的电动车、童车等出行类产品均在户外使用,其安全性要求极高,虽然可利用蓝牙技术进行极简连接控制,但由于蓝牙本身具有开放广播的特性,在设备附近的人都可以通过手机发现设备,则会带来严重的安全隐患。
针对此问题,经过反复推敲,最终决定利用安全秘钥结合云服务,在设备发现、连接操控进行严格的操作认证管控,实现极简连接体验和严格安全控车需求;结合GPS、电子地图,实现设备的出行轨迹展示功能,动态计算设备的停留点、停留时间;采用出行产品电子围栏技术,用户通过手机直接在电子地图上圈定范围区域,如果设备被移到范围外,手机就会收到报警通知,防止车辆丢失。
逻辑实现
手机靠近电动车设备,手机蓝牙打开在未连接的情况下,手机将弹出连接提示,连接后将跳转至App,可绑定设备以及查看相关状态,绑定后通过手机一键控制开关。设定自动锁车的时间,超过设定的时间限制,设备将会自动下电并设防。设置电子围栏,下电设防之后,防盗报警装置启动,超出区域报警提示。
以下为App部分效果图:
电子地图采用高德地图,接下来我们看HarmonyOS高德地图集成程序具体实现过程:
1、为项目增加高德地图依赖包
- 依赖包放入模块src同级目录libs。
- 基础依赖:mapslibrary-release.har。
- 搜索功能:searchlibrary-release.har。
- 模块build.gradle文件中配置。
implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
...
}
声明权限:模块config.json文件中配置网络权限。
"reqPermissions": [
{
"name": "ohos.permission.INTERNET"
}
]
...
在项目初始化-MyApplication.onInitialize() 方法中加入如下代码启用。
// 搜索
ServiceSettings.getInstance().setApiKey(key);
// 地图
MapsInitializer.setApiKey(key);
key需在高德开放平台-控制台-应用管理-我的应用 中为应用添加key,详见:https://lbs.amap.com/api/harmonyos-sdk/guide/get-key。
2、创建地图
xml中使用标签。
使用时建议将高度和宽度设为match_parent,如需更灵活使用则需要在代码中创建。
ohos:id="$+id:mapview"
ohos:height="match_parent"
ohos:width="match_parent"
/>
MapView mapView = (MapView) findComponentById(ResourceTable.Id_mapview);
mapView.onCreate(null);
mapView.onResume();
AMap aMap = mapView.getMap();//地图操作对象
代码中创建。
final CameraPosition LUJIAZUI = new CameraPosition.Builder()
.target(new LatLng(31.238068, 121.501654)).zoom(18).build();
AMapOptions aOptions = new AMapOptions();
aOptions.rotateGesturesEnabled(false);//设置地图是否可以通过手势进行旋转。
aOptions.zoomGesturesEnabled(true);//设置地图是否可以通过手势进行缩放。
aOptions.scrollGesturesEnabled(true);//设置地图是否可以通过手势滑动
aOptions.tiltGesturesEnabled(false);//设置地图是否可以通过手势倾斜(3D效果),默认为true。
aOptions.compassEnabled(false);//设置指南针是否可用。
aOptions.scaleControlsEnabled(false);//设置地图是否显示比例尺,默认为false。
aOptions.zoomControlsEnabled(true);//设置地图是否允许缩放。
aOptions.camera(LUJIAZUI);//设置地图初始化时的地图窗口状态
aOptions.logoPosition(AMapOptions.LOGO_POSITION_BOTTOM_LEFT);//logo位置
aOptions.mapType(AMap.MAP_TYPE_NORMAL);//MAP_TYPE_NIGHT 黑夜地图,夜间模式,值为3
MapView mapView = new MapView(this, aOptions);
ComponentContainer.LayoutConfig layoutConfig = new ComponentContainer.LayoutConfig(
ComponentContainer.LayoutConfig.MATCH_PARENT,
AttrHelper.vp2px(700, this));
layoutConfig.setMarginTop(AttrHelper.vp2px(56, this));
directionalLayout.addComponent(mapView, layoutConfig);
mapView.onCreate(null);
mapView.onResume();
AMap aMap = mapView.getMap();
//缩放按钮右侧居中
aMap.getUiSettings().setZoomPosition(AMapOptions.ZOOM_POSITION_RIGHT_CENTER);
创建后不用时记得销毁。
建议包含mapView的页面单独用一个PageAbility承载。
protected void onStop() {
super.onStop();
if (mapView != null) {
mapView.onDestroy();
}
}
3、常用配置
CameraPosition:
aMap.moveCamera(CameraUpdateFactory.newCameraPosition(
new CameraPosition.Builder()
.target(new LatLng(31.238068,121.501654)).zoom(18).build()));//地图移动窗口
常用使用属性:
(LatLng) target:当前区域屏幕中心经纬度坐标。
(float) zoom:目标可视区域的缩放级别(放大级别),3.0f时地图可视区域最大、20.0f时地图可视区域最小。
常用 Listener。
调用 aMap.setXXXListener() 设置。
OnMapLoadedListener 地图加载完成监听接口。
AMapGestureListener 地图手势识别的回调接口(如禁用手势,识别到相关手势也会回调,但OnCameraChangeListener不会触发)。
OnCameraChangeListener 地图Camera状态发生变化的监听接口.当调用AMap.animateCamera(CameraUpdate)、AMap.moveCamera(CameraUpdate)及手势操作地图时会触发该回调(即当前可视窗口变化监听)。
UiSettings:
UiSettings uiSettings = aMap.getUiSettings()。
可设置地图logo、比例尺、缩放按钮、定位按钮、指南针显示,还可设置旋转手势、拖拽手势、倾斜手势、缩放手势、双指缩放手势是否可用(屏蔽地图底层操作)。
Projection:
用于屏幕像素点坐标系统和地球表面经纬度点坐标系统之间的变换。
public LatLng fromScreenLocation(Point var1) //将屏幕坐标转换成地理坐标。
public Point toScreenLocation(LatLng var1) //将地理坐标转换成屏幕坐标
public VisibleRegion getVisibleRegion() //返回当前可视区域(包含MapView四个角点的经纬度坐标)坐标信息。
4、常见问题解答
在开发过程中,我们经常会遇到以下问题:
1.在xml使用标签再从代码中获取MapView对象,地图已默认初始化,默认地图中心为北京市,缩放级别为10.0f,需要调用aMap.moveCamera()方法将窗口移至我们想要的位置,aMap.moveCamera()方法会触发OnCameraChangeListener监听。
2.Projection.toScreenLocation()方法是基于当前窗口中心点及缩放级别计算的屏幕坐标,该坐标可能会超出屏幕显示区域,尤其是地图初始化还未移动窗口时调用。
3.不太建议在监听回调接口中触发其他监听,可能造成逻辑或优先级冲突(如在AMapGestureListener监听回调中调用aMap.moveCamera()方法从而又触发了OnCameraChangeListener监听)。
4.使用地图后退出页面,地图出现在其他页面底层,原因为地图使用后未销毁,建议包含mapView的页面单独用一个PageAbility承载,在Ability.onStop()方法中调用mapView的onDestroy()方法销毁地图。