Hello I want to achieve Socket IO in flutter, for that I am using the below example but I cannot see the data which I'm emitting to that particular channel, I am using with both emulator and physical device but the word "TEST" which I'm emitting to chat channel, is not printing on console please help me out.
Example:
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:socket_flutter_plugin/socket_flutter_plugin.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
#override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
try {
SocketFlutterPlugin myIO = new SocketFlutterPlugin();
myIO.socket("http://10.2.2.22:9006");
myIO.connect();
String jsonData =
'{"content":"test"}';
myIO.emit("chat",jsonData);
myIO.on("chat",(data){
debugPrint(data.toString());
});
} on PlatformException {
_platformVersion = 'Failed to get platform version.';
}
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: new Center(
child: new Text('Running on: $_platformVersion\n'),
),
),
);
}
}
Output ::
Launching lib\main.dart on Android SDK built for x86 in debug mode...
Built build\app\outputs\apk\debug\app-debug.apk.
D/SocketIO (18242): Socket initialised
D/SocketIO (18242): Connected
D/SocketIO (18242): Pushing {"content":"test"} on topic chat
D/SocketIO (18242): registering to chat topic
D/NetworkSecurityConfig(18242): No Network Security Config specified, using platform default
D/ (18242): HostConnection::get() New Host Connection established 0x9fc9d980, tid 18264
D/EGL_emulation(18242): eglMakeCurrent: 0x9c1f32e0: ver 2 0 (tinfo 0x9fc83550)
Using this package flutter_socket_io, I was able to connect to a Socket IO server.
import 'package:flutter_socket_io/flutter_socket_io.dart';
import 'package:flutter_socket_io/socket_io_manager.dart';
...
class _MyAppState extends State<MyApp> {
SocketIO socket;
...
void _onInitSocketIO() {
socket = SocketIOManager().createSocketIO("http://10.2.2.22:9006", "/", query: "", socketStatusCallback: _onSocketStatus);
socket.init();
socket.connect();
}
void _onSocketStatus(dynamic data) {
// If socket connects successfully
if (data == "connect") {
// Send message to server on the 'chat' event.
String jsonData = '{"content":"test"}';
socket.sendMessage('chat', jsonData);
// Subscribe to the 'chat' event.
socket.subscribe("chat", _onReceiveChatEvent);
}
}
void _onReceiveChatEvent(dynamic data) {
debugPrint(data);
}
}
I'd say that you are emiting before listening, so you can't hear what you are emiting (as you are not listening)...
Try inversing the sequence of emit and on like so
myIO.on("chat",(data){
debugPrint(data.toString());
});
myIO.emit("chat",jsonData);
and move the decalaration of myIO to the State level:
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
SocketFlutterPlugin myIO;
// ...
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
try {
myIO = new SocketFlutterPlugin();
//...
}
//...
}
}
Related
I'm using local_auth for user verification.
The root widget of my app is a stateless widget.
The bug:
The authentication screen pops up as usual. If the fingerprint (or pin) matches, the user can then access the app. However, if the back button is pressed (while the authentication screen is still up), the authentication window vanishes and the user can access the app without authenticating.
I'm using Flutter-2.5.3 and local_auth-1.1.8.
This is the main.dart:
//other imports here
import 'package:local_auth/local_auth.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
var localAuth = LocalAuthentication();
SharedPreferences prefs = await SharedPreferences.getInstance();
if (prefs.getBool('auth') == true) {
await localAuth.authenticate(
localizedReason: 'Authenticate to access Notes',
useErrorDialogs: true,
stickyAuth: true,);
}
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]).then((_) {
runApp(ProviderScope(child: MyApp()));
});
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
//returns my widget
}
}
I tried moving the runApp block under a conditional, such that the main root window gets called only when the authentication was successful. However the result remained the same.
This was what I did:
if (prefs.getBool('auth') == true) {
var authenticate = await localAuth.authenticate(
localizedReason: 'Authenticate to access Notes',
useErrorDialogs: true,
stickyAuth: true,);
if (authenticate == true) {
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]).then((_) {
runApp(ProviderScope(child: MyApp()));
});
}
}
This is what worked for me:
Changing MyApp to a StatefulWidget.
Adding an awaited function that attempts to authenticate the user before the user can access the widget (that is, the build function).
Modifying the code:
//other imports here
import 'package:local_auth/local_auth.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
//removing the authentication block from the main method
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]).then((_) {
runApp(ProviderScope(child: MyApp()));
});
}
class MyApp extends StatefulWidget { //changing MyApp to StatefulWidget
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
_authenticate(); //the function that handles authentication
}
void _authenticate() async {
var localAuth = LocalAuthentication();
SharedPreferences prefs = await SharedPreferences.getInstance();
if (prefs.getBool('auth') == true) {
var authenticate = await localAuth.authenticate(
localizedReason: 'Authenticate to access Notes',
useErrorDialogs: true,
//Not using stickyAuth because: https://github.com/flutter/flutter/issues/83773
// stickyAuth: true,
);
if (authenticate != true)
exit(0); //exiting the app if the authentication failed
}
}
#override
Widget build(BuildContext context) {
//returns my widget
}
}
I am developing a flutter application with network activities. To get data, I am connecting to a REST API, this API is fast as it should.
For more information, this API is using AWS API Gateway and AWS Lambda along with other AWS technologies.
Below is my code, connecting to network.
class RoleService with ChangeNotifier {
NavLinks _navLinks = NavLinks();
late List<Role> _roles;
/// Get all Roles
Future<void> getAllRoles(String authToken) async {
try {
var data = await http.get(
Uri.parse("https://api2.example.com/userrel/roles/getall"),
headers: {HttpHeaders.authorizationHeader: "Bearer $authToken"},
);
var jsonData =
convert.json.decode(data.body).cast<Map<String, dynamic>>();
_roles = jsonData.map<Role>((json) => new Role.fromJson(json)).toList();
print(_roles);
} catch (error) {
print(error);
throw error;
}
}
}
You can see the postman performance of the above API call below. For flutter testing, i am using Huawei p30 Lite android phone.
Then, when I execute the same API call in flutter, this is what I get.
Observing the outputs from postman I can see it has cached the DNS Lookup, TCP Handshake and SSL Handshake. postman does this after calling the API base URI for the first time. Then from the 2nd time onwards, the DNS Lookup etc are cached saving lot of time in future API calls to the same base URI.
But in flutter the "Connection established" time is high, even though the time to retrieve data is only few milliseconds.
How can I avoid the connection delays and get the maximum performance? If caching the SSL, DNS Lookup etc is the solution, how can I do that in flutter?
It seems this question is there for many people. So, let me answer my own question.
Can flutter remember the network connection? Yes it can.
Flutter only require one network call to the same API to remember the connection. From the second call onward to the same API, it will use its "cached" memory giving you a big performance boost.
So first remember, this only works if you are calling the same API multiple times. If you are calling different APIs, this will not work. However in many apps, you have an API that built by the API team and you will be calling the same throughput the app.
The solution is to use flutter http.Client. Then share the same http.Client across the calls you make to the same API. You will see only first call takes time for "connection", rest of the calls do not take that time.
An example is available in flutter http pub page. It says ,
If you're making multiple requests to the same server, you can keep
open a persistent connection by using a Client rather than making
one-off requests. If you do this, make sure to close the client when
you're done:
Check below example. It is only for your reference, not the best way of using this.
main.dart
import 'package:flutter/material.dart';
import 'package:network_test/role_service.dart';
import 'package:network_test/user_role_service.dart';
import 'package:network_test/user_service.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var startTime = "";
var endTime = "";
void _network() async {
var client = http.Client();
RoleService _roleService = RoleService();
UserService _userService = UserService();
UserRoleService _userRoleService = UserRoleService();
String authToken = "****";
String uid = "555555";
try {
await _roleService.getAllRoles(authToken, client);
//await _roleService.getAllRoles(authToken, client);
await _userService.getUserByUID(authToken, uid, client);
await _userService.getUserByID(authToken, 27, client);
await _userRoleService.getUserRoleByUser(authToken, 27, client);
} finally {
client.close();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
"Start Time: " + startTime,
style: Theme.of(context).textTheme.headline4,
),
Text(
"End Time: " + endTime,
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _network,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
role_service.dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'package:network_test/role.dart';
import 'dart:convert' as convert;
import 'dart:io';
class RoleService with ChangeNotifier {
late List<Role> _roles;
String link2 = "https://api2.somewhere.com/userrel";
/// Return roles
List<Role> returnRoles() {
return _roles;
}
/// Get all Roles
Future<void> getAllRoles(String authToken, Client client) async {
try {
var data = await client.get(Uri.parse(link2 + "/role/getall"),
headers: {HttpHeaders.authorizationHeader: "Bearer $authToken"});
var jsonData =
convert.json.decode(data.body).cast<Map<String, dynamic>>();
_roles = jsonData.map<Role>((json) => Role.fromJson(json)).toList();
print(_roles[0].roleName);
} catch (error) {
print(error);
throw error;
}
}
}
now I told you that above is not the best practice. Why? Because you will be creating and destroying the http.Client in many different places. Let's pay attention to a better practice.
In almost every app, we use State Management. I am a fan of Provider, it could be anything of your choice. i figured out the best way is to let the state management to remember the creation of http.Client. Since I am using Provider, I created the following class.
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
class ConnectionService with ChangeNotifier {
http.Client _client = http.Client();
http.Client returnConnection() {
return _client;
}
}
And this is my main class
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => ConnectionService()),
],
child: MyApp(),
));
}
Now when the app opens, I call the ConnectionService class to make the connection and do my API calls such as checking user authentication, user access etc. And only the first call is taking its time to build the connection, other calls do not.
I am new to flutter and developing an app but I am facing an issue regarding a post request to the asp.net core API method.
This below is the flutter code that I am using to post data to the asp.net core API method.
Future registerUser(
String userFullName, String username, String email, String password) async {
var body = jsonEncode({
"UserFullName": userFullName,
"Username": username,
"Email": email,
"Password": password
});
final response = await http.post(
Uri.parse(GetURI.baseURI() + 'Account/Register'),
body: body,
headers: {"content-type": "application/json"});
print("Hello Body! " + response.statusCode.toString());
print(response.body);
return null;
}
On button click, I am calling the above function to post data but getting an error. The code for the button click is below:
onPressed: () async {
final validationSuccess = _formKey.currentState!.validate();
if (validationSuccess) {
_formKey.currentState!.save();
final formData = _formKey.currentState!.value;
final userData = await registerUser(
_formKey.currentState!.fields['username']!.value,
_formKey.currentState!.fields['email']!.value,
_formKey.currentState!.fields['email']!.value,
_formKey.currentState!.fields['password']!.value);
print(userData!.userFullName);
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('$formData'),
duration: Duration(seconds: 5),
));
}
}
On clicking the button it gives me the error like below:
[ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: HandshakeException: Handshake error in client (OS Error:
CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:359))
This is the Class code from where I am returning my URL:
class GetURI {
static String baseURI() {
return 'https://10.103.78.29:44318/api/';
}
}
My main.dart file
import 'dart:io';
import 'package:bugsmashmobileapp/Screen/LoginScreen/login_body.dart';
import 'package:bugsmashmobileapp/Screen/SignupScreen/signup_body.dart';
import 'package:bugsmashmobileapp/Screen/WelcomeScreen/getting_started_screen.dart';
import 'package:flutter/material.dart';
class MyHttpOverrides extends HttpOverrides {
#override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
}
void main() {
HttpOverrides.global = new MyHttpOverrides();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'BUGSMASH APP',
theme: ThemeData(
primarySwatch: Colors.blue, scaffoldBackgroundColor: Colors.white),
home: GettingStartedScreen(),
routes: {
SignupScreen.routeName: (context) => SignupScreen(),
LoginScreen.routeName: (context) => LoginScreen()
},
);
}
}
I have tried many ways and searched a lot but not able to get a good way to solve this error. If anyone can help it would be appreciated.
When I tried ngrok the problem is solved for me.
First I created an account on ngrok (Click here to go to website) and then you need to install its software to generate a URL and forwarding it to your API Project. Then you can use that URL in your Flutter Project without any issue.
I'm attempting to run location updates on a Flutter isolate thread, the error is only present when running an isolate. Location requests works without issues on the main thread. The goal here is to run this as a background service, working with dart code only.
I am using Geolocator plugin for location requests.
This is the error I am facing when starting the isolate:
Exception has occurred. FlutterError
(ServicesBinding.defaultBinaryMessenger was accessed before the
binding was initialized.
I have tried to include the WidgetsFlutterBinding.ensureInitialized() before runApp but without results.
Looking at the call stack of the error, it seems problems occur at the android location platform call: checkPermissionStatus
This happens regardless of what location plugin I am using, it stops at the permission status check.
I have figured it could have something to do with awaiting location permission user input, but this check will fail on a non-ui thread?
See this simple main.dart file for an example:
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Isolate location test',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Isolate location test'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Isolate isolate;
bool isRunning = false;
String output = '';
ReceivePort receivePort;
void start() async {
receivePort = ReceivePort();
await Isolate.spawn(locationUpdate, receivePort.sendPort);
receivePort.listen((dynamic data) {
setState(() {
isRunning = true;
});
}, onDone: () {
print("done");
});
}
void stop() {
if (isolate != null) {
setState(() {
isRunning = false;
});
receivePort.close();
isolate.kill(priority: Isolate.immediate);
isolate = null;
}
}
static void locationUpdate(SendPort sendPort) async {
Geolocator().checkGeolocationPermissionStatus().then((status) {
sendPort.send(status);
});
// Geolocator().getCurrentPosition().then((pos) {
// sendPort.send(pos);
// });
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(child: Text(output)),
floatingActionButton: FloatingActionButton(
onPressed: isRunning ? stop : start,
child: Icon(isRunning ? Icons.stop : Icons.play_circle_filled),
),
);
}
}
I want to disable logging of Firebase Analytics in a Flutter project when the app is being run on Firebase Test Lab. According to Firebase docs, TestLab can be detected by adding the following in MainActivity.java
String testLabSetting = Settings.System.getString(getContentResolver(), "firebase.test.lab");
if ("true".equals(testLabSetting)) {
// Do something when running in Test Lab
// ...
}
How can I access the result of this test on the dart side in main.dart which is where I want to disable logging (as there are some other reasons logging is disabled already in the dart code).
Thanks!
I just found this. I didn't try it yet though:
https://pub.dev/packages/flutter_runtime_env
This project allows you to check if you're running in the Firebase
Test Labs
You can use it like their example:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_runtime_env/flutter_runtime_env.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool _shouldBeEnabled = false;
#override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
var result = await shouldEnableAnalytics();
setState(() {
_shouldBeEnabled = result;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Should Enable Analytics'),
),
body: Center(
child: Text('Should Analytics be Enabled: $_shouldBeEnabled\n'),
),
),
);
}
}
EDIT:
I think I found a better solution.
https://pub.dev/packages/flutter_sentry
It has the follow method
/// Return `true` if running under Firebase Test Lab (includes pre-launch
/// report environment) on Android, `false` otherwise.
static Future<bool> isFirebaseTestLab() async
It seems to be the best solution so far...
EDIT 2:
Fuck it! I just created a small plugin.
https://pub.dev/packages/is_firebase_test_lab_activated