WebViewClient 簡介 API 案例



設計思想理解

在WebView的設計中,不是什么事都要WebView類干的,有相當多的雜事是分給其他類做的,這樣WebView專心干好自己的解析、渲染工作就行了。比如我們最熟知的,所有針對WebView的設置都封裝到了 WebSettings里。我們知道,在使用WebView加載資源過程中,可能會有大量各種類型事件的回調,為了方便開發組處理這些回調, 針對不同的事件回調,google將這些回調進行了分類集合,於是就產生了WebViewClient、WebChromeClient這兩個大類。

很多同學一看到WebChromeClient類里有Chrome,立馬就會想到google的Chrome瀏覽器,其實這里並不是"特指"Chrome瀏覽器的意思,而是"泛指"瀏覽器 的意思。

為什么叫WebChromeClient呢?這是 因為WebChromeClient中集合了影響瀏覽器的事件到來時的回調方法,所以這里需要突出瀏覽器的概念,而Chrome則是google自家的瀏覽器名稱,也是目前市面上最受歡迎的瀏覽器,所以就采用了WebChromeClient來做為名稱吧,純屬臆想……

簡單來說就是
  • WebViewClient:在影響【View】的事件到來時,會通過WebViewClient中的方法回調通知用戶
  • WebChromeClient:當影響【瀏覽器】的事件到來時,就會通過WebChromeClient中的方法回調通知用法。

回調事件總結

WebViewClient就是幫助WebView處理各種 通知、請求事件的,常用到的如:
  1. onLoadResource、onPageStart、onPageFinish
  2. onReceiveError、onReceivedHttpError、onReceivedSslError
  3. shouldInterceptRequest、shouldOverrideKeyEvent、shouldOverrideUrlLoading
  4. onReceivedClientCertRequest、onReceivedHttpAuthRequest、onReceivedLoginRequest
  5. 其他:doUpdateVisitedHistory、onFormResubmission、onPageCommitVisible、onRenderProcessGone、onScaleChanged、onUnhandledKeyEvent

實際使用的話,如果你的WebView只是用來處理一些html的頁面內容,只用WebViewClient就行了,如果需要更豐富的處理效果,比如JS、進度條等,就要用到WebChromeClient。

API

shouldInterceptRequest 方法

  • WebResourceResponse  shouldInterceptRequest(WebView view, WebResourceRequest request)  Notify the host application of a resource request and allow the application to return the data. 通知資源請求的主機應用程序,並允許應用程序返回數據。
    • If the return value is null, the WebView will continue to load the resource as usual. Otherwise, the return返回的 response and data will be used. NOTE: This method is called on a thread other than而不是 the UI thread so clients should exercise caution謹慎 when accessing private data or the view system. 
    • 該函數會在請求資源前調用,且無論任何資源,比如超鏈接、JS文件、圖片等,在每一次請求資源時都會回調我們可以通過返回一個自定義的WebResourceResponse來讓WebView加載指定的資源。比如,如果我們需要改變網頁的背景,替換網頁中圖片等,都可以在這個回調時處理。但是必須注意的是,此回調是在非UI線程中執行的。
    • 參數 request:Object containing the details of the request. 包含請求的詳細信息的對象
    • 返回值:A WebResourceResponse containing the response information or null if the WebView should load the resource itself.
例如,替換所有的圖片為自定義的圖片
if (request.getUrl().toString().endsWith(".jpg")) {
    try {
        return new WebResourceResponse("text/html", "UTF-8", view.getContext().getAssets().open("icon.jpg"));
    } catch (IOException e) {
        e.printStackTrace();
    }
}
return null;
  • WebResourceResponse  shouldInterceptRequest(WebView view, String url)  This method was deprecated in API level 21. Use shouldInterceptRequest(WebView, WebResourceRequest) instead.
  • boolean  shouldOverrideKeyEvent(WebView view, KeyEvent event)  Give the host application a chance to handle the key event synchronously. 給主機應用程序一次同步處理鍵事件的機會。默認行為返回false。
    • e.g. 例如 menu shortcut菜單快捷鍵 key events need to be filtered過濾 this way. If return true, WebView will not handle the key event. If return false, WebView will always handle the key event, so none of the super in the view chain will see the key event.
    • 重寫此方法才能夠處理在瀏覽器中的按鍵事件。如果應用程序想要處理該事件則返回true,否則返回false。
    • 返回值True if the host application wants to handle the key event itself, otherwise return false. 

