Android控件十五:WebView使用(一):Native與JS相互調用

原文:https://blog.csdn.net/harvic880925/article/details/51464687

一、基本用法

1、加載在線URL
void loadUrl(String url)
如:
mWebView.loadUrl(“http://www.baidu.com”);
這個函數主要加載url所對應的網頁地址,或者用於調用網頁中的指定的JS方法,但有一點必須注意的是:loadUrl()必須在主線程中執行!!!否則就會報錯!!!。
加載在線網頁地址是會用到聯網permission權限的,所以需要在AndroidManifest.xml中寫入下面代碼申請權限:

注意:上種情況默認使用系統瀏覽器打開,要使用webview打開,需要設置WebViewClient實例
mWebView.setWebViewClient(new WebViewClient());

2、加載本地URL
本地web文件路徑:assets/xx.html
如:
mWebView.loadUrl(“file:///android_asset/web.html”);

總結:

  1. 如果是在線網址記得添加網絡訪問權限
  2. 在線網址中,如果要使用webview打開,記得設置WebViewClient
  3. 打開本地html文件時,是不需要設置WebViewClient,對應的asstes目錄的url爲:file:///android_asset/xxxxx

3、WebView基本設置
如果我們需要設置WebView的屬性,是通過WebView.getSettings()獲取設置WebView的WebSettings對象,然後調用WebSettings中的方法來實現的。
WebSettings的方法簡介:

			/**
			* 是否支持縮放,配合方法setBuiltInZoomControls使用,默認true
			*/
			setSupportZoom(boolean support)
			 
			/**
			* 是否需要用戶手勢來播放Media,默認true
			*/
			setMediaPlaybackRequiresUserGesture(boolean require)
			 
			/**
			* 是否使用WebView內置的縮放組件,由浮動在窗口上的縮放控制和手勢縮放控制組成,默認false
			*/
			setBuiltInZoomControls(boolean enabled)
			 
			/**
			* 是否顯示窗口懸浮的縮放控制,默認true
			*/
			setDisplayZoomControls(boolean enabled)
			 
			/**
			* 是否允許訪問WebView內部文件,默認true
			*/
			setAllowFileAccess(boolean allow)
			 
			/**
			* 是否允許獲取WebView的內容URL ,可以讓WebView訪問ContentPrivider存儲的內容。 默認true
			*/
			setAllowContentAccess(boolean allow)
			 
			/**
			* 是否啓動概述模式瀏覽界面,當頁面寬度超過WebView顯示寬度時,縮小頁面適應WebView。默認false
			*/
			setLoadWithOverviewMode(boolean overview)
			 
			/**
			* 是否保存表單數據,默認false
			*/
			setSaveFormData(boolean save)
			 
			/**
			* 設置頁面文字縮放百分比,默認100%
			*/
			setTextZoom(int textZoom)
			 
			/**
			* 是否支持ViewPort的meta tag屬性,如果頁面有ViewPort meta tag 指定的寬度,則使用meta tag指定的值,否則默認使用寬屏的視圖窗口
			*/
			setUseWideViewPort(boolean use)
			 
			 
			/**
			* 是否支持多窗口,如果設置爲true ,WebChromeClient#onCreateWindow方法必須被主程序實現,默認false
			*/
			setSupportMultipleWindows(boolean support)
			 
			/**
			* 指定WebView的頁面佈局顯示形式,調用該方法會引起頁面重繪。默認LayoutAlgorithm#NARROW_COLUMNS
			*/
			setLayoutAlgorithm(LayoutAlgorithm l)
			 
			/**
			* 設置標準的字體族,默認”sans-serif”。font-family 規定元素的字體系列。
			* font-family 可以把多個字體名稱作爲一個“回退”系統來保存。如果瀏覽器不支持第一個字體,
			* 則會嘗試下一個。也就是說,font-family 屬性的值是用於某個元素的字體族名稱或/及類族名稱的一個
			* 優先表。瀏覽器會使用它可識別的第一個值。
			*/
			setStandardFontFamily(String font)
			 
			/**
			* 設置混合字體族。默認”monospace”
			*/
			setFixedFontFamily(String font)
			 
			/**
			* 設置SansSerif字體族。默認”sans-serif”
			*/
			setSansSerifFontFamily(String font)
			 
			/**
			* 設置SerifFont字體族,默認”sans-serif”
			*/
			setSerifFontFamily(String font)
			 
			/**
			* 設置CursiveFont字體族,默認”cursive”
			*/
			setCursiveFontFamily(String font)
			 
			/**
			* 設置FantasyFont字體族,默認”fantasy”
			*/
			setFantasyFontFamily(String font)
			 
			/**
			* 設置最小字體,默認8. 取值區間[1-72],超過範圍,使用其上限值。
			*/
			setMinimumFontSize(int size)
			 
			/**
			* 設置最小邏輯字體,默認8. 取值區間[1-72],超過範圍,使用其上限值。
			*/
			setMinimumLogicalFontSize(int size)
			 
			/**
			* 設置默認字體大小,默認16,取值區間[1-72],超過範圍,使用其上限值。
			*/
			setDefaultFontSize(int size)
			 
			/**
			* 設置默認填充字體大小,默認16,取值區間[1-72],超過範圍,使用其上限值。
			*/
			setDefaultFixedFontSize(int size)
			 
			/**
			* 設置是否加載圖片資源,注意:方法控制所有的資源圖片顯示,包括嵌入的本地圖片資源。
			* 使用方法setBlockNetworkImage則只限制網絡資源圖片的顯示。值設置爲true後,
			* webview會自動加載網絡圖片。默認true
			*/
			setLoadsImagesAutomatically(boolean flag)
			 
			/**
			* 是否加載網絡圖片資源。注意如果getLoadsImagesAutomatically返回false,則該方法沒有效果。
			* 如果使用setBlockNetworkLoads設置爲false,該方法設置爲false,也不會顯示網絡圖片。
			* 當值從true改爲false時。WebView會自動加載網絡圖片。
			*/
			setBlockNetworkImage(boolean flag)
			 
			/**
			* 設置是否加載網絡資源。注意如果值從true切換爲false後,WebView不會自動加載,
			* 除非調用WebView#reload().如果沒有android.Manifest.permission#INTERNET權限,
			* 值設爲false,則會拋出java.lang.SecurityException異常。
			* 默認值:有android.Manifest.permission#INTERNET權限時爲false,其他爲true。
			*/
			setBlockNetworkLoads(boolean flag)
			 
			/**
			* 設置是否允許執行JS。
			*/
			setJavaScriptEnabled(boolean flag)
			 
			/**
			* 是否允許Js訪問任何來源的內容。包括訪問file scheme的URLs。考慮到安全性,
			* 限制Js訪問範圍默認禁用。注意:該方法隻影響file scheme類型的資源,其他類型資源如圖片類型的,
			* 不會受到影響。ICE_CREAM_SANDWICH_MR1版本以及以下默認爲true,JELLY_BEAN版本
			* 以上默認爲false
			*/
			setAllowUniversalAccessFromFileURLs(boolean flag)
			 
			 
			/**
			* 是否允許Js訪問其他file scheme的URLs。包括訪問file scheme的資源。考慮到安全性,
			* 限制Js訪問範圍默認禁用。注意:該方法隻影響file scheme類型的資源,其他類型資源如圖片類型的,
			* 不會受到影響。如果getAllowUniversalAccessFromFileURLs爲true,則該方法被忽略。
			* ICE_CREAM_SANDWICH_MR1版本以及以下默認爲true,JELLY_BEAN版本以上默認爲false
			*/
			setAllowFileAccessFromFileURLs(boolean flag)
			 
			/**
			* 設置存儲定位數據庫的位置,考慮到位置權限和持久化Cache緩存,Application需要擁有指定路徑的
			* write權限
			*/
			setGeolocationDatabasePath(String databasePath)
			 
			/**
			* 是否允許Cache,默認false。考慮需要存儲緩存,應該爲緩存指定存儲路徑setAppCachePath
			*/
			setAppCacheEnabled(boolean flag)
			 
			/**
			* 設置Cache API緩存路徑。爲了保證可以訪問Cache,Application需要擁有指定路徑的write權限。
			* 該方法應該只調用一次,多次調用自動忽略。
			*/
			setAppCachePath(String appCachePath)
			 
			/**
			* 是否允許數據庫存儲。默認false。查看setDatabasePath API 如何正確設置數據庫存儲。
			* 該設置擁有全局特性,同一進程所有WebView實例共用同一配置。注意:保證在同一進程的任一WebView
			* 加載頁面之前修改該屬性,因爲在這之後設置WebView可能會忽略該配置
			*/
			setDatabaseEnabled(boolean flag)
			 
			/**
			* 是否存儲頁面DOM結構,默認false。
			*/
			setDomStorageEnabled(boolean flag)
			 
			/**
			* 是否允許定位,默認true。注意:爲了保證定位可以使用,要保證以下幾點:
			* Application 需要有android.Manifest.permission#ACCESS_COARSE_LOCATION的權限
			* Application 需要實現WebChromeClient#onGeolocationPermissionsShowPrompt的回調,
			* 接收Js定位請求訪問地理位置的通知
			*/
			setGeolocationEnabled(boolean flag)
			 
			/**
			* 是否允許JS自動打開窗口。默認false
			*/
			setJavaScriptCanOpenWindowsAutomatically(boolean flag)
			 
			/**
			* 設置頁面的編碼格式,默認UTF-8
			*/
			setDefaultTextEncodingName(String encoding)
			 
			/**
			* 設置WebView代理,默認使用默認值
			*/
			setUserAgentString(String ua)
			 
			/**
			* 通知WebView是否需要設置一個節點獲取焦點當
			* WebView#requestFocus(int,android.graphics.Rect)被調用的時候,默認true
			*/
			setNeedInitialFocus(boolean flag)
			 
			/**
			* 基於WebView導航的類型使用緩存:正常頁面加載會加載緩存並按需判斷內容是否需要重新驗證。
			* 如果是頁面返回,頁面內容不會重新加載,直接從緩存中恢復。setCacheMode允許客戶端根據指定的模式來
			* 使用緩存。
			* LOAD_DEFAULT 默認加載方式
			* LOAD_CACHE_ELSE_NETWORK 按網絡情況使用緩存
			* LOAD_NO_CACHE 不使用緩存
			* LOAD_CACHE_ONLY 只使用緩存
			*/
			setCacheMode(int mode)
			 
			/**
			* 設置加載不安全資源的WebView加載行爲。KITKAT版本以及以下默認爲MIXED_CONTENT_ALWAYS_ALLOW方
			* 式,LOLLIPOP默認MIXED_CONTENT_NEVER_ALLOW。強烈建議:使用MIXED_CONTENT_NEVER_ALLOW
			*/
			setMixedContentMode(int mode)
		
		使用實例:
			示例1:在WebView中啓用JavaScript:
				WebSettings webSettings = mWebView.getSettings();
				webSettings.setJavaScriptEnabled(true);
				
			示例2:設置緩存
				優先使用緩存
				webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
				不使用緩存:
				webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
			示例3:打開頁面時, 自適應屏幕:
				WebSettings webSettings =   mWebView .getSettings();       
				webSettings.setUseWideViewPort(true);//設置此屬性,可任意比例縮放
				webSettings.setLoadWithOverviewMode(true);
			示例4:使頁面支持縮放:
				WebSettings webSettings = mWebView.getSettings();
				//開啓javascript支持
				webSettings.setJavaScriptEnabled(true); 
				// 設置可以支持縮放
				webSettings.setSupportZoom(true);
				// 設置出現縮放工具
				webSettings.setBuiltInZoomControls(true);
				
			示例5:.如果webView中需要用戶手動輸入用戶名、密碼或其他,則webview必須設置支持獲取手勢焦點
				webview.requestFocusFromTouch();	

二、JS調用Java代碼

1、概述
更多時候,網頁中需要通過JS代碼來調用本地的Android代碼,比如H5頁面需要判斷當前用戶是否登錄等。
利用JS代碼調用JAVA代碼,主要是用到WebView下面的一個函數:
public void addJavascriptInterface(Object obj, String interfaceName)
這個函數有兩個參數:
Object obj:interfaceName所綁定的對象
String interfaceName:所綁定的對象所對應的名稱
它有意義就是向WebView注入一個interfaceName的對象,這個對象綁定的是obj對象,通過interfaceName就可以調用obj對象中的方法

2,實例

Android代碼:

			public class MyActivity extends Activity {

				private WebView mWebView;
				private Button mBtn;
			 
				@Override
				public void onCreate(Bundle savedInstanceState) {
					super.onCreate(savedInstanceState);
					setContentView(R.layout.main);
			 
					mWebView = (WebView) findViewById(R.id.webview);
			 
					WebSettings webSettings = mWebView.getSettings();
					webSettings.setJavaScriptEnabled(true);
					//把MyActivity對象注入到WebView中,在WebView中的對象別名叫android
					mWebView.addJavascriptInterface(this, "android");
					mWebView.loadUrl("file:///android_asset/web.html");
				}
				
				//用於彈出MSG 
				public void toastMessage(String message) {
					Toast.makeText(getApplicationContext(), "通過Natvie傳遞的Toast:"+message, Toast.LENGTH_LONG).show();
				}
			}    

HTML代碼:

			<!DOCTYPE html>
			<html lang="en">
			<head>
				<meta charset="UTF-8">
				<title>Title</title>
				<h1>歡迎光臨啓艦的blog</h1>
				<input type="button" value="js調native" onclick="ok()">
			</head>
			<body>
				<script type="text/javascript">
					function ok() {
					android.toastMessage("哈哈,i m webview msg");
					}
				</script>
			</body>
			</html>

它的意義就是調用android對象裏的toastMessage方法,這個android就是我們利用mWebView.addJavascriptInterface(this, “android”)注入到WebView的android,它所對應的對象就將MyActivity;所以在JS中,我們就可以通過android這個別名來調用MyActivity對象中的任何public方法。

3、addJavascriptInterface自定義作用對象
mWebView.addJavascriptInterface(this, “android”);我們直接通過this,把當前整個類作爲對象傳給WebView了,但這會有很大風險,因爲我們這個類中可能會有各種函數,而這些函數是隻有本地Native代碼纔會用到,WebView是根本用不到的。所以,一般而言,我們很少直接會傳this,把整個類注入給WebView,而是單獨寫一個類專門用於JS交互,比如:

		public class MyActivity extends Activity {
			private WebView mWebView;
			private Button mBtn;
		 
			@Override
			public void onCreate(Bundle savedInstanceState) {
				super.onCreate(savedInstanceState);
				setContentView(R.layout.main);
		 
				mWebView = (WebView) findViewById(R.id.webview);
				mBtn = (Button) findViewById(R.id.btn);
		 
				WebSettings webSettings = mWebView.getSettings();
				webSettings.setJavaScriptEnabled(true);
				mWebView.addJavascriptInterface(new JSBridge(), "android");
				mWebView.loadUrl("file:///android_asset/web.html");
			}
		 
			public class JSBridge{
				public void toastMessage(String message) {
					Toast.makeText(getApplicationContext(), "通過Natvie傳遞的Toast:"+message, Toast.LENGTH_LONG).show();
				}
			}
		}    
		
		JS調用時與上面一樣:
			android.toastMessage("哈哈,i m webview msg");

4、JavascriptInterface註解
爲了解決addJavascriptInterface()函數的安全問題,在android:targetSdkVersion數值爲17(Android4.2)及以上的APP中,JS只能訪問帶有 @JavascriptInterface註解的Java函數,所以如果你的android:targetSdkVersion是17+,與JS交互的Native函數中,必須添加JavascriptInterface註解,不然無效,
比如:

			public class JSBridge {
				@JavascriptInterface
				public void toastMessage(String message) {
					Toast.makeText(getApplicationContext(), "通過Natvie傳遞的Toast:" + message, Toast.LENGTH_LONG).show();
				}
			}

三、JAVA調用JS代碼

1、JAVA調用JS代碼(調用webview中的JavaScript求和函數)
html代碼:

			<!DOCTYPE html>
			<html lang="en">
			<head>
				<meta charset="UTF-8">
				<title>Title</title>
				<h1 id="h">歡迎光臨啓艦的blog</h1>
				<input type="button" value="js調native" onclick="ok()">
			</head>
			<body>
				<script type="text/javascript">
				function sum(i,m)
					{
					document.getElementById("h").innerHTML= (i+m);
					}
				</script>
			</body>
			</html>

JAVA的調用代碼:

			public class MyActivity extends Activity {
			 
				private WebView mWebView;
				private Button mBtn;
			 
				@Override
				public void onCreate(Bundle savedInstanceState) {
					super.onCreate(savedInstanceState);
					setContentView(R.layout.main);
			 
					mWebView = (WebView) findViewById(R.id.webview);
					mBtn = (Button) findViewById(R.id.btn);
			 
					WebSettings webSettings = mWebView.getSettings();
					webSettings.setJavaScriptEnabled(true);
					mWebView.loadUrl("file:///android_asset/web.html");
			 
					mBtn.setOnClickListener(new View.OnClickListener() {
						@Override
						public void onClick(View v) {
							mWebView.loadUrl("javascript:sum(3,8)");
						}
					});
				}
			}       

2、JAVA中如何得到JS中的返回值
Android4.4以前:
(1).Java調用js代碼

				webView.addJavascriptInterface(this, "android");
				mWebView.loadUrl("javascript:sum(3,8)");
			注意,這裏通過addJavascriptInterface將MyActiviy所對應的對象注入到WebView中了。

(2).js函數處理,並將結果通過調用java方法返回

				function sum(i,m){
				var result = i+m;
				document.getElementById("h").innerHTML= result;
				android.onSumResult(result)
				}

(3).Java在回調方法中獲取js函數返回值

				public void onSumResult(int result) {
				 Log.i(LOGTAG, "onSumResult result=" + result);
				}

Android4.4之後:先寫一個具有返回值的js方法

				function getGreetings() {
				return 1; 
				}

java代碼時用evaluateJavascript方法調用:

				private void testEvaluateJavascript(WebView webView) {
				  webView.evaluateJavascript("getGreetings()", new ValueCallback() {
					  @Override
					  public void onReceiveValue(String value) {
						  Log.i(LOGTAG, "onReceiveValue value=" + value);
					  }
				  });
				}

注意:
上面限定了結果返回結果爲String,對於簡單的類型會嘗試轉換成字符串返回,對於複雜的數據類型,建議以字符串形式的json返回。evaluateJavascript方法必須在UI線程(主線程)調用,因此onReceiveValue也執行在主線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章