WebView实用功能与技巧
引子 web?native?这是个争论了很久的问题。 自从微信开放了更多的JS接口之后,移动web开发重新火了起来,前端程序猿也水涨船高。 毫无疑问,web页面有诸多优点: 跨平台:一次开发,可以同时在Android,iOS和Other Phone上运行(美好的愿望) 快速迭代,内容
引子
web?native?这是个争论了很久的问题。
自从微信开放了更多的JS接口之后,移动web开发重新火了起来,前端程序猿也水涨船高。
毫无疑问,web页面有诸多优点:
跨平台:一次开发,可以同时在Android,iOS和Other Phone上运行(美好的愿望)
快速迭代,内容统一:内容修改后,不同版本都能展示最新内容。可以避免频繁的客户端升级,也无需经过App Store的审核
语言优势:庞大JavaScript开发人员,能够带来移动端内容的繁荣
本人多年开发研究web与native混合APP,因为这里面有很多的坑,很有必要把经验归纳一番。
准备
区分APP和浏览器
我们的web页面是通过哪个应用打开的呢?这是要解决的第一个问题,这样才能做到APP与系统浏览器的内容差异化。
通过域名
将不同用途的页面归类到不同服务器或Web项目下,这是最简单也最笨的方法,如果同一个页面要在三端上都展示,那么就要复制3份了通过元数据
通过UA标识
这是web页面统计访问终端的品牌和分辨率的常用方法
我会在WebView的默认UA后面,加上自定义的标识,包括APP的标识 (AndroidApp、iPhoneApp)、应用包名和APP的版本号
判断是否微信浏览器就可以使用这个方法,同时最好检查是否加载了微信自定义的weixin.js文件
配置WebView基础参数
final WebSettings settings = getSettings();// 允许JS弹出提示框settings.setJavaScriptCanOpenWindowsAutomatically(true);// 允许web执行JSsettings.setJavaScriptEnabled(true);// 设置浏览器标识settings.setUserAgentString(buildAppUserAgent(getContext(), settings.getUserAgentString()));// 是否支持缩放,默认不支持(看起来更native)settings.setSupportZoom(false); settings.setBuiltInZoomControls(false);// 打开H5的离线缓存settings.setAppCacheEnabled(true);final String cachedir = getContext().getDir("cache", Context.MODE_PRIVATE).getPath(); settings.setAppCachePath(cachedir);// 打开H5的Dom Storage(localStorage,sessionStorage)settings.setDomStorageEnabled(true);// 如果要使用离线缓存和DomStorage必须要设置web databasefinal String dbdir = getContext().getDir("database", Context.MODE_PRIVATE).getPath(); settings.setDatabaseEnabled(true); settings.setDatabasePath(dbdir);
WebViewClient对象
监听页面加载情况(开始加载、资源加载、完成加载、页面错误)
通常情况下,我们都会有一个loading界面覆盖在webview上面,当页面加载完成隐藏loading。
这里存在2个小问题:
webview只有当所有内容都加载完成后,才会回调onPageFinished。
也就是说,当DOM元素加载完成,并且所有图片也加载完成才会触发,这对于追求体验的移动APP来说,显然无法接受。尤其是当网络不好或图片太大时尤为明显,用户看到的是明明页面已经基本出来了,却仍然在loading,无法操作。
其实JS端可以监听到DOMContentLoaded事件,此时是关闭loading的最佳时机出现加载错误时,不仅会调用onReceivedError,仍然会调用onPageFinished
有些人喜欢把loading界面和error界面写在同一个layout里,出现错误时显示error,完成加载时隐藏整个layout。
这对于普通页面来说没有问题,但是对于webview就会出现error无法被显示的情况。
所以最后将loading和error分开,在onPageFinished时,只需要隐藏loading部分。
拦截页面链接
重写shouldOverrideUrlLoading方法,当返回值为true时,需要自己处理url请求,webview将不会插手。
此方法只在涉及页面跳转时被触发。
这里存在2个问题:
低版本的某些请求不会触发此方法,直接在本webview打开了新页面。
如果想拦截,则需要在onPageStarted方法里判断url是否已经改变,更改了的话就表明打开了新的链接。页面重定向无法识别
当页面存在重定向时,API并没有提供方法作区分,这时需要自己处理。
替换加载内容
重写shouldInterceptRequest方法,可以替换JS、CSS、img等内容。
创建WebResourceResponse对象,并传入文件输入流,即可用其他资源替换本来要加载的内容。
通过此方法,我们可以预先下载页面所需的JS和CSS文件,保存到本地;然后当打开页面时,直接使用本地已下载的文件。这样可以大幅提高页面加载速度。
注:此方法只能API Level 11以后使用,低版本可通过ContentProvider实现类似功能。
WebChromeClient对象
WebViewClient类主要设计链接和资源加载的功能实现
WebChromeClient类则会涉及更底层的内容,如控制台调试、JS弹出框、显示自定义view等。
替换Alert对话框
web页面一般会通过alert方法,显示一些提示信息,但是对话框的样式却因不同的品牌差异很大,为了使我们的APP保持统一风格,有必要替换成我们自己设计的对话框。
重写onJsAlert方法,将message显示到Dialog。
该方法是模态的,必须返回内容才能关闭对话框,调用JsResult.cancel或者JsResult.confirm。如果只调用了Dialog.dismiss而没有调用JsResult的方法,会出现,虽然对话框消失,但是线程一直处于阻塞状态,造成假死现象,无法进行任何操作。
全屏播放视频
webview默认不能全屏播放,需要client端提供全屏的window。
代码如下:
@Override public void onShowCustomView (View view, WebChromeClient.CustomViewCallback callback) { mCustomViewCallback = callback;android.view.Window window = WebActivity.this.getWindow();window.setFlags( android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN, android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN);setRequestedOrientation(android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);mTitleBar.setVisibility(View.INVISIBLE);mWebView.setVisibility(View.INVISIBLE);mExitFullscreenBtn.setVisibility(View.VISIBLE);mVideoViewContainer.setVisibility(View.VISIBLE);mVideoViewContainer.addView(view);} @Override public void onHideCustomView () { mCustomViewCallback.onCustomViewHidden();android.view.Window window = WebActivity.this.getWindow();window.setFlags(0, android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN);setRequestedOrientation(android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);mTitleBar.setVisibility(View.VISIBLE);mWebView.setVisibility(View.VISIBLE);mExitFullscreenBtn.setVisibility(View.INVISIBLE);mVideoViewContainer.setVisibility(View.INVISIBLE);mVideoViewContainer.removeAllViews();}
Cookie
如果web端需要用户登录的操作,那么就涉及到native和web端同步登录状态,这就需要用到cookie。
// 打开Cookie支持CookieSyncManager.createInstance(this); CookieManager cookieManager = CookieManager.getInstance(); cookieManager.setAcceptCookie(true);
// 设置cookie sBuff.append(key).append("=").append(value);sBuff.append("; path=/");sBuff.append("; domain=").append(domain);cookieManager.setCookie(url, sBuff.toString());...... CookieSyncManager.getInstance().sync();
// 删除cookie// 清除过期的cookiecookieManager.removeExpiredCookie();// 清除所有cookiecookieManager.removeAllCookie();
因为并不存在单独删除cookie的某个字段的方法,所有要清除某个字段,要先将其设为已过期,再调用removeExpiredCookie
如何同步登录状态
简单的情况,只需要有userid即可认为已经登录,分如下两种情况:
- 先从native登录
native端调用登录接口,拿到useid后,当需要打开web时,在loadUrl之前,将userid保存到cookie中,服务端就会从cookie中读出userid。
- 先从web端登录
web登录后,webview会自动保存cookie。web端需要与native端定义接口,将username和userid通知给native端,native保存起来。
Web端与Native端互相通讯
WebView调用web端JS方法
mWebView.loadUrl("javascript:JSMethod()");
API 19以后,提供了更加便捷的方法,可以直接获取JS的返回值。(iOS本身已经提供类似API)
WebView.evaluateJavascript (String script, ValueCallback<String> resultCallback)
web端调用native代码
早期API提供的方法:
WebView.addJavascriptInterface(Object object, String name) WebView会将object注入到web端的window对象中,name是object对象定义的方法,web端通过object.name即可调用native端的功能。
but,这个方法存在安全漏洞 漏洞详细说明
如果你的targetSdkVersion>=17,那么必须将java方法加上注解@JavascriptInterface,否则web端是无法调用的。
自定义scheme
通过自定义scheme的方式,在shouldOverrideUrlLoading拦截,并定向到相应的native逻辑。
iOS端需通过此方法实现。
利用WebChromeClient.onJsPrompt
因为JS端很少使用prompt(一般使用alert)方法,所以我们可以利用这个方法,通过自定义协议格式,来实现web与native端的通信。
因为此方法需要返回JsResult对象,所以利用此机制,可以实现方法的同步调用(web端可以获取到接口方法的返回值,有利于代码和逻辑的简化)
大名鼎鼎PhoneGap(现在叫Cordova)就是利用此方法实现的web与native通讯。
我会专门写一篇,我是如何实现web与native通信的。
其他技巧
屏蔽长按事件
重写performLongClick
或者setOnLongClickListener实现空的listener
隐藏选择框
可以使用全局的一个CSS
*{-webkit-tap-highlight-color: rgba(0, 0, 0, 0);}
缩放按钮引起的崩溃
在某些机型上,当显示webview的缩放按钮时,退出Activity,就会报如下错误:
android.view.WindowLeaked: Activity com.secoo.activity.web.WebActivity has leaked window android.widget.ZoomButtonsController$Container{438e8248 V.E..... ........ 0,0-1536,194} that was originally added here at android.view.ViewRootImpl.(ViewRootImpl.java:382) at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:261) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:76) at android.widget.ZoomButtonsController.setVisible(ZoomButtonsController.java:371) ......
这是因为按钮的隐藏是延迟触发,在activity退出之后,造成了window的泄露。
解决方法:
// API 11之后,不显示缩放按钮 WebView.getSettings().setDisplayZoomControls(false);// API 11之前,在finish时,从view层级中删除webview ViewGroup viewgroup = (ViewGroup)(mWebView.getParent());viewgroup.removeView(mWebView);
技术交流请留言…
To Be Continue…

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











