原生H5 js与iOS交互传值

       最近做项目有个需求:iOS嵌套H5界面,当H5收到消息通知时,调用iOS原生的通知弹框。

       文中主要介绍H5向oc传值并调用oc中的方法,至于oc向H5传值下次用过再介绍。

方法一:

      使用UIWebView,H5和iOS约定好代理名称以及方法名,进行调用;

<input type="button" value="唤起getCall:(NSString *)callString传值" onclick="clickMy()">
 
<script>
    function clickMy() {
        var msg = JSON.stringify({"name": "lishuai","info":"233333333"});
        showMsgInApp(msg);
     }
        
    function showMsgInApp (msg)
    {
        if(appJs){
             appJs.showMsg(msg);
         }
    }
</script>

       其中,appJs是约定好的代理名,showMsg是方法名。

#import  <JavaScriptCore/JavaScriptCore.h>

@protocol JSObjcDelegate <JSExport>
    //对象调用的JavaScript方法,必须声明!!!
    - (void)showMsg:(NSString *)dic;
@end

@property (nonatomic, strong) JSContext *jsContext;
@property (strong, nonatomic) UIWebView *webView;

 //加载网页
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
_webView.delegate = self;
[_webView loadRequest: [NSURLRequest requestWithURL:@"你的url"];];
[self.view addSubview:_webView];

//进行监听设置代理 appJs
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    self.jsContext[@"appJs"] = self;
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
        context.exception = exceptionValue;
        NSLog(@"异常信息:%@", exceptionValue);
    };
}

//调用方法 showMsg
- (void)showMsg:(NSString *)dic {
    NSLog(@"Get:%@", dic);
    //调取本地通知
    [self showLocalNotification :@"default"];
}

       这个方法简洁明了,应该属于官方正规方法。但是!!!!正常页面好用,如果是Iframe标签跳转的网页中的事件,获取不到代理appJs,执行js时会报错!!!这个问题困扰了我一天,在网上也没找到好的解决办法,也就有了下面的方法二。

方法二:

       一下午没弄好,晚上躺床上吃鸡的瞬间突然想到,查找方法时介绍了oc可以捕捉到Iframe标签的跳转链接,是不是在链接中可以传递参数,类似于get请求,再对链接进行消息截取,同样可以传递值。第二天来公司一试,果然可以。

<input type="button" value="截取" onclick="showIniOS()">

<script>
    function showIniOS()
    {
        var u = navigator.userAgent;
        var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1;
        var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
        if(isiOS == true ){
            shareClick("LSIHUAI","200000");
        }
    }

    function shareClick(name,info) {
        loadURL("iosAction://h5Click?name="+name+"&info="+info);
    }

    function loadURL(url) {
        var iFrame;
        iFrame = document.createElement("iframe");
        iFrame.setAttribute("src", url);
        iFrame.setAttribute("style", "display:none;");
        iFrame.setAttribute("height", "0px");
        iFrame.setAttribute("width", "0px");
        iFrame.setAttribute("frameborder", "0");
        document.body.appendChild(iFrame);
        // 发起请求后这个iFrame就没用了,所以把它从dom上移除掉
        iFrame.parentNode.removeChild(iFrame);
        iFrame = null;
    }
</script>

       代码中加了判断是iOS以及安卓手机的方法,因为要兼容两种系统,不然会报错。其实是有事件的时候虚拟一个URL请求,用Iframe加载,但是不让Iframe显示,让客户端拦截到请求地址再进行操作。

//每次客户端有URL请求都会进行监听,注意监听到的是iosaction,A变成了a。
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL *URL = request.URL;
    NSString *scheme = [URL scheme];
    if ([scheme isEqualToString:@"iosaction"]) {
         [self share:URL];
        return NO;
    }
    return YES;
}
//截取到的链接方法进行处理
- (void)share:(NSURL *)URL
{
    NSArray *params =[URL.query componentsSeparatedByString:@"&"];
    NSMutableDictionary *tempDic = [NSMutableDictionary dictionary];
    for (NSString *paramStr in params) {
        NSArray *dicArray = [paramStr componentsSeparatedByString:@"="];
        if (dicArray.count > 1) {
            NSString *decodeValue = [dicArray[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            [tempDic setObject:decodeValue forKey:dicArray[0]];
        }
    }
    NSString *name = [tempDic objectForKey:@"name"];
    NSString *info = [tempDic objectForKey:@"info"];
    //调取本地通知
    [self showLocalNotification :@"default"];
}

       关于调取本地通知,https://blog.csdn.net/lishuai1127/article/details/80583404,前面写过一个介绍,需要的可以看看。

       这次还学会了app退到后台时,oc的方法立马停止,通知捕捉不到。从网上看了一堆代码,使用了一句像手机借了几分钟的缓冲时间。借时间方面也是个大知识点,还有挺多任务做,没有进行深究,以后有时间再好好研究一下。

- (void)applicationDidEnterBackground:(UIApplication *)application {
    [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
}

       还有这次还尝试使用了WKWebView,最后方法调用失败。。。本地文件1.html都展示不出来,没办法弄了个工程war包,放到服务器,读取URL就可以。然后一顿操作,再js中代理方法获取不到放弃了,以后再说吧。

展开阅读全文

没有更多推荐了,返回首页