iOS之H5与原生交互
少年易学老难成,一寸光阴不可轻。
1. 利用UIWebView交互
iOS7之前通过UIWebView相关代理方法进行通信。原理:通过协议拦截实现h5对原生的调用,通过直接调用js来实现原生对h5的调用。
1.1)原生调用h5
通过stringByEvaluatingJavaScriptFromString方法可以直接调用一段js代码,并返回字符串类型的返回值。
- (void)openCamera {
[_webView stringByEvaluatingJavaScriptFromString:@"phoneUrl('http://image1')"];
}
1.2)h5调用原生
在UIWebView的浏览器的JavaScript中,没有相关的接口可以调用Objective-C的相关方法,一般采用JavaScript在浏览器环境中发出URL请求, Objective-C 截获请求以获取相关请求的思路,在Objective-C中在实现UIWebViewDelegate 时截获请求:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *url = request.URL.absoluteString;
if ([url hasPrefix:@"opencame"]) {
[self openCamera];
NSLog(@"打开相机");
return NO;
}
NSLog(@"url is %@",request.URL.absoluteString);
return YES;
}
1.3)原生和h5协调
h5调用原生:需要约定协议拦截信息的规则;
原生调用h5:约定接口的规则,接口名和参数;
1.4)h5页面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1.利用UIWebView进行交互(系统API)</title>
<style>
p{
background: aqua;
text-align: center;
line-height: 50px;
height: 50px;
}
</style>
<script type="text/javascript">
function openCamera() {
window.location.href = "opencame://data=1"
}
function phoneUrl(url) {
alert(url)
}
</script>
</head>
<body>
<p onclick="openCamera()">模拟调用原生相机</p>
</body>
</html>
2. 利用JavaScriptCore.framework原生框架
在iOS7 引入了JavaScriptCore原生框架,使得JavaScript 和 Objective-C可以互相操作,但这个库不支持iOS6及以前的版本,也不支持iOS8发布的WKWebView,下面会讲到。
2.1)JavaScriptCore简介
JavaScriptCore 是 JS 引擎,通常会被叫做虚拟机,专门设计来解释和执行 JS 代码。我们首先了解下JavaScriptCore框架里创建的常见接口和协议:
JSVirtualMachine:为 JS 的运行提供了底层资源,虚拟机是线程安全;
JSContext:给JavaScript提供运行的上下文环境,通过evaluateScript:方法就可以执行一JS代码,这里可以用来管理对象,添加方法等;
JSValue:JavaScript和Objective-C数据和方法交互的桥梁,封装了JS与ObjC中的对应的类型,以及调用JS的API等;
JSManagedValue:可以处理内存管理中的一些特殊情形,它能帮助引用技术和垃圾回收这两种内存管理机制之间进行正确的转换
JSExport:这是一个协议,如果采用协议的方法交互,自己定义的协议必须遵守此协议;实现 JSExport 协议可以开放 OC 类和它们的实例方法,类方法,以及属性给 JS 调用
2.2)JSVirtualMachine
一个 JSVirtualMachine 的实例就是一个完整独立的 JS 的执行环境,为 JS 的执行提供底层资源。这个类主要用来做两件事情:
实现并发的 JavaScript 执行;
JavaScript 和 Objective-C 桥接对象的内存管理;
相关的接口如下:
NS_CLASS_AVAILABLE(10_9, 7_0)
@interface JSVirtualMachine : NSObject
- (instancetype)init;
// 进行内存管理
- (void)addManagedReference:(id)object withOwner:(id)owner;
- (void)removeManagedReference:(id)object withOwner:(id)owner;
@end
每一个 JSVirtualMachine 可以包含多个 JS 上下文(JSContext 对象)。同一个虚拟机下不同的上下文之间可以相互传值(JSValue对象)。
然而,每个虚拟机都是完整且独立的,有其独立的堆空间和垃圾回收器(Garbage Collector ),GC 无法处理别的虚拟机堆中的对象,因此你不能把一个虚拟机中创建的值传给另一个虚拟机。
2.3)JSContext
一个 JSContext 表示了一次 JS 的执行环境。我们可以通过创建一个 JSContext 去调用 JS 脚本,访问一些 JS 定义的值和函数,同时也提供了让 JS 访问 Native 对象方法的接口。
一个 JSContext 对象对应了一个全局对象。例如 Web 浏览器中的 JSContext ,其全局对象就是 Window 对象。在其他环境中,全局对象也承担了类似的角色,用来区分不同的 JavaScript Context 的作用域。
相关接口如下:
JS_EXPORT API_AVAILABLE(macos(10.9), ios(7.0))
@interface JSContext : NSObject
// 初始化,可以指定一个虚拟机,如果没有指定底层默认创建一个
- (instancetype)init;
- (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;
// 执行 JS 脚本,返回值是 JS 中最后生成的一个值,sourceURL 认作其源码 URL,用作标记
- (JSValue *)evaluateScript:(NSString *)script;
- (JSValue *)evaluateScript:(NSString *)script
withSourceURL:(NSURL *)sourceURL API_AVAILABLE(macos(10.10), ios(8.0));
// 获取当前执行的 JavaScript 代码的 context
+ (JSContext *)currentContext;
// 获取当前执行的 JavaScript function
+ (JSValue *)currentCallee API_AVAILABLE(macos(10.10), ios(8.0));
// 获取当前执行的 JavaScript 代码的 this
+ (JSValue *)currentThis;
// 获取当前 context 回调函数的参数
+ (NSArray *)currentArguments;
// 获取当前 context 的全局对象
@property (readonly, strong) JSValue *globalObject;
// 用于 JavaScript 执行异常
@property (strong) JSValue *exception;
@property (copy) void(^exceptionHandler)(JSContext *context, JSValue *exception);
// 获取当前虚拟机
@property (readonly, strong) JSVirtualMachine *virtualMachine;
// 标记当前 context
@property (copy) NSString *name API_AVAILABLE(macos(10.10), ios(8.0));
@end
2.3.1)OC调用JS
Objective-C可以使用JSContext的evalueScript()方法直接调用JavaScript代码:
直接调用JS代码(本地上下文环境):
// 001 - 直接调用h5代码
- (void)evaluateScript {
// 一个JSContext对象,就类似于JS中的window,只需要创建一次即可。
_jsContext1 = [[JSContext alloc] init];
// _jsContext1可以直接执行JS代码。
[_jsContext1 evaluateScript:@"var num = 10"];
[_jsContext1 evaluateScript:@"var squareFunc = function(value) { return value * value }"];
// 计算正方形的面积
JSValue *square = [_jsContext1 evaluateScript:@"squareFunc(num)"];
// 也可以通过下标的方式获取到方法
JSValue *squareFunc = _jsContext1[@"squareFunc"];
JSValue *value = [squareFunc callWithArguments:@[@"20"]];
NSLog(@"%@", square.toNumber); // 100
NSLog(@"%@", value.toNumber); // 400
}
直接调用JS代码(获取HTML上下文环境):
// 002 - 获取网页JSContext 调用js代码
- (void)OCEvaluateScript{
// 获取网页的JSContext对象
JSContext *jsContext = [_webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
[jsContext evaluateScript:@"changeBackgroundColor()"];
}
2.3.2)JS调用OC
各种数据类型可以转换,Objective-C的Block也可以传入JSContext中当做JavaScript的方法使用。在JavaScript中可以调用。
// 003 - JS->OC(注入Block到JSContext中当做JavaScript的方法使用,在JavaScript中可以调用)- (void)addFunctionToJS { //本地上下文环境 //JSContext *context = [[JSContext alloc] init]; //获取HTML上下文环境 JSContext *context = [_webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; context[@"log"] = ^() { NSLog(@"+++++++Begin Log+++++++"); NSArray *args = [JSContext currentArguments]; for (JSValue *jsValue in args) { NSLog(@"参数 = %@", jsValue); } JSValue *this = [JSContext currentThis]; NSLog(@"this: %@",this); NSLog(@"-------End Log-------"); }; // 执行JS代码 - 无意义,模拟效果 [context evaluateScript:@"log('Message Time', { name:'world', length:5 });"];}//+++++++Begin Log+++++++//参数 = Message Time//参数 = [object Object]//this: [object Window]//-------End Log-------
通过Block成功的在JavaScript调用方法回到了Objective-C,而且依然遵循JavaScript方法的各种特点,比如方法参数不固定。也因为这样,JSContext提供了类方法来获取参数列表(+ (JSContext *) currentArguments;)和当前调用该方法的对象(+ (JSValue *)currentThis)。对于"this"
,输出的内容是Window或者GlobalObject,这也是JSContext对象方法- (JSValue *)globalObject;
所返回的内容。因为我们知道在JavaScript里,所有全局变量和方法其实都是一个全局变量的属性,在浏览器中是window,在JavaScriptCore是什么就不得而知了。
2.4)JSValue
JSValue 实例是一个指向 JS 值的引用指针。我们可以使用 JSValue 类,在 OC 和 JS 的基础数据类型之间相互转换。你也可以使用这个类去创建包装了自定义类的 Native 对象的 JS 对象,或者是那些由 Native 方法或者 Block 实现的 JS 函数。
在 JSCore 中,JSValue 自动做了 OC 和 JS 的类型转换:

