Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android學習筆記038之WebView網頁視圖

Android學習筆記038之WebView網頁視圖

編輯:關於Android編程

前面我們介紹過了HTTP協議和Socket,這一篇我們來介紹一下Android的一個網絡控件:WebView-網頁視圖。我們知道,現在移動端有兩種開發方向:原生開發和H5移動端開發。

所謂的H5移動端開發就是通過HTML5+CSS+JS來構建一個網頁版的移動應用,這中間的媒介就是我們今天介紹的WebView,現在H5開發很熱門,優勢是:可以用百分比布局;更新的時候不需要我們像原生開發一樣需要重新下載一個APP重新安裝,只需要修改一下網頁就可以了;H5開發支持多平台,開發成本比較低,開發一款應用就可以在IOS和Android平台上運行;但是相應的H5開發也有很多的缺點:比原生應用響應慢;耗電比較大;數據積累問題;還有閃屏問題等。原生的JS是非常難學的,所以現在有很多的第三方框架:Bootstrap、AUI、Amaze UI、Frozen UI、Ionic等。下面我們開始學習一下這個WebView控件吧!

1、WebView 簡介

在Android系統中,內置了一款高性能的浏覽器,其內核就是WebKit,WebView網頁視圖,就是在這個基礎上封裝的一個控件,我們可以直接用這個控件去顯示Web頁面,直接用HTML文件做為布局文件,可以和JavaScript交互調用。簡單的說:WebView就是一個嵌套在界面上的浏覽器控件。

2、WebView的屬性和方法

下面我們了解一下WebView的常用屬性和方法

WebSettings:WebView相關配置的設置,可以通過WebView.getSettings得到設置,相關方法如下:

getSettings():返回一個WebSettings對象,用來控制WebView的屬性設置

loadUrl(String url):加載指定的Url

loadData(String data,String mimeType,String encoding):加載指定的Data到WebView中.data:是要加載的數據類型,但在數據裡面不能出現英文字符:’#’, ‘%’, ‘\’ , ‘?’ 這四個字符.其中mimeType為數據類型如:textml,image/jpeg. encoding為字符的編碼方式

loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl):作用跟上一個方法一樣,但是比上一個更加強大,推薦使用,其中baseUrl是HTML代碼片段中相關資源的相對根路徑;historyUrl是歷史Url。其余三個參數同上

setWebViewClient(WebViewClient client):為WebView指定一個WebViewClient對象.WebViewClient可以輔助WebView處理各種通知,請求等事件。

setWebChromeClient(WebChromeClient client):為WebView指定一個WebChromeClient對象,WebChromeClient專門用來輔助WebView處理js的對話框,網站title,網站圖標,加載進度條等

WebViewClient:輔助WebView處理各種通知與請求事件,常用如下的方法:

onPageStared(WebView view,String url):通知主程序網頁開始加載

onPageFinished(WebView view,String url,Bitmap favicon):通知主程序,網頁加載完畢

doUpdateVisitedHistory(WebView view,String url,boolean isReload):更新歷史記錄

onLoadResource(WebView view,String url):通知主程序WebView即將加載指定url的資源

onScaleChanged(WebView view,float oldScale,float newScale):WebView的縮放發生改變時調用

shouldOverrideKeyEvent(WebView view,KeyEvent event):控制webView是否處理按鍵事件,如果返回true,則WebView不處理,返回false則處理

shouldOverrideUrlLoading(WebView view,String url):控制對新加載的Url的處理,返回true,WebView不做處理,返回false,WebView會對其進行處理

onReceivedError(WebView view,int errorCode,String description,String failingUrl):遇到不可恢復的錯誤信息時調用

WebChromeClient:輔助WebView處理Javascript的對話框、網站圖標、網站title、加載進度等,常用方法如下:

onJsAlert(WebView view,String url,String message,JsResult result):處理Js中的Alert對話框

onJsConfirm(WebView view,String url,String message,JsResult result):處理Js中的Confirm對話框

onJsPrompt(WebView view,String url,String message,String defaultValue,JsPromptResult result):處理Js中的Prompt對話框

