iOS與HTML混編(端內JS與OC交互)基礎

iOS與HTML混編,最好的例子就是網易新聞詳情頁的實現,圖片與文字可以根據服務器返回的數據隨意排版,很方便
本文主要講WKWebView,與UIWebView和JavaScriptCore孰優孰劣我就不比較了,
網易新聞頁實現流程我就不重復寫了,還有其他好的文章放在最后,
但感覺大多說的不細,對沒有web開發經驗的來說有點難懂,所以本文會把我寫的一些簡單的js代碼拿出來,對沒有web基礎的來說更加清晰

本文的基礎知識主要為:
1.點擊html按鈕,oc的控制器dismiss掉
2.點擊oc按鈕,js切換頁面
3.點擊html按鈕,js切換頁面
4.點擊html的div標簽,js調用oc來present一個新的controller,上面有個返回按鈕,點擊可以返回webView的控制器
點擊獲取源代碼

效果圖就不放了,創建幾個文件把代碼全部復制一下就可以看到效果了

我是文件列表

ViewController中有個按鈕,點擊即可跳轉到WebVC.
WebVC的.m文件,其中值得注意的是WKDelegate,是解決WKWebView循環引用問題的代理

#import "WebVC.h"
#import <WebKit/WebKit.h>
#import "WKDelegateController.h"

@interface WebVC ()<WKUIDelegate,WKNavigationDelegate,WKDelegate>

@property (strong, nonatomic) WKWebView *webView;
@property (strong, nonatomic) WKUserContentController *userContent;
@property (weak, nonatomic) UIButton *backBtn;
@end

@implementation WebVC

- (void)dealloc
{
    NSLog(@"無循環引用");
    //這里需要注意,前面增加過的方法一定要remove掉。
    //addScriptMessageHandler要和removeScriptMessageHandlerForName配套出現,否則會造成內存泄漏。
    [self.userContent removeScriptMessageHandlerForName:@"ocMethod"];
    [self.userContent removeScriptMessageHandlerForName:@"presentMethod"];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor lightGrayColor];
    
    //創建配置
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    //創建UserContentController(提供javaScript向webView發送消息的方法)
    self.userContent = [[WKUserContentController alloc] init];

    //添加消息處理,
    //注意: addScriptMessageHandler后面的參數指代的是需要遵守WKScriptMessageHandler協議,結束時需要移除
    //但無論在哪里移除都會發現dealloc并不會執行,這樣肯定是不行的,會造成內存泄漏
    //試了下用weak指針還是不能釋放,不知道是什么原因
    //因此參考百度上的寫法是用一個新的controller來處理,新的controller再繞用delegate繞回來,即使沒移除也會走dealloc了
    WKDelegateController * delegateController = [[WKDelegateController alloc]init];
    delegateController.delegate = self;
    [self.userContent addScriptMessageHandler:delegateController  name:@"ocMethod"];
    [self.userContent addScriptMessageHandler:delegateController  name:@"presentMethod"];

    //將UserContent設置到配置文件中
    config.userContentController = self.userContent;
    //配置webView
    self.webView = [[WKWebView alloc]initWithFrame:self.view.bounds configuration:config];
    self.webView.UIDelegate = self;
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];
    //加載本地html
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"html"];
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    [self.webView loadRequest:urlRequest];
    
    //添加一個返回按鈕
    UIButton *backBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 35, 50, 50)];
    [backBtn setTitle:@"返回" forState:UIControlStateNormal];
    [backBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [backBtn addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
    self.backBtn = backBtn;
    [self.webView addSubview:backBtn];
}

//這里就是使用高端配置,js調用oc的處理地方。我們可以根據name和body,進行橋協議的處理。
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSString *messageName = message.name;
    if ([@"ocMethod" isEqualToString:messageName])
    {
        id messageBody = message.body;
        NSLog(@"%@",messageBody);
        //點擊html按鈕,讓當前webView頁面dismiss掉
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    else if([@"presentMethod" isEqualToString:messageName])
    {
        id messageBody = message.body;
        NSLog(@"%@",messageBody);
        //彈出一個新的紅色背景的控制器
        UIViewController *newVC = [[UIViewController alloc]init];
        newVC.view.backgroundColor = [UIColor redColor];
        
        //添加一個返回按鈕,返回webView
        CGRect rect = CGRectMake(100,100,100,50);
        UIButton *button = [[UIButton alloc]initWithFrame:rect];
        [button setTitle:@"返回" forState:UIControlStateNormal];
        [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        button.titleLabel.font = [UIFont systemFontOfSize:20];
        [button addTarget:self action:@selector(dismissNewVC) forControlEvents:UIControlEventTouchUpInside];
        [newVC.view addSubview:button];

        [self presentViewController:newVC animated:YES completion:nil];
    }
}

//返回方法
-(void)dismissNewVC
{
    [self dismissViewControllerAnimated:YES completion:nil];
}
//點擊oc按鈕,調用js方法
-(void)back
{
    //第一種:直接調用
    //無論web頁面跳轉多少次,只要按鈕存在,js都可以生效
    [self.webView evaluateJavaScript:@"function sayHello(){     \
                                            alert('jack')     \
                                        }                       \
                                        sayHello()"
                   completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        
    }];
    
    //第二種:直接調用html文件中的js代碼
    //注意:這種方式只有在第一個web頁面js才能生效,跳轉到第二個web頁面就無效了
    //因為頁面跳轉后,就不是我們引入的本地的html頁面了,自然也就引入不了我們本地的js代碼
    //不過也正常,我們一般只需要在第一個頁面添加一個返回按鈕,dismiss掉這個webView,其他的功能都可以用html的按鈕實現
    [self.webView evaluateJavaScript:@"hello()"completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        
    }];
    
    //第三種:調用html文件中引入的js文件的js代碼
    //注意:js效果與第二種相同
    [self.webView evaluateJavaScript:@"back()"completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        
    }];
}

//wkWebView直接調用js的彈窗是無效的,需要攔截js中的alert,用oc的方式展現出來
//該方法中的message參數就是我們JS代碼中alert函數里面的參數內容
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
    NSLog(@"----------%@",message);
    
    UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"js的彈窗" message:message preferredStyle:UIAlertControllerStyleAlert];
    [alertView addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        //一定要調用下這個block,否則會崩
        //API說明:The completion handler to call after the alert panel has been dismissed
        completionHandler();
    }]];
    [self presentViewController:alertView animated:YES completion:nil];
}

@end

WKDelegateController.h文件:

#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>
@class WKDelegateController;

@protocol WKDelegate <NSObject>

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

@end

@interface WKDelegateController : UIViewController <WKScriptMessageHandler>

@property (weak , nonatomic) id<WKDelegate> delegate;

@end

WKDelegateController.m文件

#import "WKDelegateController.h"

@interface WKDelegateController ()

@end

@implementation WKDelegateController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    if ([self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)])
    {
        [self.delegate userContentController:userContentController didReceiveScriptMessage:message];
    }
}

index.html文件

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
            <title>js與oc互調</title>
            <link href="index.css" rel="stylesheet">
    </head>
    <body>
        <button onclick="clickBtn()"> 點擊按鈕跳轉到baidu </button>
        <br>
        <button onclick="dismiss()"> 點擊按鈕dismiss回去 </button>
        <!--導航-->
        <div >
            <ul>
                <div class="time"  onclick="clickTime()">點擊我present一個新的controller</div>
                <li><a  >baidu</a></li>
                <li><a href="#" >about</a></li>
                <li><a href="#" >services</a></li>
                <li><a href="#" >gallery</a></li>
                <li><a href="#" >contact</a></li>
            </ul>
        </div>

        <!--引入的js函數文件-->
        <script src="index.js" type="text/javascript"></script>
        <!--直接寫的js函數-->
        <script type="text/javascript">
            function hello(){
                alert("你好!");
            }
        </script>

    </body>
</html>

index.js文件

//確認js加載成功
window.onload = function (){
    alert(0);
}

//點擊html按鈕,調用js方法
function clickBtn(){
    window.location.;
}

//點擊html按鈕,調用oc方法
function dismiss(){
    window.webkit.messageHandlers.ocMethod.postMessage("我點擊html按鈕,調用oc的方法,讓webView消失");
}

//點擊html的div標簽,調用oc方法
function clickTime(){
    window.webkit.messageHandlers.presentMethod.postMessage("我點擊div標簽,調用oc的方法,彈出一個控制器");
}

//點擊oc按鈕,要調用的js方法
function back() {
    window.location.;
    
}

最后是無關緊要的index.css文件

*{
    padding = 0;
    margin = 0;
}

body{
    padding:100px 0 0 0;
    text-align:center;
    background-color:lightgray;
    font-size:40px;
}

button{
    font-size:50px;
}

li{
    list-style-type:none
}

a{
    font-size:50px;
}

比較好的鏈接,也介紹了一些第三方框架:
這個實現網易新聞詳情頁寫的很詳細,所以我就不寫了.但是注意這里遺漏了解決循環引用問題,練習的時候要注意:<a href="http://www.lxweimin.com/p/75f3abd40cc1">iOS-使用WKWebview實現新聞詳情頁</a>

<a href="http://www.lxweimin.com/p/1f2dc3d3090a">iOS WKWebView導致ViewController不調用dealloc方法</a>

WKWebView并不會去NSHTTPCookieStorage中讀取cookie,因此導致cookie丟失解決辦法:<a href="http://www.lxweimin.com/p/4fa8c4eb1316">IOS進階之WKWebView</a>

講UIWebView與JavaScriptCore細的文章:
<a href="http://www.lxweimin.com/p/d19689e0ed83">iOS下JS與原生OC互相調用(總結)</a>
<a >iOS JavaScriptCore使用</a>
<a href="http://www.lxweimin.com/p/84a6b1ac974a">iOS H5容器的一些探究(一):UIWebView和WKWebView的比較和選擇</a>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,739評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,634評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,653評論 0 377
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,063評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,835評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,235評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,315評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,459評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,000評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,819評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,004評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,560評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,257評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,676評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,937評論 1 288
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,717評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,003評論 2 374

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,154評論 4 61
  • 前言 關于UIWebView的介紹,相信看過上文的小伙伴們,已經大概清楚了吧,如果有問題,歡迎提問。 本文是本系列...
    Dark_Angel閱讀 28,981評論 67 291
  • 前言 iOS開發中,用來顯示一個html頁、H5頁,經常會用的一個控件是WebView。說到WebView,你知道...
    Dark_Angel閱讀 23,488評論 31 287
  • 最近一段時間斷斷續續地下著雨,再者項目難以騰出時間,如此便找到了暫停跑步的借口,而全然不顧自己的懶惰。可是一段時間...
    叔丙仄閱讀 422評論 1 5
  • 夜深人靜,百無聊賴,偶翻某社交軟件,看看他們生活的世界。 慢慢地好多事情都變得與己無關,漸漸地從生活的積極分子淪落...
    丏莫閱讀 204評論 0 0