Android百度鹰眼轨迹
作者:短工邦技术部 - 陈文超
以“百度鹰眼轨迹”功能为基础,在外卖配送场景中展示物流路径规划方案。
例如,在实际操作中:配送员从订单接收开始记录行程数据;
系统实时更新并传输配送路径信息;
用户端可即时查看完整的物流走向;
对于经常使用外卖服务的用户而言,
更为直观地追踪订单动态,
无需 repeatedly call 商户询问订单状态。
最初想到的方法是通过系统持续采集配送员位置数据,并经由服务器接收端接收并存储。随后,在客户端实时更新并展示这些位置信息于地图界面。这种方案虽然看似简单,并且仅涉及数据传输与更新过程。但需要注意的是,在实际运行中可能会出现一些问题:例如当遇到网络环境欠佳时,在移动设备连接不稳定的场景下可能导致导航服务无法正常工作。此时生成的位置坐标可能出现扭曲状态,并且最终导出的地图展示则呈现混乱状态。
系统注意到百度地图已发布鹰眼轨迹服务的SDK。该服务能够追踪某个目标并将其位置实时更新到百度地图上。这正是我们期待的功能。接下来我们将着手开发这一SDK的功能。
需要先在API控制台中创建一个新的Android应用,并明确该应用类型为Android。随后,在配置界面勾选所有相关API设置。值得注意的是,在最近一次操作中新增的应用带来了两个关键参数——‘发布版SHA1’和‘开发板SHA1’这两个指标的引入极大地方便了对调试状态下功能模块的开发。同时解决了因开发者签名SHA1变更导致无法正常初始化SDK的问题
开发版本的SHA1值获取可以在Eclipse环境下直接进行操作。具体步骤为:进入Windows系统偏好设置,在Android构建过程中选择相应的选项。

发布版SHA1的获取:
使用keytool
第1步:运行进入控制台


第2步:定位到.android文件夹下,输入cd .android

第3步:运行命令keytool -list -v -keystore并指定路径debug.keystore后,在命令窗口中将看到三种指纹认证的数字证书。根据需求选择SHA1类型数字证书(其密码为Android安全策略),例如:
其中keytool是Java JDK自带的工具;
而debug\_keystore则是完整的Android签名证书文件路径。


当AK创建完成时,在控制台可以获取相应的AK信息...为了实现该目标,在AndroidManifest.xml中应添加必要的配置项

请访问http://lbsyun.baidu.com/index.php?title=yingyan/manage并创建鹰眼服务,请获取一个服务ID标识码,并将其用于在代码中启动鹰眼服务系统。


将开发包导入项目中

请前往该页面下载其他Android SDK版本,并根据项目需求选择必要的SDK版本,并避免单独安装每一个SDK以免导致功能冲突
在下载并获取统一 SDK 之后 导入相关.so 文件及.jar 包是必要的步骤 而鹰眼 SDK 则仅需引入.jar 包及-armveabi 即可 这样可以避免 x86 和 x86_64 架构下需要额外加载.so 文件所带来的初始化失败问题 不过 如果需要使用 JPush 极光推送 SDK 则同样仅需引入.jar 包及-armveabi 即可避免与其他库产生冲突 不过 不得不说 百度 SDK 的兼容性确实令人头疼 很容易出现库与库之间的冲突


