成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

iOS 客戶端基于 WebP 圖片格式的流量?jī)?yōu)化(上)

harryhappy / 1589人閱讀

摘要:一了解,是一種同時(shí)提供了有損壓縮與無(wú)損壓縮的圖片文件格式,是新推出的影像技術(shù),它可讓網(wǎng)頁(yè)圖檔有效進(jìn)行壓縮,同時(shí)又不影響圖片格式兼容與實(shí)際清晰度,進(jìn)而讓整體網(wǎng)頁(yè)下載速度加快。這里建議所有基于的流量?jī)?yōu)化都最好用的判斷包住,避免帶來(lái)問(wèn)題。

首先,這是一個(gè)基于具體業(yè)務(wù)的組件優(yōu)化方案,我盡量把業(yè)務(wù)邏輯從代碼中抽離出來(lái),部分地方代碼可能有刪減。

現(xiàn)在這個(gè)方案是用于一個(gè)多圖片的新聞?lì)悜?yīng)用,粗略估計(jì)過(guò),用戶在瀏覽完第一頁(yè)所有新聞(共48篇),會(huì)消耗流量達(dá)100M,其中98M為圖片,這里值得優(yōu)化的空間非常大。

針對(duì)這種情況,我們先后使用過(guò)的優(yōu)化包含:wifi條件下預(yù)載所有文章、圖片和js、css數(shù)據(jù);重用所有已經(jīng)下載的js、css和圖片的緩存;后臺(tái)圖片的壓縮。

后臺(tái)壓縮和WebP化依賴(lài)第三方多媒體處理服務(wù)器,已知比較好的國(guó)內(nèi)服務(wù)有騰訊優(yōu)圖和七牛。這里我們采用的七牛的服務(wù)。

我們的后臺(tái)通過(guò)七牛的圖片壓縮(包含質(zhì)量和分辨率),我們將首頁(yè)流量由100m減少到了80m,依然有極大的提升空間。因此客戶端采用基于WebP的流量壓縮方案,將流量由80m壓縮到了20m,減少了75%!相對(duì)于最初的處理,流量減少了80%?。╝ndroid大多數(shù)機(jī)型支持WebP animated,壓縮能達(dá)到80%,但iOS的解碼對(duì)于WebP animated圖片支持并不好,經(jīng)常會(huì)出現(xiàn)失敗的情況,所以iOS最終壓縮率取決于首頁(yè)中g(shù)if圖的個(gè)數(shù)和大小,實(shí)際測(cè)試結(jié)果,優(yōu)化幅度大概60%-80%之間)

在準(zhǔn)備做這項(xiàng)優(yōu)化之前,查閱過(guò)很多資料,發(fā)現(xiàn)WebP適配的相關(guān)文章博客,都只是介紹簡(jiǎn)單的功能性適配,所以,并沒(méi)有得到什么好的思路。

于是,在三周的時(shí)間里,我一直邊測(cè)試邊優(yōu)化,在沒(méi)有初步方案的情況下,一點(diǎn)點(diǎn)完成功能,最終整理代碼,解耦組件,整理出一套效果非常理想,并且使用方便的解決方案。

一、了解 WebP

WebP,是一種同時(shí)提供了有損壓縮與無(wú)損壓縮的圖片文件格式,是Google新推出的影像技術(shù),它可讓網(wǎng)頁(yè)圖檔有效進(jìn)行壓縮,同時(shí)又不影響圖片格式兼容與實(shí)際清晰度,進(jìn)而讓整體網(wǎng)頁(yè)下載速度加快。

WebP 無(wú)損壓縮的圖片可以比同樣大小的 PNG 小 26%;

WebP 有損壓縮的圖片可以比同樣大小的 JPEG 小 25-34%;

WebP 支持無(wú)損的透明圖層通道,代價(jià)只需增加 22% 的字節(jié)存儲(chǔ)空間;

WebP 有損透明圖像可以比同樣大小的 PNG 圖像小3倍。

