Xamarin Forms WebView 地理位置问题

4
我将尝试在Xamarin Forms应用程序中启用Webview,以获取Android设备的当前GPS坐标。目前,在手机或笔记本电脑上使用Chrome浏览器打开Webview /网站将返回GPS坐标,但是在应用程序中不会返回。我正在尝试尽可能简单地使其工作,并在此基础上进行扩展。
到目前为止的代码: 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>

你已经配置了你的应用程序以允许使用GPS吗? - SergioAMG
是的,我已经在Android清单文件中配置了权限,以允许获取精确和粗略位置。 - Ollie
3个回答

7

目前,当在手机或笔记本电脑上的Chrome浏览器中打开webview/网站时,将返回GPS坐标,但是在应用程序中不会。

您需要在Droid项目中为WebView使用自定义WebChromeClient。请参考Android WebView Geolocation

在Xamarin.Forms中,您可以按照以下步骤完成此操作:

  1. Create a custom Control for WebView in PCL project:

    public class GeoWebView:WebView
    {
    }
    

    And use it in 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>
    

  2. Create a Custom Renderer for GeoWebView in Droid Project like below:

    [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);
            }
        }
    }
    
  3. Add Permissions to AndroidManifest.xml:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    
然后,您将正确地在webview中获取您的位置。

2
欢呼!Elvis成功地解决了所有问题,我只需做出一些微小的更改。以下是我所做的详细步骤:
在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>

Elvis说需要在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
    {
    }
}

在Droid类中创建一个自定义渲染器。最初可能会出现一些错误,主要是缺少'using'指令和'assembly'中需要的关键字。
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);
        }
    }
}

在做出这些更改后,一切都运行得非常完美。再次感谢 Elvis!


1
对我来说并不像您所描述的那样顺利。我按照您所说的做了,但在JavaScript尝试获取地理位置时遇到了此错误: 01-11 22:16:27.544 E/cr_LocationProvider(10680): Caught security exception while registering for location updates from the system. The application does not have sufficient geolocation permissions. 01-11 22:16:27.546 E/cr_LocationProvider(10680): newErrorAvailable application does not have sufficient geolocation permissions. 我已经启用了精确定位和粗略位置权限。 - Munk
1
我相信这种情况发生在目标API 23或更高版本的时候。该代码在较低的SDK上运行良好。对于Marshmellow及以上版本,必须通过用户对话框明确授予权限,但我不确定在哪里或如何进行。 - A. Niese
1
我在C#中使用这个 - 遵循James Montemagno的权限。这将添加您缺少的额外检查,即var hasPermission = await UtilsPermissions.CheckPermissions(Permission.Location); - Pxaml
请问有人能让这个在API 23及以上版本中工作吗? - Haybee

0

对于 Android API 23 及以上版本,可以使用 Xamarin.Essentials 命名空间来实现类似的功能。

  1. 确保在 Manifest 文件中请求了所有必要的权限。在撰写本文时,我需要以下权限:
    <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" />
  1. 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 );
            }
        }
    }
}

完成了!

Android Permission Requesting


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接