首页投稿(暂停使用,暂停投稿)Android开发

webview 开发常用点介绍

2017-10-10  本文已影响0人  老夫掐指一算z

1.基本适配设置

settings =getSettings();
settings.setJavaScriptEnabled(true);//支持js
settings.setUseWideViewPort(true); 
settings.setLoadWithOverviewMode(true);

2.硬件加速 提高webview加载速度

if (Build.VERSION.SDK_INT >= 21) {
    settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
    setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT >= 19) {
    setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT < 19) {
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

3.设置webview 安全性 一般上传应用会对apk进行安全扫描,有关webview的安全问题,可通过该方法解决

private void setWebViewSecurity(){
    try {
        removeJavascriptInterface("searchBoxJavaBridge_");
        removeJavascriptInterface("accessibility");
        removeJavascriptInterface("accessibilityTraversal");   
        getSettings().setSavePassword(false);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
      } catch (Exception e) {
    }
}

4.支持视频全屏播放方法,重写webChromeClient getVideoLoadingProgressView,onShowCustomView,onHideCustomView
三个方法。
原理是获取视频播放的view 然后创建父类容器view 加载到根view上显示出来

 public class CommonWebChromeClient extends WebChromeClient{
 /*** 视频播放相关的方法 **/
        @Override
        public View getVideoLoadingProgressView() {
            if(videoWebFactory!=null){
                return videoWebFactory.getVideoLoadingProgressView();
            }
            return null;
        }
        @Override
        public void onShowCustomView(View view, CustomViewCallback callback) {
            if(videoWebFactory!=null){
                videoWebFactory.showCustomView(view, callback);
            }
        }
        @Override
        public void onHideCustomView() {
            if(videoWebFactory!=null){
                videoWebFactory.hideCustomView();
            }
        }
}

VideoWebFactory代码

public class VideoWebFactory {
      /** 视频全屏参数 */
    protected static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    private View customView;
    private FrameLayout fullscreenContainer;
    private WebChromeClient.CustomViewCallback customViewCallback;
    private Context context;
    private Window window;
    private WebView webView;
 
    public  VideoWebFactory (Context context,WebView webView){
        this.context =context;
        this.window =  ((Activity)context).getWindow();
        this.webView = webView;
    }
    public View getVideoLoadingProgressView(){
        FrameLayout frameLayout = new FrameLayout(context);
        frameLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        return frameLayout;
    }
    /** 视频播放全屏 **/
    public void showCustomView(View view, CustomViewCallback callback) {
        // if a view already exists then immediately terminate the new one
        if (customView != null) {
            callback.onCustomViewHidden();
            return;
        }
       window.getDecorView();
        FrameLayout decor = (FrameLayout) window.getDecorView();
        fullscreenContainer = new FullscreenHolder(context);
        fullscreenContainer.addView(view, COVER_SCREEN_PARAMS);
        decor.addView(fullscreenContainer, COVER_SCREEN_PARAMS);
        customView = view;
        setStatusBarVisibility(false);
        customViewCallback = callback;
    }
    
    /** 隐藏视频全屏 */
    public void hideCustomView() {
        if (customView == null) {
            return;
        }
        setStatusBarVisibility(true);
        FrameLayout decor = (FrameLayout) window.getDecorView();
        decor.removeView(fullscreenContainer);
        fullscreenContainer = null;
        customView = null;
        customViewCallback.onCustomViewHidden();
        webView.setVisibility(View.VISIBLE);
    }
    /** 全屏容器界面 */
   private static class FullscreenHolder extends FrameLayout {

        public FullscreenHolder(Context ctx) {
            super(ctx);
            setBackgroundColor(ctx.getResources().getColor(android.R.color.black));
        }
        @Override
        public boolean onTouchEvent(MotionEvent evt) {
            return true;
        }
    }
    private void setStatusBarVisibility(boolean visible) {
        int flag = visible ? 0 : WindowManager.LayoutParams.FLAG_FULLSCREEN;
        window.setFlags(flag, WindowManager.LayoutParams.FLAG_FULLSCREEN);
    }
    public View getCustomView() {
        return customView;
    }
}

4.支持文件上传
webview支持file文件上传,不过,对应有版本的区别,5.0以下的版本只能每次选择一个文件,5.0以上的版本支持多文件选择
(1)当触发上传文件选择的时候,webview会回调openFileChooser 方法并提供ValueCallback<Uri> mUM 作为文件上传提交对象(文件选择可以调用相关的库)
(2)最后在选择完文件之后,设置uri 对象,通过mUM.onReceiveValue(uri);进行文件提交。注意,如果没有选择文件,请设置mUM.onReceiveValue(null); 作为取消选择文件的操作,不然,webview将处于文件选择状态,web页面不能点击响应。

 public class CommonWebChromeClient extends WebChromeClient{
/**
         * 文件上传
         * */
        //For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg){
            mUM = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*");
            ((Activity)context).startActivityForResult(Intent.createChooser(i,"File Chooser"), WebFileFactory.SELECT_PHOTO);
        }
        // For Android 3.0+, above method not supported in some android 3+ versions, in such case we use this
        public void openFileChooser(ValueCallback uploadMsg, String acceptType){
            mUM = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*");
            ((Activity)context).startActivityForResult(Intent.createChooser(i, "File Browser"),WebFileFactory.SELECT_PHOTO);
        }
        //For Android 4.1+ 只能选择一个文件
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
            mUM = uploadMsg;
            if(onFileSelected!=null){
                onFileSelected.onSelectOne(mUM,mUMA);
            }
            if(webFileFactory!=null){
                webFileFactory.setmUM(mUM);
                webFileFactory.showPhotoSelectForOne();
            }
        }
       //For Android 5.0+ 多个文件选择
        public boolean onShowFileChooser(
                WebView webView, ValueCallback<Uri[]> filePathCallback,
                WebChromeClient.FileChooserParams fileChooserParams){
            mUMA = filePathCallback;
            if(onFileSelected!=null){
                onFileSelected.onSelect(mUM,mUMA);
            }
            if(webFileFactory!=null){
                webFileFactory.setmUMA(mUMA);
                webFileFactory.showPhotoSelect();
            }
            return true;
}

