現在有很多的應用已經采用了WebView和html語言結合的開發模式。html5一直很火因為一份代碼可以在多個平台上運用啊,效果各不相同都很美觀,也越來越有一些公司直接招后台程序員和html5程序員,做完的產品再安卓也能用iOS也能用,不用再招雙份的工程師了。應用程序一進去就全是UIWebView,里面發個請求到自己用html5做的頁面,這就是一個應用!當然今天的主要不是說html5,是說html語言中JS代碼和OC代碼之間的傳值。
先舉例一個簡單的用法:
我在模仿網易彩票做到設置頁面的 常見問題板塊時,扒到的素材是一個html網頁格式的
也就是說只要設置好了這些按鈕點進去都是一個頁面,只是每一個按鈕都綁定了一個 html.id的屬性 ,會html語言的都知道 有了id屬性可以直接跳到頁面的該位置。
如圖點擊進入后 會跳到這個界面,點擊了如何充值按鈕,頁面會自動跳到如何充值頂着邊。如果點擊了如何購彩,頁面也會自動跳到自動購彩頂着邊。當然了如果倒數第二個倒數第一個估計就跳不上去了,因為下面已經見底了拖上去會彈回來的所以跳不上去了,這點和C#開發的時候是一樣的。
此功能的做法:
// 建立webView UIWebView *web = (UIWebView *)self.view; // 發送請求前需要請求和請求的鏈接 NSURL *url = [[NSBundle mainBundle] URLForResource:_html.html withExtension:nil]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; // $$$$$ [web loadRequest:request]; web.delegate = self;
首先要有webView啊,我是手碼創建的
上面html是我的模型,html模型里html是一個鏈接打開本地的一個web文件。你也可以自己找好鏈接做一個plist再做一個模型
發送請求,接收數據之后,用webView加載數據
然后再給自己的webView設置代理為自己,然后遵守協議UIWebViewDelegate,就可以實現代理方法了
- (void)webViewDidFinishLoad:(UIWebView *)webView
這個方法在頁面加載完成后會調用,在這個方法中來做些js的操作。
想做js的操作,一般都是先把你想要的js代碼拼接接出一個字符串,再用這個方法傳入這個字符串完成操作
// 拼接一個腳本語言中的 自動定位代碼 NSString *javascript = [NSString stringWithFormat:@"window.location.href = '#%@'",_html.ID]; // 加載完成后執行這個代碼 [webView stringByEvaluatingJavaScriptFromString:javascript];
里面的html.ID是字符串中的一個id屬性,控制往哪跳的。
這樣核心功能就完成了。
下面再說一個高級點的用法
這是我在模仿網易新聞時做到的新聞詳情界面,
如圖點擊其中的這個庫里上籃這一行,進入的新聞詳情頁面是用html做的,扒到的數據就是這樣了,但是數據只有亂七八糟的一大串字符,需要自己排版的,特別是圖文混排有點麻煩。。這里今天就不說了,今天主要說下JS和OC間如何傳值,關於圖文混排 過幾天有時間了再詳細寫一篇。(歡迎關注我評論我)
進去之后是一個新聞詳情頁面,里面是有圖片的,有的圖片很好看我就想保存,但是問題來了,webView里面的圖片都是<div><img height= src=></img>什么什么的不是UI控件按鈕可以綁定事件,imgView至少也可以監聽手勢點擊,這個是網頁啊,如何做到點擊圖片下面彈出一個shit問你保不保存?
這就用到JS代碼和OC代碼見的傳值了,
一般大概思路是這邊發請求,那邊把請求攔下來,再扒出請求url里的字符串,再各種截取得到有用的數據
核心思路如下,從一半開始截的
NSString *onload = @"this.onclick = function() {" " window.location.href = 'sx:src=' +this.src;" "};"; [imgHtml appendFormat:@"<img onload=\"%@\" width=\"%f\" height=\"%f\" src=\"%@\">",onload,width,height,detailImgModel.src]; // 結束標記 [imgHtml appendString:@"</div>"]; // 替換標記 [body replaceOccurrencesOfString:detailImgModel.ref withString:imgHtml options:NSCaseInsensitiveSearch range:NSMakeRange(0, body.length)]; } return body;
其中onload就是加載完畢后才用,然后onclick是JS里的點擊觸發,window.location.href 是跳往哪里,后面是一個url 里面的協議頭是sx:src= 后面是自己圖片的src。 SX是我自己的符號。
就相當於我自己亂寫了一個協議頭sx://www.啥 ,有了協議頭這就是一個跳轉網頁的請求 但是要注意的是,我把// 和www啥的省略了 但是前面這個sx:src=不能再省略了,如果再省略就不是協議頭了,蘋果就會自己給你加一個他的協議頭很長很亂 后面接不住了。
然后寫這個方法 ,webView的代理方法
這個方法是在即將發送請求時會被調用,返回值是一個BOOL類型,說白了就是讓你控制什么請求允許發出去,什么請求攔下。
NSString *url = request.URL.absoluteString; NSRange range = [url rangeOfString:@"sx:src="]; if (range.location != NSNotFound) { NSInteger begin = range.location + range.length; NSString *src = [url substringFromIndex:begin]; [self savePictureToAlbum:src]; return NO; } return YES;
先取出這個請求的全url再算出sx:src=這個字符串的范圍,如果是別的真正的請求,是取不到值的,就是NSNotFound,這是允許發出去的
如果取到range了 那就是我寫的這個請求,就從這個范圍往后的字符串全截取下來,這就是html代碼里那個圖片的地址了this.src。
然后有了url鏈接就可以保存到相冊了。
保存到相冊那個方法里,有兩種選擇一種是重新下載保存,一種是從緩存中取,這種比較省流量。
NSURLCache *cache =[NSURLCache sharedURLCache]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:src]]; NSData *imgData = [cache cachedResponseForRequest:request].data; UIImage *image = [UIImage imageWithData:imgData]; UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
應該都能看懂的吧,大意就是通過這個url找到我上次請求中用這個url弄到的響應數據再轉化成圖片保存入相冊。
到此就完成了JS與OC間的傳值
當然如果只有這樣那還遠遠不夠
這里是只有一個保存圖片的方法,如果以后又有很多需要攔截的方法,打電話或者發短信等各種各樣的方法,都要一一判斷就太麻煩了。
聰明的做法是把 需要調用的方法名 和 要傳的參數 都通通寫在url里讓我攔
比如sx:call:&10086
然后我通過字符串的切割就可以 得到一個方法名 call:和一個參數10086
就可以調用- (void)call:(NSString *)phoneNumber 這個方法了。
NSRange range = [url rangeOfString:@"sx:"]; if (range.location != NSNotFound) { NSUInteger loc = range.location + range.length; NSString *path = [url substringFromIndex:loc]; // 獲得方法和參數 NSArray *methodNameAndParam = [path componentsSeparatedByString:@"&"]; // 方法名 NSString *methodName = [methodNameAndParam firstObject]; // 調用方法 SEL selector = NSSelectorFromString(methodName); if ([self respondsToSelector:selector]) { // 判斷方法的目的: 防止因為方法不存在而報錯
這一串代碼寫的很清楚了,獲得方法名和參數,把字符串轉化成SEL 然后下面就可以這么寫了
調用打電話方法 call 傳的值是 10086
如果遇到了有的方法需要傳多個值。那就該這么寫
sx:sendMsg:body:&18686652446&loveyou
通過切割可以得到方法名是 sendMsg:body: 要傳的參數用&切開 就是這個(componentsSeparatedByString:@"&")得到兩個參數電話號碼和信息內容
然后就可以調用這個方法了
這里我要說一下
如果要傳入3個4個好多個參數,要用到一個第三方框架
// Copyright (c) 2015年 shangxianDante. All rights reserved. // #import <Foundation/Foundation.h> @interface NSObject (Extension) - (id)performSelector:(SEL)selector withObjects:(NSArray *)objects; @end
// Copyright (c) 2015年 shangxianDante. All rights reserved. // #import "NSObject+Extension.h" @implementation NSObject (Extension) - (id)performSelector:(SEL)selector withObjects:(NSArray *)objects { NSMethodSignature *signature = [self methodSignatureForSelector:selector]; if (signature) { NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setTarget:self]; [invocation setSelector:selector]; for(int i = 0; i < [objects count]; i++){ id object = [objects objectAtIndex:i]; [invocation setArgument:&object atIndex: (i + 2)]; } [invocation invoke]; if (signature.methodReturnLength) { id anObject; [invocation getReturnValue:&anObject]; return anObject; } else { return nil; } } else { return nil; } } @end
然后就可以用這個方法啦
最后我想再說個簡單的小技巧
就是因為現在html5很火,就是一份代碼在電腦是一個界面在手機又是一個界面,很漂亮。有時候可以直接搬過來用但是最下面的頁腳(也許是廣告)又不想要,就可以直接截了,把人家網站搬過來再把人家的頁腳截了,有意思吧
- (void)viewDidLoad { [super viewDidLoad]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://v3.bootcss.com/"]]; self.webView.delegate = self; [self.webView loadRequest:request]; } #pragma mark - ******************** web代理方法 /** * 網頁加載完畢后調用 */ - (void)webViewDidFinishLoad:(UIWebView *)webView { NSString *js = @"document.getElementsByTagName('footer')[0].remove();"; [webView stringByEvaluatingJavaScriptFromString:js];
當然首先你肯定要用瀏覽器的開發者工具找到頁腳這部分板塊的名字叫footer啊,然后截了。
(董鉑然博客所有文章都是原創歡迎評論和關注)