Android——Webview使用詳解

基本使用

1.WebView設(shè)置
// 獲取當前頁面的 
URLpublic String getUrl();
// 獲取當前頁面的原始 URL(重定向后可能當前 url 不 同)
// 就是 http headers 的 Referer 參數(shù)毡们,loadUrl 時為 null
public String getOriginalUrl();
// 獲 取當前頁面的標題 
public String getTitle();
// 獲取當前頁面的 
faviconpublic Bitmap getFavicon();
// 獲取當前頁面的加載進度 
public int getProgress();
// 通知 WebView 內(nèi)核網(wǎng)絡(luò)狀態(tài)
// 用于設(shè)置 JS 屬性`window.navigator.isOnline`和產(chǎn)生 HTML5 事件 `online/offline`
public void setNetworkAvailable(boolean networkUp)
// 設(shè)置初始縮放比例 
public void setInitialScale(int scaleInPercent)席揽;
2.WebSettings設(shè)置
WebSettings settings = web.getSettings();
// 存儲(storage)
// 啟用 HTML5 DOM storage API,默認值 false
settings.setDomStorageEnabled(true); 
// 啟用 Web SQL Database API党巾,這個設(shè)置會影響同一進程內(nèi) 的所有 WebView话原,默認值 false
// 此 API 已不推薦使用蕾管,參考:https://www.w3.org/TR/webdatabase/
settings.setDatabaseEnabled(true); 
// 啟用 Application Caches API,必需設(shè)置有效的緩存路徑才 能生效啡氢,默認值 false
// 此 API 已廢棄状囱,參考: https://developer.mozilla.org/zh-CN/docs/Web/HTML/Using_the_application_cache
settings.setAppCacheEnabled(true);
settings.setAppCachePath(context.getCacheDir().getAbsolutePath());
// 定位(location)
settings.setGeolocationEnabled(true);
// 是否保存表單數(shù)據(jù)
settings.setSaveFormData(true); 
// 是否當webview調(diào)用requestFocus時為頁面的某個元素設(shè)置焦點, 默認值 true
settings.setNeedInitialFocus(true);
// 是否支持 viewport 屬性倘是,默認值 false// 頁面通過`<meta name="viewport" ... />`自適應手機屏幕
settings.setUseWideViewPort(true); 
// 是否使用 overviewmode 加載頁面亭枷,默認值 false// 當頁面寬 度大于 WebView 寬度時,縮小使頁面寬度等于 WebView 寬度
settings.setLoadWithOverviewMode(true); 
// 布局算法
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
// 是否支持 Javascript搀崭,默認值 false
settings.setJavaScriptEnabled(true); 
// 是否支持多窗口叨粘,默認值 false
settings.setSupportMultipleWindows(false); 
// 是否可用 Javascript(window.open)打開窗口猾编,默認 值 false
settings.setJavaScriptCanOpenWindowsAutomatically(false);
// 資源訪問
settings.setAllowContentAccess(true); 
// 是否可訪問 Content Provider 的資源,默認值 true
settings.setAllowFileAccess(true); 
// 是否可訪問本地文件升敲,默認值 true
// 是否允許通過 file url 加載的 Javascript 讀取本地文件答倡,默認值 false
settings.setAllowFileAccessFromFileURLs(false); 
// 是否允許通過 file url 加載的 Javascript 讀取全部資源(包括文件,http,https),默認值 false
settings.setAllowUniversalAccessFromFileURLs(false);
// 資源加載
settings.setLoadsImagesAutomatically(true); 
// 是否自動加載圖片
settings.setBlockNetworkImage(false); 
// 禁止加載網(wǎng)絡(luò)圖片
settings.setBlockNetworkLoads(false); 
// 禁止加載所有網(wǎng)絡(luò)資源
// 縮放(zoom)
settings.setSupportZoom(true);
// 是否支持縮放
settings.setBuiltInZoomControls(false); 
// 是否使用內(nèi)置縮放機制
settings.setDisplayZoomControls(true); 
// 是否顯示內(nèi)置縮放控件
// 默認文本編碼驴党,默認值 "UTF-8"
settings.setDefaultTextEncodingName("UTF-8");
settings.setDefaultFontSize(16); 
// 默認文字尺寸瘪撇,默認值 16,取值范圍 1-72
settings.setDefaultFixedFontSize(16); 
// 默認等寬字體尺寸港庄,默認值 16
settings.setMinimumFontSize(8); 
// 最小文字尺寸倔既,默認值 8
settings.setMinimumLogicalFontSize(8); 
// 最小文字邏輯尺寸,默認值 8
settings.setTextZoom(100); 
// 文字縮放百分比鹏氧,默認值 100
// 字體
settings.setStandardFontFamily("sans-serif"); 
// 標準字體叉存,默認值 "sans-serif"
settings.setSerifFontFamily("serif"); 
// 襯線字體,默認值 "serif"
settings.setSansSerifFontFamily("sans-serif"); 
// 無襯線字體度帮,默認值 "sans-serif"
settings.setFixedFontFamily("monospace"); 
// 等寬字體歼捏,默認值 "monospace"
settings.setCursiveFontFamily("cursive"); 
// 手寫體(草書),默認值 "cursive"
settings.setFantasyFontFamily("fantasy"); 
// 幻想體笨篷,默認值 "fantasy"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    // 用戶是否需要通過手勢播放媒體(不會自動播放)瞳秽,默認值 true
    settings.setMediaPlaybackRequiresUserGesture(true);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // 5.0 以上允許加載 http 和 https 混合的頁面(5.0 以下默認允許,5.0+默認禁止)
    settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    // 是否在離開屏幕時光柵化(會增加內(nèi)存消耗)率翅,默認值 false
    settings.setOffscreenPreRaster(false);
}
if (isNetworkConnected(context)) {
    // 根據(jù) cache-control 決定是否從網(wǎng)絡(luò)上取數(shù)據(jù)
    settings.setCacheMode(WebSettings.LOAD_DEFAULT);
} else {
    // 沒網(wǎng)练俐,離線加載,優(yōu)先加載緩存(即使已經(jīng)過期)
    settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}