onProgressChanged(WebView view,int newProgress):當加載進度條發生改變時調用

onReceivedIcon(WebView view, Bitmap icon):獲得網頁的icon

onReceivedTitle(WebView view, String title):獲得網頁的標題

這裡只是一部分的方法,還有其它的可以自行查看官方文檔:WebSettings WebViewClient WebChromeClient

3、WebView基本使用

上面我們介紹了WebView的基本概念和一些常用方法和屬性,下面我們來具體使用一下WebView這個控件:

WebView可以在XML文件中指定,也可以在Java代碼中生成,下面我們就是用在Java代碼中生成的方法:

package com.example.webview;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

/**
 * Created by Devin on 2016/8/4.
 */
public class FirstWebViewActivity extends AppCompatActivity {

private WebView mWebView;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_first);
    mWebView = new WebView(this);
    //設置在當前界面打開網頁,如果不設置的話會使用手機浏覽器打開網頁
    mWebView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            view.loadUrl("https://www.baidu.com/");
            return true;
        }
    });
    mWebView.loadUrl("https://www.baidu.com/");
    //獲取到WebSettings
    WebSettings webSettings = mWebView.getSettings();
    //設置允許加載JS
    webSettings.setJavaScriptEnabled(true);
    setContentView(mWebView);
}
}

布局文件非常簡單,就是一個布局文件而已,就不再貼代碼了。運行效果圖:

\

這樣就可以實現一個簡單的WebView使用例子,下面我們來學習其它的使用<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMyBpZD0="4webview與js的交互">4、WebView與JS的交互

上面我們學習了WebView的基本概念、常用方法、和基本使用等,我們都知道,現在HTML中有很多的JS腳本,當我們Android需要和這些JS腳本做交互的時候,需要怎麼實現呢?下面我們一起來學習WebView與JS的交互。

4.1、HTML通過JS調用Java代碼

我們通過一個例子來體會一下JS調用Java代碼:

HTML代碼:










暴露的對象:

package com.example.webview;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.webkit.JavascriptInterface;
import android.widget.Toast;

/**
 * Created by Devin on 2016/8/4.
 * 提供方法給JS調用
 *
 * @JavascriptInterface 版本兼容問題,需要在調用的方法上添加這個注解和導入這個import android.webkit.JavascriptInterface包
 */
public class JS2Java {

private Context mContext;

public JS2Java(Context mContext) {
    this.mContext = mContext;
}

/**
 * 顯示吐司
 *
 * @param content
 */
@JavascriptInterface
public void showToast(String content) {
    Toast.makeText(mContext, content, Toast.LENGTH_SHORT).show();
}

/**
 * 顯示普通列表對話框
 */
@JavascriptInterface
public void showListDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
    builder.setTitle("普通的列表對話框");
    builder.setItems(new String[]{"打籃球", "踢足球", "跑步", "游泳", "打羽毛球", "打乒乓球"}, null);
    builder.setPositiveButton("選好了", null);
    builder.create();
    builder.show();
}

/**
 * 顯示單選對話框
 */
@JavascriptInterface
public void showSingleChoice() {
    final String[] mChoices = {"五花肉炒西蘭花", "泡菜豆腐湯", "雞腿菇炒豆腐", "老火靓湯", "廣州文昌雞", "燒鵝", "白灼蝦"};
    final String[] select = {""};
    AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
    builder.setTitle("選擇你喜歡的菜");
    builder.setSingleChoiceItems(mChoices, 0, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            select[0] = mChoices[i];
        }
    });
    builder.setPositiveButton("選好了", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            ToastUtils.showToast(mContext, "選擇了:" + select[0]);
        }
    });
    builder.create();
    builder.show();
}

/**
 * 顯示多選對話框
 */
