1襟沮、動態(tài)庫制作
選擇Framework,創(chuàng)建動態(tài)庫匕垫。
Framework分動態(tài)娇钱、靜態(tài)兩種,可以通過下面路徑查看
TARGETS->Build Settings(搜索mach-o)->Mach-O Type
2并扇、代碼編寫
本例創(chuàng)建動態(tài)庫的名字為GCore去团,項目會自動生成一個名為GCore.h的頭文件
其中可導入你想用的頭文件。
UI文件夾下為demo實現(xiàn)的簡單頁面,大家可自定義自己的UI界面或功能土陪。代碼寫完后昼汗,可在路徑TARGETS->Build Phases->Headers下將你需要暴露給外面調(diào)用的頭文件添加到Public下面即可
3、動態(tài)庫編譯
編譯很簡單鬼雀,正常的Command + B快捷鍵顷窒、Xcode右上角編譯按鈕均可實現(xiàn)編譯,編譯完成后源哩,即可在Products目錄下面看到紅色的GCore.framework變成正常顏色了蹋肮,右擊選擇Show in Finder即可找到你編譯的動態(tài)庫。
注意點
動態(tài)庫編譯的時候注意選擇模擬器還是真機(Any iOS Device)璧疗;
注意release和debug狀態(tài)坯辩;
動態(tài)庫支持的最低版本號;
-
資源文件使用bundle文件包裹(本項目為GCore.bundle)崩侠,并注意資源文件使用路徑漆魔,如本項目圖片調(diào)用
// kBundlePath為GCore.bundle的路徑,可以使沙盒路徑却音,也可以是NSBundle路徑改抡,imageName為圖片名稱, [UIImage imageNamed:[NSString stringWithFormat:@"%@/%@", kBundlePath, imageName]];
系統(tǒng)在加載動態(tài)庫時系瓢,會檢查Framework的簽名阿纤,簽名中必須包含TeamIdentifier,并且Framework和主App的TeamIdentifier必須一致夷陋,模擬器測試可忽略欠拾;
目前而言,Apple并不希望開發(fā)者繞過App Store來更新App骗绕,因此需謹慎對待插件化的使用藐窄,對于不需要上架的企業(yè)級應(yīng)用,是可以使用的酬土。
4荆忍、動態(tài)庫實現(xiàn)插件化
將之前編譯好的動態(tài)庫放入服務(wù)器方便下載,然后在項目中下載并使用
-
使用AFNetworking下載動態(tài)庫到沙盒撤缴,并用SSZipArchive解壓(注意解壓路徑)
/// 下載并解壓 - (IBAction)downloadPlugInAction:(id)sender { NSString *frameworkPath = [NSString stringWithFormat:@"%@/Documents/", NSHomeDirectory()]; if ([[NSFileManager defaultManager] fileExistsAtPath:[frameworkPath stringByAppendingPathComponent:@"GCore.zip"]]){ [[NSFileManager defaultManager] removeItemAtPath:[frameworkPath stringByAppendingPathComponent:@"GCore.zip"] error:nil]; } AFHTTPSessionManager *manager = [self createAFHTTPSessionManager]; NSString *url = @"http://localhost/GCore.zip"; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) { NSLog(@"progress = %@", downloadProgress); } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) { NSString *filePath = [NSString stringWithFormat:@"%@/Documents/GCore.zip", NSHomeDirectory()]; return [NSURL fileURLWithPath:filePath]; } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) { NSLog(@"下載完成"); NSString *errMsg = @""; if (error == nil) { //刪除原有庫 NSString *frameworkPath = [NSString stringWithFormat:@"%@/Documents/", NSHomeDirectory()]; if ([[NSFileManager defaultManager] fileExistsAtPath:[frameworkPath stringByAppendingPathComponent:@"GCore.framework"]]){ [[NSFileManager defaultManager] removeItemAtPath:[frameworkPath stringByAppendingPathComponent:@"GCore.framework"] error:nil]; } if ([[NSFileManager defaultManager] fileExistsAtPath:[frameworkPath stringByAppendingPathComponent:@"GCore.bundle"]]){ [[NSFileManager defaultManager] removeItemAtPath:[frameworkPath stringByAppendingPathComponent:@"GCore.bundle"] error:nil]; } //解壓庫 NSString *zipPath = [NSString stringWithFormat:@"%@/Documents/GCore.zip", NSHomeDirectory()]; BOOL res = [SSZipArchive unzipFileAtPath:zipPath toDestination:frameworkPath]; if (res) { errMsg = @"下載并解壓成功"; } else { errMsg = @"下載但解壓失敗"; } NSLog(@"frameworkPath = %@", frameworkPath); } else { errMsg = @"下載失敗"; } UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:errMsg message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:@"確定", nil]; [alertView show]; }]; [downloadTask resume]; }
-
使用 [NSBundle bundleWithPath:frameworkPath] 將之前下載好的動態(tài)庫加載到內(nèi)存
//使用NSBundle實現(xiàn)加載 - (IBAction)loadPlugInAction:(id)sender { NSString *frameworkPath = [NSString stringWithFormat:@"%@/Documents/GCore.framework", NSHomeDirectory()]; NSError *err = nil; NSBundle *bundle = [NSBundle bundleWithPath:frameworkPath]; NSString *str = @"加載動態(tài)庫失敗!"; if ([bundle loadAndReturnError:&err]) { NSLog(@"bundle load framework success."); str = @"加載動態(tài)庫成功!"; } else { NSLog(@"bundle load framework err:%@",err); } UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:str message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:@"確定", nil]; [alertView show]; } //使用dlopen實現(xiàn)加載 - (IBAction)loadPlugInAction:(id)sender { NSString *documentsPath = [NSString stringWithFormat:@"%@/Documents/GCore.framework/GCore",NSHomeDirectory()]; [self dlopenLoadDylibWithPath:documentsPath]; if (dlopen([path cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW) == NULL) { char *error = dlerror(); NSLog(@"dlopen error: %s", error); } else { NSLog(@"dlopen load framework success."); } }
-
接下來就是動態(tài)庫調(diào)用了
- (IBAction)plugInAction:(id)sender { Class GPluginFunc = NSClassFromString(@"GPluginFunc"); if(GPluginFunc){ UIViewController *ctrl = [GPluginFunc performSelector:@selector(showUI)]; [self presentViewController:ctrl animated:true completion:nil]; } else { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"調(diào)用方法失敗!" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:@"確定", nil]; [alertView show]; } }
如此刹枉,一個簡單的動態(tài)庫實現(xiàn)插件化的工作算完成了。
5屈呕、Mac本地服務(wù)實現(xiàn)下載
如果無條件試下服務(wù)器實現(xiàn)下載功能微宝,可用Mac本實現(xiàn)本地
- 首先mac自帶apache服務(wù),我們只需要在終端輸入下面命令將服務(wù)打開即可
sudo apachectl start
啟動后在瀏覽器訪問 http://localhost 就可以看到效果
apache服務(wù)默認目錄在 /Library/WebServer/Documents 凉袱,只需要將動態(tài)庫放入該目錄并訪問對應(yīng)URL即可實現(xiàn)下載芥吟。比如本demo就是將動態(tài)庫和bundle資源文件壓縮成GCore.zip放入該目錄下面侦铜,只需瀏覽器訪問 http://localhost/GCore.zip 即可下載专甩,如果使用真機測試钟鸵,在同一網(wǎng)絡(luò)下面,可將localhost緩存Mac的網(wǎng)路IP地址即可涤躲。
apache其他命令
//關(guān)閉服務(wù)
sudo apachectl stop
//重啟服務(wù)
sudo apachectl restart