Android WebView 运用

1、webview 1.0版本 ---最简单的加载网页

 mWebView.loadUrl("http://blog.csdn.net/");

这样基本上是可以显示网页的,不过显示的内容可能和你想象的不大一样,因为没有配置各种setting。比如JS的使用,缩放,是否可以访问文件等等。

2、webview 1.1版本 -- 设置各种参数


        // HTML5支持的配置
        WebSettings webSettings = webView.getSettings();
      
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDefaultTextEncodingName("utf-8");
        webSettings.setBuiltInZoomControls(true);
        webSettings.setSupportZoom(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setAllowFileAccess(true);  //设置可以访问文件
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口
        webSettings.setLoadsImagesAutomatically(true);  //支持自动加载图片
        webSettings.setUseWideViewPort(true);  //将图片调整到适合webview的大小
            webSettings.setUserAgentString("userAgent");
        // pc网页屏幕自动适配
        webSettings.setUseWideViewPort(true);
        webSettings.setLoadWithOverviewMode(true);
        //支持多窗口模式
        webSettings.supportMultipleWindows();
        //html的支持
        webSettings.setSavePassword(false);
        webSettings.setSaveFormData(false);
        // 启用数据库
        webSettings.setDatabaseEnabled(true);
        String dir = context.getApplicationContext()
                .getDir("database", Context.MODE_PRIVATE).getPath();
        // 设置数据库路径
        webSettings.setDatabasePath(dir);
        // 使用localStorage则必须打开
        webSettings.setDomStorageEnabled(true);
        // 启用地理定位
        webSettings.setGeolocationEnabled(true);
        // 设置定位的数据库路径
        webSettings.setGeolocationDatabasePath(dir);

根据我们的需求合理设置WebSettings。这样我们基本上可以打开自己想要的页面,也有了和页面相应的交互了。但是这个可能还满足不了工作上的需求。比如我要在Webview内部跳转,加上进度条,对某些链接进行特殊处理等等,而不是点击调到系统的浏览器里面。那么我们开始下一个版本。

3、webview 1.2版本
我们需要认识一下 两个新朋友

  • WebViewClient类:处理各种通知 & 请求事件
  • WebChromeClient :辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。


    1870221-4fc780f7162c5999.png
    全部方法.png

    首先来看一下WebViewClient 中的shouldOverrideUrlLoading方法的描述

Give the host application a chance to take over the control when a new
     * url is about to be loaded in the current WebView. If WebViewClient is not
     * provided, by default WebView will ask Activity Manager to choose the
     * proper handler for the url. If WebViewClient is provided, return true
     * means the host application handles the url, while return false means the
     * current WebView handles the url.
     * This method is not called for requests using the POST "method".

中文意思大概是:当一个新的URL加载到这个WebView里的时候,主程序拥有一个接管控制权的机会,如歌这个类没有使用,默认是询问Activity Manager 选择一个恰当的处理程序给这个webview。如果我们使用这个WebViewClient,如果返回true,那么意味着交给主程序去处理这个URL,如果返回false,那么就是当前webview处理这个url。该方法不使用 POST的请求方式。翻译的很烂,英语好的可以替我翻译一下。

当我看到这个的时候也是一知半解,啥意思啊,主程序处理和webview的处理区别在哪里呢?那我们就做个demo来看一下吧。

  mWebView.setWebViewClient(new MyWebViewClient());

public class MyWebViewClient extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        boolean isOverride = super.shouldOverrideUrlLoading(view, url);
        Log.i("webview","url shouldOverrideUrlLoading:"+isOverride+"");
        return isOverride;
    }
}

如果我们设置了setWebViewClient,就说明以后的URL处理交给了这个webview,这个也是webviewclient的含义,然后我们来看返回值得区别。通过看源码或者英文描述,默认返回false,就是说明我们不会重写URl的loading,也就是说一切的点击都这在这个webview里面,相当于我们自己的浏览器。
如果返回true就说明你劫持了这个url,你想做什么自己决定,可以劫持这个url我们重新打开一个WebActivity。这样我们就可以对特定的url做处理了。
比如其他的onLoadResource、onReceivedHttpError、onPageStarted、onPageFinished就很简单了,根据名字就知道大概的功能了,就不一一讲解了。大家可以测试一下。
如果我们想要给我们的webview加上进度条又该怎么办呢?那就需要WebChromeClient大兄弟了。

 @Override
    public void onProgressChanged(WebView view, int newProgress) {
        super.onProgressChanged(view, newProgress);
    }

    @Override
    public void onReceivedTitle(WebView view, String title) {
        super.onReceivedTitle(view, title);
    }

    @Override
    public void onReceivedIcon(WebView view, Bitmap icon) {
        super.onReceivedIcon(view, icon);
    }

    @Override
    public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
        return super.onJsAlert(view, url, message, result);
    }

    @Override
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
    }

