android webview 使用笔迹

         快速开发时代,很多原生开发让位于套壳混合开发,webview这个之前没过多关注的控件成了核心,当然webview没想的那么简单,链接一放就完事了?

No!  首先要说下整体的框架,很多的项目都是fragement + webview 实现的 ,比如 首页  菜单  购物车  个人中心  四个   强烈建议还是用一个webview去处理  不要 每个fragement都new一个 webview   不然后期很麻烦的,当然如果加载的url 已经包含有底部导航栏了,那更好。下面开始遇到的问题:

   首先就是对JavaScript的支持了:

 

WebSettings websetting = webview.getSettings();
websetting.setJavaScriptEnabled(true);   //与JS交互

 

 

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

 

@Override
public 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)

的,也可以用上面的方法 解决。

 

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

 

@Override
public 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的方法显示:

 

@Override
public 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事件
   }

 

@Override
public 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);
}

@Override
public 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);
}

@Override
protected 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;
}

 

 

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

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值