I am working on a flutter project which uses Laravel echo with socket.io for chats in the backend. it was quite easy to implement in the web version with the Laravel echo package, but I am clueless on what to use for Flutter to connect and listen for events. Please I need Help!
You can follow this blog.
Here are two simple methods:
sendSingleChatMessage(ChatMessageModel chatMessageModel, User toChatUser) {
print('Sending Message to: ${toChatUser.name}, ID: ${toChatUser.id}');
if (null == _socket) {
print("Socket is Null, Cannot send message");
return;
}
_socket.emit("single_chat_message", [chatMessageModel.toJson()]);
}
setOnChatMessageReceivedListener(Function onChatMessageReceived) {
_socket.on(ON_MESSAGE_RECEIVED, (data) {
print("Received $data");
onChatMessageReceived(data);
});
}
Edit:
There is another package to use in here.
// Create echo instance
Echo echo = new Echo({
'broadcaster': 'socket.io',
'client': IO.io,
});
// Listening public channel
echo.channel('public-channel').listen('PublicEvent', (e) {
print(e);
});
// Listening private channel
// Needs auth. See details how to authorize channel below in guides
echo.private('private-channel').listen('PrivateEvent', (e) {
print(e);
});
// Listening presence channel
// Needs auth. See details how to authorize channel below in guides
echo.join('presence-channel')
.here((users) {
print(users);
}).joining((user) {
print(user);
}).leaving((user) {
print(user);
}).listen('PresenceEvent', (e) {
print(e);
});
// Accessing socket instance
echo.socket.on('connect', (_) => print('connected'));
echo.socket.on('disconnect', (_) => print('disconnected'));
Related
The WebSocket server I use needs to receive a message after the connection.
The only way seems to use WebSocket.connect instead of WebSocketChannel.connect (https://github.com/dart-lang/web_socket_channel/issues/209):
import 'package:web_socket_channel/io.dart';
// ...
IOWebSocketChannel? _channel;
// ...
WebSocket.connect("ws://...").then((ws) {
this._channel = IOWebSocketChannel(ws);
_channel!.sink.add(msg);
}
But this is not supported by web. How is it possible to do that with both mobile and web support ?
WebSocket.connect(socketUrl).then((value) {
_channel = IOWebSocketChannel(value);
_channel?.stream.listen(onData,
onError: onError, onDone: onDone, cancelOnError: true);
debugPrint(
"webSocket——readyState:${_channel?.innerWebSocket?.readyState}");
if (_channel?.innerWebSocket?.readyState == 1) {
} else {}
}).timeout(const Duration(seconds: 10));
I'm facing a problem with Flutter Web Firebase Phone Auth Verification. In debug it is working well and showing me the reCaptcha. But when I host it through GitHub pages in release mode, it shows an error "captcha-check-failed". Even the capcha isn't showing in release mode.
The signInWithPhoneNumber function:
Future<void> loginWithPhoneRequestOTPWeb(
WidgetRef ref,
GlobalKey<FormState> formKey,
String phoneNumber,
) async {
try {
EasyLoading.show();
await FirebaseAuth.instance
.signInWithPhoneNumber(
phoneNumber,
RecaptchaVerifier(
container: 'recaptcha',
size: RecaptchaVerifierSize.compact,
theme: RecaptchaVerifierTheme.dark,
onError: (e) {
print(e);
EasyLoading.showError(e.message!);
return;
},
onExpired: () {
print('Expired');
EasyLoading.showError('Session Expired');
return;
},
onSuccess: () {
EasyLoading.dismiss();
print('Captcha Success');
},
),
)
.then((ConfirmationResult result) {
// update the verificationphone provider
ref.read(sendOtpProvider(formKey).state).update((_) => true);
ref.read(confirmationResultProvider(formKey).state).update((_) => result);
EasyLoading.showSuccess(t!.otpSentSuccessfully);
});
} on FirebaseAuthException catch (e) {
if (e.code == 'invalid-phone-number') {
print('The provided phone number is not valid.');
EasyLoading.showError('The provided phone number is not valid.');
} else if (e.code == 'too-many-requests') {
print(
'You have exceeded the number of attempts allowed for this operation.');
EasyLoading.showError(
'You have exceeded the number of attempts allowed for this operation.');
} else {
print(e.code.toString());
EasyLoading.showError(e.code.toString());
}
} catch (e) {
print(e.toString());
EasyLoading.showError(e.toString());
}
}
I've tried without the RecaptchaVerifier as it is optional parameter.
Error Screenshot:
If I've missed anything please let me know. Thank You :)
Okay, I've figure out my problem. In the firebase authentication section, there is an "Authorized domains" section. Here I've to add my domains. But firebase only takes .com domains. As a result, I used firebase hosting and it is working fine
1. OBJECTIVE
I would like the connection between my custom WebSocket server (API) and my Flutter app, to be re-established automatically when encountering network issues or when the WebSocket server encounter issues.
Use case 1: the wifi stops and suddenly comes back.
Use case 2: the API is not started and restarts suddenly.
Constraint: I use Riverpod as a state management library (and I want to keep it :)).
I emphasize about the state management library because I create the WS connection in a StreamProvider (cf. Riverpod).
2. INITIAL SETUP WITHOUT AUTOMATIC RECONNECT
I created a StreamProvider as shown below:
final hostProvider =
StreamProvider.autoDispose.family<Host, String>((ref, ip) async* {
//SOCKET OPEN
final channel = IOWebSocketChannel.connect('ws://$ip:$port/v1/path');
ref.onDispose(() {
// SOCKET CLOSE
return channel.sink.close();
});
await for (final json in channel.stream) {
final jsonStr = jsonDecode(json as String);
yield Host.fromJson(jsonStr as Map<String, dynamic>);
}
});
And I created a widget to consume the data:
useProvider(hostProvider(ip)).when(
data: (data) => show the result
loading: () => show progress bar
error: (error, _) => show error
);
This piece of code works great. However, there is no automatic reconnect mechanism.
3. AUTOMATIC RECONNECT ATTEMPTS
I called a function connectWs in a try/catch whenever exceptions are caught:
final hostProvider =
StreamProvider.autoDispose.family<Host, String>((ref, ip) async* {
// Open the connection
connectWs('ws://$ip:$port/v1/path').then((value) async* {
final channel = IOWebSocketChannel(value);
ref.onDispose(() {
return channel.sink.close();
});
await for (final json in channel.stream) {
final jsonStr = jsonDecode(json as String);
yield Host.fromJson(jsonStr as Map<String, dynamic>);
}
});
});
Future<WebSocket> connectWs(String path) async {
try {
return await WebSocket.connect(path);
} catch (e) {
print("Error! " + e.toString());
await Future.delayed(Duration(milliseconds: 2000));
return await connectWs(path);
}
}
I created a connectProvider provider, as shown here below, I 'watched' in hostProvider in order to create a channel. Whenever there is an exception, I use the refresh function from the Riverpod library to recreate the channel:
// used in hostProvider
ref.container.refresh(connectProvider(ip))
final connectProvider =
Provider.family<Host, String>((ref, ip) {
//SOCKET OPEN
return IOWebSocketChannel.connect('ws://$ip:$port/v1/path');
});
Thanks in advance for your help.
Thanks, #Dewey.
In the end, I found a workaround that works for my use case:
My providers: channelProvider & streamProvider
static final channelProvider = Provider.autoDispose
.family<IOWebSocketChannel, HttpParam>((ref, httpParam) {
log.i('channelProvider | Metrics - $httpParam');
return IOWebSocketChannel.connect(
'ws://${httpParam.ip}:$port/v1/${httpParam.path}');
});
static final streamProvider =
StreamProvider.autoDispose.family<dynamic, HttpParam>((ref, httpParam) {
log.i('streamProvider | Metrics - $httpParam');
log.i('streamProvider | Metrics - socket ${httpParam.path} opened');
var bStream = ref
.watch(channelProvider(httpParam))
.stream
.asBroadcastStream(onCancel: (sub) => sub.cancel());
var isSubControlError = false;
final sub = bStream.listen(
(data) {
ref
.watch(channelProvider(httpParam))
.sink
?.add('> sink add ${httpParam.path}');
},
onError: (_, stack) => null,
onDone: () async {
isSubControlError = true;
await Future.delayed(Duration(seconds: 10));
ref.container.refresh(channelProvider(httpParam));
},
);
ref.onDispose(() {
log.i('streamProvider | Metrics - socket ${httpParam.path} closed');
sub.cancel();
if (isSubControlError == false)
ref.watch(channelProvider(httpParam)).sink?.close(1001);
bStream = null;
});
return bStream;
});
I consume streamProvider that way in my widget:
return useProvider(MetricsWsRepository.streamProvider(HttpParam(
ip: ip,
path: 'dummy-path',
))).when(
data: (data) => deserialize & doSomething1,
loading:() => doSomething2,
error: (_, stack) => doSomething3
)
I'm a bit of a beginner with riverpod but it seems to me you want to use a higher-level redux/bloc style flow to recreate the provider each time it fails ...
This higher level bloc creates the provider when the connection succeeds, and when the connection fails, you dispatch an event to the bloc that tells it to reconnect and recreate the provider ...
That's my thought, but again, I'm a beginner with this package.
I am having some trouble implementing WebSockets in my flutter application.
Here is code my code:
void connectToWebSocket() {
print("trying to connect to websocket");
final Future futureChannel = establishConnection();
futureChannel.then((future) {
print("Connection established, registering interest now...");
channel = future;
webSocketConnected = true;
channel.sink.add({
"action": "saveConnection",
"UserName": "rakshak#gmail.com",
"DeviceId": "1d0032000947363339343638"
});
}).catchError((error) {
channel = null;
webSocketConnected = false;
webSocketConnectionError = error.toString();
print("Connection failed \n $webSocketConnectionError");
});
}
Future<IOWebSocketChannel> establishConnection() async {
final IOWebSocketChannel channel = IOWebSocketChannel.connect(
'wss://1j839fy6t3.execute-api.us-east-1.amazonaws.com/Dev');
return channel;
}
Nothing seems to happen when this code runs. I can see the print messages saying "trying to connect to WebSocket" and "Connection established, registering interest now..." on the console.
The WebSocket is implemented using AWS API Gateway and I can see in the logs that the Flutter app has not connected to the WebSocket.
I have tested the WebSocket using wscat command-line tool and I know that it works.
I am not seeing any error in the console.
Let me know if you would like to see any more of my code.
Turns out you channel.sink.add accepts a string and not a Map.
Replace
channel.sink.add({
"action": "saveConnection",
"UserName": "rakshak#gmail.com",
"DeviceId": "1d0032000947363339343638"
});
With
channel.sink.add('{
"action": "saveConnection",
"UserName": "rakshak#gmail.com",
"DeviceId": "1d0032000947363339343638"
}');
and it should work.
I don't understand what you want. But If you want websocket, you can refer below one.
Add Dart Pub
adhara_socket_io
Add class
class SignalServer {
static SignalServer _instatnce;
factory SignalServer() => _instatnce ?? new SignalServer._();
SignalServer._();
SocketIO socketIO;
int State = 0;
void ConnectServer() async {
this.socketIO = await SocketIOManager().createInstance("http://192.168.50.65:8081");
socketIO.onConnect((data) {
print("Signal server connected");
State = 1;
});
socketIO.onDisconnect((_) {
print("Signal Disconnected");
State = 0;
});
socketIO.connect();
}
}
For Instance(main.dart)
static SignalServer signalServer;
....
signalServer = new SignalServer();
signalServer.ConnectServer();
For use
In any widget
void initState() {
super.initState();
setSocketEvent();
}
void setSocketEvent() async{
await MyApp.signalServer.socketIO.on("room-ready", (data) {
//enter your code
});
await MyApp.signalServer.socketIO.on("on-message", (data) {
//enter your code
});
...
}
I hope it will help you.
I am running demo code of Skype web sdk for the audio service in my IONIC App.
var conversation = application.conversationsManager.getConversation('tel:+XXXX');
conversation.selfParticipant.audio.state.when('Connected', function () {
console.log('Connected to audio call');
});
conversation.state.changed(function (newValue, reason, oldValue) {
console.log('Conversation state changed from', oldValue, 'to', newValue);
});
conversation.participants.added(function (participant) {
console.log('Participant:', participant.displayName(), 'has been added to the conversation');
});
conversation.audioService.start().then(function() {
console.log('The call has been started successfully');
}, function (error) {
console.log('An error occured starting the call', error);
});
When I run this code, I am getting error, Plugin not found. There's no description about what plugin they want.