4.混合開發(fā)必學(xué)的WebView

apk/源碼下載地址

封面.png

目錄

1.基本使用
2.與JS交互之 WebChromeClient
3.與JS交互之 addJavascriptInterface
4.實(shí)戰(zhàn)之 瀏覽器

1.基本使用

  • 布局文件中使用 webview標(biāo)簽
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>
  • 添加聯(lián)網(wǎng)權(quán)限
<uses-permission android:name="android.permission.INTERNET" />
  • 加載一個(gè)網(wǎng)址
public class _4_1_Activity extends BaseActivity {
    private WebView mWebView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_4_webview);
        mWebView = (WebView) findViewById(R.id.webView);
        mWebView.loadUrl("http://m.youdao.com/");
    }
}
  • WebViewClient 頁面加載過程中的事件通知控制
//自己控制Web加載 有些機(jī)型可能回自動(dòng)調(diào)用系統(tǒng)瀏覽器
mWebView.setWebViewClient(new WebViewClient() {

    /**
     * 攔截新的url
     * 攔截對(duì)象:新的Url
     * 調(diào)用線程:UI線程
     * @return 控制范圍:只能是yes或no
     */
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        return true;
    }

    /**
     * 攔截資源請(qǐng)求
     * 攔截對(duì)象:WebResourceRequest
     * 調(diào)用線程:IO線程
     * @return 控制范圍:模擬數(shù)據(jù)
     */
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            //攔截圖片請(qǐng)求 用空數(shù)據(jù)替換 見下圖
            if (request.getUrl().toString().contains(".png")) {
                return new WebResourceResponse(null, null,
                        new ByteArrayInputStream(new byte[0]));
            }
        }
        return super.shouldInterceptRequest(view, request);
    }

    /**
     * 攔截收到錯(cuò)誤
     */
    @Override
    public void onReceivedError(WebView view, WebResourceRequest request,
                                WebResourceError error) {
        //這里自定義了一個(gè)錯(cuò)誤頁面
        String data = "<html><body>404 not found</body></html>";
        view.loadData(data, "text/html", null);
    }
});
  • WebSettings 其它設(shè)置
WebSettings settings = mWebView.getSettings();
//設(shè)置默認(rèn)文本編碼的名字
settings.setDefaultTextEncodingName("utf-8");
//禁止加載圖片
settings.setLoadsImagesAutomatically(false);
//啟用JavaScript
settings.setJavaScriptEnabled(true);
//設(shè)置布局算法 TEXT_AUTOSIZING
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
//開啟縮放
settings.setSupportZoom(true);
//擴(kuò)大比例的縮放
settings.setUseWideViewPort(true);
settings.setBuiltInZoomControls(true);
//隱藏縮放控件
settings.setDisplayZoomControls(false);
//是否讀取緩存模式
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
//啟用設(shè)置水平滾動(dòng)條
mWebView.setHorizontalScrollBarEnabled(true);
//設(shè)置垂直滾動(dòng)條啟用
mWebView.setVerticalScrollBarEnabled(true);
// 安全考慮,防止密碼泄漏斧蜕,尤其是root過的手機(jī)
settings.setSavePassword(false);
//自適應(yīng)屏幕
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
settings.setLoadWithOverviewMode(true);
settings.setDatabaseEnabled(true);
  • 返回鍵捕捉
@Override
public void onBackPressed() {
    //webview有上級(jí)頁面
    if (mWebView.canGoBack()){
        //回退
        mWebView.goBack();
    }else{
        super.onBackPressed();
    }
}

2.與JS交互之 WebChromeClient

與JS交互之WebChromeClient.gif
  • 項(xiàng)目中內(nèi)置一個(gè)寫好網(wǎng)頁 main/assets/_4_2_javascript.html
<html>
    <!-- 寫好的javascript代碼 -->
    <script type="text/javascript">
        <!-- 提醒 -->
        function userAlert(){
            alert("來自網(wǎng)頁的提醒");
        }
        <!-- 提示 -->
        function userPrompt(){
            var result = prompt("來自網(wǎng)頁的提示");
            document.getElementById("a2").innerText = result;
        }
        <!-- 加載成功注入 -->
        function writeDiv1(message) {
            document.getElementById("div1").innerText =  message;
        }
    </script>
    <body>
        <h4 id="title">歡迎來到webview與js交互的內(nèi)容</h4>
        <div id = "div1"></div><br/>
        <a  href="javascript:void" onclick="userAlert()">點(diǎn)擊彈出提醒</a><br/>
        <a id="a2" href="javascript:void" onClick="userPrompt()">點(diǎn)擊彈出提示</a>
    </body>
</html>
  • java中代碼