WebP在Native支持方面上,早已比較成熟,據(jù)說(shuō)淘寶客戶端在兩年前就使用了WebP(主要是Native使用),后來(lái)H5全面使用,WebView的WebP采用插件的方式支持。

在安卓上,WebP的支持是非常簡(jiǎn)單的,畢竟都是谷歌的東西,自己當(dāng)然要支持,但是在iOS的WebKit內(nèi)核(UIWebView和WKWebView)上,是不能直接支持的。不過(guò)最近傳言macOS 10.12上的Safari有測(cè)試WebP的跡象,暫時(shí)還不太明朗。

二、準(zhǔn)備工作

由于OS X不支持原生WebP解碼,所以,可以先安裝一個(gè)工具。推薦使用Homebrew,具體使用參考 http://brew.sh/index_zh-cn.html

安裝完成后,使用命令

$brew install webp

就可以安裝libwebp了。

客戶端方面,Native圖片加載使用的SDWebImage,該組件直接支持WebP的解碼。需要在將預(yù)編譯宏’WebP’置為1,并在pod中引入’iOS-WebP’即可。

服務(wù)端方面,我們采用七牛圖片服務(wù)器,默認(rèn)傳給客戶端的參數(shù)是一張jpg或者png的圖片鏈接,通過(guò)修改url的請(qǐng)求參數(shù)實(shí)現(xiàn)對(duì)WebP圖片的獲取。相關(guān)規(guī)則可以參考七牛開(kāi)發(fā)文檔。

三、具體方案實(shí)現(xiàn)

首先考慮,請(qǐng)求的webp圖片是通過(guò)url參數(shù)拼接完成的,所以,需要對(duì)客戶端內(nèi)請(qǐng)求的所有圖片URL做處理,必須全部命中。而且,將來(lái)的緩存也應(yīng)基于此URL進(jìn)行處理,所以,添加一個(gè)NSURL分類(lèi),URL的處理由這個(gè)分類(lèi)統(tǒng)一處理,所有的URL替換最終都會(huì)指向這個(gè)分類(lèi)中的方法,耦合度基本可以將至最低。

@interface NSURL (ReplaceWebP)
- (NSURL *)qd_replaceToWebPURLWithScreenWidth;
- (NSString *)qd_defultWebPURLCacheKey;
- (BOOL)qd_isShouldReplaceImageFormat;
@end

下面是替換URL和緩存key的核心處理代碼

static NSString * const qdHost = @"img.host.com";
@implementation NSURL (ReplaceWebP)
- (NSString *)qd_defultWebPURLCacheKey {
    if (![self qd_isShouldReplaceImageFormat]) {
        return self.absoluteString;
    }
    NSString *key;
    if ([self isWebPURL]) {
        key = self.absoluteString;
    } else {
        key = [self qd_replaceToWebPURLWithScreenWidth].absoluteString;
    }
    return key;
}
- (NSURL *)qd_replaceToWebPURLWithImageWidth:(int)width {
  
    if ([self qd_isShouldReplaceImageFormat]) {
        NSString *urlStr;
        
        if ([self URLStringcontainFomartString:@"?"]) {
            if ([self URLStringcontainFomartString:@"format/jpg"]) {
                urlStr = [self.absoluteString stringByReplacingOccurrencesOfString:@"format/jpg" withString:@"format/webp"];
            } else {
                NSString *suffixStr = @"imageView2/0/format/webp/ignore-error/1";
                urlStr = [NSString stringWithFormat:@"%@/%@", self.absoluteString, suffixStr];
            }
        } else {
            NSString *pathExtension = [[self.absoluteString.pathExtension componentsSeparatedByString:@"-"] firstObject];
            urlStr = [NSString stringWithFormat:@"%@.%@-WebPiOSW%d",self.absoluteString.stringByDeletingPathExtension, pathExtension, width];
        }
        return [NSURL URLWithString:urlStr];
    }
    return self;
}
- (NSURL *)qd_replaceToWebPURLWithScreenWidth {
    
    int width = (int)([UIScreen mainScreen].bounds.size.width * [UIScreen mainScreen].scale);
    return [self qd_replaceToWebPURLWithImageWidth:(int)width];
}

