IOS-使用framework實現功能模組動態更新
阿新 • • 發佈:2019-01-23
測試Xcode版本為6.1.1
實現過程簡述:把想要的作為動態更新的模組,移動到我們建立的Framework工程中,然後得到我們想要的動態庫檔案,把此檔案再通過iTunes放到“主程式”專案的document資料夾下,從而實現從主程式中去載入此動態庫,從而實現功能模組的動態更新效果。理想效果為支付寶APP,而支付寶採用的是HTML5(網頁)的形式實現的,這是目前最通用的實現方式,但是不適用於複雜介面效果。
第一步:建立IOS Framework工程
第二步:生成的工程中原本的類刪掉不用
然後新增新的類檔案來實現動態載入效果
圖片和測試介面不多說,重點為PacteraFramework這個類檔案中的程式碼部分:
新增入口方法:
/*
主程式和此動態庫的關係樞紐,也就是從“主程式”到“動態庫內封裝的程式”的入口方法
@param mainCon “主程式”中入口按鈕所在的ViewController物件
@param bundle 此動態庫在document檔案中的路徑,用於xib的載入和圖片的載入
*/
-(void)showView:(id)mainCon withBundle:(NSBundle *)bundle;
實現此方法:
-(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基類的程式碼做說明)
/* *注意獲取圖片的方式,通過路徑+圖片名稱去獲取 *如果直接使用[UIImage imageNamed:@"root_top_bg.png"]方式載入是會出現問題, 因為在當前程式的路徑下是找不到此圖片的,圖片也會被封裝到framwork中 *如果在xib檔案中直接為某個控制元件新增圖片的話,和平常使用一樣直接新增圖片名稱,不會出現路徑的問題 */ [navImageView setImage:[UIImage imageWithContentsOfFile:[self.root_bundle pathForResource:@"root_top_bg" ofType:@"png"]]];
以上為一些frameweok工程中的注意事項,現在我們執行得到動態庫檔案
選擇Show in Finder,取出framwork檔案
第四步:設定此工程可以通過iTunes來實現檔案共享
然後通過itunes把framework放到document路徑中
第五步:獲取framework,並呼叫上面提到的動態庫入口方法和傳遞引數
(此專案在介面上添加了一個簡單的按鈕,點選按鈕來進入動態庫)
-(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