Please see the other answer. It is easier than this one!

I was able to get a workable solution, but it isn't pretty. Below is the implementation. If I get some time and a legit port doesn't come a long I will post an example repo.

import 'dart:html'; import 'package:flutter_web/material.dart'; import 'package:lift_ai/base/screen_state.dart'; import 'package:lift_ai/feature/property_common/property_contract.dart'; import 'package:lift_ai/feature/property_common/property_presenter_impl.dart'; import 'package:lift_ai/model/car_status.dart'; import 'package:lift_ai/model/property.dart'; import 'package:flutter_web_ui/ui.dart' as ui; import 'package:lift_ai/util/widget_util.dart'; class PropertyMapPage extends StatefulWidget { final CarStatus carStatus; PropertyMapPage(Key key, this.carStatus) : super(key: key); @override _PropertyMapPageState createState() => _PropertyMapPageState(carStatus); } class _PropertyMapPageState extends State<PropertyMapPage> implements PropertyListView { PropertyPresenter _propertyListPresenter; List<Property> properties = []; CarStatus carStatus; String createdViewId = 'hello-world-html'; bool inProgress = true; _PropertyMapPageState(this.carStatus) { _propertyListPresenter = PropertyPresenterImpl(this); } @override void initState() { super.initState(); _propertyListPresenter.getProperties(carStatus, ""); } @override void dispose() { super.dispose(); _propertyListPresenter = null; } @override Widget build(BuildContext context) { print("Creating html view"); if (inProgress) { return Center(child: CircularProgressIndicator()); } return Row( children: <Widget>[ Container( width: MediaQuery.of(context).size.width - 400, child: HtmlView( viewType: createdViewId, )), Container( width: 400, child: properties.isEmpty ? WidgetUtil.getEmptyPropertiesView(context) : ListView.builder( padding: EdgeInsets.all(8.0), itemCount: properties.length, itemBuilder: (_, index) { return WidgetUtil.buildListRow( context, _propertyListPresenter, properties[index]); }, ), ), ], ); } @override void showProperties(List<Property> properties) { String markers = ""; for (Property property in properties) { String marker = "var marker = new google.maps.Marker({position: new google.maps.LatLng(${property.lat}, ${property.lng}), map: map, title: 'Hello ${property.id}!'});

"; markers += marker; } String createdViewUpdate = DateTime.now().toString(); rootBundle.loadString('map.html').then((value) { value = value.replaceAll(new RegExp(r'markers'), markers); ui.platformViewRegistry.registerViewFactory( createdViewId, (int viewId) => IFrameElement() ..width = (MediaQuery.of(context).size.width - 400).toString() ..height = MediaQuery.of(context).size.height.toString() ..srcdoc = value ..style.border = 'none'); }); setState(() { inProgress = false; this.createdViewId = createdViewUpdate; this.properties = properties; }); } @override void updateScreenState(ScreenState screenState) { } @override void showException(String string) { // TODO: implement showException } }

map.html

<!DOCTYPE html> <html> <head> <meta name="viewport" content="initial-scale=1.0, user-scalable=no"> <meta charset="utf-8"> <title>Simple Markers</title> <style> /* Always set the map height explicitly to define the size of the div * element that contains the map. */ #map { height: 100%; } /* Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } </style> </head> <body> <div id="map"></div> <script> function initMap() { var myLatLng = {lat: 41.850033, lng: -87.6500523}; var map = new google.maps.Map(document.getElementById('map'), { zoom: 4, center: myLatLng }); markers } </script> <script async defer src="https://maps.googleapis.com/maps/api/js?key=API_KEY&callback=initMap"> </script> </body> </html>

The answer outlined by @panavtec below also works and might have an easier api work work with!

A sample repository of his solution is here:

https://github.com/dazza5000/flutter_web_google_maps_example