随后将启动相关工程,在首页将首次创建应用信息获取的唯一标识符(AK)导入到AndroidManifest.xml。
<application>
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="AK key" />
<service
android:name="com.baidu.trace.LBSTraceService"
android:enabled="true"
android:exported="true" >
</service>
<service
<!-- 我们自己的轨迹服务 -->
android:name="com.mcandmc.xxxxxxx.service.MyService"
android:enabled="true"
android:exported="false"
android:process=":track" >
</service>
</application>
添加各种权限
<!-- 这个权限用于进行网络定位-->
<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" />
<!--允许程序连接到已配对的蓝牙设备-->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!--允许程序发现和配对蓝牙设备-->
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<!-- 用于读取手机当前的状态-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 写入扩展存储,向扩展卡写入数据,用于写入离线定位数据-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- SD卡读取权限,用户写入离线定位数据-->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!--允许应用读取低级别的系统日志文件 -->
<uses-permission android:name="android.permission.READ_LOGS" />
<!--允许访问振动设备-->
<uses-permission android:name="android.permission.VIBRATE" />
<!--屏幕保持唤醒 不锁屏-->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!--允许应用程序更改主屏幕中的设置和快捷方式-->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
核心代码
public class MyService extends Service{
private static final String TAG = "MyService";
// 轨迹服务
protected static Trace trace = null;
// 鹰眼服务ID,开发者创建的鹰眼服务对应的服务ID
public static final long serviceId = xxxxxxxx;
// 轨迹服务类型
//0 : 不建立socket长连接,
//1 : 建立socket长连接但不上传位置数据,
//2 : 建立socket长连接并上传位置数据)
private int traceType = 2;
// 轨迹服务客户端
public static LBSTraceClient client = null;
// Entity监听器
public static OnEntityListener entityListener = null;
// 开启轨迹服务监听器
protected OnStartTraceListener startTraceListener = null;
// 停止轨迹服务监听器
protected static OnStopTraceListener stopTraceListener = null;
// 采集周期(单位 : 秒)
private int gatherInterval = 10;
// 设置打包周期(单位 : 秒)
private int packInterval = 20;
protected static boolean isTraceStart = false;
// 手机IMEI号设置为唯一轨迹标记号,只要该值唯一,就可以作为轨迹的标识号,使用相同的标识将导致轨迹混乱
private String imei;
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null && intent.getExtras() != null){
imei= intent.getStringExtra("imei");
}
init();
return super.onStartCommand(intent, START_STICKY, startId);
}
//被销毁时反注册广播接收器
public void onDestroy() {
super.onDestroy();
stopTrace();
}
/** * 初始化
*/
private void init() {
// 初始化轨迹服务客户端
client = new LBSTraceClient(this);
// 设置定位模式
client.setLocationMode(LocationMode.High_Accuracy);
// 初始化轨迹服务
trace = new Trace(this, serviceId, imei, traceType);
// 采集周期,上传周期
client.setInterval(gatherInterval, packInterval);
// 设置http请求协议类型0:http,1:https
client.setProtocolType(0);
// 初始化监听器
initListener();
// 启动轨迹上传
startTrace();
}
// 开启轨迹服务
private void startTrace() {
// 通过轨迹服务客户端client开启轨迹服务
client.startTrace(trace, startTraceListener);
}
// 停止轨迹服务
public static void stopTrace() {
// 通过轨迹服务客户端client停止轨迹服务
LogUtil.i(TAG, "stopTrace(), isTraceStart : " + isTraceStart);
if(isTraceStart){
client.stopTrace(trace, stopTraceListener);
}
}
// 初始化监听器
private void initListener() {
initOnEntityListener();
// 初始化开启轨迹服务监听器
initOnStartTraceListener();
// 初始化停止轨迹服务监听器
initOnStopTraceListener();
}
/** * 初始化OnStartTraceListener
*/
private void initOnStartTraceListener() {
// 初始化startTraceListener
startTraceListener = new OnStartTraceListener() {
// 开启轨迹服务回调接口(arg0 : 消息编码,arg1 : 消息内容,详情查看类参考)
public void onTraceCallback(int arg0, String arg1) {
LogUtil.i(TAG, "开启轨迹回调接口 [消息编码 : " + arg0 + ",消息内容 : " + arg1 + "]");
if (0 == arg0 || 10006 == arg0) {
isTraceStart = true;
}
}
// 轨迹服务推送接口(用于接收服务端推送消息,arg0 : 消息类型,arg1 : 消息内容,详情查看类参考)
public void onTracePushCallback(byte arg0, String arg1) {
LogUtil.i(TAG, "轨迹服务推送接口消息 [消息类型 : " + arg0 + ",消息内容 : " + arg1 + "]");
}
};
}
// 初始化OnStopTraceListener
private void initOnStopTraceListener() {
stopTraceListener = new OnStopTraceListener() {
// 轨迹服务停止成功
public void onStopTraceSuccess() {
LogUtil.i(TAG, "停止轨迹服务成功");
isTraceStart = false;
stopSelf();
}
// 轨迹服务停止失败(arg0 : 错误编码,arg1 : 消息内容,详情查看类参考)
public void onStopTraceFailed(int arg0, String arg1) {
LogUtil.i(TAG, "停止轨迹服务接口消息 [错误编码 : " + arg0 + ",消息内容 : " + arg1 + "]");
}
};
}
// 初始化OnEntityListener
private void initOnEntityListener() {
entityListener = new OnEntityListener() {
// 请求失败回调接口
@Override
public void onRequestFailedCallback(String arg0) {method stub
Looper.prepare();
LogUtil.i(TAG, "entity请求失败回调接口消息 : " + arg0);
Toast.makeText(getApplicationContext(), "entity请求失败回调接口消息 : " + arg0, Toast.LENGTH_SHORT).show();
Looper.loop();
}
// 添加entity回调接口
@Override
public void onAddEntityCallback(String arg0) {
Looper.prepare();
LogUtil.i(TAG, "添加entity回调接口消息 : " + arg0);
Toast.makeText(getApplicationContext(), "添加entity回调接口消息 : " + arg0, Toast.LENGTH_SHORT).show();
Looper.loop();
}
// 查询entity列表回调接口
@Override
public void onQueryEntityListCallback(String message) {
LogUtil.i(TAG, "onQueryEntityListCallback : " + message);
}
@Override
public void onReceiveLocation(TraceLocation location) {
}
};
}
}
在Activity中启动Servise
Intent intent = new Intent();
intent.putExtra("imei", "xxxxxx");
intent.setClass(this, MyService.class);
startService(intent);
这样APP就会在后台默默地上传轨迹啦
如果需要确认轨迹上传的状态,请访问轨迹管理界面进行检查;至于如何在APP上实现这一功能以及后续的具体操作步骤,则将在后面的章节中详细介绍。

