该楼层疑似违规已被系统折叠?隐藏此楼查看此楼
求大神!!!
单点登录的cas在服务器上运行时,点击记住密码会报500错误(不点记住密码能正常登录)。
把子站调到本机后能记住密码也能正常运行。
服务器环境:tomcat7 jdk7
服务器报错日志:
七月 04, 2018 9:49:23 上午 org.apache.catalina.core.standardwrappervalve invoke
严重: servlet.service() for servlet [cas] in context with path [/cas] threw exception [request processing failed; nested exception is java.lang.runtimeexception: org.springframework.webflow.execution.actionexecutionexception: exception thrown executing [annotatedaction@46c02ae6 targetaction = [evaluateaction@72408653 expression = utryauthenticationviaformaction.submitandfireevent(flowrequestcontext, flowscope.credential, messagecontext), resultexpression = [null]], attributes = map[[empty]]] in state 'realsubmit' of flow 'login' -- action execution attributes were 'map[[empty]]'] with root cause
java.lang.error: unresolved compilation problem:
the method sethttponly(boolean) is undefined for the type cookie
at utry.cas.web.util.cookieutil.setcookie(cookieutil.java:87)
at utry.cas.web.flow.utryauthenticationviaformaction.rememberme(utryauthenticationviaformaction.java:113)
at utry.cas.web.flow.utryauthenticationviaformaction.submitandfireevent(utryauthenticationviaformaction.java:76)
at sun.reflect.generatedmethodaccessor102.invoke(unknown source)
at sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:43)
at java.lang.reflect.method.invoke(method.java:606)
at org.springframework.expression.spel.support.reflectivemethodexecutor.execute(reflectivemethodexecutor.java:113)
at org.springframework.expression.spel.ast.methodreference.getvalueinternal(methodreference.java:102)
at org.springframework.expression.spel.ast.methodreference.access$000(methodreference.java:49)
at org.springframework.expression.spel.ast.methodreference$methodvalueref.getvalue(methodreference.java:347)
at org.springframework.expression.spel.ast.compoundexpression.getvalueinternal(compoundexpression.java:88)
at org.springframework.expression.spel.ast.spelnodeimpl.gettypedvalue(spelnodeimpl.java:131)
at org.springframework.expression.spel.standard.spelexpression.getvalue(spelexpression.java:299)
at org.springframework.binding.expression.spel.springelexpression.getvalue(springelexpression.java:84)
at org.springframework.webflow.action.evaluateaction.doexecute(evaluateaction.java:75)
at org.springframework.webflow.action.abstractaction.execute(abstractaction.java:188)
at org.springframework.webflow.execution.annotatedaction.execute(annotatedaction.java:145)
爬取(食品招商网)app spzs ? 里面的代理信息,web上无法显示,只能下载app
爬取流程:
1.电脑和手机连接同一个wifi,设置fiddler端口8888,设置手机wifi为手动连接,ip地址同电脑,端口同fiddler
2.手机浏览器访问 ip:端口,下载fiddler证书(我刚刚连接的时候可能是操作太快,网络无法访问,下次记得重启一下fiddler或者等待一会)
3.fiddler抓包成功后,手机打开app
?
?4.发现这种app几乎没有反爬,直接把headers和data复制过来,在python里面构造一下
爬取完成
?
这是比较简单的app爬虫,困难点的需要xpose和just trust me ,再难一点则要js逆向来获取某些参数(以后随缘更新,如果有业务需求再来拓展)
这篇文章主要介绍了苹果手机怎么用蓝牙传照片到安卓手机,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。
2019独角兽企业重金招聘python工程师标准>>>?
让你的ios应用程序支持运行javascript脚本:javascriptcore框架详解
? ? 说到javascript脚本,ios开发者都会想到一个名叫javascriptcore的框架。这个框架的确十分强大,其中封装了一套javascript运行环境以及native与js数据类型之间的转换桥梁快码论文。本篇博客主要讨论如何使用此框架来在ios应用中运行javascript脚本。
一、javascriptcore框架结构
? ? 在学习一个框架时,首先应该先了解整个框架的结构,拿ios开发来举例,对于一个陌生的框架,第一步需要先搞清楚这里面都包含哪些类,个各类之间是怎样的关系,这个框架和其他的框架间有无联系以及怎样产生的联系。将些问题搞清楚,有了大体上的认识后,我们再来学习其中的每个类即其他细节的应用将非常容易。我们先来看一张javascriptcore框架的结构图:
这张图是我手工画的,不是那么美观并且没有文字的解释,但是我觉得它能非常直观的表达javascriptcore中包含的类之间的关系。下面我来向你解释这张图究竟表达了什么意思,首先原生的ios应用是支持多线程执行任务的,我们知道javascript是单线程,但这并不代表我们不能在native中异步执行不同的javascript代码。
1.jsvirtualmachine——javascript的虚拟机
????javascriptcore中提供了一个名为jsvirtualmachine的类,顾名思义,这个类可以理解为一个js虚拟机。在native中,只要你愿意,你可以创建任意多个jsvirtualmachine对象,各个jsviretualmachine对象间是相互独立的,他们之间不能共享数据也不能传递数据,如果你把他们放在不同的native线程,他们就可以并行的执行无关的js任务。
2.jscontext——javascript运行环境
? ? jscontext上下文对象可以理解为是js的运行环境,同一个jsvirtualmachine对象可以关联多个jscontext对象,并且在webview中每次刷新操作后,此webview的js运行环境都是不同的jscontext对象。其作用就是用来执行js代码,在native和js间进行数据的传递。
3.jsvalue——javascript值对象
? ? javascript和objective-c虽然都是面向对象语言,但其实现机制完全不同,oc是基于类的,js是基于原型的,并且他们的数据类型间也存在很大的差异。因此若要在native和js间无障碍的进行数据的传递,就需要一个中间对象做桥接,这个对象就是jsvalue。
4.jsexport
? ? jsexport是一个协议,native中遵守此解析的类可以将方法和属性转换为js的接口供js调用。
5.一些用于c语言的结构
? ? 你一定注意到了,上图的右下角还有一块被虚线包围的区域,其中的"类"都是c语言风格,javascriptcore框架是支持在objective-c、swift和c三种语言中使用的。
二、在native中运行javascript脚本代码
? ? 我们先来编写一个最简单的例子,使用oc代码来执行一段js脚本。首先新建一个文件,将其后缀设置为.js,我这里将它命令为main.js,在其中编写如下代码:
(function(){
console.log("hello native");
})();
上面是一个自执行的函数,其中打印了“hello native”字符串。在native中编写如下代码:
- (void)viewdidload {
[super viewdidload];
nsstring * path = [[nsbundle mainbundle] pathforresource:@"main" oftype:@"js"];
nsdata * jsdata = [[nsdata alloc]initwithcontentsoffile:path];
nsstring * jscode = [[nsstring alloc]initwithdata:jsdata encoding:nsutf8stringencoding];
self.jscontext = [[jscontext alloc]init];
[self.jscontext evaluatescript:jscode];
}
需要注意,其实这里我将创建的jscontext对象作为了当前视图控制器的属性,这样做的目的仅仅是为了方便调试,不过不对此context对象进行引用,当viewdidload函数执行完成后,js运行环境也将被销毁,我们就无法在safari中直观的看到js代码的执行结果了。
? ? 运行工程,记得要打开safari浏览器的自动显示jscontent检查器,如下图:
当ios模拟器跑起来后,safari会自动弹出开发者工具,在控制台里面可以看到来自javascript的真挚问候:
刚才我们只是简单了通过原生调用了一段js代码,但是如果native在调js方法时无法传参那也太low了,我们可以直接将要传递的参数格式化到字符串中,修改main.js文件如下:
function put(name){
console.log("hello " name);
};
put(%@);
再封装一个oc方法如下:
-(void)runjs_hello:(nsstring *)name{
nsstring * path = [[nsbundle mainbundle] pathforresource:@"main" oftype:@"js"];
nsdata * jsdata = [[nsdata alloc]initwithcontentsoffile:path];
nsstring * jscode = [[nsstring alloc]initwithdata:jsdata encoding:nsutf8stringencoding];
nsstring * finistring = [nsstring stringwithformat:jscode,name];
[self.jscontext evaluatescript:finistring];
}
在viewdidload中进行调用,如下:
- (void)viewdidload {
[super viewdidload];
self.jscontext = [[jscontext alloc]init];
[self runjs_hello:@"'阿凡达'"];
}
运行再看safari控制台的结果,编程了hello 阿凡达~:
其实evaluatescript函数执行后会将js代码的执行结果进行返回,是jsvalue类型的对象,后面会再介绍。
三、在javascript中调用native方法
? ? 有来无往非君子,同样也可以在原生中编写方法让js来调用,示例如下:
- (void)viewdidload {
[super viewdidload];
void(^block)() = ^(){
nslog(@"hello javascript");
};
self.jscontext = [[jscontext alloc]init];
[self.jscontext setobject:block forkeyedsub:@"oc_hello"];
}
上面setobject:forkeyedsub:方法用来向jscontext环境的全局对象中添加属性,这里添加了一个函数属性,取名为oc_hello。这里javascriptcore会自动帮我们把一些数据类型进行转换,会将oc的函数转换为js的函数,运行工程,在safari的控制台中调用oc_hello函数,可以看到在xcode控制台输出了对javascript的真挚问候,如下:
同样,如果声明的block是带参数的,js在调用此oc方法时也需要传入参数,如果block有返回值,则在js中也能获取到返回值,例如:
bool (^block)(nsstring *) = ^(nsstring *name){
nslog(@"%@", [nsstring stringwithformat:@"hello %@",name]);
return yes;
};
self.jscontext = [[jscontext alloc]init];
[self.jscontext setobject:block forkeyedsub:@"oc_hello"];
四、深入jscontext类
? ? 看到这,你已经学会最基础的oc与js互相问好(交互)。下面我们再来深入看下jscontext中的属性和方法。
? ? 创建jscontext对象有如下两种方式:
//创建一个新的js运行环境
- (instancetype)init;
//创建一个新的js运行环境 并关联到某个虚拟机对象上
- (instancetype)initwithvirtualmachine:(jsvirtualmachine *)virtualmachine;
? ? 执行js代码有如下两个方法:
//执行js代码 结果将封装成jsvalue对象返回
- (jsvalue *)evaluatescript:(nsstring *);
//作用同上
- (jsvalue *)evaluatescript:(nsstring *) withsourceurl:(nsurl *)sourceurl ns_available(10_10, 8_0);
? ? 下面的属性和方法可以获取到js运行环境中的一些信息:
//当前的js运行环境 当js调用oc方法时,在oc方法中可以用此方法获取到js运行环境
(jscontext *)currentcontext;
//获取当前执行的js函数,当js调用oc方法时,在oc方法中可以用此方法获取到执行的函数
(jsvalue *)currentcallee;
//获取当前执行的js函数中的this指向的对象
(jsvalue *)currentthis;
//获取当前执行函数的参数列表,当js调用oc方法时,在oc方法中可以用此方法获取到执行的函数的参数列表
(nsarray *)currentarguments;
//获取当前js运行环境的全局对象
@property (readonly, strong) jsvalue *globalobject;
//当运行的javascript代码抛出了未捕获的异常时,这个属性会被赋值为抛出的异常
@property (strong) jsvalue *exception;
//设置为一个异常捕获的block,如果异常被此block捕获,exception属性就不再被赋值了
@property (copy) void(^exceptionhandler)(jscontext *context, jsvalue *exception);
//当前运行环境所关联的虚拟机
@property (readonly, strong) jsvirtualmachine *virtualmachine;
//当前运行环境名称
@property (copy) nsstring *name;
//获取当前js运行环境全局对象上的某个属性
- (jsvalue *)objectforkeyedsub:(id)key;
//设置当前js运行环境全局对象上的属性
- (void)setobject:(id)object forkeyedsub:(nsobject
//将c语言环境的js运行环境转换为oc环境的js运行环境
(jscontext *)contextwithjsglobalcontextref:(jsglobalcontextref)jsglobalcontextref;
//c语言环境的js运行上下文
@property (readonly) jsglobalcontextref jsglobalcontextref;
五、深入jsvalue类
? ? jsvalue是javascript与objective-c之间的数据桥梁。在objective-c中调用js脚本或者js调用oc方法都可以使用jsvalue来传输数据。其中属性和方法示例如下:
//所对应的js运行环境
@property (readonly, strong) jscontext *context;
//在指定的js运行环境中创建一个jsvalue对象
(jsvalue *)valuewithobject:(id)value incontext:(jscontext *)context;
//创建布尔值
(jsvalue *)valuewithbool:(bool)value incontext:(jscontext *)context;
//创建浮点值
(jsvalue *)valuewithdouble:(double)value incontext:(jscontext *)context;
//创建32位整型值
(jsvalue *)valuewithint32:(int32_t)value incontext:(jscontext *)context;
//创建32位无符号整形值
(jsvalue *)valuewithuint32:(uint32_t)value incontext:(jscontext *)context;
//创建空的js对象
(jsvalue *)valuewithnewobjectincontext:(jscontext *)context;
//创建空的js数组
(jsvalue *)valuewithnewarrayincontext:(jscontext *)context;
//创建js正则对象
(jsvalue *)valuewithnewregularexpressionfrompattern:(nsstring *)pattern flags:(nsstring *)flags incontext:(jscontext *)context;
//创建js错误信息
(jsvalue *)valuewithnewerrorfrommessage:(nsstring *)message incontext:(jscontext *)context;
//创建js null值
(jsvalue *)valuewithnullincontext:(jscontext *)context;
//创建js undefined值
(jsvalue *)valuewithundefinedincontext:(jscontext *)context;
javascript中的数据类型和objective-c的数据类型还是有着很大的差异,其中对应关系如下:
objective-c?javascriptnilundefinednsnullnullnsstringstringnsnumbernumber booleannsdictionary ??objectnsarrayarraynsdatedate? ?blockfunctionidobjectclassobject
下面这些方法可以将jsvalue值转换为objective-c中的数据类型:
//将jsvalue转换为oc对象
- (id)toobject;
//将jsvalue转换成特定oc类的对象
- (id)toobjectofclass:(class)expectedclass;
//将jsvalue转换成布尔值
- (bool)tobool;
//将jsvalue转换成浮点值
- (double)todouble;
//将jsvalue转换成32位整型值
- (int32_t)toint32;
//将jsvalue转换成32位无符号整型值
- (uint32_t)touint32;
//将jsvalue转换成nsnumber值
- (nsnumber *)tonumber;
//将jsvalue转换成nsstring值
- (nsstring *)tostring;
//将jsvalue转换成nsdate值
- (nsdate *)todate;
//将jsvalue转换成nsarray值
- (nsarray *)toarray;
//将jsvalue转换成nsdictionary值
- (nsdictionary *)todictionary;
//获取jsvalue对象中某个属性的值
- (jsvalue *)valueforproperty:(nsstring *)property;
//设置jsvalue对象中某个属性的值
- (void)setvalue:(id)value forproperty:(nsstring *)property;
//删除jsvalue对象中的某个属性
- (bool)deleteproperty:(nsstring *)property;
//判断jsvalue对象中是否包含某个属性
- (bool)hasproperty:(nsstring *)property;
//定义jsvalue中的某个属性 这个方法和javascript中object构造函数的defineproperty方法一致
/*
第2个参数设置此属性的描述信息 可以设置的键值如下:
nsstring * const jspropertydeorwritablekey;//设置布尔值 是否可写
nsstring * const jspropertydeorenumerablekey;//设置布尔值 是否可枚举
nsstring * const jspropertydeorconfigurablekey;//设置布尔值 是否可配置
nsstring * const jspropertydeorvaluekey;//设置此属性的值
nsstring * const jspropertydeorgetkey;//设置此属性的get方法
nsstring * const jspropertydeorsetkey;//设置此属性的set方法
以上set、get方法的键和value、可写性的键不能同时存在,其语法是javascript保持一致
*/
- (void)defineproperty:(nsstring *)property deor:(id)deor;
//获取js数组对象某个下标的值
- (jsvalue *)valueatindex:(nsuinteger)index;
//设置js数组对象某个下标的值
- (void)setvalue:(id)value atindex:(nsuinteger)index;
//判断此对象是否为undefined
@property (readonly) bool isundefined;
//判断此对象是否为null
@property (readonly) bool isnull;
//判断此对象是否为布尔值
@property (readonly) bool isboolean;
//判断此对象是否为数值
@property (readonly) bool isnumber;
//判断此对象是否为字符串
@property (readonly) bool isstring;
//判断此对象是否为object对象
@property (readonly) bool isobject;
//判断此对象是否为数组
@property (readonly) bool isarray;
//判断此对象是否为日期对象
@property (readonly) bool isdate;
//比较两个jsvalue是否全相等 对应javascript中的===
- (bool)isequaltoobject:(id)value;
//比较两个jsvalue对象的值是否相等 对应javascript中的==
- (bool)isequalwithtypecoerciontoobject:(id)value;
//判断某个对象是否在当前对象的原型链上
- (bool)isinstanceof:(id)value;
//如果jsvalue是function对象 可以调用此方法 和javascript中的call方法一致
- (jsvalue *)callwitharguments:(nsarray *)arguments;
//如果jsvalue是一个构造方法对象 可以调用此方法 和javascript中使用new关键字一致
- (jsvalue *)constructwitharguments:(nsarray *)arguments;
//用此对象进行函数的调用 当前对象会被绑定到this中
- (jsvalue *)invokemethod:(nsstring *)method witharguments:(nsarray *)arguments;
//将cgpoint转换为jsvalue对象
(jsvalue *)valuewithpoint:(cgpoint)point incontext:(jscontext *)context;
//将nsrange转换为jsvalue对象
(jsvalue *)valuewithrange:(nsrange)range incontext:(jscontext *)context;
//将cgrect转换为jsvalue对象
(jsvalue *)valuewithrect:(cgrect)rect incontext:(jscontext *)context;
//将cgsize转换为jsvalue对象
(jsvalue *)valuewithsize:(cgsize)size incontext:(jscontext *)context;
//转换成cgpoint数据
- (cgpoint)topoint;
//转换成nsrange数据
- (nsrange)torange;
//转换成cgrect数据
- (cgrect)torect;
//转换为cgsize数据
- (cgsize)tosize;
//将c风格的jsvalueref对象转换为jsvalue对象
(jsvalue *)valuewithjsvalueref:(jsvalueref)value incontext:(jscontext *)context;
其实在javascriptcore框架中还有一个jsmanagervalue类,这个的主要作用是管理内存。虽然我们在编写objective-c代码时有强大的自动引用技术(arc技术),我们一般无需关心对象的内存问题,在编写javascript代码时也有强大的垃圾回收机制(这种机制下甚至连循环引用都不是问题),但是在oc和js混合开发时,就很容易出现问题了,比如一个js垃圾回收机制释放掉的对象oc中却还在用,反过来也是一样。jsmanagervalue对jsvalue进行了一层包装,它可以保证在适合时候使用这个对象时对象都不会被释放,其中方法如下:
//创建jsvlaue对象的包装jsmanagervalue
(jsmanagedvalue *)managedvaluewithvalue:(jsvalue *)value;
(jsmanagedvalue *)managedvaluewithvalue:(jsvalue *)value andowner:(id)owner;
- (instancetype)initwithvalue:(jsvalue *)value;
//获取所包装的jsvalue对象
@property (readonly, strong) jsvalue *value;
六、objective-c与javascript复杂对象的映射
? ? 我们在使用javascript调用objective-c方法的实质是将一个oc函数设置为了js全局对象的一个属性,当然我们也可以设置非函数的属性或者任意jsvalue(或者可以转换为jsvalue)的值。例如:
self.jscontext = [[jscontext alloc]init];
//向js全局对象中添加一个获取当前native设备类型的属性
[self.jscontext setobject:@"ios" forkeyedsub:@"devicetype"];
但是如果我们想把oc自定义的一个类的对象设置为js全局对象的某个属性,js和oc有着完全不同的对象原理,如果不做任何处理,js是接收不到oc对象中定义的属性和方法的。这时就需要使用到前面提到的jsexport协议,需要注意,这个协议不是用来被类遵守的,它里面没有规定任何方法,其是用来被继承定义新的协议的,自定义的协议中约定的方法和属性可以在js中被获取到,示例如下:
oc中新建一个自定义的类:
@protocol myobjectprotocol
@property(nonatomic,strong)nsstring * name;
@property(nonatomic,strong)nsstring * subject;
@property(nonatomic,assign)nsinteger age;
-(void)sayhi;
@end
@interface myobject : nsobject
@property(nonatomic,strong)nsstring * name;
@property(nonatomic,strong)nsstring * subject;
@property(nonatomic,assign)nsinteger age;
@end
@implementation myobject
-(void)sayhi{
nslog(@"hello javascript");
}
@end
添加到js全局对象中:
myobject* object = [myobject new];
object.name = @"jaki";
object.age = 25;
object.subject = @"oc";
[jscontext setobject:object forkeyedsub:@"deviceobject"];
在js运行环境中可以完整的到deviceobject对象,如下:
七、c语言风格的api解释
? ? javascriptcore框架中除了包含完整的objective-c和swift语言的api外,也提供了对c语言的支持。
? ? 与js运行环境相关的方法如下:
//创建一个jscontextref组
/*
jscontextref相当于jscontext,同一组中的数据可以共享
*/
jscontextgroupref jscontextgroupcreate(void);
//内存引用
jscontextgroupref jscontextgroupretain(jscontextgroupref group);
//内存引用释放
void jscontextgrouprelease(jscontextgroupref group);
//创建一个全局的运行环境
jsglobalcontextref jsglobalcontextcreate(jsclassref globalobjectclass);
//同上
jsglobalcontextref jsglobalcontextcreateingroup(jscontextgroupref group, jsclassref globalobjectclass);
//内存引用
jsglobalcontextref jsglobalcontextretain(jsglobalcontextref ctx);
//内存引用释放
void jsglobalcontextrelease(jsglobalcontextref ctx);
//获取全局对象
jsobjectref jscontextgetglobalobject(jscontextref ctx);
//获取jscontextref组
jscontextgroupref jscontextgetgroup(jscontextref ctx);
//获取全局的运行环境
jsglobalcontextref jscontextgetglobalcontext(jscontextref ctx);
//获取运行环境名
jsstringref jsglobalcontextcopyname(jsglobalcontextref ctx);
//设置运行环境名
void jsglobalcontextsetname(jsglobalcontextref ctx, jsstringref name);
? ? 与定义js对象的相关方法如下:
//定义js类
/*
参数jsclassdefinition是一个结构体 其中可以定义许多回调
*/
jsclassref jsclasscreate(const jsclassdefinition* definition);
//引用内存
jsclassref jsclassretain(jsclassref jsclass);
//释放内存
void jsclassrelease(jsclassref jsclass);
//创建一个js对象
jsobjectref jsobjectmake(jscontextref ctx, jsclassref jsclass, void* data);
//定义js函数
jsobjectref jsobjectmakefunctionwithcallback(jscontextref ctx, jsstringref name, jsobjectcallasfunctioncallback callasfunction);
//定义构造函数
jsobjectref jsobjectmakeconstructor(jscontextref ctx, jsclassref jsclass, jsobjectcallasconstructorcallback callasconstructor);
//定义数组
jsobjectref jsobjectmakearray(jscontextref ctx, size_t argumentcount, const jsvalueref arguments[], jsvalueref* exception);
//定义日期对象
jsobjectref jsobjectmakedate(jscontextref ctx, size_t argumentcount, const jsvalueref arguments[], jsvalueref* exception);
//定义异常对象
jsobjectref jsobjectmakeerror(jscontextref ctx, size_t argumentcount, const jsvalueref arguments[], jsvalueref* exception);
//定义正则对象
jsobjectref jsobjectmakeregexp(jscontextref ctx, size_t argumentcount, const jsvalueref arguments[], jsvalueref* exception);
//定义函数对象
jsobjectref jsobjectmakefunction(jscontextref ctx, jsstringref name, unsigned parametercount, const jsstringref parameternames[], jsstringref body, jsstringref sourceurl, int startinglinenumber, jsvalueref* exception);
//获取对象的属性
jsvalueref jsobjectgetprototype(jscontextref ctx, jsobjectref object);
//设置对象的属性
void jsobjectsetprototype(jscontextref ctx, jsobjectref object, jsvalueref value);
//检查对象是否包含某个属性
bool jsobjecthasproperty(jscontextref ctx, jsobjectref object, jsstringref propertyname);
//获取对象属性
jsvalueref jsobjectgetproperty(jscontextref ctx, jsobjectref object, jsstringref propertyname, jsvalueref* exception);
//定义对象属性
void jsobjectsetproperty(jscontextref ctx, jsobjectref object, jsstringref propertyname, jsvalueref value, jspropertyattributes attributes, jsvalueref* exception);
//删除对象属性
bool jsobjectdeleteproperty(jscontextref ctx, jsobjectref object, jsstringref propertyname, jsvalueref* exception);
//获取数组值
jsvalueref jsobjectgetpropertyatindex(jscontextref ctx, jsobjectref object, unsigned propertyindex, jsvalueref* exception);
//设置数组值
void jsobjectsetpropertyatindex(jscontextref ctx, jsobjectref object, unsigned propertyindex, jsvalueref value, jsvalueref* exception);
//获取私有数据
void* jsobjectgetprivate(jsobjectref object);
//设置私有数据
bool jsobjectsetprivate(jsobjectref object, void* data);
//判断是否为函数
bool jsobjectisfunction(jscontextref ctx, jsobjectref object);
//将对象作为函数来调用
jsvalueref jsobjectcallasfunction(jscontextref ctx, jsobjectref object, jsobjectref thisobject, size_t argumentcount, const jsvalueref arguments[], jsvalueref* exception);
//判断是否为构造函数
bool jsobjectisconstructor(jscontextref ctx, jsobjectref object);
//将对象作为构造函数来调用
jsobjectref jsobjectcallasconstructor(jscontextref ctx, jsobjectref object, size_t argumentcount, const jsvalueref arguments[], jsvalueref* exception);
//获取所有属性名
jspropertynamearrayref jsobjectcopypropertynames(jscontextref ctx, jsobjectref object);
//进行内存引用
jspropertynamearrayref jspropertynamearrayretain(jspropertynamearrayref array);
//内存释放
void jspropertynamearrayrelease(jspropertynamearrayref array);
//获取属性个数
size_t jspropertynamearraygetcount(jspropertynamearrayref array);
//在属性名数组中取值
jsstringref jspropertynamearraygetnameatindex(jspropertynamearrayref array, size_t index);
//添加属性名
void jspropertynameaccumulatoraddname(jspropertynameaccumulatorref accumulator, jsstringref propertyname);
? ? js数据类型相关定义在jsvalueref中,如下:
//获取值的类型
/*
枚举如下:
typedef enum {
kjstypeundefined,
kjstypenull,
kjstypeboolean,
kjstypenumber,
kjstypestring,
kjstypeobject
} jstype;
*/
jstype jsvaluegettype(jscontextref ctx, jsvalueref);
//判断是否为undefined类型
bool jsvalueisundefined(jscontextref ctx, jsvalueref value);
//判断是否为null类型
bool jsvalueisnull(jscontextref ctx, jsvalueref value);
//判断是否为布尔类型
bool jsvalueisboolean(jscontextref ctx, jsvalueref value);
//判断是否为数值类型
bool jsvalueisnumber(jscontextref ctx, jsvalueref value);
//判断是否为字符串类型
bool jsvalueisstring(jscontextref ctx, jsvalueref value);
//判断是否为对象类型
bool jsvalueisobject(jscontextref ctx, jsvalueref value);
//是否是类
bool jsvalueisobjectofclass(jscontextref ctx, jsvalueref value, jsclassref jsclass);
//是否是数组
bool jsvalueisarray(jscontextref ctx, jsvalueref value);
//是否是日期
bool jsvalueisdate(jscontextref ctx, jsvalueref value);
//比较值是否相等
bool jsvalueisequal(jscontextref ctx, jsvalueref a, jsvalueref b, jsvalueref* exception);
//比较值是否全等
bool jsvalueisstrictequal(jscontextref ctx, jsvalueref a, jsvalueref b);
//是否是某个类的实例
bool jsvalueisinstanceofconstructor(jscontextref ctx, jsvalueref value, jsobjectref constructor, jsvalueref* exception);
//创建undefined值
jsvalueref jsvaluemakeundefined(jscontextref ctx);
//创建null值
jsvalueref jsvaluemakenull(jscontextref ctx);
//创建布尔值
jsvalueref jsvaluemakeboolean(jscontextref ctx, bool boolean);
//创建数值
jsvalueref jsvaluemakenumber(jscontextref ctx, double number);
//创建字符串值
jsvalueref jsvaluemakestring(jscontextref ctx, jsstringref string);
//通过json创建对象
jsvalueref jsvaluemakefromjsonstring(jscontextref ctx, jsstringref string);
//将对象转为json字符串
jsstringref jsvaluecreatejsonstring(jscontextref ctx, jsvalueref value, unsigned indent, jsvalueref* exception);
//进行布尔值转换
bool jsvaluetoboolean(jscontextref ctx, jsvalueref value);
//进行数值转换
double jsvaluetonumber(jscontextref ctx, jsvalueref value, jsvalueref* exception);
//字符串值赋值
jsstringref jsvaluetostringcopy(jscontextref ctx, jsvalueref value, jsvalueref* exception);
//值与对象的转换
jsobjectref jsvaluetoobject(jscontextref ctx, jsvalueref value, jsvalueref* exception);
? ? 在c风格的api中,字符串也被包装成了jsstringref类型,其中方法如下:
//创建js字符串
jsstringref jsstringcreatewithcharacters(const jschar* chars, size_t numchars);
jsstringref jsstringcreatewithutf8cstring(const char* string);
//内存引用于释放
jsstringref jsstringretain(jsstringref string);
void jsstringrelease(jsstringref string);
//获取字符串长度
size_t jsstringgetlength(jsstringref string);
//转成utf8字符串
size_t jsstringgetutf8cstring(jsstringref string, char* buffer, size_t buffersize);
//字符串比较
bool jsstringisequal(jsstringref a, jsstringref b);
bool jsstringisequaltoutf8cstring(jsstringref a, const char* b);
八、hybird app 构建思路
? ? hybird app是指混合模式移动应用,即其中既包含原生的结构有内嵌有web的组件。这种app不仅性能和用户体验可以达到和原生所差无几的程度,更大的优势在于bug修复快,版本迭代无需发版。3月8日苹果给许多开发者发送了一封警告邮件,主要是提示开发者下载脚本动态更改app原本行为的做法将会被提审拒绝。其实这次邮件所提内容和hybird app并无太大关系(对reactnative也没有影响),苹果警告的是网络下发脚本并且使用runtime动态修改native行为的应用,hybird app的实质并没有修改原native的行为,而是将下发的资源进行加载和界面渲染,类似webview。
? ? 关于混合开发,我们有两种模式:
????1.native内嵌webview,通过js与oc交互实现业务无缝的衔接。
? ? 无论是uiwebview还是wkwebkit,我们都可以在其中拿到当前的jscontext,然是使用前面介绍的方法便可以实现数据互通与交互。这种方式是最简单的混合开发,但其性能和原生相比要差一些。示意图如下:
? ? 2.下发js脚本,使用类似reactnative的框架进行原生渲染
? ? 这是一种效率非常高的混合开发模式,并且reactnative也本身支持android和ios公用一套代码。我们也可以使用javascriptcore自己实现一套解析逻辑,使用javascript来编写native应用,要完整实现这样一套东西太复杂了,我们也没有能力完成一个如此庞大的工程,但是我们可以做一个小demo来模拟其原理,这样可以更好的帮助我们理解hybird app的构建原理。
我们打算实现这样的功能:通过下发js脚本创建原生的uilabel标签与uibutton控件,首先编写js代码如下:
(function(){
console.log("progectinit");
//js脚本加载完成后 自动render界面
return render();
})();
//js标签类
function label(rect,text,color){
this.rect = rect;
this.text = text;
this.color = color;
this.typename = "label";
}
//js按钮类
function button(rect,text,callfunc){
this.rect = rect;
this.text = text;
this.callfunc = callfunc;
this.typename = "button";
}
//js rect类
function rect(x,y,width,height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
//js颜色类
function color(r,g,b,a){
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
//渲染方法 界面的渲染写在这里面
function render(){
var rect = new rect(20,100,280,30);
var color = new color(1,0,0,1);
var label = new label(rect,"hello world",color);
var rect2 = new rect(20,150,280,30);
var color2 = new color(0,1,0,1);
var label2 = new label(rect2,"hello native",color2);
var rect3 = new rect(20,200,280,30);
var color3 = new color(0,0,1,1);
var label3 = new label(rect3,"hello javascript",color3);
var rect4 = new rect(20,240,280,30);
var button = new button(rect4,"我是一个按钮",function(){
var randcolor = new color(math.random(),math.random(),math.random(),1);
globle.changebackgroundcolor(randcolor);
});
//将控件以数组形式返回
return [label,label2,label3,button];
}
创建一个objective-c类绑定到js全局对象上,作为oc方法的桥接器:
//.h
#import
#import
#import
@protocol globleprptocol
-(void)changebackgroundcolor:(jsvalue *)value;
@end
@interface globle : nsobject
@property(nonatomic,weak)uiviewcontroller * ownercontroller;
@end
//.m
#import "globle.h"
@implementation globle
-(void)changebackgroundcolor:(jsvalue *)value{
self.ownercontroller.view.backgroundcolor = [uicolor colorwithred:value[@"r"].todouble green:value[@"g"].todouble blue:value[@"b"].todouble alpha:value[@"a"].todouble];
}
@end
在viewcontroller中实现一个界面渲染的render解释方法,并建立按钮的方法转换,如下:
//
// viewcontroller.m
// javascriptcoretest
//
// created by vip on 17/3/6.
// 威尼斯人2299 copyright ? 2017年 jaki. all rights reserved.
//
#import "viewcontroller.h"
#import
#import "globle.h"
@interface viewcontroller ()
@property(nonatomic,strong)jscontext * jscontext;
@property(nonatomic,strong)nsmutablearray * actionarray;
@property(nonatomic,strong)globle * globle;
@end
@implementation viewcontroller
- (void)viewdidload {
[super viewdidload];
//创建js运行环境
self.jscontext = [jscontext new];
//绑定桥接器
self.globle = [globle new];
self.globle.ownercontroller = self;
self.jscontext[@"globle"] = self.globle;
self.actionarray = [nsmutablearray array];
[self render];
}
//界面渲染解释器
-(void)render{
nsstring * path = [[nsbundle mainbundle] pathforresource:@"main" oftype:@"js"];
nsdata * jsdata = [[nsdata alloc]initwithcontentsoffile:path];
nsstring * jscode = [[nsstring alloc]initwithdata:jsdata encoding:nsutf8stringencoding];
jsvalue * jsvlaue = [self.jscontext evaluatescript:jscode];
for (int i=0; i
jsvalue * subvalue = [jsvlaue objectatindexedsub:i];
if ([[subvalue objectforkeyedsub:@"typename"].tostring isequaltostring:@"label"]) {
uilabel * label = [uilabel new];
label.frame = cgrectmake(subvalue[@"rect"][@"x"].todouble, subvalue[@"rect"][@"y"].todouble, subvalue[@"rect"][@"width"].todouble, subvalue[@"rect"][@"height"].todouble);
label.text = subvalue[@"text"].tostring;
label.textcolor = [uicolor colorwithred:subvalue[@"color"][@"r"].todouble green:subvalue[@"color"][@"g"].todouble blue:subvalue[@"color"][@"b"].todouble alpha:subvalue[@"color"][@"a"].todouble];
[self.view addsubview:label];
}else if ([[subvalue objectforkeyedsub:@"typename"].tostring isequaltostring:@"button"]){
uibutton * button = [uibutton buttonwithtype:uibuttontypesystem];
button.frame = cgrectmake(subvalue[@"rect"][@"x"].todouble, subvalue[@"rect"][@"y"].todouble, subvalue[@"rect"][@"width"].todouble, subvalue[@"rect"][@"height"].todouble);
[button settitle:subvalue[@"text"].tostring forstate:uicontrolstatenormal];
button.tag = self.actionarray.count;
[button addtarget:self action:@selector(buttonaction:) forcontrolevents:uicontroleventtouchupinside];
[self.actionarray addobject:subvalue[@"callfunc"]];
[self.view addsubview:button];
}
}
}
//按钮转换方法
-(void)buttonaction:(uibutton *)btn{
jsvalue * action = self.actionarray[btn.tag];
//执行js方法
[action callwitharguments:nil];
}
@end
运行工程,效果如下图所示,点击按钮即可实现简单的界面颜色切换:
上面的示例工程我只实现了uilabel类与uibutton类的js-oc转换,如果将原生控件和js对象再进行一层绑定,并且实现大部分js类与原生类和他们内部的属性,则我们就开发了一套hybird app开发框架,但并没有这个必要,如果你对更多兴趣,可以深入学习下reactnative。
? ? 文中的示例demo我放在了github上,地址如下:github - zyhshao/demo-hybird: 混合开发在ios中的构建思路demo。
前端学习新人,有志同道合的朋友,欢迎交流与指导,qq群:541458536
转载于: my.oschina /u/2340880/blog/856321
还没有评论,来说两句吧...