Search code examples
google-mapsxamarinxamarin.androidxamarin.formsgoogle-geocoder

Google map Geocoder And MoveToRegion not working


I' have a very strange issue with Xamarin.Forms.Maps. I'm trying to implement a page with a map that get current location and move to region at page start.

All is working fine in IOS, but in Android, Geocoder & MoveToRegion are not working at all. Only the map is displayed.

I retrieve the location correctly (Long & Lat ) in the emulators & device. MoveToRegion do nothing & GetAddressesForPositionAsync retrive nothing.

Here the information in my manifest :

<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="mykey" />
        <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

Here the code :

map.MoveToRegion(MapSpan.FromCenterAndRadius(
                new Xamarin.Forms.Maps.Position(coordinates.Lat.Value, coordinates.Lng.Value), Distance.FromMiles(1))
            );

        var possibleAddresses = await locator.GetAddressesForPositionAsync(position);

I tried in Genymotion, Emulator from AVD. I'm not able to test in real device ( The deployment fail in my tablet )

Edit :

global::Xamarin.Forms.Forms.Init(this, bundle);

Was correctly set but still not working.

I force geocoder usage and it thrown this error :

[MonoDroid] UNHANDLED EXCEPTION:
[MonoDroid] Java.IO.IOException: grpc failed
[MonoDroid]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00069] in <6cd960837cc24c26bab2a0a29b597627>:0 
[MonoDroid]   at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeAbstractObjectMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00014] in <6cd960837cc24c26bab2a0a29b597627>:0 
[MonoDroid]   at Android.Locations.Geocoder.GetFromLocationName (System.String locationName, System.Int32 maxResults) [0x0003c] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at Android.Locations.Geocoder+<>c__DisplayClass17_0.<GetFromLocationNameAsync>b__0 () [0x00000] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Threading.Tasks.Task.Execute () [0x00010] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid] --- End of stack trace from previous location where exception was thrown ---
[MonoDroid]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at Xamarin.Forms.Maps.Android.GeocoderBackend+<GetPositionsForAddressAsync>d__1.MoveNext () [0x0006b] in <39c694c022be4f7b8a39897d372b2d00>:0 
[MonoDroid] --- End of stack trace from previous location where exception was thrown ---
[MonoDroid]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at Picaplant.Views.GeolocationPage+<HandleAdressCompleted>d__8.MoveNext () [0x00047] in /Users/OrcusZ/Documents/AutoEntrepreneur/Picaplant/Source/Picaplant/Views/GeolocationPage.xaml.cs:158 
[MonoDroid] --- End of stack trace from previous location where exception was thrown ---
[MonoDroid]   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) [0x00000] in <896ad1d315ca4ba7b117efb8dacaedcf>:0 
[MonoDroid]   at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <d278c06ad5684d6882c743a94a93ebc2>:0 
[MonoDroid]   at (wrapper dynamic-method) System.Object:6621ff63-14b8-4291-a222-45bff630bddc (intptr,intptr)
[MonoDroid]   --- End of managed Java.IO.IOException stack trace ---
[MonoDroid] java.io.IOException: grpc failed
[MonoDroid]     at android.location.Geocoder.getFromLocationName(Geocoder.java:178)
[MonoDroid] 

EDIT 2 :

Same error with Xamarin Form Working with maps sample

Any idea ?


Solution

  • Here's a working cross-platform sample app. It runs in a KitKat 4.4 API Level 19 emulator and also in a Samsung Android device. We also present a custom Geocoder implementation using HTTP requests given that the standard one works fine for an actual Android device but returns an empty response for the emulator.

    enter image description here

    XAML:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:Maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps.dll"
                 xmlns:local="clr-namespace:App20"
                 x:Class="App20.MainPage">
        <ContentPage.Content>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="8*"></RowDefinition>
                    <RowDefinition Height="4*"></RowDefinition>
                    <RowDefinition Height="*"></RowDefinition>
                    <RowDefinition Height="*"></RowDefinition>
                </Grid.RowDefinitions>
    
                <Maps:Map x:Name="map1" Grid.Row="0"></Maps:Map>
                <ListView ItemsSource="{Binding AddressList}" Grid.Row="1" />
                <Button Text="Move To Region" Grid.Row="2" Clicked="Button_Clicked_Move"></Button>
                <Button Text="Get Address" Grid.Row="3" Clicked="Button_Clicked_Address"></Button>
            </Grid>
        </ContentPage.Content>
    </ContentPage>
    

    CS:

    public partial class MainPage : ContentPage
    {
        MyViewModel vm;
    
        public MainPage()
        {
            InitializeComponent();
    
            vm = new MyViewModel();
            BindingContext = vm;
        }
    
        private void Button_Clicked_Move(object sender, EventArgs e)
        {
            map1.MoveToRegion(MapSpan.FromCenterAndRadius(
                new Position(vm.Lat, vm.Lon), Distance.FromMiles(vm.Distance)));
        }
    
        private async void Button_Clicked_Address(object sender, EventArgs e)
        {
            Geocoder gc = new Geocoder();
    
            var list = await gc.GetAddressesForPositionAsync(new Position(vm.Lat, vm.Lon));
    
            if (list.Count() > 0)
            {
                foreach (string s in list)
                    vm.AddressList.Add(s);
            }
            else
            {
                MyGeocoder mgc = new MyGeocoder();
    
                var mylist = await mgc.GetAddressesForPositionAsync(vm.Lat, vm.Lon, vm.Key);
    
                foreach (string s in mylist)
                    vm.AddressList.Add(s);
            }
        }
    }
    

    View Model:

    public class MyViewModel
    {
        public string Key { get; }
        public double Lat { get; set; }
        public double Lon { get; set; }
        public double Distance { get; set; }
        public ObservableCollection<string> AddressList { get; set; }
    
        public MyViewModel()
        {
            Lat = 40.706501;
            Lon = -74.011340;
            Distance = 0.5;
            Key = "YOUR_API_KEY";
            AddressList = new ObservableCollection<string>();
        }
    }
    

    Custom Geocoder:

    public class MyGeocoder
    {
        public async Task<IEnumerable<string>> GetAddressesForPositionAsync(double lat, double lon, string key)
        {
            HttpClient client = new HttpClient();
    
            var request = string.Format(@"https://maps.googleapis.com/maps/api/geocode/json?latlng={0},{1}&key={2}", lat, lon, key);
    
            var json = await client.GetStringAsync(request);
    
            var result = JObject.Parse(json)["results"];
    
            List<string> list = new List<string>();
    
            foreach (JToken jt in result)
                list.Add((string)jt["formatted_address"]);
    
            return list.AsEnumerable<string>();
        }
    }