问题
H5 页面的动态文案需要使用艺术字体,而通常情况下,字体包都是很大的,全部加载肯定是不行的。
那该怎么办呢?
分析
对于普通的 H5 页面需要使用艺术字体,我能想到的解决方案大致是以下几种。
1、静态文案:
- 直接用图片
- 用类似 font-spider 的工具将字体库过滤,然后引入。(如果字体库比较大)
2、动态文案:
- 硬着头皮加载整个字体库(对于移动端来说,如果字体包很大,体验肯定很棒 🐶)
- 和设计同学沟通,对于不固定文案的地方,看看能不能弃用艺术字体(看对产品的影响,通常从需求能解决是最好不过了)。
- 通过后端服务,将页面需要用到的艺术字体文案发给后端,让后端服务生成图片或者svg等,然后返回显示。
- 可能还有其他优秀的解决方案,还望分享。
这里就不讨论每种方案的优缺点了。
这里说下我们遇到的场景以及解决方案——客户端拦截请求返回本地字体包资源。
因为我们是 Hybird 开发,而且整个 app 的标题都采用了统一的艺术字体,最精彩的是标题是后台可配的。
客户端打包了一个完整的字体包(也不是很完整,过滤了常用的5000字,大概 1M,够用了),这样就可以支持艺术字体了。
但是H5就很尴尬了,请求服务端字体包,太大了。所以思路就是,能不能 H5 页面也使用客户端本地打包的那个字体包?
通过上面分析,现在需要解决的问题变成了 H5 页面访问客户端本地文件。
最先想到的是通过文件协议 file:///
直接去访问,但是试了几次,没有成功。想到可能是存在跨域了。
后来想到大部分桥协议(scheme的方式)都是通过拦截请求的方式实现的,还有之前了解过客户端缓存 H5 静态资源的需求,也是通过拦截 H5 请求,然后对比本地缓存清单,决定是返回本地文件还是向服务端发出请求。
解决方案
经过分析,我们来梳理下实现。
1、h5 页面正常发出请求(通过 http/https 协议),为了客户端能识别出这个请求是访问本地文件,这里需要对请求路径或域名进行一些特殊处理。
这里说下我们的处理方式。
通过和客户端商量,我们将域名改成 localfile
作为请求本地文件的标示。不过这样需要客户端同学响应时修改头信息中的 Access-Control-Allow-Origin ,允许跨域。
后面的 fonts 和 nbfont.tff 分别代表文件类型和名称。
@font-face {
font-family: 'nbfont';
src: url('//localfile/fonts/nbfont.ttf');
}
2、客户端拦截请求并返回本地文件。这里只了解了 Android 的实现方式。
重写 shouldInterceptRequest:
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
WebResourceResponse response = super.shouldInterceptRequest(view, url);
CLog.i("load intercept request:" + url);
if (url != null && url.contains("localfile")) {
String assertPath = url.substring(url.indexOf("localfile/") + "localfile/".length(), url.length());
try {
// 如果有跨域,还需要添加修改头部信息的代码,具体可以看下 WebResourceResponse
response = new WebResourceResponse("application/x-font-ttf",
"UTF8", getAssets().open(assertPath)
);
} catch (IOException e) {
e.printStackTrace();
}
}
return response;
}
总结
以上就是基本实现方式了,还是很简单。可能有人看到客户端拦截请求返回本地字体包资源的时候就知道怎么实现了哈。这其实就是 H5 和客户端通信协议的实现思路,只不过一个是回调返回参数,一个是返回响应文件。
简单说下这个方案的优缺点。
缺点:
1、如果字体包客户端不使用,将字体包打包在客户端会增加 APK 的大小。
2、需要客户端修改代码,所以需要发版本,版本兼容需要考虑。
3、比较适合固定某个艺术字体的需求,如果设计一个活动页换一种艺术字体,那就打扰了。
优点:
1、本地访问,速度快。
2、不仅解决了字体的问题,而且提供了一种访问客户端本地文件的方式。
最后我想说,这些问题,只是某个时期客观上的一些原因或者不足造成的,就像当年开发需要写各种浏览器的兼容,后来通过浏览器厂商对各种规范的落实和移动互联网的到来,有些以前让人头疼的问题,现在已经不存在了。
同样我们可以畅想,未来硬件性能提升,5G 基站的逐渐普及,带宽升级,流量费用降低。那么我们今天讨论的问题可能就不会是问题了,那个时候就毫不犹豫的加载整个字体库吧。
不过在这一天没有到来前,最有效的解决方法还是从产品和需求的角度入手,寻找替代方案。