android 与JS之间的交互

在页面布局很复杂并且是动态的时候,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错误。
   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错误。

 

设置webview对象显示的网页的函数为loadUrl();

  互联网页面直接用: 

myWebView.loadUrl(“http://www.google.com“);

  本地文件用(本地文件存放在:assets文件中):

myWebView.loadUrl(“file:///android_asset/XX.html“);  

  还可以直接载入html的字符串,如:

String htmlString = "

Title

This is HTML text
Formatted in italics
Anothor Line

"; // 载入这个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 Activitybutton>
<br />
<hr  color="#99FF00"/>
<button onClick="window.hello.showAndroid()">显示android内容button>
<br />
<textarea id= "shows"  cols="20" rows="10"> 暂无记录 textarea>
<br />

body>
html>
复制代码

代码实现效果图

 

android 与JS之间的交互_第1张图片

补充一下:如果在调用js中的方法时,需要访问值,只是采用 webView.loadUrl("javascript:show('"+info+"')");没法得到,可通过两种方式取得:

1) 在js中的show方法,继续调用android 原生方法将返回值通过参数的形式传过来

2)在API19后,android新增接口可直接得到返回值

 

复制代码
//第一个参数为js中的方法名,该段代码每执行一次则调用js方法一次
progressWebView.getWebview().evaluateJavascript("window.hasUserEditData()", new ValueCallback() {
                @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)

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())");

你可能感兴趣的:(android 与JS之间的交互)