WebView的使用总结

WebView是android常见的一个组件,随着混合开发的发展,越来越多的公司使用原生和h5共同开发。所以使用WebView的频率越来越高了,所以想做次总结

<a name="t0" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>WebView的常见用法

<a name="t1" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>最简单的用法

<a name="t2" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>loadUrl

loadUrl(String url);

加载一个网页,其中注意的是

1. 需要加入联网权限,

2. 还有网址必须完整即以http://或者ftp://等协议开头,不能省略!不然将加载不出来,

3. assert中的html文件。前缀换成file:///android_asset/

4. 加载sd卡中的html文件,前缀换成content://

<uses-permission android:name="android.permission.INTERNET" /> 

<a name="t3" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>loadData

public void loadData(String data, String mimeType, String encoding)

加载代码块。其中对于data可以采用encode一下再加载,速度快点

<a name="t4" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>loadDataWithBaseURL

public void loadDataWithBaseURL(String baseUrl, String data,String mimeType, String encoding, String historyUrl)

相对于loadData,其实就是一个相对路径和绝对路径的问题,loadData要求必须是绝对路径,而loadDataWithBaseURL则可以是相对路径。historyUrl可以为null。


<a name="t5" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>WebSettings的常见配置

如果我们需要设置WebView的属性,是通过WebView.getSettings()获取取设置WebView的WebSettings对象,然后调用WebSettings中的方法来实现的配置一些属性,来帮我们实现一些常见的基本操作。比如字体大小,支持缩放等

//---------------------------------------------------
// 缩放
// 1 设置支持缩放,默认true
setSupportZoom(boolean support)

// 2 设置显示缩放的组件 默认true
setDisplayZoomControls(boolean enabled)  

// 3 设置是否使用缩放的内置组件  默认false
setBuiltInZoomControls(boolean enabled) 
//--------------------------------------------------

//--------------------------------------------------
// 1 设置media 手势播放media
setMediaPlaybackRequiresUserGesture(boolean require)
//--------------------------------------------------

//--------------------------------------------------
//宽度
// 1 设置概述模式浏览界面,当页面宽度超过WebView显示宽度时,缩小页面适应WebView。默认false 
setLoadWithOverviewMode(boolean overview)    

// 2 设置支持ViewPort的meta tag属性,如果页面有ViewPort meta tag 指定的宽度,则使用meta tag指定的值,否则默认使用宽屏的视图窗口 
setUseWideViewPort(boolean use)  
//--------------------------------------------------

//--------------------------------------------------
// 字体和大小
// 1 设置页面文字缩放百分比,默认100% 
setTextZoom(int textZoom)  

// 2 设置最小字体,默认8\. 取值区间[1-72],超过范围,使用其上限值。 
setMinimumFontSize(int size)

//3 设置最小逻辑字体,默认8\. 取值区间[1-72],超过范围,使用其上限值。 
setMinimumLogicalFontSize(int size)  

//4 设置默认字体大小,默认16,取值区间[1-72],超过范围,使用其上限值。 
setDefaultFontSize(int size)

//5 设置默认填充字体大小,默认16,取值区间[1-72],超过范围,使用其上限值
setDefaultFixedFontSize(int size)  

//6 设置默认字体大小 SMALLEST is 50% SMALLER is 75% NORMAL is 100% LARGER is 150% LARGEST is 200%
setTextSize(WebSettings.TextSize t)

//7 设置标准的字体族,默认”sans-serif”。
setStandardFontFamily(String font) 

//8 设置混合字体族。默认”monospace”
setFixedFontFamily(String font) 

//9 设置SansSerif字体族。默认”sans-serif”
setSansSerifFontFamily(String font)

//10 设置SerifFont字体族,默认”sans-serif” 
setSerifFontFamily(String font) 

//11 设置CursiveFont字体族,默认”cursive” 
setCursiveFontFamily(String font)  

//12 设置FantasyFont字体族,默认”fantasy” 
setFantasyFontFamily(String font)  

//13 设置页面的编码格式,默认UTF-8
setDefaultTextEncodingName(String encoding)
//--------------------------------------------------------

//--------------------------------------------------------
//加载图片
//1 设置是否加载图片资源 包括嵌入的本地图片资源和网络图片。 默认true 
setLoadsImagesAutomatically(boolean flag)  

//2 是否加载网络图片资源 默认true
setBlockNetworkImage(boolean flag) 

//3 设置是否加载网络资源。注意如果值从true切换为false后,WebView不会自动加载,除非调用WebView#reload()
setBlockNetworkLoads(boolean flag) 
//-------------------------------------------------------

//--------------------------------------------------------
//访问
//1 设置允许访问WebView内部文件,默认true 
setAllowFileAccess(boolean allow)  

//2 设置允许获取WebView的内容URL ,可以让WebView访问ContentPrivider存储的内容。 默认true
setAllowContentAccess(boolean allow) 

//3 设置加载不安全资源的WebView加载行为,MIXED_CONTENT_ALWAYS_ALLOW和MIXED_CONTENT_NEVER_ALLOW 
setMixedContentMode(int mode)  
//--------------------------------------------------------

