Android HTML与原生交互

来源:互联网 发布:usb数据延长线 编辑:程序博客网 时间:2024/05/20 20:20

前言

HTML+原生交互是最近比较流行的方式,很多人都在使用,用了这么久的这种模式,小编#整合了下,方便技术更替之后再次查看,也希望这篇文章能够对你有用。

下面就简单整合下,HTML与原生如何交互

1.布局

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="@color/comm_bg"    android:orientation="vertical">    <include        android:id="@+id/layout_top_bar"        layout="@layout/top_bar" />   //PtrClassicFrameLayout  [下拉刷新框架view]    <com.reach.doooly.pullresh.PtrClassicFrameLayout    xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"        android:id="@+id/view_frame"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_below="@+id/layout_top_bar">        <RelativeLayout            android:layout_width="match_parent"            android:layout_height="match_parent">            <RelativeLayout                android:layout_width="match_parent"                android:layout_height="match_parent"                android:orientation="vertical">                <WebView                    android:id="@+id/view_webview"                    android:layout_width="match_parent"                    android:layout_height="match_parent" />                <ProgressBar                    android:id="@+id/view_progressbar"                    style="?android:attr/progressBarStyleHorizontal"                    android:layout_width="match_parent"                    android:layout_height="1dp"                    android:progressDrawable="@drawable/pull_progressbar_pg"                    android:visibility="gone" />            </RelativeLayout>            <include layout="@layout/webview_err_view"                android:visibility="gone"/>        </RelativeLayout>    </com.reach.doooly.pullresh.PtrClassicFrameLayout></RelativeLayout>

2.activity

package com.reach.doooly.server;import android.app.Activity;import android.os.Bundle;import com.reach.doooly.R;/** * Created by Albert on 2017/10/16. */public class WebViewActivity extends Activity{    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.webview_layout);    }}

下面我们需要做的是
[1]初始化webview

 private WebView webView; private void initView(){        webView=(WebView)findViewById(R.id.view_webview);    }

[2]webview提供javascript支持

        WebSettings webSettings = webView.getSettings();        webSettings.setTextZoom(100);//设置web端界面不随html改变        webSettings.setDomStorageEnabled(true); // 使用localStorage        webSettings.setLoadWithOverviewMode(true); // 设置页面自适应屏幕        webSettings.setJavaScriptEnabled(true); // 支持javascript        webSettings.setNeedInitialFocus(false); // 阻止内部节点获取焦点        webSettings.setPluginState(PluginState.ON);        webSettings.setAllowFileAccess(true);        webSettings.setAllowContentAccess(true);        webSettings.setAllowFileAccessFromFileURLs(true);        webSettings.setAllowUniversalAccessFromFileURLs(true);        // 修复加载资源失败BUG end        webSettings.setSavePassword(false);        // SDK3.0以上开启硬件加速,部分机器        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {            webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);        }        webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);        webView.requestFocusFromTouch();        webView.setFocusable(true);        webView.setLongClickable(true);        webView.setHorizontalScrollBarEnabled(false);//水平不显示        webView.setVerticalScrollBarEnabled(false); //垂直不显示        webView.setOnLongClickListener(new WebView.OnLongClickListener() {            @Override            public boolean onLongClick(View v) {                return true;            }        });        if (Build.VERSION.SDK_INT >= 21) {//添加这一句https和http都兼容,但其实中并没有什么用,只是为了防止有问题填写的            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);        }        webSettings.setDomStorageEnabled(true);        webSettings.setAppCacheMaxSize(1024*1024*8);//设置缓冲大小,我设的是8M        String  appCacheDir  =  context.getDir("cache", Context.MODE_PRIVATE).getPath();        webSettings.setAppCachePath(appCacheDir);        webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH);        webSettings.setAllowFileAccess(true);        webSettings.setAppCacheEnabled(true);        webSettings.setDomStorageEnabled(true);        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);        // 移除有安全隐患的接口        removeUnSafeJavascriptInterface();        webView.setWebViewClient(webViewClient);        webView.setWebChromeClient(webChromeClient);

移除有js安全隐患的接口

   /**     * 移除有安全隐患的JS接口     */    private void removeUnSafeJavascriptInterface() {        try {            webView.removeJavascriptInterface("searchBoxJavaBridge_");            webView.removeJavascriptInterface("accessibility");            webView.removeJavascriptInterface("accessibilityTraversal");        } catch (Exception e) {        }    }

