StackMob的诱惑:16小时,山寨一款移动App

2024-01-09 02:58

本文主要是介绍StackMob的诱惑:16小时,山寨一款移动App,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘要:如何在极短的时间内开发出一款“色香味俱全”的应用?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



这篇关于StackMob的诱惑:16小时,山寨一款移动App的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/585728

相关文章

AI Toolkit + H100 GPU,一小时内微调最新热门文生图模型 FLUX

上个月,FLUX 席卷了互联网,这并非没有原因。他们声称优于 DALLE 3、Ideogram 和 Stable Diffusion 3 等模型,而这一点已被证明是有依据的。随着越来越多的流行图像生成工具(如 Stable Diffusion Web UI Forge 和 ComyUI)开始支持这些模型,FLUX 在 Stable Diffusion 领域的扩展将会持续下去。 自 FLU

我在移动打工的日志

客户:给我搞一下录音 我:不会。不在服务范围。 客户:是不想吧 我:笑嘻嘻(气笑) 客户:小姑娘明明会,却欺负老人 我:笑嘻嘻 客户:那我交话费 我:手机号 客户:给我搞录音 我:不会。不懂。没搞过。 客户:那我交话费 我:手机号。这是电信的啊!!我这是中国移动!! 客户:我不管,我要充话费,充话费是你们的 我:可是这是移动!!中国移动!! 客户:我这是手机号 我:那又如何,这是移动!你是电信!!

用Unity2D制作一个人物,实现移动、跳起、人物静止和动起来时的动画:中(人物移动、跳起、静止动作)

上回我们学到创建一个地形和一个人物,今天我们实现一下人物实现移动和跳起,依次点击,我们准备创建一个C#文件 创建好我们点击进去,就会跳转到我们的Vision Studio,然后输入这些代码 using UnityEngine;public class Move : MonoBehaviour // 定义一个名为Move的类,继承自MonoBehaviour{private Rigidbo

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

简单的角色响应鼠标而移动

actor类 //处理移动距离,核心是找到角色坐标在世界坐标的向量的投影(x,y,z),然后在世界坐标中合成,此CC是在地面行走,所以Y轴投影始终置为0; using UnityEngine; using System.Collections; public class actor : MonoBehaviour { public float speed=0.1f; CharacterCo

一款支持同一个屏幕界面同时播放多个视频的视频播放软件

GridPlayer 是一款基于 VLC 的免费开源跨平台多视频同步播放工具,支持在一块屏幕上同时播放多个视频。其主要功能包括: 多视频播放:用户可以在一个窗口中同时播放任意数量的视频,数量仅受硬件性能限制。支持多种格式和流媒体:GridPlayer 支持所有由 VLC 支持的视频格式以及流媒体 URL(如 m3u8 链接)。自定义网格布局:用户可以配置播放器的网格布局,以适应不同的观看需求。硬

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD

16 子组件和父组件之间传值

划重点 子组件 / 父组件 定义组件中:props 的使用组件中:data 的使用(有 return 返回值) ; 区别:Vue中的data (没有返回值);组件方法中 emit 的使用:emit:英文原意是:触发、发射 的意思components :直接在Vue的方法中声明和绑定要使用的组件 小炒肉:温馨可口 <!DOCTYPE html><html lang="en"><head><

react笔记 8-16 JSX语法 定义数据 数据绑定

1、jsx语法 和vue一样  只能有一个根标签 一行代码写法 return <div>hello world</div> 多行代码返回必须加括号 return (<div><div>hello world</div><div>aaaaaaa</div></div>) 2、定义数据 数据绑定 constructor(){super()this.state={na

物联网之流水LED灯、正常流水灯、反复流水灯、移动流水灯

MENU 硬件电路设计软件程序设计正常流水LED灯反复流水LED灯移动流水LED灯 硬件电路设计 材料名称数量直插式LED1kΩ电阻杜邦线(跳线)若干面包板1 每一个LED的正极与开发板一个GPIO引脚相连,并串联一个电阻,负极接GND。 当然也可以选择只使用一个电阻。 软件程序设计 正常流水LED灯 因为要用到多个GPIO引脚,所以最好把所有的GPI