//缓存
//1 是否保存表单数据,默认false 
//setSaveFormData(boolean save) 

//2 是否允许数据库存储
setDatabaseEnabled(boolean flag)

//3 设置存储定位数据库的位置,考虑到位置权限和持久化Cache缓存
setGeolocationDatabasePath(String databasePath) 

//4 是否允许Cache,默认false
setAppCacheEnabled(boolean flag)

//5 设置Cache API缓存路径。
setAppCachePath(String appCachePath)

//6 是否存储页面DOM结构,默认false
setDomStorageEnabled(boolean flag) 

//7 基于WebView导航的类型使用缓存 LOAD_DEFAULT 默认加载方式 LOAD_CACHE_ELSE_NETWORK 按网络情况使用缓存 LOAD_NO_CACHE 不使用缓存 LOAD_CACHE_ONLY 只使用缓存 
setCacheMode(int mode) 

//--------------------------------------------------------

//--------------------------------------------------------
//js
//1 设置是否允许执行JS
setJavaScriptEnabled(boolean flag)  

//2 是否允许Js访问任何来源的内容。包括访问file scheme的URLs
setAllowUniversalAccessFromFileURLs(boolean flag)

//3 是否允许Js访问其他file scheme的URLs
setAllowFileAccessFromFileURLs(boolean flag)  

//4 是否允许JS自动打开窗口。默认false 
setJavaScriptCanOpenWindowsAutomatically(boolean flag)
//--------------------------------------------------------

// ------------------------------------------------------
// 其它
//1 设置WebView代理,默认使用默认值
setUserAgentString(String ua) 

//是否允许定位,默认true
setGeolocationEnabled(boolean flag)

//是否支持多窗口,如果设置为true 
setSupportMultipleWindows(boolean support)

<a name="t6" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>JS和本地的互调

<a name="t7" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>JS调用Android

主要代码:

mWebView = (WebView) findViewById(R.id.webview);  

WebSettings webSettings = mWebView.getSettings();  
webSettings.setJavaScriptEnabled(true);  
mWebView.addJavascriptInterface(mJavaInterface, "rrtoyewx");

其中

public void addJavascriptInterface(Object obj, String interfaceName)

第一个参数obj对象中实现JS调用android的实现的方法,第二个参数interfaceName是向WebView注入一个interfaceName的对象,这个对象绑定的是obj对象,即js的中调用方法的对象。

举个例子

js调用android的sendMessage的方法,并传递一个String的参数。

js代码

<html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <title>Title</title>  
        <h1>你好</h1>  
        <input type="button" value="js调native" onclick="ok()">  
    </head>  
    <body>  
        <script type="text/javascript">  
        function ok() {  
            rrtoyewx.sendMessage("我调用了android的中代码");  
        }  
        </script>  
    </body>  
</html>  

android的代码

mWebView = (WebView) findViewById(R.id.webview);  

WebSettings webSettings = mWebView.getSettings();  
webSettings.setJavaScriptEnabled(true);  
mWebView.addJavascriptInterface(mJavaInterface, "rrtoyewx");

JavaInterface的代码

public class JavaInterface{
    @JavascriptInterface 
    public void sendMessage(String message){
        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); 
    }
}

其中js调用java的代码会造成Android WebView的Js对象注入漏洞,会造成一些安全性的问题,关于这个的解决方法就是也有别人分析出并解决了

Android WebView的Js对象注入漏洞解决方案,其中对4.2以上采用@JavascriptInterface的注释,而对于4.2以下的系统

1. 不使用addJavascriptInterface的方法。

2. 在WebChromeClient的方法中的回调方法中,去解析相应的参数,方法名,然后通过反射去相应本地方法。

3. 如果存在返回值,则通过的load的方式,会调用的相应的方法。

<a name="t8" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>Android 调用js的方法

loadUrl();

直接通过loadUrl()的方式去加载js的方法。

举个例子

Android 调用js的alert的方法

Js

<html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <title>Title</title>  
        <h1 id="h">Rrtoyewx</h1>  
        <input type="button" value="js调native" onclick="ok()">  
    </head>  
    <body>  
        <script type="text/javascript">  
            function showAlert(i)  
            {  
                ....
            }  
        </script>  
    </body>  
</html> 

Android 的代码

mWebView.loadUrl("javascript:showAlert(“java调用了js的方法”)");  

如果js的方法存在返回值,一种方式需要用js调用java的方式将返回值作为返回。而4.4之后,还有另一种方式,通过evaluateJavascript的方法去调用js的方法,并在valueCallBack的回调方法“onReceiveValue(String value)”的方法回调。

public void evaluateJavascript("methodName",valueCallBack)
mWebView.evaluateJavascript("getGreetings()", new ValueCallback() {  
       @Override  
       public void onReceiveValue(String value) {  
           Log.d("Rrtoyewx", value);  
       }  
   }); 

注意,回调方法在主线程,第二,返回值只接受string的


<a name="t9" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>WebViewClient的回调方法

