WebView 和JS交互 addJavascriptInterface evaluateJavascript
发布日期:2021-09-11 05:52:32 浏览次数:24 分类:技术文章

本文共 8657 字,大约阅读时间需要 28 分钟。

注意,如果在 java 与 Javascript 交互的时候出现如下错误:
Uncaught ReferenceError: 
getDeviceID
1
1
 
1
Uncaught ReferenceError: 
getDeviceID
很可能是因为在 html 页面还没有加载完,就加载里面的 JS 方法,这样是找不到这个方法的。
解决方法为:把调用放到 onPageFinished() 里面。

addJavascriptInterface

void addJavascriptInterface(Object object, String name)
1
1
 
1
void addJavascriptInterface(Object object, String name)
参数
  • Object object : the Java object to inject注入 into this WebView's JavaScript context. Null values are ignored.
  • String name : the name used to expose暴露 the object in JavaScript
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. JavaScript should be enabled before injecting the object. For example:
class JsObject {    @JavascriptInterface    public String toString() { return "injectedObject"; }}webview.getSettings().setJavaScriptEnabled(true);webView.addJavascriptInterface(new JsObject(), "injectedObject");webView.loadData("", "text/html", null);webView.loadUrl("javascript:alert(injectedObject.toString())");
x
 
1
class JsObject {
2
   @JavascriptInterface
3
   public String toString() { return "injectedObject"; }
4
}
5
webview.getSettings().setJavaScriptEnabled(true);
6
webView.addJavascriptInterface(new JsObject(), "injectedObject");
7
webView.loadData("", "text/html", null);
8
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 apps targeting目标版本为 
JELLY_BEAN
or earlier. 
Apps that target a version later than
JELLY_BEAN
are still vulnerable
很容易受到攻击
if the app runs on a device running Android earlier than
4.2
The most secure way to use this method is to target JELLY_BEAN_MR1 and to ensure the method is called only when running on Android 4.2 or later. 
With these older versions, 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.
For applications targeted to API level
LOLLIPOP
and above, methods of injected Java objects are enumerable
枚举
from JavaScript.

evaluateJavascript

void evaluateJavascript (String script, ValueCallback
resultCallback)
1
1
 
1
void evaluateJavascript (String script, ValueCallback
resultCallback)
参数:
  • String script : the JavaScript to execute.要执行的JavaScript。
  • ValueCallback resultCallback : A callback to be invoked when the script execution completes with the result of the execution (if any). May be null if no notification of the result is required.
    当脚本执行完成时的回调,如果有执行结果的话会携带执行结果。如果不需要结果通知,可以为null。
Asynchronously evaluates JavaScript in the context of the currently displayed page. 
在当前显示页面的上下文中
异步执行JavaScript。
If non-null, resultCallback will be invoked with any result returned from that execution.
如果非空,resultCallback会被回调并携带调用后返回的
结果。 
This method must be called on the UI thread and the callback will be made on the UI thread.
此方法必须在UI线程上调用,并且
回调也是运行在UI线程上的。
Compatibility note. 
兼容性说明
Applications targeting N or later, JavaScript state from an empty WebView is no longer persisted across navigations like loadUrl(String).
目标版本为N或更高的应用程序,空的WebView中的JavaScript状态不再继续像loadUrl那样在navigations中保留。
For example, global variables and functions defined before calling loadUrl(String) will not exist in the loaded page. 
例如,在加载后的页面中将不会存在调用loadUrl之前定义的全局变量和函数。 
Applications should use addJavascriptInterface(Object, String) instead to persist JavaScript objects across navigations.
应用程序应该使用 addJavascriptInterface 来跨navigations维护JavaScript对象。

原生和js交互案例

1、注册
webview.addJavascriptInterface(new JSInterface(this, webview), JSInterface.JS_INTERFACE_NAME);
x
 
1
webview.addJavascriptInterface(new JSInterface(this, webview), JSInterface.JS_INTERFACE_NAME);
2、JS和HTML代码
    
Title
36
 
1
 
2
 
3
 
4
   
5
   Title
6
 
7
 
8
 
9
10
11
 
12
 
13
 
14
15
function jscalljava(content){
16
   console.log("【jscalljava】");
17
   JSInterface.hello(content);
18
}
19
 
