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 ...
随机推荐
- gitlab-runner-config-in-docker
gitlab in docker 网上有很多现成的解决方案,本文仅作流程梳理,若不需要,可直接用gitlab官方提供的镜像 installation Dockerfile FROM registry. ...
- python将print的打印内容保存到日志
将python程序中的所有打印内容都输出到日志文件中,在程序执行完成后,方便查询程序运行过程是否出现异常. 1. 将打印内容输出到日志文件 1.1 代码实现: sys.stdout = open('s ...
- 高级SQL分析函数-窗口函数
摘要:本文由葡萄城技术团队于博客园原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言 SQL语句中,聚合函数在统计业务数据结果时起到了重要作用 ...
- 如何让WPF中的ValidationRule实现参数绑定
背景 应用开发过程中,常常会对用户输入内容进行验证,通常是基于类型.范围.格式或者特定的要求进行验证,以确保输入符合预期.例如邮箱输入框校验输入内容是否符合邮箱格式.在WPF中,数据模型允许将Vali ...
- Avalonia 实现聊天消息渲染、图文混排(支持Windows、Linux、信创国产OS)
在实现即时通讯软件或聊天软件时,渲染文字表情.图文混排是一项非常繁琐的工作,再加上还要支持GIF动图.引用消息.撤回消息.名片等不同样式的消息渲染时,就更加麻烦了. 好在我们可以使用 ESFra ...
- Jmeter读取结果文件报错Error loading results file解决方法
最近在项目性能测试过程中,遇到jmeter读取jtl文件出错的问题,如下图所示: 方法一:修改配置文件 将要读取结果文件的组件Configure界面配置都勾选上,默认情况下有些选项没勾选会出错. 第一 ...
- 《SQLi-Labs》03. Less 11~15
@ 目录 索引 Less-11 题解 原理 Less-12 题解 Less-13 题解 Less-14 题解 Less-15 题解 原理 sqli.开启新坑. 索引 Less-11:POST 回显注入 ...
- 小红书获得小红书笔记详情 API 返回值说明
item_get_video-获得小红书笔记详情 注册开通 smallredbook.item_get_video 公共参数 名称 类型 必须 描述 key String 是 调用key(必须以 ...
- 从驾考科目二到自动驾驶,聊聊GPU为什么对自动驾驶很重要
"下一个项目,坡道起步." -- "考试不合格,请将车子开到起点,重新验证考试.你的扣分项是:起步时间超30秒:扣100分.行驶过程中车轮轧到边线:扣100分." ...
- signalr断开连接后重新连接
signalr断开连接后重新连接 产品需求连接signalr 不稳定,连着连着就断了,场面十分尴尬,导致产品经理现场被批!!(内心无比高兴 ) 分析得出问题现象: 服务器因某些特殊原因,导致服务停止一 ...