热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JS和OC相互调用

1、现状:人人都是产品经理聊聊WebApp、HybridApp与NativeApp的设计差异标点符(钱魏Way)NativeApp、WebApp还是HybridApp

1、现状:

人人都是产品经理 聊聊Web App、Hybrid App与Native App的设计差异

标点符(钱魏 Way) Native App、Web App 还是Hybrid App?

image

image

1)Native APP:Native Code编程,代码编译之后以2进制或者字节码的形式运行在OS上,直接调用OS的Device API;

2)Web APP,以HTML+JS+CSS等WEB技术编程,代码运行在浏览器中,通过浏览器来调用Device API(取决于HTML5未来的支持能力):

3)Hybrid APP,部分代码以WEB技术编程,部分代码由某些Native Container承担(例如PhonGAP(Cordova)插件,BAE插件),其目的是在HTML5尚未完全支持Device API和Network API的目前阶段,承担这部分职责。(我们当前所使用的)

2、Hybrid APP问题:

处理原生代码(OC)和HTML5的交互(JS)问题

3、JS调用OC代码:

3.1 实现 UIWebView 的代理,然后根据NSURLRequest的URL进行不同处理,JS中的将要传递的数据作为URL 重定向 :
//webView的代理相应重定向
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString *requestString = [[[request URL] absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"should-------");
if ([requestString hasPrefix:@"fdd://"]) {
//根据自己定义的规则,通过字符串的值,调用OC的方法。这里就输出一下字符串了。
NSLog(@"===%@",requestString); //可能包含商品的ID,APP拿到这个ID,使用OC代码执行相关操作
return NO; //YES 表示正常加载网页 返回NO 将停止网页加载
}

return YES;
}

优点:勉强实现JS调用OC代码,容易理解 =_=

缺点:硬编码,扩展性差

3.2 对3.1的一些扩展:

zttjhm的专栏 UIWebView中Html中用JS调用OC方法及OC执行JS代码

HTML代码:












alert提示 //href 要跳转的链接




actionsheet提示


iOS代码:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{

NSString *urlstr = request.URL.absoluteString;
NSRange range = [urlstr rangeOfString:@"fdd://"];

if (range.length!=0){
urlstr = [urlstr substringFromIndex:(range.location+range.length)];
NSString *method = urlstr;
SEL selctor = NSSelectorFromString(method);
[self performSelector:selctor withObject:nil];
return NO;
}

return YES;
}
#pragma clang diagnostic pop

- (void)alertShow{

}

- (void)actionsheetShow{

}

优点:实现JS调用OC代码,使用OC方法来处理JS的对应事件,可读性好

缺点:需要两端约定好方法,方法传多个参数不好处理

3.3 JavascriptCore框架:

CocoaChina iOS7新JavascriptCore框架介绍

hayageek Execute Javascript in iOS Applications

阿福的专栏 IOS7开发~JavascriptCore(一)

阿福的专栏 IOS7开发~JavascriptCore(二)

Kaitiren的专栏 JavascriptCore框架在iOS7中的对象交互和管理教程

http://trac.webkit.org/ JavascriptCore框架源码OC

http://opensource.apple.com/JavascriptCore框架源码C++

limlimlim的专栏 Javascript字典操作

j_akill的专栏 ios开发,Javascript直接调用oc代码而非通过改变url回调方式

jwzhangjie的专栏 OC与JS互相调用

