你如何在 Uno WASM 中实现 Google 地图

How do you implement Google Maps in Uno WASM

我是 Uno Platform 的新手,我需要帮助将 Google 地图添加到我的应用程序。由于 MapControl 不提供 WASM 支持,看来我需要嵌入一个 javascript 组件。根据 https://platform.uno/blog/how-to-embed-javascript-components-in-c-built-uno-webassembly-web-applications/ 这应该是可能的。但我似乎无法让它发挥作用。

我有一个包含以下内容的 javascript 文件,直接取自官方 google 地图站点。也不确定将地图 API 键放在哪里。

// Initialize and add the map
function initMap() {
    // The location of Uluru
    const uluru = { lat: -25.344, lng: 131.036 };
    // The map, centered at Uluru
    const map = new google.maps.Map(document.getElementById("map"), {
        zoom: 4,
        center: uluru,
    });
    // The marker, positioned at Uluru
    const marker = new google.maps.Marker({
        position: uluru,
        map: map,
    });
}

我也有这个 class,尝试按照官方 Uno Platform Embedd Javascript 组件指南中的 part 3 进行操作。

    public class GoogleMapsController : FrameworkElement
    {
        public GoogleMapsController()
        {
            LoadJavaScript();
        }

        private async void LoadJavaScript()
        {
            await this.ExecuteJavascriptAsync("initMap()");
        }

    }

要在 xaml 页面中显示地图:

<local:GoogleMapsController x:Name="googlemaps" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4" />

当我 运行 应用程序时,地图不显示。有谁知道我做错了什么?

Web 控制台中显示以下内容

fail: Windows.UI.Core.CoreDispatcher[0]
dotnet.js:1       Dispatcher unhandled exception
dotnet.js:1 System.ApplicationException
dotnet.js:1   at TestMaps.GoogleMapsController.LoadJavaScript () <0x2f90540 + 0x000e6> in <filename unknown>:0 
dotnet.js:1   at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__7_0 (System.Object state) <0x2f9ba10 + 0x00010> in <filename unknown>:0 
dotnet.js:1   at Windows.UI.Core.CoreDispatcherSynchronizationContext+<>c__DisplayClass3_0.<Post>b__0 () <0x2f9b9d0 + 0x00014> in <filename unknown>:0 
dotnet.js:1   at Windows.UI.Core.CoreDispatcher.DispatchItems () <0x2a8a0a0 + 0x001e6> in <filename unknown>:0 

如果我在 GoogleMapsController 中将 LoadJavaScript() 更改为同步,Web 控制台中将显示以下内容。

dotnet.js:1 Error #1 "ReferenceError: google is not defined" executing javascript: "
put_char @ dotnet.js:1
dotnet.js:1 (function(element) {
put_char @ dotnet.js:1
dotnet.js:1 initMap()
put_char @ dotnet.js:1
dotnet.js:1 })(Uno.UI.WindowManager.current.getView(38002));
put_char @ dotnet.js:1
dotnet.js:1 "

成功了,我以后可能会写一篇关于它的博文。

获取 Google 地图 API 密钥

您可以按照网络上提供的任何有关如何通过 Google 开发人员控制台获取 API 密钥的教程进行操作。它涉及创建项目、添加所需的账单信息、创建 API 密钥,然后为其启用 Google 地图 API。 当您打算去 public 时,请务必限制 API 密钥,以免有人滥用您的密钥以达到他们的目的并以这种方式用完您的帐单。

向您的 WASM 项目添加自定义 index.html

因为 Google 地图需要加载外部 JavaScript 库,所以在您的应用首次加载时提前加载它很有用。为此,请将 index.html 文件添加到您的 WASM 项目的根目录,其中包含以下内容:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />

    <script type="text/javascript" src="./require.js"></script>
    <script type="text/javascript" src="./mono-config.js"></script>
    <script type="text/javascript" src="./uno-config.js"></script>
    <script type="text/javascript" src="./uno-bootstrap.js"></script>
    <script async type="text/javascript" src="./dotnet.js"></script>
    <!-- Google Maps libs here: -->
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=MYAPIKEY&libraries=&v=weekly"></script>

    $(ADDITIONAL_CSS)
    $(ADDITIONAL_HEAD)
</head>
<body>
    <div id="uno-body" class="container-fluid uno-body">
        <div class="uno-loader"
             loading-position="bottom"
             loading-alert="none">

            <!-- Logo: change src to customize the logo -->
            <img class="logo"
                 src=""
                 title="Uno is loading your application" />

            <progress></progress>
            <span class="alert"></span>
        </div>
    </div>
    <noscript>
        <p>This application requires Javascript and WebAssembly to be enabled.</p>
    </noscript>
</body>
</html>

请注意,大部分代码是 Uno WASM 项目中默认的样板文件(参见 here)。将 MYAPIKEY 替换为开发者控制台中的 API 密钥。

现在您需要指示 WASM 引导程序使用此自定义 index.html。双击解决方案资源管理器中的 .csproj 并添加以下内容:

<PropertyGroup>
   <WasmShellIndexHtmlPath>index.html</WasmShellIndexHtmlPath>
</PropertyGroup>

创建自定义地图元素

与文档中的教程类似,我创建了以下元素:

#if __WASM__
using System;
using Uno.UI.Runtime.WebAssembly;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;

namespace UnoWasmGoogleMaps
{
    [HtmlElement("div")]
    public class GoogleMapView : FrameworkElement
    {
        private readonly string _mapObjectName = "map_" + Guid.NewGuid().ToString().Replace("-", "");

        public GoogleMapView()
        {            
            Background = new SolidColorBrush(Colors.Transparent);
            LoadMap();
        }

        private void LoadMap()
        {
            var javascript = $@"var {_mapObjectName} = new google.maps.Map(element, {{ center: {{lat: -34.397, lng: 150.644}}, zoom: 8 }});";

            this.ExecuteJavascript(javascript);
        }
    }
}
#endif

请注意,我正在使用自定义唯一变量名来存储由 Google 地图 API 创建的地图对象。您可以使用此变量名来操作地图并在其上调用一些函数。

使用元素

最后,您可以像这样在您的应用中使用该元素:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <local:GoogleMapView />
</Grid>

结果