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。


场景

UIWebView 和 H5 之三 OC 和 JS 之间的相互传值_第1张图片
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"]];
}

运行效果:

UIWebView 和 H5 之三 OC 和 JS 之间的相互传值_第2张图片
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;
        }

    }

运行效果:

UIWebView 和 H5 之三 OC 和 JS 之间的相互传值_第3张图片
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. 于是,数据的双向传递就达成了。

你可能感兴趣的:(UIWebView 和 H5 之三 OC 和 JS 之间的相互传值)