作者Talent•C 转载请注明出处
前言 在一般的app中占用流量最大的内容一般都是图片,以苹果公司 Retina 产品为代表的高 PPI 屏对图片的质量提出了更高的要求,如何保证在图片的精细度不降低的前提下缩小图片体积,成为了一个有价值且值得探索的事情。 但如今对于 JPEG、PNG 和 GIF 这些图片格式的优化几乎已经达到了极致, 若想改变现状开辟新局面,便要有釜底抽薪的胆量和气魄,而 Google 给了我们一个新选择:WebP。
正文 WebP是什么?
WebP(发音 weppy,来自:Google WebP ),是一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式 VP8。根据 Google 的测试,无损压缩后的 WebP 比 PNG 文件少了 45% 的文件大小,即使这些 PNG 文件经过其他压缩工具压缩之后,WebP 还是可以减少 28% 的文件大小。 在 Google 的明星产品如 Youtube、Gmail、Google Play 中都可以看到 WebP 的身影,而 Chrome 网上商店甚至已完全使用了 WebP。国外公司如 Facebook、ebay 和国内公司如腾讯、淘宝、美团等也早已尝鲜。 下面是QQ图片格式对比图
iOS中如何使用WebP格式图片? 很幸运,SDWebImage支持WebP格式图片,可以讲WebP数据–>NSData–>UIImage
There are 3 subspecs available now: Core, MapKit and WebP (this means you can install only some of the SDWebImage modules. By default, you get just Core, so if you need WebP, you need to specify it). Podfile example: $pod ‘SDWebImage/WebP’ 摘自SDWebImage
我们需要手动下载WebP这个库,由于是从Google下载的,如果下载失败,请翻墙重试!!! 下载后的文件路径
Xcode 需要如下配置 targets->build settings ->preprocessor Macros 填写 SD_WEBP=1 如图 到此app 中支持 WebP图片基本完成,但是重点来了,由于部分app使用到了UIWebview/WKWebview
这两个控件是不支持WebP图片的,目前有两种方式可以让其支持WebP格式图片。
实现方式一 NSURLProtocol
对于NSURLProtocol的作用及使用以后找个时间再讲了~~~~可以参考Apple 开发者文档 NSURLProtocol, UIWebView 直接就可以支持,但是WKWebView是不支持的,如何让WKWebView也支持NSURLProtocol可以参考这篇文章 ,不过WKWebView自定义NSURLProtocol会丢失boay数据。文章结尾会附上Demo下载地址。
WKWebView 拓展支持NSURLProtocol 具体代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
FOUNDATION_STATIC_INLINE Class ContextControllerClass() {
static Class cls;
if (!cls) {
cls = [[[WKWebView new] valueForKey:@"browsingContextController" ] class ];
}
return cls;
}
FOUNDATION_STATIC_INLINE SEL RegisterSchemeSelector() {
return NSSelectorFromString (@"registerSchemeForCustomProtocol:" );
}
FOUNDATION_STATIC_INLINE SEL UnregisterSchemeSelector() {
return NSSelectorFromString (@"unregisterSchemeForCustomProtocol:" );
}
@implementation NSURLProtocol (WebKitExt )
+ (void )wk_registerScheme:(NSString *)scheme {
Class cls = ContextControllerClass();
SEL sel = RegisterSchemeSelector();
if ([(id )cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id )cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
}
}
+ (void )wk_unregisterScheme:(NSString *)scheme {
Class cls = ContextControllerClass();
SEL sel = UnregisterSchemeSelector();
if ([(id )cls respondsToSelector:sel]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[(id )cls performSelector:sel withObject:scheme];
#pragma clang diagnostic pop
}
}
好了,现在UIWebView与WKWebView 都已经支持自定义NSURLProtocol了; 我们创建一个类CLURLProtocol 继承自NSURLProtocol
下面这几个方法必须实现
+(BOOL)canInitWithRequest:(NSURLRequest )request; +(NSURLRequest )canonicalRequestForRequest:(NSURLRequest *)request; -(void)stopLoading; -(void)startLoading;
这里不过多废话了 直接上代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
+ (BOOL )canInitWithRequest:(NSURLRequest *)request {
判断是否启用SD_WEBP 并且图片格式为webp 如果为YES 则标记请求需要自行处理并且防止无限循环 为NO则不处理
*/
BOOL useCustomUrlProtocol = NO ;
NSString *urlString = request.URL.absoluteString;
if (!SD_WEBP || ([urlString.pathExtension compare:@"webp" ] != NSOrderedSame )) {
useCustomUrlProtocol = NO ;
}else {
if ([NSURLProtocol propertyForKey:CLProtocolKey inRequest:request] == nil ) {
useCustomUrlProtocol = YES ;
}else {
useCustomUrlProtocol = NO ;
}
}
return useCustomUrlProtocol;
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void )stopLoading{
}
我们在创建一个WebV继承自UIViewController 用来展示webView1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
- (void )viewDidLoad {
[super viewDidLoad];
self .automaticallyAdjustsScrollViewInsets = NO ;
if ([self .webView isKindOfClass:[WKWebView class ]]) {
[NSURLProtocol registerClass:NSClassFromString (@"CLURLProtocol" )];
[NSURLProtocol wk_registerScheme:@"http" ];
[NSURLProtocol wk_registerScheme:@"https" ];
WKWebView *web = (WKWebView *)self .webView;
[web loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://onzbjws3p.bkt.clouddn.com/testForwebpSrc/testWebpForHtml.html" ]]];
}else if ([self .webView isKindOfClass:[UIWebView class ]])
{
[NSURLProtocol registerClass:NSClassFromString (@"CLURLProtocol" )];
UIWebView *web = (UIWebView *)self .webView;
[web loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://onzbjws3p.bkt.clouddn.com/testForwebpSrc/testWebpForHtml.html" ]]];
}
}
- (void )dealloc
{
NSLog (@"WebVC -- dealloc" );
if ([self .webView isKindOfClass:[WKWebView class ]]) {
[NSURLProtocol unregisterClass:NSClassFromString (@"CLURLProtocol" )];
[NSURLProtocol wk_unregisterScheme:@"http" ];
[NSURLProtocol wk_unregisterScheme:@"https" ];
}else if ([self .webView isKindOfClass:[UIWebView class ]])
{
[NSURLProtocol unregisterClass:NSClassFromString (@"CLURLProtocol" )];
}
}
到此为止UIWebView/WKWebView 均已支持加载webp格式图片 效果如图 WKWebView 展示效果
UIWebView 展示效果
UIImageView 展示效果
优点: 适合所有网页,可以不用修改网页内部html
内容。
缺点: NSURLProtocol 拦截App 的所有请求, 使用时需要根据个人项目情况而定, WKWebView 在post请求时会丢失boay, 目前解决方式为在WKWebView的 开始加载的 代理方法判断是否为post,为post解除注册自定义的NSURLProtocol,为GET请求时注册自定义NSURLProtocol。
实现方式二 通过JavaScript
与OC
共同完成 实现思路: 1、向网页内注入JS
2、在App 本地开启线程下载图片,下载完成后,将图片转码由 webP—> png—>Base64。 3、将 Base64及原图片下载地址一一对应调用JS
准备好的方法进行替换。 4、将下载后的图片进行缓存,并进行管理。
注意注意: A、图片未真正加载完毕时,网页中图片为了体验好可以添加默认占位图片。 B、图片显示成功前应该保持网页布局不调整,需要由JS
预先设置好布局。 C、图片在本地的缓存需要管理。
获取网页img
标签的js
代码1
2
3
4
5
6
7
8
9
10
11
12
function talentcGetAllImageSrc ()
{
var imagesList = document.images;
var srcList = [];
var patt1 = new RegExp("\.webp$" );
for (var i = 0 ; i < imagesList.length; i++) {
if (patt1.test(imagesList[i].src)) {
srcList.push(imagesList[i].src);
}
}
return JSON.stringify(srcList);
};
替换网页img
标签的js
代码1
2
3
4
5
6
7
function talentcReplaceWebPImg (src, localPath)
{
var elementList = document.querySelectorAll('img[src="' +src+'"]' );
for (var element in elementList) {
elementList[element].src = localPath;
}
}
优点: 对于UIWebview
与 WKWebView
是通用不需要特殊处理,也不会拦截App中的请求。
缺点: 对于展示的第三方网页需要根据网页做一些适配, 例如部分网页展示图片使用的div
的background-image
。
UIWebView 展示效果
WKWebView 展示效果 全文终 本文demo 下载