public class _4_2_Activity extends BaseActivity {

    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_4_webview);
        mWebView = (WebView) findViewById(R.id.webView);
        
        //啟用JavaScript
        mWebView.getSettings().setJavaScriptEnabled(true);
        //不加載緩存
        mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
        mWebView.setWebViewClient(new WebViewClient(){
            /**
             * 頁面加載成功后調(diào)用
             */
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                //頁面加載成功后 調(diào)用js中的代碼
                mWebView.loadUrl("javascript:loadSuccess('頁面加載成功android注入的內(nèi)容')");
            }
        });
        mWebView.setWebChromeClient(new WebChromeClient(){

            //處理來自js的提醒
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Toast.makeText(_4_2_Activity.this, message, Toast.LENGTH_SHORT).show();
                //處理掉這個(gè)彈窗
                result.confirm();
                return true;
            }
            //處理來自js的提示
            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                Toast.makeText(_4_2_Activity.this, message, Toast.LENGTH_SHORT).show();
                result.confirm("來自android的-莫慌");
                return true;
            }

        });
        mWebView.loadUrl("file:///android_asset/_4_2_javascript.html");
    }
}

3.與JS交互之 addJavascriptInterface

與JS交互之a(chǎn)ddJavascriptInterface.gif
  • 項(xiàng)目中內(nèi)置一個(gè)寫好的main/assets/_4_3_add_interface.html
<!Doctype html>
<html>
    <script type="text/javascript">
        <!-- 頁面加載調(diào)用的方法 -->
        window.onload = function() {
            <!-- 調(diào)用初始化標(biāo)題的接口 -->
            var str = MyJavascriptInterface.initTitle();
            document.getElementById("title").innerText = str;
        }
        <!-- 調(diào)用相加的接口 -->
        function add(){
            var sum = MyJavascriptInterface.add(1, 11);
            document.getElementById("div1").innerText = "1 + 11 = " + sum;
        }
        <!-- 被android調(diào)用的js -->
        function androidCall(){
            return "hello android";
        }
    </script>
    <body>
        <h4 id="title"></h4>
        <div id = "div1">1+11=励幼?</div>
        <div ><a href="javascript:void" onclick="add()">執(zhí)行運(yùn)算</a></div>
    </body>
</html>
  • java中的全部代碼
public class _4_3_Activity extends BaseActivity {

    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_4_webview);
        mWebView = (WebView) findViewById(R.id.webView);
        //注入Javascript接口 addJavascriptInterFace(注入對(duì)象實(shí)例,注入對(duì)象的名字)
        mWebView.addJavascriptInterface(new MyJavascriptInterface(),"MyJavascriptInterface");
        //開啟javascript
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.loadUrl("file:///android_asset/_4_3_add_interface.html");
    }

    /**
     * 需要注入的類
     * 注入范圍:
     *          api17一下注入所有Public Method
     *          api17以上 @JavascriptInterface注釋的
     */
    private class MyJavascriptInterface {

        @JavascriptInterface
        public String initTitle(){
            return getTitle().toString();
        }
        @JavascriptInterface
        public int add(int x, int y) {
            return x + y;
        }
    }

    @Override
    public void onBackPressed() {
        //在按下返回鍵的時(shí)候java調(diào)用js
        mWebView.evaluateJavascript("androidCall()", new ValueCallback<String>() {
            @Override
            public void onReceiveValue(String value) {
                Toast.makeText(_4_3_Activity.this, value, Toast.LENGTH_SHORT).show();
            }
        });
        super.onBackPressed();
    }
}

4.實(shí)戰(zhàn)之 瀏覽器

實(shí)戰(zhàn)之 瀏覽器.gif
  • 布局文件activity_4_webview.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="48dp">

        <EditText
            android:id="@+id/etInput"
            android:layout_width="match_parent"
            android:text="http://m.youdao.com/"
            android:hint="輸入網(wǎng)址"
            android:layout_height="wrap_content"
            android:inputType="textNoSuggestions" />
    </android.support.v7.widget.Toolbar>

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="3dp"
        android:layout_below="@id/toolbar"
        android:visibility="gone"
        android:background="@android:color/white"/>

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/progressBar" />

</RelativeLayout>
  • 新建一個(gè)menu文件_4_4_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/menu_go"
        android:title="前往"
        app:showAsAction="always" />
    <item
        android:id="@+id/menu_refresh"
        android:title="刷新"
        app:showAsAction="never" />
    <item
        android:id="@+id/back"
        android:title="后退"
        app:showAsAction="never" />

    <item
        android:id="@+id/forward"
        android:title="前進(jìn)"
        app:showAsAction="never" />
</menu>
  • java代碼
public class _4_4_Activity extends AppCompatActivity {

