关于wkwebview与html5交互

本文详细对比了UIWebview与WKWebview在与HTML5交互时的区别,包括代理方法、数据传递方式、弹框处理、本地路径导入及跨页操作等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       之前写过web与html5的交互,那时的载体是UIWebview,基于uiwebview属于比较老旧的网页载体,且内存消耗比较大,故今日打算把UIWebview替换成WKwebview,起初只认为是换个类名那么简单,替换过程才发现,是自己想的太简单了,下面来说说uiweb与wkweb与html5交互时的异同(注:这篇文章只是针对原生与html5交互,且UIWebview与原生交互用的是javascriptcore框架):

一,关于代理方法与传值

uiwebview常用的是UIWebviewDelegate 与JSExport,wkwebview常用的是WKSCriptMessageHandler,WKNavigationDelegate,WKUIDelagete。

 1, UIWebview的UIWebviewDelegate与WKWebview的WKNavigationDelegate功能相似,体现网页的加载周期;这两个协议里的都有网页在不同阶段里的代理方法,现列出如下:

   1》页面准备加载:UIWebViewDelegate - webView:shouldStartLoadWithRequest:navigationType相当于 WKNavigationDelegate - webView:didStartProvisionalNavigation:

   2》网页已开始加载:UIWebViewDelegate - webViewDidStartLoad: 相当于WKNavigationDelegate - webView:didCommitNavigation:

   3》页面全部加载:WKNavigationDelegate - webView:didCommitNavigation:相当于WKNavigationDelegate - webView:didFinishNavigation 

   4》页面加载失败:UIWebViewDelegate - webView:didFailLoadWithError:相当于WKNavigationDelegate - webView:didFailNavigation:withError:或者WKNavigationDelegate - webView:didFailProvisionalNavigation:withError:

如果你之前只是用到了以上列出的 UIWebViewDelegate 中的几个方法,那么只是简单地换一个方法名,让你的 ViewController 继承 WKNavigationDelegate ,继续用就可以了。

2,UIWebView的JSExport与WKWebview的WKSCriptMessageHandler都是与js交互的;

   UIWebview与js交互分为js向oc传数据与oc向js传数据。而这双向的传值方法,都是声明在遵守JSExport的在自定义协议中,当然这个自定义协议中的代理方法也都是自定义的。而WKwebview的WKSCriptMessageHandler协议中只有一个系统的方法,这个代理方法只能用来接收js传到原生的数据,而原生要想给js传数据,需要用WKWebViewConfiguration这个类对象的userContentController属性(此属性是WKUserContentController类型的),举个��:

