iOS IM SDK客户端开发文档

消息

消息:IM 交互实体,在 SDK 中对应的类型是 TDMessage。TDMessage 由 TDMessageBody 组成。

// 消息构建部分
#param mark - 消息基类
TDMessage.h
TDMessageBody.h

#param mark - 1V1消息类
TDTextMessageBody.h
TDImageMessageBody.h
TDVoiceMessageBody.h
TDVideoMessageBody.h
TDFileMessageBody.h
TDLocationMessageBody.h

#param mark - 群消息类
TDCreateGroupMessageBody.h
TDGroupAddMessageBody.h
TDGroupRemoveUidsMessageBody.h
TDDeleteGroupMessageBody.h
TDQuitGroupMessageBody.h
TDReplaceOwnerIdMessageBody.h
TDGroupSucessMessageBody.h

#param mark - 特殊消息类
TDCmdMessageBody.h
TDKeyBoardSoundMessageBody.h
TDConferenceMessageBody.h

/** 消息方法调用部分,比如添加代理,移除代理,发送消息等,
同时也包含会话相关的操作,比如创建或获取会话,获取会话列表等*/
TDChatManager.h
// 消息的协议部分,比如监听接收消息的回调方法等
ChatManagerDelegate

构造消息

以下构造消息的示例中,使用到的“初始化消息实例”方法的说明:

/// 初始化消息实例
/// @param body 消息体实例
/// @param fromUid 发送方Uid
/// @param toUid 接收方Uid
/// @param chatType 聊天类型 单聊/群聊
- (id) initMessageWithBody:(TDMessageBody *)body 
                           fromUid:(NSString *)fromUid 
                           toUid:(NSString *)toUid 
                           ChatType:(TDChatType)chatType; 

注意: 如果是给群组发消息,那么toUid为群组id

构造文字消息

/// 初始化文本消息体
/// @param aText 文本内容
- (instancetype)initWithText:(NSString *)aText;

// 调用:
TDTextMessageBody *body = [[TDTextMessageBody alloc] initWithText:@"要发送的消息"];
// 获取当前登录的环信id
NSString *from = [[TDWLClient sharedClient] currentUserId];

//生成Message
TDMessage *message = [[TDMessage alloc] initMessageWithBody:body fromUid:from toUid:@"接收者Uid" ChatType:chatType];
// chatType = SingleChat; // 单聊消息
// chatType = GroupChat;// 群聊消息

构造图片消息

/// 初始化文件消息体
/// @param aData 文件data数据
/// @param aDisplayName 文件名
- (instancetype)initWithData:(NSData *)aData
                  displayName:(NSString *)aDisplayName;
                 
// 调用:               
TDImageMessageBody *body = [[TDImageMessageBody alloc] initWithData:aImageData displayName:@"image"];

NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
TDMessage *message = [[TDMessage alloc] initMessageWithBody:body fromUid:from toUid:@"接收者Uid" ChatType:chatType];
// chatType = SingleChat; // 单聊消息
// chatType = GroupChat;// 群聊消息

构造位置消息

/// 实例化位置消息体
/// @param aLatitude 纬度
/// @param aLongitude 经度
/// @param aAddress 地理位置信息
- (instancetype)initWithLatitude:(double)aLatitude longitude:(double)aLongitude address:(NSString *)aAddress;

//调用:
TDLocationMessageBody *body = [[TDLocationMessageBody alloc] initWithLatitude:39 longitude:116 address:@"地址"]; 

NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
TDMessage *message = [[TDMessage alloc] initMessageWithBody:body fromUid:from toUid:@"接收者Uid" ChatType:chatType];
// chatType = SingleChat; // 单聊消息
// chatType = GroupChat;// 群聊消息

构造语音消息

/// 初始化文件消息体
/// @param aLocalPath 本地文件路径
/// @param aDisplayName 文件名
- (instancetype)initWithLocalPath:(NSString *)aLocalPath
                       displayName:(NSString *)aDisplayName;