    private Toolbar mToolbar;
    private WebView mWebView;
    private EditText mInputEdit;
    private ProgressBar mProgressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_4_4);
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        //設(shè)置菜單
        mToolbar.inflateMenu(R.menu._4_4_menu);
        //設(shè)置菜單監(jiān)聽
        mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.menu_go:
                        String url = mInputEdit.getText().toString().trim();
                        mWebView.loadUrl(url);
                        break;
                    case R.id.menu_refresh:
                        mWebView.reload();
                        break;
                    case R.id.back:
                        mWebView.goBack();
                        break;
                    case R.id.forward:
                        //goBackOrFprward 負(fù)數(shù)back 正數(shù)
                        mWebView.goForward();
                        break;
                }
                return true;
            }
        });
        //菜單設(shè)置回調(diào)函數(shù)
        mToolbar.setMenuCallbacks(new MenuPresenter.Callback() {
            @Override
            public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {

            }

            @Override
            public boolean onOpenSubMenu(MenuBuilder subMenu) {
                //webView可以回退才顯示回退
                mToolbar.getMenu().findItem(R.id.back).setEnabled(mWebView.canGoBack());
                //webView可以前進(jìn)才顯示前進(jìn)
                mToolbar.getMenu().findItem(R.id.forward).setEnabled(mWebView.canGoForward());
                return false;
            }
        }, null);

        mWebView = (WebView) findViewById(R.id.webView);
        mInputEdit = (EditText) findViewById(R.id.etInput);
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        mWebView.setWebViewClient(new WebViewClient(){
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                Uri uri = Uri.parse(url);
                return !uri.getScheme().toLowerCase().startsWith("http");
            }

            //開始加載
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                //顯示進(jìn)度條
                mProgressBar.setVisibility(View.VISIBLE);
            }

            //加載結(jié)束
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                //隱藏進(jìn)度條
                mProgressBar.setVisibility(View.GONE);
            }
        });
        mWebView.setWebChromeClient(new WebChromeClient(){
            //加載中
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
                //顯示進(jìn)度
                mProgressBar.setProgress(newProgress);
            }
        });
        //設(shè)置下載監(jiān)聽
        mWebView.setDownloadListener(new DownloadListener() {
            @Override
            public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
                //交給系統(tǒng)去處理
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse(url));
                startActivity(intent);
            }
        });

        WebSettings settings = mWebView.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setUseWideViewPort(true);
        settings.setSupportZoom(true);
        settings.setBuiltInZoomControls(true);
        settings.setDisplayZoomControls(false);
        settings.setCacheMode(WebSettings.LOAD_DEFAULT);
        settings.setLoadWithOverviewMode(true);
        //cookie 服務(wù)器存儲(chǔ)在終端的數(shù)據(jù) 這里不緩存cookie
        CookieManager cookieManager = CookieManager.getInstance();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            cookieManager.removeAllCookies(null);
        } else {
            cookieManager.removeAllCookie();
        }
    }

    @Override
    public void onBackPressed() {
        if (mWebView.canGoBack()) {
            mWebView.goBack();
        } else {
            super.onBackPressed();
        }
    }
}
該系列已經(jīng)出來好幾期咱圆,這一期開始將在原本枯燥的文字文章中加入gif圖片的演示效果箫章,不知道這種形式的文章需要的朋友們會(huì)不會(huì)喜歡這種風(fēng)格的文章翘单,或者有那些可以改良的地方定铜,感謝提出矮锈。

apk下載地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末豺旬,一起剝皮案震驚了整個(gè)濱河市钠惩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌族阅,老刑警劉巖篓跛,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異坦刀,居然都是意外死亡愧沟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門鲤遥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沐寺,“玉大人,你說我怎么就攤上這事盖奈』煳耄” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長究孕。 經(jīng)常有香客問我啥酱,道長,這世上最難降的妖魔是什么厨诸? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任镶殷,我火速辦了婚禮,結(jié)果婚禮上微酬,老公的妹妹穿的比我還像新娘绘趋。我一直安慰自己,他們只是感情好颗管,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布埋心。 她就那樣靜靜地躺著,像睡著了一般忙上。 火紅的嫁衣襯著肌膚如雪拷呆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天疫粥,我揣著相機(jī)與錄音茬斧,去河邊找鬼。 笑死梗逮,一個(gè)胖子當(dāng)著我的面吹牛项秉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慷彤,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼娄蔼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了底哗?” 一聲冷哼從身側(cè)響起岁诉,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎跋选,沒想到半個(gè)月后涕癣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡前标,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年坠韩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炼列。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡只搁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出俭尖,到底是詐尸還是另有隱情氢惋,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站明肮,受9級(jí)特大地震影響菱农,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜柿估,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一循未、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秫舌,春花似錦的妖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至墨缘,卻和暖如春星虹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背镊讼。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國打工宽涌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蝶棋。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓卸亮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親玩裙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子兼贸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 這篇博客主要來介紹 WebView 的相關(guān)使用方法溶诞,常見的幾個(gè)漏洞,開發(fā)中可能遇到的坑和最后解決相應(yīng)漏洞的源碼罕偎,以...
    Shawn_Dut閱讀 7,225評(píng)論 3 55
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,079評(píng)論 25 707
  • WebView 目前android市場(chǎng)上的一些應(yīng)用采用的開發(fā)方式大致分為三種: Hybrid App中實(shí)現(xiàn)的主要技...
    Reathin閱讀 2,018評(píng)論 1 9
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程很澄,因...
    小菜c閱讀 6,402評(píng)論 0 17
  • 清明時(shí)節(jié)雨紛紛,路上行人欲斷魂颜及。 又到一年清明節(jié),街上手捧黃花的人漸漸多起來了蹂楣,應(yīng)該都是祭奠先人的吧俏站。隨著社會(huì)的不...
    6cb106582cd2閱讀 557評(píng)論 0 5