移動后端服務BaaS現狀
目前,國外至少已經有二十多家企業進入了這個領域,其中,提供的后端服務比較全面的有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/