@JavascriptInterface
public void showChoices() {
    final String[] menu = {"絲瓜面筋", "糖醋鯉魚", "糖醋排骨", "剁椒魚頭", "清蒸鹹魚", "魚香肉絲", "清炒上海青", "麻婆豆腐"};
    final boolean[] isCheck = {false, false, false, false, false, false, false, false};
    AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
    builder.setTitle("請選擇你的想要的菜");
    builder.setMultiChoiceItems(menu, isCheck, new DialogInterface.OnMultiChoiceClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i, boolean b) {
            isCheck[i] = b;
        }
    });
    builder.setPositiveButton("選好了", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            String select = "";
            for (int j = 0; j < isCheck.length; j++) {
                if (isCheck[j]) {
                    select += menu[j];
                }
            }
            ToastUtils.showToast(mContext, "你選擇的菜有:" + select);
        }
    });
    builder.create();
    builder.show();
}


}

最後是Activity代碼:

public class JS2JavaActivity extends AppCompatActivity {

private WebView mWebView;

@SuppressLint("JavascriptInterface")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_js2java);
    mWebView = (WebView) findViewById(R.id.js2java);
    mWebView.loadUrl("file:///android_asset/js2java.html");
    //獲取到webSettings
    WebSettings webSettings = mWebView.getSettings();
    //設置允許加載JS
    webSettings.setJavaScriptEnabled(true);
    webSettings.setDefaultTextEncodingName("UTF-8");
    //調用addJavascriptInterface方法,將JS2Java對象暴露給JS
    mWebView.addJavascriptInterface(new JS2Java(JS2JavaActivity.this), "jS2Java");
}
}

實現的效果圖如下:

\

4.2、Android調用HTML中的JS代碼

我們實現一個例子:點擊Android的中按鈕,彈出一個多選列表,選擇之後將選擇的項傳遞給HTML頁面,並將選擇項通過innerHTML寫到HTML頁面上:

布局代碼:


HTML頁面代碼:



<script language="JavaScript">
        function showText(content){
             document.getElementById("demo").innerHTML="你選擇的菜有:"+content;
        }
    </script>

 

Activity代碼:

package com.example.webview;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Button;

/**
 * Created by Devin on 2016/8/4.
 */
public class Java2JSActivity extends AppCompatActivity {

private WebView mWebView;
private Button btn_show_js_alert;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_java2js);
    mWebView = (WebView) findViewById(R.id.webview1);

    WebSettings webSettings = mWebView.getSettings();
    webSettings.setJavaScriptEnabled(true);
    mWebView.loadUrl("file:///android_asset/java2js.html");

    btn_show_js_alert = (Button) findViewById(R.id.btn_show_js_alert);
    btn_show_js_alert.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            final String[] menu = {"絲瓜面筋", "糖醋鯉魚", "糖醋排骨", "剁椒魚頭", "清蒸鹹魚", "魚香肉絲", "清炒上海青", "麻婆豆腐"};
            final boolean[] isCheck = {false, false, false, false, false, false, false, false};
            AlertDialog.Builder builder = new AlertDialog.Builder(Java2JSActivity.this);
            builder.setTitle("請選擇你的想要的菜");
            builder.setMultiChoiceItems(menu, isCheck, new DialogInterface.OnMultiChoiceClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i, boolean b) {
                    isCheck[i] = b;
                }
            });
            builder.setPositiveButton("選好了", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    String select = "";
                    for (int j = 0; j < isCheck.length; j++) {
                        if (isCheck[j]) {
                            select += menu[j];
                        }
                    }
                    ToastUtils.showToast(Java2JSActivity.this, "你選擇的菜有:" + select);
                    mWebView.loadUrl("javascript:showText('" + select + "')");
                }
            });
            builder.create();
            builder.show();
        }
    });

}
}

實現的效果圖:

\

這樣實現了Android調用JS的代碼,並實現參數傳遞。

5、WebView文件下載

我們知道WebView是浏覽器的一個組件,我們可以通過浏覽器下載很多東西,那麼也可以通過WebView來實現文件的下載,下面我們通過例子實現文件的下載:

第一種下載方式:通過系統自身下載方式下載

package com.example.webview;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.webkit.DownloadListener;
import android.webkit.WebView;

/**
 * Created by Devin on 2016/8/5.
 */
