成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

iOS 端容器之 WKWebView 那些事

網絡
熟悉 iOS\macOS Hybrid 混合開發的同學應該都有體會,WKWebView 雖然是蘋果作為替代 UIWebView\WebView 而推出的"新"組件,但大部分開發者對它實在“愛不起來”。畢竟對于國內大部分應用開發者來說,在實際使用中 WKWebView 所謂的“優勢”未必能體現出來,但帶來的“坑”卻都著實都不淺。

 [[413463]]

一 背景

熟悉 iOS\macOS Hybrid 混合開發的同學應該都有體會,WKWebView 雖然是蘋果作為替代 UIWebView\WebView 而推出的"新"組件,但大部分開發者對它實在“愛不起來”。畢竟對于國內大部分應用開發者來說,在實際使用中 WKWebView 所謂的“優勢”未必能體現出來,但帶來的“坑”卻都著實都不淺。

目前社區或線上可查找的 WKWebView 相關資料,大多比較陳舊且人云亦云、復制粘貼類的居多。少部分真實實踐和探索的開發者,或許也因時間或精力的原因,對問題和解決方案未能做詳細的闡述。導致目前線上 WKWebView 相關的資料數量不少、但質量不高;且有不少文章存在對問題的背景解釋不清,解決方案缺乏有效驗證等問題。

我從事端容器領域開發多年,曾在生產環境方案設計上與 WKWebView "對抗"多次。目前混合開發已經是現代 App 標配,一方面是對這么長時間用法經驗上的總結,另外一方面也希望能夠為還在抗爭中的同學提供一些新視角或者解決思路,故準備結合 WebKit 部分源碼,將自己對這個組件的理解以及部分問題解決方案整理分享一下。本文嘗試說明 3 件事情:

WKWebView 使用中的典型問題有哪些

為什么會出現這些問題

這些問題的解決辦法有哪些

二 基礎回顧

iOS 端網絡設計和 WKWebView 設計特點我們可以通過官方資料來查閱。但為了后面更好的說明問題,下面我們重點回顧下與文章后續內容相關的兩個基本知識點:

iOS 端網絡設計與 Cookie 管理

WKWebView 多進程模型

1 iOS 網絡設計與 Cookie 管理

Cookie 管理是做混合開發過程中經常會涉及到的部分,在應用開發中我們知道可以通過 NSHTTPCookie 和NSHTTPCookieStorage 來管理應用的 Cookie。但在系統層面 Cookie 是如何管理的、如何與網絡層各模塊進行聯動,這對我們后面分析WKWebView 中的 Cookie 問題有著至關重要的聯系。

根據官方資料,我們可知 iOS 平臺下網絡相關模塊大概關系如下:

從上至下模塊依次為:

WebKit:應用層,客戶端 App 以及 WKWebView 處于這一層。
NSURL:可以理解為對底層 CF 接口的封裝擴展層,NSURLConnection、NSURLSession 等處于這一層。
CFNetwork:iOS 網絡模塊核心實現層,是網絡層設計中最重要的部分。負責網絡協議組裝發送接收等主要工作,與 CoreFoundation 框架關系緊密。
BSD socket:基于底層硬件接口的 socket 服務。
CFNetwork 是整個網絡系統的核心模塊,負責組裝請求、處理響應等:

核心內容包含:

CFURLRequest:包括 URL/header/body 這些請求的信息。CFURLRequest 會進一步轉換成 CFHTTPMessage。
CFHTTPMessage:主要是 HTTP 協議的定義和轉換,把每一個請求 request 轉換成標準的 HTTP 格式的文本。
CFURLConnection:主要是處理請求任務。包括 pthread 線程、CFRunloop、請求隊列的管理等等。提供了start、cancel 等等操作的 API。
CFHost:負責 DNS,有 CFHostStartInfoResolution 等函數,基于 dns_async_start 和 getaddrinfo_async_start 等方法。
CFURLCache/CFURLCredential/CFHTTPCookie:處理 緩存/證書/cookie 相關的邏輯,都有對應的NS類。
從上面分析可知關鍵信息:iOS Cookie 管理相關模塊處于 CFNetwork 這一層中。即對于請求 Response 中的 "set-cookie" 字段,在 CFNetwork 中被消費和處理。

2 WKWebView 多進程模型

通過官方資料,我們知道 WKWebView 相比 UIWebView 很大的一個變化是"多進程模型":

