2020 年 4 月后上架APP新規則和iOS13適配

iOS 13 支持適配的機型

目前最新 iPhone 11、iPhone 11 Pro和iPhone 11 Pro Max
iPhone X、iPhone XR、iPhone XS、iPhone XS Max
iPhone 8、iPhone 8 Plus
iPhone 7、iPhone 7 Plus
iPhone 6s、iPhone 6s Plus
iPhone SE
iPod touch (第七代)

適配要求
Starting April, 2020, all iPhone and iPad apps submitted to the App Store will need to be built with the iOS 13 SDK or later. They must also support the all-screen design of iPhone XS Max or the 12.9-inch iPad Pro (3rd generation), or later.

根據官網的說法,2020年4月之后所有提交到 App Store 的 iPhone 和 iPad 應用必須使用 iOS 13 以上的 SDK 進行編譯,并支持 iPhone Xs Max 或 12.9 寸 iPad Pro (3代) 及以后版本的全屏幕設計。

1.UIWebview替換成WKWebview

第一步
全局搜索UIWebview ,將相關代碼刪除或者替換
但是第一步不能檢測到.a 文件或者一些沒有添加到項目目錄中的文件中是否使用UIWebview api 現在就需要第二步
第二步
①從終端cd到要檢查的項目根目錄
②grep -r UIWebView .
以上兩步就可以檢測出項目中的.a文件中是否調用到UIWebview ,對其進行替換或者刪除

2.私有方法 KVC不讓使用

在 iOS 13 中不再允許使用 valueForKey、setValue:forKey: 等方法獲取或設置私有屬性,雖然編譯可以通過,但是在運行時會直接崩潰。

// 崩潰 api
UITextField *textField = [searchBar valueForKey:@"_searchField"];

// 替代方案 1,使用 iOS 13 的新屬性 searchTextField
searchBar.searchTextField.placeholder = @"search";

// 替代方案 2,遍歷獲取指定類型的屬性
- (UIView *)findViewWithClassName:(NSString *)className inView:(UIView *)view{
    Class specificView = NSClassFromString(className);
    if ([view isKindOfClass:specificView]) {
        return view;
    }
   if (view.subviews.count > 0) {
        for (UIView *subView in view.subviews) {
            UIView *targetView = [self findViewWithClassName:className inView:subView];
            if (targetView != nil) {
                return targetView;
            }
        }
    }
     return nil;
}

// 調用方法
 UITextField *textField = [self findViewWithClassName:@"UITextField" inView:_searchBar];
// 崩潰 api
[searchBar setValue:@"取消" forKey:@"_cancelButtonText"];
// 替代方案,用同上的方法找到子類中 UIButton 類型的屬性,然后設置其標題
UIButton *cancelButton = [self findViewWithClassName:NSStringFromClass([UIButton class]) inView:searchBar];
[cancelButton setTitle:@"取消" forState:UIControlStateNormal];
// 崩潰 api。獲取 _placeholderLabel 不會崩潰,但是獲取 _placeholderLabel 里的屬性就會
[textField setValue:[UIColor blueColor] forKeyPath:@"_placeholderLabel.textColor"];
[textField setValue:[UIFont systemFontOfSize:20] forKeyPath:@"_placeholderLabel.font"];

// 替代方案 1,去掉下劃線,訪問 placeholderLabel
[textField setValue:[UIColor blueColor] forKeyPath:@"placeholderLabel.textColor"];
[textField setValue:[UIFont systemFontOfSize:20] forKeyPath:@"placeholderLabel.font"];

// 替代方案 2
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"輸入" attributes:@{
   NSForegroundColorAttributeName: [UIColor blueColor],
   NSFontAttributeName: [UIFont systemFontOfSize:20]
}];

3.使用藍牙需要權限申請

CBCentralManager,iOS13以前,使用藍牙時可以直接用,不會出現權限提示,iOS13后,再使用就會提示了。 在info.plist里增加

<key>NSBluetoothAlwaysUsageDescription</key> 
<string>對使用藍牙的說明文案</string>

