Rexxar Android 系列学习(5) 过滤拦截

Rexxar 有很多拦截资源请求操作,刚看的时候乱的很,这里是结合缓存来实现的,下一节会介绍缓存机制,这里我们就需要知道返回给 WebView 的 WebResourceResponse 数据都是从缓存中读取即可。

所有的代码都在 RexxarWebViewClient 类当中,只需要看 handleResourceRequest(WebView webView, String requestUrl) 这一个方法。

具体过程

Rexxar 拦截 html,js 资源直接渲染进程返回,图片等其他资源先返回空的数据流再异步向流中写数据,因为渲染线程做太多工作会耗时并且 block 页面渲染,造成不好的显示效果。

我这里只介绍关于Html部分,js 同理。

首先需要判断当前url是否需要拦截处理,不需要则走系统方法,让webview自行处理,满足条件才拦截处理,这里 url 需要满足 非null 非本地 host 是豆瓣相关域名,详细就不多说了, 可以看代码:

  /**
   * @param requestUrl
   * @return
   */
  private boolean shouldIntercept(String requestUrl) {
      if (TextUtils.isEmpty(requestUrl)) {
          return false;
      }
      // file协议需要替换,用于html
      if (requestUrl.startsWith(Constants.FILE_AUTHORITY)) {
          return true;
      }

      // rexxar container api,需要拦截
      if (requestUrl.startsWith(Constants.CONTAINER_API_BASE)) {
          return true;
      }

      // 非合法uri,不拦截
      Uri uri = null;
      try {
          uri = Uri.parse(requestUrl);
      } catch (Exception e) {
          e.printStackTrace();
      }
      if (null == uri) {
          return false;
      }

      // 非合法host,不拦截
      String host = uri.getHost();
      if (TextUtils.isEmpty(host)) {
          return false;
      }

      // 不能拦截的uri,不拦截
      Pattern pattern;
      Matcher matcher;
      for (String interceptHostItem : ResourceProxy.getInstance().getProxyHosts()) {
          pattern = Pattern.compile(interceptHostItem);
          matcher = pattern.matcher(host);
          if (matcher.find()) {
              return true;
          }
      }
      return false;
  }

WebResourceResponse

WebResourceResponse 是关键的返回对象,会构造一个正确类型的输入流返回给 WebView ,不为 null WebView 就不会自己去下载了,也就节省了 WebView 访问网络资源。

图片异步返回

这部分是过滤拦截中比较重要的部分,代码较为复杂凌乱,主要是有很多错误情况处理,应为并不是每次数据都是合理和正确的。

这里采用的方案是:先返回一个空的 InputStream,然后再通过异步的方式向里面写数据。

    String fileExtension = MimeTypeMap.getFileExtensionFromUrl(requestUrl);
    String mimeType = MimeUtils.guessMimeTypeFromExtension(fileExtension);

首先要获取 url 的扩展名,也就是是什么类型的文件,然后根据类型获取 MimeType,在创建 WebResourceResponse 的时候传入,才是合理的类型。

WebResourceResponse xResponse = new WebResourceResponse(mimeType, "UTF-8", in);

然后在渲染线程中 post 一个 Runnable 异步的返回数据,当然这里做了 try catch 处理,如果期间出现异常,直接调用 super.shouldInterceptRequest(webView, requestUrl) 方法,让系统处理,从而不影响原生功能使用。

因为在返回空的 InputStream 时,我们已经创建了 mOut 对象,所以在 ResourceRequest 线程中,需要在获取到数据时通过 mOut 写如数据。

例如:

    byte[] bytes = IOUtils.toByteArray(cacheEntry.inputStream);
                LogUtils.i(TAG, "load async cache hit :" + mUrl);
                mOut.write(bytes);

这是一次正常的读取缓存成功操作并返回。

还有使用 native 访问网络处理的情况,相对缓存就是多了一步下载图片或者文件的操作,并且成功也要缓存到本地。同样需要对数据进行严格校验,出现任何失败都要分会相应的错误状态。

具体错误类型就不介绍了,这个可能和业务有关。

RexxarContainerAPI

这里简单介绍下 RexxarContainerAPI,和 RexxarWidget 类似,可以给 Web 一个 Native 的计算结果。RexxarContainerAPI 可以有很多的实现类,每一种都代表一种 Api 请求类型,用来处理不同的业务,只需要在不用业务页面添加所需要的 Api 功能即可,提供了一种通用的处理机制。

例如:

    / / 设置local api
    mRexxarWebView.addContainerApi(new FrodoContainerAPIs.LocationAPI());
    mRexxarWebView.addContainerApi(new FrodoContainerAPIs.LogAPI());

这里引用下官方介绍:

我们为 iOS 和 Android 各开发了一个 Rexxar Container。iOS 和 Android 平台截获请求的方式由于平台差异,并不完全相同。但本质上都是在 Web 和 Native 之间实现了一个 Proxy。Web 发出的请求会被 Proxy 预先处理。要么是修改后再发出去,要么是由 Rexxar Container 自己处理。

Rexxar Android 系列学习其他文章

Rexxar Android 系列学习(1) 项目结构
Rexxar Android 系列学习(2) 路由协议
Rexxar Android 系列学习(3) Native 和 web 交互
Rexxar Android 系列学习(4) 错误处理
Rexxar Android 系列学习(5) 过滤拦截
Rexxar Android 系列学习(6) 缓存机制

你可能感兴趣的:(Rexxar Android 系列学习(5) 过滤拦截)