// deprecated
settings.setRenderPriority(WebSettings.RenderPriority.HIGH);
settings.setDatabasePath(context.getDir("database", Context.MODE_PRIVATE).getPath());
settings.setGeolocationDatabasePath(context.getFilesDir().getPath());
3.WebViewClient設(shè)置
// 攔截頁面加載冕臭,返回 true 表示宿主 app 攔截并處理了該 url腺晾,否則返回 false 由當前 WebView 處理
// 此 方法在 API24 被廢棄,不處理 POST 請求 
public boolean shouldOverrideUrlLoading(WebView view, String url) {
    return false;
}
// 攔截頁面加載辜贵,返回 true 表示宿主 app 攔截并處理了該 url悯蝉,否則返回 false 由當前 WebView 處理
// 此 方法添加于 API24,不處理 POST 請求托慨,可攔截處理子 frame 的非 http 請求 
@TargetApi(Build.VERSION_CODES.N) 
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    return shouldOverrideUrlLoading(view, request.getUrl().toString());
}
// 此方法廢棄于 API21鼻由,調(diào)用于非 UI 線程
// 攔截資源請求并返回響應數(shù)據(jù),返回 null 時 WebView 將繼續(xù)加 載資源 
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
    return null;
}
// 此方法添加于 API21厚棵,調(diào)用于非 UI 線程
// 攔截資源請求并返回數(shù)據(jù)蕉世,返回 null 時 WebView 將繼續(xù)加載資 源
@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
    return shouldInterceptRequest(view, request.getUrl().toString());
}
// 頁面(url)開始加載 
public void onPageStarted(WebView view, String url, Bitmap favicon) {}
// 頁面(url)完成加載 
public void onPageFinished(WebView view, String url) {}
// 將要加載資源(url)
public void onLoadResource(WebView view, String url) {}
// 這個回調(diào)添加于 API23,僅用于主框架的導航
// 通知應用導航到之前頁面時婆硬,其遺留的 WebView 內(nèi)容將不 再被繪制狠轻。
// 這個回調(diào)可以用來決定哪些 WebView 可見內(nèi)容能被安全地回收,以確保不顯示陳舊的內(nèi)容
// 它 最早被調(diào)用彬犯,以此保證 WebView.onDraw 不會繪制任何之前頁面的內(nèi)容向楼,隨后繪制背景色或需要加載的新內(nèi)容查吊。 
// 當 HTTP 響應 body 已經(jīng)開始加載并體現(xiàn)在 DOM 上將在隨后的繪制中可見時,這個方法會被調(diào)用蜜自。
// 這個回 調(diào)發(fā)生在文檔加載的早期菩貌,因此它的資源(css,和圖像)可能不可用卢佣。
// 如果需要更細粒度的視圖更新重荠,查看 postVisualStateCallback(long, WebView.VisualStateCallback).
// 請注意這上邊的所有條件也支持 
postVisualStateCallback(long, WebView.VisualStateCallback) 
public void onPageCommitVisible(WebView view, String url) {}
// 此方法廢棄于 API23
// 主框架加載資源時出錯 
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {}
// 此方法添加于 API23
// 加載資源時出錯,通常意味著連接不到服務(wù)器
// 由于所有資源加載錯誤都會調(diào)用此 方法虚茶,所以此方法應盡量邏輯簡單
@TargetApi(Build.VERSION_CODES.M) 
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
    if (request.isForMainFrame()) {
        onReceivedError(view, error.getErrorCode(), error.getDescription().toString(), request.getUrl().toString());
    }
}
// 此方法添加于 API23
// 在加載資源(iframe,image,js,css,ajax...)時收到了 HTTP 錯誤(狀態(tài) 碼>=400)
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {}
// 是否重新提交表單戈鲁,默認不重發(fā)
public voidonFormResubmission(WebView view, Message dontResend, Message resend) {
    dontResend.sendToTarget();
}
// 通知應用可以將當前的 url 存儲在數(shù)據(jù)庫中,意味著當前的訪問 url 已經(jīng)生效并被記錄在內(nèi)核當中嘹叫。
// 此 方法在網(wǎng)頁加載過程中只會被調(diào)用一次婆殿,網(wǎng)頁前進后退并不會回調(diào)這個函數(shù)。
public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {}
// 加載資源時發(fā)生了一個 SSL 錯誤罩扇,應用必需響應(繼續(xù)請求或取消請求)
// 處理決策可能被緩存用于后續(xù)的 請求婆芦,默認行為是取消請求 
public void onReceivedSslError(WebViewview, SslErrorHandlerhandler, SslError error) {
    handler.cancel();
}
// 此方法添加于 API21,在 UI 線程被調(diào)用
// 處理 SSL 客戶端證書請求喂饥,必要的話可顯示一個 UI 來提供 KEY消约。 
// 有三種響應方式:proceed()/cancel()/ignore(),默認行為是取消請求
// 如果調(diào)用 proceed()或 cancel()员帮,Webview 將在內(nèi)存中保存響應結(jié)果且對相同的"host:port"不會再次調(diào)用 onReceivedClientCertRequest
// 多數(shù)情況下或粮,可通過 KeyChain.choosePrivateKeyAlias 啟動一個 Activity 供用戶選擇合適的私鑰
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
    request.cancel();
}
// 處理 HTTP 認證請求,默認行為是取消請求 
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
    handler.cancel();
}
// 通知應用有個已授權(quán)賬號自動登陸了 
public void onReceivedLoginRequest(WebView view, String realm, String account, String args) {}
// 給應用一個機會處理按鍵事件
// 如果返回 true捞高,WebView 不處理該事件氯材,否則 WebView 會一直處理,默 認返回 false
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
    return false;
}
// 處理未被 WebView 消費的按鍵事件
// WebView 總是消費按鍵事件硝岗,除非是系統(tǒng)按鍵或 shouldOverrideKeyEvent 返回 true
// 此方法在按鍵事件分派時被異步調(diào)用 
public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
    super.onUnhandledKeyEvent(view, event);
}
// 通知應用頁面縮放系數(shù)變化
public void onScaleChanged(WebView view, float oldScale, float newScale) {}
4. WebChromeClient設(shè)置
// 獲得所有訪問歷史項目的列表氢哮,用于鏈接著色。
public void getVisitedHistory(ValueCallback < String[] > callback) {}
// <video /> 控件在未播放時型檀,會展示為一張海報圖命浴,HTML 中可通過它的'poster'屬性來指定。
// 如果未 指定'poster'屬性贱除,則通過此方法提供一個默認的海報圖生闲。
public Bitmap getDefaultVideoPoster() {
    return null;
}
// 當全屏的視頻正在緩沖時,此方法返回一個占位視圖(比如旋轉(zhuǎn)的菊花)。
public View getVideoLoadingProgressView() {
    return null;
}
// 接收當前頁面的加載進度 
public void onProgressChanged(WebView view, int newProgress) {}
// 接收文檔標題 
public void onReceivedTitle(WebView view, String title) {}
// 接收圖標(favicon)
public void onReceivedIcon(WebView view, Bitmap icon) {}
// Android 中處理 Touch Icon 的方案
// http://droidyue.com/blog/2015/01/18/deal-with-touch-icon-in-android/index.html
public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed) {}
// 通知應用當前頁進入了全屏模式,此時應用必須顯示一個包含網(wǎng)頁內(nèi)容的自定義 View
public void onShowCustomView(View view, CustomViewCallback callback) {}
// 通知應用當前頁退出了全屏模式洗出,此時應用必須隱藏之前顯示的自定義 View
public void onHideCustomView() {}
// 顯示一個 alert 對話框 
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    return false;
}
// 顯示一個 confirm 對話框 
public boolean onJsConfirm(WebViewview, Stringurl, Stringmessage, JsResult result) {
    return false;
}
// 顯示一個 prompt 對話框 
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
    return false;
}
// 顯示一個對話框讓用戶選擇是否離開當前頁面 
public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
    return false;
}
// 指定源的網(wǎng)頁內(nèi)容在沒有設(shè)置權(quán)限狀態(tài)下嘗試使用地理位置 API镀娶。
// 從 API24 開始,此方法只為安全的源 (https)調(diào)用变骡,非安全的源會被自動拒絕 
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {}
// 當前一個調(diào)用 onGeolocationPermissionsShowPrompt() 取消時护昧,隱藏相關(guān)的 UI庄拇。
public void onGeolocationPermissionsHidePrompt() {}
// 通知應用打開新窗口 
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
    return false;
}
// 通知應用關(guān)閉窗口 
public void onCloseWindow(WebView window) {}
// 請求獲取取焦點 
public void onRequestFocus(WebView view) {}
// 通知應用網(wǎng)頁內(nèi)容申請訪問指定資源的權(quán)限(該權(quán)限未被授權(quán)或拒 絕)
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void onPermissionRequest(PermissionRequest request) {
    request.deny();
}
// 通知應用權(quán)限的申請被取消倍啥,隱藏相關(guān)的 UI禾乘。
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void onPermissionRequestCanceled(PermissionRequest request) {}
// 為'<input type="file" />'顯示文件選擇器,返回 false 使用默認處理 
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView webView, ValueCallback < Uri[] > filePathCallback, FileChooserParams fileChooserParams) {
    return false;
}
// 接收 JavaScript 控制臺消息 
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
    return false;
}

