iOS基于友盟事件統(tǒng)計封裝

統(tǒng)計分析管理類嘿歌,包含對所有ViewController添加頁面統(tǒng)計方法烟很、對單一ViewController添加頁面統(tǒng)計方法以及手動添加事件的相關(guān)方法跃洛。需要添加友盟庫

#import <UIKit/UIKit.h>

@interface RSAppAnalyticsManager : NSObject


/**
 集成測試設(shè)備id此迅,測試階段需在UM平臺->管理->集成測試中添加deviceId

 @return UM deviceId
 */
+ (NSString*)RS_debugDeviceId;
/**
 初始化統(tǒng)計功能

 @param appKey UM appKey
 @param channel 頻道(nil:App Store)
 @param open 是否打開崩潰信息收集
 */
+ (void)RS_initAppAnalyticsWithAppKey:(NSString*)appKey channel:(NSString *)channel openCrashReport:(BOOL)open;

/**
 對指定控制器添加計算統(tǒng)計

 ---*********注意*不可與全局頁面計算統(tǒng)計功能(RS_addAnalyticsForAllViewController)同時使用盗蟆,會造成死循環(huán)*********-----
 
 @param viewController 目標控制器
 */
+ (void)RS_addAnalyticsForViewController:(UIViewController*)viewController;

/**
 添加全局ViewController頁面計算統(tǒng)計
 */
+(void)RS_addAnalyticsForAllViewController;

/**
 是否開啟日志功能(release下自動設(shè)置NO)

 @param enabled 是否打開日志功能勺爱;debug狀態(tài)有效
 */
+ (void)RS_setLogEnabled:(BOOL)enabled;

/*----------------------計數(shù)事件-----------------------*/
+ (void)RS_event:(NSString *)eventId;
+ (void)RS_event:(NSString *)eventId label:(NSString *)label;
+ (void)RS_event:(NSString *)eventId attributes:(NSDictionary *)attributes;
+ (void)RS_event:(NSString *)eventId attributes:(NSDictionary *)attributes counter:(int)number;

/*----------------------計算事件-----------------------*/
+ (void)RS_beginEvent:(NSString *)eventId;
+ (void)RS_endEvent:(NSString *)eventId;
+ (void)RS_beginEvent:(NSString *)eventId label:(NSString *)label;
+ (void)RS_endEvent:(NSString *)eventId label:(NSString *)label;
+ (void)RS_beginEvent:(NSString *)eventId primarykey :(NSString *)keyName attributes:(NSDictionary *)attributes;
+ (void)RS_endEvent:(NSString *)eventId primarykey:(NSString *)keyName;
+ (void)RS_event:(NSString *)eventId durations:(int)millisecond;
+ (void)RS_event:(NSString *)eventId label:(NSString *)label durations:(int)millisecond;
+ (void)RS_event:(NSString *)eventId attributes:(NSDictionary *)attributes durations:(int)millisecond;

/*----------------------頁面統(tǒng)計-----------------------*/
+ (void)RS_logPageView:(NSString *)pageName seconds:(int)seconds;
+ (void)RS_beginLogPageView:(NSString *)pageName;
+ (void)RS_endLogPageView:(NSString *)pageName;
@end
#import "RSAppAnalyticsManager.h"
#import <UMCommon/UMCommon.h>
#import <UMAnalytics/MobClick.h>
#ifdef DEBUG
    #import <UMCommonLog/UMCommonLogHeaders.h>
#endif

#import <objc/message.h>

static NSString* const kSUBCLASS_PREFIX_NAME =  @"RSAnalytics_Target_ViewController";
@implementation RSAppAnalyticsManager

#pragma mark  - public
+ (NSString*)RS_debugDeviceId{
    return [UMConfigure deviceIDForIntegration];
}

+ (void)RS_initAppAnalyticsWithAppKey:(NSString*)appKey channel:(NSString *)channel openCrashReport:(BOOL)open{
    //開啟統(tǒng)計數(shù)據(jù)加密傳輸
    [UMConfigure setEncryptEnabled:YES];
    [MobClick setCrashReportEnabled:open];
    [UMConfigure initWithAppkey:appKey channel:channel];
}

