I am using Xamarin WebView controller to display a web site (in both iOS/Android). The web site's home page prompts to access the device location. But that prompt is not showing when I have this website on a WebView (from the App). When I open this site on the browser, from the same mobile device it shows the message box. I am just wondering if it is possible to have such prompts on Xamarin WebView?
Here is an example prompt.
This is all I have in the Xamarin app.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:nCollar"
x:Class="nCollar.MainPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<OnPlatform.iOS>0,20,0,0</OnPlatform.iOS>
<OnPlatform.Android>0,0,0,0</OnPlatform.Android>
<OnPlatform.WinPhone>0,0,0,0</OnPlatform.WinPhone>
</OnPlatform>
</ContentPage.Padding>
<WebView x:Name="webView"
Grid.Row="0"
VerticalOptions="FillAndExpand"
Source="https://www.ncollar.com.au/"/>
</ContentPage>
UPDATE 1
Android
I've tried the solution mentioned in this post, but still it doesn't show the prompt.
WebViewRenderer.cs
using Android.Webkit;
using Xamarin.Forms.Platform.Android;
[assembly: Xamarin.Forms.ExportRenderer(typeof(TestApp.Controls.WebView), typeof(TestApp.Droid.Renderers.WebViewRenderer))]
namespace TestApp.Droid.Renderers
{
public class WebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (this.Control == null)
{
return;
}
var webView = this.Element as TestApp.Controls.WebView;
if (webView == null)
{
return;
}
// webView. ings.JavaScriptEnabled = true;
this.Control.Settings.DomStorageEnabled = true;
this.Control.Settings.DisplayZoomControls = true;
this.Control.Settings.BuiltInZoomControls = true;
this.Control.Settings.SetGeolocationEnabled(true);
this.Control.Settings.JavaScriptCanOpenWindowsAutomatically = true;
this.Control.SetWebViewClient(new GeoWebViewClient());
this.Control.SetWebChromeClient(new GeoWebChromeClient());
}
}
public class GeoWebChromeClient : WebChromeClient
{
public override void OnGeolocationPermissionsShowPrompt(string origin, GeolocationPermissions.ICallback callback)
{
callback.Invoke(origin, true, false);
}
}
public class GeoWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
view.LoadUrl(url);
return true;
}
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application android:label="TestApp.Android"></application>
</manifest>
iOS
Tried NSLocationWhenInUseUsageDescription
in the plist file, but no difference.
In case of Android - you will need a custom renderer for your WebView control. (ref: gist)
public class ExtendedWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
Control.Settings.JavaScriptEnabled = true;
Control.Settings.SetGeolocationEnabled(true);
Control.Settings.SetGeolocationDatabasePath(Control.Context.FilesDir.Path);
Control.SetWebViewClient(new CustomWebViewClient());
Control.SetWebChromeClient(new CustomChromeClient(Control.Context));
}
}
public class CustomWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, string url)
{
view.LoadUrl(url);
return true;
}
}
public class CustomChromeClient : WebChromeClient
{
private readonly Context _context;
public CustomChromeClient(Context context)
{
_context = context;
}
public override void OnGeolocationPermissionsShowPrompt(string origin, GeolocationPermissions.ICallback callback)
{
const bool remember = false;
var builder = new AlertDialog.Builder(_context);
builder.SetTitle("Location")
.SetMessage(string.Format("{0} would like to use your current location", origin))
.SetPositiveButton("Allow", (sender, args) => callback.Invoke(origin, true, remember))
.SetNegativeButton("Disallow", (sender, args) => callback.Invoke(origin, false, remember));
var alert = builder.Create();
alert.Show();
}
}
Manifest permissions
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
Usage sample
<StackLayout Margin="30" BackgroundColor="#ededed">
<Label Text="WebView location prompt sample" Margin="15" HorizontalOptions="Center" />
<local:ExtendedWebView x:Name="webView" Source="https://www.yellowpages.com/" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</StackLayout>
And, in case of iOS, you need to set NSLocationWhenInUseUsageDescription
description in the info.plist
file.
And it displays the prompt.
Complete code sample can be found at this link
Original answer
In case of Android - you should be able to resolve this by adding a platform-specific renderer for WebView and implement the permission handling by adding a custom WebChromeClient.
In case of iOS - you need to add NSLocationWhenInUseUsageDescription description in your info plist
But that prompt is not showing when I have this website on a WebView (from the App).
If I got it right, you're wrapping this in an app. That's not the expected user experience from a mobile app. your app should use the platform(e.g iOS,Android) location permissions in order to get the user approval.
Xamarin will let you access Location on each platform quite differently. If the Xamarin app has access to location than the webview should inherit these permissions. So it might worth trying this recipe and try accsing location before opening the webview itself
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With