Webview 加載優(yōu)化

  • 使用本地資源替代
    可以將一些資源文件放在本地的 assets 目錄, 然后重寫 WebViewClient
    的 shouldInterceptRequest 方法虽缕,對訪問地址進行攔截始藕,當 url 地址命中本地配置的 url 時,使用本地資源替代氮趋,否則就使用網(wǎng)絡(luò)上的資源伍派。
mWebview.setWebViewClient(new WebViewClient() {
    // 設(shè)置不用系統(tǒng)瀏覽器打開,
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
    }
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) { // 如 果命中本地資源, 使用本地資源替代
        if (mDataHelper.hasLocalResource(url)) {
            WebResourceResponse response = mDataHelper.getReplacedWebResourceResponse(ge tApplicationContext(), url);
            if (response != null) {
                return response;
            }
        }
        return super.shouldInterceptRequest(view, url);
    }
    @TargetApi(VERSION_CODES.LOLLIPOP) @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest reques t) {
        String url = request.getUrl().toString();
        if (mDataHelper.hasLocalResource(url)) {
            WebResourceResponse response = mDataHelper.getReplacedWebResourceResponse(getApplicatio nContext(), url);
            if (response != null) {
                return response;
            }
        }
        return super.shouldInterceptRequest(view, request);
    }
});
  • WebView 初始化慢,可以在初始化同時先請求數(shù)據(jù)剩胁,讓后端和網(wǎng)絡(luò)不要閑著诉植;
  • 后端處理慢,可以讓服務(wù)器分 trunk 輸出昵观,在后端計算的同時前端也加載網(wǎng)絡(luò)靜態(tài)資源晾腔;
  • 腳本執(zhí)行慢,就讓腳本在最后運行啊犬,不阻塞頁面解析灼擂;
  • 同時,合理的預加載椒惨、預緩存可以讓加載速度的瓶頸更戌椭痢;
  • WebView 初始化慢康谆,就隨時初始化好一個 WebView 待用领斥;
  • DNS 和鏈接慢,想辦法復用客戶端使用的域名和鏈接沃暗;
  • 腳本執(zhí)行慢月洛,可以把框架代碼拆分出來,在請求頁面之前就執(zhí)行好孽锥。