vivox100s と x100 携帯電話はどちらも vivo の携帯電話製品ラインの代表的なモデルであり、それぞれ異なる時代における vivo のハイエンド技術レベルを代表するものであるため、2 つの携帯電話にはデザイン、性能、機能に一定の違いがあります。この記事では、消費者が自分に合った携帯電話をより適切に選択できるように、これら 2 つの携帯電話を性能比較と機能分析の観点から詳しく比較します。まずはvivox100sとx100の性能比較を見てみましょう。 vivox100s には最新の機能が搭載されています。

全角の英字を半角に変換する実践的なヒント. 現代の生活において私たちは英語の文字に触れる機会が多く、パソコンや携帯電話などを使用する際に英語の文字を入力する必要が多くなります。ただし、場合によっては全角の英字が登場するため、半角形式を使用する必要があります。では、全角の英字を半角に変換するにはどうすればよいでしょうか?ここでは、いくつかの実践的なヒントを紹介します。まず、全角英数字とはインプットメソッド内で全角の位置を占める文字のことを指しますが、半角英数字は全角の位置を占めます。

インターネットの急速な発展に伴い、セルフメディアという概念が人々の心に深く根付いてきました。では、セルフメディアとは一体何でしょうか?その主な特徴と機能は何ですか?次に、これらの問題を 1 つずつ検討していきます。 1. セルフメディアとは何ですか? We-media は、その名前が示すように、あなたがメディアであることを意味します。これは、個人またはチームがインターネット プラットフォームを通じてコンテンツを独自に作成、編集、公開、配布できる情報媒体を指します。新聞、テレビ、ラジオなどの従来のメディアとは異なり、セルフメディアはよりインタラクティブでパーソナライズされており、誰もが情報の制作者および発信者になることができます。 2. セルフメディアの主な特徴と機能は何ですか? 1. 敷居が低い: セルフメディアの台頭により、メディア業界への参入の敷居が低くなり、煩わしい機材や専門チームは必要なくなりました。

