iOS原生与H5交互WKWebView

一、原生与H5页面交互方式

  1. 登陆后将token放入wkwebview的cookie中。以后wkwebview也可以同步原生app的登陆状态了。

以下代码   @"document.cookie = ‘UID=%@‘;document.cookie = ‘CLIENT=App‘;document.cookie = ‘TOKEN=%@‘" 根据自己项目的cookie格式传递。

 1     NSString *js = @"function clearCache(){localStorage.setItem(‘fundType‘,null);localStorage.setItem(‘fundTypeIndex‘,null);}clearCache();";
 2     NSString *cookie =
 3     [NSString stringWithFormat:@"document.cookie = ‘UID=%@‘;document.cookie = ‘CLIENT=App‘;document.cookie = ‘TOKEN=%@‘",
 4      [USER_DEFAULT objectForKey:KUSERUID] == nil ? @"":[USER_DEFAULT objectForKey:KUSERUID],[USER_DEFAULT objectForKey:KUSERTOKEN] == nil [email protected]"":[USER_DEFAULT objectForKey:KUSERTOKEN]];
 5     WKUserScript *cookieScript = [[WKUserScript alloc]
 6                                   initWithSource:cookie
 7                                   injectionTime:WKUserScriptInjectionTimeAtDocumentStart
 8                                   forMainFrameOnly:YES];
 9     [self.configuration.userContentController addUserScript:cookieScript];
10     [self reloadFromOrigin];

  2、审查wkwebview中的页面元素,提取wkwebview登陆页面中的登陆按钮所调用的JS代码(尽量向js开发人员要)

然后通过这句代码执行js:把参数传递到js中。让wkwebview执行js,wkwebview就登陆了。

以下代码  @"function clearCache(){localStorage.setItem(‘fundType‘,null);localStorage.setItem(‘fundTypeIndex‘,null);}clearCache();" 是纯js代码,ios程序可以直接使用。

1 NSString *js = @"function clearCache(){localStorage.setItem(‘fundType‘,null);localStorage.setItem(‘fundTypeIndex‘,null);}clearCache();";
2             [self.baseWebView evaluateJavaScript:js completionHandler:^(id _Nullable other, NSError * _Nullable error) {
3             }];

  3、通过该方法,截取H5页面将要请求的页面地址,来做原生相应的操作。这里可以让wkwebview跳转到“hello://uid=123_token=321”的方式来告诉原生,js传了2个参数:uid=123  token=321(注意,这里是以hello开头,可以写成你们商量好的)然后通过:decisionHandler(WKNavigationActionPolicyCancel);

不让wkwebview跳转到“hello://uid=123_token=321”。去做我们真正要做的事情。

 1 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
 2     NSString *str = navigationAction.request.URL.absoluteString;//获取当前正在请求的url
 4     if ([str isEqualToString:@"https://m.cgjr.com/"] && self.viewController.tabBarController.selectedIndex != 0) {
 5         decisionHandler(WKNavigationActionPolicyCancel);
 6         [self.viewController.tabBarController setSelectedIndex:0];
 7     }
 8     if ([str isEqualToString:@"https://m.cgjr.com/site/login.html"] && self.viewController.tabBarController.selectedIndex == 0) {
 9         decisionHandler(WKNavigationActionPolicyCancel);
10         UIStoryboard *sb = [UIStoryboard storyboardWithName:@"CGTZLogin" bundle:nil];
11         CGTZLoginViewController *navC = [sb instantiateViewControllerWithIdentifier:@"CGTZLoginViewController"];
12         navC.tabBarItem.title = @"登录";
13         [self.viewController presentViewController:navC animated:YES completion:^{
14         }];
15         [self.viewController.tabBarController setSelectedIndex:0];
16     }
17     if ([str isEqualToString:@"https://m.cgjr.com/site/login.html"] && self.viewController.tabBarController.selectedIndex == 1) {
18         decisionHandler(WKNavigationActionPolicyCancel);
19         UIStoryboard *sb = [UIStoryboard storyboardWithName:@"CGTZLogin" bundle:nil];
20         CGTZLoginViewController *navC = [sb instantiateViewControllerWithIdentifier:@"CGTZLoginViewController"];
21         navC.tabBarItem.title = @"登录";
22         [self.viewController presentViewController:navC animated:YES completion:^{
23         }];
24         [self.viewController.tabBarController setSelectedIndex:1];
25     }
26     if ([str isEqualToString:@"https://m.cgjr.com/site/login.html"] && self.viewController.tabBarController.selectedIndex == 2) {
27         decisionHandler(WKNavigationActionPolicyCancel);
28         UIStoryboard *sb = [UIStoryboard storyboardWithName:@"CGTZLogin" bundle:nil];
29         CGTZLoginViewController *navC = [sb instantiateViewControllerWithIdentifier:@"CGTZLoginViewController"];
30         navC.tabBarItem.title = @"登录";
31         [self.viewController presentViewController:navC animated:YES completion:^{
32         }];
33         [self.viewController.tabBarController setSelectedIndex:2];
34     }
35     decisionHandler(WKNavigationActionPolicyAllow);
36 }

  4、在IOS平台上使用js直接调用OC方法

