Introduction
Realtime applications are becoming even more popular these days, but the development of such applications is not an easy process. Which is the reason why new realtime platforms are being born. They will make realtime application implementation much easier. Developers need no longer worry about synchronization of data with server and on top of it they can save up to 80% of their time while developing products and focus more on UX/UI.
The world’s most famous realtime platform is most probably Firebase which has more than 200 000 registered users as of today. SynergyKit, on the other hand, is name of new evolving platform of czech company Letsgood.com (Etnetera Group). At the moment is SynergyKit in public beta mode.
SynergyKit or Firebase?
In order to compare these two products, I will take a look at very frequent Use Case which is part of a chat application. The application displays realtime messages from users and they are sent using push notification if application is not in foreground. You can register and login via Facebook profile.
Sample application with source codes can be found at GitHub.
Application Screenshots
The look of application is built on sample application for Synergit and slightly modified.
Instalation
SynergyKit
SynergyKit SDK for Android minimum requirement is version Android SDK 14.
Into file build.gradle in element dependencies is needed to add following dependency.
dependencies {
...
compile
}
Since the application uses internet access, it is necessary to ask Android for right to use internet. This can be done in file AndroidManifest.xml, where you need to put following code into manifest element.
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
Next you need to initialize SynergyKit SDK before you can use it. I recommend to get it done by onCreate method from Application class.
public void onCreate() {
super.onCreate();
Synergykit.init(APPLICATION_TENANT, APPLICATION_KEY);
...
}
Firebase
Firebase SDK for Android requirement minimum is Android SDK 10.
Into file build.gradle is needed to add the following dependency and packigingOptions.
android {
...
packagingOptions {
exclude
exclude
exclude
}
}
dependencies {
...
compile
}
SInce the application uses internet access, it is needed to ask Android for right to use internet. This can be done in file AndroidManifest.xml, where you insert this code to manifest element.
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
Before its first use, Firebase needs Context to run, I recommend onCreate method from Application class.
public void onCreate() {
super.onCreate();
Firebase.setAndroidContext(this);
...
}
User login
A user will login via Facebook, name from Facebook will be saved and used for sending messages. For each user information about their online status will be saved.
SynergyKit
SDK doesn't support getting a name from Facebook AccessToken, therefore you need to get this name before login. This can be done through GraphRequest. A name of user will be saved in a variable Name.
GraphRequest request = GraphRequest.newMeRequest(AccessToken.getCurrentAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
@Override
public void onCompleted(JSONObject object, GraphResponse response) {
String name = null;
try {
name = object.getString("name");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Bundle parameters = new Bundle();
parameters.putString("fields", "name");
request.setParameters(parameters);
request.executeAsync();
In parameter User will be delivered SynergyKitUser, where will be set name, online status and data will be saved.
Synergykit.linkFacebook(user, synergykitFacebookAuthData, new UserResponseListener() {
@Override
public void doneCallback(int statusCode, SynergykitUser user) {
}
@Override
public void errorCallback(int statusCode, SynergykitError errorObject) {
}
});
Firebase
Login via Firebase is easier. You dont need to get name of user through GraphRequest. This solves Firebase SDK for Android itself.
private Firebase firebase;
...
firebase = new Firebase("https://<APP_URL>.firebaseio.com");
...
firebase.authWithOAuthToken("facebook", accessToken.getToken(), new Firebase.AuthResultHandler() {
@Override
public void onAuthenticated(AuthData authData) {
setOnline(true);
}
@Override
public void onAuthenticationError(FirebaseError firebaseError) {
}
});
But this is only user login not saving of a user. For saving I will use function which changes online status of user on server. The function is explained below in Online Status Setup.
Online Status Setup
A user with displayed chat is online. When the application is overlapped by another application, display goes off or a user closes the application, it will switch to offline. Those functions call onResume and onPause so they set the right status.
SynergyKit
The function described below sets online status to user. Parameter online is user’s status. Second parameter paralleMode will cause that this operation will run asynchronously.
private void setOnline(boolean online, boolean parallelMode) {
if (user == null) return;
user.setOnline(online);
Synergykit.updateUser(user, new UserResponseListener() {
@Override
public void doneCallback(int statusCode, SynergykitUser synergykitUser) {
user = (SKUser) synergykitUser;
}
@Override
public void errorCallback(int statusCode, SynergykitError synergykitError) {
}
}, parallelMode);
}
Firebase
The function described below sets online status to user. If user doesnt exist, it will create him. Firebase uses JSON data so here is used a map.
private void setOnline(boolean online) {
Map<String, Object> map = new HashMap<>();
map.put("name", userName);
map.put("online", online);
firebaseUsers.child("" + uId).setValue(map);
}
Messaging
Messaging is solved by adding a message into collection for both platforms, where application listens to changes which are received through websockets.
SynergyKit
Class containing all necessary attributes was created and for needs of SynergyKit expands SynergykitObject. The following code adds a message to collection.
Synergykit.createRecord(COLLECTION_MESSAGES, message, new ResponseListener() {
@Override
public void doneCallback(int statusCode, SynergykitObject synergykitObject) {
}
@Override
public void errorCallback(int statusCode, SynergykitError synergykitError) {
}
}, true);
Firebase
Class containing all necessary attributes was created. The following code adds a message to collection.
firebaseMessages.push().setValue(message, new Firebase.CompletionListener() {
@Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
if (firebaseError != null) {
} else {
}
}
});
Receiving messages
Receiving messages for both platforms is solved by listening for event adding to collection. Application will display last 100 messages.
SynergyKit
The following code gets last 100 records from messages collection.
SynergykitUri synergyKitUri = UriBuilder.newInstance()
.setResource(Resource.RESOURCE_DATA)
.setCollection(COLLECTION_MESSAGES)
.setOrderByDesc("createdAt")
.setTop(prevMessageCount)
.build();
SynergykitConfig config = SynergykitConfig.newInstance()
.setParallelMode(true)
.setType(SKMessage[].class)
.setUri(synergyKitUri);
Synergykit.getRecords(config, new RecordsResponseListener() {
@Override
public void doneCallback(int statusCode, SynergykitObject[] synergykitObjects) {
SKMessage[] messages = (SKMessage[]) synergykitObjects;
}
@Override
public void errorCallback(int statusCode, SynergykitError synergykitError) {}
});
The following code will register socket for listening for event created.
Synergykit.onSocket(EVENT_CREATED, COLLECTION_MESSAGES, new SocketEventListener() {
@Override
public void call(Object... objects) {
String data = objects[0].toString();
final SKMessage message = GsonWrapper.getGson().fromJson(data, SKMessage.class);
}
@Override
public void subscribed() {}
@Override
public void unsubscribed() {}
});
Synergykit.connectSocket();
Firebase
Query is used for filtration and cutting down the number of messages. ChildEventListener enables listening for changes.
Query query = firebaseMessages.orderByChild("timestamp").limitToLast(prevMessageCount);
query.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot == null) return;
FBMessage message = dataSnapshot.getValue(FBMessage.class);
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
@Override
public void onCancelled(FirebaseError firebaseError) {}
});
Push Notifications
Push notification will be received and displayed when a user is not on chat screen. Push notification will have form “Sender: message” and will play a default notification sound while receiving. Information regarding Push Notifications from GCM.
SynergyKit
The prerequisite is having created an application in Google Console. Into application settings in SynergyKit is necessary to write down so called API key GCM, which can be done in bookmark Settings->Android GCM.
New dependency has to be added into file build.gradle.
dependencies {
...
compile
}
Registration ID is acquired by registration to GCM service.
regid = gcm.register(SENDER_ID);
Registration ID acquired earlier has to be saved on server which will be sending out Push Notifications. SynergyKit saves this information to an instance of the class SynergyKitPlatform. Class SynergyKitPlatform is part of class SynergykitUser or its follower.
if (platform == null) {
SynergykitPlatform platform = new SynergykitPlatform(regid);
Synergykit.addPlatform(platform, new PlatformResponseListener() {
@Override
public void doneCallback(int statusCode, SynergykitPlatform platform) {
}
@Override
public void errorCallback(int statusCode, SynergykitError errorObject) {
}
}, true);
} else if (!platform.getRegistrationId().equals(regid)) {
platform.setRegistrationId(regid);
Synergykit.updatePlatform(platform, null, true);
}
Cloud code enables to run the code on the server side. From a device it is possible to turn on or set automatic turning on in event at collection. Code is written in JavaScript to browser IDE, where it can be also debugged.
I have set up trigger to event “created” in collection messages, therefore Cloud code will be called after receiving a message. The following Cloud code gets all users having set up attribute online to false and will send them notification.
var queryOfflineUsers = Synergykit.Query(Synergykit.User());
queryOfflineUsers.where().attribute("online").isEqualTo(false).find({
success: function(offline_users, code) {
if (code == 200) {
var notification = Synergykit.Notification(offline_users);
var text = parameters.name + ': ' + parameters.text;
notification.set("alert", text);
notification.send({
success: function(result, statusCode) {
callback({
result: 'success',
offline_users: offline_users
});
},
error: function(error, statusCode) {
callback;
}
});
} else {
callback;
}
},
error: callback
});
Notification has been sent to all users, yet the application is not receiving them. It is needed to implement receiving of notification from GCM in Android.
By the following code I have requested rights in manifest.
<manifest ... >
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<permission
android:name="<PACKAGE_NAME>.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="<PACKAGE_NAME>.permission.C2D_MESSAGE" />
</manifest>
GcmReceiver receives messages from GCM and has to be added to manifest.
<manifest ... >
<application ... >
...
<receiver
android:name="com.google.android.gms.gcm.GcmReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</receiver>
...
</application>
</manifest>
MyGcmListenerService is a service which will receive messages from receiver and subsequently create notification. Service has to be added to manifest, too.
<manifest ... >
<application ... >
...
<service
android:name="<PACKAGE_NAME>.MyGcmListenerService"
android:exported="false">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
...
</application>
</manifest>
Class MyGcmListenerService displays notification to user when he accepts it from GcmReceiver.
public class MyGcmListenerService extends GcmListenerService {
@Override
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("alert");
sendNotification(message);
}
private void sendNotification(String message) {
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
...
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 , notificationBuilder.build());
}
}
Firebase
Firebase doesn’t support sending push notifications and its implementations is not easy. There many tutorials on internet, though, which can help solve this situation by your own server application.
Conslusion
For this particular application is better to use SynergyKit. Firstly, for creating push notification on Firebase platform you need to use product of third party. Secondly, SynergyKit enables moving parts of codes to server and by doing this devices can last longer. Server part can be modified in browser and these changes don’t require updating of application. Both platforms offer simple user login, reading and writing data.