相关接口如下:
NS_CLASS_AVAILABLE(10_9, 7_0)@interface JSValue : NSObject@property (readonly, strong) JSContext *context;+ (JSValue *)valueWithObject:(id)value inContext:(JSContext *)context;+ (JSValue *)valueWithBool:(BOOL)value inContext:(JSContext *)context;+ (JSValue *)valueWithDouble:(double)value inContext:(JSContext *)context;+ (JSValue *)valueWithInt32:(int32_t)value inContext:(JSContext *)context;+ (JSValue *)valueWithUInt32:(uint32_t)value inContext:(JSContext *)context;+ (JSValue *)valueWithNewObjectInContext:(JSContext *)context;+ (JSValue *)valueWithNewArrayInContext:(JSContext *)context;+ (JSValue *)valueWithNewRegularExpressionFromPattern:(NSString *)pattern flags:(NSString *)flags inContext:(JSContext *)context;+ (JSValue *)valueWithNewErrorFromMessage:(NSString *)message inContext:(JSContext *)context;+ (JSValue *)valueWithNewPromiseInContext:(JSContext *)context fromExecutor:(void (^)(JSValue *resolve, JSValue *reject))callback API_AVAILABLE(macos(10.15), ios(13.0));+ (JSValue *)valueWithNewPromiseResolvedWithResult:(id)result inContext:(JSContext *)context API_AVAILABLE(macos(10.15), ios(13.0));+ (JSValue *)valueWithNewPromiseRejectedWithReason:(id)reason inContext:(JSContext *)context API_AVAILABLE(macos(10.15), ios(13.0));+ (JSValue *)valueWithNewSymbolFromDescription:(NSString *)description inContext:(JSContext *)context API_AVAILABLE(macos(10.15), ios(13.0));+ (JSValue *)valueWithNullInContext:(JSContext *)context;+ (JSValue *)valueWithUndefinedInContext:(JSContext *)context;- (id)toObject;- (id)toObjectOfClass:(Class)expectedClass;- (BOOL)toBool;- (double)toDouble;- (int32_t)toInt32;- (uint32_t)toUInt32;- (NSNumber *)toNumber;- (NSString *)toString;- (NSDate *)toDate;- (NSArray *)toArray;- (NSDictionary *)toDictionary;@property (readonly) BOOL isUndefined;@property (readonly) BOOL isNull;@property (readonly) BOOL isBoolean;@property (readonly) BOOL isNumber;@property (readonly) BOOL isString;@property (readonly) BOOL isObject;@property (readonly) BOOL isArray API_AVAILABLE(macos(10.11), ios(9.0));@property (readonly) BOOL isDate API_AVAILABLE(macos(10.11), ios(9.0));@property (readonly) BOOL isSymbol API_AVAILABLE(macos(10.15), ios(13.0));- (BOOL)isEqualToObject:(id)value;- (BOOL)isEqualWithTypeCoercionToObject:(id)value;- (BOOL)isInstanceOf:(id)value;// 当前 JSValue 为一个函数的时候,可以通过这个方法调用- (JSValue *)callWithArguments:(NSArray *)arguments;// 调用 JS 中的构造函数,arguments 数组内容必须是 JSValue 对象,以供 JS 能顺利转化- (JSValue *)constructWithArguments:(NSArray *)arguments;// 当前 JSValue 对象为 JS 中的全局对象名称,method 为全局对象的方法名称,arguments 为参数- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;@end
由2.3.2章节中介绍我们可以得知,OC 层面的 Block 是可以自动转换为 JS 层面的函数,JS 可以直接访问;但是 JS 的函数 OC 确不能直接访问,而要通过 callWithArguments: 方法来调用。
OC 的 id 类型传给 JS,只是一个指针,是没法访问其属性和方法的,但是 JS 回传到 OC 的时候 OC 还是可以正常访问的。如果需要在 JS 中,访问 OC 对象的属性和方法可以通过 JSExport 协议来实现,下面会详细介绍。
#pragma mark - JSValue- (void)ocExeJSFunction { // 本地上下文环境// JSContext *context = [[JSContext alloc] init];// [context evaluateScript:@"function add(a, b) { return a + b; }"];// JSValue *add = context[@"add"];// NSLog(@"Func: %@", add);// JSValue *sum = [add callWithArguments:@[@(18), @(32)]];// NSLog(@"Sum: %d",[sum toInt32]); //获取HTML上下文环境 JSContext *context = [_webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; JSValue *add = context[@"add"]; NSLog(@"Func: %@", add); JSValue *sum = [add callWithArguments:@[@(18), @(32)]]; NSLog(@"Sum: %d",[sum toInt32]);}// OUTPUT//Func: function add(a, b) {// return a + b;// }//Sum: 50
2.5)JSExport
实现 JSExport 协议可以开放 OC 类和它们的实例方法,类方法,以及属性给 JS 调用。我们先学习一个常规例子。
1. 定义协议类:
#import <Foundation/Foundation.h>#import <JavaScriptCore/JavaScriptCore.h>NS_ASSUME_NONNULL_BEGIN@protocol JavaScriptExecuteOCDelegate <JSExport>// 属性@property(nonatomic,strong)NSString *propertyValue;// 无参数方法:调用OC的系统相册- (void)callSystemCamera;// 一个参数方法:通过JSON传值- (void)callWithDict:(NSDictionary *)params;// 多参数方法:在JS中调用时,函数名应该为showAlertMsg(arg1, arg2)- (void)showAlert:(NSString *)title msg:(NSString *)msg;// 回传实例:JS调用OC,然后在OC中通过调用JS方法来传值给JS。- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary *)params;// 类方法+ (void)OCClassMethod;@endNS_ASSUME_NONNULL_END
2. 创建模型类,遵守协议:
// 此模型用于注入JS的模型,这样就可以通过模型来调用方法。#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>#import "JavaScriptExecuteOCDelegate.h"NS_ASSUME_NONNULL_BEGIN@interface HBNativeApisModel : NSObject<JavaScriptExecuteOCDelegate>@property(nonatomic, strong)JSContext *jsContext;@property(nonatomic, strong)UIWebView *webView;@endNS_ASSUME_NONNULL_END #import "HBNativeApisModel.h"#import <JavaScriptCore/JavaScriptCore.h>@implementation HBNativeApisModel// 属性@synthesize propertyValue;// 无参数方法:调用OC的系统相册- (void)callSystemCamera { NSLog(@"调用OC的系统相册方法"); JSValue *value = self.jsContext[@"cameraInfo"]; [value callWithArguments:nil];}// 一个参数方法:通过JSON传值- (void)callWithDict:(NSDictionary *)params { NSLog(@"JS调用了OC的方法,参数为:%@", params);}// 多参数方法:在JS中调用时,函数名应该为showAlertMsg(arg1, arg2)- (void)showAlert:(NSString *)title msg:(NSString *)msg { NSLog(@"JS调用了OC多参数方法:title=%@, msg=%@",title, msg); dispatch_async(dispatch_get_main_queue(), ^{ UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [alert show]; });}// 回传实例:JS调用OC,然后在OC中通过调用JS方法来传值给JS。- (void)jsCallObjcAndObjcCallJsWithDict:(NSDictionary *)params { NSLog(@"JS调用了OC的方法,参数为:%@", params); JSValue *value = self.jsContext[@"backParam"]; [value callWithArguments:@[@{@"name": @"Hubert", @"height": @175}]];}// 类方法+ (void)OCClassMethod { NSLog(@"JS调用了OC的类方法");}@end
3. 调用:
// 005 - 实现 JSExport 协议可以开放 OC 类和它们的实例方法,类方法,以及属性给 JS 调用- (void)jsExeNativeToJSExport { HBNativeApisModel *model = [[HBNativeApisModel alloc] init]; model.propertyValue = @"属性值:Hubert"; JSContext *context = [_webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; context[@"log"] = ^(NSString *msg){ NSLog(@"%@", msg); }; model.jsContext = context; model.webView = _webView; // 注入实例 context[@"apiModel"] = model; // 注入类 context[@"HBNativeApisModel"] = HBNativeApisModel.class; context.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { context.exception = exceptionValue; NSLog(@"异常信息:%@", exceptionValue); }; // // 访问属性// [context evaluateScript:@"log(apiModel.propertyValue)"];// // 访问实例方法// [context evaluateScript:@"apiModel.callSystemCamera()"];// [context evaluateScript:@"apiModel.callWithDict({name:'Hubert'})"];// [context evaluateScript:@"apiModel.jsCallObjcAndObjcCallJsWithDict({name:'Hubert'})"];// // 访问实例方法 - 多个参数// [context evaluateScript:@"apiModel.showAlertMsg('param1','param2')"];// // 访问类方法// [context evaluateScript:@"HBNativeApisModel.OCClassMethod()"];}
4. 注意点:
多个参数方法调用的时候,转换规则成驼峰形式,去掉所有的冒号,所有冒号后的第一个小写字母都会被转为大写。
如果不喜欢默认的转换规则,也可以使用 JSExportAs(<#PropertyName#>, <#Selector#>) 来自定义转换,比如:
JSExportAs(callFun, - (void)callValue1:(NSString *)value1 value2:(NSString *)value2);)// 调用如下:[context evaluateScript:@"apiModel.callFun('param1','param2')"];
3. 利用WKWebView交互
3.1)了解WKWebView相关类
- WKWebView:网页渲染与展示;
- WKWebViewConfiguration:添加WebView配置信息;
- WKUserScript:用于进行js注入;
- WKUserContentController:这个类主要用来做native与JavaScript的交互管理;
- WKScriptMessageHandler:这个协议类专门用来处理监听JavaScript方法从而调用原生OC方法,和WKUserContentController搭配使用;
3.2)了解WKWebView相关代理
- WKNavigationDelegate :主要处理一些跳转、加载处理操作;
- WKUIDelegate :主要处理JS脚本,确认框,警告框等;
3.3)h5调用原生
这个实现主要是依靠WKScriptMessageHandler协议类和WKUserContentController两个类:WKUserContentController对象负责注册JS方法,设置处理接收JS方法的代理,代理遵守WKScriptMessageHandler协议,实现捕捉到JS消息的回调方法。
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // 创建网页配置对象的类 WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init]; // 这个类主要用来做native与JavaScript的交互管理 // 遵守WKScriptMessageHandler协议,代理是由WKUserContentControl设置 WKUserContentController *wkUController = [[WKUserContentController alloc] init]; [wkUController addScriptMessageHandler:self name:@"jsToOcWithPrams"]; config.userContentController = wkUController; _webView = [[WKWebView alloc] initWithFrame:[UIScreen mainScreen].bounds configuration:config]; _webView.navigationDelegate = self; [self.view addSubview:_webView]; //打开URL NSString *path = [[NSBundle mainBundle] pathForResource:@"web2" ofType:@"html"]; [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath: path]]];}#pragma mark - WKScriptMessageHandler// 通过接收JS传出消息的name进行捕捉的回调方法 js调OC- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { NSLog(@"name:%@ \n body:%@ \n frameInfo:%@",message.name,message.body,message.frameInfo);}
输出结果:
name:jsToOcWithPrams body:{ age = "\U5e74\U9f84"; name = "\U540d\U5b57";} frameInfo:<WKFrameInfo: 0x7fed6452eb20; webView = 0x7fed64822000; isMainFrame = YES; request = <NSMutableURLRequest: 0x600002091660> { URL: file:///Users/Hubert/Library/Developer/CoreSimulator/Devices/872510EC-ECBA-42DE-BBF0-119826E07A79/data/Containers/Bundle/Application/9DEF6356-E45D-45BC-BBB5-057BDCC73237/BaseGrammar.app/web2.html }>
3.4)原生调用h5
通过evaluateJavaScript: completionHandler:方法可以直接调用一段js代码。
- (void)changeBackgroundColor { NSString *jsString = @"changeBackgroundColor()"; // 定义在js中的方法 [_webView evaluateJavaScript:jsString completionHandler:^(id _Nullable data, NSError * _Nullable error) { NSLog(@"调用成功"); }];}
3.5)原生和h5协调
h5调用原生:约定接口的规则,接口名和参数;
原生调用h5:约定接口的规则,接口名和参数;
4. 利用WebViewJavascriptBridge开源库
WebViewJavaScriptBridge 可以用于 WKWebView & UIWebView 中 OC 和 JS 交互。
它的基本原理是:
&emsp(1)把 OC 的方法注册到桥梁中,让 JS 去调用。
(2)把 JS 的方法注册在桥梁中,让 OC 去调用。

