Как использовать сигнализатор в Android
Я пытаюсь интегрировать signalR
в android
приложение, но не повезло. Я просматривал различные ссылки, но ни одна из них не дает правильной информации о реализации.
У меня следующие вопросы.
SignalR
интеграция должна быть сделана внутри Сервиса / Намеренного Сервиса?- Если мы хотим получить ответ через тот же метод вызова, то как его получить?
Я добавил три библиотеки, т.е. signalr android
,signalr client
а также gson
но не в состоянии понять, как работает код, нет доступной документации для понимания кода.
Некоторые из заданных вопросов, но не так много информации
SignalR в Android Studio Невозможно реализовать p2p-чат с помощью SignalR в Android
Если кто-то испытал сигнал для родных приложений, это было бы очень полезно для меня.
Обновить
public class SignalRService extends Service {
private static final String TAG = "Service";
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler; // to display Toast message
private final IBinder mBinder = new LocalBinder();
private SharedPreferences sp;
@Override
public void onCreate() {
super.onCreate();
Utility.showLog(TAG, "Service Created");
sp = getSharedPreferences(Utility.SHARED_PREFS, MODE_PRIVATE);
mHandler = new Handler(Looper.myLooper());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
startSignalR();
return result;
}
@Override
public IBinder onBind(Intent intent) {
startSignalR();
return 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)
*/
public void sendMessage() {
String SERVER_METHOD_SEND = "iAmAvailable";
final String string = new String();
mHubProxy.invoke(new String(), SERVER_METHOD_SEND, sp.getString("user_id", null), sp.getString("pass", null), "TransMedic").done(new Action() {
@Override
public void run(Object o) throws Exception {
Utility.showLog(TAG, o.toString());
}
}).onError(new ErrorCallback() {
@Override
public void onError(Throwable throwable) {
}
});
}
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
String serverUrl = "http://transit.alwaysaware.org/signalr";
mHubConnection = new HubConnection(serverUrl);
String SERVER_HUB_CHAT = "ChatHub";
mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT);
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return;
}
sendMessage();
}
@Override
public void onDestroy() {
mHubConnection.stop();
super.onDestroy();
}
}
5 ответов
ОБНОВЛЕНИЕ 2018:
Если вы используете SignalR.net Core, используйте эту библиотеку, иначе вы получите ошибку при подключении.
СТОРОНА СЕРВЕРА:
Ниже приведен мой пример кода на стороне сервера, вы можете обратить внимание на public void Send(string message)
а также public void SendChatMessage(string to, string message)
,
Серверное приложение: public void SendChatMessage (строка в, строка сообщения)
- Клиентское приложение для Android: mHubProxy.invoke("SendChatMessage", имя-получателя, сообщение);
Серверное приложение: public void Send(строковое сообщение)
- Клиентское приложение для Android: mHubProxy.invoke ("Отправить", сообщение);
namespace SignalRDemo
{
public class ChatHub : Hub
{
private static ConcurrentDictionary<string, string> FromUsers = new ConcurrentDictionary<string, string>(); // <connectionId, userName>
private static ConcurrentDictionary<string, string> ToUsers = new ConcurrentDictionary<string, string>(); // <userName, connectionId>
private string userName = "";
public override Task OnConnected()
{
DoConnect();
Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = "I'm Online" });
return base.OnConnected();
}
public override Task OnDisconnected(bool stopCalled)
{
if (stopCalled) // Client explicitly closed the connection
{
string id = Context.ConnectionId;
FromUsers.TryRemove(id, out userName);
ToUsers.TryRemove(userName, out id);
Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = "I'm Offline" });
}
else // Client timed out
{
// Do nothing here...
// FromUsers.TryGetValue(Context.ConnectionId, out userName);
// Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = "I'm Offline By TimeOut"});
}
return base.OnDisconnected(stopCalled);
}
public override Task OnReconnected()
{
DoConnect();
Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = "I'm Online Again" });
return base.OnReconnected();
}
private void DoConnect()
{
userName = Context.Request.Headers["User-Name"];
if (userName == null || userName.Length == 0)
{
userName = Context.QueryString["User-Name"]; // for javascript clients
}
FromUsers.TryAdd(Context.ConnectionId, userName);
String oldId; // for case: disconnected from Client
ToUsers.TryRemove(userName, out oldId);
ToUsers.TryAdd(userName, Context.ConnectionId);
}
public void Send(string message)
{
// Call the broadcastMessage method to update clients.
string fromUser;
FromUsers.TryGetValue(Context.ConnectionId, out fromUser);
Clients.AllExcept(Context.ConnectionId).broadcastMessage(new ChatMessage() { UserName = fromUser, Message = message });
}
public void SendChatMessage(string to, string message)
{
FromUsers.TryGetValue(Context.ConnectionId, out userName);
string receiver_ConnectionId;
ToUsers.TryGetValue(to, out receiver_ConnectionId);
if (receiver_ConnectionId != null && receiver_ConnectionId.Length > 0)
{
Clients.Client(receiver_ConnectionId).broadcastMessage(new ChatMessage() { UserName = userName, Message = message });
}
}
}
public class ChatMessage
{
public string UserName { get; set; }
public string Message { get; set; }
}
}
СТОРОНА КЛИЕНТА:
Если вы не прочитали мой ответ на следующий вопрос:
Интеграция SignalR в андроид студии
Тогда вот мой рабочий основной код:
public class SignalRService extends Service {
private HubConnection mHubConnection;
private HubProxy mHubProxy;
private Handler mHandler; // to display Toast message
private final IBinder mBinder = new LocalBinder(); // Binder given to clients
public SignalRService() {
}
@Override
public void onCreate() {
super.onCreate();
mHandler = new Handler(Looper.getMainLooper());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = super.onStartCommand(intent, flags, startId);
startSignalR();
return result;
}
@Override
public void onDestroy() {
mHubConnection.stop();
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
// Return the communication channel to the service.
startSignalR();
return 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)
*/
public void sendMessage(String message) {
String SERVER_METHOD_SEND = "Send";
mHubProxy.invoke(SERVER_METHOD_SEND, message);
}
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
Credentials credentials = new Credentials() {
@Override
public void prepareRequest(Request request) {
request.addHeader("User-Name", "BNK");
}
};
String serverUrl = "http://192.168.1.100";
mHubConnection = new HubConnection(serverUrl);
mHubConnection.setCredentials(credentials);
String SERVER_HUB_CHAT = "ChatHub";
mHubProxy = mHubConnection.createHubProxy(SERVER_HUB_CHAT);
ClientTransport clientTransport = new ServerSentEventsTransport(mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return;
}
String HELLO_MSG = "Hello from Android!";
sendMessage(HELLO_MSG);
String CLIENT_METHOD_BROADAST_MESSAGE = "broadcastMessage";
mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
new SubscriptionHandler1<CustomMessage>() {
@Override
public void run(final CustomMessage msg) {
final String finalMsg = msg.UserName + " says " + msg.Message;
// display Toast message
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), finalMsg, Toast.LENGTH_SHORT).show();
}
});
}
}
, CustomMessage.class);
}
}
Деятельность:
public class MainActivity extends AppCompatActivity {
private final Context mContext = this;
private SignalRService mService;
private boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setClass(mContext, SignalRService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
super.onStop();
}
public void sendMessage(View view) {
if (mBound) {
// Call a method from the SignalRService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
EditText editText = (EditText) findViewById(R.id.edit_message);
if (editText != null && editText.getText().length() > 0) {
String message = editText.getText().toString();
mService.sendMessage(message);
}
}
}
/**
* Defines callbacks for service binding, passed to bindService()
*/
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to SignalRService, cast the IBinder and get SignalRService instance
SignalRService.LocalBinder binder = (SignalRService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
CustomMessage Class:
public class CustomMessage {
public String UserName;
public String Message;
}
Вы также можете увидеть мой пример клиентского проекта по этой ссылке на GitHub.
ОБНОВЛЕНИЕ ДЛЯ ОТВЕТА ОТ ПРИГЛАШЕНИЯ:
Я только что добавил новые примеры методов:
Сторона сервера:
public string iAmAvailable(string username, string password, string message)
{
return "BNK Response for testing Android INVOKE";
}
Сторона клиента:
mHubProxy.invoke(String.class, "iAmAvailable", "username", "password", "TransMedic").done(new Action<String>() {
@Override
public void run(String s) throws Exception {
Log.w("SimpleSignalR", s);
}
}).onError(new ErrorCallback() {
@Override
public void onError(Throwable throwable) {
Log.e("SimpleSignalR", throwable.toString());
}
});
И вот скриншот:
Эта работа для меня: полный исходный код Android (клиент) и сервер GitHub
Слайд сервера Если один аргумент должен использовать этот интерфейс SubscriptionHandler1, если два аргумента должны использовать этот интерфейс SubscriptionHandler2,...
Пример для двух аргументов, таких как:
Слайд сервера:
using Microsoft.AspNet.SignalR;
namespace SignalRChat
{
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Two argument must use this interfaceSubscriptionHandler2 .
Clients.All.broadcastMessage(name, message);
}
}
}
Клиентский слайд:
mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
new SubscriptionHandler2<String, String>() {
@Override
public void run(final String name,final String msg) {
final String finalMsg = msg.toString();
// display Toast message
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), finalMsg, Toast.LENGTH_SHORT).show();
}
});
}
}
, String.class,String.class);
Для перехвата всех сообщений можно использовать это:
mHubConnection.received(new MessageReceivedHandler() {
@Override
public void onMessageReceived(final JsonElement json) {
Log.e("onMessageReceived ", json.toString());
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), json.toString(), Toast.LENGTH_SHORT).show();
}
});
}
});
Команда SignalR недавно выпустила Java-клиент для ASP.NET Core SignalR. Вот ссылка на документацию по началу работы https://docs.microsoft.com/en-us/aspnet/core/signalr/java-client?view=aspnetcore-2.2
выполните это руководство шаг за шагом:https://docs.microsoft.com/en-us/aspnet/core/tutorials/signalr?tabs=visual-studio-mac&amp;view=aspnetcore-5.0
1. Согласно приведенному выше руководству опубликуйте свой чат-сервер на любимом хосте.
2. добавьте эту зависимость в свой образец Android:
implementation 'com.microsoft.signalr:signalr:3.0.0'
3. добавьте эти разрешения в manifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
4. ниже код MainActivity.class:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HubConnection hubConnection =
HubConnectionBuilder.create("https://your_chat_server_url/chatHub").build();
TextView textView = (TextView)findViewById(R.id.tvMain);
ListView listView = (ListView)findViewById(R.id.lvMessages);
Button sendButton = (Button)findViewById(R.id.bSend);
EditText editText = (EditText)findViewById(R.id.etMessageText);
List<String> messageList = new ArrayList<String>();
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(MainActivity.this,
android.R.layout.simple_list_item_1, messageList);
listView.setAdapter(arrayAdapter);
hubConnection.on("ReceiveMessage", (user, message)-> {
runOnUiThread(new Runnable() {
@Override
public void run() {
arrayAdapter.add( user + " : " + message);
arrayAdapter.notifyDataSetChanged();
}
});
}, String.class,String.class);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String message = editText.getText().toString();
String user = "SAEID";
editText.setText("");
try {
hubConnection.send("SendMessage", user,message);
} catch (Exception e) {
e.printStackTrace();
}
}
});
new HubConnectionTask().execute(hubConnection);
}
static class HubConnectionTask extends AsyncTask<HubConnection, Void, Void>{
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Void doInBackground(HubConnection... hubConnections) {
HubConnection hubConnection = hubConnections[0];
hubConnection.start().blockingAwait();
return null;
}
}
}
5. ниже показан код activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tvMain" />
<ListView
android:layout_height="0dp"
android:layout_weight="1"
android:layout_width="fill_parent"
android:id="@+id/lvMessages"
android:transcriptMode="alwaysScroll">
</ListView>
<EditText
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/etMessageText"
android:hint="Enter Message" />
<Button
android:text="Send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/bSend" />
</LinearLayout>
Для тех, кто реализует клиент signalR в Android и данный ответ здесь не помогает в получении сообщений, можете проверить этот ответ Рейнев.
Ответ реализует другой метод connection.received(), который в моем случае может получать ответные сообщения от сервера.