国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

iOS 客戶端基于 WebP 圖片格式的流量優化(上)

harryhappy / 1574人閱讀

摘要:一了解,是一種同時提供了有損壓縮與無損壓縮的圖片文件格式,是新推出的影像技術,它可讓網頁圖檔有效進行壓縮,同時又不影響圖片格式兼容與實際清晰度,進而讓整體網頁下載速度加快。這里建議所有基于的流量優化都最好用的判斷包住,避免帶來問題。

首先,這是一個基于具體業務的組件優化方案,我盡量把業務邏輯從代碼中抽離出來,部分地方代碼可能有刪減。

現在這個方案是用于一個多圖片的新聞類應用,粗略估計過,用戶在瀏覽完第一頁所有新聞(共48篇),會消耗流量達100M,其中98M為圖片,這里值得優化的空間非常大。

針對這種情況,我們先后使用過的優化包含:wifi條件下預載所有文章、圖片和js、css數據;重用所有已經下載的js、css和圖片的緩存;后臺圖片的壓縮。

后臺壓縮和WebP化依賴第三方多媒體處理服務器,已知比較好的國內服務有騰訊優圖和七牛。這里我們采用的七牛的服務。

我們的后臺通過七牛的圖片壓縮(包含質量和分辨率),我們將首頁流量由100m減少到了80m,依然有極大的提升空間。因此客戶端采用基于WebP的流量壓縮方案,將流量由80m壓縮到了20m,減少了75%!相對于最初的處理,流量減少了80%!(android大多數機型支持WebP animated,壓縮能達到80%,但iOS的解碼對于WebP animated圖片支持并不好,經常會出現失敗的情況,所以iOS最終壓縮率取決于首頁中gif圖的個數和大小,實際測試結果,優化幅度大概60%-80%之間)

在準備做這項優化之前,查閱過很多資料,發現WebP適配的相關文章博客,都只是介紹簡單的功能性適配,所以,并沒有得到什么好的思路。

于是,在三周的時間里,我一直邊測試邊優化,在沒有初步方案的情況下,一點點完成功能,最終整理代碼,解耦組件,整理出一套效果非常理想,并且使用方便的解決方案。

一、了解 WebP

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

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

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

WebP 支持無損的透明圖層通道,代價只需增加 22% 的字節存儲空間;

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

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

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

二、準備工作

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

安裝完成后,使用命令

$brew install webp

就可以安裝libwebp了。

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

服務端方面,我們采用七牛圖片服務器,默認傳給客戶端的參數是一張jpg或者png的圖片鏈接,通過修改url的請求參數實現對WebP圖片的獲取。相關規則可以參考七牛開發文檔。

三、具體方案實現

首先考慮,請求的webp圖片是通過url參數拼接完成的,所以,需要對客戶端內請求的所有圖片URL做處理,必須全部命中。而且,將來的緩存也應基于此URL進行處理,所以,添加一個NSURL分類,URL的處理由這個分類統一處理,所有的URL替換最終都會指向這個分類中的方法,耦合度基本可以將至最低。

@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替換,最終都會到 - (NSURL *)qd_replaceToWebPURLWithImageWidth:(int)width 這個方法中來

下面是條件過濾,確保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這個功能,被完全抽離出來,之后的代碼,只需要考慮具體邏輯的問題了。

2. Native 圖片請求替換

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

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

所有的圖片下載,最終都走到了這個方法中,所以,替換URL應該在這個方法的最前面實現。

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

由于在評估了難度之后,我們果斷地把SDWebImage從Pods中移除,手動添加一個子工程,這樣可以比較方便地修改內部實現,而不至于用swizzling這種黑魔法來修改傳入參數。這個技能雖然炫酷,然而很多情況下,殺敵一萬,自損兩萬,不建議經常使用。

因修改了url值,若在上層通過SDImageCache判斷是否有本地緩存時,也需要對url先做qd_defultWebPURLCacheKey來獲取其真實緩存的key。這一部分比較簡單。

3. WebView 圖片請求替換

這一部分是這個方案的難度所在。

