因为最近在项目开发中使用的WebView场景相对较多,索性抽了一些时间把网上目前关于WebView的API进行了一次大总结(小部分API与方法重复,但是不影响查看与使用)
我那些关于WebView的回忆 ~ 包含入门使用、优化加载样式、监听加载状态、各场景后退键处理、俩端交互流程、header、user-agent传值、交互常见问题、较全API整合
友情提示 - 阅读更多 - 展开全文 - Ctrl+F - 搜索关键词
最近在抽时间整理该篇,整理完毕之后会删除此行 !!!
WebSettings 配置
获取配置:一切配置建立在此基础之上
//获取配置实例
WebSettings webSettings = webView.getSettings();
//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);
//支持插件
webSettings.setPluginsEnabled(true);
//定位(location)
webSettings.setGeolocationEnabled(true);
//是否保存表单数据
webSettings.setSaveFormData(true);
//是否当webview调用requestFocus时为页面的某个元素设置焦点,默认值 true
webSettings.setNeedInitialFocus(true);
//是否支持多窗口,默认值false
webSettings.setSupportMultipleWindows(false);
//布局算法
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
当前页面请求是否允许进行定位
@param origin 权限设置的源地址
@param allow 是否允许定位
@retain 当前的选择是否让内核记住
public void onGeolocationPermissionsShowPrompt(String origin,
GeolocationPermissions.Callback callback)
- 资源访问
//是否可访问Content Provider的资源,默认值 true
webSettings.setAllowContentAccess(true);
// 是否可访问本地文件,默认值 true
webSettings.setAllowFileAccess(true);
// 是否允许通过file url加载的Javascript读取本地文件,默认值 false
webSettings.setAllowFileAccessFromFileURLs(false);
// 是否允许通过file url加载的Javascript读取全部资源(包括文件,http,https),默认值 false
webSettings.setAllowUniversalAccessFromFileURLs(false);
- 设置自适应屏幕,两者合用
//将图片调整到适合webview的大小
webSettings.setUseWideViewPort(true);
// 缩放至屏幕的大小
webSettings.setLoadWithOverviewMode(true);
- 缩放操作
//支持缩放,默认为true 是下面那个的前提
webSettings.setSupportZoom(true);
//设置内置的缩放控件 若为false,则该WebView不可缩放
webSettings.setBuiltInZoomControls(true);
//隐藏原生的缩放控件
webSettings.setDisplayZoomControls(false);
- 资源加载
// 是否自动加载图片
webSettings.setLoadsImagesAutomatically(true);
// 禁止加载网络图片
webSettings.setBlockNetworkImage(false);
// 禁止加载所有网络资源
webSettings.setBlockNetworkLoads(false);
- 默认文本编码,默认值 “UTF-8”
//默认值 "UTF-8"
webSettings.setDefaultTextEncodingName("UTF-8");
// 默认文字尺寸,默认值16,取值范围1-72
webSettings.setDefaultFontSize(16);
// 默认等宽字体尺寸,默认值16
webSettings.setDefaultFixedFontSize(16);
// 最小文字尺寸,默认值 8
webSettings.setMinimumFontSize(8);
// 最小文字逻辑尺寸,默认值 8
webSettings.setMinimumLogicalFontSize(8);
// 文字缩放百分比,默认值 100
webSettings.setTextZoom(100);
- 字体
// 标准字体,默认值 "sans-serif"
webSettings.setStandardFontFamily("sans-serif");
// 衬线字体,默认值 "serif"
webSettings.setSerifFontFamily("serif");
// 无衬线字体,默认值 "sans-serif"
webSettings.setSansSerifFontFamily("sans-serif");
// 等宽字体,默认值 "monospace"
webSettings.setFixedFontFamily("monospace");
// 手写体(草书),默认值 "cursive"
webSettings.setCursiveFontFamily("cursive");
// 幻想体,默认值 "fantasy"
webSettings.setFantasyFontFamily("fantasy");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// 用户是否需要通过手势播放媒体(不会自动播放),默认值 true
webSettings.setMediaPlaybackRequiresUserGesture(true);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// 5.0以上允许加载http和https混合的页面(5.0以下默认允许,5.0+默认禁止)
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 是否在离开屏幕时光栅化(会增加内存消耗),默认值 false
webSettings.setOffscreenPreRaster(false);
}
if (isNetworkConnected(context)) {
// 根据cache-control决定是否从网络上取数据
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
} else {
// 没网,离线加载,优先加载缓存(即使已经过期)
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}
- 其他细节操作
//关闭webview中缓存
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//设置可以访问文件
webSettings.setAllowFileAccess(true);
//支持通过JS打开新窗口
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
//支持自动加载图片
webSettings.setLoadsImagesAutomatically(true);
//设置编码格式
webSettings.setDefaultTextEncodingName("utf-8");
常用API
基础
- 获取控制
WebView
的对象
WebSettings getSettings ()
- 注入
Javascript
对象(交互)
void addJavascriptInterface(Object object, String name)
- 删除之前注入的
Javascript
对象
void removeJavascriptInterface(String name)
- 重新加载当前的URL
void reload()
H5栈:网页数量、前进、后退
- 获取WebView栈内存储了多少子页面
WebBackForwardList webBackForwardList = mWebView.copyBackForwardList();
- 是否可以后退
Webview.canGoBack()
- 后退网页
Webview.goBack()
- 是否可以前进
Webview.canGoForward()
- 前进网页
Webview.goForward()
H5状态:onResume、onPause
- 激活
WebView
为活跃状态,能正常执行网页的响应
webView.onResume();
- 当页面被失去焦点被切换到后台不可见状态,需要执行
onPause
,通过onPause
动作通知内核暂停所有的动作,比如DOM 解析
、plugin执行
、JavaScript执行
webView.onPause();
- 当应用程序(存在
webview
)被切换到后台时,全局的webview
暂停请求(暂停所有webview
的布局,HTML解析和JavaScript定时器)
这个方法不仅仅针对当前的
webview
而是全局的 全应用程序的webview
,它会暂停所有webview的layout
,parsing
,javascripttimer
降低CPU功耗
webView.pauseTimers();
- 恢复
pauseTimers
状态,所有WebView的状态(布局的解析和JavaScript,计时器)
webView.resumeTimers();
避免OOM:WebView关闭时停止加载、清理缓存等
这部分有时候会被面试到,当然更多的是我们在开发中会及时回收资源,或许算是性能优化的一部分吧
- 停止当前加载
void stopLoading()
- 销毁Webview
在关闭了Activity时,如果 webview
的音乐或视频,还在播放 就必须销毁 webview
,但是注意: webview
调用destory时, webview
仍绑定在Activity上,这是由于自定义 webview
构建时传入了该Activity的context对象,因此需要先从父容器中移除 webview
,然后再销毁 webview
rootLayout.removeView(webView);
webView.destroy();
清除当前webview访问的历史记录
(只会webview
访问历史记录里的所有记录除了当前访问记录)
Webview.clearHistory();
清除网页访问留下的缓存
(由于内核缓存是全局的因此这个方法不仅仅针对webview
而是针对整个应用程序
),
Tip:是否清理缓存要看具体场景,很多大型H5页面首次加载都会很慢,如果有缓存就会好很多
Webview.clearCache(true);
仅清除自动完成填充的表单数据
,并不会清除webview
存储到本地的数据
Webview.clearFormData();
滑动:可指定滚条样式、亦可滑动顶部、底部
- 指定滚动条的样式 滚动条可以重叠或嵌入
void setScrollBarStyle(int style)
- 将
WebView
展示的页面滑动至底部
pageDown(boolean bottom)
- 将
WebView
展示的页面滑动至顶部
pageUp(boolean top)
获取H5信息:标题、加载进度、图标、高度
- 获取当前页面标题
String getTitle()
- 获取当前页面进度(0-100)
int getProgress()
- 获取当前页面图标
Bitmap getFavicon ()
- 获取HTML内容高度
int getContentHeight()
尚未规整
- 以当前的index为起始点前进或者后退到历史记录中指定的steps
如果steps为负数则为后退,正数则为前进
Webview.goBackOrForward(intsteps)
- 启动安全浏览
startSafeBrowsing(added in API level 27)
void startSafeBrowsing (Context context, ValueCallback<Boolean> callback)
- 注册监听器,以通知页面操作进度
void setFindListener(WebView.FindListener listener)
- 默认实现KeyEvent.Callback.onKeyDown():当视图可以点击时,执行按下视图KEYCODE_DPAD_CENTER或KEYCODE_ENTER释放视图 (软件键盘上的按键通常不会触发这个监听器)如果你处理了事件,则返回true 如果您想让事件由下一个接收器处理,则返回false
boolean onKeyDown (int keyCode, KeyEvent event)
- 会显示WebView的图形缩放选择器的小部件
void invokeZoomPicker()
- 获取是否在此WebView中启用隐私浏览
boolean isPrivateBrowsingEnabled ()
- 获取当前页面的原始URL 这并不一定与传递给WebViewClient.onPageStarted的URL相同,因为URL的加载已经开始,但当前页面可能还没有更改 也可能出现重定向导致原始请求的URL不同
String getOriginalUrl()
- 获取页面SSL证书,如果没有,就返回Null
SslCertificate getCertificate()
- 突出显示并滚动到找到的下一个匹配项 findAllAsync(String),就是一条一条的搜索文本 如果调用了clearMatches()那么这个方法就不执行了
void findNext(boolean forward)
- 在页面上找到查找的所有字符并且异步突出显示,通知任何注册了WebView.FindListener
void findAllAsync(String find)
- 搜索地址(只有在美国的地址才会检测到)
String findAddress (String addr)
- 文档中是否有图像,参数Message负责发送结果消息
void documentHasImages (Message response)
- 将按键事件分发到焦点路径上的下一个视图 该路径指的是从视图树的顶部向下延伸到当前有焦点的视图 如果这个View有焦点,那么就分发给自己 KeyEvent 指的是按键事件
boolean dispatchKeyEvent (KeyEvent event)
- 由父类调用,请求子类在必要时更新
mScrollX
和mScrollY
的值
void computeScroll ()
- 为你的WebView提供打印功能,PrintDocumentAdapter会将WebView内容转换成PDF 参数documentName,具体可以查看 PrintDocumentInfo
PrintDocumentAdapter createPrintDocumentAdapter(String documentName)
- 通知应用当前页退出了全屏模式,此时应用必须隐藏之前显示的自定义View
void onHideCustomView()
- webview请求得到focus,发生这个主要是当前webview不是前台状态,是后台webview
void onRequestFocus(WebView view)
- 通知应用程序从关闭传递过来的webview并从view tree中remove
void onCloseWindow(WebView window)
- 接收JavaScript控制台消息
boolean onConsoleMessage(ConsoleMessage consoleMessage)
- 使用baseUrl加载内容
void loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)
- 异步执行查找网页内包含的字符串并设置高亮,查找结果会回调
void findAllAsync (String find)
清除
- 清除通过findAllAsync(String)匹配的高亮文本
void clearMatches()
- 清除存储的SSL首选项表
void clearSslPreferences()
缩放
- 缩放
void zoomBy(float factor)
- 放大
boolean zoomIn()
- 缩放
boolean zoomOut()
- 通知WebView内核网络状态
用于设置JS属性
window.navigator.isOnline
和产生HTML5事件online/offline
void setNetworkAvailable(boolean networkUp)
常用方法
记得要声明网络权限~
<uses-permission android:name="android.permission.INTERNET"/>
加载方式、类型:网页、apk包中html页面、html页面
webView
加载地址设置 - shouldOverrideUrlLoading()
//方式1. 加载一个网页:
webView.loadUrl("http://www.google.com/");
//方式2:加载apk包中的html页面
webView.loadUrl("file:///android_asset/test.html");
//方式3:加载手机本地的html页面
webView.loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
//复写shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
通知应用程序内核即将加载url指定的资源,应用程序可以返回本地的资源提供给内核,若本地处理返回数据,内核不从网络上获取数据
@param view 接收WebViewClient的那个实例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient()),即是这个webview
@param url raw url 制定的资源
@return 返回WebResourceResponse包含数据对象,或者返回null
public WebResourceResponse shouldInterceptRequest(WebView view, String url)
加载状态监听:开始、结束
- 加载开始的操作 -
onPageStarted()
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//设定加载开始的操作
}
});
- 加载结束的操作 -
onPageFinished()
webView.setWebViewClient(new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url) {
//设定加载结束的操作
}
});
- 加载资源的操作 -
onLoadResource()
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean onLoadResource(WebView view, String url) {
//设定加载资源的操作
}
});
监听 加载错误
- 加载页面的服务器出现错误时(如
404
)调用 -onReceivedError()
//步骤1:写一个html文件(error_handle.html),用于出错时展示给用户看的提示页面
//步骤2:将该html文件放置到代码根目录的assets文件夹下
//步骤3:复写WebViewClient的onRecievedError方法
//该方法传回了错误码,根据错误类型可以进行不同的错误分类处理
webView.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl){
switch(errorCode)
{
case HttpStatus.SC_NOT_FOUND:
view.loadUrl("file:///android_assets/error_handle.html");
break;
}
}
});
- webView默认不处理
https
请求,页面会显示空白 -onReceivedSslError()
webView.setWebViewClient(new WebViewClient() {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed(); //表示等待证书响应
// handler.cancel(); //表示挂起连接,为默认方式
// handler.handleMessage(null); //可做其他处理
}
});
获取 js 交互返回值
WebView
调用JavaScript
有参数有返回值的函数,此方法必须在UI线程上调用,回调也是在UI线程的(added in API level 19
)
private void evaluateJavaScript(WebView webView){
webView.evaluateJavascript("getName()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("WebView",s.toString);
}
});
}
方法9 :如果浏览器需要重新发送POST请求,可以通过这个时机来处理 默认是不重新发送数据
@param view 接收WebViewClient的那个实例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient()),即是这个webview
@param dontResent 当浏览器不需要重新发送数据时,可以使用这个参数
@param resent 当浏览器需要重新发送数据时, 可以使用这个参数
public void onFormResubmission(WebView view, Message dontResend,
Message resend)
方法10 :通知应用程序可以将当前的url存储在数据库中,意味着当前的访问url已经生效并被记录在内核当中 这个函数在网页加载过程中只会被调用一次 注意网页前进后退并不会回调这个函数
@param view 接收WebViewClient的那个实例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient()),即是这个webview
@param url 当前正在访问的url
@ param isReload 如果是true 这个是正在被reload的url
public void doUpdateVisitedHistory(WebView view, String url,
boolean isReload)
方法11 :通知应用程序WebView接收到了一个Http auth的请求,应用程序可以使用supplied 设置webview的响应请求 默认行为是cancel 本次请求
@param view 接收WebViewClient的那个实例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient()),即是这个webview
@param handler 用来响应WebView请求的对象
@param host 请求认证的host
@param realm 认真请求所在的域
public void onReceivedHttpAuthRequest(WebView view,
HttpAuthHandler handler, String host, String realm)
方法12 :提供应用程序同步一个处理按键事件的机会,菜单快捷键需要被过滤掉 如果返回true,webview不处理该事件,如果返回false, webview会一直处理这个事件,因此在view 链上没有一个父类可以响应到这个事件 默认行为是return false;
@param view 接收WebViewClient的那个实例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient()),即是这个webview
@param event 键盘事件名
@return 如果返回true,应用程序处理该时间,返回false 交有webview处理
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event)
方法13 :通知应用程序webview 要被scale 应用程序可以处理改事件,比如调整适配屏幕
public void onScaleChanged(WebView view, float oldScale, float newScale)
方法14 :通知应用程序有个自动登录的帐号过程
@param view 请求登陆的webview
@param realm 账户的域名,用来查找账户
@param account 一个可选的账户,如果是null 需要和本地的账户进行check, 如果是一个可用的账户,则提供登录
@param args 验证制定参数的登录用户
public void onReceivedLoginRequest(WebView view, String realm, String account, String args)
缓存方面
- 当加载
html
页面时,WebView
会在/data/data/包名
目录下生成database
与cache
两个文件夹 - 请求的
URL
记录保存在WebViewCache.db
,而URL
的内容是保存在WebViewCache
文件夹下 - 是否启用缓存:
//优先使用缓存:
WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
//缓存模式如下:
//LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
//LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据
//LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
//LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据
//不使用缓存:
WebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
- 结合使用(离线加载)
if (NetStatusUtil.isConnected(getApplicationContext())) {
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//根据cache-control决定是否从网络上取数据
} else {
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//没网,则从本地获取,即离线加载
}
webSettings.setDomStorageEnabled(true); // 开启 DOM storage API 功能
webSettings.setDatabaseEnabled(true); //开启 database storage API 功能
webSettings.setAppCacheEnabled(true);//开启 Application Caches 功能
String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
webSettings.setAppCachePath(cacheDirPath); //设置 Application Caches 缓存目录
获取 加载进度、Title
- 获取WebView的title -
onReceivedTitle()
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onReceivedTitle(WebView view, String title) {
titleview.setText(title);
}
- 进度条展示 -
onProgressChanged()
webview.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress < 100) {
String progress = newProgress + "%";
progress.setText(progress);
} else {
}
});
方法18 :当前页面有个新的favicon时候,会回调这个函数(接收图标)
@param view 接收WebViewClient的那个实例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient()),即是这个webview
@param icon 当前页面的favicon
public void onReceivedIcon(WebView view, Bitmap icon)
方法19 :通知应用程序 apple-touch-icon的 url,如果应用程序需要这个icon的话, 可以通过这个url获取得到 icon
@param view 接收WebViewClient的那个实例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient()),即是这个webview
@param url apple-touch-icon 的服务端地址
@param precomposed 如果precomposed 是true 则touch-icon是预先创建的
Tips
public void onReceivedTouchIconUrl(WebView view, String url,
boolean precomposed)
方法20 :通知应用程序webview需要显示一个custom view,主要是用在视频全屏HTML5Video support(通知应用当前页进入了全屏模式,此时应用必须显示一个包含网页内容的自定义View)
@param view 即将要显示的view
@param callback 当view 需要dismiss 则使用这个对象进行回调通知
public void onShowCustomView(View view, CustomViewCallback callback)
对话框:onJsAlert、onJsConfirm、onJsPrompt、onJsBeforeUnload
- 通知应用程序显示
javascript alert
对话框,如果应用程序返回true内核认为应用程序处理这个消息,返回false,内核自己处理
@param view 接收 WebViewClient 的那个实例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient()),即是这个webview
@param url 当前请求弹出javascript 对话框webview 加载的url地址
@param message 弹出的内容信息
@result 用来响应用户的处理
public boolean onJsAlert(WebView view, String url, String message,
JsResult result)
- 通知应用程序提供
confirm
对话框
boolean onJsConfirm(WebView view, String url, String message, JsResult result)
- 通知应用程序显示一个
prompt
对话框
boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)
- 通知应用程序显示一个对话框,让用户选择是否离开当前页面,这个回调是
javascript
中的onbeforeunload
事件,如果客户端返回true,内核会认为客户端提供对话框 默认行为是return false
boolean onJsBeforeUnload(WebView view, String url, String message,
JsResult result)
原始方法:直接调默认的上传图片,请求拍照
这个回调是私有回调, 当页面需要请求打开系统的文件选择器,则会回调这个方法,比如我们需要上传图片,请求拍照,邮件的附件上传等等操作
public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture)
如果不实现这个私有API,则下面的请求都将不会执行
public void onGeolocationPermissionsHidePrompt()
有趣
appcache、web sql 超出限额
通知应用程序 webview
内核 web sql
数据库超出配额,请求是否扩大数据库磁盘配额 默认行为是不会增加数据库配额
@param url 触发这个数据库配额的url地址
@param databaseIdentifier 指示出现数据库超过配额的标识
@param quota 原始数据库配额的大小,是字节单位bytes
@param estimatedDatabaseSize 到达底线的数据大小 bytes
@param totalQuota 总的数据库配额大小 bytes
@param quotaUpdater 更新数据库配额的对象,可以使用 quotaUpdater.updateQuota(newQuota);配置新的数据库配额大小
public void onExceededDatabaseQuota(String url, String databaseIdentifier,
long quota, long estimatedDatabaseSize, long totalQuota,
WebStorage.QuotaUpdater quotaUpdater)
通知应用程序内核已经到达最大的 appcache
public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
WebStorage.QuotaUpdater quotaUpdater)
注意事项
避免WebView内存泄露
产生环境:不在xml中定义 Webview ,而是在需要的时候在Activity中创建,并且Context使用 getApplicationgContext()
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mWebView = new WebView(getApplicationContext());
mWebView.setLayoutParams(params);
mLayout.addView(mWebView);
解决方案:在 Activity 销毁( WebView )的时候,先让 WebView 加载null内容,然后移除 WebView,再销毁 WebView,最后置空
@Override
protected void onDestroy() {
if (mWebView != null) {
mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
mWebView.clearHistory();
((ViewGroup) mWebView.getParent()).removeView(mWebView);
mWebView.destroy();
mWebView = null;
}
super.onDestroy();
}
借鉴文章