Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

How to use the background-services work - nativescript/angular/android (i don't understand how to use them properly) #242

@AlexMCon

Description

@AlexMCon

I'm using this geolocation-plugin (https://github.com/NativeScript/nativescript-geolocation/tree/e125998c07ced42a215aca1a8feac1b7dbe7b6d6) to get constant location updates while app is in the background.

I tried using the code in the demo, but I'm not figuring out how to make it work.

I would like the user to press a button and the app to start monitoring his location, even if the app goes in the background.

home.component.ts

import { Component, OnInit, AfterViewInit } from "@angular/core";
import { RadSideDrawer } from "nativescript-ui-sidedrawer";
import { getRootView } from "tns-core-modules/application";
import * as app from "tns-core-modules/application";
const utils = require("tns-core-modules/utils/utils");
import { device } from "tns-core-modules/platform";


//import { GeolocationService } from "../services/geolocation/geolocation.service";


@Component({
    selector: "Home",
    moduleId: module.id,
    templateUrl: "./home.component.html"
})
export class HomeComponent implements OnInit {

    public drawer: RadSideDrawer;
    public buttonText = "Start";

    locations = [];
    watchIds = [];
    jobId = 308;
    
    constructor(
        public geolocationService: GeolocationService,
    ) {}

    ngOnInit(): void {
        app.on(app.exitEvent, this._stopBackgroundJob);
    }


    ngAfterViewInit() {
        this.drawer = <RadSideDrawer>getRootView();
        this.drawer.gesturesEnabled = true;
    }

    onDrawerButtonTap(): void {
        const sideDrawer = <RadSideDrawer>app.getRootView();
        sideDrawer.showDrawer();
    }


    _stopBackgroundJob() {
        if (app.android) {
            let context = utils.ad.getApplicationContext();
            const jobScheduler = context.getSystemService((<any>android.content.Context).JOB_SCHEDULER_SERVICE);
            if (jobScheduler.getPendingJob(this.jobId) !== null) {
                jobScheduler.cancel(this.jobId);
                console.log(`Job Canceled: ${this.jobId}`);
            }
        }
    }
    
    checkLoc(){
        this.geolocationService.buttonGetLocationTap()
    }


    _onGeolocationService(){
        this.geolocationService.enableLocation()
        .then(result => {
            this.geolocationService.monitorLocation();
            
            if(this.geolocationService.locationMonitor === true){
                this.buttonText = "Stop";
            } else {
                this.buttonText = "Start";
            }

        })
    }

    public startBackgroundTap() {
        if (app.android) {
            let context = utils.ad.getApplicationContext();
            if (device.sdkVersion >= "26") {
                const jobScheduler = context.getSystemService((<any>android.content.Context).JOB_SCHEDULER_SERVICE);
                const component = new android.content.ComponentName(context, com.nativescript.location.BackgroundService26.class);
                const builder = new (<any>android.app).job.JobInfo.Builder(this.jobId, component);
                builder.setOverrideDeadline(0);
                return jobScheduler.schedule(builder.build());
            } else {
                let intent = new android.content.Intent(context, com.nativescript.location.BackgroundService.class);
                context.startService(intent);
            }
        }
    }

    public stopBackgroundTap() {
        if (app.android) {
            if (device.sdkVersion >= "26") {
                this._stopBackgroundJob();
            } else {
                let context = utils.ad.getApplicationContext();
                let intent = new android.content.Intent(context, com.nativescript.location.BackgroundService.class);
                context.stopService(intent);
            }
        }
    }

}

geolocation.service.ts

import { Injectable } from '@angular/core';
import * as geolocation from "nativescript-geolocation";
import { Accuracy } from "tns-core-modules/ui/enums";

@Injectable({
  providedIn: 'root'
})
export class GeolocationService {

  locations= [];
  watchIds = [];

  constructor() { }

  public enableLocation() {
    return geolocation.enableLocationRequest();
  }

  public checkIfLocationIsEnabled() {
    geolocation.isEnabled()
    .then(function (isEnabled) {
      if(isEnabled) {
        return true;
      } else {
        return false;
      }
    })
  }

  public buttonGetLocationTap() {
    let that = this;
    geolocation.getCurrentLocation({
        desiredAccuracy: Accuracy.high,
        iosAllowsBackgroundLocationUpdates: true,
        iosPausesLocationUpdatesAutomatically: false,
        iosOpenSettingsIfLocationHasBeenDenied: true,
        maximumAge: 5000,
        timeout: 10000,
        updateTime: 10000,
    }).then(function (loc) {
      console.log(loc["latitude"], loc["longitude"])  
      if (loc) {
            that.locations.push(loc);
        }
    }, function (e) {
        console.log("Error: " + (e.message || e));
    });
}

  public buttonStartTap() {
      try {
          let that = this;
          that.watchIds.push(geolocation.watchLocation(
              function (loc) {
                  if (loc) {
                      that.locations.push(loc);
                  }
              },
              function (e) {
                  console.log("Error: " + e.message);
              },
              {
                  desiredAccuracy: Accuracy.high,
                  iosAllowsBackgroundLocationUpdates: true,
                  iosPausesLocationUpdatesAutomatically: false,
                  iosOpenSettingsIfLocationHasBeenDenied: true,
                  maximumAge: 7000,
                  timeout: 9000,
                  updateTime: 9000,
              }));
      } catch (ex) {
          console.log("Error: " + ex.message);
      }
  }

  public buttonStopTap() {
    let watchId = this.watchIds.pop();
    while (watchId != null) {
        geolocation.clearWatch(watchId);
        watchId = this.watchIds.pop();
    }
  }


  public buttonClearTap() {
    this.locations.splice(0, this.locations.length);
  }
}

background.service.ts

import * as geolocation from "nativescript-geolocation";
import { Accuracy } from "tns-core-modules/ui/enums";
import * as application from "tns-core-modules/application";
import { device } from "tns-core-modules/platform";

let watchId;

function _clearWatch() {
    if (watchId) {
        geolocation.clearWatch(watchId);
        watchId = null;
    }
}

function _startWatch() {
    geolocation.enableLocationRequest().then(function () {
        _clearWatch();
        watchId = geolocation.watchLocation(
            function (loc) {
                if (loc) {
                    console.log('Background Location: ' + loc.latitude + ' ' + loc.longitude);
                }
            },
            function (e) {
                console.log("Background watchLocation error: " + (e.message || e));
            },
            {
                desiredAccuracy: Accuracy.high,
                updateDistance: 1.0,
                updateTime: 3000,
                minimumUpdateTime: 100
            });
    }, function (e) {
        console.log("Background enableLocationRequest error: " + (e.message || e));
    });
}

application.on(application.exitEvent, _clearWatch);

if (application.android) {
    if (device.sdkVersion < "26") {
        (<any>android.app.Service).extend("com.nativescript.location.BackgroundService", {
            onStartCommand: function (intent, flags, startId) {
                this.super.onStartCommand(intent, flags, startId);
                return android.app.Service.START_STICKY;
            },
            onCreate: function () {
                _startWatch();
            },
            onBind: function (intent) {
                console.log("on Bind Services");
            },
            onUnbind: function (intent) {
                console.log('UnBind Service');
            },
            onDestroy: function () {
                console.log('service onDestroy');
                _clearWatch();
            }
        });
    } else {
        (<any>android.app).job.JobService.extend("com.nativescript.location.BackgroundService26", {
            onStartJob() {
                console.log('service onStartJob');
                _startWatch();
                return true;
            },
            onStopJob(jobParameters: any) {
                console.log('service onStopJob');
                this.jobFinished(jobParameters, false);
                _clearWatch();
                return false;
            },
        });
    }
}

Firstly, there is a problem with the 'com' namespace as it says "Property 'nativescript' does not exist on type 'typeof com' ". The problem appears in the home.component.ts on these 3 lines:

const component = new android.content.ComponentName(context, com.nativescript.location.BackgroundService26.class);
let intent = new android.content.Intent(context, com.nativescript.location.BackgroundService.class);
let intent = new android.content.Intent(context, com.nativescript.location.BackgroundService.class);

Secondly, I don't know what is the purpose of background-service as it i not used anywhere in the demo (or maybe it is, but in a way that I'm not familiar with).

Thank you!

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions