一:MobileProject簡介
MobileProject項目是一個以MVC模式搭建的開源功能集合,基於Objective-C上面進行編寫,意在解決新項目對於常見功能模塊的重復開發,MobileProject對於項目的搭建也進行很明確的劃分,各個模塊職責也比較明確,MobileProject也引入的一些常用第三方插件、宏定義、工具幫助類等;整個項目也是在不斷更新跟維護中,功能點也會不斷更新;代碼支持iOS7以後版本;
二:項目框架內容
三:功能點介紹
1:JSPatch熱更新功能
相信關於JSPatch插件用於項目的熱更新應該是比較常見的功能,在MobileProject裡面就實現一個關於熱更新的效果,並且有封裝一個幫助類,對於熱更新的JS文件下載及運用進行說明;包含一些下載的次數控制等;
主要源代碼如下:
+(void)HSDevaluateScript { //從本地獲取下載的JS文件 NSURL *p = FilePath; //判斷文件是否存在 NSString *curFilePath=[p.path stringByAppendingString:[NSString stringWithFormat:@"/%@",jsPatchJsFileName]]; if (![[NSFileManager defaultManager] fileExistsAtPath:curFilePath]) { return; } //獲取內容 NSString *js = [NSString stringWithContentsOfFile:curFilePath encoding:NSUTF8StringEncoding error:nil]; //如果有內容 if (js.length > 0) { //------- //服務端要對JS內容進行加密,在此處解密js內容;增加安全性 //---- //運行 [JPEngine startEngine]; [JPEngine evaluateScript:js]; } } +(void)loadJSPatch { //優化間隔一段時間 再去請求一次 否則太頻繁(這邊定義為一個小時才去請求一次) NSDate *myNowDate=[NSDate date]; if (!BBUserDefault.MBJsPatchTime) { BBUserDefault.MBJsPatchTime=myNowDate; } if ([myNowDate timeIntervalSinceDate:BBUserDefault.MBJsPatchTime]<3600) { return; } //重新賦值 BBUserDefault.MBJsPatchTime=myNowDate; //使用AFNetWork下載在服務器的js文件 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; NSURL *URL = [NSURL URLWithString:kJSPatchServerPath]; NSURLRequest *request = [NSURLRequest requestWithURL:URL]; NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; if (httpResponse.statusCode==200) { NSURL *documentsDirectoryURL = FilePath; //保存到本地 Library/Caches目錄下 return [documentsDirectoryURL URLByAppendingPathComponent:jsPatchJsFileName]; } else { return nil; } } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { NSLog(@"下載失敗 to: %@", filePath); }]; [downloadTask resume]; }
關於詳細的運用可以下載源代碼進行查看;
2:LKDB實體映射數據庫的運用
在平時開發過程中經常會碰到跟數據庫打交道,而LKDB是一個不錯的實體映射成數據庫插件,可以很輕松就能完成實體針數據庫列的映射,並能進行一些在實體層面上的增刪改查的操作,當然也可以進行SQL語句的運用;能夠滿足我們平時項目的運用;
主要源代碼如下:
+(LKDBHelper *)getUsingLKDBHelper { static LKDBHelper* db; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSString *sqlitePath = [MPLKDBHelper downloadPath]; NSString* dbpath = [sqlitePath stringByAppendingPathComponent:[NSString stringWithFormat:@"MPData.db"]]; NSLog(@"當前創建數據庫地址路徑:%@",dbpath); db = [[LKDBHelper alloc]initWithDBPath:dbpath]; }); return db; } /** * @author wujunyang, 15-05-21 16:05:44 * * @brief 路徑 * @return */ + (NSString *)downloadPath{ NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSString *downloadPath = [documentPath stringByAppendingPathComponent:@"DataBase"]; NSLog(@"%@",downloadPath); return downloadPath; }
上面只是簡單列出關於數據庫SQList的創建,關於運用可以查看源代碼;
3:百度地圖的運用
在平常項目中對於地圖的運用可能包含顯示跟定位等相關的內容,MobileProject項目裡有一個關於百度地圖的車行路線生成實例,並且修改大頭針跟彈出窗的效果,代碼中還運用百度地圖進行定位,並對手機不同的語言進行定位城市的處理功能;使其在定位獲取城市名字時一定是中文,排除由於手機設置語言的原因導致城市名稱不對等;
主要源代碼如下:
//百度地圖定位 [[MPLocationManager shareInstance] startBMKLocationWithReg:^(BMKUserLocation *loction, NSError *error) { if (error) { DDLogError(@"定位失敗,失敗原因:%@",error); } else { DDLogError(@"定位信息:%f,%f",loction.location.coordinate.latitude,loction.location.coordinate.longitude); CLGeocoder *geocoder=[[CLGeocoder alloc]init]; [geocoder reverseGeocodeLocation:loction.location completionHandler:^(NSArray * _Nullable placemarks, NSError * _Nullable error) { //處理手機語言 獲得城市的名稱(中文) NSMutableArray *userDefaultLanguages = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"]; NSString *currentLanguage = [userDefaultLanguages objectAtIndex:0]; //如果不是中文 則強制先轉成中文 獲得後再轉成默認語言 if (![currentLanguage isEqualToString:@"zh-Hans"]&&![currentLanguage isEqualToString:@"zh-Hans-CN"]) { //IOS9前後區分 if (isIOS9) { [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"zh-Hans-CN", nil] forKey:@"AppleLanguages"]; } else { [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"zh-Hans", nil] forKey:@"AppleLanguages"]; } } //轉換地理信息 if (placemarks.count>0) { CLPlacemark *placemark=[placemarks objectAtIndex:0]; //獲取城市 NSString *city = placemark.locality; if (!city) { //四大直轄市的城市信息無法通過locality獲得,只能通過獲取省份的方法來獲得(如果city為空,則可知為直轄市) city = placemark.administrativeArea; } NSLog(@"百度當前城市:[%@]",city); // 城市名傳出去後,立即 Device 語言 還原為默認的語言 [[NSUserDefaults standardUserDefaults] setObject:userDefaultLanguages forKey:@"AppleLanguages"]; } }]; } }];
關於地圖的展現請查看源代碼的內容;上面的代碼是主要運用於定位功能
4:二維碼功能運用
MobileProject中的二維碼主要是在基於插件LBXScan上進行開發,其封裝已經滿足平常我們見到的二維效果,項目實例主要是包含關於掃描跟從相冊選取照片然後讀取上面的二維碼效果,當然LBXScan還可以讀取條形碼的功能,可以去查看其官方實例效果;
主要源代碼如下:
//設置樣式 - (LBXScanViewStyle *)qqLBXScanViewStyle { //設置掃碼區域參數設置 //創建參數對象 LBXScanViewStyle *style = [[LBXScanViewStyle alloc]init]; //矩形區域中心上移,默認中心點為屏幕中心點 style.centerUpOffset = 44; //掃碼框周圍4個角的類型,設置為外掛式 style.photoframeAngleStyle = LBXScanViewPhotoframeAngleStyle_Outer; //掃碼框周圍4個角繪制的線條寬度 style.photoframeLineW = 6; //掃碼框周圍4個角的寬度 style.photoframeAngleW = 24; //掃碼框周圍4個角的高度 style.photoframeAngleH = 24; //掃碼框內 動畫類型 --線條上下移動 style.anmiationStyle = LBXScanViewAnimationStyle_LineMove; //線條上下移動圖片 style.animationImage = [UIImage imageNamed:@"qrcode_scan_light_green"]; return style; } //獲得掃碼的結果 - (void)scanResultWithArray:(NSArray*)array { if (array.count < 1) { [self popAlertMsgWithScanResult:nil]; return; } //經測試,可以同時識別2個二維碼,不能同時識別二維碼和條形碼 for (LBXScanResult *result in array) { NSLog(@"scanResult:%@",result.strScanned); } LBXScanResult *scanResult = array[0]; NSString*strResult = scanResult.strScanned; self.scanImage = scanResult.imgScanned; if (!strResult) { [self popAlertMsgWithScanResult:nil]; return; } //震動提醒 //[LBXScanWrapper systemVibrate]; //聲音提醒 //[LBXScanWrapper systemSound]; [MBProgressHUD showSuccess:[NSString stringWithFormat:@"掃碼的內容為:%@",strResult] ToView:nil]; }
5:照片上傳功能及附帶進度上傳效果
照片上傳應該是每個APP必備的功能模塊,所以MobileProject對它進行的一個簡單整理,主要實現了,包含選擇照片、拍照、浏覽大圖、獲得圖片GPS、圖片名稱、圖片拍照時間、上傳時對圖片進行轉正調整、壓縮圖片、圖片展現效果等,項目中也還有另外一種上傳效果,就是帶進度的上傳,選擇完幾張照片它會每張進間上傳並有相應的扇形進度效果;
主要源代碼如下:
+ (instancetype)imageWithAssetURL:(NSURL *)assetURL isUploadProcess:(BOOL)isUploadProcess{ MPImageItemModel *imageItem = [[MPImageItemModel alloc] init]; imageItem.uploadState = MPImageUploadStateInit; imageItem.assetURL = assetURL; MPWeakSelf(self); void (^selectAsset)(ALAsset *) = ^(ALAsset *asset){ if (asset) { UIImage *highQualityImage = [imageCompressHelper fullScreenImageALAsset:asset]; UIImage *thumbnailImage = [UIImage imageWithCGImage:[asset thumbnail]]; //照片信息 MPStrongSelf(self); [self imageInfoWithALAsset:asset imageItem:imageItem]; dispatch_async(dispatch_get_main_queue(), ^{ imageItem.image = [imageCompressHelper compressedImageToLimitSizeOfKB:100 image:highQualityImage];; imageItem.thumbnailImage = thumbnailImage; if (isUploadProcess) { //上傳到沙盒 成功上傳後記得刪除對應 [MPFileManager writeUploadDataWithName:imageItem.photoName andImage:imageItem.image]; } }); } }; ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init]; MPWeakSelf(assetsLibrary); [assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) { if (asset) { selectAsset(asset); }else{ MPStrongSelf(assetsLibrary); [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupPhotoStream usingBlock:^(ALAssetsGroup *group, BOOL *stop) { [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopG) { if([result.defaultRepresentation.url isEqual:assetURL]) { selectAsset(result); *stop = YES; *stopG = YES; } }]; } failureBlock:^(NSError *error) { NSLog(@"讀取圖片失敗"); }]; } }failureBlock:^(NSError *error) { NSLog(@"讀取圖片失敗"); }]; return imageItem; }
6:字體適配機型
針對目前iPhone機型已經越來越多的狀態下,在設計只出一種效果圖的情況下,要在不同的屏幕大小顯示出不同的字體大小跟布局,在MobileProject定義的幾種宏,其假設效果圖是用iphone5出,通過這幾個宏的運用就可以兼容在iPhone6+等下的布局,解決以前關於大屏字體變小等問題;
主要源代碼如下:
//不同屏幕尺寸字體適配(320,568是因為效果圖為IPHONE5 如果不是則根據實際情況修改) #define kScreenWidthRatio (Main_Screen_Width / 320.0) #define kScreenHeightRatio (Main_Screen_Height / 568.0) #define AdaptedWidth(x) ceilf((x) * kScreenWidthRatio) #define AdaptedHeight(x) ceilf((x) * kScreenHeightRatio) #define AdaptedFontSize(R) CHINESE_SYSTEM(AdaptedWidth(R)) -(void)LayoutLayoutCell { if (!self.myDateLabel) { self.myDateLabel=[[UILabel alloc]init]; self.myDateLabel.font=AdaptedFontSize(13); self.myDateLabel.textColor=[UIColor blackColor]; [self.contentView addSubview:self.myDateLabel]; [self.myDateLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(AdaptedHeight(KTopSpace)); make.left.mas_equalTo(KLeftSpace); make.right.mas_equalTo(-KLeftSpace); make.height.mas_equalTo(AdaptedHeight(15)); }]; } if (!self.myTextLabel) { self.myTextLabel=[[UILabel alloc]init]; self.myTextLabel.font=AdaptedFontSize(KTextLabelFontSize); self.myTextLabel.textColor=[UIColor grayColor]; self.myTextLabel.numberOfLines=0; [self.myTextLabel sizeToFit]; [self.contentView addSubview:self.myTextLabel]; [self.myTextLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(self.myDateLabel.bottom).offset(AdaptedHeight(KTopSpace)); make.left.mas_equalTo(KLeftSpace); make.right.mas_equalTo(-KLeftSpace); }]; } } -(void)configCellWithText:(NSString *)text dateText:(NSString *)dateText { self.myDateLabel.text=dateText; self.myTextLabel.attributedText = [MPAdaptationCell cellTextAttributed:text]; } +(CGFloat)cellHegith:(NSString *)text { CGFloat result=3*AdaptedHeight(10)+AdaptedHeight(15); if (text.length>0) { result=result+[[self cellTextAttributed:text] boundingRectWithSize:CGSizeMake(Main_Screen_Width-2*KLeftSpace, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size.height; } return result; }
如果你們項目的效果圖是以其它機型為准,則要修改宏定義的那個比例值;
7:日志記錄
日志記錄功能應該是每個APP必備,項目中運用了CocoaLumberjack進行日志記錄的展示,並在公共頁面裡已經增加了兩個展現頁,用於展現記錄的內容,在詳細的錯誤記錄裡面還有一個郵件發送的功能,可以把錯誤內容通過郵件發送給開發人員,解決項目上線後關於BUG的收集難題,MobileProject中也根據不同的環境設置記錄等級,也在項目裡面增加在控制台進行有色字體提示;
主要源代碼如下:
- (void)configureLogging { // Enable XcodeColors利用XcodeColors顯示色彩(不寫沒效果) setenv("XcodeColors", "YES", 0); [DDLog addLogger:[DDASLLogger sharedInstance]]; [DDLog addLogger:[DDTTYLogger sharedInstance]]; [DDLog addLogger:self.fileLogger]; //設置顏色值 [[DDTTYLogger sharedInstance] setColorsEnabled:YES]; [[DDTTYLogger sharedInstance] setForegroundColor:[UIColor blueColor] backgroundColor:nil forFlag:DDLogFlagInfo]; [[DDTTYLogger sharedInstance] setForegroundColor:[UIColor purpleColor] backgroundColor:nil forFlag:DDLogFlagDebug]; [[DDTTYLogger sharedInstance] setForegroundColor:[UIColor redColor] backgroundColor:nil forFlag:DDLogFlagError]; [[DDTTYLogger sharedInstance] setForegroundColor:[UIColor greenColor] backgroundColor:nil forFlag:DDLogFlagVerbose]; //設置輸出的LOG樣式 MPLoggerFormatter* formatter = [[MPLoggerFormatter alloc] init]; [[DDTTYLogger sharedInstance] setLogFormatter:formatter]; } #pragma mark - Getters - (DDFileLogger *)fileLogger { if (!_fileLogger) { DDFileLogger *fileLogger = [[DDFileLogger alloc] init]; fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling fileLogger.logFileManager.maximumNumberOfLogFiles = 7; _fileLogger = fileLogger; } return _fileLogger; }
關於其它日志的內容可以查看源代碼;包含關於日志的展現跟郵件發送的源代碼;
8:列表空白頁展現
項目中有時在列表沒有數據或者說是網絡請求出現的情況下是要有相關提示,MobileProject也引入的一個空白提示效果用於其功能,基本上可以滿足平時的開發要求;
主要源代碼如下:
-(void)loadMyTableData { //請求服務端接口並返回數據 __weak typeof(self)weakSelf = self; //成功時 [self.myTableView reloadData]; [self.myTableView.mj_header endRefreshing]; //增加無數據展現 [self.view configBlankPage:EaseBlankPageTypeView hasData:self.dataArray.count hasError:(self.dataArray.count>0) reloadButtonBlock:^(id sender) { [MBProgressHUD showInfo:@"重新加載的數據" ToView:self.view]; [weakSelf.myTableView.mj_header beginRefreshing]; }]; //失敗時 // [self.view configBlankPage:EaseBlankPageTypeView hasData:(self.dataArray.count>0) hasError:YES reloadButtonBlock:^(id sender) { // [MBProgressHUD showInfo:@"重新加載的數據" ToView:self.view]; // [weakSelf.myTableView reloadData]; // }]; }
關於空白頁的編寫可以直接看源代碼了,是一個UIView的分類,也可以根據項目對它進行調整滿要求;
9:自定義彈出窗
自定義的彈出窗UIAlert在IOS7跟IOS8以後是有不一樣的效果,經常會在一些項目中要求模擬系統的UIAlert的樣式進行編寫,針對這種情況加入的一個自定義彈出窗,模擬系統UIAlertView效果,增加一個帶UITextView的彈出效果,其它自定義視圖根據項目再創建;實例中有幾個這方面的實例;
主要源代碼如下:
WJYAlertInputTextView *myInputView=[[WJYAlertInputTextView alloc]initPagesViewWithTitle:@"消息內容" leftButtonTitle:@"取消" rightButtonTitle:@"確定" placeholderText:@"請輸入正確的訂單號"]; __weak typeof(self)weakSelf = self; myInputView.leftBlock=^(NSString *text) { NSLog(@"當前值:%@",text); [weakSelf.alertView dismissWithCompletion:nil]; }; myInputView.rightBlock=^(NSString *text) { if (text.length==0) { //ToView:weakSelf.alertView這樣才會顯示出來 否則會被AlertView蓋住 [MBProgressHUD showError:@"內容沒有輸入" ToView:weakSelf.alertView]; return; } weakSelf.alertView.window.windowLevel = UIWindowLevelStatusBar +1; [MBProgressHUD showAutoMessage:[NSString stringWithFormat:@"當前內容為:%@",text]]; [weakSelf.alertView dismissWithCompletion:nil]; }; _alertView=[[WJYAlertView alloc]initWithCustomView:myInputView dismissWhenTouchedBackground:NO]; [_alertView show];
其它效果可以直接查看源代碼,也可以照了源代碼給出的實例創建出各種種樣的自定義彈出窗效果;
10:其它功能模塊
a:關於引導頁功能的封裝,只要簡單傳入一組圖片就可以實現引導頁的功能模塊
b:關於啟動廣告功能的封裝,同樣也是傳入一組圖片就可以有展現效果,圖片還是加載服務端,下載並保存在本地;
c:友盟管理幫助類的封裝,主要是一些關於友盟統計的代碼跟頁面記錄功能,結合runtime功能進行記錄效果
d:記錄設備唯一標識功能,在IOS中現在是不能再獲取設備的唯一碼,在MobileProject引入的一個插件從而可以獲取設備的FCUUID,同樣可以達到相應的效果;
e:省市區三級聯動的效果功能,從本地讀取省市區數據並加載,可以綁定默認值及選擇後的效果;
f:還有關於友盟第三方登錄的功能及友盟第三方分享的功能
g:封裝MBProgressHUD擴展類,定義一些常見的提示效果,詳見MBProgressHUD+MP類
h:集成CYLTabBarController插件,為項目增加底部4個TabBar菜單,並且有相應的未讀提醒效果,及點擊事件的運用;
i:集成個推消息推送功能(ThirdMacros.h修改相應的key值),證書也要用你們自個的消息證書;
j:增加FLEX,在本地測試版本開啟,FLEX是Flipboard官方發布的一組專門用於iOS開發的應用內調試工具,能在模擬器和物理設備上良好運作,而開發者也無需將其連接到LLDB/Xcode或其他遠程調試服務器,即可直接查看或修改正在運行的App的每一處狀態。
k:UITableViewCell倒計時功能,實例因為沒有服務端接口,所以時間都以本地時間為准,正式項目時間都要從服務端獲取;
l:引入WebViewJavascriptBridge進行H5交互,並對官網實例進行注解
四:總結
上面主要列出一些目前項目中的封裝或者是實例功能模塊,還有一些其它的運用就沒有在這詳細進行講解,比如網絡運用、宏定義、分類擴展類、其它小型幫助類及常用的第三方插件等,可以下載源代碼進行查看,項目也在不斷的完善中,對於項目的構架也在提一步的提升,對於編寫的代碼也不斷的優化;
項目的源代碼地址:https://github.com/wujunyang/MobileProject
如果喜歡或者有幫助可以點星哈,如果您也有空閒時間可以一起完善,保持關注會不斷的更新功能;