目前,国外至少已经有二十多家企业进入了这个领域,其中,提供的后端服务比较全面的有StackMob、Parse、Kinvey。而国内,和国外的概念比较接近的有Bmob、AMTBaaS,还有我们的Xone。
StackMob
StackMob算是最早进入该领域的,成立于2010年1月,去年5月份的时候,那时该团队还只有6个人,就获得了750万美元的投资。目前该团队有24个人,每月访问量已经超过300万,使用其服务的应用已经达到120万。支持的SDK已经涵盖了iOS、Android、JavaScript、 Ruby,还有Custom Code。其中,Custom Code是用于服务端开发的,可以用Java和Scala语言进行开发。通过Custom Code,开发者就可以在服务端处理一些无法在客户端处理的逻辑。StackMob提供的功能服务也挺全面的,大的方面,数据存储、推送服务、地理位置服务、社交等,再细入到支持角色管理、ACL、复杂和多层的数据模型、多种查询条件等等。
而那么多SDK中,我只看了Android的。其SDK也挺简单易用的,应用程序自身的数据模型只要继承StackMobModel即可,而用户类则继承StackMobUser,然后可以直接定义自己的属性。另外,它也支持嵌套的数据模型,最多支持3层嵌套。比如下面的代码:
- public class Task extends StackMobModel {
- private String name;
- private Date dueDate;
- private int priority;
- private boolean done;
- private Task prerequisite;
- public Task(String name, Date dueDate) {
- super(Task.class);
- this.name = name;
- this.dueDate = dueDate;
- this.priority = 0;
- this.done = false;
- }
- public void setPrerequisite(Task prereq) {
- this.prerequisite = prereq;
- }
- }
- public class TaskList extends StackMobModel {
- private String name;
- private List<Task> tasks;
- private Task topTask;
- private TaskList parentList;
- public TaskList(String name) {
- super(TaskList.class);
- tasks = new ArrayList<Task>();
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public List<Task> getTasks() {
- return tasks;
- }
- }
保存数据时,代码就可以如下:
- TaskList taskList = new TaskList("StackMob Tasks");
- taskList.getTasks().add(new Task("Learn about relations", new Date()));
- taskList.getTasks().add(new Task("Learn about queries", new Date()));
- taskList.save(StackMobOptions.depthOf(1));
StackMob的这种模式,简单易懂,操作上也很方便,数据模型的扩展性也很好。
不过,文件存储就没这么方便了,StackMob不提供将文件上传到它自己的平台服务器,只提供接口,让你将文件上传到开发者自己的S3上面。也就是说,开发者必须自己先申请AWS的S3,才可以使用StackMob提供的文件存储服务。
还有,StackMob的推送服务是使用Google的GCM服务的,所以,开发者还需要拥有Google的GCM账号才能注册使用StackMob的推送服务。
另外,其Model和Controller的分离也还不够好。例如,对于用户操作的方法,在StackMobUser里提供了很多方法,但在StackMob里也提供了不少方法。如果将数据操作的部分可以统一接口就更好了。
再看看StackMob提供的Custom Code,它也提供了操作后台数据很全面的各种方法和类。使用起来也挺简单,比如写个hello_world的例子,后台服务类需要实现CustomCodeMethod接口,比如下面代码:
- public class HelloWorldExample implements CustomCodeMethod {
- /**
- * This method simply returns the name of your method that we'll expose over REST for
- * this class. Although this name can be anything you want, we recommend replacing the
- * camel case convention in your class name with underscores, as shown here.
- *
- * @return the name of the method that should be exposed over REST
- */
- @Override
- public String getMethodName() {
- return "hello_world";
- }
- /**
- * This method returns the parameters that your method should expect in its query string.
- * Here we are using no parameters, so we just return an empty list.
- *
- * @return a list of the parameters to expect for this REST method
- */
- @Override
- public List<String> getParams() {
- return Arrays.asList();
- }
- /**
- * This method contains the code that you want to execute.
- *
- * @return the response
- */
- @Override
- public ResponseToProcess execute(ProcessedAPIRequest request, SDKServiceProvider serviceProvider) {
- //Send push messages...
- //Query the datastore...
- //Run complex server side operations..
- //Then prepare your custom JSON to send back to the mobile client
- Map<String, String> args = new HashMap<String, String>();
- args.put("msg", "hello world!");
- return new ResponseToProcess(HttpURLConnection.HTTP_OK, args);
- }
- }
然后,在Android端这样调用:
- StackMob.getStackMob().getDatastore().get("hello_world", new StackMobCallback() {
- @Override public void success(String responseBody) {
- //responseBody is "{ \"msg\": \"Hello, world!\" }"
- }
- @Override public void failure(StackMobException e) {
- }
- });
StackMob教程指南:https://developer.stackmob.com/tutorials
#p#
Parse
Parse比StackMob晚成立一年,近期也得到了700万美元的注资,目前团队20人,有2万名开发者使用其平台,40万款应用使用其服务。 支持的API有iOS、Android、JavaScript、Windows 8,以及提供了REST API和Cloud Code JS API。Cloud Code JS API和StackMob的Custom Code一样用于服务端开发,处理自己的逻辑,不同的是,StackMob用Java或Scala开发,而Parse提供JS的接口。Parse提供的功 能服务也算是比较全面的,StackMob提供的大部分功能服务,它也提供了。而支持Windows8,这点还比StackMob领先了一步。另外,它对 ACL的设置也比StackMob灵活。StackMob只能在后台管理页面对角色设置ACL,而Parse可以在代码中设置全局的ACL,也可以对每个 对象设置ACL。文件存储方面,Parse虽然也是保存在S3,但它将用户的文件保存在自己的平台,而不是开发者自己的S3,这一点也比StackMob 要方便得多。
不过,Parse的SDK使用起来就没StackMob那么方便了。Parse保存和查询对象的代码如下:
- ParseObject gameScore = new ParseObject("GameScore");
- gameScore.put("score", 1337);
- gameScore.put("playerName", "Sean Plott");
- gameScore.put("cheatMode", false);
- gameScore.saveInBackground();
- ParseQuery query = new ParseQuery("GameScore");
- query.getInBackground("xWMyZ4YEGZ", new GetCallback() {
- public void done(ParseObject object, ParseException e) {
- if (e == null) {
- int score = object.getInt("score");
- String playerName = object.getString("playerName");
- boolean cheatMode = object.getBoolean("cheatMode");
- } else {
- // something went wrong
- }
- }
这样子,开发者就很难定义自己的数据模型,全部操作都只能通过ParseObject了。Model和Controller完全耦合在一起,应用与Parse的耦合性非常强,如果开发者想要移植到其他平台就会很麻烦。而且,这种模式,对于开发比较复杂的应用也将变得麻烦。
再看看Parse的Cloud Code。使用Parse的Cloud Code,需要下载Parse提供的命令行工具,然后需要用parse new命令创建一个存放代码的目录,还需要输入邮箱和密码登录开发者的账号,选择一个应用,并用cd命令进入创建的目录:
$ parse new MyCloudCode Email: ninja@gmail.com Password: 1:MyApp Select an App: 1 $ cd MyCloudCode
MyCloudCode目录会自动生成几个文件:
-config/ global.json -cloud/ main.js
其中,main.js就是保存开发者自己所有Cloud Code的地方。写个最简单的例子:
- Parse.Cloud.define("hello", function(request, response) {
- response.success("Hello world!");
- });
然后用parse deploy命令部署到Parse平台上:
$ parse deploy
然后,在Android端就可以用以下代码调用:
- ParseCloud.callFunction("hello", new HashMap<Object, Object>(), new FunctionCallback<String>() {
- void done(String result, ParseException e) {
- if (e == null) {
- // result is "Hello world!"
- }
- }
- });
Parse文档:https://parse.com/docs
#p#
Kinvey
Kinvey则是TechStars下的一家创业公司,也是去年成立,到目前为止也已经得到了700万美元的投资,目前团队19人,而使用其平台的 应用数则没有公布。前端支持的API有iOS、Android、JavaScript和REST,后端同样提供了Backend Logic接口供开发者处理后台逻辑。相较于StackMob和Parse,Kinvey提供的功能就没那么全面了,缺少了角色管理,也缺少了地理位置服 务。
Kinvey的SDK有一点我比较喜欢,那就是Model和Controller有了较好的分离,Model提供了接口 MappedEntity,Controller则用KCSClient做入口。不过,数据模型的定义却不如StackMob那样方便,多了一步属性与后 台表字段的映射。代码如下:
- public class MyEntity implements MappedEntity {
- private String uname;
- private String id;
- @Override
- public List<MappedField> getMapping() {
- return Arrays.asList(new MappedField[] { new MappedField("uname", "name"),
- new MappedField ("id", "_id") });
- }
- // Getters and setters for all fields are required
- public String getUname() { return uname; }
- public void setUname(String n) { uname = n; }
- public String getId() { return id; }
- public void setId(String i) { id = i; }
- }
其中,getMapping方法就是处理映射关系。然后保存数据就可以通过以下代码:
- MyEntity item = ...;
- item.setName("Idle Blue");
- mKinveyClient.mappeddata("collectionName").save(item, new ScalarCallback<MyEntity>() {
- @Override
- public void onFailure(Throwable e) { ... }
- @Override
- public void onSuccess(MyEntity r) { ... }
- });
其中,mKinveyClient.mappeddata("collectionName")方法得到MappedAppData,该类封装了 MappedEntity相关的各种操作。另外,通过mKinveyClient.resource("name")方法则得到 KinveyResource,该类封装了文件相关的各种操作。
Kinvey另外还提供了和ParseObject类似的方式,代码如下:
- EntityDict album = mKinveyClient.entity("albums");
- album.putProperty("title", "Idle Blue");
- album.save(new ScalarCallback<EntityDict>() {
- @Override
- public void onFailure(Throwable e) { ... }
- @Override
- public void onSuccess(EntityDict r) { ... }
- });
Kinvey的Backend Logic与StackMob和Parse有着很大不同。StackMob和Parse虽然处理方式不同,但基本思路都是前端传送指定的方法(如 hello_world),后台写相应的代码处理这个方法。而Kinvey的Backend Logic则是在对数据库操作的前后分别提供接口处理。如下图:
PreProcess提供了几个方法:
- function onPreSave(request,response,modules){
- }
- function onPreDelete(request,response,modules){
- }
- function onPreFetch(request,response,modules){
- }
PostProcess也提供了几个方法:
- function onPostSave(request,response,modules){
- }
- function onPostDelete(request,response,modules){
- }
- function onPostFetch(request,response,modules){
- }
Kinvey文档:http://docs.kinvey.com/overview.html
#p#
Bmob
Bmob不是一家公司的名字,只是广州一家叫鹏锐的IT公司的其中一个产品。Bmob应该算是国内第一个BaaS平台,今年4月份的时候上线的。而 到目前为止,Bmob还只有Android的SDK,而且还是山寨Parse的,但功能比Parse少了很多,没有角色管理,没有ACL,也没有关系查 询,更没有后端的Cloud Code,跟Parse的SDK比较一下,就会知道相比Parse少了非常多的东西,基本上就是Parse的一个简化版。版本升级过一次,在第二版加入了 支付功能,而支付卡基本上都是些游戏卡,很明显,这是为付费游戏提供的服务。
看看Bmob的代码,和Parse一样的吧:
- BmobObject gameScore = new BmobObject("GameScore");
- gameScore.put("score", 1200);
- gameScore.put("playerName", "张小明");
- gameScore.put("cheatMode", false);
- try {
- gameScore.save();
- } catch (BmobException e) {
- // e.getMessage() 捕获的异常信息
- }
Bmob第一版的时候,就出现过很多问题,如经常断线,数据丢失等,逐渐失去开发者的信任,基本功能也还很不完善。而第二版没有去完善那些重要的功 能,提高开发者的信任度,反而推出了支付功能,我觉得这是个错误的策略。首先,重点应该放在完善基本功能和提高开发者对平台的信任度;其次,支付功能这种 安全性要求非常高的服务,只有在平台已经非常成熟,用户对其已经非常信任的前提下提供才会有效用,在经常断线,数据会出现丢失的情况下,有谁敢去用支付功 能呢?
另外,Bmob还提供了很多应用分析的功能,这一点,我也觉得多余了。专业的应用分析,已经有友盟平台了,没必要自己再做一套。
Bmob还存在很多不成熟的地方,第一版上线到目前也已经半年多了,改善的东西很少,发展速度较慢,给我的感觉就是他们没有抓到真正的重点,或者他们将精力移到了广告平台——他们的另一个产品,毕竟那是实实在在可以赚到钱的产品。
Bmob官网:http://bmob.cn/
#p#
AMTBaaS
AMTBaaS是诚迈科技最近推出的BaaS平台,9月中旬发布了iOS的SDK,10月中旬又发布了Android的SDK。目前,处于内测阶 段。提供的文档,除了API,也只有一个用户手册提供下载。网站和文档的用户体验都比较差,其SDK的体验也是很差,就说一个用户注册的方法:
- register(Context context, java.lang.String useremail, java.lang.String passWord, java.lang.String confirmPwd, boolean ischeckCode, java.lang.String checkcode, AmtUserCallback amtUserCallback)
再看看用户注册的操作:
- // 注册消息
- public static final int MESSAGE_REGISTER = 1001;
- // 构造AmtUser对象
- private AmtUser amtUser = new AmtUser();
- // 注册
- amtUser.register(UserActivity.this, “user@qq.com”, “123456”, “123456”, true, “53Fe”, new AmtUserCallback() {
- @Override
- public void onSuccess(Object object) {
- if (object != null) {
- // 回调方法中不可直接操作UI控件
- mhandler.sendMessage(mhandler.obtainMessage(
- MESSAGE_REGISTER, object));
- }
- }
- @Override
- public void onFailure(AmtException amtException) {
- if (amtException != null) {
- // 回调方法中不可直接操作UI控件
- mhandler.sendMessage(mhandler.obtainMessage(
- MESSAGE_REGISTER, amtException));
- }
- }
- });
- /**
- * 注册回调句柄
- */
- Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what) {
- case MessageTypes.MESSAGE_REGISTER:
- // 注册失败
- if (msg.obj instanceof AmtException) {
- AmtException amtException = (AmtException)msg.obj;
- AmtUtil.log("UserActivity", "注册失败:"+
- amtException.getMessage(), "i");
- }
- // 注册成功
- else if (msg.obj instanceof String) {
- String result = (String)msg.obj;
- If (AmtConstants.SUCCESS.equals(result) {
- AmtUtil.log("UserActivity", "注册成功", "i");
- }
- }
- break;
- }
- }
- };
一个注册就这么麻烦,完全不懂用户体验。对于其前景不看好。
AMTBaaS官网:http://amtbaas.com/
#p#
Xone
Xone则是我们公司现在的核心产品,目前开发了两个月左右,前端只支持 Android,目前的SDK提供的功能有版本管理、数据存储、用户管理、文件存储、地理信息服务,推送服务还没开发出来。后端也提供JS的 Backend Logic服务,刚开发完。网站也只是搭了个雏形,现在正在重新设计和完善之中。
为了将Model和Controller较好地分离并能简单的使用SDK,我们采用了这样的结构:
1. 数据模型我们定义了一个基类XoneEntity,类里只定义了几个基本属性,不带任何数据操作的方法。另外定义了继承它的两个子 类,XoneGeoEntity和XoneUser,XoneGeoEntity用于带有地理信息的数据模型,XoneUser则是用户数据模型。应用程 序自身的数据模型则继承XoneEntity,然后定义自己的属性即可,不需要像Kinvey那样还要做映射。如果应用程序自身的数据模型需要包含地理信 息,则继承XoneGeoEntity,用户模型则继承XoneUser。
2. 对各种服务分类提供了接口,每个接口里定义了相应的数据操作的方法。服务接口有:
- AppService:应用程序和平台相关的服务接口
- CollectionService<T extends XoneEntity>:集合相关的服务接口
- UserService<T extends XoneUser>:用户相关的服务接口
- FileService:文件相关的服务接口
3. XoneClient是Controller的入口,通过XoneClient实例的getXXXService()的各种方法调用各种服务接口,再通过服务接口调用具体的数据操作方法。比如,用户注册:
- UserService<XoneUser> userService = xoneClient.getUserService();
- userService.signUp(user, callback);
一切都还在完善之中,各种功能服务,以及网站。后续,当我们的平台正式上线时,我们的SDK还将会开源。
Xone官网:http://xone.im/