iOS开发 (类似QQ微信) 一账号不能在多台设备登录的实现
2017-04-27 本文已影响261人
糖糖本尊
IMG_0062.PNG
前言:
我们app是做信息的,不想一个账户在多台设备登录,于是便开发了踢下线的功能
废话不说,直接后入式
该功能的实现主要逻辑是用户登录时间,获取该设备的一个设备号,传给后台服务器,调用后台一个接口,该接口会保存该设备的设备号,登录时间,然后利用一个长连接,发送给该用户上次登录的设备,该设备收到消息,进行下线,清除用户登录的状态,刷新界面(该长连接我们是使用融云发送的消息) ,当我们收到消息时间,去清除用户登录的状态,进行下线处理,弹框提示用户等操作
用户使用app多样,情况也很多,下面我根据不同情况进行分析
- A 用户启动程序
此时我们要把长连接建立起来,因为我们用的是融云,所以我门就要连接融云服务器(具体参照融云开发文档:http://www.rongcloud.cn/docs/ios_imlib.html) 融云服务器连接成功后,会时刻监听消息
if ([message.content isMemberOfClass:[RCTextMessage class]]) {
RCTextMessage *testMessage = (RCTextMessage *)message.content;
NSLog(@"消息内容:%@", testMessage.content);
NSLog(@"%lld",message.sentTime);
NSLog(@"%@",message.targetId);
NSLog(@"%lld",message.receivedTime);
__block NSDictionary * userInfo = @{@"content":
[NSString stringWithFormat:@"%@", testMessage.content],
@"sentTime" : [NSString stringWithFormat:@"%lld",message.sentTime],
@"targetId":[NSString stringWithFormat:@"%@",message.targetId],
@"receivedTime" : [NSString stringWithFormat:@"%lld",message.receivedTime]
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.5 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
if ([JYDUserData share].isLogined) {
NSDictionary * param = @{//@"channelId":[JYDUserData share].channelId,
@"userId":[JYDUserData share].userId,
@"devno":[JYDUserData share].UUIDString
};
[HttpManager postWithMethodString:@"" parameter:param OldSign:@"api.html" callBackBlock:^(id responseObject)
{
// NSLog(@"退出登录%@",responseObject);
[self ForcedReturn_Mothed:userInfo];
[[JYDUserData share] saveUserInfoWithUserName:nil Password:nil UserId:nil Token:nil Mobile:nil IsLogin:NO];
// [self unBind];
[[NSNotificationCenter defaultCenter] postNotificationName:@"USERINFO"object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:USER_NOTION_EXIT object:nil];
}];
}
});
}
NSLog(@"还剩余的未接收的消息数:%d", nLeft);
}
- 2使用融云有弊端性,因为,他们的服务器一旦崩溃什么的,我们收不到消息,用户就无法踢下线,所以我们要引入一套自检机智,让服务器返回最新的一台设备的设备号,我们调用他们的接口,判断如果最近的一台设备和本设备相同,就把自己踢下线
-(void)programInto
{
//获取用户登录的状态
if (![JYDTools getUserIsLogin]) {
return;
}
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//本台设备channelid
NSString *uuid= [JYDUserData share].UUIDString;
//上次登录的设备的channelid
NSArray *prev_UUIDArr=[self getServerSaveUUID];
NSString *prev_uuid=@"";
if (prev_UUIDArr.count > 0) {
prev_uuid=[prev_UUIDArr objectAtIndex:0];
}
if (![prev_uuid isEqualToString:uuid]&& prev_UUIDArr != nil)
{
//强踢下线
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.5 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
if ([JYDTools getUserIsLogin]) {
NSDictionary * param = @{
@"userId":[JYDUserData share].userId,
@"devno":[JYDUserData share].UUIDString
};
[HttpManager postWithMethodString:@"" parameter:param OldSign:@"api.html" callBackBlock:^(id responseObject)
{
//if (![[JYDUserData share].userId isEqualToString:@""])
{
NSDictionary * userInfo = @{@"content":
[NSString stringWithFormat:@"强制下线" ],
@"targetId":[NSString stringWithFormat:@"%@",prev_uuid],
};
[self ForcedReturn_Mothed:userInfo];
[[JYDUserData share] saveUserInfoWithUserName:nil Password:nil UserId:nil Token:nil Mobile:nil IsLogin:NO];
[self unBind];
[[NSNotificationCenter defaultCenter] postNotificationName:@"USERINFO"object:nil];
}
}];
}
});
}
});
}
- B 用户登录,我们就利用融云发送消息,把登录过的设备但不包含自己的设备,发送消息,其他设备一旦收到消息,就会清除用户登录的状态
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//获取服务器保存的上次设备的channelid
NSArray *prev_UUID=[self getServerSaveUUID];
[JYDCommon savePushuserToSetting];
//刷新后台channelid为现在设备的
//获取本设备的channelid
NSString *UUID=[JYDUserData share].UUIDString;
//获取融云发送消息
[self SendMessage_RCIM:nil from_UUID:UUID to_UUID:prev_UUID];
});
}
}
//from_UUID本台设备的设备号 to_UUID获取服务器返回的该帐号登录过的设备号
-(void)SendMessage_RCIM:(NSString *)content from_UUID:(NSString *) from_UUID to_UUID:(NSArray *) to_UUID
{
//如果没有请求到服务器保存的设备号,说明是新用户,不发消息
if (from_UUID==nil || from_UUID.length<1) {
return;
}
//自定义消息的类型
if (content==nil || content.length<1) {
content = @"强制下线";
}
//融云的消息类
RCTextMessage * testMeassage = [RCTextMessage messageWithContent:content];
//循环该帐号登录过的设备的list
for (int i=0; i<to_UUID.count; i++)
{
//获取第i个该帐号登录设备的设备号
NSString *uuid=[to_UUID objectAtIndex:i];
//如果服务器保存的设备号和本台设备的设备号相同,就继续下次循环,说明该帐号又回到同一台设备登录,不能把自己踢下线,不满足,就把之前登录过的所有的设备都踢下线
if([uuid isEqualToString:from_UUID])
{
continue;
}
//发送消息
[[RCIMClient sharedRCIMClient] sendMessage:ConversationType_PRIVATE
targetId:uuid
content:testMeassage
pushContent:nil
pushData:nil
success:^(long messageId) {
NSLog(@"发送成功。当前消息ID:%ld", messageId);
} error:^(RCErrorCode nErrorCode, long messageId) {
NSLog(@"发送失败。消息ID:%ld, 错误码:%ld", messageId, (long)nErrorCode);
}];
}
}