在iOS13中,藍牙變成了和位置,通知服務等同樣的可以針對單個app授權的服務。

- (NSString*) getWifiSsid {
  if (@available(iOS 13.0, *)) {
    //用戶明確拒絕,可以彈窗提示用戶到設置中手動打開權限
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
      NSLog(@"User has explicitly denied authorization for this application, or location services are disabled in Settings.");
      //使用下面接口可以打開當前應用的設置頁面
      //[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
      return nil;
    }
    CLLocationManager* cllocation = [[CLLocationManager alloc] init];
    if(![CLLocationManager locationServicesEnabled] || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined){
      //彈框提示用戶是否開啟位置權限
      [cllocation requestWhenInUseAuthorization];
      usleep(50);
      //遞歸等待用戶選選擇
      return [self getWifiSsidWithCallback:callback];
    }
  }
  NSString *wifiName = nil;
  CFArrayRef wifiInterfaces = CNCopySupportedInterfaces();
  if (!wifiInterfaces) {
    return nil;
  }
  NSArray *interfaces = (__bridge NSArray *)wifiInterfaces;
  for (NSString *interfaceName in interfaces) {
    CFDictionaryRef dictRef = CNCopyCurrentNetworkInfo((__bridge CFStringRef)(interfaceName));
 
    if (dictRef) {
      NSDictionary *networkInfo = (__bridge NSDictionary *)dictRef;
      NSLog(@"network info -> %@", networkInfo);
      wifiName = [networkInfo objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID];
      CFRelease(dictRef);
    }
  }
  CFRelease(wifiInterfaces);
  return wifiName;
}

4.MPMoviePlayerController 被棄用

在 iOS 9 之前播放視頻可以使用 MediaPlayer.framework 中的MPMoviePlayerController類來完成,它支持本地視頻和網絡視頻播放。但是在 iOS 9 開始被棄用,如果在 iOS 13 中繼續使用的話會直接拋出異常:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.'

解決方案使用 AVFoundation 里的 AVPlayer。

5.推送的 deviceToken 獲取到的格式發生變化

原本可以直接將 NSData 類型的 deviceToken 轉換成 NSString 字符串,然后替換掉多余的符號即

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
   NSString *token = [deviceToken description];
   for (NSString *symbol in @[@" ", @"<", @">", @"-"]) {
       token = [token stringByReplacingOccurrencesOfString:symbol withString:@""];
   }
   NSLog(@"deviceToken:%@", token);
}

在 iOS 13 中,這種方法已經失效,NSData類型的 deviceToken 轉換成的字符串變成了:

{length = 32, bytes = 0xd7f9fe34 69be14d1 fa51be22 329ac80d ... 5ad13017 b8ad0736 }

解決方案
需要進行一次數據格式處理,參考友盟的做法,可以適配新舊系統,獲取方式如下

#include 
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    if (![deviceToken isKindOfClass:[NSData class]]) return;
    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat:@"xxxxxxxx",
                          ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                          ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                          ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
    NSLog(@"deviceToken:%@", hexToken);
}

6.UISearchBar 黑線處理導致崩潰

之前為了處理搜索框的黑線問題,通常會遍歷 searchBar 的 subViews,找到并刪除 UISearchBarBackground。