webFileFactory为 图片选择 处理类

public class WebFileFactory {
    private Context context;
    private ValueCallback<Uri> mUM;
    private ValueCallback<Uri[]> mUMA;
    private Uri uri;
    public static final int TAKE_PICTURE = 102;
    public static final int SELECT_PHOTO = 103;
    public static final int TAKE_VIDEO = 107;
    public static final int SELECT_VIDEO = 106;
    public static final int TAKE_PICTURE_ONE = 104;
    public static final int SELECT_PHOTO_ONE = 105;
    public static final int TAKE_VIDEO_ONE = 108;
    public static final int SELECT_VIDEO_ONE = 109;

    public WebFileFactory(Context context) {
        this.context = context;
    }

    public void setmUM(ValueCallback<Uri> mUM) {
        this.mUM = mUM;
    }

    public void setmUMA(ValueCallback<Uri[]> mUMA) {
        this.mUMA = mUMA;
    }

    public void showPhotoSelectForOne() {
        String[] datas = new String[] { "拍照", "录像", "相册", "视频" };
        SheetView sheetView = new SheetView(context, datas);
        sheetView.setLisenter(new SheetView.Lisenter() {
            @Override
            public void onSelect(int position) {
                if (position == 1) {
                    uri = Uri.fromFile(new File(
                            FileUtils.getAppImageFilePath(context) + "/" + System.currentTimeMillis() + ".png"));
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
                    intent.putExtra("return-data", true);
                    ((Activity) context).startActivityForResult(intent, WebFileFactory.TAKE_PICTURE_ONE);
                } else if (position == 2) {
                    uri = Uri.fromFile(new File(
                            FileUtils.getAppImageFilePath(context) + "/" + System.currentTimeMillis() + ".mp4"));
                    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);// 创建一个请求视频的意图
                    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);// 设置视频的质量,值为0-1,
                    intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 60);// 设置视频的录制长度,s为单位
                    intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 20 * 1024 * 1024L);// 设置视频文件大小,字节为单位
                    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
                    ((Activity) context).startActivityForResult(intent, WebFileFactory.TAKE_VIDEO_ONE);
                } else if (position == 3) {
                    Intent intent = new Intent(context, SelectPhotoActivity.class);
                    intent.putExtra("max", 1);
                    ((Activity) context).startActivityForResult(intent, WebFileFactory.SELECT_PHOTO_ONE);
                } else if (position == 4) {
                    Intent i = new Intent(Intent.ACTION_PICK,
                            android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
                    ((Activity) context).startActivityForResult(i, WebFileFactory.SELECT_VIDEO_ONE);
                }
            }
        });
        sheetView.show();
    }

    public void showPhotoSelect() {
        String[] datas = new String[] { "拍照", "录像", "相册", "视频" };
        SheetView sheetView = new SheetView(context, datas);
        sheetView.setLisenter(new SheetView.Lisenter() {
            @Override
            public void onSelect(int position) {
                if (position == 1) {
                    uri = Uri.fromFile(new File(
                            FileUtils.getAppImageFilePath(context) + "/" + System.currentTimeMillis() + ".png"));
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
                    intent.putExtra("return-data", true);
                    ((Activity) context).startActivityForResult(intent, WebFileFactory.TAKE_PICTURE);
                } else if (position == 2) {
                    uri = Uri.fromFile(new File(
                            FileUtils.getAppImageFilePath(context) + "/" + System.currentTimeMillis() + ".mp4"));
                    Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);// 创建一个请求视频的意图
                    intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);// 设置视频的质量,值为0-1,
                    intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 60);// 设置视频的录制长度,s为单位
                    intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 20 * 1024 * 1024L);// 设置视频文件大小,字节为单位
                    intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, uri);
                    ((Activity) context).startActivityForResult(intent, WebFileFactory.TAKE_VIDEO);
                } else if (position == 3) {
                    Intent intent = new Intent(context, SelectPhotoActivity.class);
                    intent.putExtra("max", 9);
                    ((Activity) context).startActivityForResult(intent, WebFileFactory.SELECT_PHOTO);
                } else if (position == 4) {
                    Intent i = new Intent(Intent.ACTION_PICK,
                            android.provider.MediaStore.Video.Media.EXTERNAL_CONTENT_URI);
                    ((Activity) context).startActivityForResult(i, WebFileFactory.SELECT_VIDEO);
                } else {
                    if (mUMA != null) {
                        mUMA.onReceiveValue(null);
                    } else if (mUM != null) {
                        mUM.onReceiveValue(null);
                    }
                }
            }
        });
        sheetView.show();
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == TAKE_PICTURE_ONE || requestCode == TAKE_VIDEO_ONE) {
            if (uri != null) {
                mUM.onReceiveValue(uri);
            }
        } else if (requestCode == SELECT_PHOTO_ONE) {
            if (data != null) {
                Bundle bundle = data.getBundleExtra("bundle");
                List<PhotoInfo> imgs = bundle.getParcelableArrayList("imgs");
                Uri uri = Uri.parse(imgs.get(0).getPath_file());
                mUM.onReceiveValue(uri);
            } else {
                if (mUMA != null) {
                    mUMA.onReceiveValue(null);
                } else if (mUM != null) {
                    mUM.onReceiveValue(null);
                }
            }
        } else if (requestCode == SELECT_VIDEO_ONE) {
            if (data != null) {
                Uri uri = data.getData();
                Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
                cursor.moveToFirst();
                String path = "file://" + cursor.getString(1); // 视频文件路径
                Uri uri_video = Uri.parse(path);
                mUM.onReceiveValue(uri_video);
            } else {
                if (mUMA != null) {
                    mUMA.onReceiveValue(null);
                } else if (mUM != null) {
                    mUM.onReceiveValue(null);
                }
            }
        }

        if (requestCode == TAKE_PICTURE || requestCode == TAKE_VIDEO) {
            if (uri != null) {
                Uri[] uris = new Uri[] { uri };
                mUMA.onReceiveValue(uris);
            }
        } else if (requestCode == SELECT_PHOTO) {
            if (data != null) {
                Bundle bundle = data.getBundleExtra("bundle");
                List<PhotoInfo> imgs = bundle.getParcelableArrayList("imgs");
                Uri[] uris = new Uri[imgs.size()];
                for (int i = 0; i < imgs.size(); i++) {
                    PhotoInfo photoInfo = imgs.get(i);
                    Uri uri = Uri.parse(photoInfo.getPath_file());
                    uris[i] = uri;
                }
                mUMA.onReceiveValue(uris);
            } else {
                if (mUMA != null) {
                    mUMA.onReceiveValue(null);
                } else if (mUM != null) {
                    mUM.onReceiveValue(null);
                }
            }
        } else if (requestCode == SELECT_VIDEO) {
            if (data != null) {
                Uri uri = data.getData();
                Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
                cursor.moveToFirst();
                String path = "file://" + cursor.getString(1); // 视频文件路径
                Uri uri_video = Uri.parse(path);
                mUMA.onReceiveValue(new Uri[] { uri_video });
            } else {
                if (mUMA != null) {
                    mUMA.onReceiveValue(null);
                } else if (mUM != null) {
                    mUM.onReceiveValue(null);
                }
            }
        }
    }
}

