美文网首页
安卓日志01——webview一些疏漏的地方

安卓日志01——webview一些疏漏的地方

作者: 9dfaf364d57f | 来源:发表于2018-02-03 15:07 被阅读221次

这篇文章主要讲小盆友在工作中遇到的一些问题,如果喜欢请给个心:

目录:
1、onReceivedSslError的应用
2、白名单拦截
3、登录、唤起原生支付
4、标题的优化
5、图片保存

1、onReceivedSslError的应用

在2017年11月11日双十一的冲击下,嵌套在app内的网页大多被劫持,公司的app的webview加载网页有白名单,一旦不是白名单中的网页就会不进行请求,导致会白屏。在这样的场景下,公司决定全部换成https的链接,换成了https,有些机型会有白屏问题,需要在WebViewClient的onReceivedSslError方法加入如下处理:

//为了避免https白屏
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    handler.proceed();
}

onReceivedSslError是在 SSL 证书验证错误时会进行回调,这里这样处理,其实是相当暴力,但却符合国内app的处理方式(尽量让用户少动脑少操作),话虽如此,这样的应用无法google play,因为google play有规定不能这样处理,也给出了如下的处理方式(其实就是将风险转给用户):

@Override
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setMessage(R.string.notification_error_ssl_cert_invalid);
    builder.setPositiveButton("continue", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            handler.proceed();
        }
    });
    builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            handler.cancel();
        }
    });
    final AlertDialog dialog = builder.create();
    dialog.show();
}
2、白名单拦截

在上一小结讲到白名单,这里就略微提一下,操作很简单,在WebViewClient中重写shouldInterceptRequest方法

@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
    //isFilter是一个自定义绕白名单标记,在开启webview时,可以传入,如果为false,表示不拦截
    if (!isFilter) {    
        return super.shouldInterceptRequest(view, url);
    }
    //isValidUrl方法可以自己定义,我的话是使用一个list存放(后台获取),判断url是否含有其中的字符串,
    //若有,则说明在白名单中,进行正常请求;否则,返回空响应。
    if (isValidUrl(url)) {           
        return super.shouldInterceptRequest(view, url);
    }
    return new WebResourceResponse("text/html", "UTF-8", myInputStream);
}
//空的响应
private InputStream myInputStream = new InputStream() {
    @Override
    public int read() throws IOException {
        return -1;
    }
};
3、登录、唤起原生支付

重写WebViewClient中的shouldOverrideUrlLoading

@Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url) {
    if (isLoginPage(url)) {  //进行判断是否为登录链接(此处方法只是用于验证url是否为app规定的登陆页)
        gotoRefreshToken(url);    //进行刷新获取token(该方法只是发起获取token请求)
        return true;
    } else if (url.startsWith("weixin://wap/pay?")) {   //微信
        gotoPage(url, "请先安装微信APP,再进行支付");
        return true;
    } else if (url.startsWith("alipays://platformapi")) {//支付宝
        gotoPage(url, null);
        return true;
    } 
    return super.shouldOverrideUrlLoading(view, url);
}

private void gotoPage(String url, String tip) {
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    if (intent.resolveActivity(getContext().getPackageManager()) != null) {
        startActivity(intent);
    } else {
        if (!TextUtils.isEmpty(tip)) {
            ToastTool.showTips2Center(tip);
        }
        Log.e("webfragment", "route:未找到" + url);
    }
}
4、标题的优化

当webview标题变动时,会调用WebChromeClient的onReceivedTitle,可以在方法中设置toolbar的标题,并需要手动在onProgressChanged中去判断是否加载完。

@Override
public void onReceivedTitle(WebView view, String title) {
    super.onReceivedTitle(view, title);
    getWebCallback().setWebTitle(title);//此处回调改toolbar的标题
}
5、图片保存

需要长按一个图片弹出一个框提示“是否保存该图片”,webview并没有默认支持,需要自己做处理,只需要在给webview添加长按事件

mWebView.setOnLongClickListener(this);

然后在

@Override
public boolean onLongClick(View v) {
    final WebView.HitTestResult result = ((WebView) v).getHitTestResult();
    if (result != null) {
        int type = result.getType();
        //图片保存
        if (type == WebView.HitTestResult.IMAGE_TYPE || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {

            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
            builder.setTitle("提示");
            builder.setMessage("是否保存该图片");
            builder.setCancelable(false);
            builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            });
            builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                    String imgurl = result.getExtra();      //标签的内容

                    final String path = FileUtils.getMyCacheDir("aoyunWeb") + System
                            .currentTimeMillis() / 1000 + (imgurl
                            .endsWith(".png") ? ".png" : ".jpg");
                    final File file = new File(path);  //生成文件

                    Observable<DownloadHelper.Progress> observable;

                    if (imgurl.startsWith("data:image/")) {  //base64的图
                        
                    } else {  //网络图
                       
                    }
                }
            });
            builder.create().show();

            return true;
        }
    } 
}  
6、webview唤起原生图片选择

在WebChromeClient中添加如下代码:

//安卓2.+使用
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
    Log.d(TAG, "openFileChoose(ValueCallback<Uri> uploadMsg)");
    mUploadMessage = uploadMsg;
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    getActivity().startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}

//安卓3.+使用
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
    Log.d(TAG, "openFileChoose( ValueCallback uploadMsg, String acceptType )");
    mUploadMessage = uploadMsg;
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    getActivity().startActivityForResult(
            Intent.createChooser(i, "File Browser"),
            FILECHOOSER_RESULTCODE);
}

//安卓4.+使用
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
    Log.d(TAG, "openFileChoose(ValueCallback<Uri> uploadMsg, String acceptType, String capture)");
    mUploadMessage = uploadMsg;
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
}

// Android 5.0+ 以上使用
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
    mUploadCallbackAboveL = filePathCallback;
    Intent i = new Intent(Intent.ACTION_GET_CONTENT);
    i.addCategory(Intent.CATEGORY_OPENABLE);
    i.setType("image/*");
    getActivity().startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
    return true;
}

在Activity中添加回调:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == WebFragment.FILECHOOSER_RESULTCODE) {
        if (null == webFragment.mUploadMessage && null == webFragment.mUploadCallbackAboveL)
            return;
        Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
        if (webFragment.mUploadCallbackAboveL != null) {
            onActivityResultAboveL(requestCode, resultCode, data);
        } else if (webFragment.mUploadMessage != null) {
            Uri uri = Uri.parse("file://" + uriToPath(this, result));
            webFragment.mUploadMessage.onReceiveValue(uri);
            webFragment.mUploadMessage = null;
        }
    }
}

并添加成员属性:

public ValueCallback<Uri> mUploadMessage;
public final static int FILECHOOSER_RESULTCODE = 1;
public ValueCallback<Uri[]> mUploadCallbackAboveL;     

相关文章

网友评论

      本文标题:安卓日志01——webview一些疏漏的地方

      本文链接:https://www.haomeiwen.com/subject/tpnnnxtx.html