WKWebView 在運行時,核心模塊運行在獨立進程中,與 App 進程獨立。

WKWebView 使各種問題的原因,有不少和多進程運行模式有很大的關系。

多進程模型詳解

但具體是什么樣形態的多進程?我們通過一張簡圖來說明下:

WKWebView(WebKit) 包含 3 種進程:UI Process, Networking Process, WebContent Process。
UI Process:即 App 進程,WKWebView(WebKit) 中部分模塊運行在此進程,會負責啟動其它進程。
Networking Process:即網絡模塊進程,主要負責 WKWebView 中網絡請求相關功能;此進程 App 中只會有啟動一次,多個 WKWebView 間共享。
WebContent Process:即 Web 模塊進程,主要負責 WebCore, JSCore 相關模塊的運行,是 WKWebView 的核心進程。此進程在 App 中會啟動多次,每個 WKWebView 會有自己獨立的 WebContent 進程。
各個進程之間通過 CoreIPC 進程通信。
總的來說:在一個客戶端 App 中,多個 WKWebView 使用中會共享一個 UI 進程(與 App 進程共享)、共享一個 Networking 進程、每個 WKWebView 實例獨享一個 WebContent 進程。

示例:

此處關于 WebContent Process 和 Networking Process 的啟動規則,官方文檔并未解釋特別清楚,且因為版本迭代等原因,文檔與目前最新規則也略有出入。為避免混淆與歧義,下面結合 WebKit 源碼稍作分析。

WebContent 進程啟動規則

根據官方文檔描述:

A WKProcessPool object represents a single process that WebKit uses to manage web content. To provide a more secure and stable experience, WebKit renders the content of web views in separate processes, rather than in your app’s process space. By default, WebKit gives each web view its own process space until it reaches an implementation-defined process limit. After that, web views with the same WKProcessPool object share the same web content process.

規則是優先使用創建新進程,當進程上線超過某閾值之后則會共享,在 WebKit 內部由 maximumProcessCount 控制。但是此規則只對 iOS13 之前的系統生效,iOS13 之后的系統,WKWebView 每次創建實例都會啟動一個新的 WebContent Porcess。相關實現如下。

iOS13 前:

iOS 13 及以后:

Networking 進程啟動規則

Networking 規則相對簡單,確保在 App 生命周期內啟動一例(Crash 之后會重新創建)。相關代碼:

三 主要問題與解決方案

WKWebView 在生產環境使用中,除去相對簡單的使用和適配問題外,容易對開發者和前端同學造成困擾的問題有 4 個:

請求代理問題
Cookie 管理問題
全面屏適配問題
WebContent 進程崩潰問題
下面分別對這 4 例問題產生的原因、可嘗試的解決方案以及不同方案下引入的問題做一下說明。

1 請求代理問題

這一點應該是阻礙 WKWebView 鋪開的首要問題。問題背景也相對簡單,并非有什么技術實現上的難度,而是蘋果官方不希望 WKWebView 請求被應用攔截,美其名曰"為了安全"。但在實際使用場景中,我們又需要對 WebView 的請求進行代理以滿足業務和性能訴求,典型場景如:離線包、流量監控等。

官方不支持、業務上又有使用場景,我們只能嘗試通過"黑魔法"來解決。目前適用面比較多的解決方案有兩個:

通過 [WKBrowsingContextController registerSchemeForCustomProtocol:] 來注冊代理,為方便簡稱為代理方案1。
通過 [WKWebViewConfiguration setURLSchemeHandler:forURLScheme:] 來注冊,為方便簡稱為代理方案 2。
目前兩種解決方案的實現方法都有較為豐富的資料和說明,在此不在贅述。

雖然這兩種方案某種程度上可以"部分解決問題",但帶來的副作用相對也不少,在生產環境中如何取舍還需具體開發同學來取舍。下面分別通過 "代理方案1" 和 "代理方案2" 代指來簡單說明下,可以供大家選型時做一個參考。

代理方案 1

此為最早出現的 WKWebView 請求代理方案,可滿足 iOS 9 及以后應用使用(目前最新為 iOS 14)。根據之前調研分析,業界大部分有代理需求的 App 采用此方案或變種方案。

1)方案思路

通過 WKBrowsingContextController 將 http(s) 注冊到 Networking 的 m_registeredSchemes 數組中。對于數組中的 Scheme,WebKit 在發起請求時會通過 WKCustomProtocol 將請求發送到 App 所在的進程,并由 App 進程來執行發送。

