MainActivity.java
package com.fedming.webtonativedemo;
import android.app.Activity;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import java.util.HashMap;
/**
* <pre>
* author : fdm
* time : 2018/03/08
* desc : WebView与本地方法交互的三种方法Demo
* version: 1.0
* </pre>
*/
public class MainActivity extends Activity {
private WebView webView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = (WebView) findViewById(R.id.webView);
WebSettings webSettings = webView.getSettings();
webSettings.setAllowFileAccess(false);
webSettings.setSupportZoom(false);
webSettings.setUseWideViewPort(true);
webSettings.setJavaScriptEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setLoadsImagesAutomatically(true);
webSettings.setDefaultTextEncodingName("UTF-8");
webView.setWebChromeClient(new WebChromeClient());
/**
* 第一种
* 原理:直接构造本地化对象,映射到js页面中访问,底层原理借助了V8引擎(Android4.2 以下系统有WebView漏洞)
*/
webView.addJavascriptInterface(new JSInterface(), "MyObj");
/**
* 第二种
* 回调方法中(shouldOverrideUrlLoading)拦截请求url,分析url格式以及自定义协议、参数名称可得到具体参数
* tips:需要再次调用页面js方法获取返回值
*/
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("http:") || url.startsWith("https:")) {
return false;
}
//协议url:"js://demo?arg=111"
try {
String protocol = Utils.getUrlScheme(url);
if ("js".equals(protocol)) {
HashMap<String, String> map = Utils.getUrlParams(url);
String arg = map.get("arg");
String res = getLocalString(arg);
//再次调用web中js方法,将参数传回web去
webView.loadUrl("javascript:click_result(" + res + ")");
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
});
/**
* 第三种
* 借助WebChromeClient的回调方法(共三个),拦截JS中的三个方法:alert,confirm,prompt,解析参数,得到指定格式数据
* tips:需要页面和本地解析格式做一个约束
*/
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
@Override
public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
return super.onJsConfirm(view, url, message, result);
}
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
if (url.startsWith("http:") || url.startsWith("https:")) {
return false;
}
//协议url:"js://demo?arg=111"
try {
String protocol = Utils.getUrlScheme(message);
if ("js".equals(protocol)) {
HashMap<String, String> map = Utils.getUrlParams(message);
String arg = map.get("arg");
String res = getLocalString(arg);
result.confirm(res);
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
});
//加载asset中的网页
webView.loadUrl("file:///android_asset/js_demo.html");
}
/**
* 本地化JS对象,供web调用
* sdk17版本以上需要加上注解
*/
class JSInterface {
@JavascriptInterface
public String getPwd(String pwd) {
//执行本地方法,返回结果到web
return getLocalString(pwd);
}
}
/**
* 本地方法
*
* @param txt txt
* @return txt
*/
public String getLocalString(String txt) {
return txt;
}
}
Utils.java
package com.fedming.webtonativedemo;
import java.util.HashMap;
/**
* <pre>
* author : fdm
* time : 2018/03/08
* desc : Utils
* version: 1.0
* </pre>
*/
public class Utils {
public Utils() {
}
/**
* 获取url中的协议
*
* @param url url
* @return protocol
*/
public static String getUrlScheme(String url) {
int index = url.indexOf(":");
return url.substring(0, index);
}
/**
* 获取url中的参数
*
* @param url url
* @return args
*/
public static HashMap<String, String> getUrlParams(String url) {
int index = url.indexOf("?");
String argStr = url.substring(index + 1);
String[] argAry = argStr.split("&");
HashMap<String, String> argMap = new HashMap<String, String>(argAry.length);
for (String arg : argAry) {
System.out.println("arg:" + arg);
String[] argAryT = arg.split("=");
argMap.put(argAryT[0], argAryT[1]);
}
return argMap;
}
}
main
文件夹下 assets
文件夹
js_demo.html
<!DOCTYPE html>
<html>
<head>
<title>WebToNativeDemo</title>
<script>
function click_one(){
var result = window.MyObj.getPwd("111");
alert("第一个按钮结果:"+result);
}
function click_two(){
document.location = "js://demo?arg=222";
}
function click_result(result){
alert("第二个按钮结果:"+result);
}
function click_three(){
var result=prompt("js://demo?arg=333","");
alert("第三个按钮结果:"+result);
}
</script>
<style type="text/css">
input{
width: 800px;
height: 180px;
margin: 50px auto;
text-align:center;
font-size:50px;
}
</style>
</head>
<body>
<p style=" margin:0 auto; text-align:center;"><input id="one" class="submit" name="submit" type="submit" onclick="click_one()"/></p>
<p style=" margin:0 auto; text-align:center;"><input id="two" class="submit" name="submit" type="submit" onclick="click_two()"/></p>
<p style=" margin:0 auto; text-align:center;"><input id="three" class="submit" name="submit" type="submit" onclick="click_three()"/></p>
</body>
</html>
layout文件夹
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="54dp"
android:background="@color/colorPrimary"
android:gravity="center"
android:text="WebToNative"
android:textColor="@android:color/white"
android:textSize="18sp" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/linear_layout" />
</RelativeLayout>
app文件夹下build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '27.0.3'
defaultConfig {
applicationId "com.fedming.webtonativedemo"
minSdkVersion 19
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.1'
testCompile 'junit:junit:4.12'
}
项目根目录下build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
gradle-wrapper.properties
#Tue Oct 30 12:36:36 CST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fedming.webtonativedemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>