Android鹰眼轨迹追踪

先看下实现效果:


开启服务.png
轨迹查询.png
实时监控.png


鹰眼是一套轨迹管理服务,接入该服务后,可追踪车辆/人员等运动物体,实现实时定位、轨迹追踪和轨迹存储查询等功能。基于鹰眼提供的接口和云端服务,可以迅速构建一套完全属于您自己的完整、精准且高性能的轨迹管理系统,可应用于车队管理、人员管理等领域。具体请查看官网介绍。

鹰眼服务流程.png

这篇文章就讲一下如何在Android App中实现轨迹追踪,既然要追踪轨迹,肯定得先获取这个设备的一系列轨迹点,这就需要我们在终端集成鹰眼服务。我们以Android手机为例,集成鹰眼轨迹SDK后,App将会按照我们设定的频率主动采集实时轨迹。


什么是Android鹰眼轨迹SDK?

鹰眼轨迹是一套基于Android 2.1及以上版本设备的应用程序接口, 可以通过该接口实现轨迹追踪功能:

  • 轨迹追踪:按照设定的频率主动采集实时轨迹
  • 轨迹存储:云端实现海量轨迹数据存储
  • 轨迹查询:查询被追踪者实时位置、历史轨迹和里程
  • 轨迹纠偏:云端对轨迹进行实时去噪、绑路、抽稀处理,解决轨迹偏移问题
  • 地理围栏:当被追踪者进出一定范围(圆形、多边形、线型、行政区)的虚拟地理区域时,监控者可以接收到自动报警通知
  • 图像存储:支持随轨迹上传、存储和查询图像文件




接入鹰眼服务

开发工具:Android Studio

一. 获取AK

使用百度鹰眼Android SDK,需要先获取服务密钥(AK),申请地址:http://lbsyun.baidu.com/apiconsole/key,申请时需要用到开发版SHA1值和发布版SHA1值,详细教程可查看:Android获取SHA1(开发版和发布版)


二. 创建鹰眼服务

1. 创建服务
进入鹰眼轨迹管理平台,点击"创建服务"按钮,在弹窗中填写信息后完成服务创建。

创建鹰眼服务.png

2. 获取 service_id
创建服务成功后即可列表左侧的"系统 ID(service_id)",如:217548,即为访问该service的唯一标识,在后续的接口调用中均要使用。

serviceID.png


三. 接入鹰眼服务

1. 配置库文件

SDK下载地址:http://lbsyun.baidu.com/index.php?title=android-yingyan/sdkandev-download

下载的压缩包解压后将jar包和so文件复制到项目lib目录下,并在app build.gradle的android标签中加入如下代码并Sync Now。

sourceSets {
    main {
        jniLibs.srcDirs = ['libs']
    }
}


2. 设置AndroidManifest.xml

<service 
          android:name="com.baidu.trace.LBSTraceService" 
          android:enabled="true"
          android:process=":remote"/> 
<meta-data
    android:name="com.baidu.lbsapi.API_KEY"
    android:value="上面申请的ak值" />


3. 加入相关权限

    <!-- 这个权限用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <!-- 这个权限用于访问GPS定位-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <!-- 获取运营商信息,用于支持提供运营商信息相关的接口-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!-- 这个权限用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <!-- 写入扩展存储,向扩展卡写入数据,用于写入对象存储BOS数据-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <!-- 访问网络,网络定位需要上网-->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- Android O之后开启前台服务需要申请该权限 -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <!-- Android Q之后,后台定位需要申请该权限 -->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

    <!-- 以下不是鹰眼SDK需要的基础权限,可选 -->
    <!-- 用于加快GPS首次定位,可选权限,非必须-->
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/>
    <!-- 用于Android M及以上系统,申请加入忽略电池优化白名单,可选权限,非必须-->
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>


4. 初始化轨迹服务

// 轨迹服务ID 
long serviceId = 0;
// 设备标识
String entityName = "myTrace";
// 是否需要对象存储服务,默认为:false,关闭对象存储服务。注:鹰眼 Android SDK v3.0以上版本支持随轨迹上传图像等对象数据,若需使用此功能,该参数需设为 true,且需导入bos-android-sdk-1.0.2.jar。
boolean isNeedObjectStorage = false;
// 初始化轨迹服务
Trace mTrace = new Trace(serviceId, entityName, isNeedObjectStorage);
// 初始化轨迹服务客户端
LBSTraceClient mTraceClient = new LBSTraceClient(getApplicationContext());


5. 设置定位和回传周期

