小权
小权
  • 发布:2020-02-09 17:57
  • 更新:2020-03-12 00:05
  • 阅读:8536

后台(或锁屏)持续/实时定位的实现方案

分类:HTML5+

注意,本问题的解决方案需要对原生打包熟练,并且能编写简单原生代码(如有过编写原生插件经验)
另,ios只要正确设置Background Modes和对应权限申请描述即可,本文只关心安卓端

问题描述:

watchPosition监听位置信息,每间隔一段时间获取位置信息上传,实现后台实时定位,当app退到后台或锁屏一段时间(通常几分钟)后,便获取不到位置信息了。

解决方案:(以百度SDK为例)

第一种:

根据百度官方建议:http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/addition-func/android8-notice,我们可以自行编写一个原生插件,如:

package com.XX.XXX.H5PlusPlugin;  

import android.app.Activity;  
import android.app.Notification;  
import android.app.PendingIntent;  
import android.content.Context;  
import android.content.Intent;  
import android.os.Build;  
import android.os.Bundle;  

import io.dcloud.common.DHInterface.IWebview;  
import io.dcloud.common.DHInterface.StandardFeature;  
import io.dcloud.common.util.JSUtil;  

import com.XX.XXX.util.NotificationUtils;  

import com.baidu.location.BDAbstractLocationListener;  
import com.baidu.location.BDLocation;  
import com.baidu.location.LocationClient;  
import com.baidu.location.LocationClientOption;  

import org.json.JSONArray;  
import org.json.JSONException;  
import org.json.JSONObject;  
import java.text.SimpleDateFormat;  
import java.util.Date;  
import java.text.ParsePosition;  

public class BaiduLocation extends StandardFeature {  
        public String callBackID = "";  
        public Activity curActivity;  
        public IWebview curWebview;  

        private LocationClient mClient;  

        private NotificationUtils mNotificationUtils;  
        private Notification notification;  

        public void onStart(Context pContext, Bundle pSavedInstanceState, String[] pRuntimeArgs) {  
                /**  
                 * 如果需要在应用启动时进行初始化,可以继承这个方法,并在properties.xml文件的service节点添加扩展插件的注册即可触发onStart方法  
                 * */  
        }  

        public void watchPosition(IWebview pWebview, JSONArray array) {  
                curWebview = pWebview;  
                curActivity = pWebview.getActivity();  
                // 原生代码中获取JS层传递的参数,  
                // 参数的获取顺序与JS层传递的顺序一致  
                callBackID = array.optString(0);  
                //String verifyToken = array.optString(1);  

                // 定位初始化  
                mClient = new LocationClient(pWebview.getContext());  
                LocationClientOption mOption = new LocationClientOption();  
                mOption.setScanSpan(10000);  
                mOption.setCoorType("bd09ll");  
                mOption.setIsNeedAddress(true);  
                mOption.setOpenGps(true);  
                mClient.setLocOption(mOption);  
                //mClient.registerLocationListener(myLocationListener);  
                mClient.registerLocationListener(new BDAbstractLocationListener() {  
                                                         public void onReceiveLocation(BDLocation bdLocation) {  
                                                                 JSONObject json=makeJSON(bdLocation,"bd09ll");  
                                                                 //结果返回给js层  
                                                                 JSUtil.execCallback(curWebview, callBackID, json.toString(), JSUtil.OK, true,true);  
                                                         }  
                                                 });  

                //设置后台定位  
                //android8.0及以上使用NotificationUtils  
                if (Build.VERSION.SDK_INT >= 26) {  
                        mNotificationUtils = new NotificationUtils(pWebview.getContext());  
                        Notification.Builder builder2 = mNotificationUtils.getAndroidChannelNotification  
                                ("适配android 8限制后台定位功能", "正在后台定位");  
                        notification = builder2.build();  
                } else {  
                        //获取一个Notification构造器  
                        Notification.Builder builder = new Notification.Builder(curActivity);  
                        Intent nfIntent = new Intent(curActivity, curActivity.getClass());  

                        builder.setContentIntent(PendingIntent.  
                                getActivity(curActivity, 0, nfIntent, 0)) // 设置PendingIntent  
                                .setContentTitle("适配android 8限制后台定位功能") // 设置下拉列表里的标题  
                                .setSmallIcon(android.R.drawable.btn_star) // 设置状态栏内的小图标  
                                .setContentText("正在后台定位") // 设置上下文内容  
                                .setWhen(System.currentTimeMillis()); // 设置该通知发生的时间  

                        notification = builder.build(); // 获取构建好的Notification  
                }  
                notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音  

                mClient.enableLocInForeground(1, notification);  
                mClient.start();  
        }  

