Categories
Tutorials

Let Geo location work on Hybrid Mobile Apps

I’ll focus on Geo location with Ionic framework but same is true for others (All of them that use cordova/phonegap in one way or the other such as nativscript, weex, quasar).

By Hybrid mobile apps I mean apps that uses web technologies and cordova to run native on handheld devices.

Using a native feature in Ionic is a two step process.
1. Install a cordova plugin
2. Install ionic wrapper

Developing an Ionic application is a breeze because they are easy to debug and test. Because they use web technogies so you can debug them like rest of your web apps using browser developer tools. Unlike nativescript which requires an emulator. The second line adds a wrapper which converts cordova plugin into a Promise. It also handle errors if app runs in non cordova based environment i-e browser.

Lets get user current coordinates.

this.geo.getCurrentPosition({timeout: 30000})
.then(location => {
  console.log(location.coords)
  //latitude:12.34567
  //longitude:01.01010
}.catch(error => {
  console.log(error)
}

Whenever an app encounters this code, it asks user to authorize the Geo location access as shown in following screenshot.

Request for Geo location authorization Ionic

If user allows Geo location access, code runs in then block. We get user’s current position, end of story. The catch block kicks in when user denies.

That’s all I have for you today. If you don’t want to go beyond happy case that leave right now.

But…..

Look at this thread. Here people are giving reference of increasing timeout to 60 seconds to get over this problem. But there is no winning reply to this thread because they are missing a very basic concept.

The above code snippet will sometimes return nothing. Both then and catch blocks can beskipped. Giving geo location access is useless if location is disabled from settings. That’s why there is {timeout:30000} which waits for thirty seconds. It’s like detecting the inbound aircraft when your radars are turned off.

That’s the whole purpose and motivation behind this article.

Enough with Diagnosing

Let’s come to the solution. To best explain things, I have created the following flow diagram. (click on the image for larger version and watch out all those cross references)

Resolve Geolocation cordova ionic

In steps it would be
1. Check Location permission
2. If app is authorized than check whether location setting is enabled
3. If location enabled true than you are set to go
4. From Step 1, if location is not authorized than requestLocationAuthorization
5. If it’s granted than we check whether location setting is enabled
6. If not than requestEnableLocation
7. As soon as user Agrees, we have fully working Geo location.

Solution

We need plugins such as Diagnostic and Request Location Accuracy Plugin. The latter one requests enabling/changing of Location Services by triggering a native dialog from within the app, avoiding the need for the user to leave your app to change location settings manually.

Request Location Services using native dialog ionic
Request location services using native dialog

There are many ways to achieve via code whatever mentioned in the chart above. I tried go the linear way like mentioned in the steps but there we some many if/else block and callback and all the cross referencing.

In order to better deal this async behavior I am gonna use async/await. Location is prerequisite in my case, otherwise app will not be usable.

private async detectGeolocation() {
  const locAuthorized = await this.diagnostic.isLocationAuthorized();
  const locAvailable = await this.diagnostic.isLocationAvailable();

  if (locAuthorized && locAvailable) {

    // You location is authorized you are good to go :)
    this.initApp();
  } else {
    // Looks like you have no access to GPS, you need to resolve Geo Location :(
  }
}

On line 2 and 3 I am using Ionic Native wrapper for cordova diagnostic plugin which converts it into nice Promise. Both of these two lines will return boolean which will stored in their associated variables. On Line 5 I am deciding whether to allow app usage ask user to resolve Geo location.

public async resolveGeolocation() {
  try {
    const reqLocAuthorization = await this.diagnostic.requestLocationAuthorization();
    const reqLocEnable = await this.requestEnableLocation();

    //We get following success codes from cordova.plugins.locationAccuracy
    //{message: "All location settings are satisfied.", code: 0}
    //{message: "User agreed to make required location settings changes.", code: 1}
    const codes: any = [0, 1];

    if (reqLocAuthorization === 'GRANTED' && codes.includes(reqLocEnable['code'])) {
      this.initApp();
    }

  } catch (error) {
    // Looks like you have diss-allowed GPS, you need to resolve Geo Location in order to use this app :(
  }

}

Try/Catch is used to handle errors in async function. Comments make the code snippet self explanatory.

The whole detection process as done detectGeolocation() can be skipped. We can directly request for Authorization and Enabling of Location Services. It will silently handle the detection and only prompt user if needed.

Conclusion

I was caught up in this problem for weeks. I didn’t had the general understanding of how Location services work. There is dichotomy between using geolocation on the web and that on native mobile apps. Kindly jump in if you seek room of improvement in this solution.

7 replies on “Let Geo location work on Hybrid Mobile Apps”

Imdad bhai has solved this long time ago. Hope your try to ask for help. So, you don’t have to struggle with these simple problems.

Actually these things and solution was flying around in my mind and I had to log it somewhere so they can be easily revisited.

Hello, nice Article.

I’ve written a code where i use requestRuntimePermission and switchToLocationSettings too, this code is recursive to call the function tryGeolocation when all will be ok .

https://github.com/jossephalvarez/Geo-location-Ionic-Recursive/blob/master/get-location.ts

The context: The page need location to get offers by lat/long, the user can’t enter if GPS. is not active.

Now I am thinking about to refactor this code with observable RXJS5 , because is the only part of my code where I use promises. I dont know if the performance will be better but i would like to achieve this flow with observables . If you want we can do it to get a nice example to the comunity .

Tell me what do you think about that .

Kind Regards

I think it would be smart.

Observable could make the code much smaller and readable. There are two If condition. I wish we could abstract the top level if condition.

That smart observable could automatically handle the Authorization and let us just to ask for Enable the location.

I can’t say much about php, I think we use JavaScript Geolocation Api to get access to user location. Later on you can send those geopoints to Server of your choice.

I’ve implemented this plugin code, But there is something very strange, it only works if the device GPS is already enabled before launching the app, if I enable it when app is running, it never fetches the location and hence always fall into error method. I’ve verified this behavior that If I run google maps and locate my self (before opening my app), then my app works without any issue, otherwise it keep falling into error method. Any help will be highly appreciated .

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.