最近因爲公司業務須要,須要在移動端調用JS去解析大衆點評網頁,同時抓取評論相關內容。對iOS與JS交互進行了研究,總結一下。javascript
技術點總結:html
首先,OC與JS的交互須要用到UIWebView來實現。java
技術點一:OC調用JS方法。jquery
這個其實在蘋果API中已經集成的很好了,只須要一個方法stringByEvaluatingJavaScriptFromString 就能夠了,去API中查看它是UIWebView的對象方法,須要傳入的參數爲NSString,這個字符串是所調用的JS方法的方法名。該方法的返回值一樣是一個字符串,爲JS方法的返回值。ios
技術點二:JS調用OC方法web
這個用到了WebView的代理方法app
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType;函數
網頁加載每個請求的時候都會調用這個方法,你能夠在JS中加載一個僞URL請求,實際上是事先協商好格式的字符串,這樣在iOS只須要解析這個請求,若是發現是事先協商好的格式的請求,那麼你就能夠去調用對應的方法了。ui
原理相對來講仍是比較簡單的,說說再具體實現中遇到的幾個坑點。編碼
坑點總結:
坑點一:由於須要把抓取到的大衆點評的網頁傳給JS方法,可是JS方法傳入參數長度大於480時就接收不到參數,具體緣由不明。
解決方法:for循環屢次調用這個方法,每次傳入480,用一個JS方法專門去接收並拼接成整個網頁的字符串。
坑點二:因爲以上for循環上傳html,可能恰好截到某些敏感的字符。
解決方法:以前是先總體轉義好的,截取時碰到仍是有可能碰到一些敏感字符,因此先截取再轉義。那麼截取的長度就須要稍微短一些,由於轉義完的字符仍是不能超過480。
坑點三:這個主要是JS的問題,返回的字符爲ASCII加密格式,一直在移動端解析不出來。
解決方法:只需在JS返回參數是用encodeURIComponent這個方法進行一下編碼就能夠了。
坑點四:大衆點評的網頁相同網址在電腦端訪問自動是電腦版,手機端自動是手機版,而手機版的評論條數比較少,這就須要咱們去用手機端去訪問到電腦版的網頁。
解決方法:須要將手機的UserAgent設置爲電腦端便可。
坑點五:像上面那樣設置了UserAgent,可是在其餘頁面還須要展現手機端的網頁,還須要在離開這個界面的時候將userAgent設置回去。
爲了清楚將代碼放在下方:
iOS代碼:
#import "ViewController.h"
#define kPCUserAgent @"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.7 Safari/537.36"
#define kAppUserAgent @"Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1C28 Safari/419.3"
@interface ViewController ()<UIWebViewDelegate>
{
UIWebView *myWebView;
}
@implementation ViewController
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// 確保在訪問別的點評網頁時是手機版
[[NSUserDefaults standardUserDefaults]registerDefaults:@{@"UserAgent":kAppUserAgent}];
}
- (void)viewDidLoad {
[super viewDidLoad];
myWebView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 0,320, 658)];
myWebView.delegate = self;
myWebView.autoresizingMask = UIViewAutoresizingFlexibleWidth| UIViewAutoresizingFlexibleHeight;
myWebView.scalesPageToFit = YES;
NSURLRequest *request= [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://p.test.aijee.cn/CApp1_4_5/changedpcomment"]];
[myWebView loadRequest:request];
[self.view addSubview:myWebView];
[[NSUserDefaults standardUserDefaults]registerDefaults:@{@"UserAgent":kPCUserAgent}];
// @"http://p.test.aijee.cn/CApp1_4_5/changedpcomment"
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
//網頁加載完成調用此方法
if (webView == myWebView) {
NSString *url =@"http://www.dianping.com/shop/4739340/";
NSString *appConnect = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:url] encoding:NSUTF8StringEncoding error:nil];
for (int i = 0; i < appConnect.length / 300 + 1; i++) {
NSRange range;
if (i == appConnect.length / 300) {
range = NSMakeRange(i * 300, appConnect.length - i * 300);
} else {
range = NSMakeRange(i * 300,300);
}
NSString *appContentString = [appConnect substringWithRange:range];
appContentString = [appContentString stringByReplacingOccurrencesOfString:@"\r" withString:@""];
appContentString = [appContentString stringByReplacingOccurrencesOfString:@"\n" withString:@""];
appContentString = [appContentString stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""];
appContentString = [appContentString stringByReplacingOccurrencesOfString:@"/" withString:@"\\/"];
NSString *string = [NSString stringWithFormat:@"changedpcomment('%@')",appContentString];
[webView stringByEvaluatingJavaScriptFromString:string];
}
NSString *string = [webView stringByEvaluatingJavaScriptFromString:@"changedpcomment2()"];
NSString *decodeString = [self decodeFromPercentEscapeString:string];
NSLog(@"result = %@",decodeString);
NSData *dataString = [decodeString dataUsingEncoding:NSUTF8StringEncoding];
NSArray *array = [NSJSONSerializationJSONObjectWithData:dataString options:NSJSONReadingAllowFragments error:nil];
NSLog(@"array = %@",array);
}
}
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *urlString = [[request URL] absoluteString];
urlString = [urlString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"urlString=%@",urlString);
NSArray *urlComps = [urlString componentsSeparatedByString:@"://"];
if([urlComps count] && [[urlComps objectAtIndex:0] isEqualToString:@"objc"])
{
NSArray *arrFucnameAndParameter = [(NSString*)[urlCompsobjectAtIndex:1] componentsSeparatedByString:@":/"];
NSString *funcStr = [arrFucnameAndParameter objectAtIndex:0];
if (1 == [arrFucnameAndParameter count])
{
// 沒有參數
if([funcStr isEqualToString:@"doFunc1"])
{
/*調用本地函數1*/
NSLog(@"doFunc1");
}
}
else
{
//有參數的
if([funcStrisEqualToString:@"getParam1:withParam2:"])
{
[self getParam1:[arrFucnameAndParameter objectAtIndex:1] withParam2:[arrFucnameAndParameter objectAtIndex:2]];
}
}
return NO;
}
return YES;
}
- (void)getParam1:(NSString*)str1 withParam2:(NSString*)str2
{
NSLog(@"收到html傳過來的參數:str1=%@,str2=%@",str1,str2);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
JS代碼:
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="content-type">
<title>js調用oc</title>
<script type="text/javascript" src="/js/jquery-1.8.0.min.js"></script>
<script type="text/javaScript">
</script>
</head>
<body>
<!--
<p><input type="text" id="text1" value="我來自ios蘋果"/></p>
<p><input type="text" id="text2" value="我來自earth地球"/></p>
<p><input type="button" id="enter" value="enter" onclick="testClick('getParam1:withParam2:');"/></p>
</body>
-->
<input onclick="changedpcomment2();" value="點擊" type="button">
<textarea rows="100" cols="10000" id="aaa">
</textarea>
</body>
<script src="/js/content.js"></script>
<script type="text/javascript">
//處理html 獲取評論
var aa = ""; // 全局變量 用於接收所有的html
// 獲取所有html的方法
function changedpcomment(html){
aa=aa+html;
}
// 具體去解析html的方法
function changedpcomment2(){
return encodeURIComponent(newData); // 將解析好的數據編好碼返回給OC
}
// 點擊按鈕,調用OC方法
function testClick(cmd)
{
var str1=document.getElementById("text1").value;
var str2=document.getElementById("text2").value;
window.location.href="objc://"+cmd+":/"+EncodeUtf8(str1)+":/"+EncodeUtf8(str2);
}
</script>
</html>