Android 与js的简单交互——从WebView开始

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MonaLisaTearr/article/details/80215971

        前言:最近做一个论坛社交类型的项目,要android端与pc端的论坛公用数据,所以详情页比较难有固定的格式,后来决定用H5来做,由于帖子的点赞、转发、评论、分享等细小的功能比较多,不可避免的android端就跟pc端有着很复杂的交互逻辑了,接下来总结下自己使用webview的一些经历跟踩过的坑!

一、WebView

        首先WebView的时候肯定是从WebSettings说起,这个对象包含了很多WebView的基本配置,他的获取方式不是new出来的而是通过WebView的事例获取的:

mWebView = (WebView) findViewById(R.id.webview);
WebSettings settings = mWebView.getSettings();

1、以下是一些比较常用到的设置,当然还有很多设置项,那些没有过的日后再研究

mWebView = (WebView) findViewById(R.id.webview);
WebSettings settings = mWebView.getSettings();

/*设置当前webview是否支持js*/
settings.setJavaScriptEnabled(true);

/**
* 设置webview的缓存方式,分为以下几种
* 1、LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
* 2、LOAD_DEFAULT: 根据cache-control决定是否从网络上取数据
* 3、LOAD_NO_CACHE: 不使用缓存,只从网络获取数据
* 4、LOAD_CACHE_ELSE_NETWORK:只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据
*/
settings.setCacheMode(WebSettings.LOAD_DEFAULT);

/*设置默认编码*/
settings.setDefaultTextEncodingName("utf-8");

/*调整图片适合webview大小*/
settings.setUseWideViewPort(false);

/*设置webview是否支持缩放*/
settings.setSupportZoom(true);

/*支持多窗口*/
settings.supportMultipleWindows();

/*设置可访问文件*/
settings.setAllowFileAccess(true);

/*支持通过js打开新的窗口*/
settings.setJavaScriptCanOpenWindowsAutomatically(true);

/*支持自动加载图片*/
settings.setLoadsImagesAutomatically(true);

/*定义缓存文件的目录*/
settings.setAppCachePath(path);

当然涉及到的设置还有很多,比如说播放视频需要进行的一些设置等等,这里就不罗列了,大家可以去查查相关的文档!

二、WebViewClient

        说完了基本设置,接下来就是WebView中最重要的一个对象了,就是WebViewClient对象,这个对象中定义了很多的空方法,这些方法在WebView运行的适时间会被回调,所以当我们想要在那个时候做某些事情,就可以选择性的去覆写这些方法就可以了,下面介绍下里面一些常用的方法:

mWebView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        /*这个方法在webview开始加载网络数据的时候会被回调,我们可以在这里做一些页面加载完全前的事,比如说显示加载进度条等。*/
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        /*这个方法会在页面加载完成后回调,可以在这个方法中进行页面加载进度条的隐藏等操作*/
    }

    @Override
    public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
        super.onReceivedError(view, request, error);
        /*页面加载失败回调*/
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        /**
        * 1、这个方法也是经常用到的,当用户点击网页上某个超链接时,就是回调该方法,这个时候会传给我们即将方法的
        * 链接,我们如果不想让用户跳到该链接,可以在这里进行拦截,跳转到指定的页面。在5.0之后这个方法就被
        * shouldOverrideUrlLoading(WebView view, WebResourceRequest request)取代了,当然,看源码就知道,
        * 内部也是调用了shouldOverrideUrlLoading(WebView view, String url),这时候google经常干事。
        *
        * 2、还有就是返回值的问题,其实很简单,返回false的时候,系统会按照被点击的链接进行调整,返回true的时候
        * 系统不会进行跳转,所有的跳转逻辑需要我们自己去处理,所以使用false就好了(大神除外)
        */
        if (url.equals("http://www.baidu.com")) {
            mWebView.loadUrl("http://www.sina.com");
        }
        return false;
    }

    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        /**
        * 1/当网页加载资源过程中发现SSL错误会调用此方法。我们应用程序必须做出响应,是取消请求handler.cancel(),
        * 还是继续请求handler.proceed();内核的默认行为是handler.cancel();
        *
        * 2、SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)
        * 是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。
        */
    }
});

三、WebChromeClient

        除了WebViewClient这个对象之外还有一个很重要的对象,就是WebChromeClient对象,这个对象同样的定义了很多空方法,我们可以选择性的覆写,从而获取页面的一些信息。

mWebView.setWebChromeClient(new WebChromeClient(){
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        /**
        * 这个方法是返回网页加载进度的,这个方法几乎是必用的方法,因为我们所有的界面的加载都会用到加载进度,以达到较好的
        * 交互效果
        */
    }
});

四、DownloadListener

        有些网页上免不了提供一些下载的链接,比如说一些app的推广,文件的下载等等,那么我们就要对这一部分内容进行处理了,因为webview本身不内置下载管理这样的一个功能的,接下来介绍DownloadListener这个接口,这个接口有一个抽象方法onDownloadstart()方法,这个方法就是给我们返回将要下载的一些文件的信息的,下面时候简单的事例:

/*设置下载的listener*/
mWebView.setDownloadListener(new WvDownloadListener());

private class WvDownloadListener implements DownloadListener{

    @Override
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
        /**
        * 这里我们可以拿到url,当然就可以为所欲为了,既可以使用系统的下载管理器,当然也可以加入到自己实现的下载管理中
        */
    }
}

五、网页返回问题

        有个小问题,就是返回的问题,在电脑上我们都是点浏览器上面的返回按钮回到上一页的,但是手机上就不一样了,如果我们打开了多个网页,当我们按手机back键的时候,是直接退出程序了,这显然不是和我们想要的效果,我们想要的是回到上一页,其实这个webview时候提供有goBack()的返回方法的,我们需要做的就是监听手机的back键而已,看代码:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {//是否还有上一页
        mWebView.goBack();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

六、我去,说了那么多,TMD竟然忘记了说什么加载页面的,其实也简单,就一个api,看代码:

/*加载网络数据*/
mWebView.loadUrl("http://www.baidu.com");

/*加载本地资产目录的html文件*/
mWebView.loadUrl("file:///android_asset/xxx.html");

七、android与js的交互

        接下来聊聊android与js的交互吧,其实说白了就是java与js的互调,只要使用到webview,那么跟网页的js交互是无可避免的,当然也是最重要的部分,毕竟几乎跟网页的所有数据交互都是通过js的,那么下面就记录下我这次用的一些东西。

1、JavaScriptInterface,这个东西就是java与js交互的关键,说白了就是交互的桥梁,下面是js掉java的实现过程。

/**
* 为webview设置JavascriptInterface对象,这样WbInterface就会被映射成网页中的一个android(第二个参数可自定义,但是必须与网页上使用的一致)对象
* 这样,js就可以通过android这个对象去访问WbInterface所定义的方法了。
*/
mWebView.addJavascriptInterface(new WbInterface(),"android");

/**
* 该对象通过webview的会被映射到网页中,网页中拿到该对象
*/
private class WbInterface{

    @JavascriptInterface
    public void showToast(String msg){
        /**
        * 定义即将被js调用的adroid端方法,注意添加 @JavascriptInterface注解
        */
        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
    }
}

js中的写法:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>js调用android方法</title>
</head>
<body>
/**
* 注意,window.android.showToat()中的android必须与mWebView.addJavascriptInterface(new WbInterface(),"android")中的
* 第二个参数一致,包括方法名也必须与WbInterface中的方法名一致。
*/
<input type="button" onclick="window.android.showToast('android方法我调用了!')">
</body>
</html>

2、上面是js调用android的实现,接下来看看android调用js的实现,我们试着在android的button的onClick事件中调用js中的一个call()方法,代码如下:

mButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        /**
        * 这句代码的意思就是点击android端的button按钮时,调用了js中的call方法,并给该方法传递了arg参数
        */
        mWebView.loadUrl("javascript:call("+"'"+arg+"'"+")");
    }
});

js中方法的定义:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>android调用js方法</title>

    <script>
        window.onload = function () {

            function call(arg) {
                /**
                * 进行具体页面操作
                */
                alert("我被android调了!")
            }
        }
    </script>
</head>
<body>
</body>
</html>

八、saveState(Bundle bundle)、restoreState(Bundle bundle )

        接下来介绍两个很好用的方法,webview的saveState(Bundle bundle)跟restoreState(Bundle bundle ),这两个方法是为了方法页面状态恢复的,也就是当我们的页面退出后,当我们再次打开该页面的时候,恢复到关闭前时的状态,由于activity关闭是会回调onSaveInstanceState(Bundle outState)方法,所以我们可以在这里进行页面状态的保存,然后在activity的onCreate(Bundle savedInstanceState)方法中进行还原页面,代码如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mWebView = (WebView) findViewById(R.id.webview);

    if (savedInstanceState !=null){
        /*恢复关闭时状态*/
        mWebView.restoreState(savedInstanceState);
    }else {
        // 正常加载webview
    }
}



@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
    super.onSaveInstanceState(outState, outPersistentState);
    /*保存页面当前状态*/
    mWebView.saveState(outState);
}

好了,基本的使用方式就大概这些,当然设计到的其它还有很多很多,比如说WebView的性能上的优化,这个绝对是重头戏,待后期有交深刻的理解再分享下!下面提几个小问题:

1、我们在做一些js与java的交互时,比如说java调js方法,最好在页面加载完毕之后再做,也就是onPageFinished(WebView view, String url)方法执行之后,或者onProgressChanged(WebView view, int newProgress)方法的newProgress的返回值达到100之后,否则如果js文件还没加载下来,js中的方法是肯定是调不同的!

2、在离开webview所在的页面的时候,别忘了调下webview的onDestory()方法,还有就是webview最好不要直接写在xml中,而是通过addview的方法加入,这样创建webview的时候可以使用applicationContext,这样webview就不会持有当前activity的实例,理论上可以防止内存泄漏。

3、一般建议webview的界面单独开一个进程,这点网上说是防止OOM对主进程的影响,may be!

猜你喜欢

转载自blog.csdn.net/MonaLisaTearr/article/details/80215971
今日推荐