Signal R in Android
Recently i developed a Android chatting application for the company called zupportdesk. I went through lot of difficulties since there is a very few online resources available for reference to implement signal R in Android, but somehow i figured it out by putting lot of time and effort on it. Now i thought of sharing what i have learned so that it will help some developers someday.
This tutorial will give you instruction on how to implement signal R in Android. Before getting started i expect you to have some knowledge on Android, Android Services and Signal R, therefore this tutorial is not for beginners. Ok lets get started
What is a signal R
SignalR is a new library used to add real-time web functionality to your applications. Signal R uses technology such as
- web sockets
- Event Source,
- forever frame
- long polling
Signal R is capable of selecting the best from those four technology depending on your internet connection and your application stability.
Signal R is used in application such as
- Chatting application
- Stock market application
- Real-time gaming
It is also used in variety of sectors where ever the real-time communication is needed. to learn more about signal R visit signalr.net.
Required Libraries
- gson-2.2.2 – Download
- signalr-client-sdk-android – Download
- signalr-client-sdk – Download
Download these libraries and put it on your libs folder and then add it to your build.gradle as shown below.
1 2 3 |
compile files('libs/gson-2.2.2.jar') compile files('libs/signalr-client-sdk-android.jar') compile files('libs/signalr-client-sdk.jar') |
Also we must ignore some files in the library
1 2 3 |
exclude 'lib/getLibs.ps1' exclude 'lib/getLibs.sh' exclude 'lib/gson-2.2.2.jar' |
You app will work fine with out excluding these files, but when you upload it to the play store your application supported devices will be zero. Therefore its better to exclude the files now itself.
finally your build.gradle file will look some what similar to this
apply plugin: ‘com.android.application’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion "24.0.1" useLibrary 'org.apache.http.legacy' defaultConfig { applicationId "applicationname.desk.ystem" minSdkVersion 15 targetSdkVersion 24 versionCode 5 versionName "1.5.16.11.16" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } packagingOptions { exclude 'META-INF/DEPENDENCIES' exclude 'META-INF/NOTICE' exclude 'META-INF/LICENSE' exclude 'lib/getLibs.ps1' exclude 'lib/getLibs.sh' exclude 'lib/gson-2.2.2.jar' } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' compile files('libs/gson-2.2.2.jar') compile files('libs/signalr-client-sdk-android.jar') compile files('libs/signalr-client-sdk.jar') compile ('org.apache.httpcomponents:httpcore:4.4.1'){ exclude group: 'org.apache.httpcomponents', module: 'httpclient' } } |
These type for application consumes huge amount of data and battery life of the device, therefore it is important to choose the best service that supports your application, I am going to use Android Bind service for this example. Because i want the application to run background task only when the application is open on the device.
To do the real time communication the services need to do three task.
- It should connect to Proxy hub and the keeps the connection continuously open.
- It should subscribe to the hub method , so that it can receive information from hub to the device, whenever the change or a new message is received to the hub.
- It should invoke the hub method when a device need to send messages to the hub
Example for hub method subscription are shown below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Subscription subscription11 = proxy.subscribe("SampleMethos4"); subscription11.addReceivedHandler(new Action<JsonElement[]>(){ public void run(JsonElement[] eventParameters) throws Exception { Log.d("removeTab", String.valueOf(eventParameters[0])); Chatting.TransferSuccess(String.valueOf(eventParameters[0])); } }); Subscription subscription12 = proxy.subscribe("SAmpleMethod3"); subscription12.addReceivedHandler(new Action<JsonElement[]>(){ public void run(JsonElement[] eventParameters) throws Exception { Log.d("inviteCanceled", String.valueOf(eventParameters[0])); Chatting.TransferCancled(String.valueOf(eventParameters[0])); } }); |
Example for invoke Hub methods are shown below
1 2 3 4 5 6 7 8 9 |
public void SampleMethod1(String visitorId, String message, String operatorId, String token, String spinnerId){ String datetime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime()); mHubProxy.invoke("SampleMethod5",visitorId, message, operatorId, false, false, false, token, datetime, spinnerId); } public void SampleMethos2(String companyID, String operatorID, String receiverID, String receivername, String operatorName,String visitorID, String visitorName, String widgetID, String token){ String transferDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime()); mHubProxy.invoke("SampleMethod6", companyID, operatorID, receiverID, receivername, operatorName, visitorID, visitorName, transferDate, null, widgetID, token); } |
Finally You Service should look somewhat similar to this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.util.Log; import com.google.gson.JsonElement; import java.text.SimpleDateFormat; import java.util.Calendar; import microsoft.aspnet.signalr.client.hubs.Subscription; import microsoft.aspnet.signalr.client.Action; import microsoft.aspnet.signalr.client.ErrorCallback; import microsoft.aspnet.signalr.client.LogLevel; import microsoft.aspnet.signalr.client.Logger; import microsoft.aspnet.signalr.client.MessageReceivedHandler; import microsoft.aspnet.signalr.client.hubs.HubConnection; import microsoft.aspnet.signalr.client.hubs.HubProxy; import desk.zupport.chatsystem.Chatting; import desk.zupport.chatsystem.Data.ApplicationEnvironmentURL; import desk.zupport.chatsystem.fragment.ActiveFragment; import desk.zupport.chatsystem.fragment.IncommingFragment; import desk.zupport.chatsystem.fragment.OtherFragment; /** * Created by baman on 8/19/16. */ public class SignalRService extends Service { private HubConnection mHubConnection; private HubProxy mHubProxy; private Handler mHandler; // to display Toast message private final LocalBinder mBinder = new LocalBinder(); public Boolean is_service_connected = false; public String ProfileId; public String profileToken; public String CompanyID; public String DisplayName; private Context context; public ApplicationEnvironmentURL applicationEnvironment; public String environment; public String HubURL; public SignalRService() { mHubConnection = new HubConnection("YOUR CONNECTION NAME"); } @Override public void onCreate() { super.onCreate(); Log.d("service", "Inside oncreate - service"); // context = this.getApplicationContext(); context = getBaseContext(); SharedPreferences prefs = getSharedPreferences("YOUR FILE NAME", MODE_PRIVATE); ProfileId = prefs.getString("ProfileId", "Not defined"); profileToken = prefs.getString("profileToken", "Not defined"); CompanyID = prefs.getString("companyId", "Not defined"); DisplayName = prefs.getString("DisplayName", "Not defined"); mHandler = new Handler(Looper.getMainLooper()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d("service", "service start - service"); int result = super.onStartCommand(intent, flags, startId); startSignalR(); return result; } @Override public void onDestroy() { mHubConnection.stop(); super.onDestroy(); } @Override public boolean onUnbind(Intent intent) { Log.d("Unbounding", "SignalRservice Service unbound"); return super.onUnbind(intent); } @Override public IBinder onBind(Intent intent) { // Return the communication channel to the service. Log.d("service", "onBind - service"); startSignalR(); return (IBinder) mBinder; } /** * Class used for the client Binder. Because we know this service always * runs in the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { public SignalRService getService() { // Return this instance of SignalRService so clients can call public methods return SignalRService.this; } } /** * method for clients (activities) */ private void getIncommingcht(){ Log.d("Inside : ", "getIncommingcht - service - Method"); mHubProxy.invoke("addGroup", ProileId, Copanyid, "true", Token); mHubProxy.invoke("GetChatQueue",ProileId, Token); } public void selectVisitor(String visitor_id, String CompanyID, String DisplayName, String startTime){ String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime()); mHubProxy.invoke("seleVisitr", DisplayName, timeStamp, startTime); } private void startSignalR() { // Create a new console logger Logger logger = new Logger() { @Override public void log(String message, LogLevel level) { Log.d("Log Message : ", message); } }; // Connect to the server HubConnection conn = new HubConnection("Your HUB URL HERE", "", true, logger); // Create the hub proxy HubProxy proxy = conn.createHubProxy("chatHub"); mHubProxy = proxy; Subscription subscription = proxy.subscribe("getResponse"); subscription.addReceivedHandler(new Action<JsonElement[]>(){ public void run(JsonElement[] eventParameters) throws Exception { Log.d("getVisitorResponse-data", String.valueOf(eventParameters[0])); Log.d("getVisitorResponse-time", String.valueOf(eventParameters[1])); IncommingFragment.getVisitorResponse(eventParameters[0]); } }); Subscription subscription1 = proxy.subscribe("recieveChat"); subscription1.addReceivedHandler(new Action<JsonElement[]>(){ public void run(JsonElement[] eventParameters) throws Exception { Log.d("IncomingChat_data", String.valueOf(eventParameters[0])); IncommingFragment.receivedincommingchats(eventParameters[0]); } }); Subscription subscription2 = proxy.subscribe("visitor_mobile"); subscription2.addReceivedHandler(new Action<JsonElement[]>(){ public void run(JsonElement[] eventParameters) throws Exception { Log.d("visitorSelected_mobile", String.valueOf(eventParameters[1])); ActiveFragment.selectedVisitorsList(String.valueOf(eventParameters[1])); } }); /*proxy.subscribe(new Object() { @SuppressWarnings("unused") public void recieveIncomingChat(RecieveIncomingchats recieveIncomingchats) { MainFragment.receivedincommingchats(recieveIncomingchats); Log.d("hit:", "Hit on receive Incoming chats"); } @SuppressWarnings("unused") public void serviceStatus(boolean temp){ Log.d("service_status", "status called"); } });*/ // Subscribe to the error event conn.error(new ErrorCallback() { @Override public void onError(Throwable error) { error.printStackTrace(); } }); // Subscribe to the connected event conn.connected(new Runnable() { @Override public void run() { System.out.println("CONNECTED"); is_service_connected = true; getIncommingcht(); } }); // Subscribe to the closed event conn.closed(new Runnable() { @Override public void run() { System.out.println("DISCONNECTED"); } }); // Start the connection conn.start().done(new Action<Void>() { @Override public void run(Void obj) throws Exception { System.out.println("Done Connecting!"); } }); // Subscribe to the received event conn.received(new MessageReceivedHandler() { @Override public void onMessageReceived(JsonElement json) { System.out.println("RAW received message: " + json.toString()); } }); } } |
In you Activity just call the Service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
private final ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { Log.d("Activity : ", "Inside service connected - Activity "); // We've bound to SignalRService, cast the IBinder and get SignalRService instance SignalRService.LocalBinder binder = (SignalRService.LocalBinder) service; mService = binder.getService(); mBound = true; Log.d("Activity : ", "bound status - " + mBound); } @Override public void onServiceDisconnected(ComponentName arg0) { mService=null; mBound = false; Log.d("Activity : ", "bound disconnected - status - " + mBound); } }; @Override protected void onStop() { super.onStop(); // Unbind from the service if (mBound) { unbindService(mConnection); mBound = false; Log.d("Activity : ", "bound disconnecting - status - " + mBound); } mService.onDestroy(); } |
That’s it. if you do this properly you will have the connection between your signal R hub and your Android device. You can Check the connection information on ADT logs. From now on you just have to invoke and subscribe to hub method to send and receive messages.
Hope this helps. If you have any questions are suggestions, please feel free to ask. Happy Coding 🙂
Nimesh
Great article. Keep it up
sathyabaman
Thank you.
M karmakar
ApplicationEnvironmentURL applicationEnvironment; what is that?