iOS進(jìn)階補(bǔ)完計(jì)劃--打點(diǎn)上報(bào)、無(wú)痕埋點(diǎn)

最近研習(xí)了美團(tuán)等大廠(chǎng)的一些埋點(diǎn)方案凫岖。
還要感謝大神《xuhaoranLeo》的指點(diǎn)江咳。(既然大神沒(méi)空寫(xiě)博客、但我可以代勞哈)哥放。

本文的宗旨是盡量全面歼指、精簡(jiǎn)、滿(mǎn)足我能想到盡量多的埋點(diǎn)需求甥雕。

主要通過(guò)以下這些方面來(lái)談?wù)勚新顸c(diǎn)那些事:

  • 打點(diǎn)/上報(bào)的大概流程
  • 日志記錄類(lèi)型
  • 日志應(yīng)該帶有的數(shù)據(jù)
  • 打點(diǎn)的具體方式
  • 何時(shí)上報(bào)
  • 具體實(shí)現(xiàn)(iOS)

打點(diǎn)/上報(bào)的大概流程

  • 打點(diǎn):當(dāng)發(fā)生需要收集的行為/狀態(tài)時(shí)踩身、將其記錄在日記中。
  • 上報(bào):選擇合適的時(shí)機(jī)將日志上報(bào)社露。

日志記錄類(lèi)型

根據(jù)業(yè)務(wù)需要大致可以具有以下類(lèi)型

  • 頁(yè)面/產(chǎn)品曝光
  • 用戶(hù)點(diǎn)擊
  • 性能打點(diǎn)(數(shù)據(jù)庫(kù)操作效率挟阻、APP運(yùn)行卡頓)
  • 網(wǎng)絡(luò)監(jiān)控

日志應(yīng)該帶有的數(shù)據(jù)

  • 一切分析時(shí)用得到的數(shù)據(jù)例子:
    行為(點(diǎn)擊、瀏覽)峭弟、用戶(hù)(uid)附鸽、業(yè)務(wù)信息(gid、gtype)等瞒瘸。

  • 關(guān)鍵業(yè)務(wù)的性能監(jiān)聽(tīng)(其實(shí)性能打點(diǎn)我比較推薦單獨(dú)進(jìn)行坷备、畢竟這是開(kāi)發(fā)關(guān)心的、產(chǎn)品分析并不需要):

  • 網(wǎng)絡(luò)請(qǐng)求失敗率情臭、錯(cuò)誤碼
  • 數(shù)據(jù)層操作耗時(shí)省撑、App卡頓堆棧

打點(diǎn)的具體方式

  • 代碼埋點(diǎn):具體業(yè)務(wù)代碼處、手動(dòng)添加埋點(diǎn)代碼俯在。比如衡量圖片上傳丁侄、數(shù)據(jù)解析、OI操作的時(shí)間等
  • 聲明埋點(diǎn): 通過(guò)將事件標(biāo)識(shí)朝巫、業(yè)務(wù)字段作為屬性添加在響應(yīng)控件上鸿摇。簡(jiǎn)化代碼埋點(diǎn)的代碼量。
  • 無(wú)痕埋點(diǎn):獲取全部操作劈猿、通過(guò)plist文件拙吉、決定需要上報(bào)的指定操作《美團(tuán):Mixpanel》
  • 無(wú)埋點(diǎn):上報(bào)所有操作潮孽、由服務(wù)器篩選《GrowingIO》

具體實(shí)現(xiàn):

由于每個(gè)項(xiàng)目的需求不同、具體實(shí)現(xiàn)也不一樣筷黔。
這里只大概理順?biāo)悸贰?/p>

周期內(nèi)記錄:

既然是統(tǒng)一上報(bào)往史、就需要在上報(bào)之前將本次周期中所有的指定操作記錄下來(lái)。

  • 每次操作中佛舱。由一個(gè)指定的模型(json)進(jìn)行存儲(chǔ)椎例。
  • 而整個(gè)周期中。我們采用一個(gè)單例请祖、單例中有一個(gè)數(shù)組對(duì)單次模型進(jìn)行存儲(chǔ)订歪。
  /*
  * 數(shù)據(jù)存儲(chǔ)模型
  */
  
  @interface KTBehaviorData : NSObject
  @property (nonatomic, strong) NSString *op_type; // 1點(diǎn)擊事件 2頁(yè)面事件 3IO操作
  @property (nonatomic, strong) NSString *page_code; // 頁(yè)面Id
  @property (nonatomic, strong) NSString *event_code; // 事件Id
  @property (nonatomic, strong) NSDictionary *object_dic; // 內(nèi)容Id
  @property (nonatomic, strong) NSString *op_time; // 點(diǎn)擊事件操作時(shí)間
  @property (nonatomic, strong) NSString *start_time; // 頁(yè)面事件開(kāi)始時(shí)間
  @property (nonatomic, strong) NSString *end_time; // 頁(yè)面事件結(jié)束時(shí)間
  
  @end
  
  
  @interface KTBehaviorUpLoadData : NSObject
  @property (nonatomic, strong) NSString *app_type; //
  @property (nonatomic, strong) NSString *app_version;
  @property (nonatomic, strong) NSString *os_type; // 1蘋(píng)果iOS
  @property (nonatomic, strong) NSString *os_version; // 系統(tǒng)版本
  @property (nonatomic, strong) NSString *device_id; // 設(shè)備id
  @property (nonatomic, strong) NSString *user_id; // 用戶(hù)id
  @property (nonatomic, strong) NSString *login_account; // 用戶(hù)賬號(hào)
  @property (nonatomic, strong) NSString *screen; // 屏幕分辨率...
  @property (nonatomic, strong) NSMutableArray <KTBehaviorData *>*datas;
      
  @end

存儲(chǔ)&&上報(bào):

在APP結(jié)束時(shí)歸檔存儲(chǔ)、APP啟動(dòng)時(shí)上傳給服務(wù)器肆捕、上傳失敗則將歸檔數(shù)據(jù)重新寫(xiě)入單例追加刷晋。

  • 寫(xiě)入

    @implementation KTBehaviorDataManager
    + (void)load {
    
        //殺死程序 (但當(dāng)程序位于后臺(tái)唄殺死不執(zhí)行)
        __block id observer1 = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
            NSLog(@"殺死程序---將數(shù)據(jù)寫(xiě)入本地");
            //將數(shù)據(jù)寫(xiě)入本地
            [[KTBehaviorDataManager sharedManager] writeBehaviorData];
            
            [[NSNotificationCenter defaultCenter] removeObserver:observer1];
        }];
    
    
    //程序切換至后臺(tái)
        __block id observer2 = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
            NSLog(@"程序切換至后臺(tái)---將數(shù)據(jù)寫(xiě)入本地");
            //將數(shù)據(jù)寫(xiě)入本地
            [[KTBehaviorDataManager sharedManager] writeBehaviorData];
            
            [[NSNotificationCenter defaultCenter] removeObserver:observer2];
        }];
    }
    
  • 上傳

    @implementation KTBehaviorDataUpLoader
    + (void)load {
      //程序啟動(dòng)、上報(bào)記錄
      __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
      
          [KTBehaviorDataUpLoader upLoadData];
          [[NSNotificationCenter defaultCenter] removeObserver:observer];
      }];
    }
    

打點(diǎn):

打點(diǎn)的方式有很多慎陵、但本質(zhì)上都一樣眼虱。只是打點(diǎn)的代碼書(shū)寫(xiě)位置不同而已。

這里有一點(diǎn)需要注意一下:
在將捕獲的信息寫(xiě)入manager的時(shí)候席纽、記得加上安全保障捏悬。因?yàn)檎麄€(gè)app里有很多地方都將會(huì)對(duì)manager進(jìn)行操作、雖然出現(xiàn)資源搶奪的問(wèn)題不大润梯、但是并不代表永遠(yuǎn)不會(huì)过牙。

 #import "KTBehaviorDataManager.h"
  - (void)pushKTBehaviorDataWithModel:(KTBehaviorData *)model {
  
      //線(xiàn)程鎖、保證數(shù)據(jù)完整性
      @synchronized(self) {
        [self.data.datas addObject:model];
      }
  
  }

代碼埋點(diǎn)

看著多仆救、但如果你把代碼封裝一下抒和。就會(huì)發(fā)現(xiàn)少很多了

  - (void)submitBtnClick {
      KTBehaviorData *data = [[KTBehaviorData alloc] init];
      data.op_type = @"2";
      data.page_code = @"push";
      data.event_code = @"submitBtnClick";
      data.object_id = @{@"title":@"xx",@"content":@"xx"};
      data.op_time = [NSDate getCurrentTimeStamp];
      [[KTBehaviorDataManager sharedManager] pushKTBehaviorDataWithModel:data];
  }

