When interacting with my function that initiate specs, flutter return me this error : "_CastError (Null check operator used on a null value)"
error code :
initSpecsTechs() async {
specs = await APIBike()
.getSpecsTechs(jwt: _user!.jwt, bikeId: favoriteBike!.id);
initBluetoothConnection();
initSliderAutomaticExtinctionValue();
initSliderAutomaticLockingValue();
initBackLightMode();
}
Full code of my page setting (first line contain the error code):
import 'package:myapp/api_bike.dart';
import 'package:myapp/api_user.dart';
import 'package:myapp/ux_components.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'blur_filter.dart';
class SettingsPage extends StatefulWidget {
#override
SettingsPageState createState() => SettingsPageState();
SettingsPage({required Key key}) : super(key: key);
}
class SettingsPageState extends State<SettingsPage>
with AutomaticKeepAliveClientMixin<SettingsPage> {
User? _user;
List<Bike> _bikes = [];
Bike? favoriteBike;
Specs? specs;
bool connectedByBluetooth = true;
double _currentSliderAutomaticExtinctionValue = 0;
double _currentSliderAutomaticLockingValue = 0;
bool theftAlertIsActive = true;
bool batteryAlertIsActive = true;
bool maintainAlertIsActive = true;
bool constantBackLight = true;
double spaceAfterSmallTitle = 15;
double spaceAfterWidget = 20;
//INIT FUNCTIONS
init() async {
await initUser();
await initBikes();
await initFavoriteBike();
await initSpecsTechs();
}
Future initUser() async {
final storage = new FlutterSecureStorage();
String mail = await storage.read(key: "mail") ?? "";
String password = await storage.read(key: "password") ?? "";
UserResponse userResponse = await APIUser()
.login(mail, password); //L'identifiant peut ĂȘtre le username ou le mail
User? user = userResponse.user;
if (user != null) {
setState(() {
_user = user;
});
}
return user;
}
initBikes() async {
if (_user != null) {
List<Bike> bikes = await APIBike().getAllUserBikes(jwt: _user!.jwt);
setState(() {
_bikes = bikes;
});
} else {
print("could not get the bikes call the user is null");
}
}
initFavoriteBike() async {
if (_bikes.length == 0) {
favoriteBike = null;
} else if (_bikes.length == 1) {
setState(() {
favoriteBike = _bikes.first;
});
} else {
Bike? favBike = await APIBike().getFavoriteBike(jwt: _user!.jwt);
if (favBike != null) {
setState(() {
favoriteBike = favBike;
});
} else {
print("PROBLEM : FAVORITE BIKE IS NULL");
}
}
}
initSpecsTechs() async {
specs = await APIBike()
.getSpecsTechs(jwt: _user!.jwt, bikeId: favoriteBike!.id);
initBluetoothConnection();
initSliderAutomaticExtinctionValue();
initSliderAutomaticLockingValue();
initBackLightMode();
}
initBackLightMode() {
if (specs != null) {
bool constantBackLightValue = false;
if (specs!.rearLight == "fixed") {
constantBackLightValue = true;
}
setState(() {
constantBackLight = constantBackLightValue;
});
} else {
print("Fake value used for initBackLightMode");
}
}
initTheftAlertIsActive() {
if (specs != null) {
setState(() {
theftAlertIsActive = specs!.theftAlarm;
});
} else {
print("Fake value used for initStealAlertIsActive");
}
}
initBatteryAlertIsActive() {
if (specs != null) {
setState(() {
batteryAlertIsActive = specs!.batteryAlarm;
});
} else {
print("Fake value used for initBatteryAlertIsActive");
}
}
initMaintenanceAlertIsActive() {
if (specs != null) {
setState(() {
maintainAlertIsActive = specs!.maintenanceAlarm;
});
} else {
print("Fake value used for initMaintenanceAlertIsActive");
}
}
initBluetoothConnection() {
//If this value is false then the page is all grey with nothing active
setState(() {
connectedByBluetooth = true;
});
}
initSliderAutomaticExtinctionValue() {
if (specs != null) {
double sliderValue = 0;
if (specs!.automaticSwitchOff == 0) {
sliderValue = 4;
} else if (specs!.automaticSwitchOff == 5) {
sliderValue = 0;
} else if (specs!.automaticSwitchOff == 10) {
sliderValue = 1;
} else if (specs!.automaticSwitchOff == 15) {
sliderValue = 2;
} else if (specs!.automaticSwitchOff == 20) {
sliderValue = 3;
} else {
//If there is a problem (it is not suppose to happen, we set it to never)
sliderValue = 0;
}
setState(() {
_currentSliderAutomaticExtinctionValue = sliderValue;
});
} else {
print("Fake value used for initSliderAutomaticExtinctionValue");
}
}
initSliderAutomaticLockingValue() {
if (specs != null) {
double sliderValue = 0;
if (specs!.automaticLocking == 0) {
sliderValue = 4;
} else if (specs!.automaticLocking == 1) {
sliderValue = 0;
} else if (specs!.automaticLocking == 3) {
sliderValue = 1;
} else if (specs!.automaticLocking == 5) {
sliderValue = 2;
} else if (specs!.automaticLocking == 10) {
sliderValue = 3;
} else {
//If there is a problem (it is not suppose to happen, we set it to never)
sliderValue = 0;
}
setState(() {
_currentSliderAutomaticLockingValue = sliderValue;
});
} else {
print("Fake value used for initSliderAutomaticLockingValue");
}
}
#override
void initState() {
super.initState();
init();
}
//UPDATE FUNCTIONS
updateRearLightValue(String newValue) async {
//TODO change the value on the bike by BLE
bool operationSucceed = await APIBike().updateSpecsTechs(
jwt: _user!.jwt,
bikeId: favoriteBike!.id,
specToUpdate: "rear_light",
newSpecValue: newValue);
if (operationSucceed) {
print("Rear light value updated successfully");
} else {
print("Error: rear light value didn't update correctly");
}
return operationSucceed;
}
updateAutomaticShutDownValue(double sliderValue) async {
//TODO change the value on the bike by BLE
int newValue = 0; // is also the value for never
if (sliderValue == 0) {
newValue = 5;
} else if (sliderValue == 1) {
newValue = 10;
} else if (sliderValue == 2) {
newValue = 15;
} else if (sliderValue == 3) {
newValue = 20;
} //else the new value is 0 which is never
bool operationSucceed = await APIBike().updateSpecsTechs(
jwt: _user!.jwt,
bikeId: favoriteBike!.id,
specToUpdate: "automatic_switch_off",
newSpecValue: newValue);
if (operationSucceed) {
print("Automatic switch off value updated successfully");
} else {
print("Error: Automatic switch off value didn't update correctly");
}
return operationSucceed;
}
updateAutomaticLockingValue(double sliderValue) async {
//TODO change the value on the bike by BLE
int newValue = 0; // is also the value for never
if (sliderValue == 0) {
newValue = 1;
} else if (sliderValue == 1) {
newValue = 3;
} else if (sliderValue == 2) {
newValue = 5;
} else if (sliderValue == 3) {
newValue = 10;
} //else the new value is 0 which is never
bool operationSucceed = await APIBike().updateSpecsTechs(
jwt: _user!.jwt,
bikeId: favoriteBike!.id,
specToUpdate: "automatic_locking",
newSpecValue: newValue);
if (operationSucceed) {
print("Automatic locking value updated successfully");
} else {
print("Error: Automatic locking value didn't update correctly");
}
return operationSucceed;
}
updateTheftAlertIsActive(bool newValue) async {
bool operationSucceed = await APIBike().updateSpecsTechs(
jwt: _user!.jwt,
bikeId: favoriteBike!.id,
specToUpdate: "theft_alarm",
newSpecValue: newValue);
if (operationSucceed) {
print("Theft alert value updated successfully");
} else {
print("Error: theft alert value didn't update correctly");
}
return operationSucceed;
}
updateBatteryAlertIsActive(bool newValue) async {
bool operationSucceed = await APIBike().updateSpecsTechs(
jwt: _user!.jwt,
bikeId: favoriteBike!.id,
specToUpdate: "battery_alarm",
newSpecValue: newValue);
if (operationSucceed) {
print("Battery alert value updated successfully");
} else {
print("Error: battery alert value didn't update correctly");
}
return operationSucceed;
}
updateMaintenanceAlertIsActive(bool newValue) async {
bool operationSucceed = await APIBike().updateSpecsTechs(
jwt: _user!.jwt,
bikeId: favoriteBike!.id,
specToUpdate: "maintenance_alarm",
newSpecValue: newValue);
if (operationSucceed) {
print("Maintenance alert value updated successfully");
} else {
print("Error: maintenance alert value didn't update correctly");
}
return operationSucceed;
}
/.../
And finally my api for the user :
import 'dart:collection';
import 'package:myapp/api_bike.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class ResponseWithError {
final bool result;
final String error;
ResponseWithError(this.result, this.error);
}
class APIUser {
//For dev
final String serverAddress =
"https://myadress.com/";
//TODO For production:
//final String serverAddress = "https://prodadress.com";
Future<ResponseWithError> createUser(
String firstname, String lastname, String email, String password) async {
var body =
"""{"username": "$firstname $lastname", "firstname": "$firstname", "lastname": "$lastname", "email": "$email", "password": "$password"}""";
var client = new http.Client();
var response = await client.post(
Uri.parse("$serverAddress/auth/local/register"),
body: body,
headers: {"Content-Type": 'application/json'});
if (response.statusCode == 200) {
print("USER CREATED");
print(response.body);
return ResponseWithError(true, "none");
} else {
print("Error " + response.statusCode.toString());
print("Response Body");
print(response.body);
var responseBody = jsonDecode(response.body);
if (responseBody["message"][0]["messages"][0]["id"] != null) {
String errorMessageId = responseBody["message"][0]["messages"][0]["id"];
if (errorMessageId == "Auth.form.error.email.format") {
return ResponseWithError(false, "email format");
}
}
return ResponseWithError(false, "not known");
}
}
Future<UserResponse> login(String identifier, String password) async {
var body = """{"identifier": "$identifier", "password": "$password"}""";
var client = new http.Client();
var response = await client.post(Uri.parse("$serverAddress/auth/local"),
body: body, headers: {"Content-Type": 'application/json'});
if (response.statusCode == 200) {
//print("USER LOGGED IN");
final parsed = jsonDecode(response.body);
User user = User.fromJson(parsed);
UserResponse userResponse = UserResponse(user, true);
return userResponse;
} else {
//print("Error " + response.statusCode.toString());
//print("Response Body");
//print(response.body);
var responseBody = jsonDecode(response.body);
if (responseBody["message"][0]["messages"][0]["id"] != null) {
String errorMessageId = responseBody["message"][0]["messages"][0]["id"];
if (errorMessageId == "Auth.form.error.confirmed") {
print("User not confirmed");
UserResponse userResponse = UserResponse(null, false);
return userResponse;
} else /*if(errorMessageId == "Auth.form.error.invalid")*/ {
print("email or password incorrect");
UserResponse userResponse = UserResponse(null, true);
return userResponse;
}
}
//Should not happen, but just in case
UserResponse userResponse = UserResponse(null, true);
return userResponse;
}
}
Future<bool> updateToken(String jwt, String notificationId) async {
var body = """{"notification_id": "$notificationId"}""";
var client = new http.Client();
var response = await client.put(Uri.parse("$serverAddress/users/token"),
body: body,
headers: {
"Content-Type": 'application/json',
'Authorization': 'Bearer $jwt'
});
if (response.statusCode == 200) {
print("NOTIFICATION TOKEN UPDATED");
return true;
} else {
print("Error " + response.statusCode.toString());
print("Response Body");
print(response.body);
return false;
}
}
Future<bool> updateEmail(String jwt, String newEmail) async {
var confirmed = false;
var body = """{"email": "$newEmail", "confirmed": "$confirmed"}""";
var client = new http.Client();
var response = await client.put(Uri.parse("$serverAddress/users/me"),
body: body,
headers: {
"Content-Type": 'application/json',
'Authorization': 'Bearer $jwt'
});
if (response.statusCode == 200) {
print("EMAIL UPDATED");
return true;
} else {
print("Error " + response.statusCode.toString());
print("Response Body");
print(response.body);
return false;
}
}
Future<bool> updateNames(
String jwt, String newFirstname, String newLastName) async {
var body =
"""{"username": "$newFirstname $newLastName", "firstname": "$newFirstname", "lastname": "$newLastName"}""";
var client = new http.Client();
var response = await client.put(Uri.parse("$serverAddress/users/me"),
body: body,
headers: {
"Content-Type": 'application/json',
'Authorization': 'Bearer $jwt'
});
if (response.statusCode == 200) {
print("NAMES UPDATED");
return true;
} else {
print("Error " + response.statusCode.toString());
print("Response Body");
print(response.body);
return false;
}
}
Future<bool> updatePassword(String jwt, String newPassword) async {
var body = """{"password": "$newPassword"}""";
var client = new http.Client();
var response = await client.put(Uri.parse("$serverAddress/users/me"),
body: body,
headers: {
"Content-Type": 'application/json',
'Authorization': 'Bearer $jwt'
});
if (response.statusCode == 200) {
print("PASSWORD UPDATED");
return true;
} else {
print("Error " + response.statusCode.toString());
print("Response Body");
print(response.body);
return false;
}
}
Future<bool> sendConfirmationCode(String email) async {
var body = """{"email": "$email"}""";
var client = new http.Client();
var response = await client.post(
Uri.parse("$serverAddress/auth/send-email-confirmation"),
body: body,
headers: {"Content-Type": 'application/json'});
if (response.statusCode == 200) {
print("EMAIL SENT to $email");
return true;
} else {
print("Error " + response.statusCode.toString());
print("Response Body");
print(response.body);
return false;
}
}
Future<bool> verifyEmail(String email, String code) async {
var body = """{"email": "$email", "confirmation": "$code"}""";
var client = new http.Client();
var response = await client.put(
Uri.parse("$serverAddress/auth/email-confirmation"),
body: body,
headers: {"Content-Type": 'application/json'});
if (response.statusCode == 200) {
print("EMAIL VERIFIED");
return true;
} else {
print("Error " + response.statusCode.toString());
print("Response Body");
print(response.body);
return false;
}
}
Future<bool> passwordForgotten({required String email}) async {
var body = """{"email": "$email"}""";
var client = new http.Client();
var response = await client.post(
Uri.parse("$serverAddress/auth/forgot-password"),
body: body,
headers: {"Content-Type": 'application/json'});
if (response.statusCode == 200) {
return true;
} else {
print("Error passwordForgotten :" + response.statusCode.toString());
print("Response Body");
print(response.body);
return false;
}
}
}
class UserResponse {
User? user;
bool userConfirmed;
UserResponse(this.user, this.userConfirmed);
}
class User {
final int id;
final String jwt;
final String username;
final String firstname;
final String lastname;
final String email;
final String provider;
final bool confirmed;
final bool? blocked;
final String? notificationId;
final String createdAt;
final String updatedAt;
final List<int>?
bikesId; //Here we just save the ids of the bikes linked to the user
final Subscription? subscription;
final Role role;
User({
required this.id,
required this.jwt,
required this.username,
required this.firstname,
required this.lastname,
required this.email,
required this.provider,
required this.confirmed,
required this.blocked,
required this.notificationId,
required this.createdAt,
required this.updatedAt,
required this.bikesId,
required this.subscription,
required this.role,
});
factory User.fromJson(Map<String, dynamic> json) {
if (json['user']['subscription'] != null) {
return User(
id: json['user']['id'] as int,
jwt: json['jwt'] as String,
username: json['user']['username'] as String,
firstname: json['user']['firstname'] as String,
lastname: json['user']['lastname'] as String,
email: json['user']['email'] as String,
provider: json['user']['provider'] as String,
confirmed: json['user']['confirmed'] as bool,
blocked: json['user']['blocked'] as bool?,
notificationId: json['user']['notification_id'] as String?,
createdAt: json['user']['created_at'] as String,
updatedAt: json['user']['updated_at'] as String,
bikesId: createBikesIdList(json['user']['bikes_id']),
subscription: Subscription(
id: json['user']['subscription']['id'],
name: json['user']['subscription']['name'],
createdAt: json['user']['subscription']['created_at'],
updatedAt: json['user']['subscription']['updated_at']),
role: Role(
id: json['user']['role']['id'],
name: json['user']['role']['name'],
description: json['user']['role']['description'],
type: json['user']['role']['type'],
));
} else {
return User(
id: json['user']['id'] as int,
jwt: json['jwt'] as String,
username: json['user']['username'] as String,
firstname: json['user']['firstname'] as String,
lastname: json['user']['lastname'] as String,
email: json['user']['email'] as String,
provider: json['user']['provider'] as String,
confirmed: json['user']['confirmed'] as bool,
blocked: json['user']['blocked'] as bool?,
notificationId: json['user']['notification_id'] as String?,
createdAt: json['user']['created_at'] as String,
updatedAt: json['user']['updated_at'] as String,
bikesId: createBikesIdList(json['user']['bikes_id']),
subscription: null,
role: Role(
id: json['user']['role']['id'],
name: json['user']['role']['name'],
description: json['user']['role']['description'],
type: json['user']['role']['type'],
));
}
}
describe() {
print("id : $id\njwt : $jwt");
}
}
class Role {
final int id;
final String name;
final String description;
final String type;
Role({
required this.id,
required this.name,
required this.description,
required this.type,
});
}
class Subscription {
final int id;
final String name;
final String createdAt;
final String updatedAt;
Subscription(
{required this.id,
required this.name,
required this.createdAt,
required this.updatedAt});
}
Can you try like this? I think user or favoriteBike is null. You need to null check.
initSpecsTechs() async {
if(_user != null && favoriteBike != null){
specs = await APIBike()
.getSpecsTechs(jwt: _user!.jwt, bikeId: favoriteBike!.id);
initBluetoothConnection();
initSliderAutomaticExtinctionValue();
initSliderAutomaticLockingValue();
initBackLightMode();
}
}
initSpecsTechs() async {
specs = await APIBike()
.getSpecsTechs(jwt: _user!.jwt, bikeId: favoriteBike!.id);
initBluetoothConnection();
initSliderAutomaticExtinctionValue();
initSliderAutomaticLockingValue();
initBackLightMode();
}
The "!" operator causes the exception instead use "?" like this
specs = await APIBike()
.getSpecsTechs(jwt: _user?.jwt??'', bikeId: favoriteBike?.id??'');
Related
I am trying to print the content of the notification that comes through PHP (topics) How to print the content of the notification in the terminal using Flutter?
code:
class PushNotificationService {
late BuildContext context;
PushNotificationService({required this.context});
Future initialise() async {
FirebaseMessaging.instance.subscribeToTopic('TopicToListen');
print('firebase_token->initialize===${messaging == null}==');
iOSPermission();
print('firebase_token->initialize=///');
messaging.getToken();
print('firebase_token->initialize==**');
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('ic_launcher');
/* const IOSInitializationSettings initializationSettingsIOS = IOSInitializationSettings();
const MacOSInitializationSettings initializationSettingsMacOS = MacOSInitializationSettings();*/
final DarwinInitializationSettings initializationSettingsIOS =
DarwinInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
onDidReceiveLocalNotification:
(int id, String? title, String? body, String? payload) async {
/* didReceiveLocalNotificationStream.add(
ReceivedNotification(
id: id,
title: title,
body: body,
payload: payload,
),
);*/
},
);
/*const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
macOS: initializationSettingsMacOS);*/
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsIOS,
);
/*flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String? payload) async {
print("payload*****$payload");
selectNotificationPayload(payload);
});*/
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse:
(NotificationResponse notificationResponse) {
switch (notificationResponse.notificationResponseType) {
case NotificationResponseType.selectedNotification:
selectNotificationPayload(notificationResponse.payload!);
break;
case NotificationResponseType.selectedNotificationAction:
print(
"notification-action-id--->${notificationResponse.actionId}==${notificationResponse.payload}");
break;
}
},
onDidReceiveBackgroundNotificationResponse: backgroundMessage,
);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
if (message.data != null) {
var data = message.data;
var notif = message.notification;
if (data['type'] == "default" || data['type'] == "category") {
var title = data['title'].toString();
var body = data['message'].toString();
var image = data['image'];
var payload = data["news_id"];
if (payload == null) {
payload = "";
} else {
payload = payload;
}
if (image != null && image != "") {
if (notiEnable!) {
generateImageNotication(title, body, image, payload);
}
} else {
if (notiEnable!) {
generateSimpleNotication(title, body, payload);
}
}
} else {
//Direct Firebase Notification
var title = notif?.title.toString();
var msg = notif?.body.toString();
var img = notif?.android?.imageUrl.toString();
if (notiEnable!) {
(img != null)
? generateImageNotication(title!, msg!, img, '')
: generateSimpleNotication(title!, msg!, '');
}
}
}
});
messaging.getInitialMessage().then((RemoteMessage? message) async {
bool back = await getPrefrenceBool(ISFROMBACK);
print("message******$message");
if (message != null && back) {
var data = message.data;
var notif = message.notification;
if (data['type'] == "default" || data['type'] == "category") {
var title = data['title'].toString();
var body = data['message'].toString();
var image = data['image'];
var payload = data["news_id"];
if (payload == null) {
payload = "";
} else {
payload = payload;
}
if (image != null && image != "") {
if (notiEnable!) {
generateImageNotication(title, body, image, payload);
}
} else {
if (notiEnable!) {
generateSimpleNotication(title, body, payload);
}
}
} else {
//Direct Firebase Notification
var title = notif?.title.toString();
var msg = notif?.body.toString();
var img = notif?.android?.imageUrl.toString();
if (notiEnable!) {
(img != null)
? generateImageNotication(title!, msg!, img, '')
: generateSimpleNotication(title!, msg!, '');
}
}
setPrefrenceBool(ISFROMBACK, false);
}
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
print("message******$message");
if (message.data != null) {
var data = message.data;
var notif = message.notification;
if (data['type'] == "default" || data['type'] == "category") {
var title = data['title'].toString();
var body = data['message'].toString();
var image = data['image'];
var payload = data["news_id"];
if (payload == null) {
payload = "";
} else {
payload = payload;
}
if (image != null && image != "") {
if (notiEnable!) {
generateImageNotication(title, body, image, payload);
}
} else {
if (notiEnable!) {
generateSimpleNotication(title, body, payload);
}
}
} else {
//Direct Firebase Notification
var title = notif?.title.toString();
var msg = notif?.body.toString();
var img = notif?.android?.imageUrl.toString();
if (notiEnable!) {
(img != null)
? generateImageNotication(title!, msg!, img, '')
: generateSimpleNotication(title!, msg!, '');
}
}
}
setPrefrenceBool(ISFROMBACK, false);
});
}
void iOSPermission() async {
await messaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
//when open dynamic link news index and id can used for fetch specific news
Future<void> getNewsById(
String id,
String index,
) async {
var param = {
NEWS_ID: id,
ACCESS_KEY: access_key,
// ignore: unnecessary_null_comparison
USER_ID: CUR_USERID != null && CUR_USERID != "" ? CUR_USERID : "0",
LANGUAGE_ID: CUR_LANGUAGE_ID
};
var apiName = getNewsByIdApi;
http.Response response = await http
.post(Uri.parse(apiName), body: param, headers: headers)
.timeout(Duration(seconds: timeOut));
var getdata = json.decode(response.body);
String error = getdata["error"];
if (error == "false") {
var data = getdata["data"];
List<News> news = [];
news = (data as List).map((data) => new News.fromJson(data)).toList();
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => NewsDetails(
model: news[0],
index: int.parse(index),
id: news[0].id,
isDetails: true,
news: [],
)));
}
}
selectNotificationPayload(String? payload) async {
if (payload != null && payload != "") {
debugPrint('notification payload: $payload');
getNewsById(payload, "0");
} else {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
}
}
}
I searched so much in the firebase documentation and couldn't find anything that could help me with the issue.
I would appreciate your help
I inserted the following line into the main.dart file
And I got the notification content in the terminal.
Hope this helps people in the future
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('Handling a background message ${message.notification?.body}');
}
TL;DR
I am receiving notification on all state(foreground, background(on-Paused), terminated(on-Detached)) but it's redirecting me to the intended url only in(foreground and terminated state). Surprisingly, on receiving notification during foreground state, on-select notification works on-Background state(on-Paused) as well and I am redirected to my intended url. But the main problem is while recieving notification on-background state(on-Paused) without receiving notification on foreground at first, it just redirects me to where I was. Here is the code I am currently working on:
void afterInitFirebase() async {
NotificationSettings settings = await _firebaseMessaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
await _firebaseMessaging
.subscribeToTopic(topic)
.onError((error, stackTrace) => {print(error)});
await _firebaseMessaging.getToken().then((value) => {
Preference.setString(fcm_token, value),
});
await _firebaseMessaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
await _firebaseMessaging.getInitialMessage().then((RemoteMessage? message) {
if (message != null) {
// _handleIncomingLinks();
MyNotification().initMessaging(message, isPush: true);
}
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
displayNotification(message);
});
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print("${message.from} =--> ON MESSAGE OPENED APP");
});
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
HttpOverrides.global = MyHttpOverrides();
try {
await Firebase.initializeApp().then((value) {
afterInitFirebase();
});
} catch (e) {
print(
"EXCEPTION ON MAIN:" + e.toString(),
);
}
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await fitNotification.getNotificationAppLaunchDetails();
final uri = await getInitialUri();
String initialRoute = splash_page;
String id = "0";
if (notificationAppLaunchDetails!.didNotificationLaunchApp) {
selectedNotificationPayload = notificationAppLaunchDetails.payload;
print("payload $selectedNotificationPayload");
var parts = selectedNotificationPayload?.split(SEPARATOR);
if (parts != null) {
if (parts[0] == "course" ||
parts[0].toLowerCase() == "coursedetails" ||
parts[0].toLowerCase() == "coursedetails") {
id = parts[1];
//course details page
initialRoute = course_details;
} else if (parts[0].toLowerCase() == "allcourse") {
initialRoute = all_course;
if (parts.length > 1) {
id = parts[1];
}
print("payload: $initialRoute $id");
} else if (parts[0].toLowerCase() == "allplan") {
if (parts.length > 1) {
id = parts[1];
}
initialRoute = "/allPlans";
} else if (parts[0].toLowerCase() == "web") {
id = parts[1];
initialRoute = web_page;
} else if (parts[0].toLowerCase() == "plan") {
id = parts[1];
initialRoute = plans_details_page;
} else if (parts[0].toLowerCase() == "quiz") {
initialRoute = web_page_entrance;
} else if (parts[0].toLowerCase() == "wishlist") {
initialRoute = route_wish_list;
} else if (parts[0].toLowerCase() == "carts") {
initialRoute = my_carts;
} else {
initialRoute = notification_page;
}
}
}
if (uri == null) {
} else {
String path = uri.toString();
if (path.toLowerCase().contains("coursedetails") ||
path.toLowerCase().contains("/home/course")) {
String idStr = uri.path.substring(uri.path.lastIndexOf('/') + 1);
id = idStr;
initialRoute = course_details;
}
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
displayNotification(message);
}
void displayNotification(RemoteMessage message) {
log(message.data.toString());
MyNotification().initMessaging(message);
}
This is my MyNotification class:
const String SEPARATOR = "|";
class MyNotification {
void initMessaging(RemoteMessage message, {isPush: true}) async {
var androidInit = AndroidInitializationSettings('ic_notification');
var iosInit = IOSInitializationSettings();
var initSetting =
InitializationSettings(android: androidInit, iOS: iosInit);
await fitNotification.initialize(initSetting,
onSelectNotification: onSelectNotification);
var rand = new Random();
int id = 1;
String? title = "";
String? body = "";
String? icon = "";
String? type = "";
String? itemId = "";
String link = "";
if (message.notification != null) {
title = "${message.notification?.title}";
body = "${message.notification?.body}";
icon = "${message.notification?.android?.imageUrl}";
if (Platform.isAndroid) {
icon = "${message.notification?.android?.imageUrl}";
} else {
icon = "${message.notification?.apple?.imageUrl}";
}
}
if (message.data['source'] == "webengage") {
isPush = true;
Map<String, dynamic> messageData =
jsonDecode(message.data['message_data']);
if (messageData.containsKey("title")) {
title = messageData["title"];
body = messageData["message"];
}
if (messageData.containsKey("expandableDetails")) {
Map<String, dynamic> expDetail = messageData["expandableDetails"];
if (expDetail.containsKey("image")) {
icon = expDetail["image"];
}
if (expDetail.containsKey("style")) {
if (expDetail['style'] == "RATING_V1" ||
expDetail['style'] == "CAROUSEL_V1") {
isPush = false;
}
}
}
if (messageData.containsKey("custom")) {
List<dynamic> customData = messageData['custom'];
print("element1: ${customData.toString()}");
customData.forEach((element) {
Map<String, dynamic> maps = element;
var key = maps['key'];
var value = maps['value'];
if (key == "itemId") {
itemId = value;
}
if (key == "type") {
type = value;
}
});
}
} else {
if (message.data.containsKey("icon")) {
icon = message.data['icon'];
}
if (message.data.containsKey("title")) {
title = message.data['title'];
body = message.data['body'];
}
if (message.data.containsKey("type")) {
type = message.data['type'];
}
if (message.data.containsKey("itemId")) {
itemId = message.data["itemId"];
}
}
if (title?.isNotEmpty == true && body?.isNotEmpty == true) {
showNotification(rand.nextInt(1000), title, body, icon,
"${type}$SEPARATOR${itemId}$SEPARATOR${icon}",
isPush: isPush);
}
}
Future<Uint8List> _getByteArrayFromUrl(String url) async {
final http.Response response = await http.get(Uri.parse(url));
return response.bodyBytes;
}
Future<void> showNotification(int notificationId, String? notificationTitle,
String? notificationContent, String? icon, String payload,
{String channelId = '1234',
String channelTitle = 'Android Channel',
String channelDescription = 'Default Android Channel for notifications',
Priority notificationPriority = Priority.high,
Importance notificationImportance = Importance.max,
bool isPush = true}) async {
//with icon
if (icon != null && icon.isNotEmpty) {
final String bigPicturePath =
await _downloadAndSaveFile(icon, 'bigPicture.jpg');
final BigPictureStyleInformation bigPictureStyleInformation =
BigPictureStyleInformation(
FilePathAndroidBitmap(bigPicturePath),
largeIcon: FilePathAndroidBitmap(bigPicturePath),
);
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
channelId, channelTitle,
channelDescription: channelDescription,
playSound: false,
importance: notificationImportance,
priority: notificationPriority,
styleInformation: bigPictureStyleInformation,
icon: 'for_icon',
);
final IOSNotificationDetails iOSPlatformChannelSpecifics =
IOSNotificationDetails(attachments: <IOSNotificationAttachment>[
IOSNotificationAttachment(bigPicturePath)
]);
final MacOSNotificationDetails macOSPlatformChannelSpecifics =
MacOSNotificationDetails(attachments: <MacOSNotificationAttachment>[
MacOSNotificationAttachment(bigPicturePath)
]);
final NotificationDetails notificationDetails = NotificationDetails(
iOS: iOSPlatformChannelSpecifics,
macOS: macOSPlatformChannelSpecifics,
android: androidPlatformChannelSpecifics);
if (isPush) {
await fitNotification.show(
notificationId,
notificationTitle,
notificationContent,
notificationDetails,
payload: payload,
);
}
} else {
//with out icon
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
channelId,
channelTitle,
channelDescription: channelDescription,
playSound: false,
importance: notificationImportance,
priority: notificationPriority,
icon: 'for_icon',
);
final NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
if (isPush) {
await fitNotification.show(notificationId, notificationTitle,
notificationContent, platformChannelSpecifics,
payload: payload);
}
}
var parts = payload.split(SEPARATOR);
var now = new DateTime.now();
var formatter = new DateFormat('yyyy-MM-dd HH:mm:ss');
String formattedDate = formatter.format(now);
NotificationModelData model = NotificationModelData(
courseId: parts[1],
icon: "$icon",
title: notificationTitle.toString(),
description: notificationContent.toString(),
type: parts[0],
notifyTime: formattedDate,
isRead: false,
id: now.millisecondsSinceEpoch.toString());
var db = AppDatabase.instance;
db.into(db.notificationModel).insert(model).then(
(value) => print(value),
);
}
Future<String> _downloadAndSaveFile(String url, String fileName) async {
final Directory directory = await getApplicationDocumentsDirectory();
final String filePath = '${directory.path}/$fileName';
final http.Response response = await http.get(Uri.parse(url));
final File file = File(filePath);
await file.writeAsBytes(response.bodyBytes);
return filePath;
}
Future<dynamic> onSelectNotification(String? payload) async {
selectedNotificationPayload = payload;
var parts = payload!.split(SEPARATOR);
if (parts[0].toLowerCase() == "course") {
//course details page
Navigator.pushNamed(
navigatorKey.currentState!.overlay!.context, course_details,
arguments: <String, String>{
'course_id': parts[1],
'thumbnail': parts[2]
});
} else if (parts[0].toLowerCase() == "web") {
await Navigator.pushNamed(
navigatorKey.currentState!.overlay!.context, web_page,
arguments: <String, String>{'paymentUrl': "${parts[1]}"});
} else if (parts[0].toLowerCase() == "allcourse") {
Navigator.pushNamed(
navigatorKey.currentState!.overlay!.context, all_course,
arguments: <String, String>{'course_id': "${parts[1]}"});
} else if (parts[0].toLowerCase() == "plan") {
Navigator.pushNamed(
navigatorKey.currentState!.overlay!.context, plans_details_page,
arguments: <String, String>{'plan_id': "${parts[1]}"});
} else if (parts[0].toLowerCase() == "allplan") {
Navigator.pushNamed(
navigatorKey.currentState!.overlay!.context, all_plans,
arguments: <String, String>{'id': "${parts[1]}"});
} else if (parts[0].toLowerCase() == "quiz") {
Navigator.of(navigatorKey.currentState!.overlay!.context)
.pushNamed(web_page_entrance);
} else {
//notification page
await Navigator.pushNamed(
navigatorKey.currentState!.overlay!.context, notification_page);
}
}
This is my WebPage class:
var url = "";
class WebPage extends StatefulWidget {
void launchURL() async {
if (await canLaunch(url))
await launch(url);
else
throw "Could not launch $url";
}
#override
_WebPageState createState() => _WebPageState();
}
class _WebPageState extends State<WebPage>{
bool isLoading = true;
final _key = UniqueKey();
Map? _arguments;
var _webViewController;
#override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
return widget.launchURL();
});
}
#override
Widget build(BuildContext context) {
_arguments = ModalRoute.of(context)!.settings.arguments as Map?;
if (_arguments?.containsKey("paymentUrl") == true) {
url = _arguments!["paymentUrl"];
} else if (_arguments?.containsKey("course_id") == true) {
url = _arguments!["course_id"];
} else {
print(url);
}
return Scaffold(
body: SplashPage(),
);
}
}
I hope I am being clear enough. I have been stuck for days now on this particular issue with it haunting me in my dreams too. Any help would be greatly appreciated.
I have an endpoint that returns data in the following JSON format.
{
"data": [
{
"balance": "40.000000"
}
]
}
I want to display the above balance into a wallet UI. I am having difficulty to display a single element that is not using controller formfield.
Below is additional code:
wallet_service.dart
Future<ApiResponse> getWalletBalance() async {
ApiResponse apiResponse = ApiResponse();
try {
String token = await getToken();
final response = await http.get(Uri.parse(wallet),
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer $token'
});
switch(response.statusCode){
case 200:
apiResponse.data = Wallet.fromJson(jsonDecode(response.body));
break;
case 401:
apiResponse.error = unauthorized;
break;
default:
apiResponse.error = somethingWentWrong;
break;
}
}
catch (e){
apiResponse.error = serverError;
}
return apiResponse;
}
walletui.dart
class _DashboardState extends State<Dashboard> {
Wallet? wallet;
bool loading = true;
GlobalKey<FormState> formKey = GlobalKey<FormState>();
//TextEditingController txtBalanceController = TextEditingController();
//int mybalance=0;
// get user detail
void getUserWallet() async {
ApiResponse response = await getWalletBalance();
if(response.error == null) {
setState(() {
wallet = response.data as Wallet;
//log('data: $wallet');
loading = false;
//txtBalanceController.text = wallet?.balance?? '';
});
}
else if(response.error == unauthorized){
logout().then((value) => {
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context)=>Login()), (route) => false)
});
}
else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('${response.error}')
));
}
}
#override
void initState() {
getUserWallet();
super.initState();
}
}
Wallet Model Class
class Wallet {
int? id;
String? balance;
Wallet({
this.id,
this.balance,
});
factory Wallet.fromJson(Map<String, dynamic> json){
return Wallet(
id: json['id'],
balance: json['balance'],
);
}
}
My goal is to store the balance in a variable wallet that I can execute in the UI and display that value.
Please follow this link call for api:https://github.com/JayswalViraj/Flutter-Login-With-Rest-API
Please you understand after implemente.
Becoming mad about a simple piece of code...
I have a class:
class Monkey {
final String uid;
final String email;
final String password;
final int registrationMethod;
final int accountCreationTime; //* in milliseconds
final String name;
final String nickname;
final int birthday; //* in milliseconds
final String phone;
final String countryCode;
final String codiceComune;
final String comune;
final String provincia;
final String regione;
final String cap;
final String sigla;
final String zona;
final String codiceCatastale;
final int popolazione;
final bool isRegistered;
final bool shareName;
final bool acceptedRules;
final String picUrl;
final int
userPicType; //* 1 - Email / 2 - Google / 3 - Facebook / 4 - Apple / 5 - File
const Monkey(
this.uid,
this.email,
this.password,
this.registrationMethod,
this.accountCreationTime,
this.name,
this.nickname,
this.birthday,
this.phone,
this.countryCode,
this.codiceComune,
this.comune,
this.provincia,
this.regione,
this.cap,
this.sigla,
this.zona,
this.codiceCatastale,
this.popolazione,
this.isRegistered,
this.shareName,
this.acceptedRules,
this.picUrl,
this.userPicType,
);
}
I have a variable:
static Monkey monkey = const Monkey(
'uid',
'email',
'password',
0,
0,
'name',
'nickname',
0,
'phone',
'countryCode',
'codiceComune',
'comune',
'provincia',
'regione',
'cap',
'sigla',
'zona',
'codiceCatastale',
0,
false,
false,
false,
'picUrl',
0);
I have a method to fill the variable:
Future<Monkey?> getMonkey() async {
try {
await _firestore
.collection('users')
.doc(getUID())
.get()
.then((DocumentSnapshot documentSnapshot) {
Map<String, dynamic> data =
documentSnapshot.data() as Map<String, dynamic>;
if (data.isNotEmpty) {
if (kDebugMode) {
print("Point 1");
}
return Monkey(
data['uid'],
data['email'],
data['password'],
data['registrationMethod'],
data['accountCreationTime'],
data['name'],
data['nickname'],
data['birthday'],
data['phone'],
data['countryCode'],
data['codiceComune'],
data['comune'],
data['provincia'],
data['regione'],
data['cap'],
data['sigla'],
data['zona'],
data['codiceCatastale'],
data['popolazione'],
data['isRegistered'],
data['shareName'],
data['acceptedRules'],
data['picUrl'],
data['userPicType']);
} else {
if (kDebugMode) {
print(
"La lettura di monkey non ha restituito dati, elsedella lettura Monkey.");
}
return null;
}
});
} catch (err) {
if (kDebugMode) {
print("Errore durante la lettura di Monke: " + err.toString());
}
return null;
}
if (kDebugMode) {
print(
"Point 2");
}
return null;
}
This is my execution:
Variables.monkey = (await _firebase.getMonkey())!;
As I can see my code fire Print Point 1 but also Print Point 2.
I printed data and it is filled successfully.
But I receive this error:
[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: Null check operator used on a null value
#0 _RegistrationScreenState.registerUser
package:whybye/screens/registration_screen.dart:345
edit:
Just removed any 'final' from Class Monkey, however same result.
The error is here:
Future<Monkey?> getMonkey() async {
try {
await _firestore
.collection('users')
.doc(getUID())
.get()
.then((DocumentSnapshot documentSnapshot) {
Map<String, dynamic> data =
documentSnapshot.data() as Map<String, dynamic>;
if (data.isNotEmpty) {
if (kDebugMode) {
print("Point 1");
}
return Monkey(
data['uid'],
data['email'],
data['password'],
data['registrationMethod'],
data['accountCreationTime'],
data['name'],
data['nickname'],
data['birthday'],
data['phone'],
data['countryCode'],
data['codiceComune'],
data['comune'],
data['provincia'],
data['regione'],
data['cap'],
data['sigla'],
data['zona'],
data['codiceCatastale'],
data['popolazione'],
data['isRegistered'],
data['shareName'],
data['acceptedRules'],
data['picUrl'],
data['userPicType']);
} else {
if (kDebugMode) {
print(
"La lettura di monkey non ha restituito dati, elsedella lettura Monkey.");
}
return null;
}
});
} catch (err) {
if (kDebugMode) {
print("Errore durante la lettura di Monke: " + err.toString());
}
return null;
}
if (kDebugMode) {
print(
"Point 2");
}
return null;
}
Where return Monkey is inside another process (await _firestore).
This mean the code is ok but I had to add:
Monkey monkey;
monkey = await _firestore...
return monkey(...)...
and outside the _firestore process return the real monkey...
Before I found the solution I tried tons of code and finally I switched to String:
Future<String> getMonkey() async {
String res;
try {
res = await _firestore
.collection('users')
.doc(getUID())
.get()
.then((DocumentSnapshot documentSnapshot) {
Map<String, dynamic> data =
documentSnapshot.data() as Map<String, dynamic>;
if (data.isNotEmpty) {
if (kDebugMode) {
print("I dati di Monkey non sono vuoti: ");
}
Monkey.uid = data['uid'];
Monkey.email = data['email'];
Monkey.password = data['password'];
Monkey.registrationMethod = data['registrationMethod'];
Monkey.accountCreationTime = data['accountCreationTime'];
Monkey.name = data['name'];
Monkey.nickname = data['nickname'];
Monkey.birthday = data['birthday'];
Monkey.phone = data['phone'];
Monkey.countryCode = data['countryCode'];
Monkey.codiceComune = data['codiceComune'];
Monkey.comune = data['comune'];
Monkey.provincia = data['provincia'];
Monkey.regione = data['regione'];
Monkey.cap = data['cap'];
Monkey.sigla = data['sigla'];
Monkey.zona = data['zona'];
Monkey.codiceCatastale = data['codiceCatastale'];
Monkey.popolazione = data['popolazione'];
Monkey.isRegistered = data['isRegistered'];
Monkey.shareName = data['shareName'];
Monkey.acceptedRules = data['acceptedRules'];
Monkey.picUrl = data['picUrl'];
Monkey.userPicType = data['userPicType'];
return 'success';
} else {
if (kDebugMode) {
print(
"La lettura di monkey non ha restituito dati, elsedella lettura Monkey.");
}
return 'error';
}
});
} catch (err) {
if (kDebugMode) {
print("Errore durante la lettura di Monkey: " + err.toString());
}
return 'error';
}
if (res == 'success') {
return 'success';
} else {
return 'error';
}
}
As you can see the real Return function is at bottom:
if (res == 'success') {
return 'success';
} else {
return 'error';
}
This error occurs when you use a bang operator (!) on a nullable instance which wasn't initialized.
Replace your execution with this:
var monkey = await _firebase.getMonkey();
if(monkey != null){
Variables.monkey = monkey;
}
I hope it would help you.
I want to send multiple string values from one smartphone device to another device via Bluetooth in flutter. I have seen flutter_blue and flutter_bluetooth_searial package examples also but i cant find anything that sends multiple strings values via Bluetooth. can anyone please suggest how i can be able to achieve this task?
I used flutter_bluetooth_searial in one of my projects, here is the the whole class including: sending data (multiple strings), receiving data, connect, disconnect, auto-pairing, ...etc
Hope you find this helpful.
import 'dart:async';
import 'dart:typed_data';
import 'dart:convert' show utf8;
import 'package:flutter/foundation.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class BluetoothStore extends ChangeNotifier {
var _instance = FlutterBluetoothSerial.instance;
var _dataBuffer = '';
void Function(String) _onDataCallback = (String data) {};
StreamSubscription<Uint8List> _dataSubscription;
StreamSubscription<BluetoothDiscoveryResult> _scannedDevicesSubscription;
BluetoothDiscoveryResult _connectedDevice;
BluetoothConnection _connection;
var name = "...";
var address = "...";
var pinNum = "1234";
var isScanning = false;
var _isConnecting = false;
var _autoPair = false;
var scannedDevices = List<BluetoothDiscoveryResult>();
var state = BluetoothState.UNKNOWN;
BluetoothStore() {
initBluetooth();
}
bool get autoPair => _autoPair;
bool get isConnecting => _isConnecting;
bool get isConnected => _dataSubscription != null;
set autoPair(bool value) {
_autoPair = value;
if (value) {
_instance.setPairingRequestHandler((request) {
if (request.pairingVariant == PairingVariant.Pin)
return Future.value(pinNum);
return Future.value("");
});
} else {
_instance.setPairingRequestHandler(null);
}
notifyListeners();
}
void initBluetooth() async {
// Get bluetooth initial state
this.state = await _instance.state;
this.address = await _instance.address;
this.name = await _instance.name;
notifyListeners();
_instance.onStateChanged().listen((state) {
this.state = state;
_reset();
});
}
Future<bool> pairWith(BluetoothDevice device) async {
var pairedDevices = await _instance.getBondedDevices();
if (pairedDevices.length < 7) {
var result = await _instance.bondDeviceAtAddress(device.address);
if (result) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
type: device.type,
bondState:
result ? BluetoothBondState.bonded : BluetoothBondState.none,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
}
return Future.value(result);
}
return Future.value(false);
}
// Notice the return value
Future<bool> unpairFrom(BluetoothDevice device) async {
var result = await _instance.removeDeviceBondWithAddress(device.address);
if (result) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
type: device.type,
bondState:
result ? BluetoothBondState.none : BluetoothBondState.bonded,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
}
return Future.value(result);
}
Future<bool> enable() => _instance.requestEnable();
Future<bool> disable() => _instance.requestDisable();
Future<void> openSettings() => _instance.openSettings();
Future<bool> connectTo(BluetoothDevice device) async {
_isConnecting = true;
if (isConnected) await _connection.close();
notifyListeners();
try {
var connection = await BluetoothConnection.toAddress(device.address);
_isConnecting = false;
_connection = connection;
_dataSubscription = connection.input.listen(_onDataReceived);
_dataSubscription.onDone(_onDisconnect);
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
_connectedDevice = scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
bondState: device.bondState,
type: device.type,
isConnected: true,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
return Future.value(true);
} catch (_) {
_isConnecting = false;
_dataSubscription = null;
_connection = null;
notifyListeners();
return Future.value(false);
}
}
Future<List<BluetoothDevice>> pairedDevices() async {
var result = await _instance.getBondedDevices();
return Future.value(result);
}
void disConnect() async {
if (isConnected) {
this.unpairFrom(_connectedDevice.device);
_connection.dispose();
}
}
void startScanning() {
isScanning = true;
scannedDevices.clear();
notifyListeners();
if (isConnected) scannedDevices.add(_connectedDevice);
_scannedDevicesSubscription = _instance.startDiscovery().listen((device) {
scannedDevices.add(device);
});
_scannedDevicesSubscription.onDone(() async {
isScanning = false;
notifyListeners();
});
}
void _onDataReceived(Uint8List data) {
// Allocate buffer for parsed data
var backspacesCounter = 0;
data.forEach((byte) {
if (byte == 8 || byte == 127) backspacesCounter++;
});
var buffer = Uint8List(data.length - backspacesCounter);
var bufferIndex = buffer.length;
// Apply backspace control character
backspacesCounter = 0;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i] == 8 || data[i] == 127) {
backspacesCounter++;
} else {
if (backspacesCounter > 0) {
backspacesCounter--;
} else {
buffer[--bufferIndex] = data[i];
}
}
}
// Create message if there is new line character
var dataString = String.fromCharCodes(buffer);
var index = buffer.indexOf(13);
if (~index != 0) {
// \r\n
var data = backspacesCounter > 0
? _dataBuffer.substring(0, _dataBuffer.length - backspacesCounter)
: _dataBuffer = _dataBuffer + dataString.substring(0, index);
_onDataCallback(data);
_dataBuffer = dataString.substring(index);
} else {
_dataBuffer = (backspacesCounter > 0
? _dataBuffer.substring(0, _dataBuffer.length - backspacesCounter)
: _dataBuffer + dataString);
}
}
void _onDisconnect() {
// reset
if (this.state == BluetoothState.STATE_ON) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == _connectedDevice.device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: _connectedDevice.device.name ?? '',
address: _connectedDevice.device.address,
type: _connectedDevice.device.type,
bondState: _connectedDevice.device.bondState,
),
rssi: _connectedDevice.rssi,
);
}
_reset();
}
void _reset() {
_dataBuffer = '';
_isConnecting = false;
_dataSubscription = null;
_scannedDevicesSubscription = null;
_connectedDevice = null;
_connection = null;
if (this.state != BluetoothState.STATE_ON) {
scannedDevices.clear();
}
notifyListeners();
}
void onDataReceived(void Function(String) callback) {
_onDataCallback = callback;
}
bool sendData(String data) {
try {
data = data.trim();
if (data.length > 0 && isConnected) {
_connection.output.add(utf8.encode(data + "\r\n"));
return true;
}
} catch (e) {
return false;
}
return false;
}
void dispose() {
_instance.setPairingRequestHandler(null);
if (isConnected) _dataSubscription.cancel();
_scannedDevicesSubscription?.cancel();
super.dispose();
}
}
You can consume this class using ChangeNotifierProvider
ChangeNotifierProvider<BluetoothStore>.value(value: BluetoothStore())