由于從 Networking 進程將數據發送到 App 進程時,WebKit 內有意剝離了 Body 部分(見 WebCoreArgumentCodersMac.mm):

故需要對攜帶 body 的請求做一些特殊處理。處理方案是通過在 WKWebView 內注入腳本,重寫掉 WebView 內請求發送相關方法。在請求發送之前將 body 部分序列化之后通過 bridge 傳遞到 App 進程暫存。

App 進程代理 WKWebView 請求時,根據規則按需拼接緩存的 body,完成之后再進行發送動作。

2)方案弊端

此方案雖然適用面較廣,但是弊端也很明顯。主要有兩方面:

(1)問題一:無法定向處理、只能一刀切即如果 App 采用此方案,對其所有 WKWebView 實例的發送的請求都需要代理。如果有 WKWebView 實例中并未注入腳本或者執行代理,則可能導致請求無法發送、發送缺少 body 等問題,常見于一些集成的二方庫、三方庫中的 WKWebView 實例。

(2)問題二:重寫腳本完備性很難保障由于需要在 JS 層重寫請求發送邏輯,比如 form 表單提交、AJAX、Fetch 等接口,重寫接口的質量直接決定方案的完備度。且 WKWebView 原設計有不少能力在 c++ 層面實現,僅在 JS 重寫無法保證對齊。目前已知的問題有:

對于同步請求,此方案目前無法支持。
對于流式請求,比如上傳場景,目前支持度較差。只能在 JS 側全量讀取之后再進行發送。
無法處理 Fetch API Stream 返回值。
當使用 Form 表單提交內容包含大塊數據時,可能出現丟失、Crash 等情況。

代理方案 2

此方案是基于蘋果在 iOS 11 上開放的 [WKWebViewConfiguration setURLSchemeHandler:forURLScheme:] 接口做"擴展"來實現。對于 iOS 11.3 以后的設備,此方案具備較好實用性(WebKit 處理了部分 Body 傳遞問題)。

1)方案思路

[WKWebViewConfiguration setURLSchemeHandler:forURLScheme:] 可以在 WKWebView 實例上注冊自定義請求 Scheme。如果 WKWebView 發送的請求匹配注冊 Scheme,則會代理到 UI 進程(App 進程) 執行發送動作。
WKWebView 內部默認不支持注冊 http(s) 等標準 Scheme,但是有"黑魔法"可繞過限制。
對于 AJAX 發送 BLOB 數據時,也會出現 body 丟失的情況,可以參考 代理方案1 中類似的方案來解決。
2)方案優勢

代理方案 2 相對方案 1 兩個巨大的優勢在于:

不用一刀切,配置與 WKWebView 實例綁定:即可以定向處理我們需要處理的 WKWebView 實例,對于 三方庫 中的對象,完全可以做到無影響,安全性大大提高。
不用重寫所有發送請求:大部分情況下請求中的 body 是可以被攜帶到 App 進程,即我們只需定向處理部分異常即可,健壯性大大提升。
3)方案弊端

此方案除去有 iOS 11.3 的系統版本限制外,在具體運行中也有也有不少很難處理的問題,主要如下:

(1)問題一:多圖分片下載情況下,WKWebView 內部存在處理時序存在 BUG

問題表現:在 WKWebView 中加載大圖、且大圖數據存在存在分片返回時,WKWebView 內部時序處理異常可能導致 圖片無法展示、圖片展示不完整等問題。具體可結合 WebKit 中對圖片加載的流程來簡單說明下:

問題即出現在上述 step1, step2, step3 的執行順序上。在異常情況下,會偶現執行順序為:step1 -> step3 -> step2, 且 step3 不再被觸發(allDataReceived),進而導致圖片最終的內容未渲染上屏。

解決方案:目前暫無有效的解決辦法,通過配置 suppressesIncrementalRendering 配置為 YES 某種程度上可以緩解問題,但并無法根治且對體驗略有影響。

(2)問題二:iOS 12及以下系統系統同步 AJAX 導致 Crash

問題表現:在 WKWebView 中如果出現 Web 頁面發送 sync request,則可導致 WebContent 進程崩潰,WKWebView 回調 webViewWebContentProcessDidTerminate,進而導致頁面白屏等問題。此問題可明確是 WebKit 內部的 BUG,且已有相關 Fix:

Bug1: WebURLSchemeHandlerProxy::loadSynchronously crash with sync request(2018-08-06 14:14 ):https://bugs.webkit.org/show_bug.cgi?id=188358

 

Bug2: WKURLSchemeHandler crashes when sent errors with sync XHR(2019-06-20 01:20):https://bugs.webkit.org/show_bug.cgi?id=199063

處理方案:對于 Bug1,處理相對比較簡答,即在網絡請求回調 error 之前優先回調部分空數據,規避掉問題;但是對于 Bug2,目前缺少有效的解決辦法。

(3)問題三:301 請求下 SWAP 導致頁面無法轉場問題

問題表現:如果頁面中存在使用 301 做重定向的情況,可能會出現重定向頁面無法加載的情況,進而導致頁面異常、白屏等問題。

處理方案:關閉 processSwapsOnNavigation,將置為 NO(內部屬性)。

總的來說,雖然代理方案 2 相比代理方案 1 有很大的優勢,但此方案因為版本限制等原因,目前使用量相比代理方案 1 略低。且與代理方案 1 相比,此方案的優勢和劣勢都很明顯,如多圖分片場景下可能導致圖片無法展示的問題,目前未找到有效的解決辦法。方案 2 是否可替代方案 1 在生產環境使用,還需使用同學自己斟酌。

2 Cookie 問題

根據官方文檔及資料,我們可知 WKWebView 因為其"獨立存儲",導致 Cookie 和 Cache 與 App 不互通,進而有問題。但是這種表述較為模糊,且實際使用中 WKWebView 與 App 的 Cookie 并非完全隔離,這種模棱兩可的表現很難讓人搞清楚"通"或"不通"的邊界在哪里。

下面首先根據自己對這塊的理解,嘗試說明下 WKWebView 使用 Cookie 問題到底是什么、以及背后的原因。由于蘋果并未對全部代碼開源,下有不少內容是自己的理解和推斷,無法保證完全正確,僅介紹部分思路和判斷,供大家在需要時參考。

Cookie 管理策略

根據上節的背景介紹我們可知,iOS Cookie 相關內容,是在 CFNetwork 這一層由 CFHTTPCookie、CFHTTPCookieStorage 等來管理,是 CFNetwork 模塊的一部分。且對于 Session Cookie 和 持久化 Cookie,系統有著不同的管理策略:

Session Cookie:內存中保存,進程周期內生效。在 iOS 移動端,一個 App 進程 即對應于一個 Session,即 Session Cookie 可在進程內共享。
持久化 Cookie:這部分 Cookie 除保存內存以外,還會持久化到磁盤,可多次使用。本地文件存儲在 沙箱文件夾/Library/Cookies/Cookies.binarycookies;需要特別注意的是:持久化 Cookie 并非在產生之后立即同步到 Cookies.binarycookies,根據經驗會有一個 300ms ~ 3s 的延遲。

WKWebView Cookie 問題

基于上節的 iOS Cookie 管理、結合多進程模型,我們大概可以推斷 App 與 WKWebView Cookie 管理模型,見如下簡圖:

注意:WKHTTPCookieStore 為示意,畫到了 Networking 進程,實際情況中此模塊分散在 WebContent、Networking 以及 UI Process 中,且各進程中的部分通過 IPC 橋接。

根據上圖可以引導出 WKWebView Cookie 相關的 2 個核心點:

1)WKWebView Cookie 問題具體是什么

對于 "Session Cookie":App 進程與 WKWebView 進程(WebContent + Networking)之間 完全隔離。
對于 "持久化 Cookie":App 進程與 WKWebView 進程(WebContent + Networking)之間 同步存在時差。
2)造成 WKWebView Cookie 問題的根本原因

App 進程 與 Networking 雙進程的設計。

核心目標

在了解 WKWebView 問題以及對應的根本原因之后,如何來處理此問題相對也清晰了:根據是否采用代理了 WKWebView 的網絡請求,我們需要不同的處理策略。

場景 1 - 未代理 WKWebView 網絡請求:Cookie 完全由 Networking 進程管理,WKWebView 內可自閉環。大部分情況下 App 進程也無需感知,如果確實需要感知,可以根據業務場景選擇 JS 橋接、強制持久化等方案。
場景 2 - 已代理 WKWebView 網絡請求:Cookie 大部分是由 App 進程來管理,此時應該采用何種同步策略。
由于場景 1 中我們并未在生產環境中采用,故本文不打算做冒然分析。下面主要聚焦于場景 2 來做進一部分分析。在場景 2 下我們的核心目標:

