精华内容
下载资源
问答
  • webview
    千次阅读
    2022-03-09 13:41:12

    Android WebView 的相关设置

    settings相关设置

     webView.settings.apply {
                //开启js
                javaScriptEnabled = true
                //弹出框的设置
                //1.NARROW_COLUMNS:可能的话使所有列的宽度不超过屏幕宽度
                //2.NORMAL:正常显示不做任何渲染
                //3.SINGLE_COLUMN:把所有内容放大webview等宽的一列中
                layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS
                //它会使用网页元标记中定义的属性加载WebView。因此它按照html中的定义缩放网页。
                useWideViewPort = true
    
                /************ 缓存模式 **********/
                //保存密码
                savePassword = true
                //保存表单数据
                saveFormData = true
                //开启数据库
                databaseEnabled = true
                //设置DOM Storage缓存
                domStorageEnabled = true
                //关闭webView中缓存
                cacheMode = WebSettings.LOAD_NO_CACHE
                //设置缓存路径
                setAppCachePath(cacheDir.absolutePath)
    
                /************ 页面自动适配 **********/
                //步骤1.隐藏webview缩放按钮
                displayZoomControls = true
    
                //步骤2 设置页面布局
                //1)方式一,控制页面布局,有一定缺陷可能导致页面显示温度,不推荐
                layoutAlgorithm = WebSettings.LayoutAlgorithm.SINGLE_COLUMN
    
                //2)方式二,自动根据手机分辨率缩放,推荐
                useWideViewPort = true
                loadWithOverviewMode = true
    
                /************ 页面缩放支持 **********/
                //仅支持双击缩放,不支持触摸缩放(android4.0)
                setSupportZoom(true)
                //设置支持缩放,设置了此属性,setSupportZoom(true);也默认设置为true
                builtInZoomControls = true
    
                /************ 图片加载 **********/
                //默认为false,true表示阻塞图片请求
                blockNetworkImage = true
                //支持自动加载图片
                loadsImagesAutomatically = true
    
                /************ 字体相关 **********/
                //设置WebView标准字体库字体,默认字体“sans-serif”。
                standardFontFamily = ""
                //设置WebView字体最小值,默认值8,取值1到72
                minimumFontSize = 8
                //设定编码格式
                defaultTextEncodingName = "UTF-8"
                //设置在WebView内部是否允许访问文件
                allowFileAccess = true
                //设置WebView中加载页面字体变焦百分比,默认100,整型数。
                textZoom = 100
    
                /************ 插件相关 **********/
                //支持插件
                pluginState = WebSettings.PluginState.ON
                setRenderPriority(WebSettings.RenderPriority.HIGH)
                //多窗口
                supportMultipleWindows()
                //当webview调用requestFocus时为webview设置节点 webview
                setNeedInitialFocus(true)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    //设置Web调试
                    WebView.setWebContentsDebuggingEnabled(true)
    
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        //解决加载Https和Http混合模式网页加载问题
                        mixedContentMode = WebSettings.LOAD_NORMAL
                    }
    
                }
                //追加自定义标识符,一定要+=
                userAgentString += "/native_$packageName"
            }
    
    

    WebClient相关设置

    		//webView相关事件触发,就会通过webViewClient 中的方法回调通知
              webView.webViewClient = object: WebViewClient(){
    
                override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                    super.onPageStarted(view, url, favicon)
                    Log.i("webViewClient" , "页面开始加载")
                }
    
                override fun onPageFinished(view: WebView?, url: String?) {
                    super.onPageFinished(view, url)
                    Log.i("webViewClient" , "页面加载完成回调")
                }
    
                override fun onLoadResource(view: WebView?, url: String?) {
                    super.onLoadResource(view, url)
                    Log.i("webViewClient" , "加载Url资源回调")
                }
    
                override fun onReceivedError(
                    view: WebView?,
                    request: WebResourceRequest?,
                    error: WebResourceError?
                ) {
                    super.onReceivedError(view, request, error)
                    Log.i("webViewClient" , "访问地址错误回调")
                }
    
                override fun onReceivedSslError(
                    view: WebView?,
                    handler: SslErrorHandler?,
                    error: SslError?
                ) {
                    super.onReceivedSslError(view, handler, error)
                    Log.i("webViewClient" , "加载SSl错误回调")
                }
    
            }
    
           
    

    webChromeClient 相关设置

     //当影响浏览器的事件到来时,就会通过WebChromeClient中的方法回调通知用法。
            webView.webChromeClient = object : WebChromeClient(){
                override fun onJsAlert(
                    view: WebView?,
                    url: String?,
                    message: String?,
                    result: JsResult?
                ): Boolean {
                    Log.i("webChromeClient" , "当网页调用alert()来弹出alert弹出框前回调,用以拦截alert()函数")
                    return super.onJsAlert(view, url, message, result)
                }
    
                override fun onJsConfirm(
                    view: WebView?,
                    url: String?,
                    message: String?,
                    result: JsResult?
                ): Boolean {
                    Log.i("webChromeClient" , "当网页调用confirm()来弹出confirm弹出框前回调,用以拦截confirm()函数")
                    return super.onJsConfirm(view, url, message, result)
                }
    
                override fun onJsPrompt(
                    view: WebView?,
                    url: String?,
                    message: String?,
                    defaultValue: String?,
                    result: JsPromptResult?
                ): Boolean {
                    Log.i("webChromeClient" , "当网页调用prompt()来弹出prompt弹出框前回调,用以拦截prompt()函数")
                    return super.onJsPrompt(view, url, message, defaultValue, result)
                }
    
                override fun onReceivedTitle(view: WebView?, title: String?) {
                    Log.i("webChromeClient" , "网页的title回调")
                    super.onReceivedTitle(view, title)
                }
    
                override fun onReceivedIcon(view: WebView?, icon: Bitmap?) {
                    Log.i("webChromeClient" , "网页的icon回调")
                    super.onReceivedIcon(view, icon)
                }
    
                override fun onShowFileChooser(
                    webView: WebView?,
                    filePathCallback: ValueCallback<Array<Uri>>?,
                    fileChooserParams: FileChooserParams?
                ): Boolean {
                    Log.i("webChromeClient" , "文件选择回调")
                    return super.onShowFileChooser(webView, filePathCallback, fileChooserParams)
                }
    
                override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean {
                    Log.i("webChromeClient" , "打印 console 信息")
                    return super.onConsoleMessage(consoleMessage)
                }
    
                override fun onProgressChanged(view: WebView?, newProgress: Int) {
                    super.onProgressChanged(view, newProgress)
                    Log.i("webChromeClient" , "通知程序当前页面加载进度")
                }
            }
    
    更多相关内容
  • uniapp 使用webView通讯

    2022-04-04 03:54:31
    uniapp 使用webView通讯
  • 网页浏览 一个用于C / C ++ / Golang的微型跨平台Webview库,用于构建现代的跨平台GUI。 此外,还有, , , , 和。 该项目的目标是为使用最广泛的平台创建一个通用HTML5 UI抽象层。 它支持双向JavaScript绑定(从C...
  • 带google包名的可以下载 google system webview覆盖安装,可以略过 此文件包含 arm和arm64的webview这是AOSP Webview, 包名com.android.webview, 不带google的 带google包名的可以下载 google system webview覆盖...
  • WebView2Loader.dll 包含 x86 x64 Rad Studio 使用
  • 3D WebView for Windows and macOS Web Browser 3.14.1
  • Android webview版本替换
  • android webview 版本69.0

    2018-12-25 11:31:28
    这是AOSP的webview,包名com.android.webview,不是google的webview
  • 其中之一就是小程序不能向内置的webview实时传参,因为只能通过url地址首次传递数过去。官方不开放接口看起来无可奈何。 但是世上无难事儿,只怕有心人,作为一个合格的程序员就应该是一个有心人。
  • com.google.android.webview

    2017-02-27 21:43:10
    android system webview 适配系统>=5.0
  • webview获取html源码

    2015-08-23 21:27:56
    webview获取html源码,解析xml,完成 html和webview的交互。
  • Android之深入WebView

    千次阅读 2022-03-08 17:36:46
    WebView 目录 思维导图 WebView 的基本使用 WebView WebSettings WebViewClient WebChromeClient WebView 与 JS 交互 Android 去调用 JS 代码 JS 调用 Android 代码 WebView 常见问题汇总 WebView 优化 参考 ...

    WebView

    目录

    1. 思维导图
    2. WebView 的基本使用
      • WebView
      • WebSettings
      • WebViewClient
      • WebChromeClient
    3. WebView 与 JS 交互
      • Android 去调用 JS 代码
      • JS 调用 Android 代码
    4. WebView 常见问题汇总
    5. WebView 优化
    6. 参考

    思维导图

    在这里插入图片描述

    基本使用

    WebView 是一个基于 webkit 引擎,展示 web 页面的空间。WebView 在低版本和高版本采用了不同的 webkit 内核版本,4.4 ( API 19 ) 之后直接使用了 Chrome。

    WebView 类
        /**
         * 返回键后退网页
         * 如果又重写了 onBackPressed 方法,只会回调 onKeyDown
         */
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) {
                mWebView.goBack();
                return true;
            }
            return super.onKeyDown(keyCode, event);
        }
    	mWebView.onPasue();
        //清除缓存数据
        mWebView.clearCache(true);	//清除缓存
        mWebView.clearHistory();	//清除浏览记录
        mWebView.clearFormData();	//清除自动填充的表单数据
    
    WebSetting 类

    对 WebView 进行配置和管理。

        private void setWebViewSettings(WebView webView){
            WebSettings webSettings=webView.getSettings();
            webSettings.setJavaScriptEnabled(true); //支持 JS
            webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过 JS 打开新的窗口
            //设置自适应屏幕
            webSettings.setUseWideViewPort(true);
            webSettings.setLoadWithOverviewMode(true);
    
            webSettings.setLoadsImagesAutomatically(true);  //设置自动加载图片
            webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);    //不使用缓存
    		//...
        }
    
    WebViewClient 类

    处理各种通知和请求事件等等。

    //在当前 WebView 打开页面,而不是系统浏览器
    //如果不需要转发处理,只需要传递一个 WebViewClent 实例,根本不需要重写 shouldOverrideUrlLoading 方法     
    public class MyWebViewClient extends WebViewClient {
    
        private Context mContext;
    
        public MyWebViewClient(Context context) {
            mContext = context;
        }
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            //当前 WebView 处理
            if (request.getUrl().getHost().equals("https://www.example.com")) {
                return false;
            }
            //如果需要转发处理
            mContext.startActivity(new Intent(Intent.ACTION_VIEW, request.getUrl()));
            return true;
        }
    
        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
            switch (error.getErrorCode()){
                case WebViewClient.ERROR_CONNECT:   //连接失败
                    view.loadUrl("file:///android_asset/error.html");
                    break;
            }
        }
    
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
            handler.proceed();  //等待证书响应 
            //handler.cancel();   //挂起连接 默认行为
        }
    }
    
    //使用WebViewClient
    mWebView.setWebViewClient(new MyWebViewClient(MainActivity.this));
    
    WebChromeClient 类

    辅助 WebView 处理 JS 的对话框、网站标题等等。

    public class MyWebChromeClient extends WebChromeClient {
    
        /**
         * 网页加载进度
         */
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            super.onProgressChanged(view, newProgress);
        }
    
        /**
         * 网页标题加载完毕回调
         */
        @Override
        public void onReceivedTitle(WebView view, String title) {
            super.onReceivedTitle(view, title);
        }
    
        /**
         * 拦截输入框
         */
        @Override
        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
            return super.onJsPrompt(view, url, message, defaultValue, result);
        }
    
        /**
         * 拦截确认框
         */
        @Override
        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
            return super.onJsConfirm(view, url, message, result);
        }
    
        /**
         * 拦截弹框
         */
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
            return super.onJsAlert(view, url, message, result);
        }
    }
    
    //使用WebChromeClient 
    mWebView.setWebChromeClient(new MyWebChromeClient());
    

    WebView 与 JS 交互

    WebView 与 JS 交互分为俩种情况,一种是JS 调用 Android 代码,另一种是JS 调用 Android 方法。

    Android 调用 JS 代码
    • webView.loadUrl(url)
    • webView.evaluateJavascript()

    首先选准备一个静态文件:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Title</title>
        <script>
       function callJS(){
          alert("Android调用了 JS 的 callJS() 方法");
       }
        </script>
        <p3>
            WebView 与 JS 交互!
        </p3>
    </head>
    </html>
    

    第一种方式:loadUrl()

            mWebView.loadUrl("javascript:callJS()");
            mWebView.setWebChromeClient(new WebChromeClient(){
                @Override
                public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
                    AlertDialog dialog=new AlertDialog.Builder(WebViewContactActivity.this)
                            .setTitle("Title")
                            .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    result.confirm();
                                }
                            })
                            .setCancelable(false)
                            .setMessage(message)
                            .create();
                    dialog.show();
                    return true;
                }
            });
    

    可以看到,WebView 只是载体,内容的渲染还的通过 WebChromeClient 承载。

    第二种方式:evaluateJavascript()

            mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
                @Override
                public void onReceiveValue(String value) {
                    //JS 返回的结果
                    Toast.makeText(WebViewContactActivity.this, "value " + value, Toast.LENGTH_SHORT).show();
                }
            });
    

    只是把上面的 loadUrl 换成 evaluateJavascript 方法而已。但是这种方法比第一种方式效率高,因为该方法的执行不会使页面刷新。

    两种方法的对比:

    调用方式优点缺点使用场景
    loadUrl方便简洁效率低不需要获取返回值,对性能要求较低时
    evaluatedJavascript效率高向下兼容性差( API > 19 )API > 19

    当然也可以通过 Build.VERSION 来进行判断执行。

    JS 调用 Android 代码
    • 通过 WebView.addJavascriptInterface 进行对象映射
    • 通过 WebViewClient.shouldOverrideUrlLoading 方法回调拦截 url
    • 通过 WebChromeClient 的 onJsAlert、onJsConfirm、onJsPrompt 方法回调拦截 JS 对话框 alert、confirm、prompt 消息

    第一种方式:WebView.addJavascriptInterface 进行对象映射

    首先先准备好资源文件,用于模拟 WebView 加载的网页:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Demo</title>
        <script>
             function callAndroid(){
                test.hello("js调用了android中的hello方法");
             }
          </script>
    </head>
    <body>
    <p2>JS 调用 Android 方法</p2>
    <button type="button" id="button1" onclick="callAndroid()">点击按钮调用 Android 的 hello 方法</button>
    </body>
    </html>
    

    然后定义一个 JS 对象映射关系的 Android 类:

    public class JSObject extends Object {
    
        private Context mContext;
    
        public JSObject(Context context) {
            mContext = context;
        }
    
        @JavascriptInterface
        public void hello(String msg){
            Toast.makeText(mContext, "JS 调用了 Android 的 hello 方法", Toast.LENGTH_SHORT).show();
        }
    }
    

    最后就是通过 WebView 设置 Android 类与 JS 代码的映射:

    mWebView.loadUrl("file:///android_asset/js_to_android.html");
    mWebView.addJavascriptInterface(new JSObject(this),"test");
    

    第二种方式:WebViewClient.shouldOverrideUrlLoading 方法回调拦截 url

    Android 通过 WebViewClient 的回调方法 shouldOverrideUrlLoading 拦截 url,解析该 url 协议,如果检测到是预先约定好的协议,就调用 Android 相应的方法。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Demo</title>
        <script>
             function callAndroid(){
                document.location = "js://webview?arg1=2333&arg2=222";
             }
          </script>
    </head>
    <body>
    <p2>JS 调用 Android 方法</p2>
    <button type="button" id="button1" onclick="callAndroid()">点击按钮调用 Android 的方法</button>
    </body>
    </html>
    
    mWebView.loadUrl("file:///android_asset/js_call_android.html");
            mWebView.setWebViewClient(new WebViewClient(){
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                    if ("js".equals(request.getUrl().getScheme())){
                        if ("webview".equals(request.getUrl().getAuthority())){
                            Toast.makeText(WebViewContactActivity.this, "JS 调用 Android 方法,参数一为:"+request.getUrl().getQueryParameter("arg1"), Toast.LENGTH_SHORT).show();
                        }
                        return true;
                    }
                    return super.shouldOverrideUrlLoading(view, request);
                }
            });
    

    第三种方式:通过 WebChromeClient 的 onJsAlert、onJsConfirm、onJsPrompt 方法回调拦截 JS 对话框的消息

    这里只示例 onJsPrompt 的回调,因为这个方法可以返回任意类型的值。

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Demo</title>
        <script>
             function callAndroid(){
                var result=prompt("js://demo?arg1=111&arg2=222");
                alert("demo " + result);
             }
          </script>
    </head>
    <body>
    <p2>JS 调用 Android 方法</p2>
    <button type="button" id="button1" onclick="callAndroid()">点击按钮调用 Android 的方法</button>
    </body>
    </html>
    
           mWebView.loadUrl("file:///android_asset/js_call_android_demo.html");
            mWebView.setWebChromeClient(new WebChromeClient(){
                @Override
                public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                    Uri uri=Uri.parse(message);
                    if ("js".equals(uri.getScheme())){
                        if ("demo".equals(uri.getAuthority())){
                            result.confirm("JS 调用了 Android 的方法");
                        }
                        return true;
                    }
                    return super.onJsPrompt(view, url, message, defaultValue, result);
                }
            });
    

    三种方式的比较:

    调用方式优点缺点使用场景
    WebView.addJavascriptInterface 对象映射方便简洁Android 4.2 一下存在漏洞Android 4.2 以上相对简单的应用场景
    WebViewClient.shouldOverrideUrlLoading 回调拦截不存在漏洞使用复杂,需要协议约束不需要返回值情况下
    WebChormeClient.onJsAlert / onJsConfirm / onJsPrompt 方法回调拦截不存在漏洞使用复杂,需要协议约束能满足大多数场景

    WebView 常见问题

    1. WebView 销毁

          @Override
          protected void onDestroy() {
              super.onDestroy();
              if (mWebView != null) {
                  mWebView.loadDataWithBaseURL("", null, "text/html", "utf-8", null);
                  mWebView.clearHistory();
                  ((ViewGroup) mWebView.getParent()).removeView(mWebView);
                  mWebView.destroy();
                  mWebView = null;
              }
          }
      
    2. Android P 阻止加载任何 http 的请求

      Mainfest 中加入:

      android:usesCleartextTraffic="true"
      
    3. Android 5.0 之后 WebView 禁止加载 http 与 https 混合内容

      if (Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP){
                mWebView.getSettings().
                    setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
              }
      
    4. WebView 开启硬件加速导致的问题

      比如不能打开 PDF,播放视频花屏等等。

      关闭硬件加速,或者直接用第三方库吧。

    WebView 优化

    1. 给 WebView 加一个加载进度条

      重写 WebChromeClient 的 onProgressChanged 方法。

    2. 提高 HTML 网页加载速度,等页面 finsh 在加载图片

      public void int () {
          if(Build.VERSION.SDK_INT >= 19) {
              webView.getSettings().setLoadsImagesAutomatically(true);
          } else {
              webView.getSettings().setLoadsImagesAutomatically(false);
          }
      }
      
    3. 自定义 WebView 错误页面

      重写 WebViewClient 的 onReceivedError 方法。

    参考

    大牛总结的非常到位,非常值得学习和借鉴。https://www.jianshu.com/p/b9164500d3fb

    展开全文
  • 一、WebView面临的问题: 1、WebView导致的内存泄漏问题,及后续引起的OOM问题。 2、Android版本不同,采用了不同的内核,兼容性Crash。 3、WebView代码质量,WebView和Native版本不一致,导致Crash。 二、...

    一、Android WebView开发(一):基础应用
    二、Android WebView开发(二):WebView与Native交互
    三、Android WebView开发(三):WebView性能优化
    四、Android WebView开发(四):WebView独立进程解决方案
    五、Android WebView开发(五):自定义WebView工具栏

    附GitHub源码:WebViewExplore


    一、WebView面临的问题:

    1、WebView导致的内存泄漏问题,及后续引起的OOM问题。

    2、Android版本不同,采用了不同的内核,兼容性Crash。

    3、WebView代码质量,WebView和Native版本不一致,导致Crash。

    二、WebView独立进程的实现:

    WebView独立进程的实现比较简单,只需要在AndroidManifest中找到对应的WebViewActivity,对其配置"android: process"属性即可。如下:

      <!--独立进程WebViewActivity-->
      <activity
          android:name=".SingleProcessActivity"
          android:configChanges="orientation|keyboardHidden|screenSize"
          android:process=":remoteWeb" />

    我们可以通过 adb shell ps|grep com.hongri.webview 指令查看验证,添加独立进程前后的对进程的打印情况:

     可以看到已经在主进程的基础上,新生成了一个remoteWeb独立进程。

    有两个进程就必然会涉及到进程间的通信,所以最终涉及到的交互及通信包括:

    前端与Native端、独立进程与主进程间的通信。

    后面会通过下面的demo逐个介绍,如下图独立进程中的SingleProcessActivity页面加载了一个本地的html前端页面,页面包含两个按钮,点击后分别最终会调用主进程的showToast方法doCalculate方法,从而实现前端及进程间的交互。

    1、前端与Native端的交互:

    [可参考:二、WebView与Native的交互]

    (1)、注册JS映射接口,并实现:

    加载本地的一个remote_web.html文件:

    public static final String CONTENT_SCHEME = "file:///android_asset/remote/remote_web.html";
    //允许js交互
    webSettings.setJavaScriptEnabled(true);
    JsRemoteInterface remoteInterface = new JsRemoteInterface();
    remoteInterface.setListener(this);
    //注册JS交互接口
    mWebView.addJavascriptInterface(remoteInterface, "webview");
    mWebView.loadUrl(CONTENT_SCHEME);

     其中 JsRemoteInterface 为对应的前端交互映射类,源码如下:

    /**
     * Create by zhongyao on 2021/12/14
     * Description: 前端交互映射类
     */
    public class JsRemoteInterface {
    
        private static final String TAG = "JsRemoteInterface";
        private final Handler mHandler = new Handler();
        private IRemoteListener listener;
    
        /**
         * 前端调用方法
         * @param cmd
         * @param param
         */
        @JavascriptInterface
        public void post(final String cmd, final String param) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (listener != null) {
                        try {
                            listener.post(cmd, param);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
    
        public void setListener(IRemoteListener remoteListener) {
            listener = remoteListener;
        }
    }
    

    (2)、前端关键代码实现:

    • remote_web.html:
    </script>
    <div class="item" style="font-size: 18px; color: #ffffff" onclick="callAppToast()">调用: showToast</div>
    <div class="item" style="font-size: 18px; color: #ffffff" onclick="callCalculate()">调用: appCalculate</div>
    <script src="remote_web.js" charset="utf-8"></script>
    <script>
        function callAppToast() {
            dj.post("showToast", {message: "this is action from html"});
        }
    
        function callCalculate() {
            dj.postWithCallback("appCalculate", {firstNum: "1", secondNum: "2"}, function(res) {
                dj.post("showToast", {message: JSON.stringify(res)});
            });
        }
    </script>
    • remote_web.js: 
    dj.post = function(cmd,para){
        if(dj.os.isIOS){
            var message = {};
            message.meta = {
                cmd:cmd
            };
            message.para = para || {};
            window.webview.post(message);
        }else if(window.dj.os.isAndroid){
            window.webview.post(cmd,JSON.stringify(para));
        }
    };
    dj.postWithCallback = function(cmd,para,callback,ud){
        var callbackname = dj.callbackname();
        dj.addCallback(callbackname,callback,ud);
        if(dj.os.isIOS){
            var message = {};
            message.meta  = {
                cmd:cmd,
                callback:callbackname
            };
            message.para = para;
            window.webview.post(message);
        }else if(window.dj.os.isAndroid){
            para.callback = callbackname;
            window.webview.post(cmd,JSON.stringify(para));
        }
    };

    2、独立进程与主进程的交互:

    (1)、定义一个AIDL文件 CalculateInterface:

    并将暴露给其他进程的方法在该文件中声明,如下图:

    需要注意的是,该文件的包名需要跟java文件夹下的源码的主包名一致。

    aidl文件源码如下,定义了上面描述的两个方法:

    // CalculateInterface.aidl
    package com.hongri.webview;
    
    // Declare any non-default types here with import statements
    
    interface CalculateInterface {
       double doCalculate(double a, double b);
       void showToast();
    }

    (2)、主进程中定义一个远程服务RemoteService【可看做Server】:

    此服务用来监听客户端的连接请求,并实现该AIDL接口,完整代码如下:

    /**
     * @author hongri
     * @description 远程Service【Server】
     * 【此Service位于主进程中】
     */
    public class RemoteService extends Service {
    
        private static final String TAG = "RemoteService";
    
        @Override
        public IBinder onBind(Intent arg0) {
            return mBinder;
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            return super.onUnbind(intent);
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
        }
    
    
        private final CalculateInterface.Stub mBinder = new CalculateInterface.Stub() {
            /**
             * remoteWeb进程调用主进程的showToast方法,实现进程间的通信。
             * @throws RemoteException
             */
            @Override
            public void showToast() throws RemoteException {
                Log.d(TAG, "showToast" + " processName:" + ProcessUtil.getProcessName(getApplicationContext()) + " isMainProcess:" + ProcessUtil.isMainProcess(getApplicationContext()));
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(), "remoteWeb进程调用了主进程的showToast方法", Toast.LENGTH_LONG).show();
                    }
                });
            }
    
            /**
             * remoteWeb进程调用主进程的doCalculate方法,实现进程间通信。
             * @param a
             * @param b
             * @return
             * @throws RemoteException
             */
            @Override
            public double doCalculate(double a, double b) throws RemoteException {
                Calculate calculate = new Calculate();
                final double result = calculate.calculateSum(a, b);
                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(getApplicationContext(), "remoteWeb进程调用了主进程的doCalculate方法, 计算结果为:" + result, Toast.LENGTH_LONG).show();
                    }
                });
                return result;
            }
        };
    }
    

    (3)、在独立进程SingleProcessActivity中绑定远程服务RemoteService

        /**
         * 绑定远程服务RemoteService
         */
        private void initService() {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.hongri.webview", "com.hongri.webview.service.RemoteService"));
            bindService(intent, mConn, BIND_AUTO_CREATE);
        }

    (4)、绑定成功后,将服务端返回的Binder对象(service)转换成AIDL接口所属的类型(CalculateInterface):

        private CalculateInterface mRemoteService;
    
        private final ServiceConnection mConn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d(TAG, "onServiceConnected");
                //当Service绑定成功时,通过Binder获取到远程服务代理
                mRemoteService = CalculateInterface.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d(TAG, "onServiceDisconnected");
                mRemoteService = null;
            }
        };

    (5)、此时就可以根据前端post方法的调用,来根据 mRemoteService 实例针对性的调用主进程的showToast与doCalculate方法:

        @Override
        public void post(String cmd, String param) throws RemoteException {
            Log.d(TAG, "当前进程name:" + ProcessUtil.getProcessName(this) + " 主进程:" + ProcessUtil.isMainProcess(this));
            dealWithPost(cmd, param);
        }
    
        /**
         * 前端调用方法处理
         *
         * @param cmd
         * @param param
         * @throws RemoteException
         */
        private void dealWithPost(String cmd, String param) throws RemoteException {
            if (mRemoteService == null) {
                Log.e(TAG, "remote service proxy is null");
                return;
            }
            switch (cmd) {
                case "showToast":
                    Log.d(TAG, "showToast");
                    mRemoteService.showToast();
                    break;
                case "appCalculate":
                    Log.d(TAG, "appCalculate --> " + param);
                    try {
                        JSONObject jsonObject = new JSONObject(param);
                        double firstNum = Double.parseDouble(jsonObject.optString("firstNum"));
                        double secondNum = Double.parseDouble(jsonObject.optString("secondNum"));
                        double calculateResult = mRemoteService.doCalculate(firstNum, secondNum);
                        Log.d(TAG, "calculateResult:" + calculateResult);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    break;
                default:
                    Log.d(TAG, "Native端暂未实现该方法");
                    break;
            }
        }

    点击前端页面的doCalculate方法,调用结果如下: 

    表示最终实现了remoteWeb 独立进程与主进程之间的通信。

    附GitHub源码:WebViewExplore

    参考:

    Android WebView独立进程解决方案

    展开全文
  • webView选择图片并上传

    千次下载 热门讨论 2013-08-19 16:19:46
    android 使用webView选择图片并上传,相关联的服务器代码地址:http://download.csdn.net/detail/vipa1888/5975311
  • 腾讯X5浏览器服务jar包tencentX5WebView
  • Android WebView播放视频(包括全屏播放)

    千次下载 热门讨论 2014-09-26 14:51:15
    Android WebView播放视频开发中总结的一些经验,希望同大家分享,这个是相应的Demo,一些经验和注释都在代码中写到。
  • 鸿蒙开发(17)---WebView组件

    千次阅读 多人点赞 2021-07-02 13:15:16
    目录WebView组件 WebView组件

    WebView组件

    在实际的App开发中,我们往往还会直接跳转到网页。比如微信人家给你发了一个链接,默认也是在App之内打开的。

    当然,很多公司的App就只使用一个WebView作为整体框架,比如我们常用的读书App:掌阅等。这样开发的好处是,只要使用少量的代码即可完成交互。

    所以,今天我们将来介绍鸿蒙App的WebView组件的使用方式。

    基本用法

    首先,与前面讲解的其他组件一样,这里通过XML布局文件进行操作。示例代码如下:

    <ohos.agp.components.webengine.WebView
        ohos:id="$+id:ability_main_webview"
        ohos:height="match_parent"
        ohos:width="match_parent"/>
    

    需要注意的是,博主这里输入的是ohos.agp.components.webengine.WebView,你直接输入WebView也是有提示的。

    不过,WebView与ohos.agp.components.webengine.WebView并不等价,这可能是鸿蒙的一个漏洞,直接输入WebView并不能使用这个组件。

    接下来,就需要加载我们的网页进行显示,代码如下所示:

    public class MainAbilitySlice extends AbilitySlice {
        private WebView webView;
        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
            super.setUIContent(ResourceTable.Layout_ability_main);
            this.webView=(WebView)findComponentById(ResourceTable.Id_ability_main_webview);
            this.webView.load("https://www.baidu.com");
        }
    }
    

    很简单,我们使用load()函数进行网页的加载。不过,在主界面,直接这么加载是不会显示任何东西的。

    防止WebView跳转到浏览器

    这是因为,鸿蒙默认的WebView组件是直接跳转到浏览器的,而你在主页这么做,那连显示都不必,何必安装App呢?

    所以,我们需要禁止WebView跳转到浏览器,它才可能在主页显示这个组件。而它的setWebAgent()方法就是防止跳转浏览器的。示例如下:

    public class MainAbilitySlice extends AbilitySlice {
        private WebView webView;
        @Override
        public void onStart(Intent intent) {
            super.onStart(intent);
            super.setUIContent(ResourceTable.Layout_ability_main);
            this.webView=(WebView)findComponentById(ResourceTable.Id_ability_main_webview);
            this.webView.setWebAgent(new WebAgent(){
                @Override
                public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
                    return super.isNeedLoadUrl(webView, request);
                }
            });
            this.webView.load("https://www.baidu.com/");
        }
    }
    

    这里就是默认设置一下WebAgent,并覆写isNeedLoadUrl方法,当然什么都不动就行。isNeedLoadUrl主要检查是否基于当前WebView请求加载。

    运行之后,效果如下:

    运行效果

    使用JavaScript

    鸿蒙的WebView组件默认是不支持JavaScript,需要进行设置。通过如下代码,即可完成JavaScript交互。

    webView.getWebConfig().setJavaScriptPermit(true);
    

    网页调用App方法

    要完成网页与App的交互,必然涉及到两者的数据交互以及方法的调用。比如,这里我们通过网页让App弹出网页指定的内容。示例如下:

    final String jsName = "JsCallbackToApp";
        webView.addJsCallback(jsName, new JsCallback() {
            @Override
            public String onCallback(String msg) {
                new ToastDialog(getContext())
                    .setText(msg)
                    .show();
                return "jsResult";
            }
    });
    

    在网页中,我们需要通过JsCallbackToApp.call传递参数调用。代码如下:

    function myClick() {
        var result = JsCallbackToApp.call("我是网页传递给App的数据");
    }
    

    App调用网页方法

    同样的,我们有时候也要将App的处理结果传递给网页进行处理。这里我们通过executeJs()方法进行调用,示例如下:

    webView.executeJs("javascript:aAddb(5,5)", new AsyncCallback<String>() {
        @Override
        public void onReceive(String msg) {
            new ToastDialog(getContext())
                .setText("a+b="+msg)
                .show();
        }
    });
    

    同时,需要定义与executeJs第1个方法参数同名的方法,代码如下:

    function aAddb(a, b) {
        return a + b;
    }
    

    资源文件中引用网页

    在鸿蒙App的项目中,有一个rawfile文件夹,是专门用于放置我们非应用配置的额外文件的。比如,这里我们放置html文件,如下图所示:
    exampleHTML
    通过WebAgent的processResourceRequest()方法,我们可以直接按自己定义的文件规则加载html文件。代码如下:

    public class MainAbilitySlice extends AbilitySlice {
        @Override
        public void onStart(Intent intent) {
        	this.webView.setWebAgent(new WebAgent(){
                @Override
                public boolean isNeedLoadUrl(WebView webView, ResourceRequest request) {
                    return super.isNeedLoadUrl(webView, request);
                }
    
                @Override
                public ResourceResponse processResourceRequest(WebView webView, ResourceRequest request) {
                    final String authority = "example.com";
                    final String rawFile = "/rawfile/";
                    final String local = "/local/";
                    Uri requestUri = request.getRequestUrl();
                    if (authority.equals(requestUri.getDecodedAuthority())) {
                        String path = requestUri.getDecodedPath();
                        if (TextTool.isNullOrEmpty(path)) {
                            return super.processResourceRequest(webView, request);
                        }
                        if (path.startsWith(rawFile)) {
                            // 根据自定义规则访问资源文件
                            String rawFilePath = "entry/resources/rawfile/" + path.replace(rawFile, "");
                            String mimeType = URLConnection.guessContentTypeFromName(rawFilePath);
                            try {
                                Resource resource = getResourceManager().getRawFileEntry(rawFilePath).openRawFile();
                                ResourceResponse response = new ResourceResponse(mimeType, resource, null);
                                return response;
                            } catch (IOException e) {
                                HiLog.info(TAG, "open raw file failed");
                            }
                        }
                        if (path.startsWith(local)) {
                            // 根据自定义规则访问本地文件
                            String localFile = getContext().getFilesDir() + path.replace(local, "/");
                            HiLog.info(TAG, "open local file " + localFile);
                            File file = new File(localFile);
                            if (!file.exists()) {
                                HiLog.info(TAG, "file not exists");
                                return super.processResourceRequest(webView, request);
                            }
                            String mimeType = URLConnection.guessContentTypeFromName(localFile);
                            try {
                                InputStream inputStream = new FileInputStream(file);
                                ResourceResponse response = new ResourceResponse(mimeType, inputStream, null);
                                return response;
                            } catch (IOException e) {
                                HiLog.info(TAG, "open local file failed");
                            }
                        }
                    }
                    return super.processResourceRequest(webView, request);
                }
            });
            this.webView.getWebConfig().setJavaScriptPermit(true);
            this.webView.load("https://example.com/rawfile/example.html");
        }
    }
    

    processResourceRequest()方法是在请求资源时调用。

    而网页的源代码如下所示:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>title</title>
            <script type="text/javascript">
            function myClick() {
                 var result = JsCallbackToApp.call("我是网页传递给App的数据");
            }
            function aAddb(a, b) {
                return a + b;
            }
            </script>
        </head>
        <body>
            <input
                    type="button"
                    onclick="myClick()"
                    value="弹出鸿蒙ToastDialog"/>
        </body>
    </html>
    

    鸿蒙里面还有一个提示组件ToastDialog,但是这是一个简单的组件,在我们WebView进行交互的时候已经介绍过了,单独一篇博文太多,就不在赘述。

    运行之后,效果如下:

    最终效果
    本文源代码:https://github.com/liyuanjinglyj/JavaCardDemo

    展开全文
  • android webview播放网页视频

    千次下载 热门讨论 2014-03-26 21:35:29
    在网上找了太多webview播放网页视频的代码,太乱了,总结完了写了一个最最简单的demo 可以拿去参考 注意事项 在avtivity上面有
  • Android WebView基本使用

    千次阅读 2020-11-09 10:35:31
    Android WebView在Android平台上是一个特殊的View, 基于webkit引擎、展现web页面的控件,这个类可以被用来在你的app中仅仅显示一张在线的网页,还可以用来开发浏览器。WebView内部实现是采用渲染引擎来展示view的...
  • Android WebView添加夜间模式

    热门讨论 2015-04-01 17:43:22
    Android WebView添加夜间模式
  • android用webview加载html5网络视频全屏播放

    千次下载 热门讨论 2014-08-27 16:27:10
    本人自己写的一个android用webview加载html5播放视频,支持全屏播放!以前上传了个版本,那个要积分下载,但修改不了,所以重新上传一下!这个版本加了个全屏双击时会退出全屏!
  • WebView

    千次阅读 2016-07-15 15:38:59
    一、、WebView: (一)、介绍:  Android提供了一个内置浏览器,该浏览器可以查看网站,查看邮件,播放视频。要使用该内置浏览器,要通过WebView组件实现。webView组件式专门用来浏览网页的。 类...
  • android webview loadUrl实现原理浅析

    千次阅读 2021-01-13 15:40:54
    Android与JS通过WebView互相调用方法(二者沟通的桥梁是WebView),实际上是: Android去调用JS的代码 JS去调用Android的代码 对于Android调用JS代码的方法有2种: 通过 WebView.loadUrl() 通过 WebView....
  • WebView页面长按时会弹出一个复制框,但如果里面的item不是我们想要的或者想自定义,那么可以通过覆盖WebView的 startActionMode 方法来实现: /** * 长按弹出ActionMode菜单样式 * @param callback * @...
  • Flutter WebView使用以及分析

    千次阅读 2021-07-23 14:50:12
    Flutter WebView使用以及分析 一、背景 在开发过程中很多时候都需要用WebView展示网页,在android中可以直接使用WebView控件加载网页,iOS也有WKWebView或UIWebView,那么在flutter中如何加载网页? 从以下问题入手...
  • Android WebView最佳优化(WebView池)

    千次阅读 2021-06-26 11:44:34
    本文说下WebView优化,如何大幅提高WebView加载速度。一种可以从设置缓存下手,另一种使用WebView池。本文采用第二种方法,基于X5 WebView优化,这种效果非常明显,给人丝滑般流畅。网上的WebView池方案基本没有考虑...
  • android webView加载html 并引用本地资源(图片、字体库)
  • webview Android和vue.js的交互

    千次阅读 2022-04-03 23:26:05
    通过WebView的addJavascriptInterface()进行对象映射 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框...
  • HarmonyOS之常用组件WebView的使用

    千次阅读 2021-07-18 20:33:01
    一、WebView 功能 WebView 提供在应用中集成 Web 页面的能力。 请使用真机或模拟器运行查看 WebView 效果,预览器不支持 WebView 显示。 只有预置 WebView 能力的真机设备才支持 WebView 功能,智能穿戴设备不支持...
  • Android:最全面的 Webview 详解

    千次阅读 2021-05-27 10:55:47
    其实这是Android里一个叫WebView的组件实现的。今天我将全面介绍WebView的常用用法。 目录 1. 简介 WebView是一个基于webkit引擎、展现web页面的控件。 Android的Webview在低版本和高版本采用了不同的webkit...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 150,491
精华内容 60,196
关键字:

webview