This is a quick comparison of some of the Android flavors of various BaaS APIs. It attempts to simply show the same ideas (library initialization, user authentication, data read/write, etc) with the various APIs, to give the AeroGear team some context as to possible directions.
There is a nice list of providers here (current as of 08/2012):
And also a comparison of StackMob/Kinvey/Parse here:
We should at some point also have a similar survey of backend REST APIs for comparison purposes.
##Open Questions
- Data-binding to classes or generic property bags?
- How to handle data relations?
- How to handle binary data?
- Explicit class schemas or schemaless?
- How to best handle local caching + sync?
- Provide atomic counters? (most of these libraries do)
- Manage clients with API keys?
#StackMob
##Summary
- https://stackmob.com/devcenter/docs
- Uses GSON (https://sites.google.com/site/gson/gson-user-guide) for data binding
- Open Source (Apache Licensed, on GitHub - https://github.com/stackmob/StackMob_Android)
###Initialization
final String API_KEY = "YOUR API KEY HERE";
final String API_SECRET = "YOUR API SECRET HERE";
//leave this as a blank string if you don't have a user object.
//if you leave it blank, however, you must not call login, logout or any of the twitter or facebook methods,
//so we highly recommend that you set up a user object
final String USER_OBJ_NAME = "users";
//0 for sandbox, 1 or higher for a deployed API
final Integer API_VERSION = 0;
StackMob stackmob = new StackMob(API_KEY, API_SECRET, USER_OBJ_NAME, API_VERSION);
###Data-bound classes
public class Task extends StackMobModel {
private String name;
private Date dueDate;
private int priority = 0;
private boolean done = false;
public Task(String name) {
super(Task.class);
this.name = name;
}
//Add whatever setters/getters/other functionality you want here
}
Storing an object:
Task blogPostTask = new Task("Write blog post");
blogPostTask.save(); // Takes optional callback argument
Getting a collection of objects:
StackMobModelQuery<Task> tasksQuery = new StackMobModelQuery<Task>(Task.class);
// Can now specify any constraints, i.e. tasksQuery.fieldIsLessThan("priority", "5")
tasksQuery.send(new StackMobQueryCallback<Task>() {
@Override
public void success(List<Task> tasks) {
//You now have a list of every Task ever saved
}
@Override
public void failure(StackMobException e) {
//handle failure case
}
});
###Login/auth
Map<String, String> args = new HashMap<String, String>();
args.put("username", "johndoe");
args.put("password", "mypassword");
StackMobCommon.getStackMobInstance().login(args, new StackMobCallback() {
@Override public void success(String response) {
//login succeeded
}
@Override public void failure(StackMobException e) {
//login failed
}
});
###Register user with Facebook
StackMobCommon.getStackMobInstance().registerWithFacebookToken(fbToken, username, new StackMobCallback() {
@Override public void success(String response) {
//registration succeeded
}
@Override public void failure(StackMobException e) {
//registration failed
}
});
#Kinvey
###Summary
- http://docs.kinvey.com/android-developers-guide.html
- Custom object mappings via MappedEntity class
###Initialization
KinveySettings = KinveySettings.loadFromProperties(getApplicationContext());
sharedClient = KCSClient.getInstance(getApplicationContext(), settings);
###Data-bound classes
Kinvey uses inline metadata to define and customize object mappings.
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; }
}
Modifying/saving an item:
MyItemMappedEntity item = ...;
item.setTitle("Idle Blue");
sharedClient.mappeddata("items").save(item, new ScalarCallback<Void>() {
@Override
public void onFailure(Throwable e) { ... }
@Override
public void onSuccess(Void r) { ... }
});
Getting a collection of items:
sharedClient.mappeddata("items").all(ListEntity.class, new ListCallback<Item>() {
@Override
public void onSuccess(List<Item> result) { ... }
@Override
public void onFailure(Throwable error) { ... }
});
###Generic objects (property bags)
EntityDict album = sharedClient.entity("albums");
album.putProperty("title", "Idle Blue");
album.save(new ScalarCallback<Void>() {
@Override
public void onFailure(Throwable e) { ... }
@Override
public void onSuccess(Void r) { ... }
});
#Parse
###Summary
- https://www.parse.com/docs/android_guide
- No data binding, objects are generic property bags (ParseObject)
- Explicit relation support
###Initialization
Parse.initialize(this, "Your Application Id", "Your Client Key");
###Login
ParseUser.logInInBackground("Jerry", "showmethemoney", new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
// Hooray! The user is logged in.
} else {
// Signup failed. Look at the ParseException to see what happened.
}
}
});
###Login/Register with Facebook
ParseFacebookUtils.logIn(this, new LogInCallback() {
@Override
public void done(ParseUser user, ParseException err) {
if (user == null) {
Log.d("MyApp", "Uh oh. The user cancelled the Facebook login.");
} else if (user.isNew()) {
Log.d("MyApp", "User signed up and logged in through Facebook!");
} else {
Log.d("MyApp", "User logged in through Facebook!");
}
}
});
###Creating/updating objects
ParseObject gameScore = new ParseObject("GameScore");
gameScore.put("score", 1337);
gameScore.put("playerName", "Sean Plott");
gameScore.put("cheatMode", false);
gameScore.saveInBackground(); // or saveEventually() for offline!