for (UIView *view in _searchBar.subviews.lastObject.subviews) {
    if ([view isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
        [view removeFromSuperview];
        break;
    }
}

在 iOS13 中這么做會導致 UI 渲染失敗,然后直接崩潰,崩潰信息如下:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Missing or detached view for search bar layout'

解決方案
設置 UISearchBarBackground 的 layer.contents 為 nil:

for (UIView *view in _searchBar.subviews.lastObject.subviews) {
    if ([view isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
        view.layer.contents = nil;
        break;
    }
}

7.UINavigationBar 設置按鈕邊距導致崩潰

從 iOS 11 開始,UINavigationBar使用了自動布局,左右兩邊的按鈕到屏幕之間會有 16 或 20 的邊距。
為了避免點擊到間距的空白處沒有響應,通常做法是:定義一個 UINavigationBar 子類,重寫 layoutSubviews 方法,在此方法里遍歷 subviews 獲取 _UINavigationBarContentView,并將其 layoutMargins 設置為 UIEdgeInsetsZero。

- (void)layoutSubviews {
    [super layoutSubviews];
    
    for (UIView *subview in self.subviews) {
        if ([NSStringFromClass([subview class]) containsString:@"_UINavigationBarContentView"]) {
            subview.layoutMargins = UIEdgeInsetsZero;
            break;
        }
    }
}

然而,這種做法在 iOS 13 中會導致崩潰,崩潰信息如下:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Client error attempting to change layout margins of a private view'

解決方案
使用設置 frame 的方式,讓 _UINavigationBarContentView 向兩邊伸展,從而抵消兩邊的邊距。

- (void)layoutSubviews {
    [super layoutSubviews];
    
    for (UIView *subview in self.subviews) {
        if ([NSStringFromClass([subview class]) containsString:@"_UINavigationBarContentView"]) {
            if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
                UIEdgeInsets margins = subview.layoutMargins;
                subview.frame = CGRectMake(-margins.left, -margins.top, margins.left + margins.right + subview.frame.size.width, margins.top + margins.bottom + subview.frame.size.height);
            } else {
                subview.layoutMargins = UIEdgeInsetsZero;
            }
            break;
        }
    }
}

8.使用 UISearchDisplayController 導致崩潰

在 iOS 8 之前,我們在 UITableView 上添加搜索框需要使用 UISearchBar + UISearchDisplayController 的組合方式,而在 iOS 8 之后,蘋果就已經推出了 UISearchController 來代替這個組合方式。在 iOS 13 中,如果還繼續使用 UISearchDisplayController 會直接導致崩潰,崩潰信息如下:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'UISearchDisplayController is no longer supported when linking against this version of iOS. Please migrate your application to UISearchController.'

解決方案
使用 UISearchController 替換 UISearchBar + UISearchDisplayController 的組合方案。

9.Xcode 11 創建的工程在低版本設備上運行黑屏

使用 Xcode 11 創建的工程,運行設備選擇 iOS 13.0 以下的設備,運行應用時會出現黑屏。這是因為 Xcode 11 默認是會創建通過 UIScene 管理多個 UIWindow 的應用,工程中除了 AppDelegate 外會多一個 SceneDelegate:



這是為了 iPadOS 的多進程準備的,也就是說 UIWindow 不再是 UIApplication 中管理,但是舊版本根本沒有 UIScene。
解決方案
在 AppDelegate 的頭文件加上:

@property (strong, nonatomic) UIWindow *window;

10.使用 @available 導致舊版本 Xcode 編譯出錯。

在 Xcode 11 的 SDK 工程的代碼里面使用了 @available 判斷當前系統版本,打出來的包放在 Xcode 10 中編譯,會出現一下錯誤:

Undefine symbols for architecture i386:
    "__isPlatformVersionAtLeast", referenced from:
        ...
ld: symbol(s) not found for architecture i386

從錯誤信息來看,是 __isPlatformVersionAtLeast 方法沒有具體的實現,但是工程里根本沒有這個方法。實際測試無論在哪里使用@available ,并使用 Xcode 11 打包成動態庫或靜態庫,把打包的庫添加到 Xcode 10 中編譯都會出現這個錯誤,因此可以判斷是 iOS 13 的 @available 的實現中使用了新的 api。
解決方案
如果你的 SDK 需要適配舊版本的 Xcode,那么需要避開此方法,通過獲取系統版本來進行判斷:

if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
    ...
}

另外,在 Xcode 10 上打開 SDK 工程也應該可以正常編譯,這就需要加上編譯宏進行處理

#ifndef __IPHONE_13_0
#define __IPHONE_13_0 130000
#endif

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
...
#endif

11.暗黑模式