shouldOverrideUrlLoading 方法

boolean  shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
 Give the host application a chance to take over the control when a new url is about to be loaded in the current WebView.  當一個新的url即將加載到當前的WebView中時,讓主機應用程序有機會接管控制權。
    • 當加載的網頁需要重定向的時候就會回調這個函數,告知我們應用程序是否需要接管控制網頁加載,如果應用程序接管並且return true,意味着主程序接管網頁加載,如果返回false,則會讓webview自己處理。
    • 由於每次超鏈接在加載前都會先走shouldOverrideUrlLoading回調,所以如果我們想攔截某個URL(比如將其轉換成其它URL進行自定義跳轉,或彈吐司等其他操作)可以在這里做。
    • If WebViewClient is not provided, by default WebView will ask Activity Manager to choose the proper handler正確的處理程序 for the url. If WebViewClient is provided, return true means the host application handles the url, while return false means the current WebView handles the url. 則返回true表示主機應用程序處理該url,而返回false表示當前的WebView處理該URL。
    • 根據以上描述可以知道:我們只需僅僅給WebView設置一個WebViewClient對象,而不需要重寫shouldOverrideUrlLoading方法(即使用它的默認回調)就可以實現在此WebView中加載網頁中的其他URL了。現在大部分APP采用的重寫shouldOverrideUrlLoading的做法大都是畫蛇添足(當然如果需要自定義跳轉的話,是一定要重寫此方法的)。
    • 參數 request:Object containing the details of the request.
    • 返回值 返回true則當前應用程序要自己處理這個url, 返回false則不處理
Notes:
This method is not called for requests using the POST "method".  當請求的方式是"POST"方式時這個回調是不會通知的。
This method is also called for subframes with non-http schemes,  這種方法也被稱為具有非http方案的子幀
    thus it is strongly disadvised勸止,勸阻(某人做某事) to unconditionally(無條件地) call loadUrl(String) 
    from inside the method 
  • boolean   shouldOverrideUrlLoading(WebView view, String url)  This method was deprecated in API level 24. Use shouldOverrideUrlLoading(WebView, WebResourceRequest) instead.

Error回調

  • void  onReceivedError(WebView view, int errorCode, String description, String failingUrl)  This method was deprecated in API level 23. Use onReceivedError(WebView, WebResourceRequest, WebResourceError) instead.
  • void  onReceivedError(WebView view, WebResourceRequest request, WebResourceError error)  Report web resource loading error to the host application. 向主機應用程序報告Web資源加載錯誤
    • 當瀏覽器訪問指定的網址發生錯誤時會通知我們應用程序,比如網絡錯誤。我們可以在這里做錯誤處理,比如再請求加載一次,或者提示404的錯誤頁面。
    • These errors usually indicate表示 inability to connect to the server無法連接到服務器. Note that unlike the deprecated廢棄 version of the callback, the new version will be called for any resource (iframe, image, etc), not just for the main page. Thus因此, it is recommended to perform minimum required work 執行最低要求的工作 in this callback.
    • 參數 requestThe originating request.
    • 參數 errorInformation about the error occured.
