Android与javaScript的交互

WebView与js的交互包含两方面,一是在html中通过js调用java代码;二是在安卓java代码中调用js。

一、html中通过js调用java代码

js中调用java代码其实就记住一点,WebView设置一个和js交互的接口(这里的接口是一般的意思,不是java中接口的含义),这个接口其实就是一个一般的类,同时为这个接口取一个别名。这个过程如下:

mWebView.addJavaScriptInterface(new DemoJavaScriptInterface(),"demo");

new DemoJavaScriptInterface()就是这个接口,demo就是这个接口的别名。

上面的代码执行后在html中js就能通过别名(这里是“demo”)来调用DemoJavaScriptInterface类中的任何方法了。

如果我们想让html中的一个button点击之后调用java中的函数可以这样:

<input type="button" value="click me" onclick="window.demo.clickOnAndroid()"/>

但是因为安全问题,在Android4.2中(如果应用的android:targetSdkVersion为17+)JS只能访问带有@javaScriptInterface注解的java函数,所以开发版本较高的时候,在需要被调用的函数前加上这个注解。4.2以下为了安全尽量不要调用addJavascriptInterface,需要另谋他法。

下面是google官方给的实例:

WebViewDemo.java

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

packagecom.google.android.webviewdemo;

importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.os.Handler;

importandroid.util.Log;

importandroid.webkit.JsResult;

importandroid.webkit.WebChromeClient;

importandroid.webkit.WebSettings;

importandroid.webkit.WebView;

/**

* Demonstrates how to embed a WebView in your activity. Also demonstrates how

* to have javascript in the WebView call into the activity, and how the activity

* can invoke javascript.

* <p>

* In this example, clicking on the android in the WebView will result in a call into

* the activities code in {@link DemoJavaScriptInterface#clickOnAndroid()}. This code

* will turn around and invoke javascript using the {@link WebView#loadUrl(String)}

* method.

* </p><p>

* Obviously all of this could have been accomplished without calling into the activity

* and then back into javascript, but this code is intended to show how to set up the

* code paths for this sort of communication.

*

*/

publicclassWebViewDemoextendsActivity {

privatestaticfinalString LOG_TAG ="WebViewDemo";

privateWebView mWebView;

privateHandler mHandler =newHandler();

@Override

publicvoidonCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

mWebView = (WebView) findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();

webSettings.setSavePassword(false);

webSettings.setSaveFormData(false);

webSettings.setJavaScriptEnabled(true);

webSettings.setSupportZoom(false);

mWebView.setWebChromeClient(newMyWebChromeClient());

mWebView.addJavascriptInterface(newDemoJavaScriptInterface(),"demo");

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

}

finalclassDemoJavaScriptInterface {

DemoJavaScriptInterface() {

}

/**

* This is not called on the UI thread. Post a runnable to invoke

* loadUrl on the UI thread.

*/

publicvoidclickOnAndroid() {

mHandler.post(newRunnable() {

publicvoidrun() {

mWebView.loadUrl("javascript:wave()");

}

});

}

}

/**

* Provides a hook for calling "alert" from javascript. Useful for

* debugging your javascript.

*/

finalclassMyWebChromeClientextendsWebChromeClient {

@Override

publicbooleanonJsAlert(WebView view, String url, String message, JsResult result) {

Log.d(LOG_TAG, message);

result.confirm();

returntrue;

}

}

}</p>

demo.html

[代码]xml代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

<html>

<scriptlanguage="javascript">

/* This function is invoked by the activity */

function wave() {

alert("1");

document.getElementById("droid").src="android_waving.png";

alert("2");

}

</script>

<body>

<!-- Calls into the javascript interface for the activity -->

<aonClick="window.demo.clickOnAndroid()">

<divstyle="width:80px;

margin:0px auto;

padding:10px;

text-align:center;

border:2px solid #202020;" >

<imgid="droid"src="android_normal.png"/><br>

Click me!

</div>

</a>

</body>

</html>

main.xml

[代码]xml代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<TextView

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/intro"

android:padding="4dip"

android:textSize="16sp"

/>

<WebView

android:id="@+id/webview"

android:layout_width="fill_parent"

android:layout_height="0dip"

android:layout_weight="1"

/>

</LinearLayout>

Android调用js

调用webview页面内的js方法,调用形式:

mWebView.loadUrl("javascript:wave()");

其中wave()是js中的一个方法,当然你可以把这个方法改成其他的方法,也就是android调用其他的方法。但java不能直接获取Js方法的返回结果。

小结

具体交互流程如下:

  • 点击图片,则在js端直接调用android上的方法clickOnAndroid();
  • clickOnAndroid()方法(利用线程)调用js的方法。
  • 被调用的js直接控制html。

利用webView的这种方式在有些时候UI布局就可以转成相应的html代码编写了,而html布局样式之类有DW这样强大的工具,而且网上很多源码,很多代码片。在UI和视觉效果上就会节省很多时间,重复发明轮子没有任何意义。

交互结果

Android Webview中Java调用Js方法很容易,loadUrl("javascript:isOk()")就可以调用isOk这个Js方法,但不能直接获取Js方法的返回结果。

1.传统的方法中,Js获取Java信息可以采用如下方式:

[代码]java代码:

?

1

2

3

4

5

6

7

classJsObject {

@JavascriptInterface

publicString toString() {return"injectedObject"; }

}

webView.addJavascriptInterface(newJsObject(),"injectedObject");

webView.loadData("","text/html",null);

webView.loadUrl("javascript:alert(injectedObject.toString())");

2.Java获取Js信息(如通过Js获取网页源代码)可以这样:

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

importandroid.app.Activity;

importandroid.graphics.Bitmap;

importandroid.os.Bundle;

importandroid.util.Log;

importandroid.webkit.WebView;

importandroid.webkit.WebViewClient;

publicclassHtmlSourceextendsActivity {

privateWebView webView;

@Override

publicvoidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

webView = (WebView)findViewById(R.id.webview);

webView.getSettings().setJavaScriptEnabled(true);

webView.addJavascriptInterface(newInJavaScriptLocalObj(),"local_obj");

webView.setWebViewClient(newMyWebViewClient());

webView.loadUrl("http://www.cnblogs.com/hibraincol/");

}

finalclassMyWebViewClientextendsWebViewClient{

publicbooleanshouldOverrideUrlLoading(WebView view, String url) {

view.loadUrl(url);

returntrue;

}

publicvoidonPageStarted(WebView view, String url, Bitmap favicon) {

Log.d("WebView","onPageStarted");

super.onPageStarted(view, url, favicon);

}

publicvoidonPageFinished(WebView view, String url) {

Log.d("WebView","onPageFinished ");

view.loadUrl("javascript:window.local_obj.showSource(''+"+

"document.getElementsByTagName('html')[0].innerHTML+'');");

super.onPageFinished(view, url);

}

}

finalclassInJavaScriptLocalObj {

publicvoidshowSource(String html) {

Log.d("HTML", html);

}

}

}

当网页中有超链接跳转时,将会调用WebClient的shouldOverrideUrlLoading方法,若设置 WebViewClient 且该方法返回 true,则说明由应用的代码处理该 url,WebView 不处理,就可以达到拦截跳转的效果。