寫在前面
本來是做 Android 開發(fā)土浸、兼職 Unity 開發(fā),公司有業(yè)務(wù)需求要做 iOS汇四,還好需求比較簡單:做一個(gè) WebView + AR 的 App。WebView 感覺比較簡單踏烙,AR 的話就用 EasyAR 吧,免費(fèi)無水印值得推薦历等。
但是讨惩。。寒屯。
做完后要改需求荐捻,原因是有人告知單純的 WebView App 發(fā)布的時(shí)候?qū)徍瞬粫?huì)通過。為了不蹚渾水還是直接重做吧:首頁是一個(gè)全屏 Banner寡夹,內(nèi)容是日歷加下方的圖片处面,點(diǎn)擊到 AR 頁面掃描首頁的圖片可以看到視頻。
作為一只程序猿要有各種東西都能做菩掏,各種代碼都會(huì)碼的覺悟魂角,仗著有點(diǎn)代碼基礎(chǔ)(Java C#)就直接開搞。
一. 準(zhǔn)備工作
- 硬件:一臺(tái) Mac智绸,Mac Mini 也湊合(公司就幾臺(tái)Mini)...測試機(jī)若干野揪,測試 AR 必須用真機(jī)。順手的鼠標(biāo)鍵盤鼠標(biāo)墊...
- 軟件:XCode (我這里的是Version 9.1)瞧栗,CocoaPods(用于引用第三方庫)
- 賬號(hào)和證書:
- 想要發(fā)布一個(gè) iOS App斯稳,首先需要一個(gè)開發(fā)者賬號(hào),個(gè)人級(jí)的價(jià)值 $99迹恐。也就是大家常說的 99美元賬號(hào):
- 有了賬號(hào)就可以申請(qǐng)證書挣惰,有證書才能在真機(jī)上調(diào)試你的 App。順帶提一下殴边,沒有付錢的或者過期的賬號(hào)是沒有證書等選項(xiàng)的...別問我是怎么知道的通熄。證書的申請(qǐng)也是一大串的事情要做,不過仔細(xì)看教程一步一步來很好理解的找都。
二. 基礎(chǔ)知識(shí)
-
基礎(chǔ)語法:
語法還是蠻重要的鳍悠,本人沒有看語法直接上的。開始寫代碼全靠猜和 Copy荷并,走了很多彎路绕娘,現(xiàn)在看來還不如老老實(shí)實(shí)看看語法。不過看歸看晓猛,本著效率優(yōu)先建議看個(gè)大概饿幅,用的時(shí)候再回來仔細(xì)找相關(guān)的研究。
-
視頻教程:
這個(gè)視頻教程比較基礎(chǔ)栗恩,像我這樣的純小白看的很開心。
下面這個(gè)就比較全面了洪燥,但是也有許多我沒用上的知識(shí)磕秤。
所以綜合一下乳乌,建議是不需要全部看完,根據(jù)項(xiàng)目需求來學(xué)習(xí)相關(guān)知識(shí)市咆,畢竟先做出項(xiàng)目才是王道汉操。
三. HelloWorld
因?yàn)?EasyAR 提供 iOS 版本的示例代碼,所以在現(xiàn)有的代碼基礎(chǔ)上進(jìn)行二次開發(fā)蒙兰,接下來根據(jù)項(xiàng)目需求來一步一步進(jìn)行開發(fā)磷瘤。
3.1 建立 WebView
第一版的 App 首頁就是個(gè) WebView,本小白剛開始做的時(shí)候直接在 Main.storyboard 里面拖放 UIWebView搜变,現(xiàn)在看來是 Low 上加 Low...
首先來說采缚,不建議在 storyboard 直接做事情,因?yàn)槭褂?storyboard 編程比較適合一個(gè)人開發(fā)挠他,而且維護(hù)性不高仰担。全部用代碼則會(huì)顯得一目了然,代碼閱讀性比較高绩社。但是 storyboard 也有很多優(yōu)勢摔蓝,同時(shí)有很多團(tuán)隊(duì)支持使用 storyboard 開發(fā)。所以我們要根據(jù)具體情況使用合適的方法來完成一個(gè)優(yōu)雅的項(xiàng)目愉耙。
再者贮尉,UIWebView 是比較老的一個(gè)控件,而比較新的 WebView 控件則是 WKWebView朴沿,無論從內(nèi)存占用和使用體驗(yàn)來說都優(yōu)于 UIWebView猜谚。
下面是我找到使用簡單,代碼清晰赌渣,而且?guī)斑M(jìn)后退和進(jìn)度條的 WKWebView 使用實(shí)例魏铅,還有源碼哦。使用的時(shí)候根據(jù)需求修改各個(gè)控件的位置和大小就可以了坚芜。
3.2 添加標(biāo)題 View
項(xiàng)目需求 WebView 上面需要一個(gè)標(biāo)題欄览芳,一個(gè)光禿禿的 WebView 確實(shí)也不甚好看,標(biāo)題欄是一個(gè)簡單的圖片鸿竖,用 UIImageView 就可以啦沧竟。
// 狀態(tài)欄(statusbar)
CGRect rectStatus = [[UIApplication sharedApplication] statusBarFrame];
// 當(dāng)前view的寬和高
CGFloat w = self.view.bounds.size.width;
CGFloat h = self.view.bounds.size.height;
// 添加title
UIImageView *titleImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, rectStatus.size.height, w, 60)];
[titleImage setImage:[UIImage imageNamed:@"ic_title"]];
[self.view addSubview:titleImage];
代碼很好理解,首先獲取手機(jī)狀態(tài)欄的屬性缚忧,因?yàn)樗母叨刃枰玫轿虮谩H缓螳@取當(dāng)前 App 顯示區(qū)域的 View 的寬和高,最后添加標(biāo)題欄的icon闪水。短短的一段代碼包含了很多信息:
- CGRect:簡單的理解為包含了某 View 的原點(diǎn)和 Size 的屬性糕非,上文代碼中是獲得了狀態(tài)欄的這個(gè)屬性。
- CGFloat:只是對(duì)float或double的typedef定義,看作是數(shù)據(jù)類型就好朽肥,代碼中是儲(chǔ)存了當(dāng)前View的寬和高禁筏。
- UIImageView:基礎(chǔ)控件使用,不再多說鞠呈。
-
CGRectMake:實(shí)例化某控件時(shí)來定義視圖的起點(diǎn)坐標(biāo)以及寬度和高度等屬性的參數(shù)。上面代碼中 titleImage 的 CGRectMake:
CGRectMake(0, rectStatus.size.height, w, 60)
第一個(gè)參數(shù) 0右钾,說明該 View 起點(diǎn) x 軸為 0蚁吝,也就是屏幕最左側(cè)。
第二個(gè)參數(shù) rectStatus.size.height 這個(gè)是狀態(tài)欄的高度舀射,說明 titleImage 的 y 軸起點(diǎn)為狀態(tài)欄高度那一行窘茁,與 x 軸的點(diǎn)結(jié)合起來就確定了 titleImage 的起點(diǎn)。
第三個(gè)參數(shù)是 View 的寬度脆烟,我希望它鋪滿屏幕山林,所以是屏幕寬度 w。
第四個(gè)參數(shù)是 View 的高度邢羔,自己指定驼抹。
- 指定 UIImageView 的圖片資源:
[titleImage setImage:[UIImage imageNamed:@"ic_title"]];
資源存儲(chǔ)在 Assets.xcassets 資源文件夾,圖片名稱為 ic_title拜鹤。
3.3 添加 UIButton 的點(diǎn)擊和返回
上面的 titleBar 有左右兩個(gè)按鈕框冀,左邊的按鈕用于跳轉(zhuǎn)到當(dāng)天時(shí)間的頁面,右邊的跳轉(zhuǎn)到 AR 界面敏簿,沒有美工啊...暫時(shí)先實(shí)現(xiàn)功能吧明也,按鈕的點(diǎn)擊響應(yīng)什么的,以后再說惯裕。
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *todayButton = [[UIButton alloc] initWithFrame:CGRectMake(0, rectStatus.size.height, w*0.18, titleHeight)];
//設(shè)置按鈕點(diǎn)擊觸發(fā)動(dòng)作跳轉(zhuǎn)
[todayButton addTarget:self action:@selector(goToday:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:todayButton];
UIButton *arButton = [[UIButton alloc] initWithFrame:CGRectMake(w-w*0.18, rectStatus.size.height, w*0.18, titleHeight)];
//設(shè)置按鈕點(diǎn)擊觸發(fā)動(dòng)作跳轉(zhuǎn)
[arButton addTarget:self action:@selector(goAR:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:arButton];
}
- (void)goToday:(UIButton*) sender
{
...
}
- (void)goAR:(UIButton*) sender
{
// 實(shí)例化要跳轉(zhuǎn)的 ViewController
ViewController *subView = [[ViewController alloc] init];
// 設(shè)置跳轉(zhuǎn)動(dòng)畫類型
[subView setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
// 執(zhí)行跳轉(zhuǎn)
[self presentModalViewController:subView animated:YES];
}
代碼比較簡單温数,實(shí)例化兩個(gè)按鈕分別綁定不用的方法,goToday() 聊不到所以省略掉蜻势。goAR() 注釋寫的比較明白撑刺,這種跳轉(zhuǎn)比較簡單不需要 Navigationbar,而從 AR 界面跳轉(zhuǎn)回來是這樣的:
- (void)viewDidLoad {
[super viewDidLoad];
UIImage * buttonImage = [UIImage imageNamed:@"ic_back"];
self.backButton = [[UIButton alloc] initWithFrame:CGRectMake(20, 30, 30, 30)];
// 設(shè)置按鈕的標(biāo)題文字以及顏色
//[self.backButton setTitle:@"返回" forState:UIControlStateNormal];
//[self.backButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
// 設(shè)置按鈕背景圖
[self.backButton setImage:buttonImage forState:UIControlStateNormal];
//設(shè)置按鈕點(diǎn)擊觸發(fā)動(dòng)作跳轉(zhuǎn)
[self.backButton addTarget:self action:@selector(backToView:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.backButton];
}
- (void) backToView:(UIButton*) sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
與其說是跳轉(zhuǎn)回來握玛,不如說是把當(dāng)前的 View 隱藏更為貼切猜煮,更多關(guān)于界面跳轉(zhuǎn)可以參考下文或自行度娘:
3.4 iOS 消息傳遞與小菊花
需求:掃描識(shí)別到圖片之后要播放視頻,但是視頻文件比較大败许,所以在識(shí)別到圖片的時(shí)候開始旋轉(zhuǎn)小菊花并在線緩存視頻王带,開始播放視頻或者離開識(shí)別圖隱藏小菊花。
找到的資料是這樣的:
-
Notification 傳遞消息
這么多方法對(duì)于我這樣的小白來說是一臉懵逼的市殷,最后用了比較簡單的 Notification (盲通信) 來做愕撰。Notification 的思路很簡單:A 要接收 B 的消息,那么讓 A 來設(shè)置監(jiān)聽,A 銷毀時(shí)移除監(jiān)聽搞挣。等有消息需要傳遞的時(shí)候 B 直接發(fā)送带迟,A 就能收到并調(diào)用具體方法。
Class B 發(fā)現(xiàn)識(shí)別圖開始發(fā)送消息
- (void)onFound
{
// 發(fā)現(xiàn)識(shí)別圖發(fā)送消息顯示并播放小菊花動(dòng)畫
[[NSNotificationCenter defaultCenter] postNotificationName:@"showIndicator" object:nil];
if (prepared) {
// 視頻馬上就要播放囱桨,隱藏小菊花動(dòng)畫
[[NSNotificationCenter defaultCenter] postNotificationName:@"closeIndicator" object:nil];
}
}
Class A 設(shè)置監(jiān)聽并根據(jù)發(fā)來的消息展示和隱藏小菊花
- (void)viewDidLoad {
// 注冊(cè)觀察者顯示
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showIndicator) name:@"showIndicator" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(closeIndicator) name:@"closeIndicator" object:nil];
}
//接受消息顯示小菊花
- (void)showIndicator
{
dispatch_async(dispatch_get_main_queue(), ^{
//do your UI
[self.activityIndicator startAnimating];
self.textView.text = @"Loading...";
});
}
//接受消息關(guān)閉小菊花
- (void)closeIndicator
{
dispatch_async(dispatch_get_main_queue(), ^{
//do your UI
[self.activityIndicator stopAnimating];
self.textView.text = @"";
});
}
為求方便直接注冊(cè)監(jiān)聽兩個(gè)方法仓犬,其實(shí)更好的寫法是只監(jiān)聽一個(gè)方法,Class B 發(fā)送 Notification 時(shí)帶參數(shù)舍肠,Class A 根據(jù)不同參數(shù)作不同的處理搀继。
-
小菊花(UIActivityIndicatorView)的使用
小菊花的用法比較簡單,先創(chuàng)建需要顯示的時(shí)候直接調(diào)用就好翠语。
// 創(chuàng)建全局變量
@property (strong, nonatomic) UIActivityIndicatorView *activityIndicator;
- (void)viewDidLoad {
// 小菊花設(shè)置
self.activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleWhiteLarge)];
// 這個(gè)是用來設(shè)置小菊花的中心點(diǎn)叽躯,很多 View 也可以設(shè)置
self.activityIndicator.center = CGPointMake(width/2,height/2-40);
}
// 顯示小菊花
[self.activityIndicator startAnimating];
// 隱藏小菊花
[self.activityIndicator stopAnimating];
自定義外觀和更多使用方式可以參考文章:
3.5 CocoaPods 以及第三方庫的使用
主要功能和 WebView 做好之后要改需求,原因上文已經(jīng)提到過肌括,接下來要做一個(gè)全屏滑動(dòng)点骑、內(nèi)容為 2018 年日歷的 Banner,以及根據(jù)當(dāng)前的日期跳轉(zhuǎn)到指定的日歷頁面谍夭,用下面的代碼獲取日期后跳轉(zhuǎn)到 Banner 的某一頁就可以了黑滴。
- 獲取系統(tǒng)日期并轉(zhuǎn)換格式
//獲取當(dāng)前時(shí)間日期并返回 int
- (int)getDate:(NSString *)dateType{
NSDate *date=[NSDate date];
NSDateFormatter *format1=[[NSDateFormatter alloc] init];
if([dateType isEqualToString:@"mouth"]){
[format1 setDateFormat:@"MM"];
}else if([dateType isEqualToString:@"day"]){
[format1 setDateFormat:@"dd"];
}else{
[format1 setDateFormat:@"MMdd"];
}
// @"yyyy-MM-dd hh:mm:ss"
NSString *dateStr = [format1 stringFromDate:date];
return [dateStr intValue];
}
// 獲取日期并返回 NSString〗羲鳎可以返回具體周幾
- (NSString*) getAllDate{
NSDate*date = [NSDate date];
NSCalendar*calendar = [NSCalendar currentCalendar];
NSDateComponents*comps;
comps =[calendar components:(NSCalendarUnitWeekOfYear | NSCalendarUnitWeekday |NSCalendarUnitWeekdayOrdinal)
fromDate:date];
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init] ;
// [dateFormatter setDateFormat:@"YYYY-MM-dd EEEE"];
[dateFormatter setDateFormat:@"MMM dd YYYY"];
NSString *currentTimeString = [dateFormatter stringFromDate:date];
return currentTimeString;
}
然后就是 Banner 了跷跪,讓我自己去寫這樣一個(gè) Banner 是不太可能的,首先技術(shù)不到家而且也沒啥時(shí)間去慢慢研究著寫齐板,所以使用第三方庫是最合適的吵瞻。于是在 GayHub 找各種 Banner 庫,發(fā)現(xiàn)大家都在用 Pod 導(dǎo)入甘磨。
- CocoaPods 安裝
查了下發(fā)現(xiàn) Pod 是用來導(dǎo)入第三方庫的工具橡羞,全稱 CocoaPods。雖然直接下載Library 放到項(xiàng)目里可以用但是保不齊第三方庫又引用了其它庫济舆,難道都要一個(gè)一個(gè) Copy 進(jìn)項(xiàng)目卿泽?況且這種東西向來是學(xué)了不虧而且以后做 iOS 開發(fā)總要用到的,所以還是老老實(shí)實(shí)學(xué)著怎么安裝和使用吧滋觉。
安裝 CocoaPods 之前需要先安裝 Ruby 運(yùn)行環(huán)境签夭,然后才能命令行安裝 CocoaPods:
Ruby運(yùn)行環(huán)境:如何在Mac OS X上安裝 Ruby運(yùn)行環(huán)境
接下來參考下文來安裝 CocoaPods
CocoaPods:看一遍就會(huì)的CocoaPods的安裝和使用教程
安裝過程中可能會(huì)報(bào)各種各樣的錯(cuò)誤,不要著急椎侠,參考下方資料第租。如果資料不能解決你的問題,Google 或 度娘 你的報(bào)錯(cuò)Log我纪。
安裝完畢就可以使用 CocoaPods 了慎宾,多去 GayHub 轉(zhuǎn)轉(zhuǎn)丐吓,總有各種各樣的驚喜等著你。
3.6 其它問題
- App 啟動(dòng)圖
記錄一個(gè)問題趟据,本來好好的啟動(dòng)圖券犁,到了大屏手機(jī)忽然就不顯示了。后來把 2X 3X 的都放進(jìn)去就正常顯示了...常識(shí)哇汹碱。 - 狀態(tài)欄文字主題
某些設(shè)備默認(rèn)狀態(tài)欄文字是黑色的粘衬,加上下面的代碼就可以改成白色字體。但是狀態(tài)欄背景色修改起來問題頗多咳促,這里提供一個(gè)小辦法稚新,在 storyboard 當(dāng)前 ViewControler 界面頂添加一個(gè)的純色背景,圖片亦可等缀,橫鋪滿屏幕即可:
//設(shè)置狀態(tài)欄字體樣式
- (UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;//白色
}
- App Icon
有很多網(wǎng)站提供自動(dòng)生成 App Icon 的功能枷莉,扔進(jìn)去 1024X1024 的圖標(biāo)就可以生成一套圖標(biāo)娇昙,很方便尺迂。類似的網(wǎng)站還有很多就不一一列舉了。
移動(dòng)應(yīng)用圖標(biāo)生成工具冒掌,一鍵生成所有尺寸的應(yīng)用圖標(biāo)
四. App 發(fā)布
這里有一個(gè)很詳細(xì)的教程:
跟著教程一步一步做終于是把 App 扔上去審核了噪裕,感覺比較難找的就是 iTunesConnect 放個(gè)鏈接標(biāo)記一下。
到這里就完成了項(xiàng)目需求股毫。文中引用了各種連接膳音,就不一一提示引用了,感謝那么多前輩的無私分享铃诬,也祝大家都能完成一個(gè)完美的 App祭陷。
補(bǔ)充:
上架過程中遇到的各種問題:
- 使用權(quán)限需要告訴用戶具體用來干什么,比如 "相機(jī)用于識(shí)別圖片"趣席。