UIWebView 和 H5 之三 OC 和 JS 之间的相互传值

当我们建立好 JSContext 和 WebView 的 JS 执行环境的连接关系之后。
我们就可以通过 JSContext 读写 这个 JS 环境的。
主要表现在:
一、 我们可以通过 JSContext 读取 JS 原来的属性 & 函数。

 // 读取 JS 本身的一些函数和变量
    JSValue *jsVar = _jsContext[@"jsVar"];
    JSValue *jsFunc = _jsContext[@"jsFunc"];

二、我们也可以通过 JSContext 通过注入的方式 写入 OC 的方法和变量。

// 往 JSContext 中注入 OC 的数据和方法
    _jsContext[@"ocStr"] = @"我是 OC 的字符串";
    _jsContext[@"ocFunc"] = ^{
        NSLog(@"我是 OC 的方法");
    };

一个比较常见的场景是:

我们会在 OC 里面调用 JS 的方法。
我们会在 JS 里面调用 OC 注入的方法。

都是方法,就有返回值。有返回值,就存在数据传递。

当我们在 OC 中一个带有返回值的 JS 方法时,JS 方法的返回值,就传递到了 OC。
当我们在 JS 中调用一个带有返回值的 OC 方法时,OC 方法的返回值,就传递到了 JS。


场景

15207769160924.jpg

需要实现的效果:

  1. 当往 HTML 文本框里输入一些数据,完毕之后,点击OC 从 JS 获取数据的 UIButton 按钮 。把数据传递到 OC ,然后显示在橙色的 UILabel 上面。
  2. 当在 OC 的 UITextField 中输入用户的昵称和手机之后,需要点击 HTML 中的 从 OC 获取数据,让后把数据显示在 HTML 中的昵称 & Phone 的 span 后面。

分析:

  1. 需要从 JS 获取数据到 OC。数据是来自 JS 的。所以,我们需要在 OC 中调用一个返回数据的 JS 方法。(当然了,JS 里的变量,对象等都可以返回数据)
  2. 需要从 OC 获取数据到 JS。数据肯定是来自 OC 的方法的。所以,我们需要在 JSContext 中注入一个 OC 的方法,并返回数据。让 JS 钩住这个方法,然后再点击了 从 OC 获取数据 的按钮之后,调用这个注入的 OC 方法。

数据来自 JS -->数据来源是 JS 函数 --> JS 函数返回值 --> OC 通过 JSContext 获取 JS 函数,并获取返回数据。

数据来自 OC --> 数据来源是 OC 方法 --> OC 方法返回值 --> OC 需要注入到 JSContext 中,以便 JS 调用 --> JS 调用钩住的 OC 的方法,调用并获取 OC 方法的返回值。


实现目的1:从 JS 获取数据到 OC

从 JS 获取数据到 OC。
潜台词:数据来自 JS -> 来自 JS 函数 -> OC 需要通过 JSContext 找到这个 JS 函数 -> 调用并获取 JS 函数的返回值。

/// 把数据传递给 OC
function sendDataToOC() {
    var jsName = document.getElementById("jsName").value;
    var jsPhone = document.getElementById("jsPhone").value;
    
    return {
        "jsName" : jsName,
        "jsPhone" : jsPhone
    };
}

OC 需要通过 JSContext 来获取到这个 JS 函数,调用并获得返回值。

// 从 JS 获取数据
- (IBAction)getDataFromJSClick:(id)sender {
    // 两种写法。
    // 第一种,对 JS 比较熟练的,可以这么写。
    NSDictionary *dataFromJS = [_jsContext evaluateScript:@"sendDataToOC();"].toDictionary;
    // 第二种,拿到 JSValue 在执行。
    // dataFromJS = [_jsContext[@"sendDataToOC"] callWithArguments:nil].toDictionary;
    
    self.dataFromJSLbl.text = [NSString stringWithFormat:@"jsName:%@ jsPhone:%@",dataFromJS[@"jsName"],dataFromJS[@"jsPhone"]];
}

运行效果:

JS 传递数据到 OC.gif

实现目的2:JS 从 OC 获取数据
JS 从 OC 获取数据。
潜台词:数据来自 OC --> 来自 OC 的方法 --> 需要把这个方法注入到 JSContext,以便让 JS 来调用OC 的方法并获取返回值。

我们需要往 JSContext 中注入一个 OC 的方法(这里表现为 :block),并将数据返回。

 // 把数据传递给 JS。本质上就是让 JS 调用一个返回值的 OC 方法。
    __weak typeof(self) weakSelf = self;
    _jsContext[@"backDataToJS"] = ^{
        __strong typeof(weakSelf) sself = weakSelf;
        NSString *ocName = sself.nickNameTxt.text;
        NSString *ocPhone = sself.phoneTxt.text;
        
        return @{@"name" : ocName , @"18571656584" : ocPhone};
    };

backDataToJS 这个 OC 的方法已经注入到 JSContext 中了。
说白了,就是在当前浏览器的 JS 执行环境中声明了这么一个全局函数。

JS 方面,需要调用这个来自 OC 注入的 JS 函数。(其内部执行的仍然是 OC 的 block,也就是前面一直说的 勾住了)

window.onload = function() {
        // 从 OC 获取数据
        document.getElementById("btn").onclick = function() {
            var dataFromOC = backDataToJS(); // backDataToJS 是 OC 注入到 JSContext 里的 OC 方法 block。
            document.getElementById("nameLabel").innerText = dataFromOC.name;
            document.getElementById("ageLabel").innerText = dataFromOC.18571656584;
        }

    }

运行效果:

OC 传递数据到 JS.gif

最后总结:

  1. 首先让 JS 和 OC 共享一个 JSContext。这样 OC 可以往 JSContext 中注入 OC 的 block。也可以调用 JSContext 中本来已经存在的 JS 函数。同样的 JS 也可以调用 OC 注入的 block。这样的双向调用方法/函数。就为数据传递提供了基础。
  2. 当数据来自 OC 时,说明是 JS 调用 OC 的方法。OC 的方法在 JS 这端表现为,一个全局的 JSFunction。
  3. 当数据来自 JS 时,说明是 OC 调用 JS 函数。通过 JSContext 来获取到这个 JS 函数,并调用。获取来自 JSFunction 的返回。
  4. 于是,数据的双向传递就达成了。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,423评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,147评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,019评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,443评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,535评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,798评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,941评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,704评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,152评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,494评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,629评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,295评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,901评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,978评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,333评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,499评论 2 348

推荐阅读更多精彩内容

  • 一、JavaScriptCore常用的类 JavaScriptCore作用:JavaScriptCore是苹果原生...
    CoderZS阅读 899评论 0 8
  • 注:本文copy自//www.greatytc.com/p/ac534f508fb0,纯属当笔记使用。 概...
    BookKeeping阅读 730评论 1 3
  • 本文由我们团队的 纠结伦 童鞋撰写。 写在前面 本篇文章是对我一次组内分享的整理,大部分图片都是直接从keynot...
    知识小集阅读 15,229评论 11 172
  • 写在前面 本篇文章是对我一次组内分享的整理,大部分图片都是直接从keynote上截图下来的,本来有很多炫酷动效的,...
    等开会阅读 14,402评论 6 69
  • 笑来老师这周第一个问答,我重新阅读后,想想周围朋友的经历,跟大家聊聊。 印象深刻的大学间的一个哥们,且称他为A君吧...
    天狼42阅读 295评论 0 3