<a name="t10" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onPageStarted

public void onPageStarted(WebView view, String url, Bitmap favicon)   

当前页面开始加载时调用,我们可以在其中做一些准备的工作,比如加载processbar

<a name="t11" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onPageFinished

public void onPageFinished(WebView view, String url)  

当前页面的加载完成时调用,我们可以在其中释放一个资源,和关闭一些东西

<a name="t12" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>shouldOverrideUrlLoading

public boolean shouldOverrideUrlLoading(WebView view, String url)

函数会在加载其他的链接时回调,表示webview是否屏蔽的这个链接,默认返回false,如果返回true则表示不会加载这个url了。我们可以在其中屏蔽一些操作。

<a name="t13" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onReceivedError

public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)  

参数的说明:WebView view:当前的WebView实例,int errorCode:错误码,String description:错误描述,String failingUrl:当前出错的URL。一般加载本地的404界面的,即出现一个错误提示。

<a name="t14" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onReceivedSslError

public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error) 

HTTPS协议是通过SSL来通信的,所以当使用HTTPS通信的网址(以https://开头的网站)出现错误时,就会回调的该方法,参数说明

WebView view:当前的WebView实例,SslErrorHandler handler:SslErrorHandler.proceed()和SslErrorHandler.cancel(),SslErrorHandler.proceed()表示忽略错误继续加载,SslErrorHandler.cancel()表示取消加载。在onReceivedSslError的默认实现中是使用的SslErrorHandler.cancel()来取消加载。SslError error:当前的的错误对象,SslError包含了当前SSL错误的基本所有信息。

注意

1 onReceivedSslError回调,不一定会回调onReceivedError的方法。

2 加载默认的onReceivedSslError的会出现的白屏。

3 可以忽略这个错误继续加载的

<a name="t15" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>shouldInterceptRequest

public WebResourceResponse shouldInterceptRequest(WebView view,  
        String url) ;

当页面中许多的资源文件,每请求一个资源文件,都会回调这个方法,这个不主线程调用。所以我们可以在请求资源的时候,在这里屏蔽一些操作

<a name="t16" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onLoadResource

public void onLoadResource(WebView view, String url

请求资源文件的时候调用,

<a name="t17" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onScaleChanged

public void onScaleChanged(WebView view, float oldScale, float newScale)  

webView的发生缩放改变的时候调用

<a name="t18" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>shouldOverrideKeyEvent

public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event)  

屏蔽一个按键的操作,返回false,则不屏蔽,交给webview处理,true反之

<a name="t19" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onFormResubmission

onFormResubmission(WebView view, Message dontResend, Message resend)  

设置是否重发数据,post的请求的时候,默认不重新发送

<a name="t20" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>doUpdateVisitedHistory

doUpdateVisitedHistory(WebView view, String url, boolean isReload) 

通知主机程序更新访问的链接

<a name="t21" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onUnhandledInputEvent

onUnhandledInputEvent(WebView view, InputEvent event) 

让主程序处理WebView未处理的Input Event。

<a name="t22" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onReceivedLoginRequest

onReceivedLoginRequest(WebView view, String realm, String account, String args)

自动登录请求的回调方法


<a name="t23" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>WebChromeClient的事件

<a name="t24" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onJsAlert

public boolean onJsAlert(WebView view, String url, String message,JsResult result)

网页调用alert的时候调用

<a name="t25" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onJsConfirm(),返回值代表是否消费, JsResult 的cancle的方法和con

public boolean onJsConfirm(WebView view, String url, String message,JsResult result)

网页调用confirm的时候调用,返回值代表是否消费,

<a name="t26" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onJsPrompt

public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) 

网页调用prompt的时候调用,返回值代表是否消费,

<a name="t27" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onConsoleMessage

public boolean onConsoleMessage(ConsoleMessage consoleMessage)

打印console的消息的时候,常用来监视js代码的错误

<a name="t28" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onProgressChanged

 public void onProgressChanged(WebView view, int newProgress)

加载页面的进度的改变的时候,

<a name="t29" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onReceivedTitle

public void onReceivedTitle(WebView view, String title)

页面的title的发生变化时候的回调

<a name="t30" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onReceivedIcon

public void onReceivedIcon(WebView view, Bitmap icon)

接受到新的icon的回调方法

<a name="t31" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onReceivedTouchIconUrl

public void  onReceivedTouchIconUrl(WebView view, String url, boolean precomposed)

页面的按下图标的icon的url

<a name="t32" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>getVisitedHistory

public void getVisitedHistory(ValueCallback callback)

获取访问页面的访问历史

<a name="t33" style="box-sizing: border-box; background: transparent; color: rgb(79, 161, 219); text-decoration: none; margin: 0px; padding: 0px; font-weight: 400; outline: 0px;"></a>onShowFileChooser

public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback,FileChooserParams fileChooserParams)

试图打开文件的浏览器的回调方法,其中fileChooserParams对象包含的许多的信息。比如打开文件的mimeType,mode等


from:http://blog.csdn.net/zhi184816/article/details/51832711

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容