內(nèi)存泄漏

直接 new WebView 并傳入 application context 代替在 XML 里面聲明以防止 activity 引用被濫用嚼黔,能解決 90+%的 WebView 內(nèi)存泄漏。

vWeb = new WebView(getContext().getApplicationContext());
container.addView(vWeb);
銷毀 WebView
if (vWeb != null) {
    vWeb.setWebViewClient(null);
    vWeb.setWebChromeClient(null);
    vWeb.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
    vWeb.clearHistory();
    ((ViewGroup) vWeb.getParent()).removeView(vWeb);
    vWeb.destroy();
    vWeb = null;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惜辑,一起剝皮案震驚了整個濱河市唬涧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盛撑,老刑警劉巖碎节,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異抵卫,居然都是意外死亡狮荔,警方通過查閱死者的電腦和手機胎撇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殖氏,“玉大人晚树,你說我怎么就攤上這事⊙挪桑” “怎么了爵憎?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長总滩。 經(jīng)常有香客問我纲堵,道長巡雨,這世上最難降的妖魔是什么闰渔? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮铐望,結(jié)果婚禮上冈涧,老公的妹妹穿的比我還像新娘。我一直安慰自己正蛙,他們只是感情好督弓,可當我...
    茶點故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乒验,像睡著了一般愚隧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锻全,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天狂塘,我揣著相機與錄音,去河邊找鬼鳄厌。 笑死荞胡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的了嚎。 我是一名探鬼主播泪漂,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼歪泳!你這毒婦竟也來了萝勤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤呐伞,失蹤者是張志新(化名)和其女友劉穎敌卓,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荸哟,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡假哎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年瞬捕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舵抹。...
    茶點故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡肪虎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惧蛹,到底是詐尸還是另有隱情扇救,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布香嗓,位于F島的核電站迅腔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏靠娱。R本人自食惡果不足惜沧烈,卻給世界環(huán)境...
    茶點故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望像云。 院中可真熱鬧锌雀,春花似錦、人聲如沸迅诬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侈贷。三九已至惩歉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俏蛮,已是汗流浹背撑蚌。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嫁蛇,地道東北人锨并。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像睬棚,于是被迫代替她去往敵國和親第煮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,446評論 2 359

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