下面为一些事件处理等支持

 /**     * 添加javascript插件     *     * @param plugin     * @param name     */    @SuppressLint("JavascriptInterface")    public void addJavascriptInterface(Object plugin, String name) {        webView.addJavascriptInterface(plugin, name);    }    /**     * 是否支持JS alert 显示     *     * @param isSupport     */    public void setSupportJsAlert(boolean isSupport) {        try {            if (!isSupport) {                webView.setWebChromeClient(null);            } else {                webView.setWebChromeClient(new WebChromeClient() {                    @Override                    public boolean onJsAlert(WebView view, String url,                                             String message, final JsResult result) {                        CommAlertDialog CommAlertDialog1 = new CommAlertDialog(context);                        CommAlertDialog1.setConfim();                        CommAlertDialog1.setMessage("提示:");                        final TextView comm_submit = (TextView) comm_dialog.findViewById(R.id.comm_submit);                        comm_submit.setOnClickListener(new View.OnClickListener() {                            @Override                            public void onClick(View v) {                                result.confirm();                            }                        });                        CommAlertDialog1.setCancelable(false);                        CommAlertDialog1.show();                        return true;                    }                });            }        } catch (Exception e) {        }    }    private WebChromeClient webChromeClient=new WebChromeClient(){        @Override        public void onProgressChanged(WebView view, int newProgress) {            // TODO 自动生成的方法存根            if (newProgress == 100) {                if(context instanceof LoginFragmentActvity || context instanceof WebViewActivity) {                    progressBar.setVisibility(View.INVISIBLE);// 加载完网页进度条消失                }else{                    progressBar.setVisibility(View.GONE);// 加载完网页进度条消失                }                if(plugin!=null){                    plugin.hideWaitPanel();                }            } else {                progressBar.setVisibility(View.VISIBLE);                progressBar.setProgress(newProgress);// 设置进度值                if(plugin!=null){                    plugin.showWaitPanel();                }            }        }    };    private WebViewClient webViewClient = new WebViewClient() {        @Override        public void onReceivedSslError(WebView view, android.webkit.SslErrorHandler handler, android.net.http.SslError error) {            handler.proceed();        }        @Override        public boolean shouldOverrideUrlLoading(WebView view, String url) {            try {                view.requestFocus();                view.loadUrl(url);                webView.setVisibility(View.VISIBLE);                error_rela_layout.setVisibility(View.GONE);            } catch (Exception e) {            }            return true;        }        @Override        public void onPageStarted(WebView view, String url, Bitmap favicon) {            Logs.d(TAG, "onPageStarted----");            plugin.showWaitPanel("加载中...");        }        @Override        public void onPageFinished(WebView view, String url) {            plugin.hideWaitPanel();            if (context instanceof RHFragmentActivty) {//处理标题事件                RHFragmentActivty ac = (RHFragmentActivty) context;            }            if (comm_dialog != null && comm_dialog.isShowing()) {                error_rela_layout.setVisibility(View.VISIBLE);            } else {                error_rela_layout.setVisibility(View.GONE);            }        }        @Override        public void onReceivedError(WebView view, final int errorCode,                                    String description, String failingUrl) {            try {                plugin.hideWaitPanel();                error_rela_layout.setVisibility(View.VISIBLE);                plugin.errPageBack();                String errorFlagString = "";                switch (errorCode) {                    case ERROR_AUTHENTICATION://                        errorFlagString = "用户认证失败";                        errorFlagString = "网络异常,请检查网络";                        break;                    case ERROR_CONNECT:                        errorFlagString = "连接服务器失败";                        break;                    case ERROR_TIMEOUT:                        errorFlagString = "网络连接超时";                        break;                    case ERROR_PROXY_AUTHENTICATION://                        errorFlagString = "用户代理验证失败";                        errorFlagString = "网络异常,请检查网络";                        break;                    case ERROR_HOST_LOOKUP:                        //errorFlagString = "服务器绑定或代理失败";                        errorFlagString = "网络异常,请检查网络";                        break;                    case ERROR_BAD_URL:                        errorFlagString = "URL 格式错误";                        break;                    default:                        errorFlagString = "未知错误";                        break;                }                final int err = errorCode;                final String msg = description;                if (comm_dialog == null) {                    comm_dialog = new CommAlertDialog(context);                    comm_dialog.setConfim();                    comm_dialog.setTitle("系统提示");                    comm_dialog.setMessage(errorFlagString + "");                    final TextView comm_submit = (TextView) comm_dialog.findViewById(R.id.comm_submit);                    comm_submit.setOnClickListener(new View.OnClickListener() {                        @Override                        public void onClick(View v) {                            if (webViewManageListener != null) {                                webViewManageListener.onClickErrorConfirm(err, msg);                            }                            comm_dialog.dismiss();                        }                    });                }                if (comm_dialog != null && comm_dialog.isShowing() != true) {                    comm_dialog.show();                }//                if (view.canGoBack()) {//                    view.goBack();//                }            } catch (Exception e) {                plugin.hideWaitPanel();                plugin.errPageBack();//                if (view.canGoBack()) {//                    view.goBack();//                }            }        }    };    /**     * WebViewManage 监听器     */    public interface WebViewManageListener {        // 联网错误弹出确认框,点击确认框监听        public void onClickErrorConfirm(int errorCode, String description);    }

在页面错误中,每个项目的实际需求不一样,请按照当前项目的实际需求开发选取。

3.NATIVE提供该HTML的js方法

1)js方法类的父类

package com.reach.doooly.base.plugin;/** * 插件基类,项目中插件需要继承此类,防止js注入 * @author qinming.fu@reach-core.com * Copyright (c) 2014 Shanghai P&C Information Technology Co., Ltd. */public class RHBasePlugin {    /**     * 防止js注入     */    public Object getClass(Object o) {        return null;    }    /**     * 处理js回调函数,如果函数不带括号,就加上括号     */    public String handleJsFunc(String func) {        String handledFunc = func;        if (!func.endsWith(")")) {            handledFunc += "()";        }        return handledFunc;    }}

2)具体提供给html的js func实现
下面以弹出加载框为例子