onPageFinished tells you that the WebView has stopped loading, onReceivedError tells you there was an error.
They're not "success" and "failure" callbacks which is why you'll get both in case of an error.
也即:onPageFinished僅僅表示網頁加載完成了,不能說明這個網頁是否成功的加載了。
  • void  onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse)  Notify the host application that an HTTP error has been received from the server while loading a resource. 通知主機應用程序在加載資源時從服務器收到HTTP錯誤。
    • HTTP errors have status codes >= 400. This callback will be called for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to perform minimum required work 執行最低要求的工作 in this callback. 
    • Note that the content of the server response服務器響應的內容 may not be provided within the errorResponse parameter 參數中可能不提供.
    • 參數 requestThe originating request.
    • 參數 errorResponseInformation about the error occured.
  • void  onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)  Notify the host application that an SSL error occurred while loading a resource. 當網頁加載資源過程中發現SSL錯誤時回調。
    • The host application must call either handler.cancel() or handler.proceed(). Note that the decision決定 may be retained保留 for use in response用來響應 to future SSL errors. The default behavior is to cancel the load.
    • HTTPS協議是通過SSL來通信的,所以當使用HTTPS通信的網址出現錯誤時,就會通過onReceivedSslError回調通知過來
    • SslErrorHandler只有兩個函數proceed()和cancel()。proceed()表示忽略錯誤繼續加載,cancel()表示取消加載。在onReceivedSslError的默認實現中是使用的cancel()來取消加載,所以一旦出來SSL錯誤,HTTPS網站就會被取消加載了。如果想忽略錯誤繼續加載就只有重寫onReceivedSslError,並在其中調用proceed()。
    • 當HTTPS傳輸出現SSL錯誤時,錯誤會只通過onReceivedSslError回調傳過來,而不會觸發onReceivedError回調。
    • 參數 handler:An SslErrorHandler object that will handle the user's response. 處理用戶請求的對象。
    • error :The SSL error object. 包含了當前SSL錯誤的基本所有信息