// 调用:
TDVoiceMessageBody *body = [[TDVoiceMessageBody alloc] initWithLocalPath:aPath displayName:@"audio"];
body.duration = duration;

NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
TDMessage *message = [[TDMessage alloc] initMessageWithBody:body fromUid:from toUid:@"接收者Uid" ChatType:chatType];
// chatType = SingleChat; // 单聊消息
// chatType = GroupChat;// 群聊消息

构造视频消息

/// 初始化文件消息体
/// @param aLocalPath 本地文件路径
/// @param aDisplayName 文件名
- (instancetype)initWithLocalPath:(NSString *)aLocalPath
                       displayName:(NSString *)aDisplayName;

// 调用:
TDVideoMessageBody *body = [[TDVideoMessageBody alloc] initWithLocalPath:[aUrl path] displayName:@"video.mp4"];

NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
TDMessage *message = [[TDMessage alloc] initMessageWithBody:body fromUid:from toUid:@"接收者Uid" ChatType:chatType];
// chatType = SingleChat; // 单聊消息
// chatType = GroupChat;// 群聊消息

构造文件消息

/// 初始化文件消息体
/// @param aLocalPath 本地文件路径
/// @param aDisplayName 文件名
- (instancetype)initWithLocalPath:(NSString *)aLocalPath
                       displayName:(NSString *)aDisplayName;

// 调用:       
TDFileMessageBody *body = [[TDFileMessageBody alloc] initWithLocalPath:[aUrl path] displayName:@"file"];

NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
TDMessage *message = [[TDMessage alloc] initMessageWithBody:body fromUid:from toUid:@"接收者Uid" ChatType:chatType];
// chatType = SingleChat; // 单聊消息
// chatType = GroupChat;// 群聊消息

构造透传消息

SDK 提供的一种特殊类型的消息,即 CMD,不会存 db,也不会走 APNS 推送,类似一种指令型的消息。比如您的服务器要通知客户端做某些操作,您可以服务器和客户端提前约定好某个字段,当客户端收到约定好的字段时,执行某种特殊操作。

/// 初始化透传消息
/// @param aText 透传消息text 用户自定义
- (instancetype)initWithCmdText:(NSString *)aText;

// 调用:
TDCmdMessageBody *body = [[TDCmdMessageBody alloc] initWithCmdText:aCMDText];

NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
TDMessage *message = [[TDMessage alloc] initMessageWithBody:body fromUid:from toUid:@"接收者Uid" ChatType:chatType];
// chatType = SingleChat; // 单聊消息
// chatType = GroupChat;// 群聊消息

会话

// 主要用到的类
// 会话方法调用部分,包含创建或获取会话,获取会话列表等
TDChatManager.h

/**
获取所有会话
@param completion 完成的回调 返回会话数组
 数组中存的为TDSessionModel *类型
*/
- (void) getAllConversations:(LoadAllConversationComplection)completion;

// 调用:
[[TDWLClient sharedClient].chatManager getAllConversations:^(NSArray * _Nonnull contacts, NSError * _Nullable error) {
    if (error) {
        NSLog(@"get AllConversations error = %@",error);
        return;
    }

    // 这里根据你的需要去拿到contacts,进行业务操作
    .......
}];
/**
 删除一个会话
 @param sessionId  会话id  是NSString类型
 */
- (BOOL) deleteConversationWithSessionId:(NSString *)sessionId;

// 调用:
BOOL deleteResult = [[TDWLClient sharedClient].chatManager deleteConversationWithSessionId:@"要删除的会话id"];

if (deleteResult) {
        // 这里已经删除成功,根据开发业务需求去刷新列表或者做其他操作
}
/**
 更新会话内部消息全部已读
 @param sessionId 会话id  NSString类型
 */
- (BOOL) updateRecentSessionReadAllWithSessionId:(NSString *)sessionId;

// 调用:
[[TDWLClient sharedClient].chatManager updateRecentSessionReadAllWithSessionId:@"会话的id"];

