本例demo下载地址:HybridDemo下载
混合开发(Hybrid)也有一段时间了,现在闲下来总结一下。
说到混合开发,重要功能有2种,一是网页端调用安卓原生接口或功能,二是安卓原生调用网页功能。
Hybrid开发流程:
创建一个供网页端调用的类,如JSObject,里面编写供网页调用的方法,记得在方法上面添加@JavascriptInterface注释,否则在有些SDK版本上使用addJavascriptInterface方法(下面会用到)绑定JS对象时会报"they will not be visible in API 17"错误。
package mhwang.com.hybriddemo;
import android.content.Context;
import android.webkit.JavascriptInterface;
import android.widget.Toast;
/**
* Author : mhwang
* Date : 2018/11/28
* Version : V1.0
*/
public class JSObject {
private Context mContext;
public JSObject(Context context) {
mContext = context;
}
@JavascriptInterface
public int add(int a, int b){
return a + b;
}
@JavascriptInterface
public void showToast(String msg){
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
}
这里提供了2个方法给网页端调用,分别为add()方法和showToast()方法。
创建html网页hybrid_test.html,并添加调用接口,在网页的javascript代码中使用上面安卓提供的MyJS.add()来调用。MyJS可以看成是JSObject类在网页中的别名,下面会使用webview的addJavascriptInterface()方法将它们关联起来。
Hybrid开发测试
网页端
正常来说Android端直接使用webview的loadUrl(“javascript:”+网页方法名)就可以直接调用的,但是方法一多这样就比较容易乱,因此创建一个专门管理的类好点。
创建生成网页方法的类NativeObject。
package mhwang.com.hybriddemo;
/** 用于封装拼接调用js方法的语句
* Author : mhwang
* Date : 2018/11/28
* Version : V1.0
*/
public class NativeObject {
/** 为了方便获取String 类型的字符串
* @param s 加‘’号的参数
* @return 加了‘’号的参数
*/
private static String getJsStringParam(String s){
return "'"+s+"'";
}
public static String makeSentence(String world1, String world2){
return "javascript:makeSentence("+getJsStringParam(world1)+","+getJsStringParam(world2)+")"; // 这里要注意的是,若是传递的参数是字符串,那么在拼接调用的url的时候需要对参数加上‘’号。
}
public static String add(int a, int b){
// 不是字符串的话不用加‘’号
return "javascript:add("+a+","+b+")";
}
}
这里生成的2个方法是跟上面网页javascript代码提供的2个方法对应的。然后在需要调用的地方使用就可以,如:
wv_test.loadUrl(NativeObject.add(5, 10));
如果系统版本大于4.4,可以使用evalute.Javascript()方法,该方法的好处是可以回调javascript的返回结果。并且这个方法比 loadUrl 方法更加方便简洁,比 loadUrl 效率更高,因为 loadUrl 的执行会造成页面刷新一次,这个方法不会,下面是这个方法的使用示例:
final int version = Build.VERSION.SDK_INT;
if (version < 18) {
wv_tests.loadUrl(jsStr);
} else {
wv_test.evaluateJavascript(jsStr, new ValueCallback() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
}
});
}
在Android工程res下面添加assets文件夹,用于存放本地网页文件hybrid_test.html。
.xml布局文件
相应的.java文件
public class MainActivity extends Activity {
WebView wv_test;
Button btn_makeSentence;
Button btn_webAdd;
private static final String JSOBJECT = "MyJS";
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wv_test = findViewById(R.id.wv_test);
btn_makeSentence = findViewById(R.id.btn_makeSentence);
btn_webAdd = findViewById(R.id.btn_webAdd);
btn_makeSentence.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
wv_test.loadUrl(NativeObject.makeSentence("潇洒", "放荡"));
}
});
btn_webAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
wv_test.loadUrl(NativeObject.add(5, 10));
}
});
// 设置webview属性
WebSettings settings = wv_test.getSettings();
settings.setJavaScriptEnabled(true); // 设置是否能使用javascript
settings.setJavaScriptCanOpenWindowsAutomatically(true);
wv_test.setWebChromeClient(new WebChromeClient()); // 设置默认浏览器,否则不能弹窗
// 这里需要注意,JSObject里面提供的方法需要添加@JavascriptInterface注释,
// 否则会报"they will not be visible in API 17"错误
wv_test.addJavascriptInterface(new JSObject(this), JSOBJECT);
// 加载网页,若非本地页面,则把下面的加载地址换在页面url
wv_test.loadUrl("file:///android_asset/hybrid_test.html");
}
}
下面是一些webview常用设置项及说明(摘抄):
WebSettings webSettings = webView.getSettings();
//设置了这个属性后我们才能在 WebView 里与我们的 Js 代码进行交互,对于 WebApp 是非常重要的,默认是 false,
//因此我们需要设置为 true,这个本身会有漏洞,具体的下面我会讲到
webSettings.setJavaScriptEnabled(true);
//设置 JS 是否可以打开 WebView 新窗口
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
//WebView 是否支持多窗口,如果设置为 true,需要重写
//WebChromeClient#onCreateWindow(WebView, boolean, boolean, Message) 函数,默认为 false
webSettings.setSupportMultipleWindows(true);
//这个属性用来设置 WebView 是否能够加载图片资源,需要注意的是,这个方法会控制所有图片,包括那些使用 data URI 协议嵌入
//的图片。使用 setBlockNetworkImage(boolean) 方法来控制仅仅加载使用网络 URI 协议的图片。需要提到的一点是如果这
//个设置从 false 变为 true 之后,所有被内容引用的正在显示的 WebView 图片资源都会自动加载,该标识默认值为 true。
webSettings.setLoadsImagesAutomatically(false);
//标识是否加载网络上的图片(使用 http 或者 https 域名的资源),需要注意的是如果 getLoadsImagesAutomatically()
//不返回 true,这个标识将没有作用。这个标识和上面的标识会互相影响。
webSettings.setBlockNetworkImage(true);
//显示WebView提供的缩放控件
webSettings.setDisplayZoomControls(true);
webSettings.setBuiltInZoomControls(true);
//设置是否启动 WebView API,默认值为 false
webSettings.setDatabaseEnabled(true);
//打开 WebView 的 storage 功能,这样 JS 的 localStorage,sessionStorage 对象才可以使用
webSettings.setDomStorageEnabled(true);
//打开 WebView 的 LBS 功能,这样 JS 的 geolocation 对象才可以使用
webSettings.setGeolocationEnabled(true);
webSettings.setGeolocationDatabasePath("");
//设置是否打开 WebView 表单数据的保存功能
webSettings.setSaveFormData(true);
//设置 WebView 的默认 userAgent 字符串
webSettings.setUserAgentString("");
//设置是否 WebView 支持 “viewport” 的 HTML meta tag,这个标识是用来屏幕自适应的,当这个标识设置为 false 时,
//页面布局的宽度被一直设置为 CSS 中控制的 WebView 的宽度;如果设置为 true 并且页面含有 viewport meta tag,那么
//被这个 tag 声明的宽度将会被使用,如果页面没有这个 tag 或者没有提供一个宽度,那么一个宽型 viewport 将会被使用。
webSettings.setUseWideViewPort(false);
//设置 WebView 的字体,可以通过这个函数,改变 WebView 的字体,默认字体为 "sans-serif"
webSettings.setStandardFontFamily("");
//设置 WebView 字体的大小,默认大小为 16
webSettings.setDefaultFontSize(20);
//设置 WebView 支持的最小字体大小,默认为 8
webSettings.setMinimumFontSize(12);
//设置页面是否支持缩放
webSettings.setSupportZoom(true);