當(dāng)然矫渔、你可以把打點(diǎn)的方法抽離一下彤蔽、更精簡(jiǎn)一些而不使用Model。不過(guò)到了方法內(nèi)部之后庙洼、都一樣顿痪。

  [[KTBehaviorDataManager sharedManager] pushKTBehaviorDataWithPageId:@"xxx" objectId:@"xxx"];

稍微高級(jí)點(diǎn)、一個(gè)記錄圖片上傳速度的埋點(diǎn)油够。

  - (void)upLoadPic {
  
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          // Do the work in background
          KTBehaviorData * data = [KTBehaviorData new];
          data.op_type = @"3";
          data.page_code = @"ViewController";
          data.event_code = @"upLoadPic";
          data.start_time =[KTBehaviorData getNowTimeTimestamp];
          //圖片上傳
          [NSThread sleepForTimeInterval:5];
          
          data.end_time = [KTBehaviorData getNowTimeTimestamp];
          
          [[KTBehaviorDataManager sharedManager] pushKTBehaviorDataWithModel:data];
          NSLog(@"頁(yè)面IO埋點(diǎn)----%@",[data dicValue]);
      });
      
  }

這樣蚁袭、就完成了一次提交按鈕被點(diǎn)擊的記錄。包括時(shí)間石咬、控制器揩悄、事件、參數(shù)等鬼悠。
只要你的模型結(jié)構(gòu)足夠健壯删性、我們完全可以用一個(gè)模型記錄APP內(nèi)的各種事件亏娜。

  • 結(jié)合剛才說(shuō)的寫(xiě)入&&上報(bào)。大概這樣的效果


    上報(bào)

聲明埋點(diǎn)

通過(guò)runtime為控件動(dòng)態(tài)添加屬性蹬挺。
然后在創(chuàng)建控件時(shí)為屬性賦值维贺。

  KTBehaviorData *parameter = [[KTBehaviorData alloc] init];
  parameter.bid = @"bid";
  parameter.lab = @{@"poi_id":@"1"};
  button.kt_clickParams = parameter;

然后在事件發(fā)生時(shí)進(jìn)行記錄。


無(wú)痕埋點(diǎn)

簡(jiǎn)而言之巴帮、有兩點(diǎn)溯泣。

  • 替換方法:通過(guò)swizzle對(duì)事件進(jìn)行hook。
    這里榕茧、我提供兩種方式垃沦。
  • 1、通過(guò)類(lèi)別Hook原生方法:網(wǎng)上最普遍的方式雪猪。對(duì)event事件栏尚、table代理、頁(yè)面生命周期等方法進(jìn)行Hook只恨、但是無(wú)法直接對(duì)業(yè)務(wù)參數(shù)進(jìn)行捕獲译仗。

解決方案可以通過(guò)對(duì)NSObject擴(kuò)展出一個(gè)打點(diǎn)專(zhuān)用結(jié)構(gòu)體來(lái)獲取、但是本質(zhì)上需要污染了業(yè)務(wù)代碼官觅。

  • 2纵菌、hook指定Class中的指定方法:然后在指定方法中通過(guò)獲取class指定屬性值的方式捕獲參數(shù)。這要感謝《xuhaoranLeo》提供的方案休涤。

在下文中我會(huì)對(duì)兩種方式進(jìn)行說(shuō)明并且舉例咱圆。

  • 篩選記錄:通過(guò)plist文件。通過(guò)文件名:pageId功氨、方法名:enevtId等方式序苏、自動(dòng)為模型參數(shù)賦值。

替換方法:

  • 通過(guò)類(lèi)別Hook原生方法

現(xiàn)在還在這個(gè)階段大家對(duì)swizzle應(yīng)用都比較頻繁了捷凄、沒(méi)什么必要解釋太多忱详。直接貼代碼吧

  • 舉個(gè)例子
    頁(yè)面進(jìn)出、停留時(shí)間:

    @implementation UIViewController (KTHook)
    
    + (void)load {
        static dispatch_once_t onceToken;
          dispatch_once(&onceToken, ^{
        
              SEL originalSelector1 = @selector(viewWillAppear:);
              SEL swizzledSelector1 = @selector(kt_viewWillAppear:);
              [KTHook swizzlingInClass:[self class] originalSelector:originalSelector1 swizzledSelector:swizzledSelector1];
            
              SEL originalSelector2 = @selector(viewWillDisappear:);
              SEL swizzledSelector2 = @selector(kt_viewWillDisappear:);
              [KTHook swizzlingInClass:[self class] originalSelector:originalSelector2 swizzledSelector:swizzledSelector2];
          });
        }
    #pragma mark - Method Swizzling
    - (void)kt_viewWillAppear:(BOOL)animated
    {
      NSLog(@"進(jìn)入");
    
      [[KTBehaviorDataManager sharedManager]pushKTBehaviorDataWithPageId:NSStringFromClass([self class]) time:[KTBehaviorData getNowTimeTimestamp]];
      [self kt_viewWillAppear:animated];
    }
    
    
    - (void)kt_viewWillDisappear:(BOOL)animated
    {
      NSLog(@"離開(kāi)");
      [[KTBehaviorDataManager sharedManager]pushKTBehaviorDataWithPageId:NSStringFromClass([self class]) time:[KTBehaviorData getNowTimeTimestamp]];
      [self kt_viewWillDisappear:animated];
    }
    
