webview 那些事儿

来源:互联网 发布:淘宝关键词搜索量 编辑:程序博客网 时间:2024/05/17 18:42
         快速开发时代,很多原生开发让位于套壳混合开发,webview这个之前没过多关注的控件成了核心,当然webview没想的那么简单,链接一放就完事了?
No!  首先要说下整体的框架,很多的项目都是fragement + webview 实现的 ,比如 首页  菜单  购物车  个人中心  四个   强烈建议还是用一个webview去处理  不要 每个fragement都new一个 webview   不然后期很麻烦的,当然如果加载的url 已经包含有底部导航栏了,那更好。下面开始遇到的问题:
   首先就是对JavaScript的支持了:
 
WebSettings websetting = webview.getSettings();websetting.setJavaScriptEnabled(true);   //与JS交互



  紧接着就是 back返回按键,这里需要重写onkeydown方法了

@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {    if (keyCode == KeyEvent.KEYCODE_BACK && webview.canGoBack()) {        webview.goBack();// 返回前一个页面                return true;    } else {        //提示退出应用        AlertDialog.Builder isExit = new AlertDialog.Builder(this);        //设置对话框标题        isExit.setTitle("应用提醒");        //设置对话框消息        isExit.setMessage("确定要退出吗");        // 添加选择按钮并注册监听        isExit.setPositiveButton("确定", diaListener);  //diaListener 是实例化Dialog的对象                      isExit.setNegativeButton("取消", diaListener);        //对话框显示        isExit.show();     }    return super.onKeyDown(keyCode, event);}


 这个是webview 在activity里的可以直接重写onkeydown方法,但有的webview是在fragement里的 那就需要:

 webview.setOnKeyListener(new View.OnKeyListener() {  @Override  public boolean onKey(View view, int i, KeyEvent keyEvent) {    if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {      if (i == KeyEvent.KEYCODE_BACK && webview.canGoBack()) {        //这里处理返回键事件        Log.d(" FRAGEMENT ","CAN GOBACK = " + webview.canGoBack());        webview_fuwu.goBack();        return true;      }    }    return false;   }  });


当遇到第三方登录 如跳到  支付宝  QQ  微信 等 再按back键时,那么成功进入又一个webview的问题点 重定向问题  ,你back会变成刷新一样,出不去了,这里我是在对webview的重写方法
shouldOverrideUrlLoading

中处理

       @Override        public boolean shouldOverrideUrlLoading(WebView view, String url) {            // TODO Auto-generated method stub             Log.d(TAG, "加载的url==" + url);             //view.loadUrl(url);             return false ;        });

把view.loadUrl(url); 注释掉

有时当反复点击了back键还是没返回,log信息报 UnimplementedWebViewApi: Unimplemented WebView method onKeyDown called from: android.webkit.WebView.onKeyDown(WebView.java:2178)
的,也可以用上面的方法 解决。

对一些加载失败的连接处理时:

@Overridepublic void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {    Log.e("MianActivity", "ERROR == " + errorCode + "--->" + description + "---->" + failingUrl);    //用javascript隐藏系统定义的404页面信息    String data = "";    view.loadUrl("javascript:document.body.innerHTML=\"" + data + "\"");        if (errorCode == -10 && description.equals("net::ERR_UNKNOWN_URL_SCHEME") && failingUrl.equals("****")) {       //也可以截获错误信息在这个做自定义的处理       //    Callphone_showDialog();    } else if (errorCode == -10 && description.equals("net::ERR_UNKNOWN_URL_SCHEME") && failingUrl.equals("***")) {       //自定义处理   }}




webview开发加载的毕竟是网页啊,要是断网了呢,空白啊,所以还要做缓存处理,这个方法在webview的

webview.setWebViewClient(new WebViewClient()之前

/** * 设置webview 缓存 */private void WebView_Set() {    WebSettings websetting = webview.getSettings();    websetting.setJavaScriptEnabled(true);   //与JS交互    websetting.setDomStorageEnabled(true);    //开启DOM形式存储    websetting.setDatabaseEnabled(true);   //开启数据库形式存储    String appCacheDir = this.getDir("cache", Context.MODE_PRIVATE).getPath();   //缓存数据的存储地址    websetting.setAppCachePath(appCacheDir);    websetting.setAppCacheEnabled(true);  //开启缓存功能    websetting.setCacheMode(WebSettings.LOAD_DEFAULT);      //缓存模式    websetting.setAllowFileAccess(true);// 设置允许访问文件数据    websetting.setAppCacheMaxSize(1024 * 1024 * 8);      //设置缓存文件大小}



网上也说缓存模式设置这样:

websetting.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);      //缓存模式

两者的区别为:
LOAD_DEFAULT,根据cache-control决定是否从网络上取数据
LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据
使用LOAD_CACHE_ELSE_NETWORK会出现,比如你加购物车了,但到购物车去看没有的现象

webview除了加载url的setWebViewClient 外还有一个专用辅助方法

webview.setWebChromeClient(new WebChromeClient() {});


用于处理弹框 警示信息 图片 文件选择处理等,  因为js里面的alert  confirm 事件即使有setjavascriptenabled(true) 但仍是不识别的,同样需要在setWebChromeClient里面重写,用android的方法显示:

@Overridepublic boolean onJsAlert(WebView view, String url, String message, JsResult result) {    Log.d(TAG, "url =" + url + "----message=" + message + "-----result==" + result);    final JsResult jr = result;    if (message.contains("*******")) {        // SweetAlertDialog 自定义的一个dialog       SweetAlertDialog sd = new SweetAlertDialog(MainActivity.this, SweetAlertDialog.CUSTOM_IMAGE_TYPE);        sd.setTitleText("***********");        sd.setConfirmText("确定");        sd.setCancelable(false);        sd.setCanceledOnTouchOutside(false);        sd.setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {            @Override            public void onClick(SweetAlertDialog sDialog) {                jr.confirm();                sDialog.dismiss();            }        });        sd.show();    }else {     //处理其他alert事件   }

@Overridepublic boolean onJsConfirm(final WebView view, String url, String message, JsResult result) {    Log.d(TAG, "url =" + url + "----message=" + message + "-----result==" + result);    final JsResult jr = result;    if (message.contains("***********")) {                // SweetAlertDialog 是我自定义的一个dialog                SweetAlertDialog sd = new SweetAlertDialog(MainActivity.this, SweetAlertDialog.WARNING_TYPE);        sd.setTitleText("************?");        // .setContentText("Won't be able to recover this file!")        sd.setCancelText("取消");        sd.setConfirmText("确定");        sd.showCancelButton(true);        sd.setCancelable(false);        sd.setCanceledOnTouchOutside(false);        sd.setCancelClickListener(new SweetAlertDialog.OnSweetClickListener() {            @Override            public void onClick(SweetAlertDialog sDialog) {                // reuse previous dialog instance, keep widget user state, reset them if you need                sDialog.dismiss();                jr.cancel();            }        });        sd.setConfirmClickListener(new SweetAlertDialog.OnSweetClickListener() {            @Override            public void onClick(SweetAlertDialog sDialog) {                jr.confirm();                Toast.makeText(MainActivity.this, "移出成功", Toast.LENGTH_SHORT).show();                sDialog.dismiss();            }        });        sd.show();        return true;    }


对于webview上传文件图片同样在setWebViewChromeClient中写入方法:

//3.0++版本public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {    Log.d(TAG, "3.0++");    openFileChooserImpl(uploadMsg);}//3.0--版本public void openFileChooser(ValueCallback<Uri> uploadMsg) {    Log.d(TAG, "3.0");    openFileChooserImpl(uploadMsg);}public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {    Log.d(TAG, "4.1");    openFileChooserImpl(uploadMsg);}@Overridepublic boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {    Log.d(TAG, "5.0++");    onenFileChooseImpleForAndroid(filePathCallback);    return true;}



android在5.0之后才将webview打开文件图片方法固定,所以会有两个不同的方法,android会自己根据版本选择   下面代码会给出
这里重点说下android4.4版本的上传路径的重新获取和android4.4.4打开文件或图片取消的情况 


getRealPathFromURL( ) 是对选中的图片或文件路径的重新修改,不然上传会卡在哪里,

onActivityResult( )  是当打开文件或图片列表时,用户按back键取消返回时,传入intent 为空,所以将mUploadMessage.onReceiveValue(null)  也赋予null值,才可正常返回,


public ValueCallback<Uri> mUploadMessage;private void openFileChooserImpl(ValueCallback<Uri> uploadMsg) {    mUploadMessage = uploadMsg;    Intent i = new Intent(Intent.ACTION_GET_CONTENT);    i.addCategory(Intent.CATEGORY_OPENABLE);    i.setType("image/*");        startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);}public ValueCallback<Uri[]> mUploadMessageForAndroid5;private void onenFileChooseImpleForAndroid(ValueCallback<Uri[]> filePathCallback) {    mUploadMessageForAndroid5 = filePathCallback;    Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);    contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);    contentSelectionIntent.setType("image/*");    Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);    chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);    chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");    startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE_FOR_ANDROID_5);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent intent) {       if (requestCode == FILECHOOSER_RESULTCODE) {        if (null == mUploadMessage)            return;               if (intent == null) {            Toast.makeText(MainActivity.this, "已取消", Toast.LENGTH_SHORT).show();            mUploadMessage.onReceiveValue(null);            mUploadMessage = null;            return;        }        Log.e(TAG, "requestCode=" + requestCode + "resultCode=" + resultCode + "intent.getdata()==");        if (Build.VERSION.SDK_INT == 19) {            String realPathFromURI = getRealPathFromURI(intent.getData());            File file = new File(realPathFromURI);            if (file.exists()) {                Uri uri = Uri.fromFile(file);                Log.e(TAG, "文件uri-->" + uri);                Toast.makeText(MainActivity.this, "图片上传中...", Toast.LENGTH_SHORT).show();                mUploadMessage.onReceiveValue(uri);            }        }        mUploadMessage = null;    } else if (requestCode == FILECHOOSER_RESULTCODE_FOR_ANDROID_5) {        if (null == mUploadMessageForAndroid5)            return;        Uri result = (intent == null || resultCode != RESULT_OK) ? null : intent.getData();        if (result != null) {            Toast.makeText(MainActivity.this, "图片上传中...", Toast.LENGTH_SHORT).show();            mUploadMessageForAndroid5.onReceiveValue(new Uri[]{result});        } else {            mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});        }        mUploadMessageForAndroid5 = null;    }}public String getRealPathFromURI(Uri contentUri) {    String res = null;    String[] proj = {MediaStore.Images.Media.DATA};    Cursor cursor = MainActivity.this.getContentResolver().query(contentUri, proj, null, null, null);    if (cursor.moveToFirst()) {        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);        res = cursor.getString(column_index);    }    cursor.close();    return res;}



这些都是项目中遇到的吧,不大也不小,记录下来,也希望能帮助到有同样问题的你。



原创粉丝点击