+ (void)RS_addAnalyticsForViewController:(UIViewController*)viewController{
    if (viewController == nil || ![viewController isKindOfClass:[UIViewController class]]) {
        return;
    }
    NSString* className = NSStringFromClass([viewController class]);
    NSString* subClassName = [kSUBCLASS_PREFIX_NAME stringByAppendingString:className];
    Class subClass = NSClassFromString(subClassName);
    if (subClass == nil) {
        /*創(chuàng)建子類晃琳,在子類中添加方法下面兩個方法,確彼雎常控制器實現(xiàn)了這兩個方法*/
        subClass = objc_allocateClassPair([viewController class], subClassName.UTF8String, 0);
        objc_registerClassPair(subClass);
        /*向子類中添加viewWillAppear:和viewWillDisappear:方法卫旱,防止jviewController中未實現(xiàn)這兩個方法,而導(dǎo)致接下來交換方法實現(xiàn)交換成UIViewController的兩個方法围段,如果交換的是UIViewController的兩個方法顾翼,則會作用全局,并且全局中其他控制器沒有交換到先添加的方法奈泪,導(dǎo)致程序奔潰*/
        [self _RS_addViewWillAppearAndDisappearForSubClass:subClass formViewController:viewController];
    }
    //修改viewController的isa指針
    object_setClass(viewController, subClass);
    
    SEL rsViewWillAppearSEL = @selector(_RSAnalytics_viewWillAppear:);
    ///獲取IMP的兩種方法
//1.    Method rsViewWillAppear = class_getInstanceMethod([self class], rsViewWillAppearSEL);
       //IMP rsIMP = method_getImplementation(rsViewWillAppear);
    
//2.    IMP rsIMP = class_getMethodImplementation([self class], rsViewWillAppearSEL)
    if (class_addMethod([viewController class], rsViewWillAppearSEL, class_getMethodImplementation([self class], rsViewWillAppearSEL), "v@:B")) {
        Method viewWillAppear = class_getInstanceMethod([viewController class],@selector(viewWillAppear:));
        Method newWillAppearMethod = class_getInstanceMethod([viewController class], rsViewWillAppearSEL);
        method_exchangeImplementations(viewWillAppear, newWillAppearMethod);
    }
    
    SEL rsviewWillDisappearSel = @selector(_RSAnalytics_viewWillDisappear:);
    if (class_addMethod([viewController class], rsviewWillDisappearSel, class_getMethodImplementation([self class], rsviewWillDisappearSel), "v@:B")) {
        Method viewWllDisappear = class_getInstanceMethod([viewController class], @selector(viewWillDisappear:));
        Method newWillDisappearrMethod = class_getInstanceMethod([viewController class], rsviewWillDisappearSel);
        method_exchangeImplementations(viewWllDisappear, newWillDisappearrMethod);
    }
}
//依賴UIViewController+Analytics分類
+ (void)RS_addAnalyticsForAllViewController{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method viewWillAppear = class_getInstanceMethod([UIViewController class],@selector(viewWillAppear:));
        Method rsViewWillAppear = class_getInstanceMethod([UIViewController class],  @selector(_RSAnalytics_viewWillAppear:));
        method_exchangeImplementations(viewWillAppear,rsViewWillAppear);

        Method viewWllDisappear = class_getInstanceMethod([UIViewController class], @selector(viewWillDisappear:));
        Method rsViewWillDisappear = class_getInstanceMethod([UIViewController class],@selector(_RSAnalytics_viewWillDisappear:));
        method_exchangeImplementations(viewWllDisappear, rsViewWillDisappear);
    });
}

+ (void)RS_setLogEnabled:(BOOL)enabled{
#ifdef DEBUG
    [UMCommonLogManager setUpUMCommonLogManager];
    [UMConfigure setLogEnabled:enabled];
#endif
}

/*----------------------計數(shù)事件-----------------------*/
+ (void)RS_event:(NSString *)eventId{
    [MobClick event:eventId];
}

+ (void)RS_event:(NSString *)eventId label:(NSString *)label{
    [MobClick event:eventId label:label];
}

+ (void)RS_event:(NSString *)eventId attributes:(NSDictionary *)attributes{
    [MobClick event:eventId attributes:attributes];
}

+ (void)RS_event:(NSString *)eventId attributes:(NSDictionary *)attributes counter:(int)number{
    [MobClick event:eventId attributes:attributes counter:number];
}
/*----------------------計算事件-----------------------*/
+ (void)RS_beginEvent:(NSString *)eventId{
    [MobClick beginEvent:eventId];
}

+ (void)RS_endEvent:(NSString *)eventId{
    [MobClick endEvent:eventId];
}