所有的URL替換,最終都會(huì)到 - (NSURL *)qd_replaceToWebPURLWithImageWidth:(int)width 這個(gè)方法中來(lái)

下面是條件過(guò)濾,確保100%命中所有需要替換的圖片格式

- (BOOL)isQDHost {
    NSString *nsModel = [UIDevice currentDevice].model;
    BOOL s_isiPad = [nsModel hasPrefix:@"iPad"];
    if (s_isiPad) return NO;
    return [self URLStringcontainFomartString:qdHost];
}
- (BOOL)qd_isShouldReplaceImageFormat {
    
    if (![self isQDHost]) {
        return NO;
    }
    if ([self isWebPURL]) {
        return NO;
    }
    NSArray *extensions = @[@".jpg", @".jpeg", @".png"];
    for (NSString *extension in extensions) {
        if ([self.absoluteString.lowercaseString rangeOfString:extension options:NSCaseInsensitiveSearch].location != NSNotFound){
            return YES;
        }
    }
    return NO;
}
- (BOOL)URLStringcontainFomartString:(NSString *)string {
    return ([self.absoluteString.lowercaseString rangeOfString:string options:NSCaseInsensitiveSearch].location != NSNotFound);
}
- (BOOL)isWebPURL {
    return [self URLStringcontainFomartString:@"-webp"] || [self URLStringcontainFomartString:@"/webp"];
}
@end

所以,替換URL這個(gè)功能,被完全抽離出來(lái),之后的代碼,只需要考慮具體邏輯的問(wèn)題了。

2. Native 圖片請(qǐng)求替換

Native圖片加載使用的SDWebImage,首先需要理解SD的代碼,確定是最終的圖片下載是調(diào)用的哪個(gè)方法

- (id )downloadImageWithURL:(NSURL *)url
                                 options:(SDWebImageOptions)options
                                progress:(SDWebImageDownloaderProgressBlock)progressBlock
                               completed:(SDWebImageCompletionWithFinishedBlock)completedBlock

所有的圖片下載,最終都走到了這個(gè)方法中,所以,替換URL應(yīng)該在這個(gè)方法的最前面實(shí)現(xiàn)。

{
    if ([url isKindOfClass:NSString.class]) {
        url = [NSURL URLWithString:(NSString *)url];
    }
    if (![url isKindOfClass:NSURL.class]) {
        url = nil;
    }
    url = [url qd_replaceToWebPURLWithScreenWidth];
    ...
    ...
}

由于在評(píng)估了難度之后,我們果斷地把SDWebImage從Pods中移除,手動(dòng)添加一個(gè)子工程,這樣可以比較方便地修改內(nèi)部實(shí)現(xiàn),而不至于用swizzling這種黑魔法來(lái)修改傳入?yún)?shù)。這個(gè)技能雖然炫酷,然而很多情況下,殺敵一萬(wàn),自損兩萬(wàn),不建議經(jīng)常使用。

因修改了url值,若在上層通過(guò)SDImageCache判斷是否有本地緩存時(shí),也需要對(duì)url先做qd_defultWebPURLCacheKey來(lái)獲取其真實(shí)緩存的key。這一部分比較簡(jiǎn)單。

3. WebView 圖片請(qǐng)求替換

這一部分是這個(gè)方案的難度所在。

webkit內(nèi)核現(xiàn)在都不支持解析WebP格式的圖片,這里主要采用的iOS系統(tǒng)的NSURLProtocol來(lái)替換其網(wǎng)絡(luò)請(qǐng)求(不了解NSURLProtocol,可以動(dòng)動(dòng)自己勤勞的小手Google一下),再將網(wǎng)絡(luò)回包數(shù)據(jù)進(jìn)行轉(zhuǎn)碼成jpg或者png(為了透明度),再返回給webview進(jìn)行渲染的。