        private JSONObject makeJSON(BDLocation pLoc, String coordsType) {  
                JSONObject json = null;  
                try {  
                        json = new JSONObject();  
                        json.put("latitude", pLoc.getLatitude());  
                        json.put("longitude", pLoc.getLongitude());  
                        json.put("altitude", pLoc.getAltitude());  
                        json.put("accuracy", pLoc.getRadius());  
                        json.put("altitudeAccuracy", 0);  
                        json.put("heading", pLoc.getDirection());  
                        json.put("velocity", pLoc.getSpeed());  
                        json.put("coordsType", coordsType);  
                        try {  
                                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
                                ParsePosition pos = new ParsePosition(0);  
                                Date strtodate = formatter.parse(pLoc.getTime(), pos);  
                                json.put("timestamp", strtodate.getTime());  
                        } catch (Exception e) {  
                                e.printStackTrace();  
                                json.put("timestamp", pLoc.getTime());  
                        }  

                                json.put("address", pLoc.getAddrStr());  
                } catch (JSONException e) {  
                        e.printStackTrace();  
                }  
                return json;  
        }  

}  

其中com.XX.XXX.util.NotificationUtils是自行编写的一个生成通知的类,在百度定位sdk的demo工程中可以拷贝。
由于dcloud已经引入过百度SDK(baidu-libs-release.aar),我们不需要再添加引用。
按原生插件配置文档配置好之后,编写好js插件,然后在html页面调用即可,如

plus.BaiduLocation.watchPosition(function(p){  
    $('#div_position').prepend('<p>'+moment().format('HH:mm:ss')+'</p><p>'+JSON.stringify(p)+'</p>');  
});

第二种:

直接修改DCloud官方H5+的watchPosition方法。
该方法在geolocation-baidu-release.aar中,利用jd-ui等工具反编译导出java文件,然后新建工程,修改代码重新编译替换.class即可。(注意新建工程需要引用依赖的包lib.5plus.base-release.aar、baidu-libs-release.aar)
修改的代码就是按百度官方建议的,加上前台服务通知,调用enableLocInForeground开启前台定位,如:

package io.dcloud.js.geolocation.baidu;  

import android.app.Activity;  
import android.app.Notification;  
import android.app.NotificationChannel;  
import android.app.NotificationManager;  
import android.app.PendingIntent;  
import android.content.Context;  
import android.content.Intent;  
import android.content.SharedPreferences;  
import android.graphics.Color;  
import android.os.Build;  
import com.baidu.location.BDAbstractLocationListener;  
import com.baidu.location.BDLocation;  
import com.baidu.location.LocationClient;  
import com.baidu.location.LocationClientOption;  
import io.dcloud.common.DHInterface.FeatureMessageDispatcher;  
import io.dcloud.common.DHInterface.IEventCallback;  
import io.dcloud.common.DHInterface.IWebview;  
import io.dcloud.common.adapter.ui.AdaFrameView;  
import io.dcloud.common.adapter.util.AndroidResources;  
import io.dcloud.common.adapter.util.Logger;  
import io.dcloud.common.adapter.util.SP;  
import io.dcloud.common.util.JSUtil;  
import io.dcloud.common.util.NetTool;  
import io.dcloud.common.util.PdrUtil;  
import io.dcloud.common.util.StringUtil;  
import io.dcloud.js.geolocation.GeoManagerBase;  
import java.text.ParsePosition;  
import java.text.SimpleDateFormat;  
import java.util.Date;  
import java.util.HashMap;  
import java.util.Map;  
import org.json.JSONException;  
import org.json.JSONObject;  