public class FirstDownloadActivity extends AppCompatActivity {
private WebView mWebView;
private String url = "http://sqdd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk";

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_downfirst);
    mWebView = (WebView) findViewById(R.id.wv_first);
    mWebView.loadUrl(url);
    //為WebView設置setDownloadListener,然後重寫DownloadListener的 onDownloadStart,
    // 然後在裡面寫個Intent,然後startActivity對應的Activity即可!
    //這種方式會在通知欄顯示進度,如果手機安裝有多個浏覽器,會彈出讓用戶自己選擇下載的浏覽器
    mWebView.setDownloadListener(new DownloadListener() {
        @Override
        public void onDownloadStart(String url, String userAgent, String contentDisposition,String mimeType, long contentLength) {
            Uri uri = Uri.parse(url);
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
            startActivity(intent);
        }
    });
}
}

實現效果圖:

\

第二種:實現自定義下載操作類:

package com.example.webview;

import android.content.Context;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by Devin on 2016/8/5.
 */
public class DownLoadThread extends Thread {
private static final String TAG = "DownLoadThread";
private String downLoadUrl;
private Context context;
private FileOutputStream out = null;
private File downLoadFile = null;
private File sdCardFile = null;
private InputStream in = null;

public DownLoadThread(Context context, String downLoadUrl) {
    super();
    this.context = context;
    this.downLoadUrl = downLoadUrl;

}

@Override
public void run() {
    Log.i(TAG, "開始下載APK文件");
    try {
        URL httpUrl = new URL(downLoadUrl);
        HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
        conn.setDoInput(true);
        conn.setDoOutput(true);
        in = conn.getInputStream();
        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            Toast.makeText(context, "SD卡不可用!", Toast.LENGTH_SHORT).show();
            return;
        }
        downLoadFile = Environment.getExternalStorageDirectory();
        sdCardFile = new File(downLoadFile, "download.apk");
        out = new FileOutputStream(sdCardFile);
        byte[] b = new byte[1024];
        int len;
        Log.i(TAG, "正在下載APK");
        while ((len = in.read(b)) != -1) {
            out.write(b, 0, len);
        }
        if (out != null) {
            out.close();
        }
        if (in != null) {
            in.close();
        }
        Log.i(TAG, "下載APK文件完成");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}


package com.example.webview;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.webkit.DownloadListener;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;

/**
 * Created by Devin on 2016/8/5.
 */
public class SecondDownloadActivity extends AppCompatActivity {
private String url = "http://sqdd.myapp.com/myapp/qqteam/AndroidQQ/mobileqq_android.apk";
private WebView mWebView;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_downsecond);
    mWebView = (WebView) findViewById(R.id.wv_second);
    mWebView.loadUrl(url);
    mWebView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            view.loadUrl(url);
            return true;
        }
    });
    mWebView.setDownloadListener(new DownloadListener() {
        @Override
        public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
            new DownLoadThread(SecondDownloadActivity.this, url).start();
        }
    });
}
}

實現效果圖:

\

如此可是現實WebView下載文件

6、WebView緩存機制

現在很多門戶信息類網站的APP都是用WebView實現數據展示,這就涉及到了WebView的緩存問題。WebView中存在著兩種緩存,分別是:網頁數據緩存(存儲打開過的頁面及資源)、H5緩存(即AppCache)。

網頁數據緩存

當我們用WebView加載HTML的時候,會在data/應用package下生成database與cache兩個文件夾:

/data/data/package_name/cache/
/data/data/package_name/database/webview.db
/data/data/package_name/database/webviewCache.db

其中我們請求的Url記錄是保存在webviewCache.db裡,而url的內容是保存在webviewCache文件夾下。有五中緩存模式:

LOAD_CACHE_ONLY: 不使用網絡,只讀取本地緩存數據

LOAD_DEFAULT: 根據cache-control決定是否從網絡上取數據。

LOAD_CACHE_NORMAL: API level 17中已經廢棄, 從API level 11開始作用同LOAD_DEFAULT模式

LOAD_NO_CACHE: 不使用緩存,只從網絡獲取數據.

LOAD_CACHE_ELSE_NETWORK,只要本地有,無論是否過期,或者no-cache,都使用緩存中的數據。