對于 App 進程中產生的 Cookie,能夠及時同步到 Networking 進程:主要解決 Reponse 中存在 "Set-Cookie" 情況下,JS 端如何及時讀取相關 Cookie 的問題。
對于 WebContent 中由 JS 產生的 Cookie,能及時同步到 App 進程:主要解決在 JS 端產生 Cookie 之后,我們如何保證在后續代理的網絡請求中可被正常攜帶的問題。

同步手段

在確認方案之前,我們首先要搞清楚一個問題:客戶端側 Cookie 來源有哪些?

對于 App 進程,Cookie 來源有兩個:

通過 NSHTTPCookieStorage 寫入的。
在網絡請求 Response Header 中通過 "Set-Cookie" 寫入的。
對于 WebContent 進程,主要是 JS 通過 document.cookie 寫入的(網絡代理之后 Set-Cookie 不會在 WKWebView 進程中生效)。

其次,我們要確認可用做同步的手段有哪些:

對于 iOS 11 之后的系統,蘋果已經為我們提供了 WKHTTPCookieStore 對象用來讀寫、監聽 WKWebView 對應的 Cookie,可以直接使用。

對于 iOS 11 之前的系統,需要區分處理一下。

從 App 進程同步到 Networking 進程,簡單流程如下:

第1步,需要把 Session Cookie 持久化,臨時保存(注意需要標識,以供恢復)。
第2步,調用 NSHTTPCookieStorage 內部接口 _saveCookies 觸發強制同步。
第3步,恢復臨時保存的 Session Cookie,避免污染。
由于 Networking 進程不會產生 Cookie,所以我們下面要做的是從 WebContent 進程同步 Cookie:處理策略即在 JS 側重寫 document.cookie 方法,在 JS 修改 cookies 時,通過 bridge 將 cookie 傳遞到 App 進程。

處理方案

在理清楚問題、目標和可用手段之后,我們即可總結出 WKWebView Cookie 相關問題的處理方案:

對于 iOS 11 及之后的系統,我們可以通過 HOOK NSHTTPCookieStorage 中讀寫 Cookie 的接口,并且監聽網絡請求中 "Set-Cookie" 關鍵字,在 App 進程 Cookie 發生變化時同步到 WKWebView;同時通過 WKHTTPCookieStore 提供 cookiesDidChangeInCookieStore 能力來監聽 WKWebView 中 Cookie 的變化。
對于 iOS 11 之前的系統,處理策略類似。但是我們需要過 NSHTTPCookieStorage 接口來做強制同步,并且需要注意恢復 Cookie 的 SessionOnly 屬性;同時需要通過在 JS 側重寫 document.cookie 的方式,來感知 WKWebView 中 Cookie 的變化。
特別注意:

采用 iOS 11 之后方案處理時一定要注意,對 WKHTTPCookieStore 的操作會 涉及到 IPC 通信,如果通信過于頻繁、通信數據量過大,會產生明顯的性能問題。極端情況可能造成 IPC 模塊異常,出現所有 WKWebView 都無法加載的情況。比如典型的場景,如果一個頁面請求較多、每個請求都帶"Set-Cookie"、且業務上為了簡單,每次把 App 進程的 Cookie 全量同步到 WKWebView,則 Cookie 過多時,有一定概率(暴力測試可復現)觸發 IPC 異常,導致后續所有 WKWebView 實例都無法正常加載,只有 App 殺進程才可恢復。建議在同步 Cookie 時,盡量按需同步變化的部分。

3 全面屏適配問題

全面屏適配問題相對不復雜,但因為 WKWebView 如 UIWebView 在表現上的不同,導致容易造成一些困擾。

問題是 UIWebView 與 WKWebView 在對前端 viewport-fit 支持表現上略有差別:UIWebView 對 viewport-fit 支持度較好,表現基本與官方文檔表述一致。但是 WKWebView 中存在一個潛規則,如果 Web 頁面內 body 的高度,在沒有超出 WKWebView 組件實際高度時,viewport-fit=cover 可能不生效。

處理辦法是在頁面中規避掉此類情況,如配置 body height 為 100vh (或其它類似方案)。

4 WebContent 進程崩潰問題

