http://blog.csdn.net/y550918116j/article/details/49619847
當你在項目中想嵌入網頁時,可以使用UIWebView類嵌入Web內容。你只需要創建一個UIWebView對象,并將它附加到一個view窗口。你還可以使用這個類來執行頁面歷史的前進或后退。
本文主要介紹關于UIWebView的基礎,包括:加載網頁、實現代理以及JS和OC的互相調用。
1 準備工作
我已經為大家創建了html頁面的源代碼,只需要復制到記事本,并將文件名改為index.html。
這個頁面有輸入框、按鈕和做顯示用的,其簡單功能是在輸入框輸入數據,點擊按鈕后顯示到顯示區域。
在瀏覽器運行可以看到如下效果。
1.2 搭建項目
這個地方就不詳細描述了,創建一個簡單項目->拉一個UIWebView到界面->UIWebView指向UIViewController的屬性名。
搭建后的核心部分如下,這里我使用的VC名為BaseVC。
#import"BaseVC.h"@interfaceBaseVC() @property(weak,nonatomic)IBOutletUIWebView*webView;///< UIWebView
@end@implementationBaseVC
- (void)viewDidLoad {
[superviewDidLoad];
}@end
2 顯示Web頁面
將我們創建好的index.html拉到項目中,至于位置就隨你高興了。
然后我們改造BaseVC的viewDidLoad方法。
- (void)viewDidLoad {
[superviewDidLoad];
// 找到index.html的路徑
NSURL*url = [[NSBundlemainBundle] URLForResource:@"index"withExtension:@"html"];
NSURLRequest*urlRequest = [NSURLRequestrequestWithURL:url];// url的位置[self.webViewloadRequest:urlRequest];// 加載頁面
}
由于我們的html頁面在項目里面,我們可以直接使用[NSBundle mainBundle]去尋找。如果你使用的是網咯連接“www.baidu.com”,你可以這樣獲得NSURL。
url =[NSURL URLWithString:@"www.baidu.com"];
然后運行項目,就可以看到和瀏覽器一樣的效果。
3 代理UIWebViewDelegate
UIWebView也有代理,如果你不懂什么是代理模式,查閱我的博文《23設計模式之代理模式(Proxy)》。我們在UIWebViewDelegate發現了四個方法。
__TVOS_PROHIBITED@protocolUIWebViewDelegate
@optional
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType;
- (void)webViewDidStartLoad:(UIWebView*)webView;
- (void)webViewDidFinishLoad:(UIWebView*)webView;
- (void)webView:(UIWebView*)webView didFailLoadWithError:(nullableNSError*)error;
@end
這四個代理的作用分別是:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;:
將要加載一個web頁面,返回yes代表繼續加載,no代表不加載。
- (void)webViewDidStartLoad:(UIWebView *)webView;:
開始加載web頁面;
- (void)webViewDidFinishLoad:(UIWebView *)webView;:
加載web頁面結束;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error;:
加載web頁面出錯,你可以在error看到錯誤信息。
現在我們改造BaseVC。下面都只顯示核心代碼,不重要的代碼不顯示。
@interfaceBaseVC()<UIWebViewDelegate>
@property(weak,nonatomic)IBOutletUIWebView*webView;///< UIWebView
@end
@implementationBaseVC
- (void)viewDidLoad {
? ? ? ? ?[superviewDidLoad];
? ? ? ? // 找到index.html的路徑
? ? ?NSURL*url = [[NSBundlemainBundle] URLForResource:@"index"withExtension:@"html"];
NSURLRequest*urlRequest = [NSURLRequestrequestWithURL:url];// url的位置self.webView.delegate=self;// 代理UIWebViewDelegate
[self.webViewloadRequest:urlRequest];// 加載頁面
}
#pragma mark - UIWebViewDelegate#pragma mark 開始加載網頁
- (void)webViewDidStartLoad:(UIWebView*)webView {
? ? ? ?NSLog(@"%@", NSStringFromSelector(_cmd));
}
#pragma mark 網頁加載完成
- (void)webViewDidFinishLoad:(UIWebView*)webView {
? ? ? NSLog(@"%@", NSStringFromSelector(_cmd));
}
#pragma mark 網頁加載出錯
- (void)webView:(UIWebView*)webView didFailLoadWithError:(nullableNSError*)error {
? ? ? ? NSLog(@"%@:%@", NSStringFromSelector(_cmd), error.localizedDescription);
}
#pragma mark 網頁監聽
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
? ? ? ? NSLog(@"%@", NSStringFromSelector(_cmd));returnYES;
}
@end
運行后你會看到如下的輸出,也體現了三種回調的順序。如果你看到了其他輸出信息,我想你可能出錯了,請查閱前面的介紹,修改后再運行。
webView:shouldStartLoadWithRequest:navigationType:
webViewDidStartLoad:
webViewDidFinishLoad:
4 JS和OC互動
js和oc互動是一件很麻煩的事,畢竟是兩種不同的開發語言。oc調js很簡單,js回調oc就比較麻煩了。
oc調js:uiwebview就自帶這樣的方法
- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
js掉oc:我們都知道js可以控制頁面的跳轉,我們還可以在鏈接中攜帶參數。而UIWebView又支持攔截這些請求的操作,這就讓我們完美的實現了js調oc的操作。至于更高級的方法,我們在以后給大家介紹。
改變原有頁面的功能,我們要實現下列需求。
在輸入框輸入相關信息,點擊按鈕,將輸入的信息傳輸到oc中;
oc接受到信息后,通過oc調用js的功能將信息發到js;
js收到信息后,在頁面顯示相關信息。
由于js調用oc是通過url請求發送消息,所以,我們需要制定規范。只有符合我們規范的請求才會執行oc方法,否則不執行。
這里我使用的規范是ios::oc方法名::攜帶的參數。這樣我們在oc端,當發現這樣的請求時就開始攔截執行我們的操作。
我這里的三個參數,相信大家都能看懂,我是使用“::”分割,你也可以使用其他方式分割,或者組合你喜歡的規范。
接下來就是改造oc和js了。在BaseVC添加oc接受js調用的方法體,和改寫- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
#pragma mark - js調OC
- (void)jsCallOC:(NSString*)params {
? ? ? ? ? ? ? ?NSLog(@"%@:%@", NSStringFromSelector(_cmd), params);NSString*jsStr = [NSStringstringWithFormat:@"ocCallJS('%@')", params];
// oc調js
[self.webViewstringByEvaluatingJavaScriptFromString:jsStr];
}
#pragma mark 網頁監聽
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
? ? ? ? ? NSLog(@"%@", NSStringFromSelector(_cmd));
? ? ? // 過濾
? ? ?NSString*requestString = request.URL.absoluteString.stringByRemovingPercentEncoding;
? ? ?// 分割
? ? ? NSArray*urlComps = [requestString componentsSeparatedByString:@"::"];
if ( [urlComps count] ==3&& [@"ios"isEqualToString:[urlComps objectAtIndex:0]] ) {
? ? ? ? ? ? ? ?//解析約定的指令
? ? ? ? ? ? ? ?// 方法名
? ? ? ? ? ? ? NSString*methods = [NSStringstringWithFormat:@"%@:", [urlComps objectAtIndex:1]];
? ? ? ? ? ? ? ?SEL selector = NSSelectorFromString(methods);
? ? ? ? ? ? ? ?// 判斷類是否有方法
? ? ? ? ? ? ? ?if ( [BaseVC instancesRespondToSelector:selector]) {
? ? ? ? ? ? ? ? ? ? ? ? ? // 攜帶的參數
? ? ? ? ? ? ? ? ? ? ? NSString*params = [urlComps objectAtIndex:2];
? ? ? ? ? ? ? ? ? ? ? NSLog(@"JS調用OC代碼->UIWebView\n方法名:%@,參數:%@", methods, params);
? ? ? ? ? ? ? ? ? ? ? ? ? ?// 執行方法,攜帶參數
? ? ? ? ? ? ? ? ? ? ? ? ?[selfperformSelector:selector withObject:params];
? ? ? ? ? ? ? ? ?}else{
? ? ? ? ? ? ? ? ? ? ? ? ? ?NSLog(@"沒有提供調用的%@方法名",methods);
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ?returnNO;
? ? ? ? ? }
? ? ? ? ?returnYES;
}
[self performSelector:selector withObject:params];這段代碼的意思是執行當前頁面的方法體,并攜帶參數。我們使用通配的方式調用方法體,使代碼更優雅便捷。
然后改變js代碼。
運行項目,然后神奇的事情發生了,原來在app中嵌入網頁這么簡單。