分享一个比较通用的webview

本文详细介绍了一个通用的WebViewActivity类的实现,包括加载网页、处理URL回调、与H5交互、图片上传、相机与相册调用及图片压缩等功能。通过代码示例和详细解释,帮助开发者快速理解和应用。

1、首先说下 我现在从事的是一家p2p公司,在日常的开发以及接入存管的过程中发现的一些问题,然后归总写了一个通用类。

前提大概是这样的,接下来也不多说什么,先上代码,后面再慢慢解释。

​

​

public class WebViewActivity extends HeadMenuActivity {

    private static final String TAG = WebViewActivity.class.getSimpleName();
    private Context context = WebViewActivity.this;
    private ProgressWebView wv;
    private String serviceName = "";
    private boolean isFlag = false;
    private MyWebchromeClient webchromeClient;
    public static final int REQUEST_SELECT_FILE_CODE = 100;
    private static final int REQUEST_FILE_CHOOSER_CODE = 101;
    private static final int REQUEST_FILE_CAMERA_CODE = 102;
    // 默认图片压缩大小(单位:K)
    public static final int IMAGE_COMPRESS_SIZE_DEFAULT = 400;
    // 压缩图片最小高度
    public static final int COMPRESS_MIN_HEIGHT = 900;
    // 压缩图片最小宽度
    public static final int COMPRESS_MIN_WIDTH = 675;

    private ValueCallback<Uri> mUploadMsg;
    private ValueCallback<Uri[]> mUploadMsgs;
    // 相机拍照返回的图片文件
    private File mFileFromCamera;
    private File mTakePhotoFile;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.web_view_new_layout);
        setHeadTitleName(getIntent().getStringExtra("title"));

        String url = null;
        url = getIntent().getStringExtra("url");
        wv = (ProgressWebView) findViewById(R.id.wb);
        wv.getSettings().setDefaultTextEncodingName("UTF-8");