在Cocos2d-JS v3.0 RC2中,与Android上js调用Java一样,Cocos2d-JS也提供了在iOS和Mac上js直接调用Objective-C的方法,示例代码如下:

    var ojb = jsb.reflection.callStaticMethod(className, methodNmae, arg1, arg2, .....);

jsb.reflection.callStaticMethod方法中,我们通过传入OC的类名,方法名,参数就可以直接调用OC的静态方法,并且可以获得OC方法的返回值。

  • 参数中的类名,只需要传入OC中的类名即可,与Java不同,类名并不需要路径。比如你在工程底下新建一个类NativeOcClass,只要你将他引入工程,那么他的类名就是NativeOcClass,你并不需要传入它的路径。
1 import <Foundation/Foundation.h>
2     @interface NativeOcClass : NSObject
3     +(BOOL)callNativeUIWithTitle:(NSString *) title andContent:(NSString *)content;
4     @end

方法

  • js到OC的反射仅支持OC中类的静态方法。
  • 方法名比较要需要注意,我们需要传入完整的方法名,特别是当某个方法带有参数的时候,你需要将他的**:**也带上。根据上面的例子。此时的方法名字是**callNativeUIWithTitle:andContent:**,不要漏掉了他们之间的**:**。
  • 如果是没有参数的函数,那么他就不需要**:**,如下代码,他的方法名是callNativeWithReturnString,由于没有参数,他不需要**:**,跟OC的method写法一致。

1 +(NSString *)callNativeWithReturnString;

使用示例

  • 下面的示例代码将调用上面NativeOcClass的方法,在js层我们只需要这样调用:
1     var ret = jsb.reflection.callStaticMethod("NativeOcClass",
2                                                "callNativeUIWithTitle:andContent:",
3                                                "cocos2d-js",
4                                                "Yes! you call a Native UI from Reflection");
  • 这里是这个方法在OC的实现,可以看到是弹出一个native的对话框。并把titlecontent设置成你传入的参数,并返回一个boolean类型的返回值。
1     +(BOOL)callNativeUIWithTitle:(NSString *) title andContent:(NSString *)content{
2         UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:content delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
3         [alertView show];
4         return true;
5     }
  • 此时,你就可以在ret中接受到从OC传回的返回值(true)了。

注意

在OC的实现中,如果方法的参数需要使用float、int、bool的,请使用如下类型进行转换:

  • float,int 请使用NSNumber类型
  • bool请使用BOOL类型。
  • 例如下面代码,我们传入2个浮点数,然后计算他们的合并返回,我们使用NSNumber而不是int、float去作为参数类型。
1 +(float) addTwoNumber:(NSNumber *)num1 and:(NSNumber *)num2{
2     float result = [num1 floatValue]+[num2 floatValue];
3     return result;
4 }
  • 目前参数和返回值支持 int, float, bool, string,其余的类型暂时不支持。

  5、wkwebview独有,跟uiwebview的  jscontext 相似的 WKScriptMessage

js端这样调用:红色部分

 1 function onLoaded(){
 2         changeImageSrc();
 3     var allImage = document.getElementsByClassName("img-cache");
 4         allImage = Array.prototype.slice.call(allImage, 0);
 5         var imageUrlsArray = new Array();
 6         allImage.forEach(function(image) {
 7             var esrc = image.getAttribute("esrc");
 8             if(esrc){
 9             var newLength = imageUrlsArray.push(esrc);
10             }
11         });
12         window.webkit.messageHandlers.XXXApp.postMessage({"key":"getImageUrlArr","getImageUrlArr":imageUrlsArray});
13
14 }onLoaded();

创建wkwebview时候:

 1         WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
 2         configuration.selectionGranularity = WKSelectionGranularityCharacter;
 3         configuration.userContentController   = userVC;
 4         [configuration.userContentController addScriptMessageHandler:self name:@"XXXApp"];//这里是iOS端的标识符
 5         WKWebView * webView                   = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, kSCreenWidth, kSCreenHeight-64) configuration:configuration];
 6         webView.navigationDelegate            = self;
 7         webView.UIDelegate                    = self;
 8         NSURL *url                            = [NSURL URLWithString:self.urlString];
 9         NSMutableURLRequest *request          = [[NSMutableURLRequest alloc]initWithURL:url];
10         [webView loadRequest:request];

