background geolocation image

Nativescript Geolocation in the background for Android

Introduction for background geolocation

One question I see thrown around a lot is “How can I record a geolocation in the background?”. I see it in nativescript forums, stack overflow and on comments of blog posts.

I found no good resource that explained a modern approach to record background geolocation in nativescript especially since the Background Execution Limits that android implements in Android 8.0.

So this is the perfect guide! (Until android change their restrictions again)

By the end of reading this you will be able to record and receive locations when the app is in the background to use in whatever way you need.

Nativescript and Angular is the framework and flavour we will use for this tutorial. If you have not used Nativescript Angular before then use this guide to get started.

Outline

  • Android Foreground service
  • Nativescript Geolocation plugin

Creating a new app

Once you have the Nativescript setup complete open a new terminal window and enter.

tns create geolocation-app --template tns-template-blank-ng

Note: tns-template-blank-ng makes a blank nativescript app easier to display for this tutorial.

Once the app has finished setting up navigate into the new project and run the app.

cd geolocation-app
tns run android

Setting up Nativescript Geolocation

Install the geolocation plugin:

tns plugin add nativescript-geolocation

Request access to location:

Navigate to src/app/home.home.component.ts

Add imports for the geolocation plugin:

import * as geolocation from "nativescript-geolocation";

Within ngOnInit add the following:

geolocation.isEnabled().then((isEnabled) => {
    if (!isEnabled) {
        geolocation.enableLocationRequest(true, true).then(() => {
            console.log("User Enabled Location Service");
        }, (e) => {
            console.log("Error: " + (e.message || e));
        }).catch(ex => {
            console.log("Unable to Enable Location", ex);
        });
    }
}, (e) => {
    console.log("Error: " + (e.message || e));
});

The geolocation.isEnabled() initially checks whether the user has already accepted the popup so it will stop the function from re running blocking potential errors.

If geolocation is not enabled then the user will be prompted to accept triggered by the geolocation.enableLocationRequest function.

Add location watcher

Navigate to src/app/home/home.component.ts and add two new functions:

import { Accuracy } from "tns-core-modules/ui/enums";

.......
geolocationWatchId: number;
locations = [];

.......
// Geolocation tracking location start
locationTrackStart() {
    this.geolocationWatchId = geolocation.watchLocation(
        (loc) => {
            this.locations.push(loc)
        },
        (error) => {
            console.log("error: ", error)
        },
        {
            desiredAccuracy: Accuracy.high,
            updateDistance: 25,
            updateTime: 10000,
            minimumUpdateTime: 5000
        }
    );
}

// Clear geolocationWatchId to stop tracking
clearLocationTracker() {
    geolocation.clearWatch(this.geolocationWatchId);
}

The function locationTrackStart() is used to initially trigger the tracking of the device location. Once a successful location has been received we are pushing it to an array of locations. This will be used for displaying on the home.component.html

home.component.html

<ActionBar class="action-bar">
    <Label class="action-bar-title" text="Home"></Label>
</ActionBar>

<GridLayout class="page" rows="auto, *">
    <!-- Add your page content here -->
    <Button text="Start recording location" (tap)="locationTrackStart()"></Button>

    <ListView row="2" [items]="locations">
        <ng-template let-item="item">
            <Label text="{{ item.latitude + ', ' + item.longitude + ', ' + item.altitude }}" ></Label>
        </ng-template>
    </ListView>
</GridLayout>

Also its best to clear the location tracker to stop repeating loops. Here it is done on ngOnDestroy but you can handle it as you like.

ngOnDestroy() {        this.clearLocationTracker();    }

Now you can try it out!

Save the files and run the app. Accept location permissions and start tracking. It should look like this:

Geolocation app Homepage

Foreground Service

The foreground service the magic piece the makes background location tracking possible. It runs the app and keeps all js processes running which can include in our case the geolocation tracking.

Add a new file in the src/app folder called foreground-service.android.ts and add the following code:

@JavaProxy('org.nativescript.geolocation.ForegroundService')
class ForegroundService extends android.app.Service {
    onStartCommand(intent, flags, startId) {
        console.log('onStartCommand')
        super.onStartCommand(intent, flags, startId);
        return android.app.Service.START_STICKY;
    }

