写在前面
本来是做 Android 开发、兼职 Unity 开发,公司有业务需求要做 iOS,还好需求比较简单:做一个 WebView + AR 的 App。WebView 感觉比较简单,AR 的话就用 EasyAR 吧,免费无水印值得推荐。
但是。。。
做完后要改需求,原因是有人告知单纯的 WebView App 发布的时候审核不会通过。为了不蹚浑水还是直接重做吧:首页是一个全屏 Banner,内容是日历加下方的图片,点击到 AR 页面扫描首页的图片可以看到视频。
作为一只程序猿要有各种东西都能做,各种代码都会码的觉悟,仗着有点代码基础(Java C#)就直接开搞。
一. 准备工作
- 硬件:一台 Mac,Mac Mini 也凑合(公司就几台Mini)...测试机若干,测试 AR 必须用真机。顺手的鼠标键盘鼠标垫...
- 软件:XCode (我这里的是Version 9.1),CocoaPods(用于引用第三方库)
- 账号和证书:
- 想要发布一个 iOS App,首先需要一个开发者账号,个人级的价值 $99。也就是大家常说的 99美元账号:
ios苹果开发者账号申请流程(2017)
- 有了账号就可以申请证书,有证书才能在真机上调试你的 App。顺带提一下,没有付钱的或者过期的账号是没有证书等选项的...别问我是怎么知道的。证书的申请也是一大串的事情要做,不过仔细看教程一步一步来很好理解的。
最新的 iOS 申请证书与发布流程(2016.12)
二. 基础知识
- 基础语法:
语法还是蛮重要的,本人没有看语法直接上的。开始写代码全靠猜和 Copy,走了很多弯路,现在看来还不如老老实实看看语法。不过看归看,本着效率优先建议看个大概,用的时候再回来仔细找相关的研究。
Objective C 基础知识 | 菜鸟教程
十分钟让你明白Objective-C的语法(和Java、C++的对比)
- 视频教程:
这个视频教程比较基础,像我这样的纯小白看的很开心。
iOS8 App开发快速入门
下面这个就比较全面了,但是也有许多我没用上的知识。
iOS开发全套教程(享精品公开课)
所以综合一下,建议是不需要全部看完,根据项目需求来学习相关知识,毕竟先做出项目才是王道。
三. HelloWorld
因为 EasyAR 提供 iOS 版本的示例代码,所以在现有的代码基础上进行二次开发,接下来根据项目需求来一步一步进行开发。
3.1 建立 WebView
第一版的 App 首页就是个 WebView,本小白刚开始做的时候直接在 Main.storyboard 里面拖放 UIWebView,现在看来是 Low 上加 Low...
首先来说,不建议在 storyboard 直接做事情,因为使用 storyboard 编程比较适合一个人开发,而且维护性不高。全部用代码则会显得一目了然,代码阅读性比较高。但是 storyboard 也有很多优势,同时有很多团队支持使用 storyboard 开发。所以我们要根据具体情况使用合适的方法来完成一个优雅的项目。
再者,UIWebView 是比较老的一个控件,而比较新的 WebView 控件则是 WKWebView,无论从内存占用和使用体验来说都优于 UIWebView。
下面是我找到使用简单,代码清晰,而且带前进后退和进度条的 WKWebView 使用实例,还有源码哦。使用的时候根据需求修改各个控件的位置和大小就可以了。
iOS WKWebView添加网页加载进度条
3.2 添加标题 View
项目需求 WebView 上面需要一个标题栏,一个光秃秃的 WebView 确实也不甚好看,标题栏是一个简单的图片,用 UIImageView 就可以啦。
// 状态栏(statusbar)
CGRect rectStatus = [[UIApplication sharedApplication] statusBarFrame];
// 当前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];
代码很好理解,首先获取手机状态栏的属性,因为它的高度需要用到。然后获取当前 App 显示区域的 View 的宽和高,最后添加标题栏的icon。短短的一段代码包含了很多信息:
- CGRect:简单的理解为包含了某 View 的原点和 Size 的属性,上文代码中是获得了状态栏的这个属性。
- CGFloat:只是对float或double的typedef定义,看作是数据类型就好,代码中是储存了当前View的宽和高。
OC 获取iOS屏幕尺寸大小
- UIImageView:基础控件使用,不再多说。
- CGRectMake:实例化某控件时来定义视图的起点坐标以及宽度和高度等属性的参数。上面代码中 titleImage 的 CGRectMake:
CGRectMake(0, rectStatus.size.height, w, 60)
第一个参数 0,说明该 View 起点 x 轴为 0,也就是屏幕最左侧。
第二个参数 rectStatus.size.height 这个是状态栏的高度,说明 titleImage 的 y 轴起点为状态栏高度那一行,与 x 轴的点结合起来就确定了 titleImage 的起点。
第三个参数是 View 的宽度,我希望它铺满屏幕,所以是屏幕宽度 w。
第四个参数是 View 的高度,自己指定。
iPhone开发中Cocoa中的CGRectMake具体用法
- 指定 UIImageView 的图片资源:
[titleImage setImage:[UIImage imageNamed:@"ic_title"]];
资源存储在 Assets.xcassets 资源文件夹,图片名称为 ic_title。
3.3 添加 UIButton 的点击和返回
上面的 titleBar 有左右两个按钮,左边的按钮用于跳转到当天时间的页面,右边的跳转到 AR 界面,没有美工啊...暂时先实现功能吧,按钮的点击响应什么的,以后再说。
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *todayButton = [[UIButton alloc] initWithFrame:CGRectMake(0, rectStatus.size.height, w*0.18, titleHeight)];
//设置按钮点击触发动作跳转
[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)];
//设置按钮点击触发动作跳转
[arButton addTarget:self action:@selector(goAR:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:arButton];
}
- (void)goToday:(UIButton*) sender
{
...
}
- (void)goAR:(UIButton*) sender
{
// 实例化要跳转的 ViewController
ViewController *subView = [[ViewController alloc] init];
// 设置跳转动画类型
[subView setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
// 执行跳转
[self presentModalViewController:subView animated:YES];
}
代码比较简单,实例化两个按钮分别绑定不用的方法,goToday() 聊不到所以省略掉。goAR() 注释写的比较明白,这种跳转比较简单不需要 Navigationbar,而从 AR 界面跳转回来是这样的:
- (void)viewDidLoad {
[super viewDidLoad];
UIImage * buttonImage = [UIImage imageNamed:@"ic_back"];
self.backButton = [[UIButton alloc] initWithFrame:CGRectMake(20, 30, 30, 30)];
// 设置按钮的标题文字以及颜色
//[self.backButton setTitle:@"返回" forState:UIControlStateNormal];
//[self.backButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
// 设置按钮背景图
[self.backButton setImage:buttonImage forState:UIControlStateNormal];
//设置按钮点击触发动作跳转
[self.backButton addTarget:self action:@selector(backToView:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.backButton];
}
- (void) backToView:(UIButton*) sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
与其说是跳转回来,不如说是把当前的 View 隐藏更为贴切,更多关于界面跳转可以参考下文或自行度娘:
iOS ViewController跳转界面的几种方法简单总结
3.4 iOS 消息传递与小菊花
需求:扫描识别到图片之后要播放视频,但是视频文件比较大,所以在识别到图片的时候开始旋转小菊花并在线缓存视频,开始播放视频或者离开识别图隐藏小菊花。
找到的资料是这样的:
IOS中消息传递的8种方式
- Notification 传递消息
这么多方法对于我这样的小白来说是一脸懵逼的,最后用了比较简单的 Notification (盲通信) 来做。Notification 的思路很简单:A 要接收 B 的消息,那么让 A 来设置监听,A 销毁时移除监听。等有消息需要传递的时候 B 直接发送,A 就能收到并调用具体方法。
Class B 发现识别图开始发送消息
- (void)onFound
{
// 发现识别图发送消息显示并播放小菊花动画
[[NSNotificationCenter defaultCenter] postNotificationName:@"showIndicator" object:nil];
if (prepared) {
// 视频马上就要播放,隐藏小菊花动画
[[NSNotificationCenter defaultCenter] postNotificationName:@"closeIndicator" object:nil];
}
}
Class A 设置监听并根据发来的消息展示和隐藏小菊花
- (void)viewDidLoad {
// 注册观察者显示
[[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...";
});
}
//接受消息关闭小菊花
- (void)closeIndicator
{
dispatch_async(dispatch_get_main_queue(), ^{
//do your UI
[self.activityIndicator stopAnimating];
self.textView.text = @"";
});
}
为求方便直接注册监听两个方法,其实更好的写法是只监听一个方法,Class B 发送 Notification 时带参数,Class A 根据不同参数作不同的处理。
iOS NSNotification 消息通知的3种方式
- 小菊花(UIActivityIndicatorView)的使用
小菊花的用法比较简单,先创建需要显示的时候直接调用就好。
// 创建全局变量
@property (strong, nonatomic) UIActivityIndicatorView *activityIndicator;
- (void)viewDidLoad {
// 小菊花设置
self.activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleWhiteLarge)];
// 这个是用来设置小菊花的中心点,很多 View 也可以设置
self.activityIndicator.center = CGPointMake(width/2,height/2-40);
}
// 显示小菊花
[self.activityIndicator startAnimating];
// 隐藏小菊花
[self.activityIndicator stopAnimating];
自定义外观和更多使用方式可以参考文章:
iOS UIActivityIndicatorView用法(菊花旋转)
3.5 CocoaPods 以及第三方库的使用
主要功能和 WebView 做好之后要改需求,原因上文已经提到过,接下来要做一个全屏滑动、内容为 2018 年日历的 Banner,以及根据当前的日期跳转到指定的日历页面,用下面的代码获取日期后跳转到 Banner 的某一页就可以了。
- 获取系统日期并转换格式
//获取当前时间日期并返回 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 了,让我自己去写这样一个 Banner 是不太可能的,首先技术不到家而且也没啥时间去慢慢研究着写,所以使用第三方库是最合适的。于是在 GayHub 找各种 Banner 库,发现大家都在用 Pod 导入。
- CocoaPods 安装
查了下发现 Pod 是用来导入第三方库的工具,全称 CocoaPods。虽然直接下载Library 放到项目里可以用但是保不齐第三方库又引用了其它库,难道都要一个一个 Copy 进项目?况且这种东西向来是学了不亏而且以后做 iOS 开发总要用到的,所以还是老老实实学着怎么安装和使用吧。
安装 CocoaPods 之前需要先安装 Ruby 运行环境,然后才能命令行安装 CocoaPods:
Ruby运行环境:如何在Mac OS X上安装 Ruby运行环境
接下来参考下文来安装 CocoaPods
CocoaPods:看一遍就会的CocoaPods的安装和使用教程
安装过程中可能会报各种各样的错误,不要着急,参考下方资料。如果资料不能解决你的问题,Google 或 度娘 你的报错Log。
最详细的CocoaPods安装教程附常见错误总结
安装完毕就可以使用 CocoaPods 了,多去 GayHub 转转,总有各种各样的惊喜等着你。
3.6 其它问题
- App 启动图
记录一个问题,本来好好的启动图,到了大屏手机忽然就不显示了。后来把 2X 3X 的都放进去就正常显示了...常识哇。 - 状态栏文字主题
某些设备默认状态栏文字是黑色的,加上下面的代码就可以改成白色字体。但是状态栏背景色修改起来问题颇多,这里提供一个小办法,在 storyboard 当前 ViewControler 界面顶添加一个的纯色背景,图片亦可,横铺满屏幕即可:
//设置状态栏字体样式
- (UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;//白色
}
- App Icon
有很多网站提供自动生成 App Icon 的功能,扔进去 1024X1024 的图标就可以生成一套图标,很方便。类似的网站还有很多就不一一列举了。
移动应用图标生成工具,一键生成所有尺寸的应用图标
四. App 发布
这里有一个很详细的教程:
iOS App上架流程(2016详细版)
跟着教程一步一步做终于是把 App 扔上去审核了,感觉比较难找的就是 iTunesConnect 放个链接标记一下。
到这里就完成了项目需求。文中引用了各种连接,就不一一提示引用了,感谢那么多前辈的无私分享,也祝大家都能完成一个完美的 App。
补充:
上架过程中遇到的各种问题:
- 使用权限需要告诉用户具体用来干什么,比如 "相机用于识别图片"。