需要实现的代理方法:

 1 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
 2     NSDictionary *dataDic = message.body;
 3     if ([dataDic[@"key"] isEqualToString:@"getImageUrlArr"]) {//根据key的键值对,判断调用哪一段代码
 4         NSArray *imageArr = dataDic[@"getImageUrlArr"];
 5         if (imageArr != nil) {
 6 //            js传过来的数组我们已经拿到了!,去做你想做的!
 7         }
 8     }
 9     if ([dataDic[@"key"] isEqualToString:@"imageDidClicked"]) {
10 //        [self imageDidClicked:dataDic[@"imageDidClicked"]];
11     }
12     if ([dataDic[@"key"] isEqualToString:@"imagesDownloadComplete"]) {
13     }
19 }

wkwebview相关参考资料:http://www.henishuo.com/wkwebview-js-h5-oc/

          (swift)http://www.henishuo.com/wkwebview-js/

WKWebView所有相关的类的API汉化: http://www.henishuo.com/wkwebview-objc/

以上一共5种交互方式,总有一种适合你。

时间: 2024-08-24 16:32:38

iOS原生与H5交互WKWebView的相关文章

iOS原生与H5交互

一.WKWebView WKWebView 初始化时,有一个参数叫configuration,它是WKWebViewConfiguration类型的参数,而WKWebViewConfiguration有一个属性叫userContentController,它又是WKUserContentController类型的参数. WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; config.preference

IOS 原生与HTML交互

跟原生开发相比,H5的开发相对来一个成熟的框架和团队来讲在开发速度和开发效率上有着比原生很大的优势,至少不用等待审核.那么问题来了,H5与本地原生代码势必要有交互的,比如本地上传一些信息,H5打开本地的页面,打开本地进行微信等第三方分享等,今天就简单讲一下iOS中本地UIWebView,WKWebView与H5的交互. DEMO地址:点击下载 UIWebView的交互 stringByEvaluatingJavaScriptFromString的使用 UIWebView在2.0时代就有的类,一直

ios和安卓H5交互桥接

ios交互 demo1(摘自网络) 1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"> 6 <

安卓原生与hml交互(WebView基础)

WebView加载页面 webView有两种加载方式, 加载网络地址 webView.loadUrl("www.xxx.com/index.html"); 加载本地资源 webView.loadUrl("file:///android_asset/example.html"); 添加请求头信息,在这里可以加入认证信息等等 Map<String,String> map=new HashMap<String,String>(); map.put(

iOS原生和H5的相互调用

为什么现在越来越多的APP中开始出现H5页面? 1,H5页面开发效率更高,更改更加方便: 2,适当缩小APP安装包的大小: 3,蹭热点更加方便,比如五一,十一,双十一搞活动: 那么为什么说H5无法取代原生的APP,只能处在一个共存的例子呢? 1,这个是由系统的底层决定的,极端例子,所有的应用都通过H5展示,那么你是否需要一个浏览器? 2,涉及庞大的功能,涉及复杂的逻辑结构,涉及安全性的要求,H5可以胜任吗? 所以,H5和原生的融合会出现动态的调和,最终会找到一个平衡. 那么接下来就说下iOS开发

webview和H5交互

由于H5的灵活多变,动态可配的特点,也为了避免冗长 的审核周期,H5页面在app上的重要性正日益突显. iOS应用于H5交互的控件主要是UIWebView及WKWebView WKWebView是14年随iOS8推出的,很好的解决了UIWebView加载速度慢,内存占用大的问题 WebViewJavaScriptBridge是一款轻量级的框架,使用它结合wkwebview能十分方便的实现源生与H5的交互 webviewJavaScrptBridge的基本使用 1.初始化需bind视图 [WebV

iOS与H5交互的方案

iOS与H5交互的方案 纵观所有iOS与H5交互的方案,有以下几种: 第一种:有很多的app直接使用在webview的代理中通过拦截的方式与native进行交互,通常是通过拦截url scheme判断是否是我们需要拦截处理的url及其所对应的要处理的功能是什么.任意版本都支持. 第二种:iOS7之后出了JavaScriptCore.framework用于与JS交互,但是不支持iOS6,对于还需要支持iOS6的app,就不能考虑这个了.若需要了解,看最后的推荐阅读. 第三种:WebViewJava

iOS与H5交互

前提:在oc控制器中加载UIWebView,设置代理,遵守UIWebViewDelegate协议. 一.iOS调用JS方法 通过iOS调用JS代码实现起来比较方便直接调用UIWebView的方法- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script; 1.查询标签 // 查询标签      NSString *str = @"var word = document.getElementByI

iOS与H5交互遇到的坑

之前的博客写过使用<JavaScriptCore/JavaScriptCore.h>类来实现与H5的交互,但是在项目中还是遇到了一些不得不踩的坑.在这里将我遇到的问题以及参考网上几位大神的解决方案列举出来,如果有更好的办法,欢迎讨论指正.在阅读本博客前,请参阅我之前的<iOS与H5交互>. 一.在webView中加载H5界面,在此webView中的H5一级界面可以轻松实现oc与js方法互调,但如果在H5界面上进入二级界面,在二级界面中再使用之前方法来交互就会失效.如图:左图为H5一