Dark Mode iOS 13 推出暗黑模式,UIKit 提供新的系統顏色和 api 來適配不同顏色模式,xcassets 對素材適配也做了調整,具體適配可見: Implementing Dark Mode on iOS。 如果不打算適配 Dark Mode,可以直接在 Info.plist 中添加一欄:User Interface Style : Light,即可在應用內禁用暗黑模式。不過即使設置了顏色方案,申請權限的系統彈窗還是會依據系統的顏色進行顯示,自己創建的 UIAlertController 就不會

12.UISegmentedControl 默認樣式改變

默認樣式變為白底黑字,如果設置修改過顏色的話,頁面需要修改。
原本設置選中顏色的 tintColor 已經失效,新增了 selectedSegmentTintColor 屬性用以修改選中的顏色。
Web Content適配

13.textfield.leftview

如下方式,直接給 textfield.leftView 賦值一個 UILabel 對象,他的寬高會被 sizeToFit,而不是創建時的值。

// left view label
UILabel *phoneLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 63, 50)];
phoneLabel.text = @"手機號";
phoneLabel.font = [UIFont systemFontOfSize:16];
// set textfield left view
self.textfieldName.leftView = phoneLabel;

實際leftview的width為59,height為19
解決方法:嵌套一個UIView

// label
UILabel *phoneLabel = [[UILabel alloc] init];
phoneLabel.text = @"手機號";
phoneLabel.font = [UIFont systemFontOfSize:16];
[phoneLabel sizeToFit];
phoneLabel.centerY = 50/2.f;
// left view
UIView *leftView = [[UIView alloc] initWithFrame:(CGRect){0, 0, 63, 50}];
[leftView addSubview:phoneLabel];
// set textfield left view
self.textfieldName.leftView = leftView;

14.NSAttributedString優化

對于UILabel、UITextField、UITextView,在設置NSAttributedString時也要考慮適配Dark Mode,否則在切換模式時會與背景色融合,造成不好的體驗
不建議的做法

NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:16]};
NSAttributedString *str = [[NSAttributedString alloc] initWithString:@"富文本文案" attributes:dic];

推薦的做法

// 添加一個NSForegroundColorAttributeName屬性
NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor labelColor]};
NSAttributedString *str = [[NSAttributedString alloc] initWithString:@"富文本文案" attributes:dic];

15.TabBar紅點偏移

如果之前有通過TabBar上圖片位置來設置紅點位置,在iOS13上會發現顯示位置都在最左邊去了。遍歷UITabBarButton的subViews發現只有在TabBar選中狀態下才能取到UITabBarSwappableImageView,解決辦法是修改為通過UITabBarButton的位置來設置紅點的frame

16.WKWebView 中測量頁面內容高度的方式變更

iOS 13以前 document.body.scrollHeight
iOS 13中 document.documentElement.scrollHeight 兩者相差55 應該是瀏覽器定義高度變了

17.StatusBar 與之前版本不同

之前 Status Bar 有兩種狀態,default 和 lightContent
現在 Status Bar 有三種狀態,default, darkContent 和 lightContent
現在的 darkContent 對應之前的 default,現在的 default 會根據情況自動選擇 darkContent 和 lightContent

18. UIActivityIndicatorView

之前的 UIActivityIndicatorView 有三種 style 分別為 whiteLarge, white 和 gray,現在全部廢棄。
增加兩種 style 分別為 medium 和 large,指示器顏色用 color 屬性修改。

19.使用MJExtension 中處理NSNull的不同

這個直接會導致Crash的在將服務端數據字典轉換為模型時,如果遇到服務端給的數據為NSNull時, mj_JSONObject,其中 class_copyPropertyList方法得到的屬性里,多了一種EFSQLBinding類型的東西,而且屬性數量也不準確, 這個組件沒有更新的情況下,寫了一個方法swizzling掉把當遇到 NSNull時,直接轉為nil了。
其實目前我們項目在ios13下面還沒遇到這種情況,發一個之前項目處理null的方法,在項目里面寫一個NSObject的分類,添加下面的方法就可以了。大家請根據項目情況、數據格式修改下這個方法,MJ庫里面自己會進行替換的:

- (id)mj_newValueFromOldValue:(id)oldValue property:(MJProperty *)property {
    //為了解決json字符串先賦值給oc字典后,類型轉換crash問題,如:
    //json->oldValue:0
    //model中值為NSString類型
    //如果先將json轉為dic,dic中對應value值為NSNumber類型,則向oldValue發送isEqualToString消息會crash
    id tempValue = oldValue;
 
    if ([property.type.code isEqualToString:@"NSString"]) {
        tempValue = [NSString stringWithFormat:@"%@", tempValue];
 
        if ([tempValue isKindOfClass:[NSNull class]] || tempValue == nil || [tempValue isEqual:[NSNull null]] ||  [tempValue isEqualToString:@"(null)"] ||  [tempValue isEqualToString:@"(\n)"] ) {
            return @"";
        }
    }
    if ([property.type.code isEqualToString:@"NSNumber"]) {
//        tempValue = [NSNumber numberWithFloat:[tempValue floatValue]];
 
        if ([tempValue isKindOfClass:[NSNull class]] || tempValue == nil || [tempValue isEqual:[NSNull null]] ||  [tempValue isEqualToString:@"(null)"] ||  [tempValue isEqualToString:@"(\n)"] ) {
            return @0;
        }
    }
    return tempValue;
}

20.Sign In with Apple

在 iOS 13 中蘋果推出一種在 App 和網站上快速、便捷登錄的方式: Sign In With Apple。這是 iOS 13 新增的功能,因此需要使用 Xcode 11 進行開發。關于應用是否要求接入此登錄方式,蘋果在 App Store 應用審核指南 中提到:

Apps that exclusively use a third-party or social login service (such as Facebook Login, Google Sign-In, Sign in with Twitter, Sign In with LinkedIn, Login with Amazon, or WeChat Login) to set up or authenticate the user’s primary account with the app must also offer Sign in with Apple as an equivalent option.

如果你的應用使用了第三方或社交賬號登錄服務(如Facebook、Google、Twitter、LinkedIn、Amazon、微信等)來設置或驗證用戶的主賬號,就必須把 Sign In With Apple 作為同等的選項添加到應用上。如果是下面這些類型的應用則不需要添加:

  • 僅僅使用公司內部賬號來注冊和登錄的應用;
  • 要求用戶使用現有的教育或企業賬號進行登錄的教育、企業或商務類型的應用;
  • 使用政府或業界支持的公民身份識別系統或電子標識對用戶進行身份驗證的應用;
  • 特定第三方服務的應用,用戶需要直接登錄其郵箱、社交媒體或其他第三方帳戶才能訪問其內容。
    另外需要注意,關于何時要求接入 Sign In With Apple,蘋果在 News and Updates 中提到:
Starting today, new apps submitted to the App Store must follow these guidelines. Existing apps and app updates must follow them by April 2020.

2019 年 9 月 12 日 起,提交到 App Store 的新應用必須按照應用審核指南中的標準進行接入;現有應用和應用更新必須也在 2020 年 4 月前完成接入。

21.LaunchImage 被棄用

修改 App 啟動畫面時我們需要通過 Launch Images 進行修改。
在 iOS 8 蘋果引入了 LaunchScreen.storyboard,支持界面布局用的 AutoLayout + SizeClass。雖然兩種方式都可以正常工作,但是蘋果更希望開發者們能夠使用 LaunchScreen.storyboard 進行操作。
由于 Launch Images 需要在對應的 aseets 里面放入所有尺寸的 Launch Images ,這樣每當出現一個屏幕尺寸不同的設備時,都需要做出對應的修改,操作復雜。
因此在 2020 年 4 月之后,所有 App 都必須使用 LaunchScreen.storyboard 的方式操作啟動畫面,否則將無法提交到 App Store 進行審批。
解決方法
創建LaunchScreen.storyboard,拖入一個UIImageView,并設置約束為上下左右都為0,在info plist文件中添加Launch screen interface file base name:Launch Screen,在General->App Icons and Launch Images->Launch Screen File 選擇為LaunchScreen,清理項目并刪除已安裝的app

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容