這是一個出現概率不高,但是缺乏通用、有效解決辦法的問題。我們知道 WKWebView 多進程模式下,如果 WebContent 進程因為各種原因出現 Crash,則 WKWebView 會通過 webViewWebContentProcessDidTerminate 回調告訴開發者,一般情況下我們會通過 reload 方法重新加載頁面。同時如果用戶設備內存緊張,則可能出現系統主動 KILL WebContent 進程的情況。即可能出現 App 進程(前臺)正常,但是 WebContent 崩潰、頁面重新加載的情況。

絕大部分情況,進入此流程并不一定會對用戶操作造成困擾。但是,如果此時造成內存緊張是因為前端觸發業務導致,典型如表單中喚起相機上傳圖片,此流程對用戶的影響可能是致命的。即使我們通過 WebView reload 使頁面恢復,用戶在執行的上傳動作也會被打斷,導致提交流程出現異常、影響用戶的操作。且如果用戶設備進入此狀態,大部分情況下用戶再次操作還會觸發同樣的流程。

這種情況下,用戶無法及時感知到造成問題的根本原因,絕大多數直觀反應即為:“App 出現 bug 了!”故從用戶角度來看,缺少自動恢復、處理問題的辦法。

目前此問題缺乏有效、統一解決辦法,一種解決思路是客戶端與前端配置,針對核心、可能出現異常的流程,定向設計解決方案。通過端側的能力來將數據持久化,在類似異常發生之后使用持久化數據恢復現場,盡量在用戶無感的情況下保證用戶操作流程正常。

四 總結

以上便是我們在端容器設計開發過程中,WKWebView 使用上遇到的一些典型問題和對應的解決辦法。總的來說,目前造成這么不協調的狀態,大部分是因為系統平臺未能充分考慮開發者訴求、組件設計對歷史業務兼容性不佳導致的。當然,現在這種狀態必然也不是一種合理狀態,未來無論是系統平臺方、還是業務方、或者是開發者,當矛盾無法協調時總有一方要進行妥協。在這個時間點來臨之前,希望上面總結內容,能夠為受此類問題困擾的同學提供一些幫助。

 

責任編輯:梁菲 來源: 阿里云云棲號
相關推薦

2015-09-14 09:16:17

iOS統計打點

2019-12-10 08:00:46

Kata容器Linux

2022-10-26 09:57:52

VectorRustC++

2020-08-11 08:59:20

容器虛擬化技術

2017-01-10 13:33:51

iOS編程throttle

2011-05-19 16:47:50

軟件測試

2012-05-01 08:06:49

手機

2017-05-15 21:50:54

Linux引號

2024-02-04 17:03:30

2017-04-06 09:35:10

大數據SparkSQLSpark

2015-05-28 14:02:09

JavaJava日志性

2011-08-22 16:42:43

SqliteiPad

2011-12-02 10:32:23

Java

2014-06-06 16:08:17

初志科技

2021-10-19 21:39:51

Unsafe構造器內存

2020-09-23 09:07:16

特權賬號管理PAM網絡安全

2010-07-26 11:02:19

Perl模式匹配

2011-09-19 15:40:35

2020-07-29 08:14:59

云計算云遷移IT

2009-07-29 10:36:04

北電收購
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品一区二区电影 | 高清18麻豆| 国产大片黄色 | 在线观看国产www | 日日操夜夜干 | 国产精品久久久久久久久久久久久 | av黄色片在线观看 | 人人干在线 | 欧美日韩综合一区 | 国产成人精品一区 | 午夜精品久久久久久久久久久久久 | 亚洲一区二区久久 | 国产高潮好爽受不了了夜色 | 草樱av | 午夜精品视频 | 国产欧美在线 | 日韩h| 亚洲狠狠丁香婷婷综合久久久 | 全免一级毛片 | 国产电影一区二区 | 中文字幕乱码一区二区三区 | 日本一区二区在线视频 | 久久久久一区二区三区 | 亚洲精品久久久久中文字幕欢迎你 | 91精品国产综合久久久动漫日韩 | av二区三区| 国产最新视频在线 | 国产精品久久久久久久久动漫 | 成年视频在线观看 | 一区二区视频在线观看 | 伊人久久精品一区二区三区 | 免费看欧美一级片 | 国产成人一区二区三区 | 欧美成人免费在线 | 91资源在线 | 日韩精品999| 日韩午夜精品 | 狠狠色狠狠色综合系列 | 丝袜美腿一区二区三区动态图 | 国产一区二区中文字幕 | 男女羞羞视频大全 |