1》UIWebview

     oc给js传数据:(1)oc端:在遵守JSExport的自定义协议中声明一个方法-(void)getJsonText;

                              (2)oc端:在web的控制器的.m文件实现该方法,实现此方法时,通过jsContex创建了JSValue类型的对象,此对象即为js中的一个全局的方法

                                       -(void)getJsonText{

                                                   JSValue *getJsonTextJsMethod =self.jsContext[@"getJsonTextJsMethod"];

                                                   NSArray *array =@[@“你好吗”];

                                                  NSString *string = [[NSStringalloc]initWithFormat:@"%@",array[0]];

                                                  [getJsonTextJsMethodcallWithArguments:array];

                                         }

                           (3)js端:在js里调用getJsonText方法,并在getJsonTextJsMethod中接收oc端来的数据                                                            

                                     $(document).ready(function() { jsInterface.getJsonText()}   //调用自定义协议的代理方法

                                    var getJsonTextJsMethod =function(json){}   // json即为从oc端来的数据

    js给oc传数据:(1)oc端:在遵守JSExport的自定义协议中声明一个方法-(void)gotoNext:(NSString*)string;

                            (2)oc端:在web的控制器的.m文件实现该方法

                                           -(void)gotoNext:(NSString*)string{NSLog(@"gotoNex:%lu",string);}  //参数string即为从js传到oc端的数据

                            (3)js端:在适当的地方给自定义代理方法的参数赋值即可,此参数即为要传输的数据;  

                                           jsInterface.gotoNext(‘很好啊’);

2》WKwebView

  wkwebview与js交互时,创建web的方式与uiwebview有所区别,创建方式如下:              

                                    WKWebViewConfiguration *config = [[WKWebViewConfigurationalloc] init];

                                    self.webView = [[WKWebViewalloc] initWithFrame:[UIScreenmainScreen].boundsconfiguration:config];

                                    并设置两个代理  self.webView.navigationDelegate =self;  self.webView.UIDelegate =self;

      oc给js传数据:(1) oc端:WKWebview的 evaluateJavaScript方法,调用js的全局方法,如下

                                [self.webViewevaluateJavaScript:@"jsMethodTwo('你好吗')"completionHandler:nil]   //jsMethod为js的全局方法,此方法的参数即为要传的数据

                               (2)js端:在js的全局方法中获取传来的数据     

                                function jsMethodTwo(msg) {parseJson(msg);}   // msg即为传过来的数据,内容为'你好吗'

      js给oc传数据:(1)oc端:创建WKUserContentController类实例,并将passFromJsToOC添加到类此实例对象中,如下

                                                           WKWebViewConfiguration *config = [[WKWebViewConfigurationalloc] init];

                                                            WKUserContentController *userCC = config.userContentController

                                                           [userCCaddScriptMessageHandler:selfname:@"passFromJsToOC"]

                               (2)js端:调用如下方法:window.webkit.messageHandlers."oc中添加到WKUserContentController的方法名".postMessage('要传的数据'),距离如下

                                window.webkit.messageHandlers.passFromJsToOC.postMessage('文字')  //passFromJsToOC为添加到WKUserContentController类的实例对象

                               (3)js端:在wkwebview的WKScriptMessageHandler协议的代理方法-(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{}中,接收js传过来的数据,如下:

                                     -(void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{ self.myString = message.body;}  //注 message.body即为传过来的数据

二,关于弹框

1》UIWebview:

 h5代码与原生oc交互时,调试是个很令人头疼的问题,h5的代码要拷贝到我们本地的文件中,h5的逻辑层js在我们的工程中打断点不好使,调试起来很受罪啊!还好js端有alert,这个alert弹框在UIWebview交互时还是挺给力的;

2》WKWebview:

上边提到的alert是原生与h5交互的利器,可是在WKWebview时却不好使了,在此我们就不得不提那个叫做WKUIDelegate的协议了,我们需要实现此协议的代理方法,此协议关于弹窗的代理方法有三个,分别针对js端不同的弹框,当然与我们调试相关性最大的就是提示框alert了,其他两个弹框分别是确认框confirm以及输入框prompt;这三种弹框分别对应着三个不同的代理方法,代理方法里要实现的东西就感觉比较恶心了,在代理方法里我们需要创建oc原生的对应的弹窗,真不知道wkwebview为何要这么弄一下。js弹框与之对应的代理方法及代理方法内的实现如下:

 2.1》js的提示框alert  对应的代理方法及其实现是:

-(void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{

    UIAlertController *alertController = [UIAlertControlleralertControllerWithTitle:@"提示"message:message?:@""preferredStyle:UIAlertControllerStyleAlert];

    [alertController addAction:([UIAlertActionactionWithTitle:@"确认"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *_Nonnull action) {

        completionHandler();

    }])];

    [selfpresentViewController:alertControlleranimated:YEScompletion:nil];

}


 2.2》js的确认框confirm  对应的代理方法及其实现如下:

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {

    UIAlertController *alert = [UIAlertControlleralertControllerWithTitle:@"确认框"message:message preferredStyle:UIAlertControllerStyleAlert];

    [alert addAction:[UIAlertActionactionWithTitle:@"确定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *_Nonnull action) {

        completionHandler(YES);

    }]];

    [alert addAction:[UIAlertActionactionWithTitle:@"取消"style:UIAlertActionStyleCancelhandler:^(UIAlertAction *_Nonnull action) {

        completionHandler(NO);

    }]];

    [selfpresentViewController:alert animated:YEScompletion:NULL];

}

2.3》js的输入框 对应的代理方法及实现如下:

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler {

    UIAlertController *alert = [UIAlertControlleralertControllerWithTitle:@"输入框"message:prompt preferredStyle:UIAlertControllerStyleAlert];

    [alert addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {

        textField.textColor = [UIColorblackColor];

        textField.placeholder = defaultText;

    }];

    [alert addAction:[UIAlertActionactionWithTitle:@"确定"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *_Nonnull action) {

        completionHandler([[alert.textFieldslastObject] text]);

    }]];

    [alert addAction:[UIAlertActionactionWithTitle:@"取消"style:UIAlertActionStyleCancelhandler:^(UIAlertAction *_Nonnull action) {

        completionHandler(nil);

    }]];

    [selfpresentViewController:alert animated:YEScompletion:NULL];

}

当然了,如果不使用这个代理也是可以的,你可以先将你想要弹出的内容传到原生oc端,在收到js传来消息的代理方法里弹弹框,当然也是原生的弹框。

三、关于html5导入本地的路径

这个与web的载体无关,无论UIWebview与WKWebview都有这个问题

html5放在本地交互时,如果将html5文件整个的按group的形式导入,在加载本地html5时,js与css都没有出现,后闭门造车的发现把html文件中引入的js与css的路径去掉之后,ok,问题解决了,于是乎,以为万事ok了,最近在捣鼓WKWebview的时候,发现其实有其他更好的方法去解决这个问题。只需要在导入html5文件时换个方法就可以了,导入过程如下:

1》 以group的方式导入父文件夹


2》以folder的方式导入子文件夹,即css js html文件夹


3》导入结果截图如下:


按上述方式到文件后,运行正常,ok问题解决

四、关于oc顶用js的方法问题(只针对于WKWebview evaluateJavaScript):

上边提到WKWebview的oc调用js的方法用的是evaluateJavaScript,调用js的方法分以下情况:

1》调用js无参数的方法(对于交互似乎没啥意义):

oc端 [self.wkWebViewevaluateJavaScript:@"alertMobile()"completionHandler:nil]

js端 function alertMobile() {}

2》调用js有参数的方法(用参数传数据)

[self.wkWebViewevaluateJavaScript:@"alertName('小红')"completionHandler:nil]

function alertName(msg) {alert( msg)

3》调用js有参数的方法(用参数传数据,用返回值对oc端做回执)

[self.wkWebViewevaluateJavaScript:@"alertSendMsg('哈喽')" completionHandler:^(id result,NSError * _Nullable error) {NSLog(@"返回的值是:%@",result);}]

function alertSendMsg(num,msg) { document.getElementById('msg').innerHTML ='这是我的手机号:' + num +',' + msg + '!!'return'nihaoma';}

result即为js方法返回的nihaoma

感觉这个回执挺有用的,省去alert查看了

五、关于加载本地html并操控本地html跳页

这个题目五有点烦人啊,乍看一脸茫然吧,是的,这种跳转方式我也感觉一脸愕然。是的,就是这样设计的,客户端加载本地a页面之后如果想跳的本地b网页,是由客户端操控的,并不是我们平时那样的非本地的链接方式或本地的href方式,而是超出于宇宙之上的第三种方式--客户端控制,并给下一页传报文。

1》UIWebview:

 需要前面提到的自定义协议里的代理方法了,跳转下一页事件中,js传值给oc,在oc获取值时跳转,然后按给js传值的方式传报文给js,当然这需要在网页初始加载的时候传过去

2》WKWebview:

这个就需要研究下web的加载周期了,依旧是在跳转下一页事件中,js传值给oc,在oc获取值时按加载前页的方式加载第二页,这是后报文就得跟上节奏适时传给js了,这个传报文的位置没有UIwebview那么自动了,我们需要在第一页页面加载完成的时候(即如下代理方法)把第二页需要的报文按上述相应传值方式传过去。

-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{}

五、关于oc给js传数据的数据格式

这里只说WKWebview,UIWebview没有这个问题

WKWebview中oc在给js传值时,传的数据不能有\n,否则传不过去,如果你要穿的是报文之类的数据,千万要遍历一遍这个数据去掉里边的换行,否则是传不过来的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值