How to get local IP in Flutter Web - flutter

I'm trying to get the local IP address in a Flutter Web app. Searching the internet I came around this package: get_ip 0.4.0 - it states it is working under web.
I have this function:
Future<void> initPlatformState() async {
print("Test");
String ipAddress;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
ipAddress = await GetIp.ipAddress;
} on PlatformException {
ipAddress = 'Failed to get ipAddress.';
} on Exception {
print("Exception");
}
print("Ip: $ipAddress");
}
and I call it in initState of main.dart.
The console just has the output Test, it does not output the IP or Exception.
Has someone already used this package? Would there be an other way for a web app to get the local IP?
(I'm using MacOS)

The get_ip package states that it supports Android/iOS.
So,instead of using the package,you can directly interact with ipify endpoint.
Check out their API documentation for more!
Future<String> getIP() async {
try {
const url = 'https://api.ipify.org';
var response = await http.get(url);
if (response.statusCode == 200) {
print(response.body);
return response.body;
} else {
print(response.body);
return null;
}
} catch (exception) {
print(exception);
return null;
}
}

I'm Using ip_geolocation_api Package for getting an IP address and it is working as expected
String text = '';
GeolocationData geolocationData;
#override
void initState() {
super.initState();
this.getIp();
}
Future<void> getIp() async {
geolocationData = await GeolocationAPI.getData();
if (geolocationData != null) {
setState(() {
text = geolocationData.ip;
print(text);
});
}
}
Now You have IP in the text Variable.

Related

Flutter how can i set Auth token from flutter secure storage to dio header?

After login i setting user token to my user Secure storage. Like :
Future<AuthResponseModel?> login(AuthRequstModel model) async {
try {
Response response = await _dio.post(loginPath, data: model);
if (response.statusCode == 200) {
final AuthResponseModel authResponseModel = AuthResponseModel.fromJson(response.data);
if (authResponseModel.success!) {
await UserSecureStorage.setField("token", authResponseModel.token);
}
return AuthResponseModel.fromJson(response.data);
}
return null;
} catch (e) {
return null;
}
}
User Secure Storage =>
class UserSecureStorage {
static const _storage = FlutterSecureStorage();
static Future setField(String key, value) async {
await _storage.write(key: key, value: value);
}
static Future<String?> getField(key) async {
return await _storage.read(key: key);
}
But problem is when i want to make apiservice and when i want to auth token inside header of dio, I cant access it becouse its a future<String?> function. But i cant use await coz its inside of baseoption. Like :
class ApiService {
final _dio = Dio(BaseOptions(headers: {
'authorization': 'Bearer ${UserSecureStorage.getField("token")}', //I cant access here its only giving instance.
}));
Future<Response?> get(String path) async {
try {
Response response = await _dio.get('${ApiConstants.BASE_URL}$path');
if (response.statusCode == 200) {
return response;
}
return null;
} on DioError catch (e) {
return null;
}
}
What can i do for solve that problem ? I tried use .then(value=>value) after tried get token but didnt work too. Thanks for responses!
I think token is not getting updated because _dio is already intitalized.
Try to request for token when dio request is made like :
class ApiService {
final _dio = Dio();
Future<Response?> get(String path) async {
try {
Response response = await _dio.get('${ApiConstants.BASE_URL}$path', options: Options(headers: {"authorization": "Bearer ${UserSecureStorage.getField("token")}"}));
if (response.statusCode == 200) {
return response;
}
return null;
} on DioError catch (e) {
return null;
}
}
Use options in get method to add headers for a single request or interceptors for all requests.
I think that it is not an issue easily solvable, I would try with two different methods, you can maintain the token in a state manager such as Provider so you don't have to rely on an async function to retrive it, but this of course add in the code the state manager structure that complicates thing a little.
A bit more naive way to solve this could be to include a async initializator in the ApiService class such this
class ApiService {
late final _dio;
Future<void> init() async {
_dio = Dio(BaseOptions(headers: {
'authorization': 'Bearer ${UserSecureStorage.getField("token")}', //I cant access here its only giving instance.
}));}
Future<Response?> get(String path) async {
try {
Response response = await _dio.get('${ApiConstants.BASE_URL}$path');
if (response.statusCode == 200) {
return response;
}
return null;
} on DioError catch (e) {
return null;
}
}
And this introduce us a new issue, we have to call init everytime the class ApiService is instantiated, to solve this you could use the package get_it which grants you the possibility to instatiate only once the class and access it from everywhere in your project.
I hope this will help you solve your problem
your are getting instance because UserSecureStorage.getField("token") is future so you can get token when you put await keyword
so try like this
await UserSecureStorage.getField("token")

facing issue in method channel internet connectivity in unit testing in flutter

I have checked internet connectivity in flutter while calling api in store class like this using 'connectivity' library.
Future<bool> callApi() async {
final isInternet = await Util.checkInternetAndShowDialog(context);
if (isInternet) {
final future = _repository.callApi();
var res = await future;
return true;
}
return false;
}
In Util class network connectivity is been checked like this::
class Util {
static Future<bool> checkInternetAndShowDialog(BuildContext context) async{
var internet = await NetworkConnectivity.rechability();
if (internet == false) {
AlertMessage().showAlertDialog(context, 'error message');
}
return internet;
}
}
In NetworkConnectivity class network connectivity is been checked using Connectivity library.
class NetworkConnectivity {
static Future<bool> rechability() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
return true;
} else if (connectivityResult == ConnectivityResult.wifi) {
return true;
}
return false;
}
}
my test cases code is like below:
test('call api successfully', () async {
when(mockStore.callApi()).thenAnswer((realInvocation) => Future.value());
expect(await store.callApi(), true);
});
so while writing unit testing I am facing error of connectivity and method channel.
connectivity error image
Can any one help please me how I can mock for internet connectivity in unit testing and pass the test in flutter. I shall be thankful for this.

Use StreamSubscription as Future in Dart/Flutter

I want to connect my Flutter app to bluetooth device with flutter_blue library, and return a result (anything) when the connection is ON. But I don't understand how to do.
Here my code :
Future connect(BluetoothDevice device) async {
_btDevice = device;
StreamSubscription<BluetoothDeviceState> subscription;
subscription = device.state.listen((event) async {
if (event != BluetoothDeviceState.connected) {
await device.connect();
} else {
await device.discoverServices().then((value) => _initFeatures(value));
}
})
..onDone(() {
// Cascade
print("onDone");
});
subscription.asFuture();
//subscription.cancel();
}
And when I call this function with
await newDevice.connect(bluetoothDevice).then((value) => print('OK'));
OK is written before the real connection. _initFeatures if well call when the device is connected.
I try to use asFuture from StreamSubscription with onDone, but that change nothing.
Could you help me please ?
UPDATE 12/10
I've worked on another project for few monthes, and when I come back, I can't solve the problem, so I add the full code.
The concept is a class widget calls the connect future in other class and need to receipt the end of work.
Widget
Future<void> _connectDevice() async {
try {
widget.device.connect(widget.btDevice!).then((value) => _initValue());
} catch (e) {
print(e);
}
}
_initValue() is a method to create the rest of the screen
and the Future connect()
Future connect(BluetoothDevice device) async {
_btDevice = device;
StreamSubscription<BluetoothDeviceState> subscription;
subscription = device.state.listen((event) async {
if (event != BluetoothDeviceState.connected) {
await device.connect();
} else {
await device
.discoverServices()
.then((value) => _initFeatures(value))
.then((value) => print("OK"));
}
});
await subscription.asFuture();
await subscription.cancel();
}
What I'd like is the Future finishes when print("OK") is called, in order .then((value) => _initValue()); is called.
The problem is only this end. Maybe it's not the good way to implement this kind of solution.

How to synchronize a call from the asynchronous function in dart

I am working on my first app in Flutter, I have a bit of experience with Java and js, but I never worked with flutter before so sorry if my question will seem ridiculous to you.
The app is the voice assistant chatbot, and it is supposed to perform text to speech on each new message that customer receives, my problem is that since I am using firebase messaging all of the requests that I receive are in the asynchronous call, but I need to synchronize the access to the text to speech service otherwise I run into problem of having one text interrupt another.
This is what my code looks like at the moment:
Firebase messaging:
onMessage: (Map<String, dynamic> message) {
return this.handleBotMessage(appState, message);
},
Method that desides how to handle each particular message:
Future handleBotMessage(
Store<AppState> store,
Map<String, dynamic> dataJson,
) {
#logic that convert the message into json and extracts the message type
if (type == MessageType.CHAT_MESSAGE) {
return handleChatMessage(store, subtype, messageMap);
}
}
The method that handles text messages:
Future<dynamic> handleChatMessage(
Store<AppState> store,
MessageSubtype subtype,
Map<String, dynamic> message,
) {
#Text to speach is build as a singleton and this always returns the same instance
TextToSpeech tts = TextToSpeech();
if (subtype == MessageSubtype.TEXT) {
TextMessage textMessage = TextMessage.fromJson(message);
return tts
.speak(textMessage.text)
.then((result) => store.dispatch(NewBotMessageAction(textMessage)));
} else if (subtype == MessageSubtype.QUICK_REPLY) {
QuickReplyMessage qrMessage = QuickReplyMessage.fromJson(message);
return tts
.speak(qrMessage.text)
.then((result) => store.dispatch(NewQrOptionsAction(qrMessage)));
} else {
throw new Exception('Unexpected message subtype!');
}
}
The method that actually performs the text to speech
Future<dynamic> speak(String text) async {
return flutterTts.speak(text).then((resp) {
ttsRunning = false;
print(resp);
return resp;
}, onError: (obj, st) {
ttsRunning = false;
print(obj);
print(st.toString());
});
}
Text to speech initialization
Future init() async {
await flutterTts.setLanguage("en-US");
var res = await flutterTts.isLanguageAvailable("en-US");
print(res);
return res;
}
https://pub.dev/packages/flutter_tts
Ok, I have found the solution, the issue was as frank06 pointed out with the fact that flutter tts completes the future immediately rather than after the whole phrase was spoken.
So here is my solution, it is not perfect, but it works:
Completer completer;
Future<dynamic> speak(String text) {
print('Started speeking');
print(new DateTime.now().toIso8601String());
if (TextToSpeech.lastRequest == null) {
lastRequest = _executeSpeech(text);
} else {
lastRequest = lastRequest.then((resp) {
return _executeSpeech(text);
});
}
return lastRequest;
}
Future<dynamic> _executeSpeech(String text) {
completer = Completer();
flutterTts.speak(text).then((resp) {
ttsRunning = false;
print(resp);
return resp;
}, onError: (obj, st) {
ttsRunning = false;
print(obj);
print(st.toString());
});
return completer.future;
}
flutterTts.setCompletionHandler(() {
print('Finished speeking');
print(new DateTime.now().toIso8601String());
ttsState = TtsState.stopped;
completer.complete(ttsState);
});
flutterTts.setErrorHandler((msg) {
ttsState = TtsState.stopped;
completer.complete(ttsState);
});
If you don't want new messages interrupting those being spoken, you can queue them up. This way the new messages will wait for the current message to finish. Check out this approach:
Queue of Future in dart

Trouble with WebSockets in Flutter

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.