開始加載和加載完成

  • void  onPageFinished(WebView view, String url)  Notify the host application that a page has finished loading. 當內核加載完當前頁面時會通知我們的應用程序
    • When onPageFinished() is called, the rendering picture渲染的圖片 may not be updated yet. To get the notification for the new Picture, use onNewPicture(WebView, Picture).
    • This method is called only for main frame.
  • void  onPageStarted(WebView view, String url, Bitmap favicon)  Notify the host application that a page has started loading.當內核開始加載訪問的url時會通知應用程序
    • This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted one time for the main frame. 對每個main frame,這個函數只會被調用一次,所以如果一個頁面包含 iframe 或者 framesets 不會另外調用一次
    • This also means that onPageStarted will not be called when the contents of an embedded frame changes, i.e. clicking a link whose target is an iframe, it will also not be called for fragment navigations (navigations to #fragment_id). 當網頁內內嵌的 frame 發生改變時也不會調用onPageStarted。即點擊目標是iframe的鏈接,也不會調用fragment導航(導航到#fragment_id)
    • 參數 Bitmap favicon(網站圖標)如果這個favicon已經存儲在本地數據庫中,則會返回這個網頁的favicon,否則返回為null。
(1) iframe 可能不少人不知道什么含義,這里我解釋下,iframe 我們加載的一張,下面有很多鏈接,我們隨便點擊一個鏈接是即當前host的一個iframe.
(2) 有個問題可能是開發者困惑的,onPageStarted和shouldOverrideUrlLoading 在網頁加載過程中這兩個函數到底哪個先被調用。
     當我們通過loadUrl的方式重新加載一個網址時候,這時候會先調用onPageStarted再調用shouldOverrideUrlLoading
     當我們在打開的這個網址點擊一個link,這時候會先調用shouldOverrideUrlLoading再調用onPageStarted。
     不過shouldOverrideUrlLoading不一定每次都被調用,只有需要的時候才會被調用。

其他回調方法

  • void  doUpdateVisitedHistory(WebView view, String url, boolean isReload)  Notify the host application to update its visited links database. 通知主機應用程序更新其訪問鏈接數據庫(更新訪問歷史)
    • 通知應用程序可以將當前的url存儲在數據庫中,意味着當前的訪問url已經生效並被記錄在內核當中。這個函數在網頁加載過程中只會被調用一次。注意網頁前進后退並不會回調這個函數。
    • 參數 urlThe url being visited. 當前正在訪問的url 
    • 參數 isReloadTrue if this url is being reloaded. 如果是true,那么這個是正在被reload的url
  • void  onFormResubmission(WebView view, Message dontResend, Message resend)  As the host application if the browser should resend data as the requested page was a result of a POST. 作為主機應用程序,如果瀏覽器應該重新發送數據,因為請求的頁面是POST的結果
    • 如果瀏覽器需要重新發送POST請求,可以通過這個時機來處理。默認是不重新發送數據。
    • 參數 dontResend:The message to send if the browser should not resend 當瀏覽器不需要重新發送數據時使用的參數。
    • 參數 resend:The message to send if the browser should resend data 當瀏覽器需要重新發送數據時使用的參數。
  • void  onLoadResource(WebView view, String url)  Notify the host application that the WebView will load the resource specified by the given url. 通知應用程序WebView即將加載 url 指定的資源。
    • 注意,每一個資源(比如圖片)的加載都會調用一次此方法。
  • void  onPageCommitVisible(WebView view, String url)  Notify the host application that WebView content left over from previous page navigations will no longer be drawn. 通知主機應用程序將不再繪制從上一頁導航遺留的WebView內容。
    • This callback can be used to determine確定 the point at which it is safe to make a recycled WebView visible, ensuring保證 that no stale陳舊的 content is shown. It is called at the earliest point at which it can be guaranteed確保 that onDraw(Canvas) will no longer draw any content from previous navigations. The next draw will display either the background color of the WebView, or some of the contents of the newly loaded page.
    • This method is called when the body of the HTTP response has started loading, is reflected in反映在 the DOM, and will be visible in subsequent隨后 draws. This callback occurs early in the document loading process在文檔加載過程的早期發生, and as such you should expect期望、明白 that linked resources (for example, css and images) may not be available.
    • This callback is only called for main frame navigations.
  • void  onReceivedClientCertRequest(WebView view, ClientCertRequest request)  Notify the host application to handle a SSL client certificate request. 通知主機應用程序來處理SSL客戶端證書請求。
    • The host application is responsible負責 for showing the UI if desired需要 and providing the keys. There are three ways to respond: proceed(), cancel() or ignore(). Webview stores the response in memory (for the life of the application) if proceed() or cancel() is called and does not call onReceivedClientCertRequest() again for the same host and port pair 針對相同的主機和端口. Webview does not store the response if ignore() is called. 
    • Note that, multiple layers多層 in chromium network stack might be caching the responses緩存響應, so the behavior for ignore is only a best case effort只是最好努力的情況. This method is called on the UI thread. During the callback, the connection is suspended暫停. 
    • For most use cases, the application program should implement the KeyChainAliasCallback interface and pass it to choosePrivateKeyAlias(Activity, KeyChainAliasCallback, String[], Principal[], Uri, String) to start an activity for the user to choose the proper alias別名. The keychain activity will provide the alias through the callback method in the implemented interface. Next the application should create an async task to call getPrivateKey(Context, String) to receive the key. 
    • An example implementation of client certificates can be seen at AOSP Browser. 
    • The default behavior is to cancel, returning no client certificate.
  • void  onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)  Notifies the host application that the WebView received an HTTP authentication request. 通知應用程序WebView接收到了一個Http auth的請求
    • The host application can use the supplied提供的 HttpAuthHandler to set the WebView's response to the request. The default behavior is to cancel the request.
    • 參數 handler用來響應WebView請求的HttpAuthHandler對象
    • 參數 host請求認證的host
    • 參數 realm認證請求所在的域
  • void  onReceivedLoginRequest(WebView view, String realm, String account, String args)  Notify the host application that a request to automatically log in the user has been processed. 通知應用程序有個自動登錄帳號過程(通知主程序執行了自動登錄請求)
    • 參數 realm :The account realm used to look up accounts. 賬戶的域名,用來查找賬戶。
    • 參數 account:An optional account 可選的賬戶. If not null, the account should be checked against accounts on the device 需要和本地的賬戶進行. If it is a valid可用 account, it should be used to log in the user.
    • 參數 args:Authenticator specific arguments used to log in the user. 驗證指定參數的登錄用戶
  • boolean  onRenderProcessGone(WebView view, RenderProcessGoneDetail detail)  Notify host application that the given webview's render process has exited. 通知主機應用程序,給定的Webview渲染進程已退出。
    • Multiple多個 WebView instances may be associated with關聯 a single render渲染 process; onRenderProcessGone will be called for each WebView that was affected受影響的. 
    • The application's implementation of this callback should only attempt to clean up the specific特定的 WebView given as a parameter作為參數提供的, and should not assume假定、假設 that other WebView instances are affected. The given WebView can't be used, and should be removed from the view hierarchy視圖層次結構, all references to it should be cleaned up, e.g any references in the Activity or other classes saved using findViewById and similar calls, etc等等. To cause an render process crash for test purpose 為了測試目的,導致渲染過程崩潰, the application can call loadUrl("chrome://crash") on the WebView. 
    • Note that multiple WebView instances may be affected if they share共享 a render process, not just而不僅僅是 the specific WebView which loaded chrome://crash.
    • 參數 detail:the reason why it exited.
    • 返回值:true if the host application handled the situation情況 that process has exited, otherwise, application will crash if render process crashed, or be killed if render process was killed by the system.
  • void  onScaleChanged(WebView view, float oldScale, float newScale)  Notify the host application that the scale applied to the WebView has changed.
    • WebView顯示縮放比例發生改變時調用
  • void  onTooManyRedirects(WebView view, Message cancelMsg, Message continueMsg)  This method was deprecated in API level 8. This method is no longer called. When the WebView encounters a redirect loop, it will cancel the load.
  • void  onUnhandledKeyEvent(WebView view, KeyEvent event)  Notify the host application that a key was not handled by the WebView. 通知主機應用程序,一個鍵未被WebView處理。
    • Except system keys, WebView always consumes消耗 the keys in the normal flow正常流中的鍵 or if shouldOverrideKeyEvent returns true. 
    • This is called asynchronously異步 from where the key is dispatched調用. It gives the host application a chance to handle the unhandled key events.
    • 注意:如果事件為MotionEvent,則事件的生命周期只存在方法調用過程中,如果WebViewClient想要使用這個Event,則需要復制Event對象。