友情鏈接,NSURLProtocol用法,大神文章

同樣的,iOS在此處依然不對(duì)gif進(jìn)行任何處理。

另外,NSURLProtocol會(huì)攔截全局的網(wǎng)絡(luò)流量,為避免誤傷,這里需要多帶帶識(shí)別是否是WebView發(fā)起的請(qǐng)求,可以通過(guò)識(shí)別request中的UA是否包含”AppleWebKit”來(lái)實(shí)現(xiàn)。

@implementation QDWebURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    
    NSString *ua = [request valueForHTTPHeaderField:@"User-Agent"];
    if ([request.URL qd_isShouldReplaceImageFormat] && [ua lf_containsSubString:@"AppleWebKit"]) {
        return YES;
    }
}

這里可以接管所有WebView中需要替換的圖片URL。

下面,會(huì)自動(dòng)調(diào)用startLoading方法,這里采用了一個(gè)非常特別的方式處理

- (void)startLoading {
    if ([self.request.URL qd_isShouldReplaceImageFormat]) {
        [[SDWebImageManager sharedManager] downloadImageWithURL:self.request.URL
                                                        options:0
                                                       progress:nil
                                                      completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL)
                                                    {
                                                          NSData *data;
                                                          if ([imageURL.absoluteString.lowercaseString lf_containsSubString:@".png"]) {
                                                              data = UIImagePNGRepresentation(image);
                                                          } else {
                                                              data = UIImageJPEGRepresentation(image, 1);
                                                          }
                                                          [self.client URLProtocol:self didLoadData:data];
                                                          [self.client URLProtocolDidFinishLoading:self];
                                                      }];
        return;
    }
    self.connection = [NSURLConnection connectionWithRequest:self.request delegate:self];
}

是不是很奇特,由SDWebImageManager直接接管圖片請(qǐng)求,手動(dòng)finishLoading。

首先需要明確,WebP節(jié)約流量,究竟是怎么樣的原理:

所謂圖片格式,是采用何種解碼編碼方式?jīng)Q定的,所有數(shù)據(jù)最終一定是變成二進(jìn)制數(shù)據(jù),NSData;
既然UIWebView不支持解碼WebP,我們可以讓圖片在網(wǎng)絡(luò)中以WebP格式的NSData傳遞,本地收到data后,解碼成UIWebView可以識(shí)別的UIImage;事實(shí)上,Native方面就是這么做就可以達(dá)到目標(biāo)了,然而在WebView的請(qǐng)求中,無(wú)論我們本地做了何種處理,最終交給WebView的也一定是NSData,所以,需要再把UIImage編碼成jpg或者png(之所以我們沒(méi)有把gif也轉(zhuǎn)WebP,就是因?yàn)閺腤ebP的動(dòng)圖UIImage,轉(zhuǎn)碼成NSData這條路走不通,于是我們放棄了gif轉(zhuǎn)WebP)。

所以,大致的數(shù)據(jù)路徑如下:

本地發(fā)送WebP請(qǐng)求 ---> Server ---> 返回WebP格式Data ---> Data經(jīng)谷歌的WebP decode得到UIImage ---> 將UIImage對(duì)象編碼成JPG或PNG格式NSData ---> 替換本應(yīng)交給WebView的WebP格式Data ---> WebView接收J(rèn)PG或PNG格式Data ---> 渲染圖片

在最開(kāi)始,這里并不是這么寫(xiě)的,當(dāng)時(shí)是在系統(tǒng)的

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

方法中轉(zhuǎn)碼處理。按這個(gè)思路寫(xiě),代碼越寫(xiě)越散,BUG也越來(lái)越多。所以,換了個(gè)思路,既然SD可以支持WebP,為什么不用他來(lái)全面托管呢?

