Проблема геолокации в Xamarin Forms WebView
Я пытаюсь включить веб-просмотр в приложении форм xamarin, чтобы получить текущие GPS-координаты устройства Android. В настоящее время веб-просмотр / веб-сайт будут возвращать GPS-координаты при открытии в браузере Chrome на телефоне или ноутбуке, однако в приложении это не так. Попытка заставить это работать как можно проще и расширить его после.
Код до сих пор: страница 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"
x:Class="UITrial.Page2"
BackgroundColor = "#f0f0ea">
<Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />
<WebView Source="https://danu6.it.nuigalway.ie/OliverInternetProgramming/project/Loginproject.html" />
</ContentPage>
HTML СТРАНИЦА:
<!DOCTYPE html>
<html>
<body>
<p>Click the button to get your coordinates.</p>
<button onclick="getLocation()">Try It</button>
<p id="demo"></p>
<script>
var x = document.getElementById("demo");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.watchPosition(showPosition);
} else {
x.innerHTML = "Geolocation is not supported by this browser.";}
}
function showPosition(position) {
x.innerHTML="Latitude: " + position.coords.latitude +
"<br>Longitude: " + position.coords.longitude;
}
</script>
</body>
</html>
3 ответа
В настоящее время веб-просмотр / веб-сайт будут возвращать GPS-координаты при открытии в браузере Chrome на телефоне или ноутбуке, однако в приложении это не так.
Вам нужно использовать кастом WebChromeClient
за WebView
в проекте Droid. Пожалуйста, обратитесь к Android WebView Geolocation.
В Xamarin.Forms вы можете выполнить следующие шаги, чтобы выполнить это:
Создайте пользовательский элемент управления для WebView в проекте PCL:
public class GeoWebView:WebView { }
И используйте это в Xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:WebViewFormsDemo" x:Class="WebViewFormsDemo.MainPage"> <local:GeoWebView Source="https://danu6.it.nuigalway.ie/OliverInternetProgramming/project/Loginproject.html"></local:GeoWebView>
Создайте пользовательский рендерер для
GeoWebView
в Droid Project, как показано ниже:[assembly:ExportRenderer(typeof(GeoWebView),typeof(GeoWebViewRenderer))] namespace WebViewFormsDemo.Droid { public class GeoWebViewRenderer:WebViewRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e) { base.OnElementChanged(e); Control.Settings.JavaScriptEnabled = true; Control.SetWebChromeClient(new MyWebClient()); } } public class MyWebClient : WebChromeClient { public override void OnGeolocationPermissionsShowPrompt(string origin, GeolocationPermissions.ICallback callback) { callback.Invoke(origin, true, false); } } }
Добавить разрешения для
AndroidManifest.xml
:<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Тогда вы получите ваше местоположение в webview правильно.
Приветствия Элвису удалось заставить все работать, пришлось внести небольшие изменения, поэтому опубликую все, что я сделал в деталях:
В App.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
namespace WebViewFormsDemo
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
В MainPage.xaml убедитесь, что ваш сайт "https"
<?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:local="clr-namespace:WebViewFormsDemo"
x:Class="WebViewFormsDemo.MainPage">
<local:GeoWebView
Source="https:// --- Your Website ----></local:GeoWebView>
</ContentPage>
Как сказал Элвис, нужно создать собственный элемент управления в проекте PLC. Щелкните правой кнопкой мыши и добавьте новый "Класс", чтобы сделать это.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace WebViewFormsDemo
{
public class GeoWebView : WebView
{
}
}
После этого создайте Custom Render в классе Droid. Первоначально здесь были некоторые ошибки, в основном из-за отсутствия директив using, а также с ключевыми словами, необходимыми в ассемблере.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Android.Webkit;
[assembly: ExportRenderer(typeof(WebViewFormsDemo.GeoWebView), typeof(WebViewFormsDemo.Droid.GeoWebViewRenderer))]
namespace WebViewFormsDemo.Droid
{
public class GeoWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
Control.Settings.JavaScriptEnabled = true;
Control.SetWebChromeClient(new MyWebClient());
}
}
public class MyWebClient : WebChromeClient
{
public override void OnGeolocationPermissionsShowPrompt(string origin, GeolocationPermissions.ICallback callback)
{
callback.Invoke(origin, true, false);
}
}
}
После этих изменений все заработало отлично. Еще раз спасибо, Элвис!
Для Android API 23 и более поздних версий это аналогично можно выполнить с помощьюXamarin.Essentials
пространство имен.
- Убедитесь, что вы запросили все необходимые разрешения в файле манифеста. На момент написания этой статьи мне были нужны:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
- Создайте собственный рендерер для
WebView
и обычайWebChromeClient
использовать.
using Android.Content;
using Android.Webkit;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer( typeof( Xamarin.Forms.WebView ), typeof( Namespace.Droid.Renderers.WebViewRenderer ) )]
namespace Namespace.Droid.Renderers
{
/// <summary>
/// The <see cref="Xamarin.Forms.WebView"/> renderer.
/// Implements the <see cref="WebViewRenderer" />
/// </summary>
/// <seealso cref="WebViewRenderer" />
public class WebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
public WebViewRenderer( Context context )
: base( context ) { }
protected override void OnElementChanged( ElementChangedEventArgs<Xamarin.Forms.WebView> e )
{
base.OnElementChanged( e );
if( e.NewElement != null )
{
GeoWebViewClient cwc = new GeoWebViewClient();
Control.SetWebChromeClient( cwc );
}
}
/// <summary>
/// A custom Chrome Web Client used to process geolocation permission in Android.
/// Implements the <see cref="WebChromeClient" />
/// </summary>
/// <seealso cref="WebChromeClient" />
public class GeoWebViewClient : WebChromeClient
{
/// <summary>
/// Called when the geolocation prompt is requested through the WebView.
/// </summary>
/// <param name="origin">The origin.</param>
/// <param name="callback">The callback.</param>
public override async void OnGeolocationPermissionsShowPrompt( string origin, GeolocationPermissions.ICallback callback )
{
// Check if we have location permissions already granted.
var locationWhenInUsePermissionStatus = await Xamarin.Essentials.Permissions.CheckStatusAsync<Xamarin.Essentials.Permissions.LocationWhenInUse>();
// If not, request them.
if( locationWhenInUsePermissionStatus != PermissionStatus.Granted )
{
await Xamarin.Essentials.Permissions.RequestAsync<Xamarin.Essentials.Permissions.LocationWhenInUse>();
}
callback.Invoke( origin, true, true );
}
}
}
}
Вуаля!