I want to get the GPS location of my device. I am using GeolocatorPlugin for Xamarin to get the Longitude and Latitude of my device. GPS is enabled on my device. I already added permission to my android manifest but I still get the error: "A geolocation error occured: Unauthorized" How can I fix this?
try
{
var locator = CrossGeolocator.Current;
locator.DesiredAccuracy = 50;
var position = await locator.GetPositionAsync();
entLocation.Text = position.Longitude.ToString() + "," + position.Latitude.ToString();
}
catch (Exception ex)
{
//will catch any general exception and set message in a string
string msg = ex.Message;
await DisplayAlert("error", msg, "ok");
}
Put the code below inside your MainActivity.cs in your Android Project.
if(CheckSelfPermission(Manifest.Permission.AccessCoarseLocation) != (int)Permission.Granted)
{
RequestPermissions(new string[] { Manifest.Permission.AccessCoarseLocation, Manifest.Permission.AccessFineLocation }, 0);
}
Related
I have a Xamarin.Forms application that supports UWP, iOS, and Android. Specifically, I am now testing my app on Android emulator. For getting location, I am using Xamarin.Essentials. Here are pieces of my code:
In a PageModel:
bu = await GeolocationSrvc.GetBusinessUnitAsync();
And here is the implementation of the method above:
public static async Task<BusinessUnits> GetBusinessUnitAsync()
{
BusinessUnits bu = BusinessUnits.Aus;
try
{
Location location = await GetLocation().ConfigureAwait(false);
IEnumerable<Placemark> placemarks = await Geocoding.GetPlacemarksAsync(location);
Placemark placemark = placemarks?.FirstOrDefault();
string countryCode = placemark?.CountryCode;
switch (countryCode)
{
case "AQ":
case "AU":
case "NZ":
bu = BusinessUnits.Aus;
break;
default:
bu = BusinessUnits.NA;
break;
}
}
catch (Exception)
{
throw;
}
return bu;
}
private static Task<Location> GetLocation()
{
GeolocationRequest request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10));
TaskCompletionSource<Location> locationTaskCompletionSource = new TaskCompletionSource<Location>();
Device.BeginInvokeOnMainThread(async () =>
{
locationTaskCompletionSource.SetResult(await Geolocation.GetLocationAsync(request));
});
return locationTaskCompletionSource.Task;
}
When the execution comes to
locationTaskCompletionSource.SetResult(await Geolocation.GetLocationAsync(request));
I am asked if I want to allow the app to get my location. If I press Yes, it works as expected. But if I press No, the location is never returned (not even null), the following code is never executed. I expected in case of answering No to use default value set in
BusinessUnits bu = BusinessUnits.Aus;
But it does not happen.
Alternate approach would be to check for location permission before hand using a simple dependency service for each platform.
If the permission is granted, then continue with location fetch. Else prompt user to get permission.
For ex. Android implementation to check location permission:
public bool IsLocationPermissionGranted()
{
if (ContextCompat.CheckSelfPermission(Application.Context,
Manifest.Permission.AccessFineLocation) == Permission.Granted)
{
return true;
}
return false;
}
You're not setting the Exception of your TaskCompletionSource object:
private static Task<Location> GetLocation()
{
GeolocationRequest request = new GeolocationRequest(GeolocationAccuracy.Medium, TimeSpan.FromSeconds(10));
TaskCompletionSource<Location> locationTaskCompletionSource = new TaskCompletionSource<Location>();
Device.BeginInvokeOnMainThread(async () =>
{
try
{
locationTaskCompletionSource.SetResult(await Geolocation.GetLocationAsync(request));
}
catch(Exception exception)
{
locationTaskCompletionSource.SetException(exception);
locationTaskCompletionSource.SetResult(null);
}
});
return locationTaskCompletionSource.Task;
}
I'm following this sample tutorial for https://developer.xamarin.com/guides/xamarin-forms/cloud-services/authentication/oauth/
After download the sample, I follow the instructions and change all my clientID endpoint.I got into the Google Sign In page and browser manage to close. After browser close, it always got into OnAuthError and error message is "Error authenticating : invalid_request"
I couldn't get the OnAuthCompleted fired. Its always got into OnAuthError.
void OnLoginClicked(object sender, EventArgs e)
{
string clientId = null;
string redirectUri = null;
switch (Device.RuntimePlatform)
{
case Device.iOS:
clientId = Constants.iOSClientId;
redirectUri = Constants.iOSRedirectUrl;
break;
case Device.Android:
clientId = Constants.AndroidClientId;
redirectUri = Constants.AndroidRedirectUrl;
break;
}
var authenticator = new OAuth2Authenticator(
clientId,
null,
Constants.Scope,
new Uri(Constants.AuthorizeUrl),
new Uri(redirectUri),
new Uri(Constants.AccessTokenUrl),
null,
true);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
AuthenticationState.Authenticator = authenticator;
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
}
async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
User user = null;
if (e.IsAuthenticated)
{
// If the user is authenticated, request their basic user data from Google
// UserInfoUrl = https://www.googleapis.com/oauth2/v2/userinfo
var request = new OAuth2Request("GET", new Uri(Constants.UserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync();
if (response != null)
{
// Deserialize the data and store it in the account store
// The users email address will be used to identify data in SimpleDB
string userJson = await response.GetResponseTextAsync();
user = JsonConvert.DeserializeObject<User>(userJson);
}
if (account != null)
{
store.Delete(account, Constants.AppName);
}
await store.SaveAsync(account = e.Account, Constants.AppName);
await DisplayAlert("Email address", user.Email, "OK");
}
}
void OnAuthError(object sender, AuthenticatorErrorEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
Debug.WriteLine("Authentication error: " + e.Message);
}
I have read through all the related links. The closest questions I got from SO is this : Xamarin.Forms Google API Authenticating Users with an Identity Provider
but it still failed after configure the setting and update my packages. I'm using Xamarin.Auth 1.5.0.3 (latest stable version)
Any real hero outside can run this tutorial and make it work?
The problem is that I am using Type : "Others" at the Google Console Developer website. When I switch back the Type: "Android". It's working.
i am using code-name one to develop an app which has google map in it, i want when i open the app it gets my current location how could i do that, here is the code i have.
static Location lastKnownLocation;
#Override
protected void beforeMap(Form f) {
MapContainer mapContainer = new MapContainer(new GoogleMapsProvider("AIzaSyCyy_vOWn3DvR3Y8pzAWUmKTzBaDa81Tfc"));
lastKnownLocation = LocationManager.getLocationManager().getLastKnownLocation();
Style s = new Style();
s.setBgTransparency(0);
s.setFgColor(0);
mapContainer.addMarker(FontImage.createMaterial(FontImage.MATERIAL_MY_LOCATION, s).toEncodedImage(), new Coord(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()), "", "", evt -> {
ToastBar.showErrorMessage(lastKnownLocation.toString());
});
mapContainer.addTapListener(evt -> {
Coord coord = mapContainer.getCoordAtPosition(evt.getX(), evt.getY());
mapContainer.addMarker(FontImage.createMaterial(FontImage.MATERIAL_LOCATION_ON, s).toEncodedImage(), coord, "", "", null);
});
f.add(BorderLayout.CENTER, mapContainer);
FloatingActionButton fab = FloatingActionButton.createFAB(FontImage.MATERIAL_ADD);
fab.addActionListener(e -> {
ParseObject object = ParseObject.create("Geo");
object.put("current", new ParseGeoPoint(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()));
if (ParseUser.getCurrent() != null)
object.put("user", ParseUser.getCurrent());
try {
object.save();
ToastBar.showErrorMessage("Geo Sent");
} catch (ParseException ex) {
ex.printStackTrace();
ToastBar.showErrorMessage(ex.getMessage());
}
});
fab.bindFabToContainer(f.getContentPane());
}
}
Notice that on the device your current location will be used and highlighted since the device runs the native maps whereas the simulator runs a simulation.
Having said that you can get your location from the LocationManager class.
E.g.:
Location position = LocationManager.getLocationManager().getCurrentLocationSync();
I have implemented Google Place API autocomplete functionality for my application like this: https://developers.google.com/places/training/autocomplete-android
No it just makes a Toast with that address.
How can I get the latitude and longitude from the selected address?
Use the method
public List<Address> getFromLocationName (String locationName, int maxResults) from Android Geocoder API, pass in the location name and the maximum number of results you would like and you should be good to go.
Eg.
Geocoder coder = new Geocoder(this);
try {
ArrayList<Address> adresses = (ArrayList<Address>) coder.getFromLocationName("Some Address", 10);
for(Address add : adresses){
double longitude = add.getLongitude();
double latitude = add.getLatitude();
}
} catch (IOException e) {
e.printStackTrace();
} catch(IllegalArgumentException e){
e.printStackTrace();
}
If it helps, I've recently created a library in Java for Google Places API.
Autocompletion is as simple as:
GooglePlaces client = new GooglePlace("apiKey");
List<Prediction> predictions = client.getPlacePredictions("Empire");
for (Prediction prediction : predictions) {
String description = prediction.getDescription();
// etc etc
}
And getting a latitude-longitude from an address is as simple as.
List<Place> places = client.getPlacesByQuery(address, GooglePlaces.MAXIMUM_RESULTS);
for (Place place : places) {
if (place.getAddress().equals(address)) {
double lat = place.getLatitude();
double lng = place.getLongitude();
}
}
https://github.com/windy1/google-places-api-java
You can simply use google maps api to get the lat and long
http://maps.google.com/maps/api/geocode/json?address=&sensor=false
In the above link u have to add the address next to "address=" and u can get the json data with lat and long and some other infos.
Try GeoDataClient. Refer GeoDataClient and Place IDs and details.
geoDataClient.getPlaceById(autoCompletePredictionItem.getPlaceId())
.addOnCompleteListener(new OnCompleteListener<PlaceBufferResponse>() {
#Override
public void onComplete(#NonNull Task<PlaceBufferResponse> task) {
if (task.isSuccessful()) {
PlaceBufferResponse places = task.getResult();
Place myPlace = places.get(0);
Log.e(TAG, "Place found: " + myPlace.getLatLng().toString());
places.release();
} else {
Log.e(TAG, "Place not found.");
}
}
});
According to updated documents, GeoDAtaClient is deprecated. New way is to use this:
// Define a Place ID. val placeId = "INSERT_PLACE_ID_HERE"
// Specify the fields to return. val placeFields = listOf(Place.Field.ID, Place.Field.NAME)
// Construct a request object, passing the place ID and fields array. val request = FetchPlaceRequest.newInstance(placeId, placeFields)
placesClient.fetchPlace(request)
.addOnSuccessListener { response: FetchPlaceResponse ->
val place = response.place
Log.i(PlaceDetailsActivity.TAG, "Place found: ${place.name}")
}.addOnFailureListener { exception: Exception ->
if (exception is ApiException) {
Log.e(TAG, "Place not found: ${exception.message}")
val statusCode = exception.statusCode
TODO("Handle error with given status code")
}
}
https://developers.google.com/maps/documentation/places/android-sdk/place-details#maps_places_get_place_by_id-kotlin
i try get curent coordinate and addres with NETWORK_PROVIDER in trhead, but when i change to GPS_PROVIDER, the app force close: with the message from LogCat :
02-24 16:54:00.249: E/AndroidRuntime(3004):
android.view.ViewRoot$CalledFromWrongThreadException: Only the
original thread that created a view hierarchy can touch its views.
I think what the difference is when I just change the provider from Network to GPS, as before when using a network, application is running well..
this is the code for thread :
private void requestPosition()
{
if(!cekInternet())
{
Txt_konek.setText("Need internet Connection");
}
else
{
new Thread()
{
public void run()
{
Message localMessage = Message.obtain();
localMessage.what=1;
try
{
Splash2.this.ll = Splash2.this.show_current_location();
Splash2.this.lat = Double.valueOf(Double.parseDouble(Splash2.this.ll.substring(0,Splash2.this.ll.indexOf(",")-1)));
Splash2.this.lng = Double.valueOf(Double.parseDouble(Splash2.this.ll.substring(1+Splash2.this.ll.indexOf(","))));
Splash2.this.posisiUser = Splash2.this.goToGeocoder(Splash2.this.lat.doubleValue(), Splash2.this.lng.doubleValue());
Splash2.this.messageHandler.sendMessage(localMessage);
return;
}
catch(Exception localException)
{
while(true)
{
Splash2.this.Txt_konek.setText("no internet connection");
}
}
}
}
.start();
}
}
this method for get current location :
private String show_current_location()
{
Location localLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if(localLocation==null)
{
this.longLat = localLocation.getLatitude()+","+localLocation.getLongitude();
}
else
{
this.longLat = localLocation.getLatitude()+","+localLocation.getLongitude();
}
return this.longLat;
}
and this is locationListener :
GPS provider takes time to get a fix and you are processing your show_current_location method before that, so you are getting the error. You need to wait until you receive lat and lang
if your location localLocation is null then a null pointer exception will be thrown at
localLocation.getLatitude()