说说webView与JS的交互方式
2018-01-28 18:49
281 查看
大家对于Hybrid App应该都不会很陌生,它主要就是指native和HTML5混合开发。Hybrid App能让前端,Android和iOS都同用一套界面和逻辑,大大降低了开发和维护的成本,因此Hybrid App在移动应用开发领域占有了一席之地。
而在Android端里面,开发Hybrid App主要是使用webView控件,webView加载的HTML5网页里面有很多逻辑都是放在JS里面执行了,因此要开发一个Hybrid App,就必须知道WebView怎么和JS进行交互。
1.使用
2.使用
这两个方法在使用方式上大致相同,但是第二个方法只能在Android 4.4 后才可使用,是专门用于异步调用JavaScript方法并且能够得到一个回调结果,而且效率要比第一个方法高。因此日常开发中建议是混合使用,怎么个混合使用呢?先看一段HTML代码吧:
上面这段代码很简单,没前端基础看那几个function的方法名字应该也看明白了。接着在Android端里通过
这时就可以看到下面的运行结果了:
简单的JavaScriptInterface
这是最普遍的webView和JS的交互方式,就是使用Android的
先创建进行交互的HTML5文件:
上面代码很简单,一个button,点击就执行JavaScrip脚本中的
这样子运行就可以看下面的效果了:
不过方法虽然简单,但实际上这个方法是存在一定的风险的,如果你使用的是AndroidStudio,在你的
这个提示的意思呢,就是如果你使用了这种方式去开启JavaScript通道,你就要小心XSS攻击了。具体可以到提示里面这个网站去查看,需要合理翻墙的。
不过这个漏洞已经在Android 4.2上面修复了,如果你不用兼容到这个以下的版本,就可以不用管了。如果需要兼容,那么为了确保安全,可以用下面这个有点复杂的方法。
有点复杂的JavaScriptBridge
比如我们可以在JavaScript脚本中调用alert方法,这样对应的就会走到
不过这并不意味着我们可以任意用一个方法来用。因为在JavaScript中,
不过还有一个细节需要处理,那就是怎么样才能让Java层知道JavaScript脚本需要调用的哪一个方法呢?怎么把JavaScript脚本的参数传递进来呢?这时候就需要自定义协议了。这里我们来自定义一个协议如下:
然后本地的HTML5文件使用它:
在Android通过
这时只要给
很好用的拦截Url
通过
而且只有重写
我们还是先来一个HTML5代码:
这里多说一句,这里是练习,所以可以随便定,但是实际开发中最好和前端与iOS端的同学协商好,保证前端逻辑的清晰。
下面来看看WebViewClient类:
然后我们去gradle里面写一下配置,这样子方便以后的维护和修改:
最后就是到清单文件去配置一下需要启动的Activity了:
ok,这样子我们的拦截Url唤醒就完成了,我们运行一下看下效果:
是的,大体的原理就这么简单,但是如果你想真正的用好它来进行开发,还需要做很多工作。
与君共勉。
而在Android端里面,开发Hybrid App主要是使用webView控件,webView加载的HTML5网页里面有很多逻辑都是放在JS里面执行了,因此要开发一个Hybrid App,就必须知道WebView怎么和JS进行交互。
Android端通过WebView调用JavaScript代码
在Android端里面,WebView调用JavaScript代码的方法有2种方法:
1.使用
WebView.loadUrl(String url)
2.使用
WebView.evaluateJavascript(String script, ValueCallback<String> resultCallback)
这两个方法在使用方式上大致相同,但是第二个方法只能在Android 4.4 后才可使用,是专门用于异步调用JavaScript方法并且能够得到一个回调结果,而且效率要比第一个方法高。因此日常开发中建议是混合使用,怎么个混合使用呢?先看一段HTML代码吧:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="user-scalable=no"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <div id="input" contenteditable="true">我是测试文本</div> <script> var re = document.getElementById("input"); function setTextColor(color){ re.style.color=color; } function setBackgroundColor(){ re.style.backgroundColor="#CCC"; } function setUnderline(){ re.style.textDecoration = "underline"; } </script> </body> </html>
上面这段代码很简单,没前端基础看那几个function的方法名字应该也看明白了。接着在Android端里通过
WebView设置调用JS代码
private WebView mWebView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWebView = (WebView) findViewById(R.id.webView); mWebView.setVerticalScrollBarEnabled(false); mWebView.setHorizontalScrollBarEnabled(false); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.loadUrl("file:///android_asset/input.html"); } public void red(View view) { String red = "#F00"; execute("setTextColor('" + red + "');"); } public void black(View view) { String black = "#000"; execute("setTextColor('" + black + "');"); } public void bold(View view) { execute("setBackgroundColor();"); } public void underline(View view) { execute("setUnderline();"); } private void execute(String url) { //调用js的方法需要一个javascript:的前缀 String trigger = "javascript:" + url; // 因为evaluateJavascript()该方法在 Android 4.4 版本才可使用 // 所以使用时需进行版本判断 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //如果不需要获取返回结果可以使用下面这个 //mWebView.evaluateJavascript(trigger, null); mWebView.evaluateJavascript(trigger, new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //此处为 JS返回的结果 } }); } else { mWebView.loadUrl(trigger); } }
这时就可以看到下面的运行结果了:
JS通过WebView调用Android端的代码
搞明白了怎么通过WebView调用JS代码后,就来看下JS是怎么通过WebView来调用Android端的代码吧。我们先从简单的方法开始吧简单的JavaScriptInterface
这是最普遍的webView和JS的交互方式,就是使用Android的
@JavascriptInterface注解来实现JS和WebView的交互。
先创建进行交互的HTML5文件:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <script type="text/javascript"> function sayHello(world) { //这里让html5调用Android的代码,要与代码设置的名称一致 //也就是说Android代码需要设置WebView这个名字 webView.sayHello(world); } </script> </head> <body> <input type="button" value="Js调用Android代码" style="height: 30px;font-size:20px;" onClick="sayHello('Js调用Android代码')" /> </body> </html>
上面代码很简单,一个button,点击就执行JavaScrip脚本中的
sayHello方法。接着就是通过
WebView的
addJavascriptInterface方法去注入一个我们自己写的JavaScriptInterface:
public class JsInterfaceActivity extends AppCompatActivity { private WebView mWebView; @SuppressLint("SetJavaScriptEnabled") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //布局很简单,就一个webView setContentView(R.layout.activity_js_interface); mWebView = (WebView) findViewById(R.id.js_webView); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.loadUrl("file:///android_asset/JsInterface.html"); //注入JsInterface,这里注意映射的名字需要一致 mWebView.addJavascriptInterface(new JsInterface(), "webView"); } public class JsInterface { @JavascriptInterface public void sayHello(String word) { AlertDialog.Builder builder = new AlertDialog.Builder(JsInterfaceActivity.this); builder.setMessage(word); builder.create().show(); } } }
这样子运行就可以看下面的效果了:
不过方法虽然简单,但实际上这个方法是存在一定的风险的,如果你使用的是AndroidStudio,在你的
setJavaScriptEnabled(true);这句方法中,AndroidStudio会给你一个提示:
这个提示的意思呢,就是如果你使用了这种方式去开启JavaScript通道,你就要小心XSS攻击了。具体可以到提示里面这个网站去查看,需要合理翻墙的。
不过这个漏洞已经在Android 4.2上面修复了,如果你不用兼容到这个以下的版本,就可以不用管了。如果需要兼容,那么为了确保安全,可以用下面这个有点复杂的方法。
有点复杂的JavaScriptBridge
JavaScriptBridge顾名思义就是WebView和JavaScript沟通的通道,原理是利用WebView中的WebChromeClient类的onJsAlert()、onJsConfirm()、onJsPrompt()这3个方法回调拦截JS对话框alert()、confirm()、prompt() 消息。
比如我们可以在JavaScript脚本中调用alert方法,这样对应的就会走到
WebChromeClient类的
onJsAlert()方法中,我们就可以拿到其中的信息去解析,并且做Java层的事情。
不过这并不意味着我们可以任意用一个方法来用。因为在JavaScript中,
alert()和
confirm()的使用概率还是很高的,所以剩下一个选项了。
不过还有一个细节需要处理,那就是怎么样才能让Java层知道JavaScript脚本需要调用的哪一个方法呢?怎么把JavaScript脚本的参数传递进来呢?这时候就需要自定义协议了。这里我们来自定义一个协议如下:
hybrid://JSBridge/method?arg1=我是prompt消息&arg2=Toast
然后本地的HTML5文件使用它:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <script type="text/javascript"> function clickPrompt(){ // 调用prompt() var result=prompt("hybrid://JSBridge/method?arg1=我是prompt消息&arg2=Toast"); } </script> </head> <body> <input type="button" value="Prompt调用Android代码" style="height: 30px;font-size:20px;" onClick="clickPrompt()"/> </body> </html>
在Android通过
WebChromeClient复写
onJsPrompt(),拿到传递的数据:
public class MyWebChromeClient extends WebChromeClient { @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数) //假定传入进来的 url = "hybrid://JSBridge/method?arg1=我是prompt消息&arg2=Toast" //(同时也是约定好的需要拦截的) Uri uri = Uri.parse(message); // 如果url的协议 = 预先约定的 js 协议, 就解析往下解析参数 if ( uri.getScheme().equals("hybrid")) { // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议 // 所以拦截url,下面JS开始调用Android需要的方法 if (uri.getAuthority().equals("JSBridge")) { // 可以在协议上带有参数并传递到Android上 String query = uri.getQuery().replace("arg1=","") .replace("&arg2=",","); // 吐司一下好了,实际开发应该是依据参数执行不同的方法 Toast.makeText(view.getContext(),query,Toast.LENGTH_SHORT).show(); //参数result:代表消息框的返回值(输入值) result.confirm("js成功调用了Android的方法了"); } return true; } return super.onJsPrompt(view, url, message, defaultValue, result); } }
这时只要给
WebView设置设置上面的
WebChromeClient就好了,现在看下运行效果:
很好用的拦截Url
通过
WebViewClient复写
shouldOverrideUrlLoading ()的方法,拦截前端同学写的url,可以让前端唤起Android的native页面。这个方法用好了,可以很方便地让前端和移动端有个统一的调度。
而且只有重写
WebViewClient的
shouldOverrideUrlLoading方法,才不会跳转到系统浏览器
我们还是先来一个HTML5代码:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <script type="text/javascript"> function callLogin(){ //约定一个协议,启动一个页面 document.location = "http://login.test.gradle.com/"; } </script> </head> <body> <input type="button" value="login" style="height: 30px;font-size:20px;" onClick="callLogin()"/> </body> </html>
这里多说一句,这里是练习,所以可以随便定,但是实际开发中最好和前端与iOS端的同学协商好,保证前端逻辑的清晰。
下面来看看WebViewClient类:
public class MyWebClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url == null) { return false; } if (url.startsWith("http") || url.startsWith("https")) { view.loadUrl(url); return false; } else { Intent intent = new Intent(Intent.ACTION_VIEW); Uri parse = Uri.parse(url); //设置intent的Data intent.setData(parse); try { //设置包名 intent.setPackage(view.getContext().getPackageName()); PackageManager pm = view.getContext().getPackageManager(); ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); if (info == null) { throw new ActivityNotFoundException("No Activity found : " + intent); } else { intent.setClassName(info.activityInfo.packageName, info.activityInfo.name); } view.getContext().startActivity(intent); return true; } catch (ActivityNotFoundException e) { return false; } }
然后我们去gradle里面写一下配置,这样子方便以后的维护和修改:
defaultConfig { applicationId "test.gradle.com" minSdkVersion 16 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" manifestPlaceholders = ["URL_SCHEMA": "http", "URL_HOST": "login.test.gradle.com", "URL_CATEGORY": "gradle.com"] }
最后就是到清单文件去配置一下需要启动的Activity了:
<activity android:name=".LoginActivity"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> <category android:name="${URL_CATEGORY}"/> <data android:scheme="${URL_SCHEMA}"/> <data android:host="${URL_HOST}"/> </intent-filter> </activity>
ok,这样子我们的拦截Url唤醒就完成了,我们运行一下看下效果:
总结
Android中的WebView和JavaScript的交互方式到此就说完了,看到这儿可能大家肯定会觉得这么简单啊?是的,大体的原理就这么简单,但是如果你想真正的用好它来进行开发,还需要做很多工作。
与君共勉。
相关文章推荐
- Android中WebView与JS交互方式详解
- OC原生代码/webview与js/网页交互的最好方式
- Android:你要的WebView与 JS 交互方式 都在这里了
- WebView与 JS 交互方式
- Android:你要的WebView与 JS 交互方式 都在这里了
- Android:WebView与 JS 交互方式,前后端互相调用
- iOS WKWebView和JS交互的两种方式
- Android - webview原生和JavaScript(js)交互传值的几种方式
- Android:你要的WebView与 JS 交互方式 都在这里了
- Android:你要的WebView与 JS 交互方式 都在这里了
- Android:你要的WebView与 JS 交互方式 都在这里了
- Android:你要的WebView与 JS 交互方式 都在这里了
- WKWebView、WebView和JS的交互方式详解
- Android:你要的WebView与 JS 交互方式 都在这里了
- Android:WebView与 JS 的三种交互方式详解与对比
- Android:你要的WebView与 JS 交互方式 都在这里了
- Android:你要的WebView与 JS 交互方式 都在这里了
- Android WebView与 JS 的交互方式
- 最全面总结 Android WebView与 JS 的交互方式
- Android WebView与 JS 交互方式