how to register background task for IOS? I need to get current geolocation and send it. In flutter

85 Views Asked by At

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

0

There are 0 best solutions below