+ (void)RS_beginEvent:(NSString *)eventId label:(NSString *)label{
    [MobClick beginEvent:eventId label:label];
}

+ (void)RS_endEvent:(NSString *)eventId label:(NSString *)label{
    [MobClick endEvent:eventId label:label];
}

+ (void)RS_beginEvent:(NSString *)eventId primarykey :(NSString *)keyName attributes:(NSDictionary *)attributes{
    [MobClick beginEvent:eventId primarykey:keyName attributes:attributes];
}

+ (void)RS_endEvent:(NSString *)eventId primarykey:(NSString *)keyName{
    [MobClick endEvent:eventId primarykey:keyName];
}

+ (void)RS_event:(NSString *)eventId durations:(int)millisecond{
    [MobClick event:eventId durations:millisecond];
}

+ (void)RS_event:(NSString *)eventId label:(NSString *)label durations:(int)millisecond{
    [MobClick event:eventId label:label durations:millisecond];
}

+ (void)RS_event:(NSString *)eventId attributes:(NSDictionary *)attributes durations:(int)millisecond{
    [MobClick event:eventId attributes:attributes durations:millisecond];
}

/*----------------------頁面統(tǒng)計-----------------------*/
+ (void)RS_logPageView:(NSString *)pageName seconds:(int)seconds{
    [MobClick logPageView:pageName seconds:seconds];
}

+ (void)RS_beginLogPageView:(NSString *)pageName{
    [MobClick beginLogPageView:pageName];
}

+ (void)RS_endLogPageView:(NSString *)pageName{
    [MobClick endLogPageView:pageName];
}

#pragma mark  - private
#pragma mark  - 待添加交換方法
- (void)_RSAnalytics_viewWillAppear:(BOOL)animated{
    NSString* pageName = [RSAppAnalyticsManager _RS_getViewControllerPageName:self];
    if (pageName && pageName.length > 0) {
        [RSAppAnalyticsManager RS_beginLogPageView:pageName];
    }
    [self _RSAnalytics_viewWillAppear:animated];
}

- (void)_RSAnalytics_viewWillDisappear:(BOOL)animated{
    NSString* pageName = [RSAppAnalyticsManager _RS_getViewControllerPageName:self];
    if (pageName && pageName.length > 0) {
       [RSAppAnalyticsManager RS_endLogPageView:pageName];
    }
    [self _RSAnalytics_viewWillDisappear:animated];
}

+ (NSString*)_RS_getViewControllerPageName:(id)vcController{
    UIViewController* controller = (UIViewController*)vcController;
    NSString* pageName = [controller respondsToSelector:@selector(title)] ? controller.title : nil;
    return pageName;
}

#pragma mark  - 為子類控制器類添加viewWillAppear:和viewWillDisappear:確笔拭常控制器一定實現(xiàn)了這兩個方法,避免因未實現(xiàn)而交換UIViewController的方法實現(xiàn)涝桅,導(dǎo)致作用到全局

/**
 為類添加viewWillAppear:和viewWillDisappear:方法

 @param clazz 目標類
 @param viewController 方法來源控制器(即參照控制器添加一個相同的方法到目標類中拜姿,如果viewController沒有則根據(jù)繼承關(guān)系逐層查找,類似copy一個方法到目標類冯遂,不會影響原類)
 */
+ (void)_RS_addViewWillAppearAndDisappearForSubClass:(Class)clazz formViewController:(UIViewController*)viewController{
    SEL addWillAppearSel = @selector(viewWillAppear:);
    class_addMethod(clazz, addWillAppearSel, method_getImplementation(class_getInstanceMethod([viewController class], addWillAppearSel)), "v@:B");
    
    SEL addWillDisappearSel = @selector(viewWillDisappear:);
    class_addMethod(clazz, addWillDisappearSel, method_getImplementation(class_getInstanceMethod([viewController class], addWillDisappearSel)), "v@:B");
}
@end

對所有ViewController添加頁面統(tǒng)計方法的輔助分類

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

/**
 為設(shè)置全局頁面計算統(tǒng)計提供支撐
 */
@interface UIViewController (Analytics)

@end

NS_ASSUME_NONNULL_END
#import "UIViewController+Analytics.h"
#import "RSAppAnalyticsManager.h"

@implementation UIViewController (Analytics)


