iOS Native加載H5中的圖片

eee1397 8年前發布 | 37K 次閱讀 iOS開發 HTML Objective-C開發

來自: http://www.henishuo.com/ios-native-h5-img/

前言

最近iOS App項目中使用Webview加載H5頁面比較多,也有不少朋友經常問到這個問題,在這里我也學習學習如何通過iOS原生的方式來加載H5頁面中的圖片然后讓webview顯示圖片。

相信有很多朋友也遇到過這樣的問題,可是很多朋友都沒有思路,不知如何入手。今天,剛好學習了一下,并寫了一個簡單的demo。下面讓我們一起來學習一下吧!

本篇文章適合哪些人群閱讀?

  • 項目中有類似需求的,而又沒有思路的
  • 曾經做過類似需求的,可以參考兩者的思想有何異同,比較哪種方式更好
  • 沒有做過類似需求,且也沒有思路入手的,可以參考學習

注意:本文有Objective-C版和Swift,根據個人情況看相關章節

思路講解

這里有兩種方式可以實現:

  • 直接使用NSData同步加載圖片的方式( Swift版用同步實現
  • 通過其他第三方庫異步加載圖片的方式( ObjC版用異步實現

Swift版代碼講解

下面看看我們的核心代碼吧:

 
letpath = NSBundle.mainBundle().pathForResource("test",ofType: "html")
leturl = NSURL(fileURLWithPath: path!)
 
do {
  lethtml = tryString(contentsOfURL: url,encoding: NSUTF8StringEncoding)
  //      print(html)
  
  // 獲取所有img src中的src鏈接,并將src更改名稱
  // 這里直接采用同步獲取數據,異步也是一樣的道理,為了方便寫demo,僅以同步加載圖片為例。
  // 另外,這不考慮清除緩存的問題。
  do {
    letregex = tryNSRegularExpression(pattern: "<img\\ssrc[^>]*/>",options: .AllowCommentsAndWhitespace)
    
    letresult = regex.matchesInString(html,options: .ReportCompletion,range: NSMakeRange(0, html.characters.count))
    
    varcontent = htmlasNSString
    varsourceSrcs: [String: String] = ["": ""]
    
    for itemin result {
      letrange = item.rangeAtIndex(0)
      
      letimgHtml = content.substringWithRange(range) asNSString
      vararray = [""]
      
      if imgHtml.rangeOfString("src=\"").location != NSNotFound {
        array = imgHtml.componentsSeparatedByString("src=\"")
      } else if imgHtml.rangeOfString("src=").location != NSNotFound {
        array = imgHtml.componentsSeparatedByString("src=")
      }
      
      if array.count >= 2 {
        varsrc = array[1]as NSString
        if src.rangeOfString("\"").location != NSNotFound {
          src = src.substringToIndex(src.rangeOfString("\"").location)
          
          // 圖片鏈接正確解析出來
          print(src)
          
          // 加載圖片
          // 這里不處理重復加載的問題,實際開發中,應該要做一下處理。
          // 也就是先判斷是否已經加載過,且未清理掉該緩存的圖片。如果
          // 已經緩存過,否則才執行下面的語句。
          letdata = NSData(contentsOfURL: NSURL(string: src asString)!)
          letlocalUrl = self.saveImageData(data!,name: (srcasString).md5)
          
          // 記錄下原URL和本地URL
          // 如果用異步加載圖片的方式,先可以提交將每個URL起好名字,由于這里使用的是原URL的md5作為名稱,
          // 因此每個URL的名字是固定的。
          sourceSrcs[srcasString] = localUrl
        }
      }
    }
    
    for (src, localUrl) in sourceSrcs {
      if !localUrl.isEmpty {
        content = content.stringByReplacingOccurrencesOfString(srcasString,withString: localUrl,options: NSStringCompareOptions.LiteralSearch,range: NSMakeRange(0, content.length))
      }
    }
    
    print(contentasString)
    webView.loadHTMLString(contentasString,baseURL: url)
  } catch {
    print("match error")
  }
} catch {
  print("load html error")
}
 

NSData同步加載圖片

可以直接通過NSData來加載圖片,加載完成后,將圖片保存到本地:

 
// 加載圖片
// 這里不處理重復加載的問題,實際開發中,應該要做一下處理。
// 也就是先判斷是否已經加載過,且未清理掉該緩存的圖片。如果
// 已經緩存過,否則才執行下面的語句。
letdata = NSData(contentsOfURL: NSURL(string: src asString)!)
letlocalUrl = self.saveImageData(data!, name: (srcasString).md5)
 

異步加載圖片

這里的Demo中沒有使用異步加載圖片,其實與同步沒有多大的差別,在這里只是說一下思路,具體開發時,也是很容易套用的。這里很巧妙地使用HTML中的原始圖片URL作為Key,而原始圖片URL的md5值作為圖片的名稱,但是只要我們將圖片都統一存儲到同一個沙盒中的同一個目錄下,那么每個圖片存儲到本地后的名稱就是固定的了。因此,我們就可以在匹配到所有的 <img src="..."/> 之后,取得src的值,然后將這個url進行md5加密,再獲取document目錄的路徑,就可以得到這個url在異步加載好圖片后存儲下來的名稱,那么我們就可以在異步加載圖片之前,先修改這個url為本地存儲的路徑。剩下的就不用多說了吧。

在處理加也需要存儲本地圖片路徑與網頁中的圖片鏈接,并通過鍵值對的方式來關聯起來。

 
// 記錄下原URL和本地URL
// 如果用異步加載圖片的方式,先可以提交將每個URL起好名字,
// 由于這里使用的是原URL的md5作為名稱,
// 因此每個URL的名字是固定的。
sourceSrcs[srcasString] = localUrl
 

在獲取HTML中原始URL與本地圖片的存儲路徑關聯值后,就可以將HTML中的所有原始url替換成我們ios沙盒中存儲的圖片路徑,如下:

 
for (src, localUrl) in sourceSrcs {
  if !localUrl.isEmpty {
    content = content.stringByReplacingOccurrencesOfString(srcasString, withString: localUrl, options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, content.length))
  }
}
 

當我們已經全部將HTML中原始的圖片路徑都替換成ios沙盒中存儲的圖片路徑后,就可以通過Webview加載了:

 
webView.loadHTMLString(contentasString, baseURL: url)
 

ObjC版代碼講解

首先,我們要獲取HTML內容,并通過正則表達式來匹配出所有的 <img src="..."/> 的標簽:

 
NSURL *url = [[NSBundle mainBundle]URLForResource:@"test"withExtension:@"html"];
NSString *html = [[NSString alloc]initWithContentsOfURL:urlencoding:NSUTF8StringEncodingerror:nil];
  
NSRegularExpression *regex = [NSRegularExpressionregularExpressionWithPattern:@"<img\\ssrc[^>]*/>"options:NSRegularExpressionAllowCommentsAndWhitespaceerror:nil];
  
NSArray *result = [regexmatchesInString:htmloptions:NSMatchingReportCompletionrange:NSMakeRange(0, html.length)];
 

接下來,我們需要一個字典來存儲HTML原始的URL和與之關聯的本地URL。由于使用原始URL的md5值作為文件名字,因此本地路徑也就唯一確定了。這里就將圖片都放到Document下。

 
NSMutableDictionary *urlDicts = [[NSMutableDictionary alloc]init];
NSString *docPath = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents"];
 

然后,我們需要遍歷所有匹配到的 <img src="..."/> 標簽,并提取出Src屬性值,也就是我們要的原始URL。將并該URL存儲下來,以便下一步替換。

 
  for (NSTextCheckingResult *item in result) {
    NSString *imgHtml = [htmlsubstringWithRange:[itemrangeAtIndex:0]];
    
    NSArray *tmpArray = nil;
    if ([imgHtmlrangeOfString:@"src=\""].location != NSNotFound) {
      tmpArray = [imgHtmlcomponentsSeparatedByString:@"src=\""];
    } else if ([imgHtmlrangeOfString:@"src="].location != NSNotFound) {
      tmpArray = [imgHtmlcomponentsSeparatedByString:@"src="];
    }
    
    if (tmpArray.count >= 2) {
      NSString *src = tmpArray[1];
      
      NSUInteger loc = [srcrangeOfString:@"\""].location;
      if (loc != NSNotFound) {
        src = [srcsubstringToIndex:loc];
        
        NSLog(@"正確解析出來的SRC為:%@", src);
        if (src.length > 0) {
          NSString *localPath = [docPathstringByAppendingPathComponent:[selfmd5:src]];
          // 先將鏈接取個本地名字,且獲取完整路徑
          [urlDictssetObject:localPathforKey:src];
        }
      }
    }
  }
 

下一步,我們需要將HTML中所有的原始src的url值替換成我們app的沙盒中的圖片路徑,如果該路徑中未存在,則需要去下載圖片,否則不需要重復下載。如下:

 
  // 遍歷所有的URL,替換成本地的URL,并異步獲取圖片
  for (NSString *src in urlDicts.allKeys) {
    NSString *localPath = [urlDictsobjectForKey:src];
    html = [htmlstringByReplacingOccurrencesOfString:srcwithString:localPath];
    
    // 如果已經緩存過,就不需要重復加載了。
    if (![[NSFileManager defaultManager]fileExistsAtPath:localPath]) {
      [selfdownloadImageWithUrl:src];
    }
  }
 

下載圖片后,還需要將圖片存儲到該原始url對應的本地路徑,也就是Document下,其文件名為原始url的md5值,其他也就可以得出去唯一路徑。這里只貼出存儲代碼,關于如何下載圖片,查看demo。

 
NSData *data = UIImagePNGRepresentation(image);
NSString *docPath = [NSHomeDirectory()stringByAppendingPathComponent:@"Documents"];
 
NSString *localPath = [docPathstringByAppendingPathComponent:[selfmd5:src]];
    
if (![datawriteToFile:localPathatomically:NO]) {
  NSLog(@"寫入本地失敗:%@", src);
}
 

難點

這里有幾處難點:

  • 如何匹配 <img src="..."/> 來查找圖片鏈接
  • 在匹配到以后,如何獲取src的值
  • 在得到src的值以后,如何在iOS原生獲取圖片后讓webview加載

這里使用了正則表達式來匹配查找 <img src="..."/> ,匹配結果可能有多個,遍歷數組就可以處理所有的圖片鏈接:

 
NSRegularExpression(pattern: "<img\\ssrc[^>]*/>", options: .AllowCommentsAndWhitespace
 

存儲圖片到沙盒

通過獲取到HTML中圖片的鏈接后,我們需要通過ios原生的方式來發起請求,加載圖片,在加載完成后,我們需要將圖片存儲到沙盒中document下:

 
funcsaveImageData(data: NSData,name: String) ->String {
  letdocPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]as NSString
  
  letpath = docPath.stringByAppendingPathComponent(name)
  
  // 若已經緩存過,就不需要重復操作了
  if NSFileManager.defaultManager().fileExistsAtPath(path) {
    return path
  }
  
  do {
    trydata.writeToFile(path,options: NSDataWritingOptions.DataWritingAtomic)
  } catch {
    print("save image data with name: \(name) error")
  }
  
  return path
}
 

驗證是否成功

首先我們可以看到test.html中只有兩個img標簽:

 
<imgsrc="http://www.jhjcqc.com/ueditor/php/upload/image/20151014/1444783819412910.jpg" />
 
<imgsrc="http://www.jhjcqc.com/ueditor/php/upload/image/20151014/1444783847836404.jpg" />
 

在我們替換路徑完成后,我們加載webview,然后打印出webview所加載的HTML內容中這兩個 <img> 標簽的src是否變化,結果如下:

 
<imgsrc="/Users/huangyibiao/Library/Developer/CoreSimulator/Devices/09692E07-2E79-4070-9537-CFD9F3141B0D/data/Containers/Data/Application/73F6D429-E0FD-4BD4-B0A5-85C1BD179840/Documents/5353c07f4c2ea0471b9f3ee36dedcaac" />
 
<imgsrc="/Users/huangyibiao/Library/Developer/CoreSimulator/Devices/09692E07-2E79-4070-9537-CFD9F3141B0D/data/Containers/Data/Application/73F6D429-E0FD-4BD4-B0A5-85C1BD179840/Documents/54edea1f2edd444aaba9d0321d786962" />
 

根據效果圖,我們可以看到圖片是顯示出來了,這就說明替換成功后仍然可以加載出來圖片,實驗成功。

源代碼

想要下載源代碼,請移步github下載,內有Swift版的工程和ObjC版的工程:

https://github.com/CoderJackyHuang/iOSLoadWebViewImage
 本文由用戶 eee1397 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!