開發(fā)中一些界面如果使用OC代碼進(jìn)行編寫會(huì)十分復(fù)雜,我們經(jīng)常會(huì)使用到webView來(lái)呈現(xiàn)一個(gè)事先用HTML編寫好的網(wǎng)頁(yè)文件,通過Javascript實(shí)現(xiàn)OC(UIWebView/WKWebView)間的交互
在iOS 8中蘋果提供了WKWebView來(lái)替代UIWebView,解決了UIWebView內(nèi)存飆升等問題,這里暫時(shí)還是先以UIWebView進(jìn)行演示,主要是由于UIWebView比較簡(jiǎn)單
UIWebView代理方法所實(shí)現(xiàn)的功能都很直觀,分別是:
__TVOS_PROHIBITED @protocol UIWebViewDelegate <NSObject>
@optional
// Javascript間接調(diào)用OC方法需要使用,通過該代理方法攔截URL
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
// 開始加載
- (void)webViewDidStartLoad:(UIWebView *)webView;
// 加載完成 ,在這里執(zhí)行Javascript函數(shù)
- (void)webViewDidFinishLoad:(UIWebView *)webView;
// 加載失敗
- (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error;
項(xiàng)目準(zhǔn)備:
1.提前編寫一個(gè)html網(wǎng)頁(yè)文件,這里演示的功能十分簡(jiǎn)單,可以通過Mac自帶的Apache搭建本地服務(wù)器,也可以直接導(dǎo)入工程,這里為了演示效果,就直接將html導(dǎo)入工程來(lái)進(jìn)行演示
2.HTML頁(yè)面搭建效果及實(shí)現(xiàn)功能:
如圖,視圖中的四個(gè)按鈕分別是通過Javascript實(shí)現(xiàn)的4個(gè)函數(shù):
1.點(diǎn)擊加入購(gòu)物車
2.訪問URL
3.點(diǎn)擊彈出一個(gè)提示框,類似于OC的UIAlertController
4.求和運(yùn)算
HTML文件代碼:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript">
// 窗口提示
function alertMessage(){
alert("點(diǎn)擊了我");
}
// 求和運(yùn)算函數(shù)
function sum(a,b){
alert(a+b);
return a+b
}
// 跳轉(zhuǎn)網(wǎng)頁(yè)
function goMyPage(){
window.location.href = "http://www.reibang.com/users/5ec5747435a2/latest_articles";
}
</script>
</head>
<body>
<h1>Javascript與OC交互Demo</h1>
<br/>
<br/>
<br/>
iPhone 56 <input type="button" value="點(diǎn)擊加入購(gòu)物車" />
<div style="color: red">
點(diǎn)擊加入購(gòu)物車,在App中跳轉(zhuǎn)新頁(yè)面<br/>
</div>
<hr/>
<input type="button" value="去我的個(gè)人主頁(yè)" onclick="javascript:goMyPage()"/>
<hr/>
<input type="button" value="點(diǎn)擊彈出提示框" onclick="javascript:alertMessage()"/>
<hr/>
<input type="button" value="計(jì)算:10+21=?" onclick="javascript:sum(10,21);"/>
<hr/>
</body>
</html>
3.HTML界面搭建完成及函數(shù)功能實(shí)現(xiàn)后,接下來(lái)將進(jìn)行OC間交互的演示
$3.1 在OC執(zhí)行Javascript函數(shù)中,將使用到- (void)webViewDidFinishLoad:(UIWebView *)webView
代理方法
$3.2 在Javascript執(zhí)行OC方法中,將使用到- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
代理方法
-
OC執(zhí)行Javascript函數(shù)
在這里會(huì)需要用到UIWebView的代理方法:
WebView加載完成時(shí)調(diào)用:- (void)webViewDidFinishLoad:(UIWebView *)webView
演示效果: 當(dāng)啟動(dòng)App后,不需要手動(dòng)點(diǎn)擊按鈕便直接執(zhí)行Javascript函數(shù)
示例代碼:
#import "JSWebViewController.h"
@interface JSWebViewController () <UIWebViewDelegate>
@property (nonatomic,weak) UIWebView *webView;
@end
@implementation JSWebViewController
- (void)loadView{
self.view = [[UIWebView alloc] init];
self.view.backgroundColor = [UIColor js_colorWithHex:0xFFF8DC];
}
- (void)viewDidLoad{
[super viewDidLoad];
self.webView = (UIWebView *)self.view;
// 本地Apache服務(wù)器
// NSString *urlString = @"http://localhost:63342/demo(HTML)/JS與OC交互Demo.html";
// NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
// [self.webView loadRequest:[NSURLRequest requestWithURL:url]];
// NSString *filePath = [[NSBundle mainBundle]pathForResource:@"JS與OC交互Demo.html" ofType:nil];
// NSString *htmlString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL];
// [self.webView loadHTMLString:htmlString baseURL:[[NSBundle mainBundle] bundleURL]];
// 項(xiàng)目?jī)?nèi)資源
NSURL *url = [[NSBundle mainBundle] URLForResource:@"JS與OC交互Demo.html" withExtension:nil];
[self.webView loadRequest:[NSURLRequest requestWithURL:url]];
self.webView.delegate = self;
}
#pragma mark - UIWebViewDelegate
// 加載完成 ,在這里執(zhí)行Javascript函數(shù)
- (void)webViewDidFinishLoad:(UIWebView *)webView{
// 這里調(diào)用了"點(diǎn)擊彈出提示框"的函數(shù)(第三個(gè)按鈕)來(lái)進(jìn)行演示,實(shí)際就是將HTML中調(diào)用alertMessage()方法的代碼粘貼了過來(lái)(按照J(rèn)avascript中規(guī)定的格式)
[webView stringByEvaluatingJavaScriptFromString:@"javascript:alertMessage()"];
}
-
Javascript(間接)執(zhí)行OC方法
在這里會(huì)需要用到UIWebView的代理方法:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
返回YES--->表示讓webView 去加載這個(gè)請(qǐng)求
返回NO--->表示這個(gè)請(qǐng)求我們自己處理了, webView就不再去加載對(duì)應(yīng)請(qǐng)求
通過該代理方法,攔截URL進(jìn)行處理,當(dāng)滿足某一條件時(shí),我們?cè)贠C中調(diào)用內(nèi)部的某一方法,一般情況下,為了與標(biāo)準(zhǔn)的URL進(jìn)行區(qū)分,我們可以自定義一個(gè)URL
e.g. cart:///buy/iPhone56/10000
接下來(lái)通過"點(diǎn)擊添加購(gòu)物車"按鈕對(duì)HTML文件中的代碼進(jìn)行修改:
為"點(diǎn)擊添加購(gòu)物車"按鈕定義一個(gè)函數(shù):
//添加到購(gòu)物車
function goCart(){
// 自己定義的URL
window.location.href = "cart:///buy/10000";
}
按鈕點(diǎn)擊功能實(shí)現(xiàn),調(diào)用goCart
函數(shù):
<input type="button" value="去我的個(gè)人主頁(yè)" onclick="javascript:goMyPage()"/>
這樣HTML文件編寫完,開始在OC中進(jìn)行代碼處理
演示效果:
在加載完WebView后,點(diǎn)擊網(wǎng)頁(yè)內(nèi)部按鈕時(shí),如果請(qǐng)求的URL為我剛剛自定義的cart:///buy/10000
,則Push一個(gè)新的控制器(不影響其他WebView的展示)
示例代碼:
#pragma mark - 攔截URL后執(zhí)行的OC方法
- (void)demoMethod{
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [UIColor js_randomColor];
[self.navigationController pushViewController:viewController animated:YES];
}
#pragma mark - UIWebViewDelegate
// Javascript間接調(diào)用OC方法需要使用,通過該代理方法攔截URL
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
if ([request.URL.scheme isEqualToString:@"cart"]) {
// 執(zhí)行OC方法
[self demoMethod];
return NO;
}
return YES;
}
這樣就實(shí)現(xiàn)了在點(diǎn)擊網(wǎng)頁(yè)中的按鈕時(shí),間接的執(zhí)行了OC的方法
-
傳遞參數(shù)
對(duì)上邊的Javascript執(zhí)行OC方法在進(jìn)行一些改動(dòng),實(shí)現(xiàn)參數(shù)的傳遞
需求:將自定義URLcart:///buy/iPhone56/10000
中的iPhone56
和10000
作為參數(shù)傳遞到OC方法中,push到新界面后作為數(shù)據(jù)呈現(xiàn)
這里隨便自定義了一個(gè)View,放了兩個(gè)Label來(lái)展示數(shù)據(jù)
首先以一個(gè)URL為例,對(duì)URL中常見屬性做一下說(shuō)明:
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com/search?id=1"];
NSLog(@"scheme:%@", [url scheme]); // 協(xié)議頭字符串 http
NSLog(@"host:%@", [url host]); // 域名 www.baidu.com
NSLog(@"absoluteString:%@", [url absoluteString]); // 完整的url字符串 http://www.baidu.com:8080/search?id=1
NSLog(@"relativePath: %@", [url relativePath]); // 相對(duì)路徑 search
NSLog(@"port :%@", [url port]); // 端口 8080
NSLog(@"path: %@", [url path]); // 路徑字符串,不包含協(xié)議頭炮车、主機(jī)地址瘦穆、頓口和參數(shù) search
NSLog(@"pathComponents:%@", [url pathComponents]); // 路徑組成部分的數(shù)組 search
NSLog(@"Query:%@", [url query]); // 查詢參數(shù)字符串 id=1
所以我們只需要將URL中的路徑組成部分抽取出來(lái)作為參數(shù)傳遞到方法中即可,至于抽取方法以及傳遞方式可以根據(jù)自己的方式來(lái)處理,這里為了演示,就隨便添加到一個(gè)數(shù)組中來(lái)傳遞演示了
示例代碼:
// 帶參數(shù)
- (void)demoMethodWithParameters:(NSArray *)parameters{
UIViewController *viewController = [[UIViewController alloc] init];
JSCartView *view = [[JSCartView alloc] init];
view.data = parameters;
viewController.view = view;
[self.navigationController pushViewController:viewController animated:YES];
}
#pragma mark - UIWebViewDelegate
// Javascript間接調(diào)用OC方法需要使用,通過該代理方法攔截URL
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
if ([request.URL.scheme isEqualToString:@"cart"]) {
NSMutableArray *tempArr = [NSMutableArray array];
[request.URL.pathComponents enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (idx >= 2) {
[tempArr addObject:obj];
}
}];
// 執(zhí)行OC方法
//[self demoMethod];
[self demoMethodWithParameters:tempArr];
return NO;
}
return YES;
}