OC(UIWebView)與JS交互

開發(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)功能:

html界面搭建.png

如圖,視圖中的四個(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ù)

OC調(diào)用JS函數(shù).png

示例代碼:

#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的展示)

Javascript執(zhí)行OC方法.gif

示例代碼:

#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中的iPhone5610000作為參數(shù)傳遞到OC方法中,push到新界面后作為數(shù)據(jù)呈現(xiàn)

Javascript執(zhí)行OC方法(帶參數(shù)).gif

這里隨便自定義了一個(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;
    
}

示例代碼:https://github.com/ShenYj/DemoList

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扛或,一起剝皮案震驚了整個(gè)濱河市碘饼,隨后出現(xiàn)的幾起案子悲伶,更是在濱河造成了極大的恐慌住涉,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件花沉,死亡現(xiàn)場(chǎng)離奇詭異媳握,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)忽媒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門腋粥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人隘冲,你說(shuō)我怎么就攤上這事“掠剩” “怎么了罗珍?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蘸朋。 經(jīng)常有香客問我扣唱,道長(zhǎng),這世上最難降的妖魔是什么炼彪? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任正歼,我火速辦了婚禮,結(jié)果婚禮上局义,老公的妹妹穿的比我還像新娘膜楷。我一直安慰自己贞奋,他們只是感情好穷绵,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布仲墨。 她就那樣靜靜地躺著,像睡著了一般目养。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上幻梯,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天努释,我揣著相機(jī)與錄音,去河邊找鬼煞躬。 笑死逸邦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的雷客。 我是一名探鬼主播烛卧,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼总放!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起甥啄,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤炬搭,失蹤者是張志新(化名)和其女友劉穎穆桂,沒想到半個(gè)月后融虽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡般又,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年茴迁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了萤衰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脆栋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出糖耸,到底是詐尸還是另有隱情丘薛,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布舍扰,位于F島的核電站希坚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏裁僧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一茬底、第九天 我趴在偏房一處隱蔽的房頂上張望获洲。 院中可真熱鬧,春花似錦、人聲如沸涉馁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)胯努。三九已至逢防,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忘朝,已是汗流浹背判帮。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悦昵,地道東北人晌畅。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像抗楔,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剩岳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 一、簡(jiǎn)介 近兩年隨著HTML5的迅速發(fā)展與日趨成熟,越來(lái)越多的移動(dòng)開發(fā)者選擇使用HTML5來(lái)進(jìn)行混合開發(fā)示弓,不僅節(jié)約...
    RainyGY閱讀 1,874評(píng)論 1 12
  • 隨著H5技術(shù)的興起呵萨,在iOS開發(fā)過程中,難免會(huì)遇到原生應(yīng)用需要和H5頁(yè)面交互的問題潮峦。其中會(huì)涉及方法調(diào)用及參數(shù)傳值等...
    Chris_js閱讀 3,088評(píng)論 1 8
  • 一忱嘹、簡(jiǎn)介 近兩年隨著HTML5的迅速發(fā)展與日趨成熟,越來(lái)越多的移動(dòng)開發(fā)者選擇使用HTML5來(lái)進(jìn)行混合開發(fā)拘悦,不...
    寶寶teacher閱讀 2,313評(píng)論 3 15
  • 首先要理清一下關(guān)系: HTML:一些網(wǎng)頁(yè)控件础米。 超文本標(biāo)記語(yǔ)言分苇,標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言(SGM或SGML)下的一個(gè)應(yīng)用屁桑。...
    goyohol閱讀 738評(píng)論 0 1
  • UIWebView與JS的交互蘑斧,說(shuō)白了就是Objective-C和JavaScript的相互調(diào)用。Objectiv...
    WillPan閱讀 5,377評(píng)論 2 30