package com.reach.doooly.pullresh.webview;import android.Manifest;import android.app.Activity;import android.app.AlertDialog;import android.content.Intent;import android.content.pm.PackageManager;import android.hardware.Camera;import android.net.Uri;import android.os.Bundle;import android.support.v4.app.ActivityCompat;import android.view.LayoutInflater;import android.view.View;import android.webkit.JavascriptInterface;import android.webkit.WebView;import android.widget.ImageView;import android.widget.TextView;import com.google.gson.Gson;import com.reach.doooly.R;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONObject;import java.io.File;import java.net.URISyntaxException;import java.util.ArrayList;import java.util.List;/** * @Description native与webjs交互插件插件名称"SysClientJs" * @Author Lewis(lgs@yitong.com.cn) 2014年7月3日 上午9:23:33 * @Class JsPlugin Copyright (c) 2014 Shanghai P&C Information Technology * Co.,Ltd. All rights reserved. 修改人:fuqinming */public class NativePlugin extends RHBasePlugin {    public static final String TAG = "NativePlugin";    public static final String NAME = "RHNativeJS";    private Activity activity;    private CommAlertDialog builder;// 公用的弹出框    private WebView webView;    private TopBarSetListener topBarSetListener;    private LoadingDialog loadProgress;// 加载框    private static char ER_SPLIT_CHAR = 29;    private static String ER_CODE_MESSAGE = "MOBILE" + ER_SPLIT_CHAR + "type"            + ER_SPLIT_CHAR + "cardId";    public NativePlugin(Activity activity, WebView webView) {        this.activity = activity;        this.webView = webView;    }    public void setTopBarSetListener(TopBarSetListener topBarSetListener) {        this.topBarSetListener = topBarSetListener;    }    /**     * 2.show 加载框     */    @JavascriptInterface    public void showWaitPanel() {        Logs.d(TAG, "showWaitPanel开启等待层msg");        activity.runOnUiThread(new Runnable() {            @Override            public void run() {                if (loadProgress == null && activity instanceof MainActivity) {                    loadProgress = new LoadingDialog(activity);                }                if (loadProgress != null && !activity.isFinishing()                        && !loadProgress.isShowing()) {                    // 满足1.当前加载框存在2.activity没有关闭3.加载框没有关闭                    loadProgress.show();                }            }        });    }    }

在activity中给js类添加别名

 webViewManage.addJavascriptInterface(nativePlugin, NativePlugin.NAME);

4.HTML调用

<html><head>    <title>测试</title>    <script type="text/javascript">       function btnAction()        {          alert("测试initTopTitle() native")        RHNativeJS.showWaitPanel();        };        function jumpOne(){          alert("执行弹出");           //window.location.href='http://baidu.com';        };        function jumpTwo(){        alert("执行弹出2");        //window.location.href='http://blog.csdn.net/changemyself/article/details/40212057';        };        //btnAction();    </script></head><body><button type="submit" onclick="btnAction()"> 加载</button><p/><button type="submit" onclick="jumpOne()"> 加载1</button><p/><button type="submit" onclick="jumpTwo()"> 加载2</button></body></html>

让webview加载这个url

url = "file:///android_asset/index.html";            Logs.d(TAG, "url:" + url);            webView.loadUrl(url);

这样简单就完成了,运行代码之后会出现效果,先弹出框,然后弹出loadding框

下面是开发中需要特别注意的:
1)需要兼容HTTp和HTTPS,除了需要android原生代码证书认证之后,还需要web端jquery在2.3以上
2)html报错不会马上有小x提示,可以亲们注意日志,会提示某个方法不存在
3)键盘弹出隐藏,这里如果为adjustSize,会整体出现webview往上走,顾最好html自己实现键盘控制,当然也可以原生写,但是比较麻烦。为了更好的体验,web端实现最好不过了欧。

原创粉丝点击