public class BaiduGeoManager  
        extends GeoManagerBase  
{  
        public static final String TAG = BaiduGeoManager.class.getSimpleName();  

        boolean hasAppkey = false;  

        boolean isGeocode = true;  

        boolean isStreamApp = false;  
        static BaiduGeoManager mInstance;  
        LocationClient mClient = null;  
        LocationClientOption mOption = null;  
        HashMap<String, LocationClient> mContinuousMap = new HashMap<>();  
        HashMap<String, LocationClient> mSingleTimeMap = new HashMap<>();  

        private NotificationManager mManager;  
        public static final String ANDROID_CHANNEL_NAME = "ANDROID CHANNEL";  
        private Notification notification;  
        public Activity curActivity;  

        public BaiduGeoManager(Context pContext) {  
                super(pContext);  
                this.hasAppkey = !PdrUtil.isEmpty(AndroidResources.getMetaValue("com.baidu.lbsapi.API_KEY"));  
        }  

        public static BaiduGeoManager getInstance(Context pContext) {  
                pContext = pContext.getApplicationContext();  
                if (mInstance != null) {  
                        return mInstance;  
                }  
                mInstance = new BaiduGeoManager(pContext);  

                return mInstance;  
        }  

        public String execute(IWebview pWebViewImpl, String pActionName, String[] pJsArgs) {  
                curActivity=pWebViewImpl.getActivity();  
                String result = "";  
                try {  
                        this.isStreamApp = pWebViewImpl.obtainApp().isStreamApp();  
                        String t = (pJsArgs.length > 7) ? pJsArgs[6] : "null";  
                        int timeout = Integer.MAX_VALUE;  
                        if (!"null".equals(t)) {  
                                timeout = Integer.parseInt(t);  
                        }  
                        String intervals = (pJsArgs.length > 8) ? pJsArgs[7] : "5000";  
                        int interval = 5000;  
                        if (!intervals.equals("null")) {  
                                interval = Integer.parseInt(intervals);  
                                if (interval < 1000) {  
                                        interval = 1000;  
                                }  
                        }  
                        if (pActionName.startsWith("getCurrentPosition")) {  
                                this.isGeocode = Boolean.parseBoolean(pJsArgs[5]);  
                                boolean _enableHighAccuracy = Boolean.parseBoolean(pJsArgs[1]);  
                                boolean isNotWgs84 = !PdrUtil.isEquals("wgs84", pJsArgs[3]);  
                                if (isNotWgs84) {  
                                        startLocating(pWebViewImpl, pJsArgs[0], null, _enableHighAccuracy, timeout, -1, pActionName.endsWith("DLGEO"), pJsArgs[3], false);  
                                } else {  
                                        String _json = StringUtil.format("{code:%d,message:'%s'}", new Object[] { Integer.valueOf(17), isNotWgs84 ? "指定的provider不存在或无效" : "only support gcj02|bd09|bd09ll" });  
                                        JSUtil.execCallback(pWebViewImpl, pJsArgs[0], _json, JSUtil.ERROR, true, false);  
                                }  

                        } else if (pActionName.startsWith("watchPosition")) {  
                                this.isGeocode = Boolean.parseBoolean(pJsArgs[5]);  
                                boolean _enableHighAccuracy = Boolean.parseBoolean(pJsArgs[2]);  
                                pWebViewImpl.obtainFrameView().addFrameViewListener(new IEventCallback()  
                                {  
                                        public Object onCallBack(String pEventType, Object pArgs) {  
                                                if ((PdrUtil.isEquals(pEventType, "window_close") || PdrUtil.isEquals(pEventType, "close")) && pArgs instanceof IWebview) {  
                                                        BaiduGeoManager.this.stopContinuousLocating();  
                                                        ((AdaFrameView)((IWebview)pArgs).obtainFrameView()).removeFrameViewListener(this);  
                                                }  
                                                return null;  
                                        }  
                                });  
                                boolean isNotWgs84 = !PdrUtil.isEquals("wgs84", pJsArgs[3]);  
                                if (isNotWgs84) {  
                                        startLocating(pWebViewImpl, pJsArgs[0], pJsArgs[1], _enableHighAccuracy, timeout, interval, pActionName.endsWith("DLGEO"), pJsArgs[3], true);  
                                } else {  
                                        String _json = StringUtil.format("{code:%d,message:'%s'}", new Object[] { Integer.valueOf(17), isNotWgs84 ? "指定的provider不存在或无效" : "only support gcj02|bd09|bd09ll" });  
                                        JSUtil.execCallback(pWebViewImpl, pJsArgs[0], _json, JSUtil.ERROR, true, false);  
                                }  

                        } else if (pActionName.startsWith("clearWatch")) {  
                                this.keySet.remove(pJsArgs[0]);  
                                LocationClient tClient=(LocationClient)this.mContinuousMap.remove(pJsArgs[0]);  
                                tClient.disableLocInForeground(true);  
                                tClient.stop();  
                        }  
                        return result;  
                } catch (Exception e) {  
                        Logger.e(TAG, "e.getMessage()==" + e.getMessage());  
                        return result;  
                }  
        }  

        public void startLocating(final IWebview pWebViewImpl, final String pCallbackId, String key, boolean enableHighAccuracy, int timeOut, int intervals, final boolean isDLGeo, final String coordsType, final boolean continuous) {  
                if (this.hasAppkey) {  
                        this.mClient = new LocationClient(pWebViewImpl.getContext());  
                        this.mOption = new LocationClientOption();  
                        if (PdrUtil.isEmpty(key)) {  

                                this.mOption.setScanSpan(0);  
                                this.mSingleTimeMap.put(pCallbackId, this.mClient);  
                        } else {  
                                this.mOption.setScanSpan(intervals);  
                                this.mOption.setLocationNotify(true);  

                                this.keySet.add(key);  
                                this.mContinuousMap.put(key, this.mClient);  
                        }  
                        if (NetTool.isNetworkAvailable(this.mContext)) {  
                                if (enableHighAccuracy) {  
                                        this.mOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);  
                                } else {  
                                        this.mOption.setLocationMode(LocationClientOption.LocationMode.Battery_Saving);  
                                }  
                                this.mOption.setTimeOut(timeOut);  
                        } else {  
                                this.mOption.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);  
                                if (Integer.MAX_VALUE == timeOut) {  
                                        this.mOption.setTimeOut(3000);  
                                } else {  
                                        this.mOption.setTimeOut(timeOut);  
                                }  
                        }  
                        this.mOption.setIsNeedAddress(this.isGeocode);  
                        this.mOption.setCoorType(getCoorType(coordsType));  
                        this.mClient.setLocOption(this.mOption);  
                        this.mClient.registerLocationListener(new BDAbstractLocationListener()  
                        {  
                                public void onReceiveLocation(BDLocation bdLocation) {  
                                        if (bdLocation.getAddress() != null) {  
                                                FeatureMessageDispatcher.dispatchMessage("record_address", (bdLocation.getAddress() != null) ? (bdLocation.getAddress()).address : null);  
                                        }  
                                        Logger.e(BaiduGeoManager.TAG, "onReceiveLocation bdLocation==" + bdLocation.toString());  
                                        BaiduGeoManager.this.callBack2Front(pWebViewImpl, pCallbackId, bdLocation, BaiduGeoManager.this.getCoorType(coordsType), isDLGeo, continuous);  
                                }  
                        });  

                        if(continuous) {  
                                //设置后台定位  
                                if (Build.VERSION.SDK_INT >= 26) {  
                                        createChannels();  
                                        Notification.Builder builder2 = getAndroidChannelNotification("适配android 8限制后台定位功能", "正在后台定位");  
                                        notification = builder2.build();  
                                } else {  
                                        //获取一个Notification构造器  
                                        Notification.Builder builder = new Notification.Builder(curActivity);  
                                        Intent nfIntent = new Intent(curActivity, curActivity.getClass());  

                                        builder.setContentIntent(PendingIntent.  
                                                getActivity(curActivity, 0, nfIntent, 0)) // 设置PendingIntent  
                                                .setContentTitle("适配android 8限制后台定位功能") // 设置下拉列表里的标题  
                                                .setSmallIcon(android.R.drawable.btn_star) // 设置状态栏内的小图标  
                                                .setContentText("正在后台定位") // 设置上下文内容  
                                                .setWhen(System.currentTimeMillis()); // 设置该通知发生的时间  

                                        notification = builder.build(); // 获取构建好的Notification  
                                }  
                                notification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音  
                                this.mClient.enableLocInForeground(1,notification);  
                        }  

                        this.mClient.start();  
                } else {  
                        String _json = StringUtil.format("{code:%d,message:'%s'}", new Object[] { Integer.valueOf(16), "has not baidu appkey" });  
                        JSUtil.execCallback(pWebViewImpl, pCallbackId, _json, JSUtil.ERROR, true, false);  
                }  
        }  

        public void createChannels() {  
                // create android channel  
                NotificationChannel androidChannel = new NotificationChannel(curActivity.getPackageName()+".BDLocation",  
                        ANDROID_CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);  
                // Sets whether notifications posted to this channel should display notification lights  
                androidChannel.enableLights(true);  
                // Sets whether notification posted to this channel should vibrate.  
                androidChannel.enableVibration(true);  
                // Sets the notification light color for notifications posted to this channel  
                androidChannel.setLightColor(Color.GREEN);  
                // Sets whether notifications posted to this channel appear on the lockscreen or not  
                androidChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);  

                getManager().createNotificationChannel(androidChannel);  
        }  

        private NotificationManager getManager() {  
                if (mManager == null) {  
                        mManager = (NotificationManager) curActivity.getSystemService(Context.NOTIFICATION_SERVICE);  
                }  
                return mManager;  
        }  

        public Notification.Builder getAndroidChannelNotification(String title, String body) {  
                return new Notification.Builder(curActivity.getApplicationContext(), curActivity.getPackageName()+".BDLocation")  
                        .setContentTitle(title)  
                        .setContentText(body)  
                        .setSmallIcon(android.R.drawable.btn_star)  
                        .setAutoCancel(true);  
        }  

        private void stopContinuousLocating() {  
                for (Map.Entry<String, LocationClient> entry : this.mContinuousMap.entrySet()) {  
                        System.out.println("key= " + (String)entry.getKey() + " and value= " + entry.getValue());  
                        if (!PdrUtil.isEmpty(entry.getValue())) {  
                                LocationClient tClient=(LocationClient)entry.getValue();  
                                tClient.disableLocInForeground(true);  
                                tClient.stop();  
                        }  
                }  
        }  

        private void callBack2Front(IWebview mWebview, String mCallbackId, BDLocation location, String CoordsType, boolean isDLGeo, boolean continuous) {  
                if (!continuous &&  
                        !PdrUtil.isEmpty(this.mSingleTimeMap.get(mCallbackId))) {  
                        ((LocationClient)this.mSingleTimeMap.get(mCallbackId)).stop();  
                }  

                JSONObject _json = makeJSON(location, CoordsType);  
                if (_json == null) {  
                        geoDataError(mWebview, mCallbackId, isDLGeo, continuous);  
                } else {  

                        callback(mWebview, mCallbackId, _json.toString(), JSUtil.OK, true, isDLGeo, continuous);  
                }  
        }  

        public void callback(IWebview webview, String callId, String json, int code, boolean isJson, boolean isDLGeo, boolean continuous) {  
                if (isDLGeo) {  
                        JSUtil.execGEOCallback(webview, callId, json, code, isJson, continuous);  
                } else {  
                        JSUtil.execCallback(webview, callId, json, code, isJson, continuous);  
                }  
        }  

        private JSONObject makeJSON(BDLocation pLoc, String coordsType) {  
                JSONObject json = null;  
                try {  
                        json = new JSONObject();  
                        json.put("latitude", pLoc.getLatitude());  
                        json.put("longitude", pLoc.getLongitude());  
                        json.put("altitude", pLoc.getAltitude());  
                        json.put("accuracy", pLoc.getRadius());  
                        json.put("altitudeAccuracy", 0);  
                        json.put("heading", pLoc.getDirection());  
                        json.put("velocity", pLoc.getSpeed());  
                        json.put("coordsType", coordsType);  
                        try {  
                                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
                                ParsePosition pos = new ParsePosition(0);  
                                Date strtodate = formatter.parse(pLoc.getTime(), pos);  
                                json.put("timestamp", strtodate.getTime());  
                        } catch (Exception e) {  
                                e.printStackTrace();  
                                json.put("timestamp", pLoc.getTime());  
                        }  
                        if (this.isGeocode) {  
                                JSONObject address = new JSONObject();  
                                json.put("address", address);  
                                address.put("country", pLoc.getCountry());  
                                address.put("province", pLoc.getProvince());  
                                address.put("city", pLoc.getCity());  
                                address.put("district", pLoc.getDistrict());  
                                address.put("street", pLoc.getStreet());  
                                address.put("streetNum", pLoc.getStreetNumber());  
                                address.put("poiName", (pLoc.getPoiList() != null && pLoc.getPoiList().size() > 0) ? pLoc.getPoiList().get(0) : null);  
                                address.put("postalCode", null);  
                                address.put("cityCode", pLoc.getCityCode());  
                                json.put("addresses", pLoc.getAddrStr());  
                        }  
                } catch (JSONException e) {  
                        e.printStackTrace();  
                }  
                saveGeoData(pLoc, coordsType);  
                return json;  
        }  

        private String getCoorType(String coorType) {  
                if (PdrUtil.isEquals(coorType, "bd09ll"))  
                        return "bd09ll";  
                if (PdrUtil.isEquals(coorType, "bd09")) {  
                        return "bd09";  
                }  
                return "gcj02";  
        }  

        public void onDestroy() {  
                for (Map.Entry<String, LocationClient> entry : this.mContinuousMap.entrySet()) {  
                        if (!PdrUtil.isEmpty(entry.getValue())) {  
                                ((LocationClient)entry.getValue()).stop();  
                        }  
                }  
                this.mContinuousMap.clear();  
                for (Map.Entry<String, LocationClient> entry : this.mSingleTimeMap.entrySet()) {  
                        if (!PdrUtil.isEmpty(entry.getValue())) {  
                                ((LocationClient)entry.getValue()).stop();  
                        }  
                }  
                this.mSingleTimeMap.clear();  
        }  

        private void saveGeoData(BDLocation pLoc, String coordsType) {  
                if (!this.isStreamApp) {  
                        JSONObject jsonObject = new JSONObject();  
                        JSONObject coordsJson = new JSONObject();  

                        try {  
                                coordsJson.put("latitude", pLoc.getLatitude());  
                                coordsJson.put("longitude", pLoc.getLongitude());  
                                jsonObject.put("coords", coordsJson);  
                                jsonObject.put("coordsType", coordsType);  
                                if (this.isGeocode) {  
                                        jsonObject.put("addresses", pLoc.getAddrStr());  
                                }  
                                SharedPreferences startSp = SP.getOrCreateBundle("start_statistics_data");  
                                SP.setBundleData(startSp, "geo_data", jsonObject.toString());  
                        } catch (Exception e) {  

                                e.printStackTrace();  
                        }  
                }  
        }  

        private void geoDataError(IWebview pWebViewImpl, String pCallbackId, boolean isDLGeo, boolean continuous) {  
                String err = StringUtil.format("{code:%d,message:'%s'}", new Object[] { Integer.valueOf(40), "定位异常"});  
                if (isDLGeo) {  
                        JSUtil.execGEOCallback(pWebViewImpl, pCallbackId, err, JSUtil.ERROR, true, continuous);  
                } else {  
                        JSUtil.execCallback(pWebViewImpl, pCallbackId, err, JSUtil.ERROR, true, continuous);  
                }  
        }  
}  

总结:

以上代码只是测试功能,写得简单且不规范。其实都只是加入百度SDK已经实现的功能代码。
经打包安装到手机(目前只在华为Novaz5)测试,退到后台锁屏几十分钟再打开查看记录,一直能连续获取到位置信息。
另外,要将手机管家中对该app去掉“自动管理”,并打开“允许后台活动”开关

最后,强烈建议官方修改watchPosition方法(如加个生成前台服务通知的参数?)!!

6 关注 分享
z***@163.com 8***@qq.com androiddev 阿居 迪格立之 s***@163.com

要回复文章请先登录注册

z***@163.com

z***@163.com

文章写的很好,希望官方好好看看。同时根据这篇文章,我实现了gps持续跟踪和轨迹点上传(需要用服务来做,前台js 5分钟后网络就会down掉)。当然需要改原先的代码,原先的clearWatch还不好使,修复了下,还增加了一些功能(可传递鹰眼实体标识等),有需要的联系QQ 393216535 备注dcloud
2020-03-12 00:05
8***@qq.com

8***@qq.com

支持
2020-02-28 14:53