    onCreate() {
        console.log('onCreate')
        super.onCreate();
        this.startForeground(1, this.getNotification());
    }

    onBind(intent) {
        return super.onBind(intent);
    }

    onUnbind(intent) {
        return super.onUnbind(intent);
    }

    onDestroy() {
        console.log('onDestroy')
        this.stopForeground(true);
    }

    private getNotification() {
        const channel = new android.app.NotificationChannel(
            'channel_01',
            'ForegroundService Channel',
            android.app.NotificationManager.IMPORTANCE_DEFAULT
        );
        const notificationManager = this.getSystemService(android.content.Context.NOTIFICATION_SERVICE) as android.app.NotificationManager;
        notificationManager.createNotificationChannel(channel);
        const builder = new android.app.Notification.Builder(this.getApplicationContext(), 'channel_01');

        return builder.build();
    }
}

This is the foreground service but we need to initiate this.
Go to app.component.ts and add the following:

constructor() {
    app.on(app.exitEvent, () => {
        this.stopForegroundService();
    });
    this.startForegroundService();
}

private startForegroundService() {
    const context = app.android.context;
    const intent = new android.content.Intent();
    intent.setClassName(context, 'org.nativescript.geolocation.ForegroundService');
    context.startForegroundService(intent);
}

private stopForegroundService() {
    const context = app.android.context;
    const intent = new android.content.Intent();
    intent.setClassName(context, 'org.nativescript.geolocation.ForegroundService');
    context.stopService(intent);
}

You will need to import this:

import * as app from "tns-core-modules/application";

You may see errors on the “android.content.Intent()” saying “cannot find android”. This is because currently our codebase cannot understand the native platform types. We need to add Nativescript platform declarations so that we can correctly avoid these typings errors.

npm i tns-platform-declarations --save-dev

Next add a new file called references.d.ts in src/app and add the following lines:

/// <reference path="./../node_modules/tns-platform-declarations/ios.d.ts" />
/// <reference path="./../node_modules/tns-platform-declarations/android-26.d.ts" />

Next we add a service for the foreground service in our AndroidManifest.xml found in app_resources/android/src/main/ add this below the final <activity> inside the <application> tags

<service
android:name="org.nativescript.geolocation.ForegroundService"
    android:enabled="true"
    android:stopWithTask="true"
    android:exported="false" />

Also add permissions for using a foreground service:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Final step: Add custom service to the webpack config so it builds and runs correctly. Add this to your appComponents constant.

Before:
const appComponents = [
"tns-core-modules/ui/frame",
"tns-core-modules/ui/frame/activity",
];
After:
const appComponents = [
"tns-core-modules/ui/frame",
"tns-core-modules/ui/frame/activity",
resolve(__dirname, "./src/foreground-service.android")
];

Conclusion

Following these steps will give you background location tracking capabilities in a modern best practice approach. This screen shot shows that the location marker in the top bar is there so the locations are still tracking. You can even console.log out the locations as you track them to see it in action as it happens.
I hope this guide helps you achieve background location tracking using Nativescript Angular and Geolocation on Android.

The full version of this app is downloadable from our store here. Check out the rest of our blog and also checkout items in the shop if you want to see what other themes and apps we have on offer

nativescript charity app

How I made a prize winning app with Nativescript

Introduction

The latest Nativescript held hackathon just concluded and the winning theme is available on this website right now.

I’ve released this theme here to help others to learn from the code if you are just starting in Nativescript or have been using it for years.

Structure

The app is made up of 4 pages:

  • Home page (containing facts and information around Plastic Oceans UK)
  • Donation/Map Page (containing a link to donate and the map page)
  • Map (containing nearby locations of recycling center)
  • Tracker page (containing a tracker to track the amount you have recycled)

Initially, I started with research. I used common design inspiration websites like Dribbble and Muzli. I use these a lot to keep on top of current trends, gain insight into what designers are using and why they make certain decisions. By using these tools I got some ideas around layout and a colour palette.

After I came up with an idea it was time to start. I began by thinking of all the types of pages I wanted, what I wanted to show and any unique features that could be added that fit the charity.