頁(yè)面停留時(shí)間

同理跺涤、我們通過(guò)對(duì)UIControl的Event事件匈睁、UITableView代理等進(jìn)行hook、進(jìn)行無(wú)痕埋點(diǎn)桶错。
具體方式網(wǎng)上有很多航唆、千篇一律。我就不寫(xiě)了院刁、因?yàn)椴环衔蚁胍@取頁(yè)面參數(shù)的需求糯钙、貼出兩個(gè)教學(xué)帖想要這么實(shí)現(xiàn)的可以自取。
《iOS 打點(diǎn)方案設(shè)計(jì)》《iOS動(dòng)態(tài)性(二)可復(fù)用而且高度解耦的用戶(hù)統(tǒng)計(jì)埋點(diǎn)實(shí)現(xiàn)》

  • hook指定Class中的指定方法

思路就是上面寫(xiě)的任岸。實(shí)現(xiàn)的代碼也不難鸳玩、hook過(guò)SDK文件的童鞋應(yīng)該都知道。這里為了方便演闭、我們用了一個(gè)封裝好的工具不跟。 《Aspects》

  @implementation NSObject (KTAspectsHook)

  + (void)load {
      __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
          [self setupBehaviorObj];
          [[NSNotificationCenter defaultCenter] removeObserver:observer];
      }];
  }
  
  #pragma mark - private method
  //hook所有需要打點(diǎn)的對(duì)象方法
  - (void)setupBehaviorObj {
  
      Class clazz = NSClassFromString(@"ViewController");
      //具體事件方法
      SEL selector = NSSelectorFromString(@"upLoadPic");
      
      [clazz aspect_hookSelector:selector withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo) {
          NSLog(@"ViewController中upLoadPic方法被調(diào)用、參數(shù):aaa==%@",[[aspectInfo instance] valueForKey:@"aaa"]);
  
      } error:NULL];
      }
  
  @end

打印:

2018-01-24 14:43:21.419519+0800 kTBehaviorDemo[4587:363679] ViewController中upLoadPic方法被調(diào)用米碰、參數(shù):aaa==我是參數(shù)aaa

這樣窝革、調(diào)用者、調(diào)用方法吕座、參數(shù)虐译。三大要素就都已經(jīng)可以獲取到了。
但如何進(jìn)行批量埋點(diǎn)吴趴?

篩選記錄

用plist漆诽、這個(gè)網(wǎng)上也很多帖子。之前提的兩個(gè)帖子也都提及了锣枝。

上段代碼可以修改如下:

  + (void)setupBehaviorObj {


      NSDictionary *behaviorPlist = [self getBehaviorEvents];

      for (NSString * className in behaviorPlist) {
          //需要hook的Class
          Class clazz = NSClassFromString(className);

          //對(duì)應(yīng)Class需要hook的方法名
          NSDictionary *events = behaviorPlist[className];

          if (events[kBehaviorEvents]) {
              //事件數(shù)組
              for (NSDictionary *event in events[kBehaviorEvents]) {

                  //具體事件方法
                  SEL selector = NSSelectorFromString(event[kBehaviorEventSelectorName]);

                  [clazz aspect_hookSelector:selector withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo) {

                      //獲取參數(shù)
                      NSMutableDictionary * parameterDic = [NSMutableDictionary new];
                      if (event[kBehaviorParameter]) {

                          NSDictionary * dic = [NSObject properties_apsWithObj:[aspectInfo instance]];
                          for (NSString * parameterStr in event[kBehaviorParameter]) {
    
                              if ([dic valueForKey:parameterStr]) {
                                [parameterDic setValue:[dic valueForKey:parameterStr] forKey:parameterStr];
                              }
                          }
                      }

                      KTBehaviorData * data = [KTBehaviorData new];
                      data.op_time = [KTBehaviorData getNowTimeTimestamp];
                      data.event_code = event[kBehaviorEventId];
                      data.object_dic = parameterDic;
                      data.page_code = event[kBehaviorPageId];
                      data.op_type = event[kBehaviorType];

                      [[KTBehaviorDataManager sharedManager]pushKTBehaviorDataWithModel:data];


                  } error:NULL];

              }
          }
      }

  }

