网易云信Demo接入红包详细流程--iOS

网易云信金融魔方红包接入文档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中已经实现了该协议的方法,我们只需要在内部添加我们需要的配置就可以了

  1. 在init方法的_type中添加自定义消息对象JRMFRedPacketAttachmentJRMFRedPacketOpenAttchment

  2. 当显示的消息是领取红包的提示信息的时候不显示头像和昵称

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,376评论 25 707
  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,652评论 0 15
  • 说到拍照片,人可以分为3类。第一类,长得好还上相自带镜头感,第二类天生就上相,第三类长得普通还不上相! 第四类就是...
    ddStacy阅读 16,927评论 4 19
  • 在这个过分追求个性的时代里,人们的需求也变得多种多样,似乎有点让你摸不着头脑的感觉,比如它是一份感情、一份祝福、一...
    阿米巴中的那些事阅读 381评论 11 2
  • 5.3 哇!太神奇了, 这一切都是我创造的, 这不是真的, 这是虚构的全息幻象, 这是我的意识创造出来的, 哪里有...
    微笑起涟漪_446f阅读 202评论 0 0