4.1)WebViewJavaScriptBridge使用基本步骤
在项目里导入
WebViewJavaScriptBridge框架;导入头文件
#import <WebViewJavascriptBridge.h>;建立
WebViewJavaScriptBridge和WebView之间的关系;_bridge = [WebViewJavascriptBridge bridgeForWebView:_webView];
在HTML 文件中,复制粘贴这两段 JS 函数;
/*这段代码是固定的,必须要放到js中*/function setupWebViewJavascriptBridge(callback) { if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); } if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); } window.WVJBCallbacks = [callback]; var WVJBIframe = document.createElement('iframe'); WVJBIframe.style.display = 'none'; WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'; document.documentElement.appendChild(WVJBIframe); setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)} /*与OC交互的所有JS方法都要放在此处注册*/setupWebViewJavascriptBridge(function(bridge) { }
4.2)往桥梁中注入 OC 方法 和 JS 函数
往桥梁中注入 OC 方法;
- (void)registerHandlerForBridge { // openCarama 是 OC block 的一个别名。 // block 本身,是 JS 通过某种方式调用到 openCarama 的时候,执行的代码块。 // data ,由于 OC 这端由 JS 调用,所以 data 是 JS 端传递过来的数据。 // responseCallback OC 端的 block 执行完毕之后,往 JS 端传递的数据。 [_bridge registerHandler:@"openCarama" handler:^(id data, WVJBResponseCallback responseCallback) { NSLog(@"dataFrom JS : %@",data[@"data"]); responseCallback(@"选择照片结果 : www.baidu.com"); }];}
往桥梁中注入 JS 函数;
// 这里主要是注册 OC 将要调用的 JS 方法。setupWebViewJavascriptBridge(function(bridge){ // testJavaScriptFunction 是注入到桥梁中 JS 函数的别名。以供 OC 端调用。 // 回调函数的 data。 既然 JS 函数由 OC 调用,所以 data 是 OC 端传递过来的数据。 // responseCallback 。 JS 调用在被 OC 调用完毕之后,向 OC 端传递的数据。 bridge.registerHanlder('testJavaScriptFunction',function(data,responseCallback){ // data 是 OC 传递过来的数据. // responseCallback 是 JS 调用完毕之后传递给 OC 的数据 alert("JS 被 OC 调用了."); responseCallback({data: "js 的数据",from : "JS"}); })});
总结:
OC 端注册 OC 的方法,OC 端调用 JS 的函数。
JS 端注册 JS 的函数,JS 端调用 OC 的方法。
4.3)从桥梁中删除OC方法
在当前控制器消失的时候,要记得把注入到桥梁中的 OC block,从桥梁中删除。否则,可能会出现控制器无法释放的情况。
- (void)dealloc { [_bridge removeHandler:@"openCamera"];}
iOS之H5与原生交互的更多相关文章
- WebViewJavascriptBridge(H5与原生交互)
https://github.com/wangjiaojiao77/WebViewJavascriptBridge(IOS)和 https://github.com/wangjiaojiao77/Js ...
- 【quickhybrid】H5和Native交互原理
前言 Hybrid架构的核心就是JSBridge交互,而实现这个交互的前提是弄清楚H5和Native端的交互 本文主要介绍Native端(Android/iOS)和H5端(泛指前端)的交互原理 (之前 ...
- iOS与H5交互(WKWbebView)
前言: 在iOS开发中,或多或少的会嵌入一些H5页面,有时候需要原生代码和H5页面进行交互.iOS8开始苹果推出性能更强大的WKWebView,所以一下方法是关于WKWebView与JS的交互. 创建 ...
- iOS与H5交互
H5与App原生交互,一般会是前端页面中的JavaScript与App使用的原生开发语言的交互.技术方案应能达到以下要求: 在js与原生进行交互的时候能保证正常的正向调用逻辑返回,反向可以处理异步回调 ...
- iOS与H5交互及UIWebView缓存
iOS原生App与H5页面交互笔记 最近在做一个项目用到了原生App与H5交互,之前有做过简单的H5页面直接调用原生方法的例子,就是利用UIWebView中的代理方法 //webview每次加载之前都 ...
- IOS与h5交互记录
博主之前做过移动端app嵌入网页,与Android和IOS有交互,一直没有时间分享过程.这里不多说Android交互啦-很简单,详细了解IOS与h5的交互吧. IOS不同语法和h5的交互所建立的JSB ...
- h5 与原生 app 交互的原理
现在移动端 web 应用,很多时候都需要与原生 app 进行交互.沟通(运行在 webview中),比如微信的 jssdk,通过 window.wx 对象调用一些原生 app 的功能.所以,这次就来捋 ...
- 客户端相关知识学习(二)之h5与原生app交互的原理
前言 现在移动端 web 应用,很多时候都需要与原生 app 进行交互.沟通(运行在 webview中),比如微信的 jssdk,通过 window.wx 对象调用一些原生 app 的功能.所以,这次 ...
- h5 做app时和原生交互的小常识。
距离上次随笔或许有半年了吧,最近在用hybrid模式开发移动app,所以就简单的说说用h5技术开发app时候,做原生交互的几个小常识: 一.拨打电话或者发送短信: <a href="t ...
- 浅谈 iOS 与 H5 的交互- JavaScriptCore 框架
前言 小的作为一个iOS程序猿,可能研究JavaScript以及H5相关的知识并不是为了真正的要去转行做这一方面,其实更多的为了要研究OC中的JavaScriptCore框架,JavaScriptCo ...
随机推荐
- js 文字像打字一样缓缓出现
点击查看代码 <!DOCTYPE HTML> <html lang="en"> <head> <meta charset="UT ...
- TCP如何实现可靠传输、流量控制、拥塞控制
上一篇文章中讲述了TCP首部的存储的数据,这一篇来聊聊这些数据帮助TCP实现一些特性. 可靠传输 TCP传输会保障数据的可靠和完整,如果数据传输过程丢失了,会重新传输. 保障的第一种协议方式是 停止等 ...
- pentaho(keetle)数据同步实践
pentaho(keetle)数据同步实践 1 pentaho简介 pentaho可读作"彭塔湖",在keetle被pentaho公司收购后改名而来. pentaho是一款开源ET ...
- Unity UGUI的InputField(输入框)组件的介绍及使用
UGUI的InputField(输入框)组件的介绍及使用 1. 什么是UGUI的InputField组件? UGUI的InputField组件是Unity中的一个用户界面组件,用于接收用户的输入.它可 ...
- 《CTFshow-Web入门》06. Web 51~60
@ 目录 web51 题解 web52 题解 原理 web53 题解 原理 web54 题解 原理 web55 题解 原理 web56 题解 原理 web57 题解 原理 web58 题解 原理 we ...
- Linux文件管理知识查找文件(第二篇)
Linux文件管理知识:查找文件(第二篇) 上篇文章详细介绍了linux系统中查找文件的工具或者命令程序locate和find命令的基本操作.那么,今天这篇文章紧接着查找文件相关操作内容介绍. Fin ...
- 1.15 自实现GetProcAddress
在正常情况下,要想使用GetProcAddress函数,需要首先调用LoadLibraryA函数获取到kernel32.dll动态链接库的内存地址,接着在调用GetProcAddress函数时传入模块 ...
- 在线PNG, JPG, BMP 转ICO图标,适用WINDOWS XP, VISTA, 7, 8, 10
在线PNG, JPG, BMP 转ICO图标网址: http://static.krpano.tech/image2ico 该网站可以把PNG, JPG和BMP图片转换成包含多个层级的ICO图标, 可 ...
- MFC中使用函数实现ini文件的连续读写
实现的思路: 首先通过读取文件中的count值,确定当前信息条数: 第二步:将count进行累加,把信息写到累加后的键值"="的后面: 第三步:写入count累加值,实现连续读写: ...
- Oracle查询--增加--删除--修改主键
对Oracle表主键的操作,有四类:查询,增加,修改,删除 1.查询主键 /*查询某个表中存在的约束*/ select * from user_constraints where table_name ...