js调用java
mWebView.addJavascriptInterface(new DemoJavaScriptInterface(), "demo");
这样就把java对象DemoJavaScriptInterface生成了js的demo对象,直接window.demo调用
被js调用的java对象方法需手动加上@JavascriptInterface。
调用很快40-50ms,返回值尽量使基本类型,对象类型多了会出错。
给js给java传参或返回值是fianl的。返回值是字符串不能对它进行一些修改操作,比如想对它 substr ,取不到。怎么解决呢?转成 locale 的。使用 toLocaleString() 函数就可以了
java调用js
mWebView.loadUrl("javascript:ttt()"); //没有办法获得返回值,并且速度慢,100-200ms尽量不调用js
ttt是js的普通函数。
线程说明:
js调用java,java代码执行在名为javaBrige子线程中。
可用runOnUiThread()使java代码执行在主线程。
A. webview组件如何使用
1) 添加权限:AndroidManifest.xml中必须使用许可"android.permission.INTERNET",否则会出Web page not available错误。 2) 在要Activity中生成一个WebView组件:WebView webView = new WebView(this);或者可以在activity的layout文件里添加webview控件:
<WebView
android:id="@+id/wv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="@string/hello"
3) 设置WebView基本信息:
如果访问的页面中有Javascript,则webview必须设置支持Javascript。
webview.getSettings().setJavaScriptEnabled(true);
触摸焦点起作用
requestFocus();
取消滚动条
this.setScrollBarStyle(SCROLLBARS_OUTSIDE_OVERLAY);
4) 设置WevView要显示的网页:
互联网用:webView.loadUrl("http://www.google.com");
本地文件用:webView.loadUrl("file:///android_asset/XX.html"); 本地文件存放在:assets文件中5) 如果希望点击链接由自己处理,而不是新开Android的系统browser中响应该链接。给WebView添加一个事件监听对象(WebViewClient)并重写其中的一些方法:
shouldOverrideUrlLoading:对网页中超链接按钮的响应。当按下某个连接时WebViewClient会调用这个方法,并传递参数:按下的url。比如当webview内嵌网页的某个数字被点击时,它会自动认为这是一个电话请求,会传递url:tel:123,如果你不希望如此可通过重写shouldOverrideUrlLoading函数解决:
[java] view plaincopyprint?
- public boolean shouldOverrideUrlLoading(WebView view,String url){
- if(url.indexOf("tel:")<0){//页面上有数字会导致连接电话
- view.loadUrl(url);
- }
- return true;
- }
public boolean shouldOverrideUrlLoading(WebView view,String url){ if(url.indexOf("tel:")<0){//页面上有数字会导致连接电话 view.loadUrl(url); } return true; }
另外还有其他一些可重写的方法
1,接收到Http请求的事件
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)
public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; }
3,载入页面完成的事件
public void onPageFinished(WebView view, String url){ }
4,载入页面开始的事件
public void onPageStarted(WebView view, String url, Bitmap favicon) { }
通过这几个事件,我们可以很轻松的控制程序操作,一边用着浏览器显示内容,一边监控着用户操作实现我们需要的各种显示方式,同时可以防止用户产生误操作。
6) 如果用webview点链接看了很多页以后,如果不做任何处理,点击系统“Back”键,整个浏览器会调用finish()而结束自身,如果希望浏览的网页回退而不是退出浏览器,需要在当前Activity中处理并消费掉该Back事件。
覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法。 [java] view plaincopyprint?
- public boolean onKeyDown(int keyCoder,KeyEvent event){
- if(webView.canGoBack() && keyCoder == KeyEvent.KEYCODE_BACK){
- webview.goBack(); //goBack()表示返回webView的上一页面
- return true;
- }
- return false;
- }
public boolean onKeyDown(int keyCoder,KeyEvent event){ if(webView.canGoBack() && keyCoder == KeyEvent.KEYCODE_BACK){ webview.goBack(); //goBack()表示返回webView的上一页面 return true; } return false; }
其实webview加载资源的速度并不慢,但是如果资源多了,当然就很慢。图片、css 、js 、html这些资源每个大概需要10-200ms ,一般都是30ms就ok了。不过webview是必须等到全部资源都完成加载,才会进行渲染的,所以加载的速度很重要!从Google上我们了解到,webview加载页面的顺序是:先加载html,然后从里面解析出css、js文件和页面上的图片资源进行加载。如果webkit的缓存里面有,就不加载。加载完这些资源之后,就进行css的渲染和js的执行。Css的渲染一般不需要很长时间,几十毫秒就ok。关键是js的执行,如果用了jQuery,则执行起来需要5-6秒。而在这段时间,如果不在webview里设置背景,网页部分是白色的,很难看。这是一个很糟糕的用户体验。所以#欧#柏泰#克建议如果用网页布局程序,最好别用那些庞大的js框架。最好使用原生的js写业务脚本,以提升加载速度,改善用户体验。
在Android上怎样实现JAVA和JS交互呢?Android的webview是基于webkit内核的,webview中集成了js与java互调的接口函数,通过addJavas criptInterface方法,可以将Java的类注册进webkit,给网页上的js进行调用,而且还可以通过loadUrl方法是给webkit传递一个URL,供浏览器来进行解析,实现Java和js交互。
要想运行网页上的js脚本,webview必须设置支持Javas cript。
Java和js交互有以下一些特点:
1.Java 调用 js 里面的函数,速度并不令人满意,大概一次一两百毫秒吧,如果要做交互性很强的事情,这种速度会让人疯掉的。而反过来就不一样了, js 去调 java 的方法,速度很快,基本上 40-50 毫秒一次。所以尽量用 js 调用 java 方法,而不是 java 去调用 js 函数。
2.Java 调用 js 的函数,没有返回值,而 Js 调用 java 方法,可以有返回值。返回值可以是基本类型、字符串,也可以是对象。如果是字符串,有个很讨厌的问题,第 3 点我会讲的。如果是对象,这个对象会被转换为 js 的对象,直接可以访问里面的方法。但是我不推荐 java 返回给 js 的是对象,除非是必须。因为 js 收到 java 返回的对象,会产生一些交换对象,而如果这些对象的数量增加到了 500 或 600 以上,程序就会出问题。所以尽量返回基本数据类型或者字符串。
3.Js 调用 Java 的方法,返回值如果是字符串,你会发现这个字符串是 native 的,不能对它进行一些修改操作,比如想对它 substr ,取不到。怎么解决呢?转成 locale 的。使用 toLocaleString() 函数就可以了。不过这个函数的速度并不快,转化的字符串如果很多,将会很耗费时间。
背景:借助现有接口技术,js可以执行原生java代码中的方法,可以得到方法的返回值,可以让原生java代码在主线程中动态的操作UI;但是借助该接口,原生java代码,采用webview.loadUrl("javascript: JsFunctionName"),只能做到执行js中的方法,如果想获取js中定义的全局变量,或者获取某个js函数的返回值,这种方式无法做到,webview也没有提供别的函数来可供使用。
分析:为了实现该功能,我们分析application framework的源代码发现,从webview类loadurl()方法一路追踪,最终在WebViewCore.java中找到如下代码:
private native voidpassToJs(int frame, int node, int x, int y, int gen,
String currentText, int keyCode, intkeyValue, boolean down,
boolean cap, boolean fn, boolean sym);
在BrowserFrame中,追踪到:
private native voidnativeAddJavascriptInterface(int nativeFramePointer,
Object obj, String interfaceName);
至此我们知道android的webview实现,使用的是开源的webkit浏览器内核,该内核是用c语言(webcore)和c++语言(jscore)实现的,android的webview底层实现最终是调用的webkit内核代码,如果该内核提供了直接读取js全局变量或者函数返回值的方法,那么我们可以使用JNI(JavaNative Interface)的方式来读取出来。
方案:
(1)反射读取方式
在android.webkit包中有个BrowserFrame私有类,该类中有个Native方法:
public native StringstringByEvaluatingJavaScriptFromString(String script);
这个和苹果中的类似:
Public NSStringstringByEvaluatingJavaScriptFromString(NSString script);
虽然该类是私有的,但是我们可以利用反射技术来执行这个方法,从而取得js全局变量和函数返回值;
步骤:
1、扩展WebView,派生出MyWebView类,添加
public String stringByEvaluatingJavaScriptFromString(Stringscript)方法,该方法体中最终利用反射技术实现;
2、修改布局中的WebView为com.appeon.test.MyWebView类型;
3、 在页面load完成的情况下,编码取得JS变量或函数返回值;
除了采用反射方式能访问到私有类BrowserFrame中的stringByEvaluatingJavaScriptFromString方法之外,采用JNI技术,也能做到;下面我们采用JNI技术来实现20.4.1中的MyWebView类。
原理:java->C->java,具体到这里就是mywebview.java调用bridge.c,bridge.c再调用BrowserFrame.java
(3)扩展webkit方式
直接扩展WebCore,扩展JSBridge,实现JS的数据类型到JAVA数据类型的转换,确切的说是相互转换,这里面JAVA部分可以用反射机制来做到。
(4)Plug方式
采用插件的方式实现。
(5)使用android调用js后,通过js调用android本地方法,从而传入值的方式。
代码如下:
webView.loadUrl("javascript:androidGetInfo()");//android调用当前页面的androidGetInfo()方法。
页面的js:
<script>
var title = '${article.title}';
var articleId = '${article.id}';
var articleType = '${article.type}';
function androidGetInfo(){
window.tlsj.getInfo(title,articleType);//调用android 中的getInfo方法。
}
</script>
在android手机端代码如下:
webView.addJavascriptInterface(newObject() {
public void getInfo(String _title,String _articleType) {
title = _title;
articleType = _articleType;
Message msg = new Message();
handler.sendMessage(msg);
}
}, "tlsj");
由此即可将js中的全局变量或者函数返回值传入android手机端
分析:
反射读取方式存在一定的不稳定性,如当内部不开放函数或变量名发生变化时,反射就会出现问题。
JNI读取方式需要程序员对c++有一定了解。
使用android调用js后,通过js调用android本地方法不够灵活。
Android 4.4之后使用evaluateJavascript即可。这里展示一个简单的交互示例 具有返回值的js方法
function getGreetings() {
return 1;
}
java代码时用evaluateJavascript方法调用
private void testEvaluateJavascript(WebView webView) {
webView.evaluateJavascript("getGreetings()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Log.i(LOGTAG, "onReceiveValue value=" + value);
}});
}
输出结果
I/MainActivity( 1432): onReceiveValue value=1
注意
上面限定了结果返回结果为String,对于简单的类型会尝试转换成字符串返回,对于复杂的数据类型,建议以字符串形式的json返回。
evaluateJavascript方法必须在UI线程(主线程)调用,因此onReceiveValue也执行在主线程。
疑问解答
Alert无法弹出
你应该是没有设置WebChromeClient,按照以下代码设置
1
myWebView.setWebChromeClient(new WebChromeClient() {});
Uncaught ReferenceError: functionName is not defined
问题出现原因,网页的js代码没有加载完成,就调用了js方法。解决方法是在网页加载完成之后调用js方法
myWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//在这里执行你想调用的js函数
}
});
Uncaught TypeError: Object [object Object] has no method
安全限制问题
如果只在4.2版本以上的机器出问题,那么就是系统处于安全限制的问题了。Android文档这样说的
Caution: If you’ve set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available your web page code (the method must also be public). If you do not provide the annotation, then the method will not accessible by your web page when running on Android 4.2 or higher.
中文大意为
警告:如果你的程序目标平台是17或者是更高,你必须要在暴露给网页可调用的方法(这个方法必须是公开的)加上@JavascriptInterface注释。如果你不这样做的话,在4.2以以后的平台上,网页无法访问到你的方法。
两种解决方法
将targetSdkVersion设置成17或更高,引入@JavascriptInterface注释
自己创建一个注释接口名字为@JavascriptInterface,然后将其引入。注意这个接口不能混淆。
注,创建@JavascriptInterface代码
public @interface JavascriptInterface {
}
代码混淆问题
如果在没有混淆的版本运行正常,在混淆后的版本的代码运行错误,并提示Uncaught TypeError: Object [object Object] has no method,那就是你没有做混淆例外处理。 在混淆文件加入类似这样的代码
-keep class com.example.javajsinteractiondemo$JsInteration {
*;
}
All WebView methods must be called on the same thread
过滤日志曾发现过这个问题。
E/StrictMode( 1546): java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 1) {528712d4} called on Looper (JavaBridge, tid 121) {52b6678c}, FYI main Looper is Looper (main, tid 1) {528712d4})
E/StrictMode( 1546): at android.webkit.WebView.checkThread(WebView.java:2063)
E/StrictMode( 1546): at android.webkit.WebView.loadUrl(WebView.java:794)
E/StrictMode( 1546): at com.xxx.xxxx.xxxx.xxxx.xxxxxxx$JavaScriptInterface.onCanGoBackResult(xxxx.java:96)
E/StrictMode( 1546): at com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)
E/StrictMode( 1546): at com.android.org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:27)
E/StrictMode( 1546): at android.os.Handler.dispatchMessage(Handler.java:102)
E/StrictMode( 1546): at android.os.Looper.loop(Looper.java:136)
E/StrictMode( 1546): at android.os.HandlerThread.run(HandlerThread.java:61)
在js调用后的Java回调线程并不是主线程。如打印日志可验证
lineos:false
1
ThreadInfo=Thread[WebViewCoreThread,5,main]
解决上述的异常,将webview操作放在主线程中即可。
webView.post(new Runnable() {
@Override
public void run() {
webView.loadUrl(YOUR_URL).
}
});
相关推荐
通过以上讲解,你应该对`webviewjs与java互调`有了全面的理解,包括基本用法、JavaScript调用Java、Java调用JavaScript以及解决常见问题。希望这个`webviewDemo自己写的`能帮助你找到更多具体实践中的解决方案。在...
这个话题我们将深入探讨WebView与JavaScript的互调机制。 一、WebView简介 WebView是Android和iOS平台上的一个组件,它允许应用加载并显示网页内容。在Android中,WebView是`android.webkit.WebView`类,而在iOS中...
在`webviewDemo`这个项目中,很可能是包含了一个示例,演示了如何在Android应用中使用WebView与JavaScript进行交互。通常,这个项目会有一个Android工程,其中包含一个Activity,该Activity使用WebView加载HTML内容...
Android(Java)与JavaScript(HTML)交互有四种情况: 1) Android(Java)调用HTML中js代码 2) Android(Java)调用HTML中js代码(带参数) 3) HTML中js调用Android(Java)代码 4) HTML中js调用Android(Java...
而JavaScript与Java的交互是WebView功能的一个强大扩展,使得我们可以利用Web技术与原生Android应用进行深度集成。以下是对这个主题的详细解释: 一、WebView的基本使用 1. 初始化:在布局XML文件中添加WebView控件...
- **避免XSS攻击:** 当允许JavaScript与Java互调时,必须注意防止跨站脚本(XSS)攻击。确保不信任的JavaScript代码不能通过`addJavascriptInterface()`访问敏感的Android API。 - **使用@JavascriptInterface:*...
通过这个例子,你已经学会了如何在Android的WebView中实现JavaScript与Java的互调。这在开发混合应用或者增强WebView功能时非常有用,例如实现登录验证、数据交换等功能。注意,出于安全考虑,使用`...
总结来说,Android与JS互调是通过WebView组件实现的,通过设置JavaScript的启用状态,我们可以方便地在两者之间传递数据和调用方法。这种交互方式为开发者提供了更大的灵活性,可以结合Android的强大力量和...
JavaScript与Java互调的核心在于`WebView`的两个方法:`addJavascriptInterface()`和`evaluateJavascript()`。 1. `addJavascriptInterface()`: 这个方法用于在`WebView`中暴露Java对象给JavaScript,使得...
`WebView`是Java与JavaScript交互的基础。 ### 2. JavaScriptInterface 要实现Java代码调用JavaScript,可以创建一个`@JavascriptInterface`注解标记的接口。这个接口的方法可以在JavaScript中被调用。例如: ```...
总结起来,Android与JavaScript的互调主要依赖于`WebView`组件,通过`loadUrl()`执行JavaScript代码,`addJavascriptInterface()`暴露Java方法给JavaScript,以及`WebChromeClient`和`WebViewClient`的相关回调来...
要实现Webview与JavaScript的交互,鸿蒙系统提供了`addJavascriptInterface`方法,允许将Java对象暴露给JavaScript。例如,我们创建一个Java对象并添加到Webview: ```java MyJavaScriptInterface jsInterface = ...
实现Java代码与JavaScript的互调: 1. Java调用JavaScript: 使用`evaluateJavascript()`方法可以在当前页面执行JavaScript代码,并可以传递一个Callback来获取JavaScript的返回值: ```java webView....
JavaScript(JS)与Android之间的互调是移动应用开发中的一个重要技术,它允许Web应用与原生Android应用进行深度集成,实现功能交互。本Demo旨在演示如何实现这一互调过程,以便开发者可以更好地理解和运用到实际...
Android中webview与JS交互、互调方法实例详解 Android中webview与JS交互、互调方法实例详解主要介绍了Android中webview与JS交互、互调方法实例详解的相关资料,需要的朋友可以参考下。 一、前言 在Android开发中...
本篇将详细讲解Android与JavaScript互调的原理、方法及应用示例。 首先,Android与JavaScript交互的核心是WebView组件,它是一个内置的浏览器引擎,可以加载并显示HTML页面。通过WebView,我们可以将JavaScript代码...
而JavaScript与Android Java代码的交互是WebView的一个强大功能,能够实现更丰富的用户界面和交互体验。本文将详细介绍如何在WebView中实现JavaScript与Android Java代码的相互调用。 一、JavaScript调用Android ...
Android代码调用js不需要再依赖webview,直接引入此jar包即可,用java标准的js调用。
总结,Android原生与JS互调是混合开发中的关键技术,通过Webview组件,我们可以充分利用两者的优势,实现更丰富的功能。了解并熟练掌握这一交互机制,对提升应用的用户体验和开发效率至关重要。