這樣的話,原生請(qǐng)求和WebView的圖片緩存也可以經(jīng)由SD統(tǒng)一起來(lái),所以,這應(yīng)該是一個(gè)好的方案。

這樣的話,WebP的所有請(qǐng)求都已經(jīng)可以處理(wifi預(yù)加載暫時(shí)不管,因?yàn)槭亲约簩?xiě)的downloader,替換URL后直接改把緩存指向修改就可以),之后要處理緩存的問(wèn)題

4. 圖片緩存處理

以前的代碼已經(jīng)實(shí)現(xiàn)了內(nèi)部文章的緩存,包含js、css以及image等。這里通過(guò)NSURLCache來(lái)實(shí)現(xiàn)。相應(yīng)的,基于WebP的圖片緩存的讀取也應(yīng)該在NSURLCache中處理,在先處理完URL后,用新的Key來(lái)進(jìn)行映射。

這里建議所有基于WebView的流量?jī)?yōu)化都最好用UA的判斷包住,避免帶來(lái)問(wèn)題。因?yàn)闊o(wú)論NSURLProtocol還是NSURLCache都是全局網(wǎng)絡(luò)控制。

篇幅略長(zhǎng),具體緩存處理放在下一篇介紹。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/61792.html

相關(guān)文章

  • <轉(zhuǎn)載>圖片流量節(jié)省60%:基于CDNsharpP自適應(yīng)圖片技術(shù)實(shí)踐

    摘要:開(kāi)啟驗(yàn)證上傳一張新圖片,使用手安卓版本訪問(wèn)已支持域名的圖片,如果請(qǐng)求帶了,檢查返回圖片格式是否為如果舊的圖片未按預(yù)期返回,返回了或原圖可能是結(jié)點(diǎn)緩存,正常天后過(guò)期回源則會(huì)返回圖片。 對(duì)于圖片較多的網(wǎng)站,本文結(jié)合具體案例給出了如何基于CDN的sharpP自適應(yīng)圖片無(wú)痛接入方案,據(jù)統(tǒng)計(jì)效果可在原圖基礎(chǔ)上節(jié)省60%-75%的流量。作者:陳忱 出處:騰云閣文章 目前移動(dòng)端運(yùn)營(yíng)素材大部分依賴(lài)圖...

    JerryZou 評(píng)論0 收藏0
  • iOS 戶端基于 WebP 圖片格式流量優(yōu)化(下)

    摘要:在客戶端基于圖片格式的流量?jī)?yōu)化上這篇文章中,已經(jīng)介紹了格式圖片的下載使用,僅僅只有這樣還遠(yuǎn)遠(yuǎn)不夠,還需要對(duì)已經(jīng)下載的圖片數(shù)據(jù)進(jìn)行緩存。二圖片緩存關(guān)于的緩存,系統(tǒng)提供了一個(gè)類(lèi),。而且,既然是全局影響,肯定要用包起來(lái),防止誤傷其他緩存。 在iOS 客戶端基于 WebP 圖片格式的流量?jī)?yōu)化(上)這篇文章中,已經(jīng)介紹了WebP格式圖片的下載使用,僅僅只有這樣還遠(yuǎn)遠(yuǎn)不夠,還需要對(duì)已經(jīng)下載的圖片數(shù)...

    JiaXinYi 評(píng)論0 收藏0
  • 【譯】 WebP 支持:超出你想象

    摘要:的支持程度實(shí)際上比你想的可能要好得多。的安卓瀏覽器從版本起開(kāi)始官方支持最初發(fā)布于年月,版本起開(kāi)始部分支持。安卓版從起開(kāi)始支持。而且目前并無(wú)添加支持的任何打算。瀏覽器市場(chǎng)份額截至年月的數(shù)據(jù)顯示,占有約的市場(chǎng)份額,以約位居第二。 本文轉(zhuǎn)載自:眾成翻譯譯者:文藺鏈接:http://www.zcfy.cc/article/862原文:https://optimus.keycdn.com/sup...

    Steven 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<