1 / 51

2014

IOS 插件开发培训. 2014. 背景. 为了满足更多地应用场景, ExMobi5.0 版本开始支持原生开发。它是以插件的形式集成到 ExMobi 中, 提供给应用开发人员进行调用。 右 图为通讯录插件和仿 zaker 效果菜单插件的效果图。. 实例. 以简单的 slider 插件控件为例,来讲述 IOS 插件控件的实现。. 定义 xml 标签.

Download Presentation

2014

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. IOS插件开发培训 2014

  2. 背景 为了满足更多地应用场景, ExMobi5.0版本开始支持原生开发。它是以插件的形式集成到ExMobi中, 提供给应用开发人员进行调用。 右图为通讯录插件和仿zaker效果菜单插件的效果图。

  3. 实例 • 以简单的slider插件控件为例,来讲述IOS插件控件的实现。

  4. 定义xml标签 <nativecomponent id="native" style="width:200;height:300"type="ABC_SliderComponent" factoryname="XKPlugin_Test2_ComponentFactory" onchange="changetodo" minvalue =”1” maxvalue=”10”> </nativecomponent>

  5. 定义xml标签 控件名是固定的:nativecomponent 部分控件属性也是固定的,其中包括和基础控件统一的属性,如id、name、style,这些不多说明。具体看下插件控件特有的几个属性: 其它可以根据控件需要,自定义属性,如回调函数等。 插件名是ABC_SliderComponent 插件工厂为:XKPlugin_Test2_ComponentFactory 回调,在用户拖动控件的slider控件的时候,触发js里changetodo方法,支持传参。 注意事项:ios开发,工程内文件都不能同名,所以在命名上要注意唯一性。

  6. 插件流程图 插件类 插件工厂类 …… 插件类 调用xxx插件 getView() view ExMobi页面

  7. 制作插件

  8. 制作插件--获取基础工程 把定义的xml标签文件上传到edn门户,生成插件工程,解压缩,用xcode工具打开,如左图所示。 可以从edn门户获取实例工程,参考实例工程进行开发。 AppPlugin下固定头文件,不要做修改: XKPlugin_ComponentFactory.h XKPlugin_Component.h XKPlugin_Test2_ComponentFactory两个文件是根据定义的xml标签自动生成的,也无须处理。 生成了ABC_SliderComponent文件夹,并且包含了ABC_SliderComponent.h和ABC_SliderComponent.m两个文件,这两个文件就是插件文件。

  9. 制作插件—插件工厂类 XKPlugin_Test2_ComponentFactory插件工厂类代码如下: @implementation XKPlugin_Test2_ComponentFactory - (XKPlugin_Component*) createComponent:(NSString*) type { NSLog(@"XKPlugin_ComponentcreateComponent %@", type); if ([@"ABC_SliderComponent" isEqualToString:type]){ return [[ABC_SliderComponentalloc] init]; } return nil; }

  10. 制作插件--创建view 新建ABC_SliderViewController,继承UIViewController #import <UIKit/UIKit.h> #import "ABC_SliderComponent.h" @interfaceABC_SliderViewController : UIViewController @propertyint width; @propertyint height; @property (strong,nonatomic) UISlider* mySlider; @property (assign,nonatomic) ABC_SliderComponent* delegate; -(void)setRangeMinValue:(float)minValuemaxValue:(float)maxValue; @end 在ABC_SliderViewController.h头文件中,申明setRangeMinValue方法(设置slider控件的起始值和最大值),定义ABC_SliderComponent属性。

  11. - (void)viewDidLoad { [superviewDidLoad]; //初始化滑片 _mySlider = [[UISlideralloc] initWithFrame:CGRectMake(0, 0, 200, 50)]; //设置拖动滑块图 [_mySlidersetThumbImage:[UIImageimageNamed:@"slider_normal.png"] forState:UIControlStateNormal]; [_mySlidersetThumbImage:[UIImageimageNamed:@"slider_normal.png"] forState:UIControlStateHighlighted]; //设置valuechange事件是否实时回调 [_mySlidersetContinuous:NO]; //结束拖动 [_mySlideraddTarget:selfaction:@selector(endDrag:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside]; // 添加 [self.viewaddSubview:_mySlider]; } //结束拖动 -(void) endDrag:(UISlider*) slider { NSLog(@"slider end drag"); NSString* sliderValue = [NSStringstringWithFormat:@"%f",[_mySlidervalue]]; [_delegateonChange:sliderValue]; } //设置slider区间 -(void)setRangeMinValue:(float)minValuemaxValue:(float)maxValue{ [_mySlidersetMinimumValue:minValue]; [_mySlidersetMaximumValue:maxValue]; }

  12. 制作插件—编辑插件类 ABC_SliderComponent.h 继承了 XKPlugin_Component.h, XKPlugin_Component.h中有声明了很多方法 @interfaceXKPlugin_Component : NSObject @property int width;@property int height; -(void) initComponent;-(void) releaseComponent;-(UIView*) getView;-(void) setViewSize:(int)width height:(int) h;-(void) loadXml: (NSString*) xml;-(void) set:(NSString*) name value:(NSString*)value;-(NSString*) get:(NSString*) name;-(void) addChildElement: (NSString*)tag attributes:(NSDictionary*)attributes;-(NSString*) call:(NSString*)functionName             par1:(NSString*)param1 par2:(NSString*)param2  par3:(NSString*)param3  par4:(NSString*)param4             par5:(NSString*)param5  par6:(NSString*)param6  par7:(NSString*)param7;

  13. - (BOOL) helper_callJsScript:(NSString*) script;-(NSString*) helper_getAppId;-(UIImage*) helper_getImage:(NSString*) uri;-(BOOL) helper_setValue:(NSString*) value;-(NSString*) helper_getValue;-(BOOL) _sys_initComponent:(NSString*)appId container:(void*)nativeview;-(void) _sys_releaseComponent;//ExMobi JS脚本动态设置宽、高时触发该回调函数 -(void)onSize; //添加viewController到ExMobi导航bar中 +(void)pushViewController:(UIViewController*)viewController animated:(BOOL)animated; //弹出顶层viewcontroller +(void)popViewControllerAnimated:(BOOL*)animated; //弹出所有原生viewcontroller +(void)popAllViewControllerAnimated:(BOOL*)animated; +(void)presentModalViewController:(UIViewController*)viewController;@end

  14. @property int width;@property int height; 插件控件占据的宽度和高度,这里取的是xml标签中的style中设置的值。 Slider插件需要实现的是getView、set、get、call方法。

  15. 修改ABC_SliderComponent • 修改ABC_SliderComponent文件 • 设置成员变量ABC_SliderViewController; • 在getView方法中创建并返回ABC_SliderViewController,注意要设置其delegate为self自身,此处用到了委托模式。 -(UIView*) getView{ if (sliderView == nil){ //设置slider范围 ABC_SliderViewController* controller = [[ABC_SliderViewControlleralloc] init]; controller.delegate = self; sliderView = controller; } returnsliderView.view; }

  16. 修改ABC_SliderComponent 实现set方法,这个方法是用来获取xml里的属性的。 -(void) set:(NSString*) name value:(NSString*)value{ //设置属性值, //在js中可以调用进行赋值 //xml标签中设置的属性,也会执行此函数来赋值。 if ([@"minvalue"isEqualToString:name]) { minValue = [NSStringstringWithString:value]; NSLog(@"set: minvalue:%@",minValue); }elseif([@"maxvalue"isEqualToString:name]) { maxValue = [NSStringstringWithString:value]; NSLog(@"set: maxvalue:%@",maxValue); }elseif([@"onchange"isEqualToString:name]) { onChange = [NSStringstringWithString:value]; } }

  17. 修改ABC_SliderComponent 实现get方法。 -(NSString*) get:(NSString*) name{ //获得属性值 if ([@"minvalue"isEqualToString: name]){ returnminValue; }elseif ([@"maxvalue"isEqualToString: name]){ returnmaxValue; }elseif ([@"onchange"isEqualToString: name]){ returnonChange; } returnnil; }

  18. 修改ABC_SliderComponent 新增onChange函数,如果slider控件被拖动,就触发ExMobi中的js函数, 具体的函数名在xml中设置,即例子中设置的onchange="changetodo" 。 -(void) onChange:(NSString*) value{ if (onChange != nil){ NSString* script = [NSStringstringWithFormat:@"%@('%@');",onChange,value]; [superhelper_callJsScript:script]; } }

  19. 修改ABC_SliderComponent -(NSString*) call:(NSString*)functionName par1:(NSString*)param1 par2:(NSString*)param2 par3:(NSString*)param3 par4:(NSString*)param4 par5:(NSString*)param5 par6:(NSString*)param6 par7:(NSString*)param7{ //在js中调用给插件传值 if ([@"setRange"isEqualToString: functionName]){ floatminV = [param1 floatValue]; floatmaxV = [param2 floatValue]; [sliderViewsetRangeMinValue:minVmaxValue:maxV]; returnnil; }else{ NSLog(@"ABC_SliderComponent ERROR: unsupported function call : %@" , functionName); returnnil; } } Call方法,在ExMobi的js中可以触发此方法,一般是用来给控件赋值的。

  20. 测试插件 由于插件需要在EDN打包后才能实际使用,为了更好的开发测试,AppPlugin工程内自带了一个测试工程TestAppPlugin,所以插件制作完,可以先在测试工程中测试,测试通过后,再提交到门户上进行打包。 测试工程中有个common文件夹,下面有很多文件。 把AppPlugin写的插件工厂类的头文件复制到测试工程中。 即XKPlugin_Test2_ComponentFactory.h

  21. 测试插件 打开common下的XKPluginManager_ComponentFactory.mm文件,增加如下红色代码。 @implementation XKPluginManager_ComponentFactory - (XKPlugin_ComponentFactory*) createFactory:(NSString*) factoryName { if (_factorys == nil) { _factorys = [[NSMutableDictionaryalloc]init]; } XKPlugin_ComponentFactory* factory = [_factorysobjectForKey:factoryName]; if (factory == nil) { if ([@"XKPlugin_Test2_ComponentFactory" isEqualToString:factoryName]){ factory =[[XKPlugin_Test2_ComponentFactory alloc] init]; [_factoryssetObject:factoryforKey:factoryName]; } } return factory; }

  22. 测试插件 在ABCViewController中增加一个按钮,给按钮添加事件,点击按钮进入到ABC_TestSliderViewController页面, 新建ABC_TestSliderViewController,继承UIViewController,并且勾选生成.xib文件。 在.xib文件中,拖入view控件(x=0,y=60)。 选中view控件,右击拖入到ABC_TestSliderViewController.h中定义成属性,命名为controller。 ABC_TestSliderViewController.h需要实现XKPlugin_ComponentDelegate

  23. 测试插件 #import "ABC_TestSliderViewController.h" #import "XKPlugin_Component.h" #import "XKPluginManager_ComponentFactory.h" @interfaceABC_TestSliderViewController () { XKPlugin_Component* component; } @end @implementationABC_TestSliderViewController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [superinitWithNibName:nibNameOrNilbundle:nibBundleOrNil]; if (self) { // Custom initialization } returnself; }

  24. 测试插件 - (void)viewDidLoad { [superviewDidLoad]; [selfsetTitle:@"Test ABC_SliderComponent"]; //构建factoryManager管理类 XKPluginManager_ComponentFactory* factoryManager = [[XKPluginManager_ComponentFactoryalloc]init]; //根据factoryname创建插件工厂类 XKPlugin_ComponentFactory* factory = [factoryManagercreateFactory:@"XKPlugin_Test2_ComponentFactory"]; //根据插件名创建插件 component = [factory createComponent:@"ABC_SliderComponent"]; //插件为空则提示并返回 if (component == nil) { UIAlertView* alert = [[UIAlertViewalloc] initWithTitle:@"Test" message:@"Load ABC_SliderComponent fail"delegate:nilcancelButtonTitle:@"close"otherButtonTitles:nil]; [alert show]; return; } //传递self到插件中用于接收js回调事件 void* container = (__bridgevoid*)self; [component _sys_initComponent:@"TestApp"container:container]; //设置插件普通属性及事件属性 可用于测试js属性设置 // [component set:@"onchange" value:@"changetodo"]; //初始化插件 [component initComponent];

  25. 测试插件 //获取插件view对象 UIView* compView = [component getView]; //设置控件显示区域 if (compView != nil){ CGRect bound = self.container_.bounds; [self.container_addSubview:compView]; compView.frame = bound; compView.hidden = NO; //设置插件显示宽,高 [component setViewSize:bound.size.widthheight:bound.size.height]; } } - (void)didReceiveMemoryWarning { [superdidReceiveMemoryWarning]; } @end

  26. 打包 切换到文件管理器,获取该插件工程调用的插件工厂类 ,如XKPlugin_Test2_ComponentFactory.h; 获取生成的.a库,如plugin.a; 建立image文件夹,将插件工程所需的所有图片均拷贝至image文件夹中;建立framework文件夹,将插件工程所需的第三方.a库/framework库拷贝至该文件夹;建立xib文件夹,将插件工程所需的xib文件拷贝至改文件夹;建立other目录,将其他类型文件(如xml,plist等)拷贝至该目录,建立plugins目录,该目录下可建立多个插件名目录,将插件配置文件config.xml放置于此内。 把上述的文件放在文件夹里,并且压缩此文件夹为zip包,上传到edn门户上。

  27. 打包 插件工程所需的第三方.a/.framework库 如果用到了ExMobi中没引入的系统库, 就在此文件夹下新建framework.txt, 写上系统库的路径,以换行来分割。 其他类型文件(如xml,plist等) 多个插件名目录, 目录里包含各自的config文件 生成plugin.a的时候,把引入的第三方.a库删掉再build

  28. 打包 包含: • 1:插件工程中的工厂类头文件(必选); • 2:插件.a包(必选); • 3:包含插件配置文件的natives目录,该目录包含插件type命名的文件夹,包含插件配置文件config.xml(必选); • 4:包含第三方静态库及framework.txt文件(系统framework库路径列表)的framework文件夹(可选); • 5:插件工程图片的image文件夹(可选); • 6:包含其他文件的other文件夹(可选);

  29. 打包

  30. 打包 插件配置config.xml: <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <config> <version>1.0.0</version><!--插件版本--> <type> ABC_SliderComponent </type><!--插件名称--> <factoryname>XKPlugin_Test2_ComponentFactory</factoryname><!--插件工厂类名Ios插件特有--> <description>slider插件</description><!--插件描述--> <date>2014-01-11</date><!--插件创建日期--> <vendorurl="www.nj.fiberhome.com.cn" email="">rachel</vendor><!--插件开发者信息--> </config>

  31. FAQ • 插件工程设置采用ARC or MRC 都可以,示例工程提供ARC版 和 MRC版,若设备采用IOS 5.0及以上系统,建议采用ARC方式。 • 类名的冲突 为了避免在打包编译时,插件和ExMobi以及其它lib库的名字冲突,插件中的所有类名(包括插件类及其他辅助类),均应该使用特有的前缀 • 能否在工程中引入第三方.a库 可以,若引入第三方.a库,插件打包时需要放置于framework文件夹,压缩后一起提交。还需要注意的是,提交前可在EDN页面查找ExMobi支持的公共.a库,若插件使用的第三方库若与ExMobi使用的第三方库一样,则无须提交,打包后插件仍可正常使用。 framework也是一样的。

  32. FAQ • 插件工程是否需要引入第三方包? 不需要,插件工程本身不要引入任何的包,如果引入了第三方包,最后插件工程生成的.a可能会和ExMobi有冲突。 可以在测试工程中引入第三方包,进行测试。 • 插件工程中引用的系统Framework框架打包时是否需要提供给EDN? 请先在EDN上查看ExMobi支持的系统Framework框架列表,若插件工程引用的系统库在此列表中则不需要提供,若不在此列表中则需要提供。 • 打包时如何向EDN提供系统Framework框架列表? 假设插件包含了如下图所示系统Framework库:libz.dylib,CoreGraphics.framework,OpenAL.framework:

  33. FAQ 在framework列表中点击右键,选中Show in Finder

  34. FAQ 查看所在目录如下图所示,则相对SDK根目录路径为: usr/lib/libz.dylib

  35. FAQ 查看所在目录如下图所示,则相对SDK根目录路径为: System/Library/Frameworks/CoreGraphics.framework

  36. FAQ 向EDN提交插件工程时,建立framework.txt文件,将需要引用的系统framework路径地址放置于改文件中,格式为:每个路径地址占一行,再将framework.txt文件放置于framework文件夹中压缩打包上传至EDN即可。 • 能否使用插件工程中的图片文件 可以,插件工程中如需图片,按照普通UIImage读取方式使用即可,插件打包时需要放置于image文件夹,压缩后一起提交。需要注意图片文件命名必须使用特殊前缀以保证图片名称唯一,如: if(icon == nil){ //直接使用工程中图片 controller.icon = [UIImageimageNamed:@"ABC_city.png"]; }

  37. FAQ • 插件构建时能否使用xib文件? 可以,提交时需要一起提交打包,需要注意xib文件命名必须使用特殊前缀以保证图片名称唯一。 注意:xib使用时候,请一定不要勾选Use Autolayout选项,否则会导致提交后打包失败。

  38. FAQ • 如何获取ExMobi应用下的图片 通过XKPlugin_Component 基类的-(UIImage*) helper_getImage:(NSString*) uri方法来获取图片,注意仅支持res:前缀的应用内图片。 如:UIImage* arrow = [super helper_getImage:@"res:/image/arrow.png"]; • 如何调用ExMobi页面中的脚本 通过XKPlugin_Component 基类的- (BOOL) helper_callJsScript:(NSString*) script 方法来调用。 如: NSString* script = [NSString stringWithFormat:@"%@('%d','%@','%@');",onSelected_,index,row.code,row.name]; [super helper_callJsScript:script];

  39. FAQ • 如何设置插件控件表单提交值 通过XKPlugin_Component 基类的-(void) setNativeValue:(NSString *)value方法来调用。 如:-(void) setNativeValue:(NSString *)value { [super helper_setValue:value]; } • 如何获取插件控件表单提交值 通过XKPlugin_Component 基类的-(NSString*) helper_getValue; 方法来调用。 如: NSString* script = NSString* script = [super helper_getValue];

  40. FAQ • 能否支持全屏类ViewController布局及多个ViewControler切换 支持,通过XKPlugin_Component基类的 +(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated; 方法来添加viewController到ExMobi中 通过XKPlugin_Component基类的 + (void)popAllViewControllerAnimated:(BOOL)animated; 方法从ExMobi中移除viewController 通过+ (void)popAllViewControllerAnimated:(BOOL)animated; 方法从ExMobi中移除所有添加的viewController

  41. FAQ • 一个插件工程能否编写多个插件类 可以,按照工程创建说明构建多个插件类即可,如下图所示,该插件工程包含了 RefreshListComponent(下拉刷新插件),SliderMenuComponent(3D动态菜单),AnimationComponent(滑动容器插件)等多个插件,只需导出一个.a包即可。

More Related