//        wv.loadData(url == null ? "" : url, "text/html", "UTF-8");
        wv.loadUrl(url);
        wv.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                // TODO Auto-generated method stub
                // 返回值是true的时候控pri
                // 制去WebView打开,为false调用系统浏览器或第三方浏览器
                if (url.startsWith("http:") || url.startsWith("https:")) {
                    view.loadUrl(url);
                    return false;
                } else {
                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    startActivity(intent);
                    return true;
                }
            }

            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                handler.proceed();  // 接受所有网站的证书
            }


            @Override
            public void onLoadResource(WebView view, String url) {//判断是否成功
                super.onLoadResource(view, url);
                if (url.contains("serviceName=")) {
                    serviceName = ......;
                }
                if (url.contains("status=0")) {
                    isFlag = true;
                }
            }
        });

        WebSettings settings = wv.getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        settings.setSupportZoom(true);
        // 设置出现缩放工具
        settings.setDisplayZoomControls(false);
        settings.setBuiltInZoomControls(true);
        //扩大比例的缩放
        settings.setUseWideViewPort(true);
        //自适应屏幕
        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
        settings.setLoadWithOverviewMode(true);

        wv.addJavascriptInterface(new Back(), "Android");

        findViewById(R.id.headBackBtn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (isFlag) {
                    //TODO 需要加上授权操作
                    callbackOperation();

                }
                finish();
            }
        });
        webchromeClient = new MyWebchromeClient();
        wv.setWebChromeClient(webchromeClient);
        setOpenFileChooserCallBack(new MyWebchromeClient.OpenFileChooserCallBack() {
            @Override
            public void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType) {
                mUploadMsg = uploadMsg;
                featureSelection(0, null);
            }

            @Override
            public void showFileChooserCallBack(ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                if (mUploadMsgs != null) {
                    mUploadMsgs.onReceiveValue(null);
                }
                mUploadMsgs = filePathCallback;
            }
        });
    }
       
    private void callbackOperation() {
        if (serviceName.equals("***")) {
            EventBus.getDefault().post(new EventObject(EventConstant.Account, null));
        } 
    }

    //h5调用原生关闭界面方法
    class Back {
        @JavascriptInterface
        public void back(String msg) {
            if (serviceName.equals("")) {
                serviceName = msg;
            }
            callbackOperation();
            finish();
        }
    }


    public void onResume() {
        super.onResume();
    }

    public void onPause() {
        super.onPause();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // TODO Auto-generated method stub
//        if (keyCode == KeyEvent.KEYCODE_BACK) {
//            if (wv.canGoBack()) {
//                wv.goBack();// 返回上一页面
//                return true;
//            } else {
//                finish();
//            }
//        }
        if (isFlag) {
            callbackOperation();
        }
        return super.onKeyDown(keyCode, event);
    }

    public void setOpenFileChooserCallBack(MyWebchromeClient.OpenFileChooserCallBack callBack) {
        webchromeClient.setOpenFileChooserCallBack(callBack);
    }


    //选择拍照还是系统相册
    private void featureSelection(final int tag, final WebChromeClient.FileChooserParams fileChooserParams) {
        View inflate = View.inflate(this, R.layout.photo_to_choose, null);
        final PopupWindow window = new PopupWindow(inflate, RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        window.setBackgroundDrawable(new BitmapDrawable());
        window.setOutsideTouchable(true);
        window.setFocusable(true);
        window.setAnimationStyle(R.style.popupAnimationLong);
        window.showAtLocation(inflate, Gravity.BOTTOM, 0, 0);
        MyUtils.backgroundAlpha(WebViewLoadDataActivity.this, 0.5f);
        TextView cancle = (TextView) inflate.findViewById(R.id.tv_cancle);
        TextView photoAlbumChoose = (TextView) inflate.findViewById(R.id.photo_album_choose);
        TextView takingPictures = (TextView) inflate.findViewById(R.id.taking_pictures);
        photoAlbumChoose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ContextCompat.checkSelfPermission(WebViewLoadDataActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(WebViewLoadDataActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
                } else {
                    //调用相册
                    if (tag == 0) {
                        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        i.setType("*/*");
                        startActivityForResult(Intent.createChooser(i, "File Browser"), REQUEST_FILE_CHOOSER_CODE);
                    } else {
                        try {
                            Intent intent = null;
                            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                                intent = fileChooserParams.createIntent();
                            }
                            startActivityForResult(intent, REQUEST_SELECT_FILE_CODE);
                        } catch (ActivityNotFoundException e) {
                            mUploadMsgs = null;
                        }
                    }
                }
                window.dismiss();
            }
        });
        takingPictures.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ContextCompat.checkSelfPermission(WebViewLoadDataActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(WebViewLoadDataActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 100);
                } else {
                    //调用相机
                    takeCameraPhoto();
                }
                window.dismiss();
            }
        });
        cancle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                window.dismiss();
            }
        });
        window.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                MyUtils.backgroundAlpha(WebViewLoadDataActivity.this, 1f);
            }
        });
    }

    public void takeCameraPhoto() {
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
            Toast.makeText(this, "设备无摄像头", Toast.LENGTH_SHORT).show();
            return;
        }

        String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath();

        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        mFileFromCamera = new File(filePath, System.nanoTime() + ".jpg");

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTakePhotoFile));
            startActivityForResult(intent, REQUEST_FILE_CAMERA_CODE);
        } else {
            try {
                mTakePhotoFile = File.createTempFile("Zp" + System.nanoTime(), ".jpg", new File(filePath));
                Uri contentUri = FileProvider.getUriForFile(this,
                        "your package name.FileProvider", mTakePhotoFile);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, contentUri);
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                startActivityForResult(intent, REQUEST_FILE_CAMERA_CODE);
            } catch (IOException e) {

            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case REQUEST_SELECT_FILE_CODE:
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (mUploadMsgs == null) {
                        return;
                    }
                    mUploadMsgs.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
                    mUploadMsgs = null;
                }
                break;
            case REQUEST_FILE_CHOOSER_CODE:
                if (mUploadMsg == null) {
                    return;
                }
                Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
                mUploadMsg.onReceiveValue(result);
                mUploadMsg = null;
                break;
            case REQUEST_FILE_CAMERA_CODE:
                takePictureFromCamera();
                break;
        }
    }

    /**
     * 处理相机返回的图片
     */
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void takePictureFromCamera() {
        if (mFileFromCamera != null && mFileFromCamera.exists()) {
            String filePath = mFileFromCamera.getAbsolutePath();
            // 压缩图片到指定大小
            File imgFile = CameraUtils.compressImage(this, filePath, COMPRESS_MIN_WIDTH, COMPRESS_MIN_HEIGHT, IMAGE_COMPRESS_SIZE_DEFAULT);

            Uri localUri = Uri.fromFile(imgFile);
            Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri);
            this.sendBroadcast(localIntent);
            Uri result = Uri.fromFile(imgFile);

            if (mUploadMsg != null) {
                mUploadMsg.onReceiveValue(Uri.parse(filePath));
                mUploadMsg = null;
            }
            if (mUploadMsgs != null) {
                mUploadMsgs.onReceiveValue(new Uri[]{result});
                mUploadMsgs = null;
            }
        } else {
            if (mUploadMsg != null) {
                mUploadMsg.onReceiveValue(null);
                mUploadMsg = null;
            }
            if (mUploadMsgs != null) {
                mUploadMsgs.onReceiveValue(null);
                mUploadMsgs = null;
            }
        }
    }
}

