IOS-使用framework实现功能模块动态更新
2017-07-06 16:37
891 查看
测试Xcode版本为6.1.1
实现过程简述:把想要的作为动态更新的模块,移动到我们创建的Framework工程中,然后得到我们想要的动态库文件,把此文件再通过iTunes放到“主程序”项目的document文件夹下,从而实现从主程序中去加载此动态库,从而实现功能模块的动态更新效果。理想效果为支付宝APP,而支付宝采用的是HTML5(网页)的形式实现的,这是目前最通用的实现方式,但是不适用于复杂界面效果。
第一步:创建IOS Framework工程
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/e0adb10cf8a88aa6b5413669d25913a8.png)
第二步:生成的工程中原本的类删掉不用
然后添加新的类文件来实现动态加载效果
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/20475ba0543ead608021da81203319d6.jpeg)
图片和测试界面不多说,重点为PacteraFramework这个类文件中的代码部分:
添加入口方法:
[objc] view plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/*
主程序和此动态库的关系枢纽,也就是从“主程序”到“动态库内封装的程序”的入口方法
@param mainCon “主程序”中入口按钮所在的ViewController对象
@param bundle 此动态库在document文件中的路径,用于xib的加载和图片的加载
*/
-(void)showView:(id)mainCon withBundle:(NSBundle *)bundle;
实现此方法:
[objc] view plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
-(void)showView:(id)mainCon withBundle:(NSBundle *)bundle
{
/*
*初始化第一个controller
TheFirstViewController继承于RootViewController
*这里的重点是xib文件的加载
通常我们在初始化xib的时候并不是很在意bundle:这个参数,一般情况下都会赋予nil值
其实我们所用到的图片、xib等资源文件都是在程序内部中获取的,也就是我们常用的[NSBundle mainBundle]中获取,所谓的NSBundle本质上就是一个路径,mainBundle指向的是.app下。
而如果我们不指定bundle,则会默认从.app路径下去寻找资源。
不过很显然,我们的动态库是放到“主程序”的document文件下的,所以资源文件是不可能在[NSbundle mainBundle]中获取到的,所以这里我们需要指定bundle参数,这也是传递framework的路径的意义所在
*/
TheFirstViewController *firstCon = [[TheFirstViewController alloc]initWithNibName:@"TheFirstViewController" bundle:bundle];
//保存NSBundle
firstCon.root_bundle = bundle;
//加上导航栏,并隐藏。
UINavigationController *navCon = [[UINavigationController alloc]initWithRootViewController:firstCon];
[navCon setNavigationBarHidden:YES];
//转换传递过来的mainCon参数,实现界面跳转
UIViewController *viewCon = (UIViewController *)mainCon;
[viewCon presentViewController:navCon animated:YES completion:^{
NSLog(@"跳转到动态更新模块成功!");
}];
}
上面描述了xib文件的加载,下面是使用图片的注意事项:(使用RootViewController基类的代码做说明)
[objc] view plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/*
*注意获取图片的方式,通过路径+图片名称去获取
*如果直接使用[UIImage imageNamed:@"root_top_bg.png"]方式加载是会出现问题,
因为在当前程序的路径下是找不到此图片的,图片也会被封装到framwork中
*如果在xib文件中直接为某个控件添加图片的话,和平常使用一样直接添加图片名称,不会出现路径的问题
*/
[navImageView setImage:[UIImage imageWithContentsOfFile:[self.root_bundle pathForResource:@"root_top_bg" ofType:@"png"]]];
以上为一些frameweok工程中的注意事项,现在我们运行得到动态库文件
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/61dd2ad69ee84e4d4f06f4817dde814f.png)
选择Show in Finder,取出framwork文件
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/a2534d176db70e17329871f9e54b76fe.png)
第三步:创建“主程序”的项目工程
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/883e3c7b42f29db83cb22578dba8ee92.jpeg)
第四步:设置此工程可以通过iTunes来实现文件共享
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/aea094439e569e68d767ec8a69d4e721.png)
然后通过itunes把framework放到document路径中
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/b14483521bb574b974dafcfbbbcc4ef5.png)
第五步:获取framework,并调用上面提到的动态库入口方法和传递参数
(此项目在界面上添加了一个简单的按钮,点击按钮来进入动态库)
[objc] view plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
-(void)testFramework
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentDirectory = nil;
if ([paths count] != 0)
documentDirectory = [paths objectAtIndex:0];
//拼接我们放到document中的framework路径
NSString *libName = @"PacteraFramework.framework";
NSString *destLibPath = [documentDirectory stringByAppendingPathComponent:libName];
//判断一下有没有这个文件的存在 如果没有直接跳出
NSFileManager *manager = [NSFileManager defaultManager];
if (![manager fileExistsAtPath:destLibPath]) {
NSLog(@"There isn't have the file");
return;
}
//复制到程序中
NSError *error = nil;
//加载方式一:使用dlopen加载动态库的形式 使用此种方法的时候注意头文件的引入
// void* lib_handle = dlopen([destLibPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LOCAL);
// if (!lib_handle) {
// NSLog(@"Unable to open library: %s\n", dlerror());
// return;
// }
//加载方式一 关闭的方法
// Close the library.
// if (dlclose(lib_handle) != 0) {
// NSLog(@"Unable to close library: %s\n",dlerror());
// }
//加载方式二:使用NSBundle加载动态库
NSBundle *frameworkBundle = [NSBundle bundleWithPath:destLibPath];
if (frameworkBundle && [frameworkBundle load]) {
NSLog(@"bundle load framework success.");
}else {
NSLog(@"bundle load framework err:%@",error);
return;
}
/*
*通过NSClassFromString方式读取类
*PacteraFramework 为动态库中入口类
*/
Class pacteraClass = NSClassFromString(@"PacteraFramework");
if (!pacteraClass) {
NSLog(@"Unable to get TestDylib class");
return;
}
/*
*初始化方式采用下面的形式
alloc init的形式是行不通的
同样,直接使用PacteraFramework类初始化也是不正确的
*通过- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
方法调用入口方法(showView:withBundle:),并传递参数(withObject:self withObject:frameworkBundle)
*/
NSObject *pacteraObject = [pacteraClass new];
[pacteraObject performSelector:@selector(showView:withBundle:) withObject:self withObject:frameworkBundle];
}
第六步:运行“主程序”项目到设备上,然后点击按钮进入动态库模块吧。
注意:有时候我们运行framework工程获取framework文件,内部并没有我们想要的xib文件(这个时候内部展示的为nib格式的),所以在我们每次运行此工程的时候,都需要clean
demo下载地址:点击跳转到下载页面
感谢:http://blog.csdn.net/like7xiaoben/article/details/44081257
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/653667602dae6b5f916e4a26ef555ad3.png)
大小: 114.5 KB
动态模块更新__1_.zip (358.8 KB)
下载次数: 2
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/e6992bd7bb9e30b26a26e0551e98a370.jpeg)
大小: 61.3 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/5d3222fed730207ea6b305420916e527.png)
大小: 95 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/b7acff7fc428431124700e822feeeb64.jpeg)
大小: 35.2 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/9cb28cd1ddb6e6121522343fcc060b5a.png)
大小: 120.7 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/c47a7b8c2b54e1788a48eb15e700990b.png)
大小: 96.5 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/83a02e9e0420ae3174f4365dbb43aeba.png)
大小: 159.2 KB
查看图片附件
实现过程简述:把想要的作为动态更新的模块,移动到我们创建的Framework工程中,然后得到我们想要的动态库文件,把此文件再通过iTunes放到“主程序”项目的document文件夹下,从而实现从主程序中去加载此动态库,从而实现功能模块的动态更新效果。理想效果为支付宝APP,而支付宝采用的是HTML5(网页)的形式实现的,这是目前最通用的实现方式,但是不适用于复杂界面效果。
第一步:创建IOS Framework工程
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/e0adb10cf8a88aa6b5413669d25913a8.png)
第二步:生成的工程中原本的类删掉不用
然后添加新的类文件来实现动态加载效果
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/20475ba0543ead608021da81203319d6.jpeg)
图片和测试界面不多说,重点为PacteraFramework这个类文件中的代码部分:
添加入口方法:
[objc] view plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/*
主程序和此动态库的关系枢纽,也就是从“主程序”到“动态库内封装的程序”的入口方法
@param mainCon “主程序”中入口按钮所在的ViewController对象
@param bundle 此动态库在document文件中的路径,用于xib的加载和图片的加载
*/
-(void)showView:(id)mainCon withBundle:(NSBundle *)bundle;
实现此方法:
[objc] view plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
-(void)showView:(id)mainCon withBundle:(NSBundle *)bundle
{
/*
*初始化第一个controller
TheFirstViewController继承于RootViewController
*这里的重点是xib文件的加载
通常我们在初始化xib的时候并不是很在意bundle:这个参数,一般情况下都会赋予nil值
其实我们所用到的图片、xib等资源文件都是在程序内部中获取的,也就是我们常用的[NSBundle mainBundle]中获取,所谓的NSBundle本质上就是一个路径,mainBundle指向的是.app下。
而如果我们不指定bundle,则会默认从.app路径下去寻找资源。
不过很显然,我们的动态库是放到“主程序”的document文件下的,所以资源文件是不可能在[NSbundle mainBundle]中获取到的,所以这里我们需要指定bundle参数,这也是传递framework的路径的意义所在
*/
TheFirstViewController *firstCon = [[TheFirstViewController alloc]initWithNibName:@"TheFirstViewController" bundle:bundle];
//保存NSBundle
firstCon.root_bundle = bundle;
//加上导航栏,并隐藏。
UINavigationController *navCon = [[UINavigationController alloc]initWithRootViewController:firstCon];
[navCon setNavigationBarHidden:YES];
//转换传递过来的mainCon参数,实现界面跳转
UIViewController *viewCon = (UIViewController *)mainCon;
[viewCon presentViewController:navCon animated:YES completion:^{
NSLog(@"跳转到动态更新模块成功!");
}];
}
上面描述了xib文件的加载,下面是使用图片的注意事项:(使用RootViewController基类的代码做说明)
[objc] view plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/*
*注意获取图片的方式,通过路径+图片名称去获取
*如果直接使用[UIImage imageNamed:@"root_top_bg.png"]方式加载是会出现问题,
因为在当前程序的路径下是找不到此图片的,图片也会被封装到framwork中
*如果在xib文件中直接为某个控件添加图片的话,和平常使用一样直接添加图片名称,不会出现路径的问题
*/
[navImageView setImage:[UIImage imageWithContentsOfFile:[self.root_bundle pathForResource:@"root_top_bg" ofType:@"png"]]];
以上为一些frameweok工程中的注意事项,现在我们运行得到动态库文件
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/61dd2ad69ee84e4d4f06f4817dde814f.png)
选择Show in Finder,取出framwork文件
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/a2534d176db70e17329871f9e54b76fe.png)
第三步:创建“主程序”的项目工程
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/883e3c7b42f29db83cb22578dba8ee92.jpeg)
第四步:设置此工程可以通过iTunes来实现文件共享
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/aea094439e569e68d767ec8a69d4e721.png)
然后通过itunes把framework放到document路径中
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/b14483521bb574b974dafcfbbbcc4ef5.png)
第五步:获取framework,并调用上面提到的动态库入口方法和传递参数
(此项目在界面上添加了一个简单的按钮,点击按钮来进入动态库)
[objc] view plaincopy
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
-(void)testFramework
{
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentDirectory = nil;
if ([paths count] != 0)
documentDirectory = [paths objectAtIndex:0];
//拼接我们放到document中的framework路径
NSString *libName = @"PacteraFramework.framework";
NSString *destLibPath = [documentDirectory stringByAppendingPathComponent:libName];
//判断一下有没有这个文件的存在 如果没有直接跳出
NSFileManager *manager = [NSFileManager defaultManager];
if (![manager fileExistsAtPath:destLibPath]) {
NSLog(@"There isn't have the file");
return;
}
//复制到程序中
NSError *error = nil;
//加载方式一:使用dlopen加载动态库的形式 使用此种方法的时候注意头文件的引入
// void* lib_handle = dlopen([destLibPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LOCAL);
// if (!lib_handle) {
// NSLog(@"Unable to open library: %s\n", dlerror());
// return;
// }
//加载方式一 关闭的方法
// Close the library.
// if (dlclose(lib_handle) != 0) {
// NSLog(@"Unable to close library: %s\n",dlerror());
// }
//加载方式二:使用NSBundle加载动态库
NSBundle *frameworkBundle = [NSBundle bundleWithPath:destLibPath];
if (frameworkBundle && [frameworkBundle load]) {
NSLog(@"bundle load framework success.");
}else {
NSLog(@"bundle load framework err:%@",error);
return;
}
/*
*通过NSClassFromString方式读取类
*PacteraFramework 为动态库中入口类
*/
Class pacteraClass = NSClassFromString(@"PacteraFramework");
if (!pacteraClass) {
NSLog(@"Unable to get TestDylib class");
return;
}
/*
*初始化方式采用下面的形式
alloc init的形式是行不通的
同样,直接使用PacteraFramework类初始化也是不正确的
*通过- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
方法调用入口方法(showView:withBundle:),并传递参数(withObject:self withObject:frameworkBundle)
*/
NSObject *pacteraObject = [pacteraClass new];
[pacteraObject performSelector:@selector(showView:withBundle:) withObject:self withObject:frameworkBundle];
}
第六步:运行“主程序”项目到设备上,然后点击按钮进入动态库模块吧。
注意:有时候我们运行framework工程获取framework文件,内部并没有我们想要的xib文件(这个时候内部展示的为nib格式的),所以在我们每次运行此工程的时候,都需要clean
demo下载地址:点击跳转到下载页面
感谢:http://blog.csdn.net/like7xiaoben/article/details/44081257
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/653667602dae6b5f916e4a26ef555ad3.png)
大小: 114.5 KB
动态模块更新__1_.zip (358.8 KB)
下载次数: 2
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/e6992bd7bb9e30b26a26e0551e98a370.jpeg)
大小: 61.3 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/5d3222fed730207ea6b305420916e527.png)
大小: 95 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/b7acff7fc428431124700e822feeeb64.jpeg)
大小: 35.2 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/9cb28cd1ddb6e6121522343fcc060b5a.png)
大小: 120.7 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/c47a7b8c2b54e1788a48eb15e700990b.png)
大小: 96.5 KB
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/27/83a02e9e0420ae3174f4365dbb43aeba.png)
大小: 159.2 KB
查看图片附件
相关文章推荐
- IOS-使用framework实现功能模块动态更新
- IOS-使用framework实现功能模块动态更新
- iOS使用lua语言的使用步骤与实现插件的动态更新
- 使用Nginx反向代理和内容替换模块实现网页内容动态替换功能
- Android中使用AsyncTask实现下载文件动态更新进度条功能
- 使用Nginx反向代理和内容替换模块实现网页内容动态替换功能
- 使用JSPatch实现iOS APP动态更新
- 使用webpack的动态模块功能实现类似包扫描来简化配置
- ios中录音功能的实现AudioSession的使用
- ios开发之应用程序检查更新功能的实现
- iOS 中使用tableView实现右滑显示选择功能
- IOS开发之使用Speex格式实现简单的语音聊天功能(二)
- 使用Bootstrap + Vue.js实现表格的动态展示、新增和删除功能
- 安卓更新软件功能的实现 (不使用webview)
- 模块管理常规功能自己定义系统的设计与实现(52--功能更新[2] 对百分比字段的操作)
- 使用javascript操作多选列表框,实现动态增加删除,左右移动,上下排序移动等功能。
- jeecg 3.7.1 新版功能,集群定时任务动态发布模块 使用规则
- iOS使用CoreMotion实现摇一摇功能
- iOS Webview使用js获取图url,实现图片浏览的功能
- ios 使用自带的UIViewController实现qq加号下拉菜单的功能