iOS與HTML混編(端內(nèi)JS與OC交互)基礎(chǔ)

iOS與HTML混編,最好的例子就是網(wǎng)易新聞詳情頁(yè)的實(shí)現(xiàn),圖片與文字可以根據(jù)服務(wù)器返回的數(shù)據(jù)隨意排版,很方便
本文主要講WKWebView,與UIWebView和JavaScriptCore孰優(yōu)孰劣我就不比較了,
網(wǎng)易新聞頁(yè)實(shí)現(xiàn)流程我就不重復(fù)寫了,還有其他好的文章放在最后,
但感覺大多說(shuō)的不細(xì),對(duì)沒有web開發(fā)經(jīng)驗(yàn)的來(lái)說(shuō)有點(diǎn)難懂,所以本文會(huì)把我寫的一些簡(jiǎn)單的js代碼拿出來(lái),對(duì)沒有web基礎(chǔ)的來(lái)說(shuō)更加清晰

本文的基礎(chǔ)知識(shí)主要為:
1.點(diǎn)擊html按鈕,oc的控制器dismiss掉
2.點(diǎn)擊oc按鈕,js切換頁(yè)面
3.點(diǎn)擊html按鈕,js切換頁(yè)面
4.點(diǎn)擊html的div標(biāo)簽,js調(diào)用oc來(lái)present一個(gè)新的controller,上面有個(gè)返回按鈕,點(diǎn)擊可以返回webView的控制器
點(diǎn)擊獲取源代碼

效果圖就不放了,創(chuàng)建幾個(gè)文件把代碼全部復(fù)制一下就可以看到效果了

我是文件列表

ViewController中有個(gè)按鈕,點(diǎn)擊即可跳轉(zhuǎn)到WebVC.
WebVC的.m文件,其中值得注意的是WKDelegate,是解決WKWebView循環(huán)引用問(wèn)題的代理

#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(@"無(wú)循環(huán)引用");
    //這里需要注意,前面增加過(guò)的方法一定要remove掉。
    //addScriptMessageHandler要和removeScriptMessageHandlerForName配套出現(xiàn),否則會(huì)造成內(nèi)存泄漏。
    [self.userContent removeScriptMessageHandlerForName:@"ocMethod"];
    [self.userContent removeScriptMessageHandlerForName:@"presentMethod"];
}

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

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

    //將UserContent設(shè)置到配置文件中
    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];
    
    //添加一個(gè)返回按鈕
    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調(diào)用oc的處理地方。我們可以根據(jù)name和body,進(jìn)行橋協(xié)議的處理。
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    NSString *messageName = message.name;
    if ([@"ocMethod" isEqualToString:messageName])
    {
        id messageBody = message.body;
        NSLog(@"%@",messageBody);
        //點(diǎn)擊html按鈕,讓當(dāng)前webView頁(yè)面dismiss掉
        [self dismissViewControllerAnimated:YES completion:nil];
    }
    else if([@"presentMethod" isEqualToString:messageName])
    {
        id messageBody = message.body;
        NSLog(@"%@",messageBody);
        //彈出一個(gè)新的紅色背景的控制器
        UIViewController *newVC = [[UIViewController alloc]init];
        newVC.view.backgroundColor = [UIColor redColor];
        
        //添加一個(gè)返回按鈕,返回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];
}
//點(diǎn)擊oc按鈕,調(diào)用js方法
-(void)back
{
    //第一種:直接調(diào)用
    //無(wú)論web頁(yè)面跳轉(zhuǎn)多少次,只要按鈕存在,js都可以生效
    [self.webView evaluateJavaScript:@"function sayHello(){     \
                                            alert('jack')     \
                                        }                       \
                                        sayHello()"
                   completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        
    }];
    
    //第二種:直接調(diào)用html文件中的js代碼
    //注意:這種方式只有在第一個(gè)web頁(yè)面js才能生效,跳轉(zhuǎn)到第二個(gè)web頁(yè)面就無(wú)效了
    //因?yàn)轫?yè)面跳轉(zhuǎn)后,就不是我們引入的本地的html頁(yè)面了,自然也就引入不了我們本地的js代碼
    //不過(guò)也正常,我們一般只需要在第一個(gè)頁(yè)面添加一個(gè)返回按鈕,dismiss掉這個(gè)webView,其他的功能都可以用html的按鈕實(shí)現(xiàn)
    [self.webView evaluateJavaScript:@"hello()"completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        
    }];
    
    //第三種:調(diào)用html文件中引入的js文件的js代碼
    //注意:js效果與第二種相同
    [self.webView evaluateJavaScript:@"back()"completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        
    }];
}

