I have a Xamarin Forms app that needs to call a web page that contains a custom Bing Map and on the web page it needs to be able to get the users current location.
The app already has the required "app" permissions for both Android and iOS and I can get the users location internally in the app without issues.
When I call my external web page that has a custom Bing Map, it does allow me to get the users location in both Android and iOS BUT on iOS it asks the user "website... Would Like To Use Your Current Location. Don't Allow / OK" each time they visit the web page from inside my Xamarin app.
I found the following articles that help point me in the right directions but I just don't understand enough of iOS to piece it together.
How to prevent WKWebView to repeatedly ask for permission to access location? -- This looks like what I need but it is in iOS and does not use WkWebViewRender which is required for newer iOS apps.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/hybridwebview -- This shows me how to add "script" to the iOS side but I can't get the DidReceiveScriptMessage method to fire.
Here is my current implementation of WkWebViewRender.
public class HybridWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler
{
public HybridWebViewRenderer() : this(new WKWebViewConfiguration())
{
}
const string JavaScriptFunctionTest =
"navigator.geolocation.getCurrentPosition = function(success, error, options) {window.webkit.messageHandlers.locationHandler.postMessage('getCurrentPosition');};";
WKUserContentController userController;
public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)
{
try
{
userController = config.UserContentController;
var script = new WKUserScript(new NSString(JavaScriptFunctionTest), injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, isForMainFrameOnly: true);
userController.AddUserScript(script);
userController.AddScriptMessageHandler(this, "locationHandler");
}
catch (System.Exception ex)
{
}
}
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
var msg = message.Body.ToString();
System.Diagnostics.Debug.WriteLine(msg);
}
}
And here is the only javascript functions in my html page.
function StartTracking() {
//Add a pushpin to show the user's location.
userPin = new Microsoft.Maps.Pushpin(map.getCenter(), { visible: true });
map.entities.push(userPin);
//Watch the users location.
watchId = navigator.geolocation.watchPosition(UsersLocationUpdated);
}
function UsersLocationUpdated(position) {
var loc = new Microsoft.Maps.Location(
position.coords.latitude,
position.coords.longitude);
//Update the user pushpin.
userPin.setLocation(loc);
userPin.setOptions({ visible: true });
//Center the map on the user's location.
map.setView({ center: loc });
}
function StopTracking() {
// Cancel the geolocation updates.
navigator.geolocation.clearWatch(watchId);
//Remove the user pushpin.
map.entities.clear();
}
https://gist.github.com/hayahyts/2c369563b2e9f244356eb6228ffba261 is so close to what I need but I must be doing something wrong.
The DidReceiveScriptMessage does not get called if I use
const string JavaScriptFunction =
"navigator.geolocation.getCurrentPosition " +
" = function(success, error, options) " +
"{window.webkit.messageHandlers.locationHandler.postMessage('getCurrentPosition');};";
BUT DidReceiveScriptMessage does get called if I use
const string JavaScriptFunction =
"function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
So I'm not sure what is wrong just yet but it must be with the locationHandler replacement code.