5.附上本人封装的CommonWebView以及使用方式

public class CommonWebView extends WebView{
    private Context context;
    private WebSettings settings;
    private VideoWebFactory videoWebFactory;
    private WebFileFactory webFileFactory;
    private ValueCallback<Uri> mUM;
    private ValueCallback<Uri[]> mUMA;
    private OnFileSelected onFileSelected;
    public CommonWebView(Context context) {
        super(context);
        this.context =context;
        init();
    }
    public CommonWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context =context;
        init();
    }
    public CommonWebView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context =context;
        init();
    }
 
    private void init(){
        //基础设置
        settings =getSettings();
        settings.setJavaScriptEnabled(true);
        settings.setUseWideViewPort(true); // 关键点
        settings.setLoadWithOverviewMode(true);
        if (Build.VERSION.SDK_INT >= 21) {
            settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
            setLayerType(View.LAYER_TYPE_HARDWARE, null);
        } else if (Build.VERSION.SDK_INT >= 19) {
            setLayerType(View.LAYER_TYPE_HARDWARE, null);
        } else if (Build.VERSION.SDK_INT < 19) {
            setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }
        //设置webview安全性
        setWebViewSecurity();
        setWebViewClient();
    }
    
    private void setWebViewClient(){
        setWebViewClient(new CommonWebViewClient());
    }
    //支持视频播放
    public void setSupportVideo(CommonWebChromeClient webChromeClient){
        videoWebFactory = new VideoWebFactory(context,this);
        setWebChromeClient(webChromeClient);
    }
    //文件上传
    public CommonWebView setSupportFile(CommonWebChromeClient webChromeClient){
        webFileFactory = new WebFileFactory(context);
        settings.setAllowFileAccess(true);
        setSupportVideo(webChromeClient);
        return this;
    }
   public void setOnFileSelected(OnFileSelected onFileSelected) {
       this.onFileSelected = onFileSelected;
   }
   public WebFileFactory getWebFileFactory() {
       return webFileFactory;
   }
   public class CommonWebViewClient extends WebViewClient{
       @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
             loadUrl(url);
            return true;
        }
   }
   
   public class CommonWebChromeClient extends WebChromeClient{
       /*** 视频播放相关的方法 **/
        @Override
        public View getVideoLoadingProgressView() {
            if(videoWebFactory!=null){
                return videoWebFactory.getVideoLoadingProgressView();
            }
            return null;
        }
        @Override
        public void onShowCustomView(View view, CustomViewCallback callback) {
            if(videoWebFactory!=null){
                videoWebFactory.showCustomView(view, callback);
            }
        }
        @Override
        public void onHideCustomView() {
            if(videoWebFactory!=null){
                videoWebFactory.hideCustomView();
            }
        }
        /**
         * 文件上传
         * */
        //For Android 3.0+
        public void openFileChooser(ValueCallback<Uri> uploadMsg){
            mUM = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*");
            ((Activity)context).startActivityForResult(Intent.createChooser(i,"File Chooser"), WebFileFactory.SELECT_PHOTO);
        }
        // For Android 3.0+, above method not supported in some android 3+ versions, in such case we use this
        public void openFileChooser(ValueCallback uploadMsg, String acceptType){
            mUM = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*");
            ((Activity)context).startActivityForResult(Intent.createChooser(i, "File Browser"),WebFileFactory.SELECT_PHOTO);
        }
        //For Android 4.1+ 只能选择一个文件
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture){
            mUM = uploadMsg;
            if(onFileSelected!=null){
                onFileSelected.onSelectOne(mUM,mUMA);
            }
            if(webFileFactory!=null){
                webFileFactory.setmUM(mUM);
                webFileFactory.showPhotoSelectForOne();
            }
        }
       //For Android 5.0+ 多个文件选择
        public boolean onShowFileChooser(
                WebView webView, ValueCallback<Uri[]> filePathCallback,
                WebChromeClient.FileChooserParams fileChooserParams){
            mUMA = filePathCallback;
            if(onFileSelected!=null){
                onFileSelected.onSelect(mUM,mUMA);
            }
            if(webFileFactory!=null){
                webFileFactory.setmUMA(mUMA);
                webFileFactory.showPhotoSelect();
            }
            return true;
        }
   } 
    /**
     * 设置webview安全性
     */
    private void setWebViewSecurity(){
        try {
            removeJavascriptInterface("searchBoxJavaBridge_");
            removeJavascriptInterface("accessibility");
            removeJavascriptInterface("accessibilityTraversal");   
            getSettings().setSavePassword(false);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
            }
        } catch (Exception e) {
        }
    }
    
    public interface OnFileSelected{
        void onSelectOne(ValueCallback<Uri> mUM,   ValueCallback<Uri[]> mUMA);
        void onSelect(ValueCallback<Uri> mUM,   ValueCallback<Uri[]> mUMA);
    }
}
支持视频播放
webView.setSupportVideo(webView.new CommonWebChromeClient());
支持文件上传
webView.setSupportFile(wbw_web.new CommonWebChromeClient());
上一篇下一篇

猜你喜欢

热点阅读