OC与JS交互

关于UIWebView与JS的交互:

 这里先声明一下:示例只放上了重点代码,后面会给demo地址。

1、原始交互方法:

1、OC调用JS:向UIWebView发送- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;消息来执行一段JavaScript脚本;这里需要注意的是:该方法必须在主线程调用,否则不起作用。

  • 同时本人在项目时遇到这样的需求情况:原生controller进入下一级界面controller,该controller存在一个 webView,直接给webView传递参数,然后点击H5页面内按钮,webview进入次级界面,再次点击H5次级页面内按钮,进入下一级原生controller,而后返回有webView的controller界面并回传值给webView所在controller,当webView所在controller获取到返回数据后再传递给H5次级页面。
    • 这里发生的问题就是,我在最后一步时回传值使用的是block,在block内部使用dispatch_async(dispatch_get_main_queue(), ^{})回归主线程后再调用stringByEvaluatingJavaScriptFromString:向H5发送参数。但是此时并不能将参数发送成功,即stringByEvaluatingJavaScriptFromString:不起作用。原因暂时不知,经排查确实是在主线程了。
    • 解决方法:传值方式改为通知中心的方式,然后当收到通知后将参数发送。

2、JS调用OC:在UIWebView的代理方法- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;中拦截URL然后重定向去执行OC相关代码;

示例:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    // 原始的JS调用OC,拦截URL,重定向
    // 这里我在 index.html中采用了两种方式进行request返回,1:onclick="window.open('need://transform')";2:onclick="window.location.href='need://location'"
    if ([request.URL.absoluteString hasPrefix:@"need://transform"]) {// 跳转
        NSLog(@"执行了跳转操作");
        return NO;
    }
    if ([request.URL.absoluteString hasPrefix:@"need://location"]) {// 本界面的一些操作
        NSLog(@"执行了本界面操作");
        return NO;
    }
    return YES;
}

// 这里是点击了OC中一个原生的button所执行的方法
- (void)rightButAction:(UIButton *)sender
{
        // 使用UIWebView自带方法调用JS方法,其中picCallback('%@')是JS方法,后面是参数
        NSString * jsStr = [NSString stringWithFormat:@"picCallback('%@')", @"stringByEvaluatingJavaScriptFromString方法实现"];
        [self.mainWebView stringByEvaluatingJavaScriptFromString:jsStr];
}
2、使用JavaScriptCore:

  关于JavaScriptCore框架可以参考这篇文章,当使用时需要先导入该框架头文件#import <JavaScriptCore/JavaScriptCore.h>
1、OC调用JS: 在代理方法- (void)webViewDidFinishLoad:(UIWebView *)webView中获取交互上下文对象(JSContext) ,然后调用JSContext- (JSValue *)evaluateScript:(NSString *)script;方法执行JS代码;

2、JS调用OC:这里有两种方法,一种是针对JS中未指明调用对象的方法,一种是针对JS中指明调用对象的方法。

  • 未指明调用对象的方法:可以直接通过context获取到该方法,赋予其block的回调方式即可;

  • 指明调用对象的方法:需要创建继承JSExport的协议,协议方法要与JS中方法相同!通过context将某一类的实例赋予JS当做调用方法的对象,然后在该类中服从协议方法即可;

示例:

// JS调用OC
@protocol JSObjcDelegate <JSExport>
//协议的方法必须和JS里面的方法名称保持一致才有效!
- (void)callShare;
@end

@interface JRWebViewMutualViewController ()<UIWebViewDelegate, JSObjcDelegate>
@property (nonatomic,strong) JSContext * jsContext;// 获取交互环境,主要用于调取JS代码
@property(strong,nonatomic)UIWebView * mainWebView;
@end

@implementation JRWebViewMutualViewController

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    self.jsContext = [self.mainWebView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    // 未指明调用对象的方法
    self.jsContext[@"callCamera"] = ^() {
        NSLog(@"调用Camera了🙄");
    };
    /**
        在JS中 onclick="callCamera()" 指的是点击button直接触发callCamera方法;
        onclick="TEXT.callShare() 指点击button会让一个叫做TEXT的对象去触发callShare方法;
     */
    //在使用JSExport协议类时必须有指定的执行对象才能使用否则使用block形式的回调即可
    self.jsContext[@"TEXT"] = self;
    // 若发生异常会执行此方法
    self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        NSLog(@"异常信息是%@",exception);
    };
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
    NSLog(@"加载错误:%@", error);
}

// 这里是点击了OC中一个原生的button所执行的方法
- (void)rightButAction:(UIButton *)sender
{
        // 获取 将字符串对应的JS方法,转换成一个JSValue对象
        JSValue * jsValue = [self.jsContext evaluateScript:@"picCallback"];
        // 下面👇这一方法与上面的等效
//        JSValue * jsValue = self.jsContext[@"picCallback"];
        // 作为一个函数调用JSValue 参数是JS函数所需参数,该方法用于传参
        [jsValue callWithArguments:@[@"javaScript实现"]];
        
        // 与上面两句代码等效代码
//        [self.jsContext evaluateScript:[NSString stringWithFormat:@"picCallback('%@')", @"javaScript实现"]];
}

- (void)callShare
{
    NSLog(@"调用Share了🙄");
}
@end

 在这里因为若没有HTML的代码可能会不是那么清晰,附上HTML的代码,里面比较简单:

<!DOCTYPE html>  
<html>  
<head lang="zh-CN">
    <meta charset="UTF-8">
    <title>OC-JS交互</title>
</head>  
<body>  
    <div style="margin-top: 30px">
        <input type="button" value="调用OC原生代码示例 - 拦截协议,跳转界面" onclick="window.open('need://transform')" style = "width:300px;height:30px;border:0px;background-color:red;margin-left:10px" >
    </div>         
  
    <div>  
        <input type="button" value="调用OC原生代码示例 - 拦截协议,本界面做操作" onclick="window.location.href='need://location'" style = "width:300px;height:30px;border-style:none; background-color:#FF9;margin-left:10px; margin-top:10px">
    </div>
    
    <div>
        <p>&lt;1&gt;和后端同事协定好协议,如need://transform表示跳转,need://location表示本界面的其他操作。 <br>
        &lt;2&gt;实现UIWebView代理的shouldStartLoadWithRequest:navigationType:方法,在方法中对url进行拦截,如果是步骤 &lt;1&gt; 中定义好的协议则执行对应原生代码,返回NO进行url拦截,否则返回YES继续加载原url。</p>
    <div>
        
    <div style="margin-top: 10px">
        <input type="button" value="调用OC原生代码示例 - JSCore,跳转界面" onclick="callCamera()" style = "width:300px;height:30px;border:0px;background-color:red;margin-left:10px" >
            </div>
    
    <div>
        <input type="button" value="调用OC原生代码示例 - JSCore,本界面做操作" onclick="TEXT.callShare()" style = "width:300px;height:30px;border-style:none; background-color:#FF9;margin-left:10px; margin-top:10px">
            </div>
  
<script>  

    var picCallback = function(photos) {  
        alert(photos);  
    }  

</script>

</body>  
</html>  

demo 地址,demo是一个项目集合,暂时没什么东西,会后续往里面加入,交互界面在左侧抽屉中😆。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容