控制臺(tái)信息:


這樣厢拭、只要你的plist足夠健壯。確實(shí)可以做到幾乎完全無(wú)痕的埋點(diǎn)撇叁。

結(jié)束語(yǔ):

《demo在此》

年前比較忙供鸠、但開(kāi)了帖總要填完。所以可能有些錯(cuò)別字和語(yǔ)法坑陨闹。

每個(gè)項(xiàng)目的需求不同楞捂、情況也不同。所以這只是個(gè)demo趋厉、希望能為大家提供一個(gè)思路寨闹、并沒(méi)有封裝成一個(gè)SDK。
  • 不同的情況君账、可以用不同的打點(diǎn)方案繁堡。所謂無(wú)痕、并不一定是最好的杈绸、太暴力了帖蔓。
  • 還有就是當(dāng)項(xiàng)目很龐大的時(shí)候矮瘟、進(jìn)行hook操作瞳脓、會(huì)不會(huì)影響性能。如果影響了澈侠、有沒(méi)有什么改進(jìn)的方式劫侧。
  • 如果你有什么好的想法、或者是項(xiàng)目中有什么更好的方案。還望指教烧栋。

補(bǔ)充:

經(jīng)測(cè)写妥。
當(dāng)導(dǎo)入方法為300時(shí)、肉眼無(wú)感审姓。
當(dāng)導(dǎo)入方法為3000時(shí)珍特、約1s。
當(dāng)導(dǎo)入方法為30000時(shí)魔吐、約15s扎筒。
由于在+load中加載、這段時(shí)間會(huì)算入app啟動(dòng)白屏的時(shí)間內(nèi)酬姆。


最后

本文主要是自己的學(xué)習(xí)與總結(jié)嗜桌。如果文內(nèi)存在紕漏、萬(wàn)望留言斧正辞色。如果不吝賜教小弟更加感謝骨宠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市相满,隨后出現(xiàn)的幾起案子层亿,更是在濱河造成了極大的恐慌,老刑警劉巖立美,帶你破解...
    沈念sama閱讀 218,640評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棕所,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡悯辙,警方通過(guò)查閱死者的電腦和手機(jī)琳省,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)躲撰,“玉大人针贬,你說(shuō)我怎么就攤上這事÷5埃” “怎么了桦他?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,011評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)谆棱。 經(jīng)常有香客問(wèn)我快压,道長(zhǎng),這世上最難降的妖魔是什么垃瞧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,755評(píng)論 1 294
  • 正文 為了忘掉前任蔫劣,我火速辦了婚禮,結(jié)果婚禮上个从,老公的妹妹穿的比我還像新娘脉幢。我一直安慰自己歪沃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布嫌松。 她就那樣靜靜地躺著沪曙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪萎羔。 梳的紋絲不亂的頭發(fā)上液走,一...
    開(kāi)封第一講書(shū)人閱讀 51,610評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音贾陷,去河邊找鬼育灸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛昵宇,可吹牛的內(nèi)容都是我干的磅崭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瓦哎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼砸喻!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蒋譬,我...
    開(kāi)封第一講書(shū)人閱讀 39,257評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤割岛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后犯助,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體癣漆,經(jīng)...
    沈念sama閱讀 45,717評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評(píng)論 3 336
  • 正文 我和宋清朗相戀三年剂买,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惠爽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,021評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瞬哼,死狀恐怖婚肆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坐慰,我是刑警寧澤较性,帶...
    沈念sama閱讀 35,735評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站结胀,受9級(jí)特大地震影響赞咙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜糟港,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評(píng)論 3 330
  • 文/蒙蒙 一攀操、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧着逐,春花似錦崔赌、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,936評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至秀姐,卻和暖如春慈迈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背省有。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,054評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工痒留, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蠢沿。 一個(gè)月前我還...
    沈念sama閱讀 48,224評(píng)論 3 371
  • 正文 我出身青樓伸头,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親舷蟀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子恤磷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評(píng)論 2 355