聊天

登录成功之后才能进行聊天操作。发消息时,单聊和群聊调用的是统一接口,区别是 chatType不同。

发送消息

/**
 发送消息
 @param message  TDMessage类型
 */
- (void) sendMessage:(TDMessage *)message Completion:(void(^)(BOOL sendSuccess, NSError * _Nullable error))completion;

// 调用:
[[TDWLClient sharedClient].chatManager sendMessage:message Completion:^(BOOL sendSuccess, NSError * _Nullable error) {
        if (error) {
            // 失败
        }else {
            // 成功
        }
}];

接收消息

建议在自己工程的根控制器中注册消息代理,监听接收普通消息的回调方法,用于不在聊天页面时接收消息。

协议 ChatManagerDelegate

代理:
// 设置代理
[TDWLClient sharedClient].chatManager.chatDelegate = self;

// 移除代理
[TDWLClient sharedClient].chatManager.chatDelegate = nil;

接收普通消息会走以下回调:

/// 用于接收消息 传出delegate数据 传出数据为NSArray*类型 数据为TDMessage*类型
- (void) messagesDidReceive:(NSArray *)aMessageArray;

接收透传(cmd)消息会走以下回调:

/// 用于接收CMD消息 传出delegate数据 传出数据为NSArray *类型
- (void) CMDMessageDidReceive:(NSArray *)cmdArray;

接收按键音(KeyBorad)消息会走以下回调:

/// 用于接收按键音消息 传出delegate数据  传出数据为NSArray *类型
- (void) KeyBoradMessageDidReceive:(NSArray *)KeyBoradArray;

接收创建群(CreateGroup)的通知会走以下回调:
ps:此时为收到建群通知,还没加入群聊

/// 用于接收创建群的通知 传出delegate数据 传出数据为NSArray *类型
- (void) CreateGroupMessageDidReceive:(NSArray *)CreateGroupArray;

接收解散群的通知 会走以下回调:

/// 用于接收解散群的通知  传出delegate数据 传出数据为NSArray *类型
- (void) DeleteGroupMessageDidReceive:(NSArray *)DeleteGroupArray;

收到消息解析示例:

#pragma mark -----ChatManagerDelegate,CMDMessageDelegate,KeyBoradMessageDelegate,GroupNoticeDelegate-----
// 收到普通消息 看情况做处理
- (void) messagesDidReceive:(NSArray *)aMessageArray {

    NSLog(@"收到普通消息");

    __weak typeof(self) weakself = self;
    dispatch_async(self.msgQueue, ^{
          
        NSMutableArray *receveArray = [[NSMutableArray alloc] init];
        for (int i = 0; i < aMessageArray.count; i++) {
            TDMessage *message = aMessageArray[i];
            if (message.chatType == GroupChat) {
                if ([message.to_uid isEqualToString:self.aSessionModel.sessionId]) {
                    [receveArray addObject:message];
                }
            }else {
                if ([message.from_uid isEqualToString:self.aSessionModel.sessionId]) {
                    [receveArray addObject:message];
                }
            }
        }
        
        NSArray *formated = [weakself _formatMessages:receveArray];
        [weakself.dataArray addObjectsFromArray:formated];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            [weakself.tableView reloadData];
            [weakself _scrollToBottomRow];
        });
    });
}
- (void) CMDMessageDidReceive:(NSArray *)cmdArray {
    NSLog(@"收到了CMD消息:%@",cmdArray);
    //根据业务需求进行解析,做后续操作
    ......
}
- (void) KeyBoradMessageDidReceive:(NSArray *)KeyBoradArray {
    NSLog(@"收到了按键音消息:%@",KeyBoradArray);
    //根据业务需求进行解析,做后续操作
    ......
}
- (void) CreateGroupMessageDidReceive:(NSArray *)CreateGroupArray {
    NSLog(@"收到了建群通知:%@",CreateGroupArray);
    //根据业务需求进行解析,做后续操作
    ......
}
- (void) DeleteGroupMessageDidReceive:(NSArray *)DeleteGroupArray {
    NSLog(@"收到了删除群的通知");
    //根据业务需求进行解析,做后续操作
    ......
}

下载消息中的附件

/**
 * 文件下载方法
 * @param downloadURL 文件链接
 * @param progress 进度
 * @param completion 完成的回调
 */
- (void)downloadFileWithURL:(NSString *) downloadURL progress:(void (^)(NSProgress *downloadProgress))progress Completion:(void(^)(NSString *_Nullable filePath, NSError * _Nullable error))completion;

/// 判断文件是否已经在沙盒中存在
/// @param fileName 文件名
-(BOOL) isFileExist:(NSString *)fileName;

/// 获取文件沙盒路径
/// @param fileName 文件名
- (NSString *) getFileCachesPathWith:(NSString *)fileName;

示例:下载图片消息中的原图:

// 点击图片下载原图
- (void) _imageMessageCellDidSelected:(TDMessageCell *)aCell {
    
    __weak typeof(self) weakself = self;
    
    TDImageMessageBody *body = (TDImageMessageBody*)aCell.model.emModel.body;
    
    // 判断原图是否存在
    BOOL isFileExist = [[TDWLClient sharedClient].chatManager isFileExist:body.imgUrl];
    if (isFileExist) {
        // 获取原图路径
        NSString *imgPath = [[TDWLClient sharedClient].chatManager getFileCachesPathWith:body.imgUrl];
        NSLog(@"imgUrl:%@",body.imgUrl);
        NSLog(@"imgPath:%@",imgPath);
        UIImage *image = [UIImage imageWithContentsOfFile:imgPath];
        if (image) {
            [[TDImageBrowser sharedBrowser] showImages:@[image] fromController:self];
        } else {
            [TDAlertController showErrorAlert:@"获取原图失败T_T"];
        }
    }else {
        // 下载原图
        [self showHudInView:self.view hint:@"下载原图..."];
        [[TDWLClient sharedClient].chatManager downloadFileWithURL:body.imgUrl progress:^(NSProgress * _Nonnull downloadProgress) {
            NSLog(@"进度:%@",downloadProgress);
        } Completion:^(NSString * _Nullable filePath, NSError * _Nullable error) {
            [weakself hideHud];
            if (error) {
                [TDAlertController showErrorAlert:@"下载原图失败T_T"];
            } else {
                NSString *localPath = [[[NSString stringWithFormat:@"%@",filePath] componentsSeparatedByString:@"://"] lastObject];
                UIImage *image = [UIImage imageWithContentsOfFile:localPath];
                if (image) {
                    [[TDImageBrowser sharedBrowser] showImages:@[image] fromController:self];
                } else {
                    [TDAlertController showErrorAlert:@"下载原图失败T_T"];
                }
            }
        }];
    }
}

好友管理

注:通达IM不是好友也可以聊天,不推荐使用通达IM的好友机制。如果你有自己的服务器或好友关系,请自己维护好友关系。

好友管理涉及到的SDK头文件如下:

TDWLUserManager.h

好友管理提供的方法如下:

/**
 添加一个好友
 @param uid 用户uid  NSSting *类型
 */
- (BOOL) addFriendWithUid:(NSString *)uid;

/**
 删除一个好友
 @param uid 用户uid  NSSting *类型
 */
- (BOOL) deleteFriendWithUid:(NSString *)uid;

/**
 获取所有好友列表
 @param completion 完成后的回调
 */
- (void) getAllFriend:(LoadAllFriendCompletion)completion;

/**
 获取所有在黑名单里面的好友
 @param completion 完成后的回调
 */
- (void)getAllBlackListUser:(LoadAllFriendCompletion)completion;

/**
 拉黑某个用户
 @param uid 用户uid
 */
- (BOOL)blackUserWithUid:(NSString *)uid;