使用這五種緩存模式的策略是:判斷是否有網絡,有的話,使用LOAD_DEFAULT,無網絡時,使用LOAD_CACHE_ELSE_NETWORK。

清除緩存需要調用clearCache(boolean),CacheManager.clear高版本中需要調用隱藏API。

H5緩存

1、緩存構成,根據setAppCachePath(String appCachePath)提供的路徑,在H5使用緩存過程中生成的緩存文件。

2、緩存模式,無模式選擇,通過setAppCacheEnabled(boolean flag)設置是否打開。默認關閉,即,H5的緩存無法使用。

3、清除緩存,找到調用setAppCachePath(String appCachePath)設置緩存的路徑,把它下面的文件全部刪除就OK了。

4、控制大小,通過setAppCacheMaxSize(long appCacheMaxSize)設置緩存最大容量,默認為Max Integer。同時,可能通過覆蓋WebChromeClient.onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater)來設置緩存超過先前設置的最大容量時的策略。

7、WebView常見問題匯總

1.為WebView自定義錯誤顯示界面,覆寫WebViewClient中的onReceivedError()方法:

2.WebView cookies清理:

CookieSyncManager.createInstance(this);   
CookieSyncManager.getInstance().startSync();   
CookieManager.getInstance().removeSessionCookie();

3.清理cache 和歷史記錄:

webView.clearCache(true);   
webView.clearHistory();  

4.判斷WebView是否已經滾動到頁面底端:

getScrollY()方法返回的是當前可見區域的頂端距整個頁面頂端的距離,也就是當前內容滾動的距離.   
getHeight()或者getBottom()方法都返回當前WebView 這個容器的高度   
getContentHeight 返回的是整個html 的高度,但並不等同於當前整個頁面的高度,因為WebView 有縮放功能, 所以當前整個頁面的高度實際上應該是原始html 的高度再乘上縮放比例. 因此,更正後的結果,准確的判斷方法應該是:   
if(WebView.getContentHeight*WebView.getScale() == (webview.getHeight()+WebView.getScrollY())){ //已經處於底端 } 

5.WebView保留縮放功能但隱藏縮放控件:

    mWebView.getSettings().setSupportZoom(true);  
    mWebView.getSettings().setBuiltInZoomControls(true);  
    if (DeviceUtils.hasHoneycomb())  
          mWebView.getSettings().setDisplayZoomControls(false);  

6.在WebView加入 flash支持:

String temp = "

"; String mimeType = "text/html"; String encoding = "utf-8"; web.loadDataWithBaseURL("null", temp, mimeType, encoding, "");

7.屏蔽掉長按事件 因為webview長按時將會調用系統的復制控件:

mWebView.setOnLongClickListener(new OnLongClickListener() {  

      @Override  
      public boolean onLongClick(View v) {  
          return true;  
      }  
  });  

8.在頁面中先顯示圖片:

    @Override  
    public void onLoadResource(WebView view, String url) {  
      mEventListener.onWebViewEvent(CustomWebView.this, OnWebViewEventListener.EVENT_ON_LOAD_RESOURCE, url);  
if (url.indexOf(".jpg") > 0) {  
 hideProgress(); //請求圖片時即顯示頁面  
 mEventListener.onWebViewEvent(CustomWebView.this, OnWebViewEventListener.EVENT_ON_HIDE_PROGRESS, view.getUrl());  
 }  
super.onLoadResource(view, url);  
}  

9.處理WebView中的非超鏈接請求(如Ajax請求):

@SuppressLint("NewApi")  
@Override  
public WebResourceResponse shouldInterceptRequest(WebView view,String url) {  
// 非超鏈接(如Ajax)請求無法直接添加請求頭,現拼接到url末尾,這裡拼接一個imei作為示例  

String ajaxUrl = url;  
// 如標識:req=ajax  
if (url.contains("req=ajax")) {  
   ajaxUrl += "&imei=" + imei;  
}  

return super.shouldInterceptRequest(view, ajaxUrl);  

} 

10.WebView頁面中播放了音頻,退出Activity後音頻仍然在播放:

webView.destroy(); 

WebView網頁控件就介紹到這裡了,最後附上國內鏡像API

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved