StackMob的诱惑:16小时,山寨一款移动App
发表于2013-03-19 13:58| 5359次阅读| 来源StackMob| 11 条评论| 作者Tope Abayomi
移动开发AirBnBStackMobApartment ShareiOS行业应用BaaS摘要:如何在极短的时间内开发出一款“色香味俱全”的应用?Tope Abayomi通过使用现有的App设计模板加上StackMob后端服务及工具在短短16个小时内便山寨出一个类似于AirBnB的App——Apartment Share,从创建后端到各个阶段代码,Tope详尽地分享了自己开发的每一步骤。
AirBnB(空中食宿)的火爆程度无需多言,以遍布全球192个国家37903个城市的房屋短期租赁服务颠覆了国内外的酒店行业固有的模式。让用户从其住宅中列出一个单间来租给那些旅行或仅在城市短期居住的人,如此租赁模式诱人至极。来自App Design Vault的Tope Abayomi通过使用StackMob后端服务及工具在短短16个小时内便山寨出一个类似于AirBnB的App——Apartment Share。当然,山寨应用并将其用于商业用途实在让人诟病,因此Tope也并没有将其真正发布到App Store,此开发过程仅供开发者交流学习。
StackMob是一款优秀的BaaS(后端即服务)产品,其独有的云计算系统能为App开发者提供实时分析、消息放送、Facebook/Twitter集成、Amazon S3集成、广告、地理位置、盈利等服务。开发者只需几十分钟,就可以通过Web界面勾勾选选,定制一个API架构,而且能很快在云端激活,这也是为什么Tope花上16个小时就能开发出Apartment Share的原因所在。
在完成Apartment Share应用开发之后,Tope不仅在StackMob博客上写下了非常详细的开发步骤,而且将完整的项目示例上传以供开发者借鉴。接下来就让我们一起来围观,看Tope是如何开发出“色香味俱全”的Apartment Share的。
图:Apartment Share应用使用
Tope在Apartment Share v1.0中想要实现的功能:
一个登录及注册界面,能够让用户登录或注册该服务。
一个展示公寓列表的界面,能够让用户浏览公寓及景点。
一个能够让用户上传自己所有的公寓细节界面。
在StackMob Dashboard上创建后端
第一步是在
StackMob Dashboard上创建一个新的App。登录并创建一个新的App,选择iOS SDK选项,然后按照步骤要求在你的Xcode项目中安装StackMob SDK。
图:创建App
StackMob提供了一个名为Schema Inference的非常灵巧的功能。当对象创建请求被发送到服务器但Schema/字段不存在时,Schema Inference允许自动创建Schema(数据库对象集合)。Schema Inference无法自动确定二进制文件(图像等)及地理位置域信息,也就是说你必须在控制面板上手动创建并进行设置。点击“Schema Configuration”进入配置界面,点击“Add a New Schema(添加一个新Schema)”并以“apartment”命名。
接下来,如下图所示,填写apartment_type、location、photo、price及room_count等字段。
保存图像的字段为“二进制”类型,为了实现图像上传,我们需要将StackMob账户连接到Amazon S3存储区。按照StackMob的
Adding a Binary Field to Schemas指南中的步骤建立连接。
出于安全考虑,我们需要确保只有已登录的用户才能创建/上传新公寓,当然,公寓也应该只能由其创建者更新或删除,而StackMob很好地通过Schema权限功能解决了这一问题。
在它的Edit a Schema页面底部,你可以查找并为任意Schema设置权限。
以上设置将允许任何人使用该App来浏览、查看空闲公寓。若要创建一个公寓,你必须处于登录状态,已登录的用户可以创建一个自动被StackMob放置在对象的sm_owner字段中的对象。
完成上述操作之后点击“Save Schema”进行保存,为现有的用户模式申请权限,然后即可进入代码编写阶段。
初始化
在我们的App Delegate中,初始化一个StackMob客户端,并通过Core Data连接到数据存储。从面板上复制下
StackMob应用公钥,将其粘贴在项目中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#import "AppDelegate.h"
#import "ADVTheme.h"
#import "StackMob.h"
#define PUBLIC_KEY @"YOUR_PUBLIC_KEY"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[ADVThemeManager customizeAppAppearance];
self.client = [[SMClient alloc] initWithAPIVersion:@"0" publicKey:PUBLIC_KEY];
self.coreDataStore = [self.client coreDataStoreWithManagedObjectModel:self.managedObjectModel];
return YES;
}
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"ApartmentModel" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
登录界面
顾名思义,登录界面是一个让用户登录或创建账户的地方。如果要想实现用户创建一个账户的操作,我们就需要一个新的ViewController及展示一个拥有用户名和密码字段的相似界面。当用户点击“Sign Up”按钮时,实现创建一个新的管理对象并调用保存。
使用StackMob后端创建一个用户:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(IBAction)signUpUserPressed:(id)sender
{
User *newUser = [[User alloc] initIntoManagedObjectContext:self.managedObjectContext];
[newUser setValue:self.userRegisterTextField.text forKey:[newUser primaryKeyField]];
[newUser setPassword:self.passwordRegisterTextField.text];
[self.managedObjectContext saveOnSuccess:^{
[self.navigationController popViewControllerAnimated:YES];
} onFailure:^(NSError *error) {
//Something bad has ocurred
NSString *errorString = [error localizedDescription];
UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[errorAlertView show];
}];
}
一旦用户账户被创建,登录也就变得如此简单:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-(IBAction)logInPressed:(id)sender
{
[self.client loginWithUsername:self.userTextField.text password:self.passwordTextField.text onSuccess:^(NSDictionary *results) {
if ([[[self appDelegate] client] isLoggedIn]) {
NSLog(@"Logged in");
}
[self performSegueWithIdentifier:@"list" sender:self];
} onFailure:^(NSError *error) {
//Something bad has ocurred
NSString *errorString = [error localizedDescription];
UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[errorAlertView show];
}];
}
查看控制面板上的
Data Management截图,可以看到在后端用户已被创建。
图:Data Management
显示公寓列表
接下来就是实现显示所有空闲公寓列表操作。首先,我们创建包括公寓价格、房间数、照片及公寓类型(公寓或住宅)等属性在内的公寓对象。
图:服务器上的公寓对象
若要实现包含公寓图像的字段就必须使用Amazon S3服务。点击链接,查看如何实现“
将你的Amazon S3存储区与StackMob应用连接起来”。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-(void)getAllApartments
{
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeIndeterminate;
hud.labelText = @"Loading...";
NSFetchRequest *fetch = [[NSFetchRequest alloc] initWithEntityName:@"Apartment"];
[self.managedObjectContext executeFetchRequest:fetch onSuccess:^(NSArray *results) {
self.apartments = results;
[self.apartmentTableView reloadData];
[MBProgressHUD hideHUDForView:self.view animated:YES];
} onFailure:^(NSError *error) {
// ALERT
NSString *errorString = [error localizedDescription];
UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[errorAlertView show];
}];
}
以上代码段表示的是StackMob后端如何查询公寓列表。寻找一个名为“Apartment”的实体,即之前在服务器设置阶段为Schema所命名的对象。继而以创建日期对公寓进行排序,最后,初始化一个列表数组返回。
下一步是在一个UITableView中显示每一个公寓。在下面的代码段中,我们从Apartment对象中提取每一个属性,比如价格、照片、房间数等,并对UITableViewCell的属性进行设置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
ApartmentCell* cell = [tableView dequeueReusableCellWithIdentifier:@"ApartmentCell" forIndexPath:indexPath];
Apartment *apartment = [self.apartments objectAtIndex:indexPath.row];
NSNumber* roomCount = [apartment valueForKey:@"roomCount"];
NSString* roomCountText = [NSString stringWithFormat:@"%d Bed", [roomCount intValue]];
NSNumber* price = [apartment valueForKey:@"price"];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle: NSNumberFormatterCurrencyStyle];
NSString *priceString = [numberFormatter stringFromNumber:price];
[cell.locationLabel setText:[apartment valueForKey:@"location"]];
[cell.priceLabel setText:priceString];
[cell.roomsLabel setText:roomCountText];
[cell.apartmentTypeLabel setText:[apartment valueForKey:@"apartmentType"]];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
NSURL* imageURL = [NSURL URLWithString:[apartment valueForKey:@"photo"]];
设计公寓视图
在App中,设计占据着举足轻重的地位,要想在App Store中脱颖而出最好的方法之一便是拥有一个非常好的设计。我使用了App Design Vault上的一种能够让应用界面非常光滑、直观的
设计模板,如下图所示,每一个单元格都是由不同的元素组成,公寓的图像有一个渐变叠加,如此,公寓的位置信息可以轻松地被读取。图片下方是一个可以查看公寓更多细节的微件。
上传新对象
当你初次运行该应用时,公寓列表为空。如果想要显示公寓列表,就需要上传新对象。
通过使用UploadImageViewController中的UIElements属性可以添加一个公寓的各种细节。UIImageView属性可以实现从照片库中选择一张照片,除此之外,还有UITextFields及UISlider等其他属性。在完成一切操作之后,点击“Upload”按钮即可完成新对象上传操作。
向服务器发送对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-(void)uploadDataToServer{
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"Apartment" inManagedObjectContext:self.managedObjectContext];
NSData *imageData = UIImageJPEGRepresentation(self.uploadImageView.image, 0.4);
NSString *picData = [SMBinaryDataConversion stringForBinaryData:imageData name:@"apartment.jpg" contentType:@"image/jpg"];
NSString* apartmentType = self.apartmentTypeControl.selectedSegmentIndex == 0 ? @"House" : @"Flat";
NSNumber* price = [NSNumber numberWithFloat:[self.priceTextField.text floatValue]];
NSNumber* roomCount = [NSNumber numberWithFloat:self.roomsSlider.value];
[newManagedObject setValue:picData forKey:@"photo"];
[newManagedObject setValue:self.locationTextField.text forKey:@"location"];
[newManagedObject setValue:roomCount forKey:@"roomCount"];
[newManagedObject setValue:price forKey:@"price"];
[newManagedObject setValue:apartmentType forKey:@"apartmentType"];
[newManagedObject setValue:[newManagedObject assignObjectId] forKey:[newManagedObject primaryKeyField]];
[self.managedObjectContext saveOnSuccess:^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
NSLog(@"Successful upload");
[self.navigationController popViewControllerAnimated:YES];
} onFailure:^(NSError *error) {
[MBProgressHUD hideHUDForView:self.view animated:YES];
UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:[self.uploadError localizedDescription] delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
[errorAlertView show];
}];
}
在视图中,所有数据均从UIControls中提取。图像文件转换为二进制数据,Core Data对象属性设置输入值。最后调用管理对象信息服务,发送信息到StackMob后端,然后在Data Management中查看新建对象。
Tope写在最后:
利用StackMob等后端服务的优势能够快速将App开发付诸实践。三天的时间里从创建应用到实现运行,我慢慢悠悠地花了大约16个小时。当然,好的应用需要设计与美学的结合,如果你想一试,不妨试试我曾经使用过的
这款设计模板。总而言之,“设计模板+StackMob”,能让在短短十数小时内开发出一款“色香味俱全”的App成为小case。
开发者可以下载该
示例项目,当然也可以亲身体验,尝试在极短的时间内开发出一款App,然后在GitHub上晒晒自己开发制作的
Apartment Share。(编译/唐小引 责编/张宁)
文章来源:
StackMob