Win11 のヒントの共有: Microsoft アカウントのログインをスキップする 1 つのトリック Windows 11 は、新しいデザイン スタイルと多くの実用的な機能を備えた、Microsoft によって発売された最新のオペレーティング システムです。ただし、一部のユーザーにとっては、システムを起動するたびに Microsoft アカウントにログインしなければならないのが少し煩わしい場合があります。あなたがそのような人であれば、次のヒントを試してみるとよいでしょう。これにより、Microsoft アカウントでのログインをスキップして、デスクトップ インターフェイスに直接入ることができるようになります。まず、Microsoft アカウントの代わりにログインするためのローカル アカウントをシステムに作成する必要があります。これを行う利点は、

小紅書が若者の間で人気になるにつれ、ますます多くの人がこのプラットフォームを使用して、自分の経験や人生の洞察のさまざまな側面を共有し始めています。複数の小紅書アカウントを効果的に管理する方法が重要な問題となっています。この記事では、Xiaohongshu アカウント管理ソフトウェアの機能のいくつかについて説明し、Xiaohongshu アカウントをより適切に管理する方法を探ります。ソーシャルメディアが成長するにつれて、多くの人が複数のソーシャルアカウントを管理する必要があることに気づきます。これは小紅書ユーザーにとっても課題です。小紅書アカウント管理ソフトウェアの中には、コンテンツの自動公開、スケジュールされた公開、データ分析、その他の機能など、ユーザーが複数のアカウントをより簡単に管理できるようにするものがあります。これらのツールを通じて、ユーザーはアカウントをより効率的に管理し、アカウントの露出と注目を高めることができます。さらに、Xiaohongshu アカウント管理ソフトウェアには、

