在頁面布局很復雜並且是動態的時候,android本身的控件就變得不是那么地靈活了,只有借助於網頁的強大布局能力才能實現,但是在操作html頁面的同時也需要與android其它的組件存在交互,比如說
在load一個url時, 用戶點擊頁面內的某個按鈕后, 頁面調用android內的組件函數或由android組件去調用JS代碼去更新頁面,這都是交互問題,聽起來很復雜,其實不用擔心,webview這個類已經幫我們實現了,只需要直接用就好了。
webview用法1
1.在要Activity中實例化WebView組件:WebView webView = new WebView(this);
2.調用WebView的loadUrl()方法,設置WevView要顯示的網頁:
互聯網用:webView.loadUrl("http://www.google.com");
本地文件用:webView.loadUrl("file:///android_asset/XX.html"); 本地文件存放在:assets 文件中
3.調用Activity的setContentView( )方法來顯示網頁視圖
4.用WebView點鏈接看了很多頁以后為了讓WebView支持回退功能,需要覆蓋覆蓋Activity類的onKeyDown()方法,如果不做任何處理,點擊系統回退剪鍵,整個瀏覽器會調用finish()而結束自身,而不是回退到上一頁面
5.需要在AndroidManifest.xml文件中添加權限,否則會出現Web page not available錯誤。
<uses-permission android:name="android.permission.INTERNET" />
webview用法2
1、在布局文件中聲明WebView
2、在Activity中實例化WebView
3、調用WebView的loadUrl( )方法,設置WevView要顯示的網頁
4、為了讓WebView能夠響應超鏈接功能,調用setWebViewClient( )方法,設置 WebView視圖
5、用WebView點鏈接看了很多頁以后為了讓WebView支持回退功能,需要覆蓋覆蓋Activity類的onKeyDown()方法,如果不做任何處理,點擊系統回退剪鍵,整個瀏覽器會調用finish()而結束自身,而不是回退到上一頁面
6、需要在AndroidManifest.xml文件中添加權限,否則出現Web page not available錯誤。
<uses-permission android:name="android.permission.INTERNET"/>
設置webview對象顯示的網頁的函數為loadUrl();
互聯網頁面直接用:
myWebView.loadUrl(“http://www.google.com“);
本地文件用(本地文件存放在:assets文件中):
myWebView.loadUrl(“file:///android_asset/XX.html“);
還可以直接載入html的字符串,如:
String htmlString = "<h1>Title</h1><p>This is HTML text<br /><i>Formatted in italics</i><br />Anothor Line</p>"; // 載入這個html頁面 myWebView.loadData(htmlString, "text/html", "utf-8");
與JS交互調用必須進行下面的設置
可以通過getSettings()
獲得WebSettings,然后用setJavaScriptEnabled()
使能JavaScript:
WebView myWebView = (WebView) findViewById(R.id.webview); WebSettings webSettings = myWebView.getSettings(); webSettings.setJavaScriptEnabled(true);
javascript與android交互
android端代碼:
webView.getSettings().setJavaScriptEnabled(true); webView.addJavascriptInterface(new JSHook(), "hello"); //在JSHook類里實現javascript想調用的方法,並將其實例化傳入webview, "hello"這個字串告訴javascript調用哪個實例的方法
public class JSHook{ public void javaMethod(String p){ Log.d(tag , "JSHook.JavaMethod() called! + "+p); } public void showAndroid(){ String info = "來自手機內的內容!!!"; webView.loadUrl("javascript:show('"+info+"')"); } public String getInfo(){ return "獲取手機內的信息!!"; } }
html端代碼:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>調用Android組件測試</title> <script type="text/javascript"> function show(info){ document.getElementById("shows").innerHTML = info; } </script> </head> <body> <b>測試</b> <br /> <button onClick="window.hello.javaMethod('param')">啟動hello world Activity</button> <br /> <hr color="#99FF00"/> <button onClick="window.hello.showAndroid()">顯示android內容</button> <br /> <textarea id= "shows" cols="20" rows="10"> 暫無記錄 </textarea> <br /> </body> </html>
代碼實現效果圖
補充一下:如果在調用js中的方法時,需要訪問值,只是采用 webView.loadUrl("javascript:show('"+info+"')");沒法得到,可通過兩種方式取得:
1) 在js中的show方法,繼續調用android 原生方法將返回值通過參數的形式傳過來
2)在API19后,android新增接口可直接得到返回值
//第一個參數為js中的方法名,該段代碼每執行一次則調用js方法一次 progressWebView.getWebview().evaluateJavascript("window.hasUserEditData()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //這里為返回值 boolean hasChanged = Boolean.parseBoolean(value); //todo } });
實例代碼
package com.example.jscallandroid; import android.support.v7.app.ActionBarActivity; import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.Window; import android.view.WindowManager; import android.webkit.JavascriptInterface; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; public class MainActivity extends ActionBarActivity { //private static final String URL = "http://shouji.baidu.com/"; private static final String URL = "file:///android_asset/helloworld.html"; private WebView webView; public String tag = "MainActivity"; private Context mContext; @SuppressLint("JavascriptInterface") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); // 進行全屏 mContext = this; this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); webView = (WebView) this.findViewById(R.id.wv); webView.loadUrl(URL); webView.getSettings().setJavaScriptEnabled(true); webView.addJavascriptInterface(new JSHook(), "hello"); webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { Log.d(tag, " url:"+url); view.loadUrl(url);// 當打開新鏈接時,使用當前的 WebView,不會使用系統其他瀏覽器 return true; } }); } public class JSHook{ @JavascriptInterface public void javaMethod(String p){ Log.d(tag , "JSHook.JavaMethod() called! + "+p); } @JavascriptInterface public void showAndroid(){ final String info = "來自手機內的內容!!!"; MainActivity.this.runOnUiThread(new Runnable(){ @Override public void run() { webView.loadUrl("javascript:show('"+info+"')"); } }); } public String getInfo(){ return "獲取手機內的信息!!"; } } @Override //設置回退 //覆蓋Activity類的onKeyDown(int keyCoder,KeyEvent event)方法 public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) { webView.goBack(); //goBack()表示返回WebView的上一頁面 this.finish(); return true; } return false; } }
可能的異常:
public class JSHook{ public void javaMethod(String p){ Log.d(tag , "JSHook.JavaMethod() called! + "+p); } public void showAndroid(){ String info = "來自手機內的內容!!!"; webView.loadUrl("javascript:show('"+info+"')"); } public String getInfo(){ return "獲取手機內的信息!!"; } }
上面這段代碼在android4.4版本及之前是沒有問題的, 4.4之后就會出現以下兩個異常錯誤。
07-10 10:25:21.417: I/chromium(27333): [INFO:CONSOLE(19)] "Uncaught TypeError: Object [object Object] has no method 'showAndroid'", source: file:///android_asset/helloworld.html (19)
解決方法:在js調用方法上面加注解@JavascriptInterface
07-10 10:42:58.437: I/chromium(27621): [INFO:CONSOLE(19)] "Uncaught Error: Error calling method on NPObject.", source: file:///android_asset/helloworld.html (19)
解決方法:在對界面進行修改時必須在UI線程進行,即便它是Html的界面,因此在出現這個錯誤的時候可以用handler或runOnUiThread()方法去執行更新UI操作。
注:實例代碼是排除了在高版本中出現異常的最終代碼。
異常原因:
webview允許JavaScript 控制宿主應用程序,這是個很強大的特性,但同時,在4.2的版本前存在重大安全隱患,因為JavaScript 可以使用反射訪問注入webview的java對象的public fields,在一個包含不信任內容的WebView中使用這個方法,會允許攻擊者去篡改宿主應用程序,使用宿主應用程序的權限執行java代碼。因此4.2以后,任何為JS暴露的接口,都需要加
@JavascriptInterface
注解,這樣,這個Java對象的fields 將不允許被JS訪問。
API
public void addJavascriptInterface (Object object, String name)
Injects the supplied Java object into this WebView. The object is injected into the JavaScript context of the main frame, using the supplied name. This allows the Java object's methods to be accessed from JavaScript. For applications targeted to API level JELLY_BEAN_MR1
and above, only public methods that are annotated with JavascriptInterface
can be accessed from JavaScript. For applications targeted to API level JELLY_BEAN
or below, all public methods (including the inherited ones) can be accessed, see the important security note below for implications.
Note that injected objects will not appear in JavaScript until the page is next (re)loaded. For example:
class JsObject { @JavascriptInterface public String toString() { return "injectedObject"; } } webView.addJavascriptInterface(new JsObject(), "injectedObject"); webView.loadData("", "text/html", null); webView.loadUrl("javascript:alert(injectedObject.toString())");
IMPORTANT:
- This method can be used to allow JavaScript to control the host application. This is a powerful feature, but also presents a security risk for applications targeted to API level
JELLY_BEAN
or below, because JavaScript could use reflection to access an injected object's public fields. Use of this method in a WebView containing untrusted content could allow an attacker to manipulate the host application in unintended ways, executing Java code with the permissions of the host application. Use extreme care when using this method in a WebView which could contain untrusted content. - JavaScript interacts with Java object on a private, background thread of this WebView. Care is therefore required to maintain thread safety.
- The Java object's fields are not accessible.
Parameters
object | the Java object to inject into this WebView's JavaScript context. Null values are ignored. |
---|---|
name | the name used to expose the object in JavaScript |