/**
 将某个用户从黑名单释放
 @param uid 用户uid
 */
- (BOOL)unBlackUserWithUid:(NSString *)uid;

/**
 判断某个用户是否在黑名单
 @param uid uid 用户uid
 */
- (BOOL)isUserInBlackListWithUid:(NSString *)uid;

注:以上方法调用全部用[TDWLClient sharedClient].contactManager调用
添加好友调用示例:

BOOL addFriendSuccess = [[TDWLClient sharedClient].contactManager addFriendWithUid:@"对方Uid"];

if (addFriendSuccess) {
    // 添加好友成功
}else {
    // 添加好友失败
}

群组管理

群涉及的方法如下:

/**
 建群
 @param uidsArr  uidsArr中为想要添加的群成员uid  注: uidsArr.count >= 2  否则建群失败;
 @param name 群名 NSString *类型
 @param completion 完成的回调
 */
- (void) createGroup:(NSArray *)uidsArr andGroupName:(NSString *)name complet:(void(^)(BOOL isSuccess,NSError *_Nullable error))completion;


/**
 添加群成员
 @param gid 被添加用户的群id;
 @param uids NSArray类型  添加的用户列表
 @param completion 完成的回调
 */
- (void) addGroupMembersWithGId:(NSString *)gid andUidsArray:(NSArray *)uids complet:(void(^)(BOOL isSuccess,NSError *_Nullable error))completion;


/**
 删除群成员
 @param gid 被删除用户的群id;
 @param uids NSArray类型 删除的用户列表。
 返回类型  BOOL
 */
- (void) removeGroupMembersWithGid:(NSString *)gid andUidsArray:(NSArray *)uids complet:(void(^)(BOOL isSuccess,NSError *_Nullable error))completion;


/**
 销毁群
 @param gid 被销毁的群id。
 返回类型  BOOL
 */
- (void) destoryGroup:(NSString *)gid complet:(void(^)(BOOL isSuccess,NSError *_Nullable error))completion;

/**
 退群
 @param gid 群id  NSString类型
 */
- (void) quitGroup:(NSString *)gid complet:(void(^)(BOOL isSuccess,NSError *_Nullable error))completion;

/**
 更换群主
 @param gid 群id NSString类型
 */
- (void) changeGroupOwnerWithGroup:(NSString *)gid targetOwnerId:(NSString *)targetOwnerId complet:(void(^)(BOOL isSuccess,NSError *_Nullable error))completion;


/**
 修改群昵称(本地数据库修改,服务器暂无此功能)
 @param gid 群id NSString类型
 @param newName 新群名 NSString类型
 */
- (BOOL) changeGroupNameWithGroupId:(NSString *)gid newName:(NSString *)newName;


/// 根据群ID查询某条群组的信息
/// @param groupId 群Id NSString类型
- (NSDictionary * _Nullable) getGroupInfoWithGroupId:(NSString *)groupId;

注: 群操作中、建群/添加群成员/删除群成员/解散群/退群/更换群主 这几种功能,将会以普通消息的形式插入在聊天消息中。可根据需求选择是否显示此类消息。

音视频通话

适用场景

1对1通话API用于实现1对1语音通话和1对1视频通话,典型场景包括社交交友,远程心理咨询、远程医疗、一对一在线教育、远程视频辅助等。
其API设计思想类似于传统的电话通话,呼叫过程使用了即时通讯的消息机制,所以和即时通讯功能是紧耦合的。

发起实时通话

用户可以调用发起语音或者视频API向在线用户发起实时通话。

主要用到的类:

ITDWLCallManager.h

需要用到的代理方法,建议在开启SDK时,同时添加回调代理

/*!
 *  \~chinese
 *  添加回调代理
 *
 *  @param aDelegate  要添加的代理
 */
- (void)addDelegate:(id<TDWLCallManagerDelegate>)aDelegate;

/*!
 *  \~chinese
 *  移除回调代理
 *
 *  @param aDelegate  要移除的代理
 */