这就是完整的代码了,后面逐个解释一下。

2、我开始慢慢解释了,当然注释部分已经标明每一块的用途了,能看懂了完全不需要看下面解释。

为了应对不同的场景 列出两种不同的加载方式
        1)加载表单:wv.loadData(url == null ? "" : url, "text/html", "UTF-8");
        2)加载Url:wv.loadUrl(url);

我当时碰到的需求中需要我对回调的url进行字段的截取,于是就用到了以下方法

@Override
            public void onLoadResource(WebView view, String url) {//判断是否成功
                super.onLoadResource(view, url);
                if (url.contains("serviceName=")) {
                    serviceName = ... ...;
                }
                if (url.contains("status=0")) {
                    isFlag = true;
                }
            }

onLoadResource这是对url的监听方法,可以获取h5中所用到的url。

        WebSettings settings = wv.getSettings();
        settings.setJavaScriptEnabled(true);
        // 是否读取缓存
        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);
        settings.setSupportZoom(true);
        // 设置出现缩放工具
        settings.setDisplayZoomControls(false);
        settings.setBuiltInZoomControls(true);
        //扩大比例的缩放
        settings.setUseWideViewPort(true);
        //自适应屏幕
        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
        settings.setLoadWithOverviewMode(true);

一些webview的配置,不清楚的可以百度一下。

在完整的代码中也许大家可以看到有一些对相机或者相册的代码段。

在调用别人的h5页面时,可能会碰到需要你上传图片但是这个h5又不是你自己公司写的,外部提供的 你也无法让其进行配置,只能自己去提供适用他们的功能。

设置setWebChromeClient ,setOpenFileChooserCallBack对其做监听 判断其到底是调用相机还是相册,这里再加上我设置的WebChromeClient部分代码,以供大家参考
public class MyWebchromeClient extends WebChromeClient {

    private OpenFileChooserCallBack mOpenFileChooserCallBack;

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

    //For Android 3.0 - 4.0
    public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
        if (mOpenFileChooserCallBack != null) {
            mOpenFileChooserCallBack.openFileChooserCallBack(uploadMsg, acceptType);
        }
    }

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

    // For Android > 5.0
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
        if (mOpenFileChooserCallBack != null) {
            mOpenFileChooserCallBack.showFileChooserCallBack(filePathCallback, fileChooserParams);
        }
        return true;
    }

    public void setOpenFileChooserCallBack(OpenFileChooserCallBack callBack) {
        mOpenFileChooserCallBack = callBack;
    }

    public interface OpenFileChooserCallBack {

        void openFileChooserCallBack(ValueCallback<Uri> uploadMsg, String acceptType);

        void showFileChooserCallBack(ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams);
    }

后续的是调用系统相册与相机的代码,以及回调和对图片进行压缩,不能直接采用系统图片或者照片,一般我们拍照或者相册中所存储的照片比较大,不适用于app 需要进行压缩才行,这里我只贴出方法名 ,代码请上翻

featureSelection() takeCameraPhoto() takePictureFromCamera()  
onActivityResult()根据requestCode做出不同的操作判断

正常的按键返回一般是如此

    if (keyCode == KeyEvent.KEYCODE_BACK) {
        if (wv.canGoBack()) {
             wv.goBack();// 返回上一页面
             return true;
        } else {
             finish();
        }
    }

不过我这里因为不想要返回上一页,直接采用的是finish,而且我这里还要调用直接的一些方法

EventBus.getDefault().post(new EventObject(EventConstant.Account, null));

我采用的是eventbus去进行通知,当然也可以采用别的方法,方法很多,可以根据自己的需求来。

在我的需求里还需要跟h5做一些交互,点击h5的按钮调用原生方法

    wv.addJavascriptInterface(new Back(), "Android");//Back为自定义类名

    class Back {
        @JavascriptInterface
        public void back(String msg) {   
            //写你所想要的一些操作
        }
    }

最后再提一个点

Uri contentUri = FileProvider.getUriForFile(this, "***.FileProvider", mTakePhotoFile);

这里的FileProvider是你在AndroidManifest中定义的,一般是包名.FileProvider

别写错了

基本上我认为所有要注意的地方都提供了,代码可以直接copy来用

3、博客新生  写的可能有点乱,还望包含,如果能帮助到你,很开心。

如果有什么问题的话,可以在下面留言

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值