- (void)_RSAnalytics_viewWillAppear:(BOOL)animated{
    NSString* pageName = [UIViewController _RS_getViewControllerPageName:self];
    if (pageName && pageName.length > 0) {
        [RSAppAnalyticsManager RS_beginLogPageView:pageName];
    }
    [self _RSAnalytics_viewWillAppear:animated];
}

- (void)_RSAnalytics_viewWillDisappear:(BOOL)animated{
    NSString* pageName = [UIViewController _RS_getViewControllerPageName:self];
    if (pageName && pageName.length > 0) {
        [RSAppAnalyticsManager RS_endLogPageView:pageName];
    }
    [self _RSAnalytics_viewWillDisappear:animated];
}

+ (NSString*)_RS_getViewControllerPageName:(id)vcController{
    UIViewController* controller = (UIViewController*)vcController;
    NSString* pageName = controller.title;
    return pageName;
}
@end

以下是對UIButton蕊肥、UIView相關(guān)事件統(tǒng)計封裝

UIButton

#import <UIKit/UIKit.h>
#import "UIView+RSAnalytics.h"

/**
 UIButton事件計數(shù)統(tǒng)計分類
 */
@interface UIButton (RSAnalytics)

/**
 為UIButton添加事件,自動添加計數(shù)統(tǒng)計功能蛤肌。

 @param target 目標(響應(yīng)者)
 @param action 事件
 @param controlEvents 事件類型
 @param eventId 統(tǒng)計事件id
 @param lable 統(tǒng)計事件label
 */
- (void)RS_addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents annlyticEventId:(NSString*)eventId annlyticLable:(NSString*)lable;
@end
#import "UIButton+RSAnalytics.h"
#import <objc/runtime.h>
#import "RSAppAnalyticsManager.h"


static NSString* const RS_eventId;
static NSString* const RS_lable;

static const char* kSUBCLASS_BUTTON_IVAR_NAME = "_rsAnalytics_Target_Button";

@implementation UIButton (RSAnalytics)