The first unique page was a map of local recycling, this came from an idea of how you can make someones life simpler in order to find a place to recycle. A recycling tracker came next as I thought this would fit the charity perfectly. I did research into the impact of plastic in our oceans today in order to find the factual information included on the homepage. Finally I included a link to donate to the charity as that would be one of the most impactful things users of the app could do.

Conclusion

After entering I was actually in attendance at Angular Connect in London, UK when the winners where announced and to my surprise the app I had made won the main prize!

This app was created by me but for the community and to spread the word about the charity’s message. I want people to be able to take as much as the can from this. Whether it is from a code perspective or whether it is to donate themselves.

So go and download it. Give it a try. Let me know what you think!

Should I add anything? Should I change anything? I want to hear your feedback. Overall if you downloaded the app code and learnt anything that is the main goal.

app native roadmap

What does the future of AppNative look like?

We wanted to talk today about the roadmap for AppNative and show you what is to come. There are a lot of exciting projects underway at the moment that we think you will all want to hear about. 

Lets start by showing an overview: 

app native roadmap
AppNative Roadmap

This outlines a high level view of what’s to come, some being already decided and some still being in the works.

This year we will focus on continuing to produce high quality Nativescript themes for our users to be able to learn from best practice and highly thought over design code. 

Towards the end of the year and into 2020 we will focus our thoughts in tutorials. We recognise there is documentation on the specific components and practices made up within Nativescript, but we see a lack of design. We want to show you how you can turn the normal components into useful practical uses for your apps. This is what we aim to teach and show in future. 

Pushing further into 2020 we have some very exciting potential projects: 

  • Conversations with the experts, the people that know the reason why a button is large and why a button is small. This will be another great learning resource.
  • Venture into other areas of development but still within the app development world. We want to look at AI and Machine learning and how that can be achieved and utilised within your app. 
  • We will also potentially explore other languages/ frameworks like flutter or React Native

Our aim is that AppNative will become the place you go to for design expertise and knowledge and how you can transform your app into the best version of itself. 

Get in touch

This can all be helped by you! Let us know any feedback and be active with suggestions if you have some.

We have created a new Slack channel within the Nativescript Community Slack channel if you have not signed up yet you can here: https://www.nativescript.org/slack-invitation-form. Once signed up, just search for appnative within the channels available, thats it!

Be sure to get in contact with us here

How to 10x your Android app speed!

When I started in Android and iOS app development I came from a web development environment and this both benefits and halts the creation of mobile apps. You can take your same design, creativity and basic layout skills across but when it comes to native mobile specific details this does not cross. 

When I started I also did not have time to learn the fundamentals as project deadlines took priority.

One of the core fundamentals I came to learn was the GPU overdraw feature in the android dev tools. This turned out to be the greatest find and a massive boost to our app at the time. At the time we had a successful non-laggy iOS app but with the same code and styles our android app was struggling, big time!

After some research (playing around) in the android dev tools I came across GPU overdraw when selecting the “show on screen” option I was greeted with a whole new world of green, blue and a lot of red! If you know anything about GPU overdraw red is not good.

Lets take a look into what this is showing:

android-overdraw-device

To explain:

android-overdraw-colours

The easiest way I found to visualise this is as follows. Imagine the app’s design as a cake with many layers, for each background or border you add to an element you add another layer to the cake. Now normally have many layers of cake is great! But like I said the app world is like the 4th dimension, a totally different world! In app development having many layers is not good and results in lower performance.

The phone has to re-draw all of the layers when scrolling and loading the app. When scrolling with many layers the app feels laggy as if you are dragging it through mud.  The app is redrawing all the layers for every pixel you are scrolling. Having to redraw multiple requires more resource. So the more layers you have, the laggier the app becomes. Simple, right!?

So how do I fix this, you ask?

Well, great question! The simple answer is: Reduce any unneeded background colours or borders.

If the background of your app is white and you are setting another layer on top of it to have a white background you are doing double the work. remove that extra white background on top. if you are only using a border bottom or only using a border top replace it with a StackLayout with a background of 1px height to create the same effect but only effecting 1px instead of the entire height of the element.

Add to cart