I am using Ionic together with the native Geolocation plugin to retrieve user position and sort a list of position by closest to the user.
The Geolocation plugin works perfectly using ionic serve or ionic lab as well as iOS devices but it does not work on Android devices (nor simulator).
What other solution can I use to retrieve longitude and latitude of the user?
I'll attach the class where I use the Geolocation plugin here.
The Location class I access has a public static variable where I store the userLocation since will be modified in more classes.
this.Location.load just uses the user position to call a method in Location class to sort the list of places.
import { Component } from '#angular/core';
import { ModalController, NavController, NavParams } from 'ionic-angular';
import { SharePopup } from '../share-popup/share-popup';
import { InAppBrowser } from 'ionic-native';
import { CamhsPage } from '../camhs-page/camhs-page';
import { Locations } from '../../providers/locations';
import { Platform } from 'ionic-angular';
import { Geolocation } from 'ionic-native';
#Component({
selector: 'contact',
templateUrl: 'contact.html'
})
export class Contact {
userPosition = [0, 0];
constructor(public navCtrl: NavController, public navParams: NavParams,
public modalCtrl: ModalController, public locations: Locations,public platform: Platform) {
}
openCamhsPage(){
this.platform.ready().then(() => {
let options = {
timeout: 10000,
enableHighAccuracy: true
};
Geolocation.getCurrentPosition(options).then((data) => {
Locations.userPosition[0] = Math.round(data.coords.latitude * 100)/100;
Locations.userPosition[1] = Math.round(data.coords.longitude * 100)/100;
// console.log("CONTACT "+Locations.userPosition);
});
});
this.locations.load();
this.navCtrl.push(CamhsPage);
console.log("CONTACT "+Locations.userPosition);
}
//Open WebPage
openPage(url) {
new InAppBrowser(url, '_system');
}
}
Prerequisite : Check whether you have switch ON your GPS service in Android.
Also it is good to have Success and Error Callbacks to identify the actual Error. Something like below :
..........
// Success callback for get geo coordinates
var onSuccess = function (data) {
Locations.userPosition[0] = Math.round(data.coords.latitude * 100)/100;
Locations.userPosition[1] = Math.round(data.coords.longitude * 100)/100;
}
var onError = function (data) {
console.log("Not Able to get Geolocation");
}
openCamhsPage(){
this.platform.ready().then(() => {
Geolocation.getCurrentPosition(onSuccess, onError, { enableHighAccuracy: true });
this.locations.load();
this.navCtrl.push(CamhsPage);
console.log("CONTACT "+Locations.userPosition);
}
.......
.......
Related
TLDR: Ibeacon module example does not work
I have a small app in Ionic 5 using capacitor.
I want to use the Ibeacon library, but I get the error :
Ressource for the library is scarse and I have only found people having issue when the delegate is undefined causing the LocatonManager error here.
I also tried to look what is causing the error, apparently the device mentioned is part of the device library. So I check if the Ibeacon library properly import the device one and it does in node_modules\cordova-plugin-ibeacon\plugin.xml, like so :
<!-- Version is set to anything because the only feature we use is the device.platform property which was available
since forever. The added benefit is that we don't force the consumers of this plugin to use a certain version of
the device plugin. -->
<dependency id="cordova-plugin-device" version="*" />
My class is pretty much the example given in the Ibeacon page:
import { Component, OnInit } from '#angular/core';
import { IBeacon } from '#ionic-native/ibeacon/ngx';
import { Platform } from '#ionic/angular';
#Component({
selector: 'app-beacon',
templateUrl: './beacon.page.html',
styleUrls: ['./beacon.page.scss'],
})
export class BeaconPage implements OnInit {
public beacons: any[] = [];
constructor(
private ibeacon: IBeacon,
private platform: Platform,
private _utils: UtilsService
) {}
ngOnInit() {
console.log('ngOnInit');
if (!this.platform.is('android')) {
console.log('Beacon related activity only available on Android');
return;
}
// create a new delegate and register it with the native layer
let delegate = this.ibeacon.Delegate();
console.log('delegate :', delegate);
// Subscribe to some of the delegate's event handlers
delegate.didRangeBeaconsInRegion().subscribe(
(data) => console.log('didRangeBeaconsInRegion: ', data),
(error) => console.error()
);
delegate.didStartMonitoringForRegion().subscribe(
(data) => console.log('didStartMonitoringForRegion: ', data),
(error) => console.error()
);
delegate.didEnterRegion().subscribe((data) => {
console.log('didEnterRegion: ', data);
});
let beaconRegion = this.ibeacon.BeaconRegion(
'deskBeacon',
'F7826DA6-ASDF-ASDF-8024-BC5B71E0893E'
);
this.ibeacon.startMonitoringForRegion(beaconRegion).then(
() => console.log('Native layer received the request to monitoring'),
(error) =>
console.error('Native layer failed to begin monitoring: ', error)
);
}
}
Also I imported the IBeacon module inside my module.ts like so :
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { IonicModule } from '#ionic/angular';
import { BeaconPageRoutingModule } from './beacon-routing.module';
import { BeaconPage } from './beacon.page';
import { IBeacon } from '#ionic-native/ibeacon/ngx';
#NgModule({
imports: [CommonModule, FormsModule, IonicModule, BeaconPageRoutingModule],
declarations: [BeaconPage],
providers: [IBeacon],
})
export class BeaconPageModule {}
Did I forget to do something ? Why is device undefined ? Should I also import the device library ?
I should mention I have the device library installed.
Inside the lib they use the device to check the plataform, that is the code:
BeaconRegion.isValidUuid = function (uuid) {
// https://github.com/petermetz/cordova-plugin-ibeacon/issues/328
// If we are on Android, then allow the UUID to be specified as a wild-card (omitted)
var isAndroid = device && device.platform === "Android";
if (uuid === BeaconRegion.WILDCARD_UUID && isAndroid) {
return true;
}
var uuidValidatorRegex = this.getUuidValidatorRegex();
return uuid.match(uuidValidatorRegex) != null;
};
You can check right here https://github.com/petermetz/cordova-plugin-ibeacon/blob/270ffbbc12159861a16e5e81481103c1e09139cb/www/model/BeaconRegion.js#L38
So, you have to install the following plugin-in https://ionicframework.com/docs/native/device
npm install cordova-plugin-device
npm install #ionic-native/device
ionic cap sync
Then the find this device reference and the problem will be solved.
I'm trying to get coordinates of my device location using the cordova geolocation plugin.
When running the app on android (10), I get prompted for location permissions which I set to always allow and after that my getLocation function gets executed but I don't get any of the additional feedback which I programmed in to suggest that it has actually received coordinates.
For the moment don't focus on the loadMap component, my focus currently is to retrieve coordinates,
I already did the import in app.module.ts
This is my home.page.ts
(For debug purposes I chained together the loadMap function and getLocation function to make sure the getLocation function gets executed (which it does judging by the begin location flow message I receive)
import { Component, ViewChild } from '#angular/core';
import { Geolocation} from '#ionic-native/geolocation/ngx';
// Import classes from maps module
import {
GoogleMaps,
GoogleMap,
GoogleMapsEvent,
LatLng,
MarkerOptions,
Marker
} from '#ionic-native/google-maps';
import { Platform, NavController } from '#ionic/angular';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
lat;
lng;
constructor( public platform: Platform, public nav: NavController, private geolocation: Geolocation ) {
}
ngAfterViewInit() {
this.platform.ready().then( () => {
this.loadMap();
});
this.getLocation();
}
loadMap() {
console.log('map render start');
let map = GoogleMaps.create( 'map' );
map.one( GoogleMapsEvent.MAP_READY ).then( ( data: any ) => {
let coordinates: LatLng = new LatLng( 50.7783, 119.4179 );
let position = {
target: coordinates,
zoom: 14
};
map.animateCamera( position );
let markerOptions: MarkerOptions = {
position: coordinates,
icon: "assets/images/marker.png",
title: 'Hello California'
};
const marker = map.addMarker( markerOptions )
.then( ( marker: Marker ) => {
marker.showInfoWindow();
});
});
this.getLocation();
}
getLocation() {
console.log('begin location flow');
this.geolocation.getCurrentPosition().then((resp) => {
// resp.coords.latitude
// resp.coords.longitude
this.lat = resp.coords.latitude;
this.lng = resp.coords.longitude;
alert('lat' + this.lat + 'lon' + this.lng);
console.log('location succes');
}).catch((error) => {
console.log('Error getting location', error);
});
}
}
you need to move the method your calling that makes use of the native plugin into the platform ready promise call back. Native plugins cannot be used until this fires.
this.platform.ready().then(() => {
this.getLocation();
})
Based on your code above, you're calling this.getLocation() twice, as you pointed out, however, the first/initial this.getLocation() call gets run probably before this.platform.ready() (see ngAfterViewInit() routine).
Could this cause a conflict?
I'm working on ionic 4 application. when the user signs In, I added a checkbox to asks for Remember me, so the next time the user open the app it doesn't show the login page and directly forward the user to Home page. I have google and found this. However, while using the accepted solution, I encountered an issue, which it shows the login page for 2 or 3 seconds, then open the Home page. How I can safely achieve it without delay?
app.component.ts
import { SmsVerificationService } from 'src/app/services/SMS/sms-verification.service';
import { Component } from '#angular/core';
import { Platform } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { FCM } from '#ionic-native/fcm/ngx';
import { Plugins, Capacitor } from '#capacitor/core';
import { Router } from '#angular/router';
import { Storage } from '#ionic/storage';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent {
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private fcm: FCM,
private route: Router,
private storage: Storage
) {
this.initializeApp();
}
initializeApp() {
this.platform.ready().then(() => {
this.fcm.getToken().then(token => {
console.log(' token is ', token);
});
this.fcm.onTokenRefresh().subscribe(token => {
console.log('on token refresh ', token);
});
this.fcm.onNotification().subscribe(data => {
console.log(data);
if (data.wasTapped) {
console.log('Received in background');
// this.router.navigate([data.landing_page, data.price]);
} else {
console.log('Received in foreground');
// this.router.navigate([data.landing_page, data.price]);
}
});
this.storage.get('isLogined').then(data => {
if (data)
this.route.navigateByUrl('/main-tab');
})
this.statusBar.styleDefault();
this.splashScreen.hide();
if (Capacitor.isPluginAvailable('SplashScreen')) {
Plugins.SplashScreen.hide();
}
});
}
}
The codes that are supposed to change the page
this.storage.get('isLogined').then(data => {
if (data)
this.route.navigateByUrl('/main-tab');
})
Do you have a separate login component? If so, you can create and add a guard to your login component to navigate to your main page when Remember me was checked.
I have found on android that using geolocation from Google Maps JavaScript API and from the Ionic Framework has caused issues of being very slow or not working at all. I then found a second geolocation module for Ionic called LocationService, from this documentation: https://github.com/ionic-team/ionic-native-google-maps/blob/master/documents/locationservice/README.md. The issue that I am having is although this Location module is working for Android, it is not working on ios or by serving the app on localhost. Below is the error that I am getting and my code that sets the map's center. I am editing this.
map.html:
<ion-header>
<ion-navbar>
<ion-title>
Map
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<div id='map'></div>
</ion-content>
map.ts:
import { Component, ViewChild, ElementRef } from '#angular/core';
import { NavController, Platform, Navbar } from 'ionic-angular';
import { Geolocation } from '#ionic-native/geolocation';
import {
LocationService,
GoogleMap,
GoogleMapOptions,
MyLocation,
GoogleMaps
} from '#ionic-native/google-maps';
declare var google: any;
#Component({
selector: 'page-map',
templateUrl: 'map.html',
})
export class OfficeLocatorPage {
#ViewChild(Navbar) navBar: Navbar;
map: any;
mapOptions:any;
trafficEnabled = false;
transitEnabled = false;
bicycleEnabled = false;
markers = [];
places = [];
trafficLayer = new google.maps.TrafficLayer();
transitLayer = new google.maps.TransitLayer();
bicycleLayer = new google.maps.BicyclingLayer();
myLocation: any;
infoWindow: any;
isInfoWindowShown: boolean = false;
constructor(private navCtrl: NavController, private platform: Platform, private geolocation: Geolocation) {
}
ionViewDidLoad() {
this.navBar.backButtonClick = (e:UIEvent)=>{
this.navCtrl.pop({animate: true, animation: "transition", direction: "left", duration: 300});
};
}
ionViewDidEnter() {
this.platform.ready().then(() => {
this.places = [];
this.initMap(this);
});
}
initMap(scopeObj) {
LocationService.getMyLocation({enableHighAccuracy: true}).then((location: MyLocation) => {
this.setLocation(location.latLng);
}).catch((error: any) => {
// Can not get location, permission refused, and so on...
console.log(error);
});
}
setLocation(location) {
this.map = new google.maps.Map(document.getElementById('map'), {
center: location,
zoom: 10,
disableDefaultUI: true
});
let image = {
url: "assets/icon/blue_dot.png", // url
scaledSize: new google.maps.Size(25, 33), // scaled size
origin: new google.maps.Point(0,0), // origin
anchor: new google.maps.Point(0, 0) // ancho
};
let marker = new google.maps.Marker({
position: location,
map: this.map,
icon: image
});
this.myLocation = new google.maps.LatLng(location.lat, location.lng);
}
Error log:
Error: Uncaught (in promise): TypeError: Cannot read property 'LocationService' of null
TypeError: Cannot read property 'LocationService' of null
at http://localhost:8100/build/vendor.js:78338:35
at new t (http://localhost:8100/build/polyfills.js:3:21506)
at Function.LocationService.getMyLocation
The error seems to only show when serving the app in a web browser, Xcode just needed to be cleaned and rebuilt, so the map shows up and works now. I don't believe that it will work on the browser when running the command "ionic serve", because LocationService is an ionic native module and can't be used unless the app is installed on Android or iOS.
I am building an app that does an auto login for the user when app starts if it was closed without logging out the last time. This is done by setting a local storage value at successful login and reading it in the constructor of the landing page, which is the login page.
I used ionic build android -release to build and app worked fine. But it takes about 10 sec to load. After some search, I found building the app with --prod can reduce the load time and it did reduce my app load time to 4 sec.
But now the app can't read local storage value at the start. No errors., but, it just returns the value as null. In other pages the app can read the local storage though. Looks like some needed components are not fully loaded, when the app reaches the landing page. But, by the time user logins manually those are loaded. How do I implement an auto login while reducing the load time?
import { Component } from '#angular/core';
import { NavController, MenuController, NavParams } from 'ionic-angular';
import { AuthService } from '../../providers/auth-service';
import { Global } from '../../providers/global';
import { HomePage } from '../home/home';
import { Storage } from '#ionic/storage';
import { Network } from 'ionic-native';
#Component({
selector: 'page-login',
templateUrl: 'login.html'
})
export class LoginPage {
loginUserID: string = '';
loginUserPass: string = '';
showLogin = false;
constructor(private menu: MenuController, private navCtrl: NavController, private auth: AuthService, private global: Global, private storage: Storage, private navParams: NavParams) {
this.storage.get('user_id').then((value) => {
if(this.navParams.get('showLogin')){
this.showLogin = true;
}
else{
if(value && value != null){
this.navCtrl.setRoot(HomePage);
}
else{
this.showLogin = true;
}
}
});
if(this.global.hardwareBackAction != null){
this.global.hardwareBackAction();
}
}
ionViewDidLoad() {
this.menu.swipeEnable(false, 'side-menu');
}
public login() {
if (Network.type == 'none') {
this.global.showAlert('Information', 'No internet access');
}
else {
this.global.showLoading();
this.auth.login(this.loginUserID, this.loginUserPass).subscribe(allowed => {
this.global.loading.dismiss();
if (allowed) {
setTimeout(() => {
this.storage.set('user_id', this.loginUserID);
this.navCtrl.setRoot(HomePage);
});
}
},
error => {
this.showError(error);
});
}
}
showError(text) {
setTimeout(() => {
this.global.loading.dismiss();
});
this.global.showAlert('Error', text);
}
}