基于高德地图实现融云位置共享功能(Android篇)
效果预览:
开发准备:
1: 登录 融云开发者账号,提交 server 平台工单申请开通 实时位置共享功能。工单回复开通成功后、 2 小时生效。
2: 注册高德地图账号、申请成为开发者。获取高德地图相关 key 和 jar 包
3: Android 工程当中配置自己获取的 高德地图的 key.
注: 此处需要配置自己的 高德地图 key
code:
核心类: RealTimeLocationInputProvider
RealTimeLocationMessageProvider
LocationMapActivity
RealTimeLocationActivity
BasicMapActivity 抽象类
RealTimeLocationActivity 继承自 LocationMapActivity 继承自
BasicMapActivity
此类代码可以在 demo 的 message provider 包下 copy 到
需要注意的是 RealTimeLocationInputProvider, 继承自 LocationInputProvider(此类功用是发送当前位置的静态图给对方)。
如果你没有开通 位置共享功能 的服务 他就通不过第一个 if 判断
RealTimeLocationConstant.RealTimeLocationErrorCode errorCode = RongIMClient.getInstance().getRealTimeLocation(getCurrentConversation().getConversationType(), getCurrentConversation().getTargetId());
if (errorCode != null && errorCode != RealTimeLocationConstant.RealTimeLocationErrorCode.RC_REAL_TIME_LOCATION_CONVERSATION_NOT_SUPPORT) {//服务端未开通
然后他就会去调用父类的发送位置的方法 ,也就是 LocationInputProvider 。需要注意会话类型,位置共享目前只支持单聊 和 讨论组的会话类型
核心接口:
RongIMClient.RealTimeLocationListener
目前 demo 是在 ConversationActivity 类中实现这个接口
public interface RealTimeLocationListener {
void onStatusChange(RealTimeLocationStatus status);
void onReceiveLocation(double latitude, double longitude, String userId);
void onParticipantsJoin(String userId);
void onParticipantsQuit(String userId);
void onError(RealTimeLocationErrorCode errorCode);
}
RealTimeLocationActivity 中的
private void addUserInfoToScrollView(final String userId) {
DemoContext.getInstance().getDemoApi().getUserInfo(userId, new DemoApi.GetUserInfoListener() {
@Override
public void onSuccess(final UserInfo userInfo) {
runOnUiThread(new Runnable() {
@Override
public void run() {
horizontalScrollView.addUserToView(userInfo);
setParticipantTextView(-1);
}
});
}
@Override
public void onError(String userId, BaseException e) {
}
});
}
public void onEventMainThread(final RongEvent.RealTimeLocationReceiveEvent event) {
String userId = event.getUserId();
DemoContext.getInstance().getDemoApi().getUserInfo(userId, new DemoApi.GetUserInfoListener() {
@Override
public void onSuccess(final UserInfo userInfo) {
runOnUiThread(new Runnable() {
@Override
public void run() {
moveMarker(new LatLng(event.getLatitude(), event.getLongitude()), userInfo);
}
});
}
@Override
public void onError(String userId, BaseException e) {
}
});
}
请求获取用户信息部分 需要换成自己的 网络请求 或者 缓存信息
经纬度的获取:
LocationMapActivity 中
@Override
public void onLocationChanged(AMapLocation amapLocation) {
if (amapLocation != null && amapLocation.getAMapException().getErrorCode() == 0) {
//获取位置信息
Double geoLat = amapLocation.getLatitude();
Double geoLng = amapLocation.getLongitude();
RongIMClient.getInstance().updateRealTimeLocationStatus(conversationType, targetId, geoLat, geoLng);
}
}
如果进入界面 一直定位在北京中心 你当在此处监听你的经纬度有没有成功获取到,如果经纬度没有获取到可能是因为高德地图的 appkey 或者 keystore 没有配置 (keystore 很重要 与 高德 appkey 必须是对应的 否则无法获取到 经纬度)
key 的配置: key 的值 从高德地图获取 此处只是 demo 的示例
Use:
使用在会话界面 + 号扩展功能中使用:
InputProvider.ExtendProvider[] singleProvider = {
new ImageInputProvider(RongContext.getInstance()),
new CameraInputProvider(RongContext.getInstance()),//相机
new RealTimeLocationInputProvider(RongContext.getInstance()),//带位置共享的地理位置
// new VoIPInputProvider(RongContext.getInstance()),// 语音通话
};
InputProvider.ExtendProvider[] muiltiProvider = {
new ImageInputProvider(RongContext.getInstance()),
new CameraInputProvider(RongContext.getInstance()),//相机
new LocationInputProvider(RongContext.getInstance()),//地理位置
};
RongIM.getInstance().resetInputExtensionProvider(Conversation.ConversationType.PRIVATE, singleProvider);
RongIM.getInstance().resetInputExtensionProvider(Conversation.ConversationType.DISCUSSION, muiltiProvider);
RongIM.getInstance().resetInputExtensionProvider(Conversation.ConversationType.CUSTOMER_SERVICE, muiltiProvider);
RongIM.getInstance().resetInputExtensionProvider(Conversation.ConversationType.GROUP, muiltiProvider);
至此 Android Kit 位置共享集成实现完毕
Lib 使用:
kit 开发者无需参考下面文章
如果 lib sdk 开发者也需要使用位置共享,需要自己来实现所有的 UI 界面。lib 提供了 相关的位置共享的实现接口如下
/**
* 获取 RealTimeLocation 实例,每发起一次位置共享业务,就要获取一个实例。
* 如果获取实例失败,返回 error code,对应具体的失败信息。
* 使用时,每次进入会话,获取该会话对应的实例,以此判断位置共享业务是否可用或者正在进行中。
* 如果返回成功,使用者可以设置监听,发起位置共享。
* 如果返回正在进行中,则是对方已发起位置共享,使用者可以设置监听,加入。
* 如果返回其他失败信息,使用者可以据此做出相应的提示。
*
* @param conversationType 发起位置共享的所在会话的会话类型。
* @param targetId 发起位置共享的 target id。
* @return 是否获取实例成功。
*/
public RealTimeLocationErrorCode getRealTimeLocation(Conversation.ConversationType conversationType, String targetId) {
if (sS == null)
throw new RuntimeException("RongIMClient 尚未初始化!");
if (mLibHandler == null) {
return RealTimeLocationErrorCode.RC_REAL_TIME_LOCATION_NOT_INIT;
}
if (conversationType == null || targetId == null) {
RLog.e(this, "getRealTimeLocation", "Type or id is null!");
return null;
}
int code = -1;
try {
code = mLibHandler.setupRealTimeLocation(conversationType.getValue(), targetId);
} catch (RemoteException e) {
e.printStackTrace();
}
return RealTimeLocationErrorCode.valueOf(code);
}
/**
* 发起位置共享。
*
* @param conversationType 发起位置共享的会话类型。
* @param targetId 发起位置共享的 targetId。
*/
public RealTimeLocationErrorCode startRealTimeLocation(final Conversation.ConversationType conversationType, final String targetId) {
if (sS == null)
throw new RuntimeException("RongIMClient 尚未初始化!");
if (mLibHandler == null) {
return RealTimeLocationErrorCode.RC_REAL_TIME_LOCATION_NOT_INIT;
}
if (conversationType == null || targetId == null) {
RLog.e(this, "startRealTimeLocation", "Type or id is null!");
return null;
}
int code = -1;
try {
code = mLibHandler.startRealTimeLocation(conversationType.getValue(), targetId);
} catch (RemoteException e) {
e.printStackTrace();
}
return RealTimeLocationErrorCode.valueOf(code);
}
/**
* 加入位置共享。
*
* @param conversationType 位置共享的会话类型。
* @param targetId 位置共享的 targetId。
*/
public RealTimeLocationErrorCode joinRealTimeLocation(final Conversation.ConversationType conversationType, final String targetId) {
if (sS == null)
throw new RuntimeException("RongIMClient 尚未初始化!");
if (mLibHandler == null) {
return RealTimeLocationErrorCode.RC_REAL_TIME_LOCATION_NOT_INIT;
}
if (conversationType == null || targetId == null) {
RLog.e(this, "joinRealTimeLocation", "Type or id is null!");
return null;
}
int code = -1;
try {
code = mLibHandler.joinRealTimeLocation(conversationType.getValue(), targetId);
} catch (RemoteException e) {
e.printStackTrace();
}
return RealTimeLocationErrorCode.valueOf(code);
}
/**
* 退出位置共享。
*
* @param conversationType 位置共享的会话类型。
* @param targetId 位置共享的 targetId。
*/
public void quitRealTimeLocation(final Conversation.ConversationType conversationType, final String targetId) {
if (sS == null)
throw new RuntimeException("RongIMClient 尚未初始化!");
if (conversationType == null || targetId == null) {
RLog.e(this, "quitRealTimeLocation", "Type or id is null!");
return;
}
mWorkHandler.post(new Runnable() {
@Override
public void run() {
if (mLibHandler == null) {
return;
}
try {
mLibHandler.quitRealTimeLocation(conversationType.getValue(), targetId);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
/**
* 获取参与该位置共享的所有成员。
*
* @param conversationType 位置共享的会话类型。
* @param targetId 位置共享的 targetId。
* @return 参与成员 id 列表。
*/
public List<String> getRealTimeLocationParticipants(Conversation.ConversationType conversationType, String targetId) {
if (sS == null)
throw new RuntimeException("RongIMClient 尚未初始化!");
if (mLibHandler == null) {
return null;
}
if (conversationType == null || targetId == null) {
RLog.e(this, "getRealTimeLocationParticipants", "Type or id is null!");
return null;
}
List<String> list = null;
try {
list = mLibHandler.getRealTimeLocationParticipants(conversationType.getValue(), targetId);
} catch (RemoteException e) {
e.printStackTrace();
}
return list;
}
/**
* 获取位置共享状态。
*
* @param conversationType 位置共享的会话类型。
* @param targetId 位置共享的 targetId。
* @return 正在进行的位置共享状态。
*/
public RealTimeLocationStatus getRealTimeLocationCurrentState(Conversation.ConversationType conversationType, String targetId) {
if (sS == null)
throw new RuntimeException("RongIMClient 尚未初始化!");
if (mLibHandler == null) {
return null;
}
if (conversationType == null || targetId == null) {
RLog.e(this, "getRealTimeLocationCurrentState", "Type or id is null!");
return null;
}
int state = 0;
try {
state = mLibHandler.getRealTimeLocationCurrentState(conversationType.getValue(), targetId);
} catch (RemoteException e) {
e.printStackTrace();
}
return RealTimeLocationStatus.valueOf(state);
}
/**
* 添加位置共享观察者。
*
* @param conversationType 位置共享的会话类型。
* @param targetId 位置共享的 targetId。
* @param listener 位置共享监听。
*/
public void addRealTimeLocationListener(final Conversation.ConversationType conversationType, final String targetId, final RealTimeLocationListener listener) {
if (sS == null)
throw new RuntimeException("RongIMClient 尚未初始化!");
if (conversationType == null || targetId == null) {
RLog.e(this, "addRealTimeLocationListener", "Type or id is null!");
return;
}
mWorkHandler.post(new Runnable() {
@Override
public void run() {
if (mLibHandler == null) {
return;
}
try {
mLibHandler.addRealTimeLocationListener(conversationType.getValue(), targetId, new IRealTimeLocationListener.Stub() {
@Override
public void onStatusChange(final int status) {
if (listener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
listener.onStatusChange(RealTimeLocationStatus.valueOf(status));
}
});
}
}
@Override
public void onReceiveLocation(final double latitude, final double longitude, final String userId) {
if (listener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
listener.onReceiveLocation(latitude, longitude, userId);
}
});
}
}
@Override
public void onParticipantsJoin(final String userId) {
if (listener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
listener.onParticipantsJoin(userId);
}
});
}
}
@Override
public void onParticipantsQuit(final String userId) {
if (listener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
listener.onParticipantsQuit(userId);
}
});
}
}
@Override
public void onError(final int errorCode) {
if (listener != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
listener.onError(RealTimeLocationErrorCode.valueOf(errorCode));
}
});
}
}
});
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
/**
* 使用者调用此方法更新坐标位置。
*
* @param conversationType 位置共享的会话类型。
* @param targetId 位置共享的会话 targetId。
* @param latitude 维度
* @param longitude 经度
*/
public void updateRealTimeLocationStatus(Conversation.ConversationType conversationType,
String targetId,
double latitude,
double longitude) {
if (sS == null)
throw new RuntimeException("RongIMClient 尚未初始化!");
RLog.d(this, "updateRealTimeLocationStatus", "latitude=" + latitude);
if (conversationType == null || targetId == null) {
RLog.e(this, "updateRealTimeLocationStatus", "Type or id is null!");
return;
}
if (mLibHandler != null) {
try {
mLibHandler.updateRealTimeLocationStatus(conversationType.getValue(), targetId, latitude, longitude);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
/**
* 实时位置共享监听。
*/
public interface RealTimeLocationListener {
/**
* 位置共享状态发生改变。
*
* @param status 空闲、加入、退出、建立连接等状态
*/
void onStatusChange(RealTimeLocationStatus status);
/**
* 接收到位置共享信息。
*
* @param latitude 维度
* @param longitude 经度
* @param userId 发送者 id
*/
void onReceiveLocation(double latitude, double longitude, String userId);
/**
* 对方加入位置共享。
*
* @param userId 加入者 id
*/
void onParticipantsJoin(String userId);
/**
* 对方退出位置共享
*
* @param userId 退出者 id
*/
void onParticipantsQuit(String userId);
/**
* 位置共享过程出现错误。
*
* @param errorCode 错误码
*/
void onError(RealTimeLocationErrorCode errorCode);
}
接口的使用方式可以参考 上述文档注释 和 demo 中 kit 层如何调用 lib 层这几个接口