Android 混合开发中加载本地资源那点事

Posted QXXXD

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 混合开发中加载本地资源那点事相关的知识,希望对你有一定的参考价值。

周末跟许久未见的老王(前同事)约了个饭。我临时有事,到那都晚上9点了,很是惭愧。席间聊到公司在做“套壳”App,问我如何加载自定义自体。为了弥补自己的迟到,在整理 demo 时,顺便记录下这个过程。

刚好我最近在公司负责自研小程序框架的重构,所以这事简单啊,就调一个API。便答应回家把关键字发给他。

 // android加载自定义字体
 // 1. 配置WebViewClient
 webView.setWebViewClient(webViewClient);
 // 2. 拦截请求
 webViewClient.shouldInterceptRequest() 

其核心思想就是:拦截。

一、原理

由webView加载一个页面(loadUrl),如果被加载的html放在 assets 目录下,那么使用 file:///android_asset/xxx.html 形式加载,如果是远端地址,则按浏览器加载网页逻辑填写url即可。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1tS0W1YC-1654867998510)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/beb5a2389ba14c1dbba3d63778e37bce~tplv-k3u1fbpfcp-zoom-in-crop-mark:1956:0:0:0.image?)] 对于加载本地资源这种情况,我们要在发出的请求,离开App之前,给它拦下来。比如:要加载本地字体,那就要识别这次请求,在 shouldInterceptRequest 中根据约定规则,去本地找字体资源,并构建出请求的响应体,也就是上图中的 response。

二、实战

2.1 前端代码

首先看下前端代码:

index.html

 <div class="app">
   <div>hello world</div>
   <div>新年快乐</div>
   <img src="https://img.tukuppt.com/bg_grid/01/03/50/Ljquu0ZtJN.jpg!/fh/350" alt="">
 </div> 

外层 div 设置 class选择器为 app,app内并排3个元素。这里关键在css:

 <style>
   @font-face 
     font-family: HuaGuangGangTieZhiHei;
     src: url('http://font/HuaGuangGangTieZhiHei-KeBianTi-2.ttf');
   
   .app 
     font: 63px HuaGuangGangTieZhiHei;
   
 </style> 

这里使用 src 从服务器加载自定义字体。在类选择器 app 中使用该字体。注意这里的 http://font 并非真实的url,仅为了方便我们拦截该请求。

PS:字体的自定义url为 http://font,如果要加载本地图片,可以设置为 http://image,当然也可以统一host,这个根据自己的业务设定即可。

2.2 Android 端代码

  1. 在布局文件中增加 WebView,这个简单,不贴代码了。

  2. 设置 WebViewClient ,并重写 shouldInterceptRequest

     webView.setWebViewClient(new WebViewClient() 
       @Nullable
       @Override
       public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) 
         Uri url = request.getUrl();
         Log.e("MainActivity", "shouldInterceptRequest " + url.toString());
         if (customFont && url.toString().contains("font"))  // 1
           try 
             InputStream inputStream = getAssets().open("HuaGuangGangTieZhiHei-KeBianTi-2.ttf"); // 2
             Map<String, String> responseHeaders = new HashMap<String, String>();
             responseHeaders.put("Access-Control-Allow-Origin", "*");
             return new WebResourceResponse("font/ttf", "utf-8", 200, "ok", responseHeaders, inputStream); // 3
            catch (IOException e) 
             e.printStackTrace();
           
         
         return super.shouldInterceptRequest(view, request);
       
     ); 
    
    1. 拦截 url 中包含 font 关键字的请求
    2. 打开 assets 中的字体
    3. 构造响应体 WebResourceResponse
  3. 加载url

     webView.loadUrl("file:///android_asset/index.html"); 
    

三、后续

今天周一,老王问我调哪个方法,我便给它两个方法: 过一会,他把 MainActivity.java 发给我了,核心代码如下:

 wb.loadUrl("http://localhost/web");
 wb.setWebViewClient(new WebViewClient() 
   @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
   @Override
   public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) 
     view.loadUrl(String.valueOf(request.getUrl()));
     return true;
   
 ​
   @Override
   public boolean shouldOverrideUrlLoading(WebView view, String url) 
     view.loadUrl(url);
     return true;
   
 ​
   @Override
   public void onPageFinished(WebView view, String url) 
     if (!wb.getSettings().getLoadsImagesAutomatically()) 
       wb.getSettings().setLoadsImagesAutomatically(true);
     
   
 ); 

对比实战部分,这段代码是无法加载自定义字体的。虽然重写了 shouldOverrideUrlLoading 方法,但并没有加载 Android 端字体。

四、总结

把远程常用资源放到本地加载,是解决 h5 白屏的关键部分。不管是套壳App,还是 hybrid App,它是个系统工程。想要开发出一套完整可用的框架,需要前端到Android端的知识,尤其是网络请求,这是绕不开的。

以上是关于Android 混合开发中加载本地资源那点事的主要内容,如果未能解决你的问题,请参考以下文章

在 WebView 中加载页面之前,用本地 Android 资源替换 HTML 文档的图像

for循环,定时器,闭包混合一块的那点事。

Android-WebView中加载本地html的方法

Android Framework:关于AMS的那点事

苹果工程师对iOS线程开发的那点事津津乐道

安卓安全那点事