webkit內核現在都不支持解析WebP格式的圖片,這里主要采用的iOS系統的NSURLProtocol來替換其網絡請求(不了解NSURLProtocol,可以動動自己勤勞的小手Google一下),再將網絡回包數據進行轉碼成jpg或者png(為了透明度),再返回給webview進行渲染的。

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

同樣的,iOS在此處依然不對gif進行任何處理。

另外,NSURLProtocol會攔截全局的網絡流量,為避免誤傷,這里需要多帶帶識別是否是WebView發起的請求,可以通過識別request中的UA是否包含”AppleWebKit”來實現。

@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。

下面,會自動調用startLoading方法,這里采用了一個非常特別的方式處理

- (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直接接管圖片請求,手動finishLoading。

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

所謂圖片格式,是采用何種解碼編碼方式決定的,所有數據最終一定是變成二進制數據,NSData;
既然UIWebView不支持解碼WebP,我們可以讓圖片在網絡中以WebP格式的NSData傳遞,本地收到data后,解碼成UIWebView可以識別的UIImage;事實上,Native方面就是這么做就可以達到目標了,然而在WebView的請求中,無論我們本地做了何種處理,最終交給WebView的也一定是NSData,所以,需要再把UIImage編碼成jpg或者png(之所以我們沒有把gif也轉WebP,就是因為從WebP的動圖UIImage,轉碼成NSData這條路走不通,于是我們放棄了gif轉WebP)。

所以,大致的數據路徑如下:

本地發送WebP請求 ---> Server ---> 返回WebP格式Data ---> Data經谷歌的WebP decode得到UIImage ---> 將UIImage對象編碼成JPG或PNG格式NSData ---> 替換本應交給WebView的WebP格式Data ---> WebView接收JPG或PNG格式Data ---> 渲染圖片

在最開始,這里并不是這么寫的,當時是在系統的

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

方法中轉碼處理。按這個思路寫,代碼越寫越散,BUG也越來越多。所以,換了個思路,既然SD可以支持WebP,為什么不用他來全面托管呢?

這樣的話,原生請求和WebView的圖片緩存也可以經由SD統一起來,所以,這應該是一個好的方案。

這樣的話,WebP的所有請求都已經可以處理(wifi預加載暫時不管,因為是自己寫的downloader,替換URL后直接改把緩存指向修改就可以),之后要處理緩存的問題

4. 圖片緩存處理

以前的代碼已經實現了內部文章的緩存,包含js、css以及image等。這里通過NSURLCache來實現。相應的,基于WebP的圖片緩存的讀取也應該在NSURLCache中處理,在先處理完URL后,用新的Key來進行映射。

這里建議所有基于WebView的流量優化都最好用UA的判斷包住,避免帶來問題。因為無論NSURLProtocol還是NSURLCache都是全局網絡控制。

篇幅略長,具體緩存處理放在下一篇介紹。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/61792.html

相關文章

  • <轉載>圖片流量節省60%:基于CDNsharpP自適應圖片技術實踐

    摘要:開啟驗證上傳一張新圖片,使用手安卓版本訪問已支持域名的圖片,如果請求帶了,檢查返回圖片格式是否為如果舊的圖片未按預期返回,返回了或原圖可能是結點緩存,正常天后過期回源則會返回圖片。 對于圖片較多的網站,本文結合具體案例給出了如何基于CDN的sharpP自適應圖片無痛接入方案,據統計效果可在原圖基礎上節省60%-75%的流量。作者:陳忱 出處:騰云閣文章 目前移動端運營素材大部分依賴圖...

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

    摘要:在客戶端基于圖片格式的流量優化上這篇文章中,已經介紹了格式圖片的下載使用,僅僅只有這樣還遠遠不夠,還需要對已經下載的圖片數據進行緩存。二圖片緩存關于的緩存,系統提供了一個類,。而且,既然是全局影響,肯定要用包起來,防止誤傷其他緩存。 在iOS 客戶端基于 WebP 圖片格式的流量優化(上)這篇文章中,已經介紹了WebP格式圖片的下載使用,僅僅只有這樣還遠遠不夠,還需要對已經下載的圖片數...

    JiaXinYi 評論0 收藏0
  • 【譯】 WebP 支持:超出你想象

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

    Steven 評論0 收藏0

發表評論

0條評論

harryhappy

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<