前言
当前混合开发模式迎来了前所未有的发展,跨平台开发、热更新等优点决定了这种模式的重要地位。虽然前端界面在交互、动效等多方面距离原生应用还有差距,但毫无疑问混合开发只会被越来越多的公司接受。在iOS中,混合开发模式被分为两个时代,分别是iOS7之前的坑爹时代与之后的黄金时代,其分割代表为JavaScriptCore
框架
坑爹时代
作为完美避开iOS7之前版本的幸运儿,我只能从某位前辈的口中得知那悲惨的岁月。作为那个年代唯一能与前端界面交互的手段就是UIWebView
,先不说它自身的内存泄露缺陷,下面是一段前辈写过的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString * address = request.URL.absoluteString; for (NSString * black in _blackList) { if ([address containsString: black]) { return NO; } } for (NSString * event in _eventList) { if ([address containsString: event]) { SEL callback = NSSelectorFromString(_callbacks[event]); [self performSelector: callback]; return [event containsString: @"shouldOpen=1"]; } } return YES; } |
在那个年代,前辈的小伙伴们把前端事件的触发条件设置为链接跳转,然后通过链接中的关键字符来判断处理操作。为此,需要定义好些个数据集合来存储这些关键字符的处理操作。如果遇到应用和前端交换交互数据的时候,那一长串的参数字符全部拼接在请求地址里,想想也是醉了。另外的交互方法就是通过stringByEvaluatingJavaScriptFromString
方法来执行js
代码。
JavaScriptCore
JavaScriptCore
是一套用来对JS
代码进行解析和提供执行环境的开源框架,极大的简化了我们的交互过程。下面从项目和JS
代码相互调用的两个不同操作介绍其中相对应的方法
项目调用JS代码
- JSContext
一个JSContext
对象是JavaScript
运行的全局环境对象,它提供了代码运行和注册方法接口的服务。下面的代码就创建了一个JSContext
对象,并且定义了一部分的JS
代码加入到执行环境中
12345678910let context = JSContext()context.evaluateScript(" var age = 22 ")context.evaluateScript(" var name = 'SindriLin' ")context.evaluateScript(" var birth = 1993-01-01 ")context.evaluateScript(" var createPerson =function(age, name, birth){return {'age': age, 'name': name, 'birth': birth}} ")context.evaluateScript(" var codeDescription = 'The code create three value and a function to create a dictionary stored person information' ")
此外,在JS
代码执行过程中,可能会出现语法错误等多种错误,通过下面的代码可以对这些错误进行处理
123context?.exceptionHandler = { context, exception inprint("Java Script Run Error: \(exception)")} - JSValue
JSValue
是所有JSContext
操作后返回的值,包装了几乎所有的数据类型,包括错误和IMP
指针等。在JSValue
类结构中存在多个toXXXX
命名的方法转换成iOS
数据类型以及call
方法来调用方法。下面的代码从JSContext
环境中获取已存在的部分变量,并且执行创建一个存储person
信息的字典
12345678910let age = context?.objectForKeyedSubscript("age")let name = context?.objectForKeyedSubscript("name")let birth = context?.objectForKeyedSubscript("birth")let createFunction = context?.objectForKeyedSubscript("createPerson")let codeDescription = context?.objectForKeyedSubscript("codeDescription")let person = createFunction.call(withArguments: [age.toInt32(), name.toString(), birth.toString()])let personInfo = "name: \(person["name"]) age: \(person["age"] and birth: \(person["birth"])"print("The javaScript code description: \(codeDescription.toString())")print("The created person \(personInfo) ")
通过上面的例子,我们可以看到,只要了解到JS
代码中我们需要调用的方法信息,通过JSContext + JSValue
的方式我们就能轻松的在项目中调用前端界面的方法,而不再需要拼接长串参数字符通过链接地址传递给前端界面
JS调用项目代码
JavaScript
访问我们代码中的对象以及方法有两种方式:Blocks
和JSExport
。
- Blocks
自定义的block
代码可以通过JSContext
转换成JS
代码中的函数指针调用,这里存在一个坑就是Swift
中的闭包无法完成这样的类型转换,因此这种方式的操作流程在Swift
中是这样的:Closure
->block
->function pointer
。在闭包转成block
的这一过程中,需要使用一个重要的关键符@convention
JS
代码中的函数指针调用,这里存在一个坑就是Swift
中的闭包无法完成这样的类型转换,因此这种方式的操作流程在Swift
中是这样的:Closure
->block
->function pointer
。在闭包转成block
的这一过程中,需要使用一个重要的关键符@convention
ߘ有差距,但毫无疑问混合开发只会被越来越多的公司接受。在iOS中,混合开发模式被分为两个时代,分别是iOS7之前的坑爹时代与之后的黄金时代,其分割代表为JavaScriptCore
框架坑爹时代
作为完美避开iOS7之前版本的幸运儿,我只能从某位前辈的口中得知那悲惨的岁月。作为那个年代唯一能与前端界面交互的手段就是
UIWebView
,先不说它自身的内存泄露缺陷,下面是一段前辈写过的代码:1234567891011121314151617- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{NSString * address = request.URL.absoluteString;for (NSString * black in _blackList) {if ([address containsString: black]) {return NO;}}for (NSString * event in _eventList) {if ([address containsString: event]) {SEL callback = NSSelectorFromString(_callbacks[event]);[self performSelector: callback];return [event containsString: @"shouldOpen=1"];}}return YES;}在那个年代,前辈的小伙伴们把前端事件的触发条件设置为链接跳转,然后通过链接中的关键字符来判断处理操作。为此,需要定义好些个数据集合来存储这些关键字符的处理操作。如果遇到应用和前端交换交互数据的时候,那一长串的参数字符全部拼接在请求地址里,想想也是醉了。另外的交互方法就是通过
stringByEvaluatingJavaScriptFromString
方法来执行js
代码。JavaScriptCore
JavaScriptCore
是一套用来对JS
代码进行解析和提供执行环境的开源框架,极大的简化了我们的交互过程。下面从项目和JS
代码相互调用的两个不同操作介绍其中相对应的方法项目调用JS代码
- JSContext
一个JSContext
对象是JavaScript
运行的全局环境对象,它提供了代码运行和注册方法接口的服务。下面的代码就创建了一个JSContext
对象,并且定义了一部分的JS
代码加入到执行环境中
12345678910let context = JSContext()context.evaluateScript(" var age = 22 ")context.evaluateScript(" var name = 'SindriLin' ")context.evaluateScript(" var birth = 1993-01-01 ")context.evaluateScript(" var createPerson =function(age, name, birth){return {'age': age, 'name': name, 'birth': birth}} ")context.evaluateScript(" var codeDescription = 'The code create three value and a function to create a dictionary stored person information' ")
此外,在JS
代码执行过程中,可能会出现语法错误等多种错误,通过下面的代码可以对这些错误进行处理
123context?.exceptionHandler = { context, exception inprint("Java Script Run Error: \(exception)")} - JSValue
JSValue
是所有JSContext
操作后返回的值,包装了几乎所有的数据类型,包括错误和IMP
指针等。在JSValue
类结构中存在多个toXXXX
命名的方法转换成iOS
数据类型以及call
方法来调用方法。下面的代码从JSContext
环境中获取已存在的部分变量,并且执行创建一个存储person
信息的字典
12345678910let age = context?.objectForKeyedSubscript("age")let name = context?.objectForKeyedSubscript("name")let birth = context?.objectForKeyedSubscript("birth")let createFunction = context?.objectForKeyedSubscript("createPerson")let codeDescription = context?.objectForKeyedSubscript("codeDescription")let person = createFunction.call(withArguments: [age.toInt32(), name.toString(), birth.toString()])let personInfo = "name: \(person["name"]) age: \(person["age"] and birth: \(person["birth"])"print("The javaScript code description: \(codeDescription.toString())")print("The created person \(personInfo) ")
通过上面的例子,我们可以看到,只要了解到
JS
代码中我们需要调用的方法信息,通过JSContext + JSValue
的方式我们就能轻松的在项目中调用前端界面的方法,而不再需要拼接长串参数字符通过链接地址传递给前端界面 - JSContext