集成网易云信实现自定义消息(类似淘宝聊天发送商品信息)
上篇文章,我们整理了网易云信的快速集成过程.有兴趣的小伙伴可以移步到:ios集成网易云信IM功能遇到的坑 .简单的实现一对一聊天界面或者查看最近联系人列表.我们只需直接调用NIMKit里面的NIMSessionViewController 和 NIMSessionListViewController这两个类方法.就能实现功能.但是简单的聊天可能满足不了我们项目需要.比如要实现电商平台中,我们浏览商品.突然觉得商品还不错.去找客服聊天.那么这时候我们希望把浏览的商品也给推送过去.好让客服知道我们在看什么.并且,自定义消息设置成可点击的,方便可以点击查看商品详情.
今天我就给大家整理下怎么实现自定义消息发送.
其实具体也可以参考官方demo中实现发送大表情效果过程.毕竟大表情图片其实也是一种自定义消息发送的表现形式.
那么,发送自定义消息,我大概整理了下,觉得可以分为四部分,这样实现起来逻辑会觉得比较清晰.如下:
1.实现自定义消息model类.承接数据部分.
2.实现自定义消息view 类,承接自定义UI部分.
3.实现自定义布局配置类.
4.消息解析器(解析消息,辨别消息类型!)
最后一步,就是在入口类中注册拉起解析器和自定义布局.这样,系统才能识别消息类型,并实现自定义布局.
那!第一步,我们实现自定义消息model类,承接数据部分.
创建一个类,继承与NSObject.并实现NIMKit <NIMCustomAttachment,NTESCustomAttachmentInfo>两个协议方法.
.h类中:
#import <Foundation/Foundation.h>
#import "NIMKit.h"
#import "NTESCustomAttachmentDefines.h"
@interface NTESSendShopGoodsAttachment :NSObject<NIMCustomAttachment,NTESCustomAttachmentInfo>
//添加自定义消息元素
@property(nonatomic,copy)NSString*headerImage;
@property(nonatomic,copy)NSString*nameLabel;
@property(nonatomic,copy)NSString*priceLabel;
//数据源承接类
@property(nonatomic,strong)NSDictionary*messageDic;
@end
.m类中:
#import "NTESSendShopGoodsAttachment.h"
@implementation NTESSendShopGoodsAttachment
//对数据源进行类型分配.
- (NSString *)encodeAttachment
{
NSDictionary *dictContent =@{CM_GOODS_IMG:self.headerImage,CM_GOODS_NAME:self.nameLabel,CM_GOODS_PRICE:self.priceLabel};
NSDictionary *dict =@{CMType :@(CustomMessageSendShopGoods),
CMData :dictContent};
NSData *data = [NSJSONSerializationdataWithJSONObject:dict
options:0
error:nil];
NSString *content =nil;
if (data) {
content = [[NSStringalloc] initWithData:data
encoding:NSUTF8StringEncoding];
}
return content;
}
//实例化元素(懒加载...)
-(NSString *)headerImage{
if (!_headerImage) {
_headerImage =nil;
}
return_headerImage;
}
-(NSString *)nameLabel{
if (!_nameLabel) {
_nameLabel =nil;
}
return_nameLabel;
}
-(NSString *)priceLabel
{
if (!_priceLabel) {
_priceLabel =nil;
}
return_priceLabel;
}
//数据源setter方法实现
-(void)setMessageDic:(NSDictionary *)messageDic
{
_messageDic =messageDic;
//给元素赋值
self.headerImage =[_messageDic[@"picture"]substringFromIndex:3];
self.nameLabel =_messageDic[@"name"];
self.priceLabel =_messageDic[@"price"];
}
//设置自定义消息Bounds
- (CGSize)contentSize:(NIMMessage *)message cellWidth:(CGFloat)width{
returnCGSizeMake(200,70);
}
- (UIEdgeInsets)contentViewInsets:(NIMMessage *)message
{
if (message.session.sessionType == NIMSessionTypeChatroom)
{
CGFloat bubbleMarginTopForImage =15.f;
CGFloat bubbleMarginLeftForImage =12.f;
return UIEdgeInsetsMake(bubbleMarginTopForImage,bubbleMarginLeftForImage,0,0);
}
else
{
CGFloat bubbleMarginForImage =3.f;
CGFloat bubbleArrowWidthForImage =5.f;
if (message.isOutgoingMsg) {
return UIEdgeInsetsMake(bubbleMarginForImage,bubbleMarginForImage,bubbleMarginForImage,bubbleMarginForImage + bubbleArrowWidthForImage);
}else{
return UIEdgeInsetsMake(bubbleMarginForImage,bubbleMarginForImage + bubbleArrowWidthForImage, bubbleMarginForImage,bubbleMarginForImage);
}
}
}
//指向自定义view类
- (NSString *)cellContent:(NIMMessage *)message{
return@"NTESSessionSendShopGoodsContentView";
}
#import "NIMSessionMessageContentView.h"
//用于点击事件触发标识符!!!
extern NSString *const SendCustomWithGoodsClick;
@interface NTESSessionSendShopGoodsContentView :NIMSessionMessageContentView
//自定义展示商品信息控件
@property(nonatomic,strong)UIImageView *headerImg;
@property(nonatomic,strong)UILabel*nameLa;
@property(nonatomic,strong)UILabel*priceLa;
@end
#import "NTESSessionSendShopGoodsContentView.h"
#import "NTESSendShopGoodsAttachment.h"
#import "UIView+SL.h"
#import "UIImage+Image.h"
NSString *const SendCustomWithGoodsClick =@"SendCustomWithGoodsClick";
@interface NTESSessionSendShopGoodsContentView()
//添加手势
@property (nonatomic,strong)UITapGestureRecognizer*top;
@end
@implementation NTESSessionSendShopGoodsContentView
- (instancetype)initSessionMessageContentView{
self = [superinitSessionMessageContentView];
if (self) {
self.opaque =YES;
//点击自定义消息cell,添加手势
self.top = [[UITapGestureRecognizeralloc] initWithTarget:selfaction:@selector(tapGesture:)];
[selfaddGestureRecognizer:self.top];
self.headerImg =[[UIImageViewalloc]initWithFrame:CGRectZero];
[selfaddSubview:self.headerImg];
self.nameLa =[[UILabel alloc]initWithFrame:CGRectZero];
_nameLa.font =[UIFontsystemFontOfSize:13];
_nameLa.numberOfLines =0;
[selfaddSubview:self.nameLa];
self.priceLa =[[UILabelalloc]initWithFrame:CGRectZero];
_priceLa.font =[UIFontsystemFontOfSize:12];
_priceLa.textColor =[UIColororangeColor];
[selfaddSubview:self.priceLa];
}
returnself;
}
#pragma mark - 点击手势
- (void)tapGesture:(UITapGestureRecognizer *)recognizer {
if ([self.delegaterespondsToSelector:@selector(onCatchEvent:)]) {
NIMKitEvent *event = [[NIMKitEventalloc] init];
//添加自定义消息标识符
event.eventName =SendCustomWithGoodsClick;
event.messageModel =self.model;
event.data =self;
[self.delegateonCatchEvent:event];
}
}
//赋值
- (void)refresh:(NIMMessageModel *)data{
[superrefresh:data];
NIMCustomObject *customObject = (NIMCustomObject*)data.message.messageObject;
id attachment = customObject.attachment;
if ([attachmentisKindOfClass:[NTESSendShopGoodsAttachmentclass]]) {
self.nameLa.text =[attachmentnameLabel ];
IMAGE_URL(self.headerImg,[attachment headerImage],@"header.jpg");
self.priceLa.text =[attachmentpriceLabel];
}
}
//自定义view元素控件坐标设置
- (UIImage *)chatBubbleImageForState:(UIControlState)state outgoing:(BOOL)outgoing{
self.headerImg.frame =CGRectMake(7,8,54,54);
self.nameLa.frame =CGRectMake(70,5,125,40);
self.priceLa.frame =CGRectMake(70,50,70,15);
//背景颜色
return [UIImageimageWithColor:[UIColorwhiteColor]];
}
@end
#import "NIMCellLayoutConfig.h"
#import "NIMKit.h"
@interface NTESCellLayoutConfig :NIMCellLayoutConfig<NIMCellLayoutConfig>
@end
#import "NTESCellLayoutConfig.h"
#import "NTESSessionCustomContentConfig.h"
@interface NTESCellLayoutConfig ()
@property (nonatomic,strong) NSArray *types;
@property (nonatomic,strong) NTESSessionCustomContentConfig *sessionCustomconfig;
@end
.m文件:
@implementation NTESCellLayoutConfig
- (instancetype)init
{
if (self = [superinit])
{
//添加消息类型!我们写在了第一个
_types = @[
@"NTESSendShopGoodsAttachment",
@"NTESSnapchatAttachment",
@"NTESChartletAttachment",
@"NTESWhiteboardAttachment"
];
_sessionCustomconfig = [[NTESSessionCustomContentConfigalloc] init];
}
returnself;
}
#pragma mark - NIMCellLayoutConfig
- (CGSize)contentSize:(NIMMessageModel *)model cellWidth:(CGFloat)width{
NIMMessage *message = model.message;
//检查是不是当前支持的自定义消息类型
if ([selfisSupportedCustomMessage:message]) {
return [_sessionCustomconfigcontentSize:width message:message];
}
//检查是不是聊天室文本消息
if ([selfisChatroomTextMessage:message]) {
// return [_chatroomTextConfig contentSize:width message:message];
}
//如果没有特殊需求,就走默认处理流程
return [supercontentSize:model
cellWidth:width];
}
- (NSString *)cellContent:(NIMMessageModel *)model{
NIMMessage *message = model.message;
//检查是不是当前支持的自定义消息类型
if ([selfisSupportedCustomMessage:message]) {
return [_sessionCustomconfigcellContent:message];
}
//检查是不是聊天室文本消息
if ([selfisChatroomTextMessage:message]) {
// return [_chatroomTextConfig cellContent:message];
}
//如果没有特殊需求,就走默认处理流程
return [supercellContent:model];
}
- (UIEdgeInsets)contentViewInsets:(NIMMessageModel *)model
{
NIMMessage *message = model.message;
//检查是不是当前支持的自定义消息类型
if ([selfisSupportedCustomMessage:message]) {
return [_sessionCustomconfigcontentViewInsets:message];
}
//检查是不是聊天室文本消息
if ([selfisChatroomTextMessage:message]) {
// return [_chatroomTextConfig contentViewInsets:message];
}
//如果没有特殊需求,就走默认处理流程
return [supercontentViewInsets:model];
}
- (UIEdgeInsets)cellInsets:(NIMMessageModel *)model
{
NIMMessage *message = model.message;
//检查是不是聊天室消息
if (message.session.sessionType ==NIMSessionTypeChatroom) {
returnUIEdgeInsetsZero;
}
//如果没有特殊需求,就走默认处理流程
return [supercellInsets:model];
}
- (BOOL)shouldShowAvatar:(NIMMessageModel *)model
{
if ([selfisSupportedChatroomMessage:model.message]) {
returnNO;
}
return [supershouldShowAvatar:model];
}
- (BOOL)shouldShowLeft:(NIMMessageModel *)model{
if ([selfisSupportedChatroomMessage:model.message]) {
returnYES;
}
return [supershouldShowLeft:model];
}
- (BOOL)shouldShowNickName:(NIMMessageModel *)model{
if ([selfisSupportedChatroomMessage:model.message]) {
returnYES;
}
return [supershouldShowNickName:model];
}
- (CGFloat)nickNameMargin:(NIMMessageModel *)model{
if ([selfisSupportedChatroomMessage:model.message]) {
NSDictionary *ext = model.message.remoteExt;
NIMChatroomMemberType type = [ext[@"type"]integerValue];
switch (type) {
caseNIMChatroomMemberTypeManager:
caseNIMChatroomMemberTypeCreator:
return50.f;
default:
break;
}
return15.f;
}
return [supernickNameMargin:model];
}
- (NSArray *)customViews:(NIMMessageModel *)model
{
if ([selfisSupportedChatroomMessage:model.message]) {
NSDictionary *ext = model.message.remoteExt;
NIMChatroomMemberType type = [ext[@"type"]integerValue];
NSString *imageName;
switch (type) {
caseNIMChatroomMemberTypeManager:
imageName = @"chatroom_role_manager";
break;
caseNIMChatroomMemberTypeCreator:
imageName = @"chatroom_role_master";
break;
default:
break;
}
UIImageView *imageView;
if (imageName.length) {
UIImage *image = [UIImageimageNamed:imageName];
imageView = [[UIImageViewalloc] initWithImage:image];
CGFloat leftMargin =15.f;
CGFloat topMatgin =0.f;
CGRect frame = imageView.frame;
frame.origin =CGPointMake(leftMargin, topMatgin);
imageView.frame = frame;
}
return imageView ?@[imageView] :nil;
}
return [supercustomViews:model];
}
#pragma mark - misc
- (BOOL)isSupportedCustomMessage:(NIMMessage *)message
{
NIMCustomObject *object = message.messageObject;
return [objectisKindOfClass:[NIMCustomObjectclass]] &&
[_typesindexOfObject:NSStringFromClass([object.attachmentclass])] != NSNotFound;
}
- (BOOL)isSupportedChatroomMessage:(NIMMessage *)message
{
return message.session.sessionType == NIMSessionTypeChatroom &&
(message.messageType ==NIMMessageTypeText || [selfisSupportedCustomMessage:message]);
}
- (BOOL)isChatroomTextMessage:(NIMMessage *)message
{
return message.session.sessionType == NIMSessionTypeChatroom &&
message.messageObject ==NIMMessageTypeText;
}
#import "NIMBaseSessionContentConfig.h"
@interface NTESSessionCustomContentConfig :NSObject<NIMSessionContentConfig>
@end
.m文件:
#import "NTESSessionCustomContentConfig.h"
#import "NTESCustomAttachmentDefines.h"
@interface NTESSessionCustomContentConfig()
@end
@implementation NTESSessionCustomContentConfig
- (CGSize)contentSize:(CGFloat)cellWidth message:(NIMMessage *)message
{
NIMCustomObject *object = message.messageObject;
NSAssert([object isKindOfClass:[NIMCustomObject class]],@"message must be custom");
id<NTESCustomAttachmentInfo> info = (id<NTESCustomAttachmentInfo>)object.attachment;
return [infocontentSize:message cellWidth:cellWidth];
}
- (NSString *)cellContent:(NIMMessage *)message
{
NIMCustomObject *object = message.messageObject;
NSAssert([object isKindOfClass:[NIMCustomObject class]],@"message must be custom");
id<NTESCustomAttachmentInfo> info = (id<NTESCustomAttachmentInfo>)object.attachment;
return [infocellContent:message];
}
- (UIEdgeInsets)contentViewInsets:(NIMMessage *)message
{
NIMCustomObject *object = message.messageObject;
NSAssert([object isKindOfClass:[NIMCustomObject class]],@"message must be custom");
id<NTESCustomAttachmentInfo> info = (id<NTESCustomAttachmentInfo>)object.attachment;
return [infocontentViewInsets:message];
}
@end
#import <Foundation/Foundation.h>
#import "NIMKit.h"
@interface NTESCustomAttachmentDecoder :NSObject<NIMCustomAttachmentCoding>
@end
#import "NTESCustomAttachmentDecoder.h"
#import "NTESCustomAttachmentDefines.h"
#import "NSDictionary+SLJSON.h"
#import "NTESSendShopGoodsAttachment.h"
#import "NTESChartletAttachment.h"
@implementation NTESCustomAttachmentDecoder
- (id<NIMCustomAttachment>)decodeAttachment:(NSString *)content
{
id<NIMCustomAttachment> attachment =nil;
NSData *data = [contentdataUsingEncoding:NSUTF8StringEncoding];
if (data) {
NSDictionary *dict = [NSJSONSerializationJSONObjectWithData:data
options:0
error:nil];
if ([dictisKindOfClass:[NSDictionaryclass]])
{
NSInteger type = [dictjsonInteger:CMType];
NSDictionary *data = [dictjsonDict:CMData];
switch (type) {
caseCustomMessageTypeChartlet:
{
attachment = [[NTESChartletAttachmentalloc] init];
((NTESChartletAttachment *)attachment).chartletCatalog = [datajsonString:CMCatalog];
((NTESChartletAttachment *)attachment).chartletId = [datajsonString:CMChartlet];
}
break;
caseCustomMessageSendShopGoods:
{
attachment = [[NTESSendShopGoodsAttachmentalloc] init];
((NTESSendShopGoodsAttachment *)attachment).headerImage = [datajsonString:CM_GOODS_IMG];
((NTESSendShopGoodsAttachment *)attachment).nameLabel = [datajsonString:CM_GOODS_NAME];
((NTESSendShopGoodsAttachment *)attachment).priceLabel = [datajsonString:CM_GOODS_PRICE]; }
default:
break;
}
attachment = [selfcheckAttachment:attachment] ? attachment :nil;
}
}
return attachment;
}
- (BOOL)checkAttachment:(id<NIMCustomAttachment>)attachment{
BOOL check =NO;
if ([attachmentisKindOfClass:[NTESSendShopGoodsAttachmentclass]]) {
NSString *headerImg = ((NTESSendShopGoodsAttachment *)attachment).headerImage;
NSString *shopNameLa = ((NTESSendShopGoodsAttachment *)attachment).nameLabel;
NSString *priceLa = ((NTESSendShopGoodsAttachment *)attachment).priceLabel;
check = shopNameLa.length&&priceLa.length&&headerImg.length ?YES : NO;
}elseif ([attachment isKindOfClass:[NTESChartletAttachmentclass]]) {
NSString *chartletCatalog = ((NTESChartletAttachment *)attachment).chartletCatalog;
NSString *chartletId =((NTESChartletAttachment *)attachment).chartletId;
check = chartletCatalog.length&&chartletId.length ?YES : NO;
}
return check;
}
@end
[NIMCustomObjectregisterCustomDecoder:[NTESCustomAttachmentDecodernew]];
//注册 NIMKit自定义排版配置
[[NIMKitsharedKit] registerLayoutConfig:[NTESCellLayoutConfignew]];
在需要发送商品自定义消息的地方:
//自定义消息
-(void)sendManager:(UIButton *)btn
{
//隐藏topView
static int a =80;
[UIViewanimateWithDuration:0.5animations:^{
CGRect rect =self.topView.frame;
rect.origin.y -=a;
self.topView.frame =rect;
} completion:^(BOOL finished) {
[self.topViewremoveFromSuperview];
}];
//发送自定义消息
self.attachment = [[NTESSendShopGoodsAttachmentalloc] init];
_attachment.messageDic =self.messageDict;
NIMMessage *message = [[NIMMessagealloc] init];
NIMCustomObject *customObject = [[NIMCustomObjectalloc] init];
customObject.attachment =_attachment;
message.messageObject = customObject;
[selfsendMessage:message];
}
#pragma mark ---------------- cell点击事件 ------------------
- (NSDictionary *)cellActions
{
staticNSDictionary *actions = nil;
staticdispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
actions = @{@(NIMMessageTypeImage) : @"showImage:",
@(NIMMessageTypeVideo) : @"showVideo:",
@(NIMMessageTypeLocation) :@"showLocation:",
@(NIMMessageTypeFile) : @"showFile:",
@(NIMMessageTypeCustom): @"showCustom:"};
});
return actions;
}
-(BOOL)onTapCell:(NIMKitEvent *)event
{
BOOL handle =[superonTapCell:event];
NSString *eventName = event.eventName;
if ([eventNameisEqualToString:NIMKitEventNameTapAudio])
{
//音频
[self.interactormediaAudioPressed:event.messageModel];
handle = YES;
}
elseif([eventNameisEqualToString:NIMKitEventNameTapContent]){
BOOL handle =NO;
NIMMessage *message = event.messageModel.message;
NSDictionary *actions = [selfcellActions];
NSString *value = actions[@(message.messageType)];
if (value) {
SEL selector =NSSelectorFromString(value);
NSLog(@"value ---- %@,%d",value,(selector && [selfrespondsToSelector:selector]));
if (selector && [selfrespondsToSelector:selector]) {
SuppressPerformSelectorLeakWarning([self performSelector:selector withObject:message]);
handle = YES;
}
}
}
elseif([eventNameisEqualToString:NIMKitEventNameTapLabelLink])
{
NSString *link = event.data;
[self.viewmakeToast:[NSStringstringWithFormat:@"tap link : %@",link]
duration:2
position:CSToastPositionCenter];
handle = YES;
}elseif ([eventName isEqualToString:SendCustomWithGoodsClick]){
//自定义商品注入
NIMCustomObject * customObject =(NIMCustomObject *)event.messageModel.message.messageObject;
id attachment =customObject.attachment;
NSString * goodsId =[attachment goodsAttaId];
//自定义商品注入
JKNewGoodsDetailVC * goodVC =[[JKNewGoodsDetailVC alloc]init];
//添加商品id
goodVC.goodsId = [goodsId intValue];
[self.navigationController pushViewController:goodVC animated:YES];
handle =YES;
}
// if (!handle) {
// NSAssert(0, @"invalid event ----哈哈哈!垃圾...崩溃了");
// }
return handle;
}
集成网易云信实现自定义消息(类似淘宝聊天发送商品信息)相关推荐
- Android 类似淘宝的多商品订单评价
前言 近期在做一个商城类项目,需要实现对一个订单里的多个商品分别评价的功能(类似于淘宝的评价),花费了一点时间把效果做了出来,并在这里分享出来也权当做了记录,图个日后使用方便. 效果图 设计原理 设计 ...
- 使用Python获取国际版淘宝AliExpress的商品信息
AliExpress全球速卖通,又称国际版淘宝,是一款面向海外的购物网站. 之前有获取过Amazon的信息,偶然间发现了这个网站,所以今天看看这个国际版淘宝上面有没有我想要的东西. 不知道这上面能不能 ...
- 淘宝开放平台Api的小试牛刀(获取淘宝客推广商品信息)
最近在学习淘宝开放平台,属于初学小菜鸟,有一点点小成就给大家分享一下. 要做这个东西,第一步你必须注册为淘宝开发方平台的开发人员.地址:http://open.taobao.com/index.htm ...
- 如何抓取淘宝上的商品信息和详情页信息
来源于微擎里的人人商城里的插件, 采用接口: 第一个接口未获取基本信息接口,id为淘宝商品ID http://hws.m.taobao.com/cache/wdetail/5.0/?id=' .$id ...
- python爬虫 爬取淘宝搜索页面商品信息数据
主要使用的库: requests:爬虫请求并获取源码 re:使用正则表达式提取数据 json:使用JSON提取数据 pandas:使用pandans存储数据 以下是源代码: #!coding=utf- ...
- 【爬虫】爬取淘宝网的商品信息
文章目录 一.思路 1.根据关键词搜索 2.数据提取 3.数据保存 二.结果 三.源代码 一.思路 首先,从命令行参数列表中,提取出要爬取商品的关键词,根据关键词拼接URL,请求相应的URL,然后利用 ...
- 网易云信-新增自定义消息(iOS版)
https://www.jianshu.com/p/2bfb1c4e9f21 前言 公司业务需要,PC端,移动端都用到了第三方 网易云信 IM来实现在线客服咨询. 在这当中难免遇到一些需求是网易云信没 ...
- nginx简介(轻量级开源高并发web服务器:大陆使用者百度、京东、新浪、网易、腾讯、淘宝等)(并发量5w)(一般网站apache够用了,而且稳定)...
nginx简介(轻量级开源高并发web服务器:大陆使用者百度.京东.新浪.网易.腾讯.淘宝等)(并发量5w)(一般网站apache够用了,而且稳定) 一.总结 1.在连接高并发的情况下,Nginx是A ...
- 写一个类似淘宝的ios app需要用到哪些技术?
写一个类似淘宝的ios app需要用到哪些技术? 让我想起了有人私信我,说不缺钱,做个类似知乎的东西,包括加运营,需要多少钱. 扯淡结束,正好最近看了一点这方面的东西,也许对题主来说有点帮助. 手机淘 ...
最新文章
- JavaScript有哪三部分组成?
- php设计模式的六大原则(六):迪米特法则
- 检查Red Hat JBoss BRMS部署架构的规则和事件(第二部分)
- Bugku杂项-convert
- android按钮控件常见问题,Android的基本控件和Activity的应用总结
- html 手机分辨率,移动端各种分辨率手机屏幕----适配方法集锦
- Windows Phone 8.1 多媒体(3):音乐
- Autofs自动挂在实现
- html浮动之后怎么隐藏,div浮动之后排在一行,在把浮动去掉,把div用display设置成inline-block之后就不能排在一行了。...
- Subtext--为skin准备相关文件加载
- vue-tv-focusable
- axio并发请求示例
- oss图片无法在网站中显示
- 半自动安装jieba分词库
- 【转】26张PPT让你告别拖延症
- [刷题]leetcode\283_移动零
- stack overflow -最好的编程技术论坛!
- Win10系统电脑关机时提示“内存不能为read”的解决方法
- 编译kernel外部模块
- 方舟端游进服务器无限闪退,【求助】方舟一进服务器 过一会儿 闪退 弹白框求解...