here is my code for background task:
const String notificationChannelId = "foreground_service";
const int foregroundServiceNotificationId = 888;
const String initialNotificationTitle = "TRACK YOUR LOCATION";
const String initialNotificationContent = "Fetching location data";
const int timeInterval = 20; //in seconds
@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
DartPluginRegistrant.ensureInitialized();
// For flutter prior to version 3.0.0
// We have to register the plugin manually
SharedPreferences prefs = await SharedPreferences.getInstance();
String ownerEmail = prefs.getString('owner_email') ?? '';
int smartContractId = prefs.getInt('smart_contract_id') ?? 0;
String driverEmail = prefs.getString('driver_email') ?? '';
String devpubkey = prefs.getString('devpubkey') ?? '';
String primaryDevImei = prefs.getString('primary_device_imei') ?? '';
int activationDate1 = prefs.getInt('activation_date') ?? 0;
print('HHHHHEEEELLLLLLLLLLLL ${ownerEmail}');
if (service is AndroidServiceInstance) {
service.on('setAsForeground').listen((event) async {
await service.setAsForegroundService();
});
service.on('setAsBackground').listen((event) async {
await service.setAsBackgroundService();
});
}
// bring to foreground
final algorithm = Ed25519();
// if (service is AndroidServiceInstance) {
// if (await service.isForegroundService()) {
Timer.periodic(const Duration(seconds: timeInterval), (timer) async {
try {
Position pos = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
timeLimit: Duration(seconds: 30),
forceAndroidLocationManager: true,
);
// Save location data to shared preferences
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setDouble('latitude', pos.latitude);
prefs.setDouble('longitude', pos.longitude);
double latitude = pos.latitude;
double longitude = pos.longitude;
double unixTimeMilliseconds = DateTime
.now()
.millisecondsSinceEpoch / 1000.0;
dynamic activationDate = DateTime.fromMillisecondsSinceEpoch(
activationDate1);
print("This is act date $activationDate");
// Calculate the time difference in minutes between the current time and activation date
final timeDifference = activationDate
.difference(DateTime.now())
.inMinutes;
Map<String, String?> keys = await SessionManager.instance
.readKeyPair();
// на всякие случае
if (keys['private_key'] != null) {
String? privateKeyHex = keys['private_key'];
String? publicKeyHex = keys['public_key'];
final data = DataNew(
ownerEmail: ownerEmail,
email: driverEmail,
imei: primaryDevImei,
smartContractIds: smartContractId,
sw: true,
latitude: latitude,
longitude: longitude,
speed: pos.speed,
dateTime: unixTimeMilliseconds,
devpubkey: devpubkey,
production: true,
);
// print('My data ${jsonEncode(data)}');
print('Unix Time ${unixTimeMilliseconds}');
// print('Data is here ${jsonEncode(dataJson)}');
print('The data is ${data}');
print('This is my DateType ${DateTime
.now()
.runtimeType}');
// print('This is my imei ${inputData['imei']}');
// Initialize LocationApiClient and call sendLocationData method
print('My DateTime ${DateTime.now()}');
// LocationApiClient locationApiClient = LocationApiClient();
// Check if keys are not null
if (privateKeyHex == null || publicKeyHex == null) {
print('Keys not found!');
return;
}
// Convert Hex keys to bytes
List<int> privateKeyBytes = HEX.decode(privateKeyHex);
List<int> publicKeyBytes = HEX.decode(publicKeyHex);
// Prepare keys
SimplePublicKey publicKey = SimplePublicKey(
publicKeyBytes, type: KeyPairType.ed25519);
final keyPairData = SimpleKeyPairData(
privateKeyBytes, publicKey: publicKey, type: KeyPairType.ed25519);
print('Hello my key pair is this ${keyPairData}');
print('Hello my private key ${privateKeyHex}');
print('Hello my public key ${publicKeyHex}');
Map<String, dynamic> dataJson = data.dict();
dataJson['pubkey'] = HEX.encode(publicKeyBytes);
// Sort keys
var sortedKeys = dataJson.keys.toList(growable: false)
..sort((k1, k2) => k1.compareTo(k2));
Map<String, dynamic> sortedMap = Map<String, dynamic>.from(
Map.fromIterable(
sortedKeys, key: (k) => k, value: (k) => dataJson[k])
);
print('Data json before adding ${sortedMap}');
// Convert data to bytes
List<int> message = utf8.encode(json.encode(sortedMap));
print("iska ${jsonEncode(sortedMap)}");
// Sign the data
final signature = await algorithm.sign(
message,
keyPair: keyPairData,
);
print('Signature bytes for iska: ${HEX.encode(signature.bytes)}');
// Add signature and the public key to the data
sortedMap['signature'] = HEX.encode(signature.bytes);
print('Sorted map ${json.encode(sortedMap)}');
// BackgroundTask backgroundTask = BackgroundTask.fromJson(sortedMap);
final mySignature = HEX.encode(signature.bytes);
final data2 = BackgroundTask(
driverEmail: driverEmail,
imei: primaryDevImei,
ownerEmail: ownerEmail,
smartContractId: smartContractId,
sw: true,
positionLatitude: latitude,
positionLongitude: longitude,
pubkey: publicKeyHex,
speed: pos.speed,
timestamp: unixTimeMilliseconds,
signature: mySignature,
devpubkey: devpubkey,
production: true,
);
print('This is data2 $data2');
LocationApiClient locationApiClient = LocationApiClient();
// Use new method here to prepare data with 'tx'
Map<String, dynamic> sortedData = locationApiClient.prepareDataWithTx(
data2);
// Print the sorted data to verify if it's correctly structured
print('Hello this is sorted data with tx $sortedData');
print('Sorted data $data2');
// Check if there are less than 5 minutes remaining until activation date
if (timeDifference <= 5.0) {
// Your code to send the location data
try {
// Call sendLocationData with sortedData
final sorted = jsonEncode(sortedData);
print('Eskendir ${sorted}');
String statusCode = await locationApiClient.sendLocationData(
sorted);
print(
'Background task data sent successfully! Response.body: $statusCode');
print('Activation date is : ${activationDate1}');
} catch (e) {
// Handle error when sending the location data
print('Failed to send background task data: $e');
}
if (!(await Geolocator.isLocationServiceEnabled())) {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'channel_id',
'channel_name',
importance: Importance.high,
priority: Priority.high,
ticker: 'ticker',
);
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
'GPS is not enabled',
'Please enable GPS',
platformChannelSpecifics,
payload: 'open_settings',
);
}
final connectivity = Connectivity();
connectivity.onConnectivityChanged.listen((
ConnectivityResult result) async {
if (result == ConnectivityResult.none) {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'channel_id',
'channel_name',
importance: Importance.high,
priority: Priority.high,
ticker: 'ticker',
);
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
'Failed to connect Internet',
'Please enable Internet',
platformChannelSpecifics,
);
}
});
}
print('Json encoded ${jsonEncode(dataJson)}');
}
await Duration(seconds: 35);
}
catch (e, s) {
if (!(await Geolocator.isLocationServiceEnabled())) {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'channel_id',
'channel_name',
importance: Importance.high,
priority: Priority.high,
ticker: 'ticker',
);
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
'GPS is not enabled',
'Please enable GPS',
platformChannelSpecifics,
payload: 'open_settings',
);
}
final connectivity = Connectivity();
connectivity.onConnectivityChanged.listen((
ConnectivityResult result) async {
if (result == ConnectivityResult.none) {
const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails(
'channel_id',
'channel_name',
importance: Importance.high,
priority: Priority.high,
ticker: 'ticker',
);
const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
'Failed to connect Internet',
'Please enable Internet',
platformChannelSpecifics,
);
}
});
}
/////
Geolocator.getPositionStream().listen((Position position) async {
final permission = await Geolocator.checkPermission();
if (permission == LocationPermission.always) {
service.invoke('on_location_changed', position.toJson());
}
});
});
// }
// }
service.on("stop_service").listen((event) async {
await service.stopSelf();
});
// final secureStorage = FlutterSecureStorage();
// while (true) {
//
// await Future.delayed(Duration(seconds: 60));
// }
}
@pragma("vm:entry-point")
Future<bool> iosBackground(ServiceInstance service)async{
WidgetsFlutterBinding.ensureInitialized();
DartPluginRegistrant.ensureInitialized();
return true;
}
class BackgroundService {
//Get instance for flutter background service plugin
final FlutterBackgroundService flutterBackgroundService =
FlutterBackgroundService();
FlutterBackgroundService get instance => flutterBackgroundService;
Future<void> initializeService() async {
await NotificationService(FlutterLocalNotificationsPlugin()).createChannel(
const AndroidNotificationChannel(
notificationChannelId, notificationChannelId));
await flutterBackgroundService.configure(
androidConfiguration: AndroidConfiguration(
// this will be executed when app is in foreground or background in separated isolate
onStart: onStart,
// auto start service
autoStart: false,
isForegroundMode: true,
notificationChannelId: notificationChannelId,
foregroundServiceNotificationId: foregroundServiceNotificationId,
initialNotificationTitle: initialNotificationTitle,
initialNotificationContent: initialNotificationContent,
),
//Currently IOS setup is not completed.
iosConfiguration: IosConfiguration(
// auto start service
autoStart: true,
// this will be executed when app is in foreground in separated isolate
onBackground: iosBackground,
onForeground: onStart
),
);
await flutterBackgroundService.startService();
}
void setServiceAsForeGround() async {
flutterBackgroundService.invoke("setAsForeground");
}
void stopService() {
flutterBackgroundService.invoke("stop_service");
}
}
It perfectly works on Android, but on IOS it is not works. In console I have these errors: "Could not schedule app refresh: Error Domain=BGTaskSchedulerErrorDomain Code=3 "(null)" Could not schedule app refresh: Error Domain=BGTaskSchedulerErrorDomain Code=3 "(null)""
So, how can I fix it? Please help me XD