这篇文章主要介绍了苹果手机怎么用蓝牙传照片到安卓手机,具有一定借鉴价值,需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获,下面让小编带着大家一起了解一下。
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
downie 4是一款流行的 mac 视频下载工具,可让您从各种网站下载视频,包括 youtube、vimeo、twitter 等。使用 downie 4,您可以轻松下载不同格式和分辨率的视频,以及从视频中提取音轨。
downie 4 的主要优点之一是其简单易用。您需要做的就是复制要下载的视频的 url 并将其粘贴到应用程序中。downie 4 会自动检测视频并为您提供可用下载选项列表。
downie 4 的另一个重要功能是它能够一次下载多个视频。您只需向应用程序添加多个 url,它就会一个一个地下载它们,从而节省您的时间和精力。
总的来说,如果您正在为您的 mac 寻找可靠且高效的视频下载器,downie 4 绝对值得考虑。它易于使用、灵活且支持范围广泛的视频源。
改进的hls支持
hls流下载速度提高了4倍。
dash支持
现在支持dash流。
主要的后处理改进
由于downie在转换之前分析视频,后期处理的一些下载只需要几秒钟而不是几分钟!
简单模式
如果您的首选是尽可能保持简单的用户界面,有一个简单的模式给你!
按网站和播放列表进行文件分组
现在所有下载都可以根据您从哪个播放列表下载播放列表的位置将其分类到文件夹中。
延迟队列开始
安排你的下载半夜,这样你就不会占用其他家庭的带宽!
用户引导提取中的弹出窗口支持
用户引导提取现在可以选择支持弹出窗口,以便您可以登录到在单独窗口中打开登录的网站。
?downie 4 mac破解版下载
整理 | 朱珂欣? ?
出品 | csdn程序人生(id:coder_life)
喜大普奔,就在今天,推特在苹果 app store 更名成功!
据悉,由于未遵循苹果的「铁令」,这「破例」之举让“x”成为目前苹果 app store 内唯一的单字母应用。
更名受阻,遭到苹果「拦路」
半个月前,马斯克给推特换了个耳目一新的新标志 —— “x”,只为将其重塑为一个集音频、视频、信息、支付和银行服务于一体的「万能应用程序」。
随后,在推动改名进程上,也是如火如荼。
推特 ios、android 客户端名称及 logo,平台内 logo 、认证用户账号尾部的徽标,以及公司总部大楼外的 logo 等均已更换为了“x”。
只可惜,在苹果 app store 上更名受阻。
根据苹果用户的反馈,推特只见应用程序标志更改,不见其名称更新。
在苹果 app store 中却仍然保留了原始名称“twitter”,而并非“x”。?
从「坚守底线」到为旧交情「开绿灯」
众所周知,苹果向来铁令如山,以其严格的审核规则而闻名。
两天前,苹果就摆明了态度 —— 拒绝推特将其应用名称“twitter”更改为“x”的请求。
理由很简单,“x”不符合规范。
按照 app store 的相关规定,应用名称至少需要由两个字符组成。
产品设计师 nick sheriff 曾在推特上发文表示,苹果在 ios 上不允许任何应用使用单个字符作为命名。
如果更名获得特批,将是自 app store 成立以来首次破例。
为此,软件开发人员 yusuf alp 甚至提出了一个「解决方法」:“x 和一个空格(之前还是之后)怎么样?”?
令人没想到的是,在事情僵持两天后,推特的更名计划就得到了苹果的「优待」。
如今,打开?app store,苹果用户可以直接通过“x”搜索找到更名后的应用程序。
据 ars technica 报道称,苹果愿意为“x”破例,很有可能是因为苹果与 x corp 首席执行官 linda yaccarino 早前的「交情」。
在 linda yaccarino 接手推特之前,苹果和她此前所在的 nbcuniversal 建立了重要的品牌8797威尼斯老品牌的合作伙伴关系。
但是,目前苹果尚未对其「开绿灯」的行为作出回应。
更名“x”背后的非议与风险
值得关注的是,“x”的更名也带来了一些不利影响。
一位警官在 ars technica 的采访中曾指出:“美国以外的许多品牌,尤其是亚洲的很多品牌都只有一个字符,但并且没有受到 app store 的特殊待遇”。
他还表示,苹果需要进行技术变革才能让推特品牌的重塑顺利进行下去,而这些变化也会对苹果 app store 产生影响。
与此同时,苹果的「破例」,也让不少网友借机调侃道:
“若不能如愿改名,下个目标大概是收购苹果,改掉规则”; “这是库克开后门改了,大佬之间没有那么多条条框框”; “或许应了那句‘有钱能使鬼推磨’”……
而在「非议」之外,“x”将面临的一些商标方面的法律挑战,也不容忽视。
据悉,仅在美国就有近 900 家公司提交了涉及字母 x 的商标注册,其中包括科技巨头 meta 和微软。
商标律师 josh gerben 曾告诉路透社,字母 x 经常在商标中引用,这意味着 x 很有可能会被指控侵犯另一家公司的知识产权。
loeb & loeb 律师事务所的商标律师 douglas masters 也曾表示,徽标的简单性可能会使品牌更难以保护。
对此,你怎么看?
参考链接:
arstechnica /tech-policy/2023/07/blaze-your-glory-twitters-x-becomes-first-one-letter-iphone-app/
bleepingcomputer /news/technology/apple-rejects-new-name-x-for-twitter-ios-app-because-rules/
还没有评论,来说两句吧...