zoukankan      html  css  js  c++  java
  • 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 ?@"":[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种交互方式,总有一种适合你。

  • 相关阅读:
    AsyncTask Note
    从今以后我要写我写过的技术及代码
    金额阿拉伯数转中文
    [导入]匿名方法引起的异常
    [导入]对.net事件的看法
    [导入]把DataGrid控件定制成漂亮的课程表
    [导入]IIs上的证书安装要点
    oracle创建表空间
    如何在命令行更改IP地址
    server.mappath 与page命名空间说明
  • 原文地址:https://www.cnblogs.com/yujidewu/p/7206673.html
Copyright © 2011-2022 走看看