- (void)removeDelegate:(id<TDWLCallManagerDelegate>)aDelegate;

主要方法

/*!
 *  \~chinese
 *  发起实时会话
 *
 *  @param aType                     通话类型
 *  @param aRemoteName      被呼叫用户的IM账号(不能与自己通话)
 *  @param aCompletionBlock 完成的回调
 *
 */
- (void)startCall:(TDWLCallType)aType
       remoteName:(NSString *)aRemoteName
       completion:(void (^)(TDWLCallSession * _Nullable aCallSession,TDWLError * _Nullable error))aCompletionBlock;

注意: TDWLCallType 为枚举类型
TDWLCallTypeAudio = 0,    /*! \~chinese 实时语音 \~english Voice call */
TDWLCallTypeVideo,        /*! \~chinese 实时视频 \~english Video call */

/*!
 *  \~chinese
 *  接收方同意通话请求
 *
 *  @param  aCallId     通话ID
 *
 *  @result 错误信息
 */
- (TDWLError *)answerIncomingCall:(NSString *)aCallId;

/*!
 *  \~chinese
 *  结束通话
 *
 *  @param aCallSession  aCallSession   通话对象
 *  @param aReason       结束原因
 *
 *  @result 错误
 */
- (TDWLError *)endCall:(TDWLCallSession *)aCallSession
                reason:(TDWLCallEndReason)aReason;

扩展

/*!
 *  \~chinese
 *  切换前后摄像头
 *
 */
- (void)updateSipCallWithSwitchCamera;

/*!
 *  \~chinese
 *  设置是否静音
 *
 */
- (void)updateSipCallIsMute:(BOOL)aIsMute;

/*!
 *  \~chinese
 *  设置视频是否可用
 *
 */
- (void)updateSipCallIsEnableVideo:(BOOL)aEnableVideo;

示例:

[[TDWLClient sharedClient].callManager startCall:aType
                                          remoteName:aUsername
                                          completion:^(TDWLCallSession * _Nullable aCallSession, TDWLError * _Nullable error) {
        if (error == nil) {
            // 成功,根据业务需求进行后续处理
        } else {
            // 失败,根据业务需求进行后续处理
        }
}];

外网呼叫

外网呼叫API用于打外网电话使用,场景包括客服、销售等
其API设计思想类似于传统的电话通话。

主要用到的类:

ITDWLSipCallManager.h

需要用到的代理方法,建议在开启SDK时,同时添加回调代理

/*!
 *  \~chinese
 *  添加回调代理
 *
 *  @param aDelegate  要添加的代理
 */
- (void)addDelegate:(id<TDWLSipChannelDelegate>)aDelegate;

/*!
 *  \~chinese
 *  移除回调代理
 *
 *  @param aDelegate  要移除的代理
 */
- (void)removeDelegate:(id<TDWLSipChannelDelegate>)aDelegate;

主要方法:

/*!
 *  \~chinese
 *  发起SIP实时音频会话
 *
 *  @param sipNumber        被呼叫用户的Sip账号 可以是手机号
 *  @param remoteName       被呼叫用户的昵称
 *  @param aCompletionBlock  完成的回调
 *
 */
- (void)startAudioCallWithSipNumber:(NSString *)sipNumber
                          remoteName:(NSString * _Nullable)remoteName
                          completion:(void (^_Nonnull)(TDWLError * _Nullable error))aCompletionBlock;


/*!
 *  \~chinese
 *  设置是否静音
 *
 */
- (void)updateSipCallIsMute:(BOOL)aIsMute;

示例:

[[TDWLClient sharedClient].sipManager startAudioCallWithSipNumber:@"手机号或者对方sip号" remoteName:aUsername
                                                               completion:^(TDWLError * _Nullable error) {
        if (error == nil) {
            // 成功
        } else {
            // 失败
        }
}];

更新于:2020.07.11
by 张宗琦

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

推荐阅读更多精彩内容