鹰眼轨迹数据传输采取定期打包回传的方式,以节省流量。开发者可以自定义定位频率和打包回传频率,频率可设置范围为:2~300秒。例如:定位频率为5s,打包回传频率为10s,则2次定位后打包回传一次。

// 定位周期(单位:秒)
int gatherInterval = 5;
// 打包回传周期(单位:秒)
int packInterval = 10;
// 设置定位和打包周期
mTraceClient.setInterval(gatherInterval, packInterval);


6. 初始化监听器

    // 初始化轨迹服务监听器
    OnTraceListener mTraceListener = new OnTraceListener() {
        /**
         * 绑定服务回调接口
         * @param i  状态码
         * @param s 消息 0:成功 1:失败
         */
        @Override
        public void onBindServiceCallback(int i, String s) {
            Log.e(TAG,"绑定服务回调");
            Log.e(TAG,i+"");
            Log.e(TAG,s+"");
        }

        /**
         * 开启服务回调接口
         * @param status 状态码
         * @param message 消息
         *                <pre>0:成功 </pre>
         *                <pre>10000:请求发送失败</pre>
         *                <pre>10001:服务开启失败</pre>
         *                <pre>10002:参数错误</pre>
         *                <pre>10003:网络连接失败</pre>
         *                <pre>10004:网络未开启</pre>
         *                <pre>10005:服务正在开启</pre>
         *                <pre>10006:服务已开启</pre>
         */
        @Override
        public void onStartTraceCallback(int status, String message) {
            Log.e(TAG,"开启服务回调");
            Log.e(TAG,status+"");
            Log.e(TAG,message+"");
        }
        /**
         * 停止服务回调接口
         * @param status 状态码
         * @param message 消息
         *                <pre>0:成功</pre>
         *                <pre>11000:请求发送失败</pre>
         *                <pre>11001:服务停止失败</pre>
         *                <pre>11002:服务未开启</pre>
         *                <pre>11003:服务正在停止</pre>
         */
        @Override
        public void onStopTraceCallback(int status, String message) {
            Log.e(TAG,"停止服务回调");
            Log.e(TAG,status+"");
            Log.e(TAG,message+"");
        }
        /**
         * 开启采集回调接口
         * @param status 状态码
         * @param message 消息
         *                <pre>0:成功</pre>
         *                <pre>12000:请求发送失败</pre>
         *                <pre>12001:采集开启失败</pre>
         *                <pre>12002:服务未开启</pre>
         */
        @Override
        public void onStartGatherCallback(int status, String message) {
            Log.e(TAG,"开启采集回调");
            Log.e(TAG,status+"");
            Log.e(TAG,message+"");
        }
        /**
         * 停止采集回调接口
         * @param status 状态码
         * @param message 消息
         *                <pre>0:成功</pre>
         *                <pre>13000:请求发送失败</pre>
         *                <pre>13001:采集停止失败</pre>
         *                <pre>13002:服务未开启</pre>
         */
        @Override
        public void onStopGatherCallback(int status, String message) {
            Log.e(TAG,"停止采集回调");
            Log.e(TAG,status+"");
            Log.e(TAG,message+"");
        }
        /**
         * 推送消息回调接口
         *
         * @param messageNo 状态码
         * @param message 消息
         *                  <pre>0x01:配置下发</pre>
         *                  <pre>0x02:语音消息</pre>
         *                  <pre>0x03:服务端围栏报警消息</pre>
         *                  <pre>0x04:本地围栏报警消息</pre>
         *                  <pre>0x05~0x40:系统预留</pre>
         *                  <pre>0x41~0xFF:开发者自定义</pre>
         */
        @Override
        public void onPushCallback(byte messageNo, PushMessage message) {
            Log.e(TAG,"推送消息回调");
            Log.e(TAG,messageNo+"");
            Log.e(TAG,message+"");
        }

        @Override
        public void onInitBOSCallback(int i, String s) {

        }
    };


7. 开启轨迹追踪

开启轨迹追踪需要进行以下两步操作:

(1)开启鹰眼服务,启动鹰眼 service

// 开启服务
mTraceClient.startTrace(mTrace, mTraceListener);

(2)开启轨迹采集,启动轨迹追踪。

// 开启采集
mTraceClient.startGather(mTraceListener);

至此,正式开启轨迹追踪。


8. 结束轨迹追踪

结束轨迹追踪时,可以有两种选择:
(1)停止轨迹服务:此方法将同时停止轨迹服务和轨迹采集,完全结束鹰眼轨迹服务。若需再次启动轨迹追踪,需重新启动服务和轨迹采集,示例代码如下:

// 停止服务
mTraceClient.stopTrace(mTrace, mTraceListener);

(2)停止轨迹采集:此方法将停止轨迹采集,但不停止轨迹服务(即,不再采集轨迹点了,但鹰眼 service 还存活)。

// 停止采集
mTraceClient.stopGather(mTraceListener);


接入鹰眼服务按照官方文档很容易实现,在实际项目中其实经常需要后台运行,所以可以将这些逻辑放到 service 中来实现,然后做相应的服务保活,让其在后台进行轨迹采集。而像轨迹服务、轨迹服务客户端这些对象或变量可以放到 application 中,以方便在整个应用中使用。


四、自定义属性上传

1. 轨迹点自定义属性数据上传

顾名思义,轨迹点自定义属性数据上传就是针对每一个轨迹点增加上传的自定义属性字段,轨迹中的每个位置点可拥有一系列开发者自定义的描述字段,如汽车的电量、发动机转速等,用以记录行程中的实时状态信息。

为实现自定义属性数据上传,开发者须重写OnCustomAttributeListener监听器中的onTrackAttributeCallback()接口,调用 LBSTraceClient.setOnCustomAttributeListener()方法设置自定义属性监听器,并按照设置的定位周期更新onTrackAttributeCallback()的返回值,示例如下:

// 为实现自定义属性数据上传,须重写OnCustomAttributeListener监听器中的onTrackAttributeCallback()接口
mTraceClient.setOnCustomAttributeListener(new OnCustomAttributeListener() {
    @Override
    public Map<String, String> onTrackAttributeCallback() {
        Map<String, String> map = new HashMap<String, String>();
        map.put("key1", "value1");
        map.put("key2", "value2");
        return map;
    }

    //l - 回调时定位点的时间戳(毫秒)
    @Override
    public Map<String, String> onTrackAttributeCallback(long l) {
        return null;
    }
});

SDK每采集一次轨迹,便会自动回调onTrackAttributeCallback()接口,获取属性值并写入当前轨迹点的属性字段中。onTrackAttributeCallback()的返回值是Map<String, String>类型,每个对象都是一个<key,value>对,其中key为自定义字段名称,value为值。


2. 自定义entity属性上传

这里先说明一下,上面的轨迹点自定义属性上传指的是每一个轨迹点增加上传的自定义属性字段。我们目前每一个设备有一个设备标识,也就是在初始化轨迹服务传入的 entityName ,那如果我们还需要上传当前这个entity的其他属性,比如用户姓名、年龄或性别等该如何做呢?

方式一:通过调用 addEntity() 方法主动添加
这种方式等于我们主动添加一个entity,也就不需要我们在初始化轨迹服务传入 entityName ,addEntity()方法需要传入两个参数,具体使用方式可以看鹰眼SDK的API文档,示例如下:

AddEntityRequest request = new AddEntityRequest();
request.setServiceId(serviceId);
request.setEntityName(entityName);
Map<String, String> columns = new HashMap<String, String>();
columns.put("USER_ID", "1001");
columns.put("USER_SEX", "男");
columns.put("ACC_NBR", "1234567890");
request.setColumns(columns);
mTraceClient.addEntity(request, new OnEntityListener() {
    @Override
    public void onAddEntityCallback(AddEntityResponse addEntityResponse) {
        super.onAddEntityCallback(addEntityResponse);
    }
});


方式二:通过调用 updateEntity() 方法指定自定义属性
如果我们在初始化轨迹服务传入了entityName ,服务端将会自动创建以entityName命名的entity。由于服务端自动创建的entity不包含自定义属性的值,若需要指定entity自定义属性,需要再调用updateEntity()方法,通过columnKey字段指定自定义属性的值。
示例如下:

//自定义entity属性上传
UpdateEntityRequest updateEntityRequest = new UpdateEntityRequest();
updateEntityRequest.setServiceId(serviceId);
updateEntityRequest.setEntityName(entityName);
Map<String, String> columns = new HashMap<String, String>();
columns.put("USER_ID", "1001");
columns.put("USER_SEX", "男");
columns.put("ACC_NBR", "1234567890");
updateEntityRequest.setColumns(columns);
mTraceClient.updateEntity(updateEntityRequest, new OnEntityListener() {
     @Override
     public void onAddEntityCallback(AddEntityResponse addEntityResponse) {
         super.onAddEntityCallback(addEntityResponse);
     }
 });


最后附上源码地址:https://download.csdn.net/download/xch_yang/85595480
原创不易,转载请注明出处。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342