- (void)RS_addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents annlyticEventId:(NSString*)eventId annlyticLable:(NSString*)lable{
    if (![target respondsToSelector:action])
        return;
    
    objc_setAssociatedObject(self, &RS_eventId, eventId, OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &RS_lable, lable, OBJC_ASSOCIATION_COPY_NONATOMIC);
    
    objc_setAssociatedObject(target, kSUBCLASS_BUTTON_IVAR_NAME, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    NSString* selName = [NSStringFromSelector(action) rangeOfString:@":"].location == NSNotFound ? NSStringFromSelector(@selector(RS_analyticsEvent_)) : NSStringFromSelector(@selector(RS_analyticsEvent_:));
    const char* types = [NSStringFromSelector(action) rangeOfString:@":"].location == NSNotFound ? "v@:" : "v@:@";
    SEL sel = NSSelectorFromString(selName);
    IMP imp = class_getMethodImplementation(self.class, sel);
    if (class_addMethod([target class], sel, imp, types)) {
        Method actionMethod = class_getInstanceMethod([target class], action);
        Method newMethod = class_getInstanceMethod([target class], sel);
        method_exchangeImplementations(actionMethod, newMethod);
    }
    [self addTarget:target action:action forControlEvents:controlEvents];
}

- (void)RS_analyticsEvent_:(UIButton*)eventView{
    [RSAppAnalyticsManager RS_event:eventView.eventId label:eventView.lable];
    [self RS_analyticsEvent_:eventView];
}

- (void)RS_analyticsEvent_{
    UIButton* eventView = objc_getAssociatedObject(self, kSUBCLASS_BUTTON_IVAR_NAME);
    [RSAppAnalyticsManager RS_event:eventView.eventId label:eventView.lable];
    [self RS_analyticsEvent_];
}

#pragma mark  - getter
- (NSString *)eventId{
    return objc_getAssociatedObject(self, &RS_eventId);
}

- (NSString *)lable{
    return objc_getAssociatedObject(self, &RS_lable);
}
@end

UIView點擊事件

#import <UIKit/UIKit.h>


/**
 視圖添加點擊事件分類(同時添加事件計數(shù)統(tǒng)計)
 */
@interface UIView (RSAnalytics)

/**
 為視圖添加點擊事件;自動添加事件計數(shù)統(tǒng)計功能

 @param target 目標(響應(yīng)者)
 @param action 事件
 @param eventId 統(tǒng)計事件id
 @param lable 統(tǒng)計事件label
 */
- (void)RS_addTarget:(id)target forTouchUpInsaidAction:(SEL)action annlyticEventId:(NSString*)eventId annlyticLable:(NSString*)lable;
@end
#import "UIView+RSAnalytics.h"
#import <objc/message.h>
#import "RSAppAnalyticsManager.h"

static NSString* const RS_eventId;
static NSString* const RS_lable;


static const char* kSUBCLASS_VIEW_IVAR_NAME = "_rsAnalytics_Target_View";
@implementation UIView (RSAnalytics)

- (void)RS_addTarget:(id)target forTouchUpInsaidAction:(SEL)action annlyticEventId:(NSString*)eventId annlyticLable:(NSString*)lable{
    if (![target respondsToSelector:action])
        return;
    
    if (!self.userInteractionEnabled)
        self.userInteractionEnabled = YES;
    
    objc_setAssociatedObject(self, &RS_eventId, eventId, OBJC_ASSOCIATION_COPY_NONATOMIC);
    objc_setAssociatedObject(self, &RS_lable, lable, OBJC_ASSOCIATION_COPY_NONATOMIC);
    
    objc_setAssociatedObject(target, kSUBCLASS_VIEW_IVAR_NAME, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    NSString* selName = [NSStringFromSelector(action) rangeOfString:@":"].location == NSNotFound ? NSStringFromSelector(@selector(RS_analyticsEvent_)) : NSStringFromSelector(@selector(RS_analyticsEvent_:));
    const char* types = [NSStringFromSelector(action) rangeOfString:@":"].location == NSNotFound ? "v@:" : "v@:@";
    SEL sel = NSSelectorFromString(selName);
    IMP imp = class_getMethodImplementation(self.class, sel);
    if (class_addMethod([target class], sel, imp, types)) {
        Method actionMethod = class_getInstanceMethod([target class], action);
        Method newMethod = class_getInstanceMethod([target class], sel);
        method_exchangeImplementations(actionMethod, newMethod);
    }
    UITapGestureRecognizer* tapGest = [[UITapGestureRecognizer alloc] initWithTarget:target action:action];
    [self addGestureRecognizer:tapGest];
}

- (void)RS_analyticsEvent_:(UIGestureRecognizer*)ges{
    [RSAppAnalyticsManager RS_event:ges.view.eventId label:ges.view.lable];
    [self RS_analyticsEvent_:ges];
}

- (void)RS_analyticsEvent_{
    UIButton* eventView = objc_getAssociatedObject(self, kSUBCLASS_VIEW_IVAR_NAME);
    [RSAppAnalyticsManager RS_event:eventView.eventId label:eventView.lable];
    [self RS_analyticsEvent_];
}

#pragma mark  - getter setter
- (NSString *)eventId{
    return objc_getAssociatedObject(self, &RS_eventId);
}

- (NSString *)lable{
    return objc_getAssociatedObject(self, &RS_lable);
}
@end

初版壁却,沒有深入測試過,如有問題或者更好的實現(xiàn)方法可在評論中留言

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末裸准,一起剝皮案震驚了整個濱河市展东,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炒俱,老刑警劉巖盐肃,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異权悟,居然都是意外死亡砸王,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門僵芹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人小槐,你說我怎么就攤上這事拇派『稍” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵件豌,是天一觀的道長疮方。 經(jīng)常有香客問我,道長茧彤,這世上最難降的妖魔是什么骡显? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮曾掂,結(jié)果婚禮上惫谤,老公的妹妹穿的比我還像新娘。我一直安慰自己珠洗,他們只是感情好溜歪,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著许蓖,像睡著了一般蝴猪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上膊爪,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天自阱,我揣著相機與錄音,去河邊找鬼米酬。 笑死沛豌,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的淮逻。 我是一名探鬼主播琼懊,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼爬早!你這毒婦竟也來了哼丈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤筛严,失蹤者是張志新(化名)和其女友劉穎醉旦,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桨啃,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡车胡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了照瘾。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片匈棘。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖析命,靈堂內(nèi)的尸體忽然破棺而出主卫,到底是詐尸還是另有隱情逃默,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布簇搅,位于F島的核電站完域,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瘩将。R本人自食惡果不足惜吟税,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望姿现。 院中可真熱鬧肠仪,春花似錦、人聲如沸建钥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽熊经。三九已至泽艘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間镐依,已是汗流浹背匹涮。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留槐壳,地道東北人然低。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像务唐,于是被迫代替她去往敵國和親雳攘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容