案例

public class MyWebViewClient extends WebViewClient {
	private ProgressBar mProgressBar;
	private WebViewActivity activity;
	
	public MyWebViewClient(WebViewActivity activity) {
		super();
		this.activity = activity;
		mProgressBar = activity.getProgress_bar();
	}
	
	@Override
	public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
		//通知主機應用程序更新其訪問鏈接數據庫(更新訪問歷史)。isReload:是否是正在被reload的url
		Log.i("bqt", "【doUpdateVisitedHistory】" + url + "   " + isReload);
		super.doUpdateVisitedHistory(view, url, isReload);
	}
	
	@Override
	public void onPageStarted(WebView view, String url, Bitmap favicon) {
		//favicon(網站圖標):如果這個favicon已經存儲在本地數據庫中,則會返回這個網頁的favicon,否則返回為null
		Log.i("bqt", "【onPageStarted】" + url);
		if (mProgressBar != null) mProgressBar.setVisibility(View.VISIBLE);//在開始加載時顯示進度條
		activity.getIv_icon().setVisibility(View.GONE);
		super.onPageStarted(view, url, favicon);
	}
	
	@Override
	public void onPageFinished(WebView view, String url) {
		Log.i("bqt", "【onPageFinished】" + url);
		if (mProgressBar != null) mProgressBar.setVisibility(View.GONE);//在結束加載時隱藏進度條
		super.onPageFinished(view, url);
	}
	
	@Override
	public void onLoadResource(WebView view, String url) {
		Log.i("bqt", "【onLoadResource】" + url);//每一個資源(比如圖片)的加載都會調用一次
		super.onLoadResource(view, url);
	}
	
	@TargetApi(Build.VERSION_CODES.M)
	@Override
	public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
		//訪問指定的網址發生錯誤時回調,我們可以在這里做錯誤處理,比如再請求加載一次,或者提示404的錯誤頁面
		//如點擊一個迅雷下載的資源時【ftp://***  -10  net::ERR_UNKNOWN_URL_SCHEME】
		Log.i("bqt", "【onReceivedError】" + request.getUrl().toString() + "  " + error.getErrorCode() + "  " + error.getDescription());
		if (error.getErrorCode() == -10) view.loadUrl("file:///android_asset/h5/test.html");
		else super.onReceivedError(view, request, error);
	}
	
	@TargetApi(Build.VERSION_CODES.M)
	@Override
	public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
		//HTTP錯誤具有> = 400的狀態碼。請注意,errorResponse參數中可能不提供服務器響應的內容。
		//如【502  utf-8  text/html】【http://www.dy2018.com/favicon.ico  404    text/html】
		Log.i("bqt", "【onReceivedHttpError】" + request.getUrl().toString() + "  " + errorResponse.getStatusCode()
				+ "  " + errorResponse.getEncoding() + "  " + errorResponse.getMimeType());
		super.onReceivedHttpError(view, request, errorResponse);
	}
	
	@Override
	public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
		//HTTP錯誤具有> = 400的狀態碼。請注意,errorResponse參數中可能不提供服務器響應的內容。
		//如,點擊12306中的購票時【https://kyfw.12306.cn/otn/  3  Issued to: CN=kyfw.12306.cn,***】
		Log.i("bqt", "【onReceivedSslError】" + error.getUrl() + "  " + error.getPrimaryError() + "  " + error.getCertificate().toString());
		if (new Random().nextBoolean()) super.onReceivedSslError(view, handler, error);//默認行為,取消加載
		else handler.proceed();//忽略錯誤繼續加載
	}
	
	@Override
	public void onScaleChanged(WebView view, float oldScale, float newScale) {
		//應用程序可以處理改事件,比如調整適配屏幕
		Log.i("bqt", "【onScaleChanged】" + "oldScale=" + oldScale + "  newScale=" + newScale);
		super.onScaleChanged(view, oldScale, newScale);
	}
	
	@TargetApi(Build.VERSION_CODES.LOLLIPOP)
	@Override
	public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
		//每一次請求資源時都會回調。如果我們需要改變網頁的背景,可以在這里處理。
		//如果返回值為null,則WebView會照常繼續加載資源。 否則,將使用返回的響應和數據。
		Log.i("bqt", "【shouldInterceptRequest】" + request.getUrl().toString() + "  " + request.getMethod());
		if (new Random().nextBoolean()) return super.shouldInterceptRequest(view, request);
		else if (request.getUrl().toString().endsWith("你妹的.jpg")) {
			try {
				return new WebResourceResponse("text/html", "UTF-8", view.getContext().getAssets().open("icon.jpg"));
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
	
	@Override
	public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
		//給主機應用程序一次同步處理鍵事件的機會。如果應用程序想要處理該事件則返回true,否則返回false。
		Log.i("bqt", "【shouldOverrideKeyEvent】" + event.getAction() + "  " + event.getKeyCode());
		return super.shouldOverrideKeyEvent(view, event);
	}
	
	@TargetApi(Build.VERSION_CODES.LOLLIPOP)
	@Override
	public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
		//貌似都還是調用的廢棄的那個方法
		Log.i("bqt", "【shouldOverrideUrlLoading】" + request.getUrl().toString() + "  " + request.getMethod());
		return super.shouldOverrideUrlLoading(view, request);
	}
	
	@SuppressWarnings("deprecation")
	@Override
	public boolean shouldOverrideUrlLoading(WebView view, String url) {
		boolean b = new Random().nextBoolean();
		Log.i("bqt", "【shouldOverrideUrlLoading廢棄方法】" + b + "  " + url);
		//識別電話、短信、郵件等
		if (url.startsWith(WebView.SCHEME_TEL) || url.startsWith("sms:") || url.startsWith(WebView.SCHEME_MAILTO)) {
			Intent intent = new Intent(Intent.ACTION_VIEW);
			intent.setData(Uri.parse(url));
			view.getContext().startActivity(intent);
			return true;
		}
		
		if (b) return super.shouldOverrideUrlLoading(view, url);//沒必要折騰,只要設置了WebViewClient,使用默認的實現就行!
		else {
			view.loadUrl(url);//不去調用系統瀏覽器, 而是在本WebView中跳轉
			return true;
		}
	}
}
2017-8-15





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM