网易云信金融魔方红包接入文档v2.0
一、文档说明
基于网易云信的IM,接入金融魔方IM红包SDK实现App快速集成发单聊红包、发群聊红包、拆红包并查看交易记录等功能
【注:示例中的partnerId为金融魔方分配给商户的唯一标识的渠道id】
在阅读下面内容之前请确保在项目有中已经导入了金融魔方红包SDK
如若想集成钱包功能,也请导入钱包SDK
金融魔方SDK下载地址
金融魔方红包接入文档
网易云信集成红包Demo
网易云信demo下载地址(网易原生)
二、集成流程详解
1、获取token值
#pragma mark - 登录成功后获取红包thirdToken
// 云信登录之后的回调方法
@implementation NTESAppDelegate
- (void)onLogin:(NIMLoginStep)step {
if(step == NIMLoginStepSyncOK) {
NSLog(@"同步完成");
[JRMFTools getJrmfPacketThirdTokenWithUserId:[[NIMSDK sharedSDK].loginManager currentAccount] partnerId:[JRMFSington GetPacketSington].JrmfPartnerId appMethod:NO completion:^(NSString *thirdToken, BOOL isOnline) {
[JRMFSington GetPacketSington].JrmfThirdToken = thirdToken;
[JrmfPacket instanceJrmfPacketWithPartnerId:[JRMFSington GetPacketSington].JrmfPartnerId EnvelopeName:@"云红包" SchemeUrl:kSchemeUrl appMothod:isOnline];
[JrmfWalletSDK instanceJrmfWalletSDKWithPartnerId:[JRMFSington GetPacketSington].JrmfPartnerId AppMethod:isOnline];
}];
}
}
2、定义消息枚举(在NTESCustomAttachmentDefines中)
typedef NS_ENUM(NSInteger,NTESCustomMessageType){
CustomMessageTypeJanKenPon = 1, //剪子石头布
CustomMessageTypeSnapchat = 2, //阅后即焚
CustomMessageTypeChartlet = 3, //贴图表情
CustomMessageTypeWhiteboard = 4, //白板会话
CustomMessageTypeRedPacket = 5, // 发送红包
CustomMessageTypeRedPacketOpen = 6 //领取红包提示信息
};
3、自定义消息体
- 自定义消息对象
创建一个实现NIMCustomAttachment,NTESCustomAttachmentInfo的红包协议对象
红包消息对象
@interface JRMFRedPacketAttachment : NSObject <NIMCustomAttachment, NTESCustomAttachmentInfo>
/**
祝福语,如:恭喜发财,大吉大利
*/
@property (copy, nonatomic) NSString *title;
/**
红包的描述,如:云信红包
*/
@property (copy, nonatomic) NSString *desc;
/**
红包的文字内容,为title和desc拼接的字符串
*/
@property (nonatomic,copy) NSString *content;
/**
红包ID
*/
@property (copy, nonatomic) NSString *bribery_ID;
- 实现 NIMCustomAttachment,NTESCustomAttachmentInfo 协议
@implementation JRMFRedPacketAttachment
// 自定义消息解码,必须实现的方法
- (NSString *)encodeAttachment {
NSDictionary *dictContent = @{CMBriberyMsg: self.title, CMContent: self.content, CMBriberyName: self.desc , CMBriberyId: self.bribery_ID};
NSDictionary *dict = @{CMType: @(CustomMessageTypeTest), CMData: dictContent};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:0
error:nil];
return [[NSString alloc] initWithData:jsonData
encoding:NSUTF8StringEncoding];
}
// 该方法返回消息view的大小
// kRedPacketImage为自己在外部定义的静态方法,用来获取图片Image,用户可自行定义
- (CGSize)contentSize:(NIMMessage *)message cellWidth:(CGFloat)width {
return kRedPacketImage(@"bg_from_hongbao");
}
// 该方法返回消息内容和消息view的边界距离
- (UIEdgeInsets)contentViewInsets:(NIMMessage *)message {
CGFloat bubblePaddingForImage = 3.f;
CGFloat bubbleArrowWidthForImage = 5.f;
if (message.isOutgoingMsg) {
return UIEdgeInsetsMake(bubblePaddingForImage,bubblePaddingForImage,bubblePaddingForImage,bubblePaddingForImage + bubbleArrowWidthForImage);
}else{
return UIEdgeInsetsMake(bubblePaddingForImage,bubblePaddingForImage + bubbleArrowWidthForImage, bubblePaddingForImage,bubblePaddingForImage);
}
}
// 该方法返回与之相关联的显示消息的view,JRMFSessionRedPacketContentView为创建的消息view
- (NSString *)cellContent:(NIMMessage *)message{
return @"JRMFSessionRedPacketContentView";
}
红包领取提示消息对象
@interface JRMFRedPacketOpenAttchment : NSObject <NIMCustomAttachment, NTESCustomAttachmentInfo>
/**
红包发送者ID
*/
@property (nonatomic, strong) NSString * sendPacketId;
/**
红包发送者名字
*/
@property (strong, nonatomic) NSString *sendNickName;
/**
拆红包ID
*/
@property (nonatomic, strong) NSString * openPacketId;
/**
* 红包ID
*/
@property (nonatomic, strong) NSString * packetId;
/**
是否为最后一个红包
*/
@property (nonatomic, strong) NSString * isGetDone;
/**
* 拆红包者昵称
*/
@property (nonatomic, strong) NSString * openNickName;
/**
展示的领取信息
*/
@property (copy, nonatomic) NSString *openMessage;
【注:在@implementation JRMFRedPacketOpenAttchment中的实现和JRMFRedPacketAttachment大体相同,具体内部实现根据需求操作(参考demo)】
- 自定义消息界面,新建气泡内容
气泡内容类需要继承 NIMSessionMessageContentView,并使用 - (instancetype)initSessionMessageContentView 作为初始化方法。内容里根据业务需求自行排版
红包消息界面
static NSString *const JRMFRedPacketEventOpen = @"JRMFRedPacketEventOpen";
@interface JRMFSessionRedPacketContentView : NIMSessionMessageContentView
/**
祝福语
*/
@property (nonatomic,strong) UILabel *titleLabel;
/**
红包操作描述语,如:领取红包,查看红包
*/
@property (nonatomic,strong) UILabel *subTitleLabel;
/**
红包描述,如:云信红包
*/
@property (strong, nonatomic) UILabel *descLabel;
@interface JRMFSessionRedPacketContentView ()
// 拆红包的点击手势
@property (strong, nonatomic) UITapGestureRecognizer *tap;
@end
@implementation JRMFSessionRedPacketContentView
- (instancetype)initSessionMessageContentView{
self = [super initSessionMessageContentView];
if (self) {
// 添加点击手势 -- 用于拆红包
_tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)];
[self addGestureRecognizer:_tap];
// 内容布局
_titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_titleLabel.font = [UIFont systemFontOfSize:13.f];
_subTitleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_subTitleLabel.font = [UIFont systemFontOfSize:12.f];
_descLabel = [[UILabel alloc] initWithFrame:CGRectZero];
_descLabel.font = [UIFont systemFontOfSize:12.f];
[self addSubview:_titleLabel];
[self addSubview:_subTitleLabel];
[self addSubview:_descLabel];
}
return self;
}
#pragma mark - 点击手势
- (void)tapGesture:(UITapGestureRecognizer *)recognizer {
if ([self.delegate respondsToSelector:@selector(onCatchEvent:)]) {
NIMKitEvent *event = [[NIMKitEvent alloc] init];
event.eventName = JRMFRedPacketEventOpen;
event.messageModel = self.model;
event.data = self;
[self.delegate onCatchEvent:event];
}
}
#pragma mark - 系统父类方法
- (void)refresh:(NIMMessageModel*)data{
//务必调用super方法
[super refresh:data];
NIMCustomObject *object = data.message.messageObject;
JRMFRedPacketAttachment *attachment = (JRMFRedPacketAttachment *)object.attachment;
self.titleLabel.text = attachment.title;
self.descLabel.text = attachment.desc;
self.titleLabel.textColor = [UIColor whiteColor];
self.subTitleLabel.textColor = [UIColor whiteColor];
self.descLabel.textColor = [UIColor lightGrayColor];
[_titleLabel sizeToFit];
CGRect rect = _titleLabel.frame;
if (CGRectGetMaxX(rect) > self.bounds.size.width) {
rect.size.width = self.bounds.size.width - rect.origin.x - 20;
_titleLabel.frame = rect;
}
[_subTitleLabel sizeToFit];
[_descLabel sizeToFit];
}
- (UIImage *)chatBubbleImageForState:(UIControlState)state outgoing:(BOOL)outgoing {
if (outgoing) {
// 当消息头像位于右边的时候cell显示的内容,以及返回背景图片
}else {
// 当消息头像位于左边的时候cell显示的内容,以及返回背景图片
}
}
红包领取提示消息界面
static NSString *const JRMFRedPacketEventOpenMessage = @"JRMFRedPacketEventOpenMessage";
@interface JRMFSessionRedPacketOpenContentView : NIMSessionMessageContentView
// 提示的Label
@property(strong, nonatomic) UILabel *messageLabel;
@implementation JRMFSessionRedPacketOpenContentView
// 实现JRMFSessionRedPacketContentView(红包发送界面)中相同的方法
.........
// 注意在以下方法中返回一个空的图片就好
- (UIImage *)chatBubbleImageForState:(UIControlState)state outgoing:(BOOL)outgoing {
return [UIImage alloc];
}
- 新建自定义消息气泡布局配置
配置需要实现 NIMCellLayoutConfig 协议。这里除了自定义消息外,其他消息沿用内置配置,所以配置类继承基类 NIMCellLayoutConfig
在demo中已经实现了该协议的方法,我们只需要在内部添加我们需要的配置就可以了
在init方法的_type中添加自定义消息对象JRMFRedPacketAttachment和JRMFRedPacketOpenAttchment
当显示的消息是领取红包的提示信息的时候不显示头像和昵称
// 头像显示
- (BOOL)shouldShowAvatar:(NIMMessageModel *)model{
.......
if ([self isRedPacketOpenMessage:model.message]) {
return NO;
}
return [super shouldShowAvatar:model];
}
// 昵称显示
- (BOOL)shouldShowNickName:(NIMMessageModel *)model{
.......
if ([self isRedPacketOpenMessage:model.message]) {
return NO;
}
return [super shouldShowNickName:model];
}
// 不显示红包领取的头像和昵称
- (BOOL)isRedPacketOpenMessage:(NIMMessage *)message {
if (message.messageType == NIMMessageTypeCustom) {
NIMCustomObject *object = message.messageObject;
if (object) {
if ([object.attachment isKindOfClass:[JRMFRedPacketOpenAttchment class]]) {
return YES;
}
}
}
return NO;
}
3.将创建好的布局配置类注入到组件中,保证在会话页实例化之前注入即可。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
//注册 NIMKit 自定义排版配置
[[NIMKit sharedKit] registerLayoutConfig:[CellLayoutConfig class]];
...
}
- 在附加按钮面板中添加发送红包的按钮,在NTESSessionConfig的- (NSArray *)mediaItems方法中添加
// onTapMediaItemRedPacket:是点击事件的方法名,一定要与NTESSessionViewController中的自定义的点击方法名称一样
NIMMediaItem *redPacket = [NIMMediaItem item:@"onTapMediaItemRedPacket:" normalImage:[UIImage imageNamed:@"ic_hongbao"] selectedImage:[UIImage imageNamed:@"ic_hongbao"] title:@"红包"];
......
// 將redPacket按钮添加到数组items中,并将items添加defaultMediaItems返回
return [defaultMediaItems arrayByAddingObjectsFromArray:items];
- 定义消息发送方法--在NTESSessionMsgConverter中
// 发送红包
+ (NIMMessage *)msgWithRedPacket:(JRMFRedPacketAttachment *)attachment {
NIMMessage *message = [[NIMMessage alloc] init];
NIMCustomObject *customObject = [[NIMCustomObject alloc] init];
customObject.attachment = attachment;
message.messageObject = customObject;
NIMMessageSetting *setting = [[NIMMessageSetting alloc] init];
setting.apnsEnabled = NO;
message.setting = setting;
return message;
}
// 领取红包后显示的提示信息
+ (NIMMessage *)msgWithOpenRedPacket:(JRMFRedPacketOpenAttchment *)attachment {
NIMMessage *message = [[NIMMessage alloc] init];
NIMCustomObject *customObject = [[NIMCustomObject alloc] init];
customObject.attachment = attachment;
message.messageObject = customObject;
message.remoteExt = @{
CMSendPacketAccid: attachment.sendPacketId,
CMOpenPacketAccid: attachment.openPacketId
};
NIMMessageSetting *setting = [[NIMMessageSetting alloc] init];
setting.apnsEnabled = NO;
message.setting = setting;
return message;
}
4、消息发送及消息事件处理
- 在NTESSessionViewController实现消息发送
// 附加按钮中红包发送点击事件
- (void)onTapMediaItemRedPacket:(NIMMediaItem *)item {
.......
// 在这里调用红包发送的接口
}
#pragma mark - 红包发送回调
// 调用红包发送的回调方法(魔方SDK提供)
- (void)dojrmfActionDidSendEnvelopedWithID:(NSString *)envId Name:(NSString *)envName Message:(NSString *)envMsg Stat:(jrmfSendStatus)jrmfStat {
// 当红包发送成功之后,给消息对象赋值,并发送消息
if (jrmfStat == kjrmfStatSucess) {
JRMFRedPacketAttachment *attachment = [[JRMFRedPacketAttachment alloc] init];
attachment.title = envMsg;
attachment.bribery_ID = envId;
attachment.desc = envName;
// 发送消息
[self sendMessage:[NTESSessionMsgConverter msgWithRedPacket:attachment]];
}
}
- 消息点击事件的处理
- (void)onTapCell:(NIMKitEvent *)event {
.......
// 拆(领取)红包
if([eventName isEqualToString:JRMFRedPacketEventOpen]){
// 用户相关信息获取(参照Demo)
......
// 调用拆红包的接口(魔方SDK提供)
[jrmf doActionPresentOpenViewController:self thirdToken:[JRMFSington GetPacketSington].JrmfThirdToken withUserName:nickName userHead:headUrl userID:userId envelopeID:attachment.bribery_ID isGroup:isGroup];
handled = YES; //必须设置为YES,不然会崩溃
//拆红包消息提示语“红包”字段的点击事件
}else if([eventName isEqualToString:JRMFRedPacketEventOpenMessage]) {
......
// 调用展示详情页面的接口
[jrmf doActionPresentPacketDetailInViewWithUserID:userId packetID:attachment.packetId thirdToken:[JRMFSington GetPacketSington].JrmfThirdToken];
handled = YES;
}
}
#pragma mark - 成功领取一个红包
// 成功领取一个红包后的回调方法(魔方SDK提供)
- (void)dojrmfActionOpenPacketSuccessWithGetDone:(BOOL)isDone{
......
[self sendMessage:[NTESSessionMsgConverter msgWithOpenRedPacket:attachment]];
}
5、消息接收
- 使用 NIMCustomAttachmentCoding 协议支持自定义消息的反序列化,在云信demo中提供了NTESCustomAttachmentDecoder类,我们只需实现里面相关的消息解码即可
@implementation NTESCustomAttachmentDecoder
- (id<NIMCustomAttachment>)decodeAttachment:(NSString *)content
{
......
if ([dict isKindOfClass:[NSDictionary class]])
{
......
switch (type) {
......
// 在当前方法中添加红包消息的解码信息
case CustomMessageTypeRedPacket:
{
attachment = [[JRMFRedPacketAttachment alloc] init];
((JRMFRedPacketAttachment *)attachment).title = [data jsonString:CMBriberyMsg];
((JRMFRedPacketAttachment *)attachment).content = [data jsonString:CMContent];
((JRMFRedPacketAttachment *)attachment).desc = [data jsonString:CMBriberyName];
((JRMFRedPacketAttachment*)attachment).bribery_ID = [data jsonString:CMBriberyId];
}
break;
case CustomMessageTypeRedPacketOpen:
{
attachment = [[JRMFRedPacketOpenAttchment alloc] init];
((JRMFRedPacketOpenAttchment *)attachment).sendPacketId = [data jsonString:CMSendPacketId];
((JRMFRedPacketOpenAttchment *)attachment).openNickName = [data jsonString:CMOpenNickName];
((JRMFRedPacketOpenAttchment *)attachment).packetId = [data jsonString:CMPacketId];
((JRMFRedPacketOpenAttchment *)attachment).isGetDone = [data jsonString:CMIsGetDone];
((JRMFRedPacketOpenAttchment *)attachment).openPacketId = [data jsonString:CMOpenPacketId];
((JRMFRedPacketOpenAttchment *)attachment).openMessage = [data jsonString:CMOpenMessage];
((JRMFRedPacketOpenAttchment *)attachment).sendNickName = [data jsonString:CMSendNickName];
}
break;
default:
break;
}
attachment = [self checkAttachment:attachment] ? attachment : nil;
}
......
}
- 并在 - (BOOL)application: didFinishLaunchingWithOptions: 中注入
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
[NIMCustomObject registerCustomDecoder:[[AttachmentDecoder alloc]init]];
...
}
- 部分消息拦截
群组中的红包领取信息,如果不是红包发送者或者是领取者是不应该收到该红包的领取消息
@implementation NTESAppDelegate
- (void)onRecvMessages:(NSArray<NIMMessage *> *)messages{
// 在该方法中对消息进行筛选,并在筛选完成之后通知UI界面不显示该消息(详情见Demo)
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 设置代理对象
[[NIMSDK sharedSDK].chatManager addDelegate:self];
......
}
6、消息列表最近消息展示
- 在消息列表中,对应的会话显示最近消息,云信demo中在NTESSessionListViewController进行操作
// 在该方法中添加对应的展示信息
- (NSString *)contentForRecentSession:(NIMRecentSession *)recent{
// 根据object.attachment的类型来确定展示的信息
}
7、在设置页面接入“我的钱包”
- 首先需要注册钱包(在第一步获取token的时候注册钱包)
- 在设置界面添加“我的钱包”
@interface NTESSettingViewController ()<NIMUserManagerDelegate>
- (void)buildData{
......
NSArray *data = @[
......
@{
HeaderTitle:@"",
RowContent :@[
@{
Title :@"我的钱包",
CellAction :@"onTouchShowWallet:",
ShowAccessory : @(YES)
},
],
FooterTitle:@""
},
......
];
......
}
// 点击“我的钱包”事件
- (void)onTouchShowWallet:(id)sender {
JrmfWalletSDK * jrmf = [[JrmfWalletSDK alloc] init];
NSString *userId = [[NIMSDK sharedSDK].loginManager currentAccount];
NIMKitInfo *userInfo = [[NIMKit sharedKit] infoByUser:userId];
//展示我的钱包页面
[jrmf doPresentJrmfWalletPageWithBaseViewController:self userId:userId userName:userInfo.showName userHeadLink:userInfo.avatarUrlString thirdToken:[JRMFSington GetPacketSington].JrmfThirdToken];
}
8、用户基本信息更新
- 在云信Demo中更新用户信息,并不会实时更新红包中的用户的基本信息,需要手动调用更新接口
// 在云信中更新用户信息之后需要手动调用该方法来更新红包中的用户信息(魔方SDK接口)
+ (void)updateUserMsgWithUserId:(NSString *)userId userName:(NSString *)userName userHead:(NSString *)userHeadLink thirdToken:(NSString *)thirdToken completion:(void (^)(NSError *error, NSDictionary *resultDic))completionAction;