在页面布局很复杂并且是动态的时候,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>
代码实现效果图
实例代码
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)
Added in API level 1
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 |