20
function jscalljava2(){
21
   console.log("【jscalljava2】");
22
   var content="[\"包青天\",\"白乾涛\",\"bqt\"]";
23
   JSInterface.hello2(content);
24
}
25
 
26
function javacalljs(content){
27
   console.log("【js中的javacalljs方法被调用了】content="+content);
28
}
29
 
30
function javacalljs2(content){
31
   console.log("【js中的javacalljs2方法被调用了】content="+content);
32
   return 20094;
33
}
34
 
35
 
36
 
3、原生代码
public class JSInterface {	public static final String JS_INTERFACE_NAME = "JSInterface";//JS调用类名	private Context mContext;	private WebView webView;		public JSInterface(Context context, WebView webView) {		this.mContext = context;		this.webView = webView;	}		@JavascriptInterface	public void hello(String content) {		Log.i("bqt", "JS 调用原生时是否发生在主线程:" + (Looper.myLooper() == Looper.getMainLooper()));//false		new Handler(Looper.getMainLooper()).post(() -> //WebView等UI操作必须在主线程中进行				Toast.makeText(mContext, "原生的hello方法被调用了:" + content, Toast.LENGTH_SHORT).show());				SystemClock.sleep(3000);//模拟耗时操作				String call = "javascript:javacalljs(" + System.currentTimeMillis() + ")";//格式很重要,大部分错误都是由于格式问题导致的		new Handler(Looper.getMainLooper()).post(() -> webView.loadUrl(call));//WebView等UI操作必须在主线程中进行	}		@JavascriptInterface	public void hello2(String content) {		new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(mContext, content, Toast.LENGTH_SHORT).show());				SystemClock.sleep(3000);//模拟耗时操作				String call = "javascript:javacalljs2(" + System.currentTimeMillis() + ")";//JS此方法的返回值会通过onReceiveValue回调到原生		new Handler(Looper.getMainLooper()).post(() -> webView.evaluateJavascript(call, value -> {			Log.i("bqt", "ValueCallback 是否发生在主线程:" + (Looper.myLooper() == Looper.getMainLooper()));//true			Toast.makeText(mContext, "【onReceiveValue】" + value, Toast.LENGTH_SHORT).show();		}));	}}
35
 
1
public class JSInterface {
2
public static final String JS_INTERFACE_NAME = "JSInterface";//JS调用类名
3
private Context mContext;
4
private WebView webView;
5
 
6
public JSInterface(Context context, WebView webView) {
7
this.mContext = context;
8
this.webView = webView;
9
}
10
 
11
@JavascriptInterface
12
public void hello(String content) {
13
Log.i("bqt", "JS 调用原生时是否发生在主线程:" + (Looper.myLooper() == Looper.getMainLooper()));//false
14
new Handler(Looper.getMainLooper()).post(() -> //WebView等UI操作必须在主线程中进行
15
Toast.makeText(mContext, "原生的hello方法被调用了:" + content, Toast.LENGTH_SHORT).show());
16
 
17
SystemClock.sleep(3000);//模拟耗时操作
18
 
19
String call = "javascript:javacalljs(" + System.currentTimeMillis() + ")";//格式很重要,大部分错误都是由于格式问题导致的
20
new Handler(Looper.getMainLooper()).post(() -> webView.loadUrl(call));//WebView等UI操作必须在主线程中进行
21
}
22
 
23
@JavascriptInterface
24
public void hello2(String content) {
25
new Handler(Looper.getMainLooper()).post(() -> Toast.makeText(mContext, content, Toast.LENGTH_SHORT).show());
26
 
27
SystemClock.sleep(3000);//模拟耗时操作
28
 
29
String call = "javascript:javacalljs2(" + System.currentTimeMillis() + ")";//JS此方法的返回值会通过onReceiveValue回调到原生
30
new Handler(Looper.getMainLooper()).post(() -> webView.evaluateJavascript(call, value -> {
31
Log.i("bqt", "ValueCallback 是否发生在主线程:" + (Looper.myLooper() == Looper.getMainLooper()));//true
32
Toast.makeText(mContext, "【onReceiveValue】" + value, Toast.LENGTH_SHORT).show();
33
}));
34
}
35
}
2017-8-25

转载地址:https://blog.csdn.net/weixin_34406061/article/details/85982950 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:大脑不清醒什么原因?
下一篇:WPF richTextBox 滚动到某项

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月04日 09时50分31秒