位置消息
IMKit 提供了位置插件,实现了发送位置消息、位置缩略图功能。本文还描述了如何自行实现了应用内位置共享。
- SDK 默认发送的消息包含位置消息内容对象 [RCLocationMessage](类型标识:
RC:LBSMsg
)。 - 实时位置共享也是基于消息实现的。SDK 默认使用类型标识为
RC:RL
、RC:RLStart
、RC:RLJoin
、RC:RLQuit
的消息。
局限
- IMKit 的位置插件基于 MapKit。如需使用其他地图服务,您可以自定义插件,自行构造位置消息并发送。添加自定义插件的方法详见输入区域。
- 位置插件默认仅支持点击发送位置。
用法
IMKit 从 5.2.3 及之后开始支持 LocationKit
插件。如果从低于 5.2.3 的 IMKit 版本升级,请参见下文升级旧版位置插件。
集成位置插件
请根据 IMKit 的导入方式,选择集成 LocationKit
插件的方式。
-
使用 CocoaPods
Framework(要求 SDK ≥ 5.2.3)
rubypod 'RongCloudIM/LocationKit',' x.y.z' #位置插件
源码(要求 IMKit 同为源码,要求 SDK ≥ 5.2.3)
rubypod 'RongCloudOpenSource/LocationKit', 'x.y.z' #位置插件
-
手动集成。如果项目中 IMKit 源码为手动导入,请通过融云官网 SDK 下载页面下载
LocationKit
插件。由于 IMKit 的LocationKit
插件依赖 IMLib SDK 提供的Location
库,您还需要额外添加Location
库。您可以选择通过 CocoaPods 导入Location
Framework,或使用下载包中的RongLocation.xcframework
文件。rubypod 'RongCloudIM/Location',' x.y.z' # IMLib SDK 位置基础库
x.y.z 代表具体版本,请通过融云官网 SDK 下载页面或 CocoaPods 仓库等方式查询最新版本。
发送位置消息
位置插件集成完毕后,在扩展面板里会自动生成位置消息入口。用户点击输入栏右侧 +
号按钮可展开扩展面板,点击位置图标,即可发送位置消息。
集成位置插件后,默认仅支持点击发送位置。
使用实时位置共享
IMKit SDK 没有提供实时位置共享功能插件。您可以参考融云示例应用 SealTalk 中的代码,在您应用中实现实时位置共享。
图中参与位置实时共享人员的用户头像、昵称需要 App 提供给 IMKit,具体方法参考设置用户信息。
下面以 SealTalk 示例应用开源代码为例,说明在单聊会话中实现位置共享的步骤。操作完成后,就可以在单聊会话中使用位置实时共享功能。您也可以参考在 SealTalk 的 RCDChatViewController.m。
-
下载 SealTalk 项目源码,将源码中的
Sections/Chat/RealTimeLocation
导入工程。shellhttps://github.com/rongcloud/sealtalk-ios
-
在会话页面中导入下面头文件。
Objective C#import <objc/runtime.h>
#import "RealTimeLocationEndCell.h"
#import "RealTimeLocationStartCell.h"
#import "RealTimeLocationStatusView.h"
#import "RealTimeLocationViewController.h"
#import "RealTimeLocationDefine.h"
static const char *kRealTimeLocationKey = "kRealTimeLocationKey";
static const char *kRealTimeLocationStatusViewKey = "kRealTimeLocationStatusViewKey"; -
设置相关属性。
Objective C@interface RCDChatViewController () < RCRealTimeLocationObserver,
RealTimeLocationStatusViewDelegate>
@property(nonatomic, weak) id<RCRealTimeLocationProxy> realTimeLocation;
@property(nonatomic, strong) RealTimeLocationStatusView *realTimeLocationStatusView;
@end -
获取位置共享服务并注册消息。
Objective C- (void)viewDidLoad{
[super viewDidLoad];
[self registerRealTimeLocationCell];
[self getRealTimeLocationProxy];
}Objective C- (void)registerRealTimeLocationCell {
[self initRealTimeLocationStatusView];
[self registerClass:[RealTimeLocationStartCell class] forMessageClass:[RCRealTimeLocationStartMessage class]];
[self registerClass:[RealTimeLocationEndCell class] forMessageClass:[RCRealTimeLocationEndMessage class]];
}
- (void)getRealTimeLocationProxy {
__weak typeof(self) weakSelf = self;
[[RCRealTimeLocationManager sharedManager] getRealTimeLocationProxy:self.conversationType
targetId:self.targetId
success:^(id<RCRealTimeLocationProxy> realTimeLocation){
weakSelf.realTimeLocation = realTimeLocation;
[weakSelf.realTimeLocation addRealTimeLocationObserver:weakSelf];
[weakSelf updateRealTimeLocationStatus];
} error:^(RCRealTimeLocationErrorCode status) {
NSLog(@"get location share failure with code %d",(int)status);
}];
}
- (void)initRealTimeLocationStatusView {
self.realTimeLocationStatusView =
[[RealTimeLocationStatusView alloc] initWithFrame:CGRectMake(0, 62, self.view.frame.size.width, 0)];
self.realTimeLocationStatusView.delegate = self;
[self.view addSubview:self.realTimeLocationStatusView];
} -
点击位置时弹出位置实时共享选项。
Objective C//RCDChatViewController Class
- (void)pluginBoardView:(RCPluginBoardView *)pluginBoardView clickedItemWithTag:(NSInteger)tag {
switch (tag) {
case PLUGIN_BOARD_ITEM_LOCATION_TAG: {
if (self.realTimeLocation) {
[RCActionSheetView showActionSheetView:nil cellArray:@[RTLLocalizedString(@"send_location"), RTLLocalizedString(@"location_share")]
cancelTitle:RTLLocalizedString(@"cancel")
selectedBlock:^(NSInteger index) {
if (index == 0) {
[super pluginBoardView:self.chatSessionInputBarControl.pluginBoardView
clickedItemWithTag:PLUGIN_BOARD_ITEM_LOCATION_TAG];
}else{
[self showRealTimeLocationViewController];
}
} cancelBlock:^{
}];
} else {
[super pluginBoardView:pluginBoardView clickedItemWithTag:tag];
}
}break;
default:
[super pluginBoardView:pluginBoardView clickedItemWithTag:tag];
break;
}
} -
实时位置共享监听代理方法。
Objective C- (void)onRealTimeLocationStatusChange:(RCRealTimeLocationStatus)status {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf updateRealTimeLocationStatus];
});
}
- (void)onReceiveLocation:(CLLocation *)location type:(RCRealTimeLocationType)type fromUserId:(NSString *)userId {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf updateRealTimeLocationStatus];
});
}
- (void)onParticipantsJoin:(NSString *)userId {
__weak typeof(self) weakSelf = self;
if ([userId isEqualToString:[RCCoreClient sharedCoreClient].currentUserInfo.userId]) {
[self notifyParticipantChange:RTLLocalizedString(@"you_join_location_share")];
} else {
[[RCIM sharedRCIM]
.userInfoDataSource
getUserInfoWithUserId:userId
completion:^(RCUserInfo *userInfo) {
if (userInfo.name.length) {
[weakSelf notifyParticipantChange:[NSString stringWithFormat:RTLLocalizedString(@"someone_join_share_location"),userInfo.name]];
} else {
[weakSelf notifyParticipantChange:[NSString stringWithFormat:RTLLocalizedString(@"user_join_share_location"),userId]];
}
}];
}
}
- (void)onParticipantsQuit:(NSString *)userId {
__weak typeof(self) weakSelf = self;
if ([userId isEqualToString:[RCCoreClient sharedCoreClient].currentUserInfo.userId]) {
[self notifyParticipantChange:RTLLocalizedString(@"you_quit_location_share")];
} else {
[[RCIM sharedRCIM]
.userInfoDataSource
getUserInfoWithUserId:userId
completion:^(RCUserInfo *userInfo) {
if (userInfo.name.length) {
[weakSelf
notifyParticipantChange:[NSString stringWithFormat:RTLLocalizedString(@"someone_quit_location_share"),userInfo.name]];
} else {
[weakSelf
notifyParticipantChange:[NSString stringWithFormat:RTLLocalizedString(@"user_quit_location_share"),userId]];
}
}];
}
}
- (void)onRealTimeLocationStartFailed:(long)messageId {
dispatch_async(dispatch_get_main_queue(), ^{
for (int i = 0; i < self.conversationDataRepository.count; i++) {
RCMessageModel *model = [self.conversationDataRepository objectAtIndex:i];
if (model.messageId == messageId) {
model.sentStatus = SentStatus_FAILED;
}
}
NSArray *visibleItem = [self.conversationMessageCollectionView indexPathsForVisibleItems];
for (int i = 0; i < visibleItem.count; i++) {
NSIndexPath *indexPath = visibleItem[i];
RCMessageModel *model = [self.conversationDataRepository objectAtIndex:indexPath.row];
if (model.messageId == messageId) {
[self.conversationMessageCollectionView reloadItemsAtIndexPaths:@[ indexPath ]];
}
}
});
}
- (void)notifyParticipantChange:(NSString *)text {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.realTimeLocationStatusView updateText:text];
[weakSelf performSelector:@selector(updateRealTimeLocationStatus) withObject:nil afterDelay:0.5];
});
}
- (void)onFailUpdateLocation:(NSString *)description {
}
#pragma mark - 实时位置共享状态 view 代理方法
- (void)onJoin {
[self showRealTimeLocationViewController];
}
- (RCRealTimeLocationStatus)getStatus {
return [self.realTimeLocation getStatus];
}
- (void)onShowRealTimeLocationView {
[self showRealTimeLocationViewController];
}
- (void)setRealTimeLocation:(id<RCRealTimeLocationProxy>)realTimeLocation{
objc_setAssociatedObject(self, kRealTimeLocationKey, realTimeLocation, OBJC_ASSOCIATION_ASSIGN);
}
- (id<RCRealTimeLocationProxy>)realTimeLocation {
return objc_getAssociatedObject(self, kRealTimeLocationKey);
}
- (void)setRealTimeLocationStatusView:(RealTimeLocationStatusView *)realTimeLocationStatusView {
objc_setAssociatedObject(self, kRealTimeLocationStatusViewKey, realTimeLocationStatusView,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (RealTimeLocationStatusView *)realTimeLocationStatusView {
return objc_getAssociatedObject(self, kRealTimeLocationStatusViewKey);
}
//弹出实时位置共享页面
- (void)showRealTimeLocationViewController {
RealTimeLocationViewController *lsvc = [[RealTimeLocationViewController alloc] init];
lsvc.realTimeLocationProxy = self.realTimeLocation;
if ([self.realTimeLocation getStatus] == RC_REAL_TIME_LOCATION_STATUS_INCOMING) {
[self.realTimeLocation joinRealTimeLocation];
} else if ([self.realTimeLocation getStatus] == RC_REAL_TIME_LOCATION_STATUS_IDLE) {
[self.realTimeLocation startRealTimeLocation];
}
lsvc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController presentViewController:lsvc
animated:YES
completion:^{
}];
}
//更新实时位置共享状态
- (void)updateRealTimeLocationStatus {
if (self.realTimeLocation) {
[self.realTimeLocationStatusView updateRealTimeLocationStatus];
__weak typeof(self) weakSelf = self;
NSArray *participants = nil;
switch ([self.realTimeLocation getStatus]) {
case RC_REAL_TIME_LOCATION_STATUS_OUTGOING:
[self.realTimeLocationStatusView updateText:RTLLocalizedString(@"you_location_sharing")];
break;
case RC_REAL_TIME_LOCATION_STATUS_CONNECTED:
case RC_REAL_TIME_LOCATION_STATUS_INCOMING:
participants = [self.realTimeLocation getParticipants];
if (participants.count == 1) {
NSString *userId = participants[0];
[weakSelf.realTimeLocationStatusView
updateText:[NSString stringWithFormat:RTLLocalizedString(@"user_location_sharing"), userId]];
[[RCIM sharedRCIM]
.userInfoDataSource
getUserInfoWithUserId:userId
completion:^(RCUserInfo *userInfo) {
if (userInfo.name.length) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.realTimeLocationStatusView updateText:[NSString stringWithFormat:RTLLocalizedString(@"someone_location_sharing"),userInfo.name]];
});
}
}];
} else {
if (participants.count < 1)
[self.realTimeLocationStatusView removeFromSuperview];
else
[self.realTimeLocationStatusView
updateText:[NSString stringWithFormat:@"%d人正在共享地理位置", (int)participants.count]];
}
break;
default:
break;
}
}
} -
(可选)在
IMLibCore
的RCConfig.plist
文件中,添加如下配置,开启群组会话的实时位置共享功能。群聊最多支持5人同时位置共享。xml<key>RealTimeLocationShare</key>
<dict>
<key>SupportConversationTypes</key>
<array>
<string>1</string>
<string>3</string>
</array>
</dict>
升级旧版位置插件
IMKit 5.2.3 之前版本升级到 5.2.3 时,旧版位置插件即失效。
- 5.2.3 之前,IMKit 内置了位置插件。
- 5.2.3 及之后,IMKit 不再内置位置插件。不需要位置功能时,可不必集成位置插件(LocationKit),避免 App 上架因获取位置权限需要审核的问题。
- IMKit 5.2.3 之前版本升级到 5.2.3 时,原发送位置功能即失效。