H5+App后台持续定位功能实现

it2023-12-30  70

H5+App后台持续定位功能实现

1. 项目需求2. 实现过程3.最终实现4. 关于测试用例

1. 项目需求

最近有个需求就是需要完成在后台的实时定位,并且要将获取到的定位信息写到Map控件上去。也就是说,即使手机锁屏了或者手机退出到菜单页面也要保证定位能正常运行并且将数据绘制到地图控件中。

2. 实现过程

找了网上很多的实现,各种样的都有。这里稍微列举一下,毕竟都是都是方法,也从中找到了一些实现的思路。其实个人认为主要还是为了保活JS,让JS代码生效,即可完成我们的操作。

1.监听后台事件,让其呈现出不退出的状态。 代码如下

let mainq = plus.android.runtimeMainActivity(); //为了防止快速点按返回键导致程序退出重写quit方法改为隐藏至后台 plus.runtime.quit = function(){ mainq.moveTaskToBack(false); }; //重写toast方法如果内容为 ‘再按一次退出应用’ 就隐藏应用,其他正常toast plus.nativeUI.toast = (function(str){ if(str == '再按一次退出应用'){ mainq.moveTaskToBack(false); return false; }else{ console.log('不处理') } });

这种方法可以保证用户在按返回键时不会退出应用,而是保持后台状态。但是过一会或者是点击其他应用,然后在进入目标应用的时候,应用显示启动页面,重新开启。

2.使用maps的watchlocationpoint()函数进行定位监听。这里就不附上代码了,我自己在尝试后这个方法后台也是会被杀掉,所以也淘汰。

3.使用NJS拉起一个通知栏来保活。这个方法看起来也行(后面的方法也是基于这个思路的),但是我小米8SE 直接复制过来的NJS代码,通知栏空空如也,对我来说这个方法行不通,也看了网上的类似代码,进行了简单修改,但还是无济于事。所以我个人淘汰了这个方法,大家有兴趣可以去官方社区看看。

4.使用原生安卓拉起来保活,这部走了很多弯路。也稍微了解了一下Activity生命周期,服务启动,布局一些乱七八糟的啥的。这里会碰到的问题可能就是:安卓应用后台运行没问题,但是JS还是死掉了(用了websocket和定时器进行测试做出的判断,可能存在测试方式的巧合,不确定性等等)。

附上之前做的小记录。

3.最终实现

最终是使用了原生安卓调用高德后台持续定位,并开启通知栏服务进行挂活。然后,在监听到定位信息的回调函数中使用webview.loadUrl()调用要执行的JS代码进行保活,在JS的test123()方法中进行maps的描点划线操作。这里我在测试的时候加了网络请求到我的阿里云服务器,在服务器上打印时间来检测JS是否被调用,是否存活。

参考了这位老哥代码博客: https://blog.csdn.net/qq_22718203/article/details/86571635

附上简单代码:

/** * 定位监听 */ AMapLocationListener locationListener = new AMapLocationListener() { @Override public void onLocationChanged(AMapLocation location) { //这里是单例模式获取webview页面,如果获取多次页面会不断刷新,数据丢失。 WebView webView = GetMapInfoToWeb.getInstance(); //调用js的test123()方法 webView.loadUrl("javascript:test123()"); System.out.println("======================webview"+webView); if (null != location) { StringBuffer sb = new StringBuffer(); //errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明 if (location.getErrorCode() == 0) { double lat = location.getLatitude(); double lon = location.getLongitude(); } else { //定位失败 sb.append("定位失败" + "\n"); sb.append("错误码:" + location.getErrorCode() + "\n"); sb.append("错误信息:" + location.getErrorInfo() + "\n"); sb.append("错误描述:" + location.getLocationDetail() + "\n"); System.out.println(sb.toString()); } } else { } } };

PS:webview这里也碰到了一些小坑,之前调试的时候已经可以实现安卓直接调用JS代码。但是页面一直刷新,其实是获取当前激活页面的问题。后面使用了单例模式去解决他(可以根据需求来启动再获取对应的页面存入单例即可,或者对单例进行简单修改)。代码也附上(使用双重检查即可):

/* 单例模式获取webview页面,避免获取多次导致页面刷新。 原功能:获取webview页面,调用JS方法 */ public class GetMapInfoToWeb { public static volatile WebView Webview; public static WebView getInstance(){ if(Webview == null){ synchronized (GetMapInfoToWeb.class){ if(Webview == null){ IApp iApp = SDK.obtainCurrentApp(); // 这里获取要调用方法的页面,目前vue打包还有一些问题 IWebview iWebview = SDK.obatinFirstPage(iApp); Webview = iWebview.obtainWebview(); } } } return Webview; } }

4. 关于测试用例

这里的测试我通过: 1.JS原生定时器计数显示到页面上 2.webview.loadUrl()调用JS方法执行网络请求,查看阿里服务器的日志时间; 3.打印出地图点的个数到页面中。(webview.loadUrl()调用一次方法就执行一次创建新点)

/* 绘制路线 */ function drawMap(x,y){ if(map == null){ return; } /* 定位到当前位置 */ map.centerAndZoom( new plus.maps.Point(y,x),18); let nowPoint = new plus.maps.Point(y,x); /* 添加到划线数组中 */ changedPosition.push(nowPoint); document.getElementById('point').innerHTML = changedPosition.length; let nowMaker = new plus.maps.Marker(nowPoint); nowMaker.setLabel("到此一游"); map.addOverlay(nowMaker); /* 新建一条线 */ var changemap = new plus.maps.Polyline( changedPosition ); map.addOverlay(changemap ); /* 发送网络请求 */ doSend("test"); } /* 发送网络连接判断JS是否存活 */ function doSend(info){ var xhr = new plus.net.XMLHttpRequest(); xhr.onreadystatechange = function () { switch ( xhr.readyState ) { case 0: console.log( "xhr请求已初始化" ); break; case 1: console.log( "xhr请求已打开" ); break; case 2: console.log( "xhr请求已发送" ); break; case 3: console.log( "xhr请求已响应"); break; case 4: if ( xhr.status == 200 ) { console.log( "xhr请求成功:"+xhr.responseText ); } else { console.log( "xhr请求失败:"+xhr.readyState ); } break; default : break; } } xhr.open( "GET", "阿里云服务器"+info ); xhr.send(); }

4.测试记录:

github地址:https://github.com/2017LLLLL/h5plusMaps/tree/master

最新回复(0)