C 言語では、他の変数のアドレスを格納するポインタを表し、& は変数のメモリ アドレスを返すアドレス演算子を表します。ポインタの使用に関するヒントには、ポインタの定義、ポインタの逆参照、ポインタが有効なアドレスを指していることの確認が含まれます。アドレス演算子の使用に関するヒントには、変数アドレスの取得、配列要素のアドレスを取得するときに配列の最初の要素のアドレスを返すことなどが含まれます。 。ポインター演算子とアドレス演算子を使用して文字列を反転する実際の例。

私たちは Excel で表を作成したり編集したりすることがよくありますが、ソフトウェアに触れたばかりの初心者にとって、Excel を使用して表を作成する方法は私たちほど簡単ではありません。以下では、初心者、つまり初心者がマスターする必要があるテーブル作成のいくつかの手順について演習を行います。初心者向けのサンプルフォームを以下に示します。入力方法を見てみましょう。 1. Excel ドキュメントを新規作成するには 2 つの方法があります。 [デスクトップ]-[新規作成]-[xls]ファイル上の何もない場所でマウスを右クリックします。 [スタート]-[すべてのプログラム]-[Microsoft Office]-[Microsoft Excel 20**] を実行することもできます。 2. 新しい ex ファイルをダブルクリックします。

VSCode (Visual Studio Code) は、Microsoft によって開発されたオープン ソース コード エディターであり、強力な機能と豊富なプラグイン サポートを備えており、開発者にとって推奨されるツールの 1 つです。この記事では、初心者が VSCode の使用スキルをすぐに習得できるようにするための入門ガイドを提供します。この記事では、VSCode のインストール方法、基本的な編集操作、ショートカット キー、プラグインのインストールなどを紹介し、具体的なコード例を読者に提供します。 1. まず VSCode をインストールします。