//wkWebView直接調(diào)用js的彈窗是無(wú)效的,需要攔截js中的alert,用oc的方式展現(xiàn)出來(lái)
//該方法中的message參數(shù)就是我們JS代碼中alert函數(shù)里面的參數(shù)內(nèi)容
- (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) {
        //一定要調(diào)用下這個(gè)block,否則會(huì)崩
        //API說(shuō)明: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互調(diào)</title>
            <link href="index.css" rel="stylesheet">
    </head>
    <body>
        <button onclick="clickBtn()"> 點(diǎn)擊按鈕跳轉(zhuǎn)到baidu </button>
        <br>
        <button onclick="dismiss()"> 點(diǎn)擊按鈕dismiss回去 </button>
        <!--導(dǎo)航-->
        <div >
            <ul>
                <div class="time"  onclick="clickTime()">點(diǎn)擊我present一個(gè)新的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函數(shù)文件-->
        <script src="index.js" type="text/javascript"></script>
        <!--直接寫的js函數(shù)-->
        <script type="text/javascript">
            function hello(){
                alert("你好!");
            }
        </script>

    </body>
</html>

index.js文件

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

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

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

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

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

最后是無(wú)關(guān)緊要的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;
}

比較好的鏈接,也介紹了一些第三方框架:
這個(gè)實(shí)現(xiàn)網(wǎng)易新聞詳情頁(yè)寫的很詳細(xì),所以我就不寫了.但是注意這里遺漏了解決循環(huán)引用問(wèn)題,練習(xí)的時(shí)候要注意:<a href="http://www.itdecent.cn/p/75f3abd40cc1">iOS-使用WKWebview實(shí)現(xiàn)新聞詳情頁(yè)</a>

<a href="http://www.itdecent.cn/p/1f2dc3d3090a">iOS WKWebView導(dǎo)致ViewController不調(diào)用dealloc方法</a>

WKWebView并不會(huì)去NSHTTPCookieStorage中讀取cookie,因此導(dǎo)致cookie丟失解決辦法:<a href="http://www.itdecent.cn/p/4fa8c4eb1316">IOS進(jìn)階之WKWebView</a>

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,414評(píng)論 4 61
  • 前言 關(guān)于UIWebView的介紹,相信看過(guò)上文的小伙伴們,已經(jīng)大概清楚了吧,如果有問(wèn)題,歡迎提問(wèn)。 本文是本系列...
    Dark_Angel閱讀 29,507評(píng)論 67 291
  • 前言 iOS開發(fā)中,用來(lái)顯示一個(gè)html頁(yè)、H5頁(yè),經(jīng)常會(huì)用的一個(gè)控件是WebView。說(shuō)到WebView,你知道...
    Dark_Angel閱讀 23,736評(píng)論 31 287
  • 最近一段時(shí)間斷斷續(xù)續(xù)地下著雨,再者項(xiàng)目難以騰出時(shí)間,如此便找到了暫停跑步的借口,而全然不顧自己的懶惰??墒且欢螘r(shí)間...
    叔丙仄閱讀 454評(píng)論 1 5
  • 夜深人靜,百無(wú)聊賴,偶翻某社交軟件,看看他們生活的世界。 慢慢地好多事情都變得與己無(wú)關(guān),漸漸地從生活的積極分子淪落...
    丏莫閱讀 222評(píng)論 0 0

友情鏈接更多精彩內(nèi)容