因为项目需求需要显示较为复杂的UI,类似echart的各种统计图。如果封装Android和iOS两端的组件费时费力,因此就想到通过加载本地HTML的方式来实现,但是发现weex的webView组件是没有加载本地html的功能,因此就要自己扩展一下。
这次封装的webView组件具有较强的通用性,可以在HTML界面的事件传递到weex端,也可以在weex端调用HTML端的js方法,这篇先主要说一下Android端的封装。
首先按照weex官网提供的组件封装方式新建HtmlComponent类继承WXComponet<WebView>。
public class Html5Component extends WXComponent<WebView>{
//我们操作的webView
private WebView webView;
//持有组建的当前weex实例
private WXSDKInstance instance;
//要加载的HTML文件,此文件放在assets下的html文件夹下
private String url="file:///android_asset/html/index.html";
//浏览器加载界面是否完成
private boolean mLoadFinish=false;
//构造方法,获得当前weex实例instance
public Html5Component(WXSDKInstance instance, WXDomObject dom, WXVContainer parent) {
super(instance, dom, parent);
this.instance = instance;
}
public Html5Component(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, int type) {
super(instance, dom, parent, type);
this.instance = instance;
}
//初始化webView设置一些参数
@SuppressLint("SetJavaScriptEnabled")
private void init(){
webView.setInitialScale(100);
webView.addJavascriptInterface(this,"native");
WebSettings webSettings=webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小
webSettings.setSupportZoom(false); //支持缩放,默认为true。是下面那个的前提。
// webSettings.setBuiltInZoomControls(false); //设置内置的缩放控件。若为false,则该WebView不可缩放
// webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件
//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setAllowFileAccess(false); //设置可以访问文件
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式
webView.loadUrl(url);
//复写shouldOverrideUrlLoading()方法,使得打开网页时不调用系统浏览器, 而是在本WebView中显示
webView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onPageFinished(WebView view, String url) {
mLoadFinish=true;
//这里出发webView组件的finish事件,表示网页已经加载完成
fireEvent("finish");
}
});
}
//父类的方法,重写这个方法获取path属性的值,这个是我们要加载的html界面
@Override
protected WebView initComponentHostView(@NonNull Context context) {
if(getDomObject().getAttrs().get("path")!=null){
this.url="file:///android_asset/html/"+getDomObject().getAttrs().get("path").toString();
}
//新建webView
this.webView = new WebView(context);
init();
return this.webView;
}
@Override
protected void onCreate() {
super.onCreate();
}
@Override
public void onActivityDestroy() {
super.onActivityDestroy();
}
/*要加载的html的文件路径*/
@WXComponentProp(name = "path")
public void setPath(String path) {
this.url="file:///android_asset/html/"+path;
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onFinishLayout() {
super.onFinishLayout();
}
//为html提供的通用的触发webView在weex中的对应方法名的事件
@JavascriptInterface
public void fireWeexEvent(final String weexMethod, String param){
String data="";
if(param!=null){
data=param;
}
final HashMap map=new HashMap();
map.put("data",data);
this.webView.post(new Runnable() {
@Override
public void run() {
fireEvent(weexMethod,map);
}
});
}
/*为weex界面提供的调用h5中js方法的接口*/
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@JSMethod
public void executeJsFunction(String functionName, String param, final JSCallback callback){
if (!mLoadFinish){
return;
}
if (!TextUtils.isEmpty(functionName)) {
webView.evaluateJavascript("javascript:"+functionName+"("+param+")", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
if(callback!=null){
HashMap map=new HashMap();
map.put("res",value);
callback.invoke(map);
}
}
});
}
}
}
这里着重说明fireWeexEvent和executeJSFunction这两个方法的用法。
1、 fireWeexEvent(String weexMethod,String param)
在HTML中可以调用这个方法出发webView组件上对应weexMethod参数的事件,并可以传递param作为参数到weex端,
具体写法如下:
在HTML中在合适的时机通过js执行
native.fireWeexEvent('newEvent','yololiu');
在weex端接受事件和参数
<webView ref="myWeb" @newEvent="newEvent" path="index.html" @finish="htmlFinish" style="width: 720px; height:600px;">
</webView>
<script>
var modal=weex.requireModule('modal');
export default {
methods: {
htmlFinish(){
modal.alert({message:'界面加载完成'});
},
newEvent(e){
//e.data即为HTML传来的值
modal.alert({message:e.data});
}
}
</script>
2、 executeJSFunction(String functionName,String param,JSCallBack callback)
使用方法如下:
在HTML中声明方法doSomeThing
function doSomeThing(param){
console.log(param);
}
在weex端调用此方法
<webView ref="myWeb" path="index.html" @finish="htmlFinish" style="width: 720px; height:600px;">
</webView>
<script>
var modal=weex.requireModule('modal');
export default {
methods: {
htmlFinish(){
modal.alert({message:'界面加载完成'});
},
excuJS(e){
this.$refs.myWeb.executeJSFunction('doSomeThing','传到HTML的数据',
function(){
//执行完成的回调
})
}
}
</script>
封装完成不要忘记在Application中注册组件
WXSDKEngine.registerComponent("webView", Html5Component.class);
至此Android的webView组件就封装完成了,下一篇简单说一下iOS端的封装 ,原理和Android端基本一致,有iOS开发基础的话可以自己试一下。