JavascriptCore框架只要引入了5个文件,每个文件里都定义跟文件名对应的类:

  1. JSContext (提供着运行环境)

  2. JSValue (Javascript和Object-C之间互换的桥梁)

  3. JSManagedValue (将 JSValue 转为 JSManagedValue 类型后,可以添加到 JSVirtualMachine 对象中,这样能够保证你在使用过程中 JSValue 对象不会被释放掉,当你不再需要该 JSValue 对象后,从 JSVirtualMachine 中移除该 JSManagedValue 对象,JSValue 对象就会被释放并置空。

  4. JSVirtualMachine(JSVirtualMachine就是一个用于保存弱引用对象的数组,加入该数组的弱引用对象因为会被该数组 retain,所以保证了使用时不会被释放,当数组里的对象不再需要时,就从数组中移除,没有了引用的对象就会被系统释放。

  5. JSExport(神秘的语言穿梭机—JSExport协议)

HTML代码:



































JS代码:

function max(a, b){
return a>b?a:b;
}

function callBack(a, b){
var paramters = postParamters(20, 18); //执行OC的postParamters方法
var par1 = paramters['paramter1'];
var par2 = paramters['paramter2'];
paramters['paramter1'] = par1 + a;
paramters['paramter2'] = par2 + b;
return paramters;
}

function buttonClick2(title, message){
JavascriptAction(title, message);
}

var nativeManager; //需要全局申明
function buttonClick3(title, message){
nativeManager.doSomeThing('js to os' + title + ' ' , message);
}

function buttonClick4(title, message){
nativeManager.onePushSubmit('js to os' + title + ' ' , message);
}

function buttonClick5(s1, s2, s3, s4){
nativeManager.morePraramters(s1, s2, s3, s4);
}

iOS代码:

OC注入JS代码:

//OC注入JS代码,再获取JS代码中的变量
JSContext *iCOntext= [[JSContext alloc] init];
[iContext evaluateScript:@"var arr = [21, 7, 'harry up'];"]; //上下文执行该JS代码(变量)
JSValue *jsArr = iContext[@"arr"];
NSArray *ocArr = [jsArr toArray];
NSLog(@"JS Array: %@ \n OC Array: %@", jsArr, ocArr);

//OC注入JS代码,再获取JS代码中的方法
NSString *jsCode = @"function sum(a, b) {return a+b;}"; //定义JS方法
[iContext evaluateScript:jsCode]; //上下文执行该JS代码(方法)
JSValue *jsFunc = iContext[@"sum"]; //从上下文获取JS方法
JSValue *result = [jsFunc callWithArguments:@[@20, @18]]; //js方法传入参数并且返回结果
NSLog(@"result : %d", [result toInt32]);

OC通过JS文件注入JS代码

//OC注入JS代码(JS文件),再获取JS代码中的方法, (扩展)
NSString *path = [[NSBundle mainBundle] pathForResource:@"jsCore" ofType:@"js"];
NSString *pluginScript = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[iContext evaluateScript:pluginScript]; //上下文执行该JS代码(方法)
JSValue *jsFunc2 = iContext[@"max"]; //从上下文获取JS方法
JSValue *result2 = [jsFunc2 callWithArguments:@[@20, @18]]; //js方法传入参数并且返回结果
NSLog(@"result2 : %d", [result2 toInt32]);

//2、JS执行OC的postParamters方法
iContext[@"postParamters"] = ^(NSInteger a, NSInteger b){
NSDictionary *info = @{@"paramter1" : [NSNumber numberWithInteger:a + 20],
@"paramter2" : [NSNumber numberWithInteger:a + 18]};
return info;
};

//1、OC执行JS中callBack方法
JSValue *callBackFunc = iContext[@"callBack"];
JSValue *vv = [callBackFunc callWithArguments:@[@20, @18]];
NSDictionary *callBackDic = [vv toDictionary];
NSLog(@"callBackDic : %@", callBackDic);

OC和HTML上的JS交互

UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"redirect" ofType:@"html"];
NSURLRequest *rq = [NSURLRequest requestWithURL:[NSURL URLWithString:htmlPath]];
[webView loadRequest:rq];
webView.delegate = self;
[self.view addSubview:webView];

//此处通过当前webView的键获取到jscontext
JSContext *cOntext= [webView valueForKeyPath:@"documentView.webView.mainFrame.JavascriptContext"];
//通过context对JS上的每一个方法进行回调监听
context[@"JavascriptAction"] = ^(){
NSArray *args = [JSContext currentArguments];
for (JSValue *jsVal in args){
NSLog(@"%@", jsVal);
}
};

//通过对象对JS上的每一个方法进行回调监听
context[@"nativeManager"] = [NativeManager new];

NativeManager.h代码:

#import 
#import

@protocol NativeManagerExport

///<对于JS代码是:nativeManager.doSomeThing(s1, s2),JSExport协议根据JS方法,使用多个:进行分割
- (void)doSomeThing:(NSString *)someThing :(NSString *)s2;

///<对于JS代码是:nativeManager.onePushSubmit(s1, s2),JSExport协议根据JS方法中的大写字母进行方法分割
- (void)onePush:(NSString *)s1 submit:(NSString *)s2;

///<对于JS代码是:buttonClick5(s1, s2, s3, s4) 使用JSExport的提供的宏JSExportAs来处理
JSExportAs(morePraramters,
- (void)morePraramtersWithP1:(NSString *)p1 p2:(NSString *)p2 p3:(NSString *)p3 p4:(NSString *)p4
);
@end

@interface NativeManager : NSObject
@end

NativeManager.m代码:

#import "NativeManager.h"

@implementation NativeManager

- (void)doSomeThing:(NSString *)someThing :(NSString *)s2{
NSLog(@"使用OC对象来处理JS的点击事件");
NSLog(@"js 传递 : %@ %@", someThing, s2);
}

- (void)onePush:(NSString *)s1 submit:(NSString *)s2{
NSLog(@"使用OC对象来处理JS的点击事件2");
NSLog(@"js 传递 : %@ %@", s1, s2);
}

- (void)morePraramtersWithP1:(NSString *)p1 p2:(NSString *)p2 p3:(NSString *)p3 p4:(NSString *)p4{
NSLog(@"使用OC对象来处理JS的点击事件3");
NSLog(@"js 传递 : %@ %@ %@ %@", p1, p2, p3, p4);
}

@end

iOSlog日志:

JSToOCDemo[28592:1486323] JS Array: 21,7,harry up 
OC Array: (
21,
7,
"harry up"
)

JSToOCDemo[54490:1751112] result : 38
JSToOCDemo[60727:1932210] callBackDic : {
paramter1 = 60;
paramter2 = 56;
}

JSToOCDemo[28592:1486529] JS点击方法传递参数标题
JSToOCDemo[28592:1486529] JS点击方法传递参数信息

优点:实现JS调用OC代码,使用OC类来管理JS的对应方法,模块化清晰,能处理多个带参数方法

缺点:内存问题需要自己处理好,支持iOS7以上的项目才能使用

3.4 EasyJSWebView第三方代码:

github dukeland/EasyJSWebView

开源中国-珲少 IOS NSInvocation应用与理解

iteye-啸笑天 Objective C运行时(runtime)技术的几个要点总结

HTML代码:


iOS代码:

EasyJSWebView *eWebView = [[EasyJSWebView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:eWebView];

EJSWNativeManager *manager = [EJSWNativeManager new];
//将OC管理类对象manager和JS的全局对象easyJSManager绑定
[eWebView addJavascriptInterfaces:manager WithName:@"easyJSManager"];
eWebView.delegate = self;

NSString *htmlPath = [[NSBundle mainBundle] pathForResource:@"redirect" ofType:@"html"];
NSURLRequest *rq = [NSURLRequest requestWithURL:[NSURL URLWithString:htmlPath]];
[eWebView loadRequest:rq];

EJSWNativeManager.h代码:

#import 

@interface EJSWNativeManager : NSObject
- (void)saveUserInfo:(NSString *)name :(NSString *)password;
@end

EJSWNativeManager.m代码:

#import "EJSWNativeManager.h"

@implementation EJSWNativeManager
- (void)saveUserInfo:(NSString *)name :(NSString *)password{
NSLog(@"EasyJSWebView点击事件带参数");
NSLog(@"js 传递 : %@ %@", name, password);
}
@end

EasyJSWebView源码分析:在UIWebViewDelegate代理的webViewDidStartLoad方法中,根据 [eWebView addJavascriptInterfaces:manager WithName:@”easyJSManager”] 方法的OC管理类对象manager和JS的全局对象easyJSManager在document创建新的子节点,该子节点的href对应的链接是由easyJSManager和manager的方法按照一定方式拼接,在点击HTML上的 “EasyJSWebView点击事件带参数”按钮时,button的onClick事件:Javascript:easyJSManager.saveUserInfo会重新 调用OC的webView: shouldStartLoadWithRequest: navigationType:方法,这个时候再根据一定方式拼接来找到该点击事件所附带的信息。

优点:实现JS调用OC代码,使用OC类来管理JS的对应方法,模块化清晰

缺点:必须继承EasyJSWebView,这使得它和第三方优秀的webview不好同时使用

项目下载地址


推荐阅读
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 移动端常用单位——rem的使用方法和注意事项
    本文介绍了移动端常用的单位rem的使用方法和注意事项,包括px、%、em、vw、vh等其他常用单位的比较。同时还介绍了如何通过JS获取视口宽度并动态调整rem的值,以适应不同设备的屏幕大小。此外,还提到了rem目前在移动端的主流地位。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • PHPMailer邮件类邮件发送功能的使用教学及注意事项
    本文介绍了使用国外开源码PHPMailer邮件类实现邮件发送功能的简单教学,同时提供了一些注意事项。文章涵盖了字符集设置、发送HTML格式邮件、群发邮件以及避免类的重定义等方面的内容。此外,还提供了一些与PHP相关的资源和服务,如传奇手游游戏源码下载、vscode字体调整、数据恢复、Ubuntu实验环境搭建、北京爬虫市场、进阶PHP和SEO人员需注意的内容。 ... [详细]
author-avatar
holy190
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有