Microsoft has just released a Java SignalR SDK which allows Java and Android clients to access ASP.NET SignalR back ends. The library is open source, and currently it is up to you to build the .jar packages yourself. For your convenience I’ve uploaded my built .jar files. Given that this library as of yet is still fairly undocumented, and I spent quite some time on getting it up and running, I figured I’d provide a short introduction tutorial here. I found the C# SignalR client documentation to be the most useful while figuring out the API as the classes and methods overall seem to correspond. The tests in the GitHub repository are another useful resource. I’ll mainly be focusing on the specific differences in the Java library, and refer you to the original documentation for more elaborate information.
We will create a simple Hub supporting bidirectional communication. A quick and easy way to get a C# back end up and running for the purpose of this tutorial is to self-host a SignalR server in a simple console or WPF application. The following C# code shows a simple hub with one method which can be called by the Java client, SendMessage.
public class MessageHub : Hub { public static event Action<string, string> MessageReceived = delegate { }; public void SendMessage( string name, string message ) { MessageReceived( name, message ); } }
I added a static event handler which can be consumed by the console or WPF front end to display the received message. SendMessage is called from a different thread, so in case you want to update the UI, don’t forget to use a dispatcher!
MessageHub.MessageReceived += ( name, message ) => _dispatcher.Invoke( () => { MessageBox.Content = String.Format( "{0} said {1}", name, message ); } );
Onwards to the client side code! To set up a Java project which can use the SignalR client API, add the ‘signalr-client-sdk.jar’ and ‘gson-2.2.2.jar’ to the project build path. For Android projects the references need to be added differently. Drag the two jars, and the additional ‘signalr-client-sdk-android.jar’ to the libs folder in Eclipse. By doing so they will automatically be added as Android libraries.
As mentioned before, the SignalR Java client follows the same structure as the C# client API, thus setting up a connection is quite similar. However, for Android applications an additional platform component needs to be loaded as shown below; also don’t forget to add internet permission to your manifest file, or you will receive a SocketException when trying to connect.
Platform.loadPlatformComponent( new AndroidPlatformComponent() ); // Change to the IP address and matching port of your SignalR server. String host = "http://192.168.0.xxx:8080"; HubConnection connection = new HubConnection( host ); HubProxy hub = connection.createHubProxy( "MessageHub" );
This simply configures the connection. Establishing the actual connection is somewhat different than the C# documentation due to limitations of Java. To mimic language support for async in C#, the SignalRFuture class is introduced. Asynchronous operations return an instance of this class, without actually performing any real work yet. What follows is example code of how to start the connection synchronously by calling get() on the SignalRFuture. Don’t forget to cleanly stop() the connection when shutting down the application.
SignalRFuture<Void> awaitConnection = connection.start(); try { awaitConnection.get(); } catch (InterruptedException e) { // Handle ... } catch (ExecutionException e) { // Handle ... }
In case your server is up and running, you should now be ready to start listening to and submitting messages. Again, listening to events in C# is more straightforward since it supports lambdas as the C# client API documentation demonstrates.
stockTickerHubProxy.On<Stock>( "UpdateStockPrice", stock => Console.WriteLine( "Stock update for {0} new price {1}", stock.Symbol, stock.Price) );
Doing something similar in Java requires elaborate inline anonymous classes, or the creation of a handler class per event you want to listen to. Suppose the server would send a message “context.Clients.All.UpdateStatus( “Online” );”, handling this the ‘C# way’ would like as follows:
hub.on( "UpdateStatus", new SubscriptionHandler<String>() { @Override public void run( String status ) { // Since we are updating the UI, // we need to use a handler of the UI thread. final String fStatus = status; handler.post( new Runnable() { @Override public void run() { statusField.setText( fStatus ); } } ); } } , String.class );
Therefore, Microsoft has seemingly added a method not available in the C# API to the Java client. Calling hub.subscribe( listener ) where listener is an object implementing corresponding methods for every available incoming event is a much more straightforward way to listen to messages. Under the covers this uses reflection to hook everything up correctly. These methods need to be public!
hub.subscribe( this ); ... public void UpdateStatus( String status ) { final String fStatus = status; handler.post(new Runnable(){ @Override public void run() { statusField.setText( fStatus ); }}); }
More complex types work as well, as long as it is supported by JSON. I don’t know the specifics, but this will be dependent on the SignalR server and the gson library used by the SignalR Java client. The following code prepares the client to call a new method on the server which you can add to the MessageHub: “public void SendCustomType( CustomType object ) { … }“.
// A simple C# class which can be sent over SignalR. public class CustomType { public string Name; public int Id; }
// The same type as defined in Java. public class CustomType { public String Name; public int Id; }
Finally, calling the earlier SendMessage() and the newly added SendCustomType() can be done as follows. As you can see, remote method invocation again returns a SignalRFuture, and a subsequent get() is needed.
try { hub.invoke( "SendMessage", "Client", "Hello world!" ).get(); hub.invoke( "SendCustomType", new CustomType() {{ Name = "Universe"; Id = 42; }} ).get(); } catch (InterruptedException e) { // Handle ... } catch (ExecutionException e) { // Handle ... }
Similarly, you can simply pass custom objects from the server to the client by adding the custom type as a method parameter: “public void SomeMethod( CustomType bleh ) { … }“
Nice write-up, thank you for the tutorial.
can you provide the source code for this tutorial?
kinda confuse how to use this signalR library..
I’ll need more information than that to know where you are stuck … try posting on Stack Overflow (http://stackoverflow.com/), and posting the url here.
Thanks for the great tutorial. I m getting following Console message, but event is not firing
Verbose – serverSentEvents – Found new data:data: {}
Verbose – serverSentEvents – Trigger onData: {}
Verbose – HubConnection – Received data:
I had tried two ways
Option1
hub.on( “testMessage”, new SubscriptionHandler1() {
@Override
public void run(CustomMessage msg) {
//semaphore.release();
Log.d(“result := “, msg.text);
Toast.makeText(MainActivity.this, msg.text, Toast.LENGTH_LONG).show();
}
}, CustomMessage.class);
Option2
hub.subscribe(“testMessage”);
Handler handler = new Handler();
public void addMessage( CustomMessage msg ) {
final String fStatus = msg.text;
handler.post(new Runnable(){
@Override
public void run() {
Toast.makeText(MainActivity.this, fStatus, Toast.LENGTH_LONG).show();
}});
}
Try posting this with proper formatting on Stack Overflow instead.
I have added the question in Stack overflow. http://stackoverflow.com/questions/25286262/signalr-hub-on-method-is-not-firing-in-android
How do I use Java reflection with hub.subscribe(“MessageFromServer”), cause I am struggling to let my android client get triggered by a message send from the server to client.
What do you mean “how do I use Java reflection”? As I stated, reflection is used under the covers by the Java SignalR SDK. You do not need to implement this yourself when using `hub.subscribe`. However you seem to be confusing `hub.on` with `hub.subscribe`. `hub.on` accepts a method name as you seemingly suggest to be “MessageFromServer”. `hub.subscribe` as I described in this post accepts an object which will listen to incoming messages. Messages are automatically coupled to public methods of the object.
Hi I am trying to create chat in android. using your blog. can you tell me what are parameters in hub.invoke method and how to get message in details
As mentioned before, the SignalR Java client follows the same structure as the C# client API (http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-net-client), thus setting up a connection is quite similar.
You can use that documentation.
i am unable to do connect Signal R with Samsung device can u please tell me Solution while with other device its working fine
i am getting negotiation exception
@steven we are some little bit confused by seeing all .net & Android code here. If you have any working android sample can you please share for me.
hi Steven,
I have been trying to get the java client working for the past week, can’t get past the NegotiatonException. I have posted a question over at stackoverflow, can you help me with this?
http://stackoverflow.com/questions/27365362/signalr-java-client-test-integration-android-invalidhttpstatuscodeexception
P.S. the question is for the client-tests that ship with the git repo itself, I have also tried the method described here (start from scratch), same issue. Below is the pastebin from your code (the connection bit):
D/javaclient(27057): java.util.concurrent.ExecutionException: microsoft.aspnet.signalr.client.transport.NegotiationException: There was a problem in the negotiation with the server
Adding to my answer in case someone else runs into it. It was a crappy mistake on my part, jumped into java client without understanding signalr properly! The Hub class on the server and the Hub proxy name has to be the same. So on the server side the class:
public class MessageHub : Hub
And on the client side
HubProxy hub = connection.createHubProxy( “MessageHub” );
And voila! Thanks for the blog.
Could you help me ~
How to Get a Value by public SignalRFuture invoke(final Class resultClass, final String method, Object… args)
——————————————————
my code as below:
Class resultClass = null;
SignalRFuture str = hub.invoke(resultClass,
“HelloWorld2”, “123”);
str.done(new Action() {
@Override
public void run(String arg0) throws Exception {
Log.i(“0.03”, “arg0=” + arg0);// i can’t receive the result
}
}).onError(new ErrorCallback() {
@Override
public void onError(Throwable error) {
Log.i(“0.03”, “error=” + error.toString());
}
});
——————————————————
by other way, as below:
hub.on(“receiveHelloWorldReturn”,
new SubscriptionHandler1() {
@Override
public void run(String msg) {
Log.i(“0.03”, “Result” + msg); // i can receive the result
}
}, String.class);
hub.invoke(“HelloWorldReturn”);
please help me, how to receive the return value by
How to Get a Value by public SignalRFuture invoke(final Class resultClass, final String method, Object… args)
How you create the jars ? i have tried to recompile with Android Studio the latest sources , using GSON 2.3, but with these jars and GSON 2.3 i get the error “could not find class microsoft.aspnet.signalr.client.transport.websocket transport” in logcat while creating the HubProxy
I also experienced some troubles building the jars, but unfortunately do not remember the specifics. If you manage to build them it might be worthwhile sharing them.
Hi, how you generate signalr-client-sdk-android.jar ? i’ve downloaded source code from github, import the project in AndroidStudio and build the project. The result is only aar file for signalr-client-sdk-android module.
Thank you
I also experienced some troubles building the jars, but unfortunately do not remember the specifics. If you manage to build them it might be worthwhile sharing them.
This is late, but you have to use the aar (import it as a new module, File -> New -> New Module, select at the bottom the option for “Import .JAR or .AAR Package”) and the jar. Add the .jar (client-sdk, NOT the one for Android, that will be the .AAR) to your /libs folder, and then be sure to right-click the jar in Android Studio and select the “Add as library…” option. Finally, add in your build.gradle the following lines:
compile project(‘:signalr-client-sdk-android-release’)
compile files(‘libs/signalr-client-sdk.jar’) [this may be added automatically with the above “Add as library…” step]
This will get you to building, at least.
great tuttorial thenks however i have an issue with hub.invoke( “Send”, “Android”,”hie”).get(); im getting a java.lang.null pointer exeption even though my andorid client has succesfully connected to the signalr Server.. i know this because onconnected server method fires
Try debugging.
tutorial based on another failed microsoft open source tale! who care this project? last 7 months there is no contributor, 32 issues collected but no one closed them.
Very nice I followed this tutorial..,works great .,but only on emulator..
But in device error is install failed CPU abi incompatible.,anye can help me out,.
My device is 4.4.2 KitKat.., cheers thanks
Hi, I got the java client working, received message is working but I cannot send the message. My code looks like
globalVariable.getmProxy().invoke(“SendToOperators”, “21”, “test message”).done(new Action() {
@Override
public void run(Void obj) throws Exception {
System.out.println(“SENT!”);
}
}).onError(new ErrorCallback() {
@Override
public void onError(Throwable throwable) {
System.out.println(“ERROR!”);
}
});
I tried with get() too. Like..
globalVariable.getmProxy().invoke(“SendToOperators”, “21”, “test message”).get();
It throws exception…
11-22 01:30:16.202 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Expected EOF at line 1 column 10
11-22 01:30:16.202 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at com.google.gson.JsonParser.parse(JsonParser.java:65)
11-22 01:30:16.202 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at com.google.gson.JsonParser.parse(JsonParser.java:45)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at microsoft.aspnet.signalr.client.transport.TransportHelper.processReceivedData(TransportHelper.java:41)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at microsoft.aspnet.signalr.client.Connection.processReceivedData(Connection.java:733)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at microsoft.aspnet.signalr.client.Connection.access$0(Connection.java:728)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at microsoft.aspnet.signalr.client.Connection$1.onData(Connection.java:302)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at microsoft.aspnet.signalr.client.transport.HttpClientTransport$2.onResponse(HttpClientTransport.java:122)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at microsoft.aspnet.signalr.client.http.java.NetworkRunnable.run(NetworkRunnable.java:82)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at java.lang.Thread.run(Thread.java:864)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ Caused by: com.google.gson.stream.MalformedJsonException: Expected EOF at line 1 column 10
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1310)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at com.google.gson.stream.JsonReader.peek(JsonReader.java:390)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ at com.google.gson.JsonParser.parse(JsonParser.java:60)
11-22 01:30:16.212 26464-27292/com.eb5.uvexa.uvexadriver W/System.err﹕ … 8 more
I have a working dot net client so I can say that the asp.net code is fine.
I will appreciate your help.
Thanks,
Anup
Facing a huge issue here. I can’t seem to set this up in my project. I followed every step. Here’s my Stack overflow question: http://stackoverflow.com/questions/35264835/setting-up-signal-r-in-android-crash-issue
Hello everyone, I just need a quick response plus help on how to send a message to specific client as a client from java, for instance I am connected c# back end and I have connected to the hub now I want to instruct the hub in java that, the message I am sending you is to send to a specific client.
How to do it ???