美文网首页
从集成Scratch来踩webview的坑

从集成Scratch来踩webview的坑

作者: 苏联老斯基 | 来源:发表于2021-02-11 14:12 被阅读0次

    大家好,我是一个默默无闻的小Android搬运工。
    最近,领导问我,小伙子忙不忙啊,公司要做幼儿编程,你准备一下吧。
    我说怎么回事,领导给我发了个编程猫APP,就按照这个做。
    我一看,哦,以前没研究过啊,这是什么鬼,然后前端小伙伴给了我一个本地HTML代码,我一看,so easy啊,这不就是webview加载本地HTML么,5分钟就能结束。
    说做就做,小代码咔咔一写

    webview.loadurl("file:///android_asset/html/index.html")
    很快啊,啪,项目运行起来了,点一点,诶,能点,看来可以了,再点一点,诶,这个保存怎么没反应,这个打开文件怎么没反应
    这就让我这个CV工程师脸没处放了,那必须得解决了,一步一步来

    1.保存文件->下载blob类型文件

    [img]http://chuantu.xyz/t6/741/1613038816x2073530471.png
    -配置webview

          webSettings.defaultTextEncodingName = "utf-8"    //设置编码
          webSettings.cacheMode = WebSettings.LOAD_DEFAULT  //设置缓存策略
          webSettings.javaScriptEnabled = true  //启用js(重要)
          webSettings.loadWithOverviewMode = true  //是否使用概览模式
          webSettings.useWideViewPort = true  //设置屏幕自适应
    

    -添加下载回调

    web.setDownloadListener { url, userAgent, contentDisposition, mimetype, contentLength ->
                //下载代码
            }
    

    此回调会返回下载url
    -注入js代码(重头戏,)
    首先js代码

      request.open('GET', '" + url + "', true);
      request.setRequestHeader('Content-type', 'text/plain');
      request.responseType = 'blob';
      request.onload = function (e) {
           if (this.status === 200) {
                   var blobFile = this.response;
                   var reader = new FileReader();
                   reader.readAsDataURL(blobFile);
                   reader.onloadend = function() {
                   var base64data = reader.result;
                   window.java.down(base64data);
                   }
               }
      };
      request.send();
    

    只需要把url传进去就好了
    完整代码

    val blob = "  var request = new XMLHttpRequest();" +
                        "        request.open('GET', '" + url + "', true);" +
                        "        request.setRequestHeader('Content-type', 'text/plain');" +
                        "        request.responseType = 'blob';" +
                        "        request.onload = function (e) {" +
                        "            if (this.status === 200) {" +
                        "                var blobFile = this.response;" +
                        "                var reader = new FileReader();" +
                        "                reader.readAsDataURL(blobFile);" +
                        "                reader.onloadend = function() {" +
                        "                var base64data = reader.result;" +
                        "                window.java.down(base64data);" +
                        "                }" +
                        "             }" +
                        "        };" +
                        "        request.send();"
    val js = "javascript:$blob"
    web.evaluateJavascript(js,null)    //注入js代码并执行
    
    web.addJavascriptInterface(object : Any() {
                @JavascriptInterface
                fun down(base64: String?) {
                      //得到下载的base64字符串,需自行转换
                }
            }, "java")
    

    2.上传文件,打开文件管理器

    webview配置如上
    -重写WebChromeClient

    class ZpWebChromeClient : WebChromeClient() {
        private var mOpenFileChooserCallBack: OpenFileChooserCallBack? = null
    
        //For Android 3.0 - 4.0
        // For Android < 3.0
        @JvmOverloads
        fun openFileChooser(uploadMsg: ValueCallback<Uri>, acceptType: String = "") {
            if (mOpenFileChooserCallBack != null) {
                mOpenFileChooserCallBack!!.openFileChooserCallBack(uploadMsg, acceptType)
            }
        }
    
        // For Android 4.0 - 5.0
        fun openFileChooser(uploadMsg: ValueCallback<Uri>, acceptType: String, capture: String) {
            openFileChooser(uploadMsg, acceptType)
        }
    
        override fun onConsoleMessage(cm: ConsoleMessage?): Boolean {
            println(("JavaScript log, " + cm!!.sourceId() + ":" + cm.lineNumber() + ", " + cm.message()))
            return true
        }
    
        // For Android > 5.0
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        override fun onShowFileChooser(webView: WebView, filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams): Boolean {
            if (mOpenFileChooserCallBack != null) {
                mOpenFileChooserCallBack!!.showFileChooserCallBack(filePathCallback, fileChooserParams)
            }
            return true
        }
    
        fun setOpenFileChooserCallBack(callBack: OpenFileChooserCallBack?) {
            mOpenFileChooserCallBack = callBack
        }
    
        override fun onProgressChanged(view: WebView, newProgress: Int) {
            super.onProgressChanged(view, newProgress)
        }
    
        interface OpenFileChooserCallBack {
            fun openFileChooserCallBack(uploadMsg: ValueCallback<Uri>, acceptType: String)    //打开文件选择回调
            fun showFileChooserCallBack(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams)    //选择文件回调
        }
    

    Activity实现ZpWebChromeClient.OpenFileChooserCallBack并设置webview.setwebChromeClient,然后自行处理文件选择就可,别忘了在onActivityResult获取回调

    调用手机摄像头

    此处就比较简单了,js配置依旧如上
    在自定义WebChromeClient中添加onPermissionRequest,然后activity中会调用增加拦截权限代码

    /* access modifiers changed from: private */
        fun requestCameraPermissions(permissionRequest2: PermissionRequest) {
            mViewModel.permissionRequest = permissionRequest2
            val arrayList = ArrayList<Any>()
            for (str in permissionRequest2.resources) {
                if (str == "android.webkit.resource.VIDEO_CAPTURE" && ContextCompat.checkSelfPermission(
                                this,
                                mViewModel.ANDROID_PERMISSION_CAMERA
                        ) != 0
                ) {
                    arrayList.add(mViewModel.ANDROID_PERMISSION_CAMERA)
                }
                if (str == "android.webkit.resource.AUDIO_CAPTURE" && ContextCompat.checkSelfPermission(
                                this,
                                mViewModel.ANDROID_PERMISSION_RECORD_AUDIO
                        ) != 0
                ) {
                    arrayList.add(mViewModel.ANDROID_PERMISSION_RECORD_AUDIO)
                }
            }
            if (!arrayList.isEmpty()) {
                ActivityCompat.requestPermissions(
                        this,
                        (arrayList.toArray(arrayOfNulls<String>(arrayList.size)) as Array<String?>),
                        2
                )
            } else {
                grantPermission()
            }
        }
    
        private fun grantPermission() {
            val permissionRequest2: PermissionRequest =
                    mViewModel.permissionRequest as PermissionRequest
            permissionRequest2.grant(permissionRequest2.resources)
            mViewModel.permissionRequest = null
        }
    

    此段代码即可调用摄像头

    手动向webview添加header信息

    虽然现在webview支持自动添加头部信息,但是,拦不住特殊需求啊,产品非要略过登录直接到下一步,没得办法只能手动添加header了。
    -依旧是启用js
    -注入js
    在WebViewClient的onPageFinished方法中添加js代码

    val key = "pro__Access-Token"
    val js = "window.localStorage.setItem('$key','${
          mViewModel.local(let {
                 PreferenceUtils.getString(
                       this@WriteActivity,
                       "token"
                 )
            } as String)
           }');"
    view.evaluateJavascript(js) { value: String ->
    println(
             "localStorage:$value"
             )
    }
    

    需要注意的是,代码中的key值和value值需要和前端沟通,规定好要什么给什么

    到这里遇到的坑就暂时填上了,等到遇到了再研究

    源码地址,由于涉及公司项目所以不增加html页面

    相关文章

      网友评论

          本文标题:从集成Scratch来踩webview的坑

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