Peter
Peter

Reputation: 741

How to implement Android Background service in a NativeScript Angular project?

I'm trying to create a background service for nativescript-geolocation to get notifications when an event has been triggered.

I've found a lot of examples for the general NS version, but nothing for the Angular version and I can't find the way to implement it.

Currently, I'm getting Class "com.nativescript.location.BackgroundService" not found. error messages.

Services have been declared in the AndroidManifest.xml, deleted the platforms dir, and did a clean build.

<service android:name="com.nativescript.location.BackgroundService"
         android:exported="false" >
</service>
<service android:name="com.nativescript.location.BackgroundService26"
         android:permission="android.permission.BIND_JOB_SERVICE"
         android:enabled="true"
         android:exported="false">
</service>

I use this as a reference and trying to create the Angular version of this https://github.com/NativeScript/nativescript-geolocation/tree/master/demo

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";
import * as Toast from "nativescript-toast";

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) {
          let toast = Toast.makeText('Background Location: \n' + loc.latitude + ', ' + loc.longitude);
          toast.show();
          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);

export function getBackgroundServiceClass() {
  if (application.android) {
    if (device.sdkVersion < "26") {
      @JavaProxy("com.nativescript.location.BackgroundService")
      class BackgroundService extends (<any>android).app.Service {
        constructor() {
          super();
          return global.__native(this);
        }
        onStartCommand(intent, flags, startId) {
          console.log('service onStartCommand');
          this.super.onStartCommand(intent, flags, startId);
          return android.app.Service.START_STICKY;
        }
        onCreate() {
          console.log('service onCreate');
          _startWatch();
        }
        onBind(intent) {
          console.log('service onBind');
        }
        onUnbind(intent) {
          console.log('service onUnbind');
        }
        onDestroy() {
          console.log('service onDestroy');
          _clearWatch();
        }
      }
      return BackgroundService;
    } else {
      @JavaProxy("com.nativescript.location.BackgroundService26")
      class BackgroundService26 extends (<any>android.app).job.JobService {
        constructor() {
          super();
          return global.__native(this);
        }
        onStartJob(): boolean {
          console.log('service onStartJob');
          _startWatch();
          return true;
        }
        onStopJob(jobParameters: any): boolean {
          console.log('service onStopJob');
          this.jobFinished(jobParameters, false);
          _clearWatch();
          return false;
        }
      }
      return BackgroundService26;
    }
  } else {
    return null;
  }
}
export const BackgroundServiceClass = getBackgroundServiceClass();

app.component.tns.ts

import {Component, ElementRef, ViewChild} from '@angular/core';

import { BackgroundServiceClass } from "@src/background-service";


import { Page } from "tns-core-modules/ui/page";
const utils = require("tns-core-modules/utils/utils");
import * as application from "tns-core-modules/application";
import { device } from "tns-core-modules/platform";

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})

export class AppComponent {




  /* Background servie stuffs */
  page: Page;
  watchIds = [];
  jobId = 308; // the id should be unique for each background job. We only use one, so we set the id to be the same each time.
  com: any;

  constructor(

  ) {

  }

  ngOnInit(){


    application.on(application.exitEvent, this._stopBackgroundJob);


  }

  ngAfterViewInit(){

  }

  _stopBackgroundJob() {
    if (application.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}`);
      }
    }
  }

    startBackgroundTap() {
      if (application.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, BackgroundServiceClass.class);
          const builder = new (<any>android.app).job.JobInfo.Builder(this.jobId, component);
          builder.setOverrideDeadline(0);
          jobScheduler.schedule(builder.build());
        } else {
          let intent = new android.content.Intent(context, BackgroundServiceClass.class);
          context.startService(intent);
        }
      }
    }
}

AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android" package="__PACKAGE__" android:versionCode="13" android:versionName="1.31">
    <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

  <application android:name="com.tns.NativeScriptApplication" android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/AppTheme" android:windowSoftInputMode="adjustResize" android:hardwareAccelerated="true" android:networkSecurityConfig="@xml/network_security_config">
      <service android:name="com.nativescript.location.BackgroundService"
               android:exported="false" >
      </service>

      <service android:name="com.nativescript.location.BackgroundService26"
               android:permission="android.permission.BIND_JOB_SERVICE"
               android:enabled="true"
               android:exported="false">
      </service>
      <activity android:name="com.tns.NativeScriptActivity" android:label="@string/title_activity_kimera" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|locale|uiMode" android:theme="@style/LaunchScreenTheme">
            <meta-data android:name="SET_THEME_ON_LAUNCH" android:resource="@style/AppTheme" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.tns.ErrorReportActivity" />
    </application>
</manifest>

Upvotes: 0

Views: 1842

Answers (1)

KadoLakatt
KadoLakatt

Reputation: 43

For the problem you mention try this:

  1. Check your version of Nativescript and the version the example. Breaking changes between versions may be affecting. Try a downgrade to Nativescript 5, create a new project and paste your code.
  2. Then, try a clean build.

For Background Location Tracking, I suggest you to try Foreground Services combined with nativescript-geolocation plugin. Check this article is a well explained tutorial of the first topic:

https://dev.to/ozymandiasthegreat/android-continuous-background-services-with-nativescript-42c9

Repo link:

https://github.com/OzymandiasTheGreat/Nativescript-ServiceExample/blob/master/package-lock.json

Upvotes: 0

Related Questions