这几个是比较常用的方法。
onProgressChanged可以监听到打开页面的进度。
onReceivedTitle可以获取页面的title
onReceivedIcon可以获取页面的Icon
onShowFileChooser webview调用系统的文件系统
重点和难点是 webview如何如何能打开比如图库,摄像头等功能。
因为不同android版本的打开方法不一样所以我们要

   //For Android 3.0+
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
        mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
    }


    // For Android < 3.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg) {
        openFileChooser(uploadMsg, "");
    }


    // For Android  > 4.1.1
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
        openFileChooser(uploadMsg, acceptType);
    }


    // For Android > 5.0
    @Override
    public boolean onShowFileChooser(WebView webView, com.tencent.smtt.sdk.ValueCallback<Uri[]> valueCallback, FileChooserParams fileChooserParams) {
        mOpenFileChooserCallBack.openFileChooserCallBackAndroid5(valueCallback, "");
        return true;
    }

根据不同api来调用我们的处理函数。
既然js会调用这些方法中的一个,其实也就是分为5.0以上和以下两个回调方法。那么我们也相应的让activity回调webview的这个方法。

public interface OpenFileChooserCallBack {
        void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType);

        void openFileChooserCallBackAndroid5(ValueCallback<Uri[]> uploadMsg, String acceptType);
    }

然后就是打开图库或者摄像头

  @Override
    public void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType) {
        mValueCallback = uploadMsg;
        if (checkRights()) {
            showOptions();
        }
    }

    @Override
    public void openFileChooserCallBackAndroid5(ValueCallback<Uri[]> uploadMsg, String acceptType) {
        mValueCallbackAndroid5 = uploadMsg;
        if (checkRights()) {
            showOptions();
        }
    }
 //检车读写文件 拍照像个权限
    private boolean checkRights() {
        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            //申请WRITE_EXTERNAL_STORAGE权限
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA},
                    WRITE_EXTERNAL_STORAGE_REQUEST_CODE);
            return false;
        }
        return true;
    }

    public void showOptions() {
        android.app.AlertDialog.Builder alertDialog = new android.app.AlertDialog.Builder(this);
        alertDialog.setOnCancelListener(new ReOnCancelListener());
        alertDialog.setTitle("选择图片");
        alertDialog.setItems(new String[]{"相机选取", "拍照", "取消"}, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (which == 0) {
                            mSourceIntent = ImageUtil.choosePicture();
                            startActivityForResult(mSourceIntent, REQUEST_CODE_PICK_IMAGE);
                            overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right);
                        } else if (which == 1) {
                            mSourceIntent = ImageUtil.takeBigPicture();
                            startActivityForResult(mSourceIntent, REQUEST_CODE_IMAGE_CAPTURE);
                            overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right);
                        } else {
                            dialog.dismiss();
                            dialog.cancel();
                        }
                    }
                }
        );
        alertDialog.show();
    }

那么怎么把图片的信息交给js呢?

 @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

        Log.i("webview", "onActivityResult");
        if (resultCode != Activity.RESULT_OK) {
            return;
        }
        switch (requestCode) {

            case REQUEST_CODE_IMAGE_CAPTURE:
            case REQUEST_CODE_PICK_IMAGE: {
                try {
                    if (mValueCallback == null && mValueCallbackAndroid5 == null) {
                        return;
                    }
                    String sourcePath = ImageUtil.retrievePath(this, mSourceIntent, data);
                    if (TextUtils.isEmpty(sourcePath) || !new File(sourcePath).exists()) {
                        Log.i("webview", "sourcePath empty or not exists.");
                        break;
                    }
                    Uri uri = Uri.fromFile(new File(sourcePath));
                    if (mValueCallback != null) {
                        mValueCallback.onReceiveValue(uri);
                        Log.i("webview", "   mValueCallback.onReceiveValue(uri)"+uri);
                    }

                    if (mValueCallbackAndroid5 != null) {
                        mValueCallbackAndroid5.onReceiveValue(new Uri[]{uri});
                        Log.i("webview", "   mValueCallbackAndroid5.onReceiveValue(uri)"+uri);
                    }

                    //通知更新图库
                    if (requestCode == REQUEST_CODE_IMAGE_CAPTURE) {
                        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            }
        }
    }

我们回调方法里面ValueCallback<Uri> mValueCallback,ValueCallback<Uri[]> mValueCallbackAndroid5 负责把消息带给js,如果没有url那么记得 =null,不然下次回调方法不会调用。我猜测是因为 有一个值得判断,如果为空才会相应,不为空就不相应。感兴趣的朋友可以看看源码,我的水平有限,希望各位朋友不吝指教。
对于交互http://blog.csdn.net/carson_ho/article/details/52693322大神写的很好,可以参考这个。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值