I am developing an application for Xamarin.UWP
which is trying to inject Javascript into a local html file (uri: ms-appdata:///local/index.html) like so:
async void OnWebViewNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
if (args.IsSuccess)
{
// Inject JS script
if (Control != null && Element != null)
{
foreach (var f in Element.RegisteredFunctions.Where(ff => !ff.IsInjected))
{
await Control.InvokeScriptAsync("eval", new[] { string.Format(JavaScriptFunctionTemplate, f.Name) });
f.Injected();
}
}
}
}
Then when the Javascript method is called this will call the OnWebViewScriptNotify
method so that I can proccess the request in my application.
The trouble is this doesnt work for some kind of security reasons :
This was a policy decision we made that we have had feedback on so we re-evaluate it. The same restriction doesn't apply if you use NavigateToStreamUri together with a resolver object. Internally that's what happens with ms-appdata:/// anyway.
I then tried what is advised in this case which was to use a resolver as mentioned here: https://stackoverflow.com/a/18979635/2987066
But this has a massive affect on performance, because it is constantly converting all files to a stream to load in, as well as certain pages loading incorrectly.
I then looked at using the AddWebAllowedObject
method like so:
private void Control_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
if (Control != null && Element != null)
{
foreach (var f in Element.RegisteredFunctions)
{
var communicator = new HtmlCommunicator(f);
Control.AddWebAllowedObject("HtmlCommunicator", communicator);
}
}
}
Where HtmlCommunicator
is:
[AllowForWeb]
public sealed class HtmlCommunicator
{
public JSFunctionInjection Function { get; set; }
public HtmlCommunicator(JSFunctionInjection function)
{
Function = function;
}
public void Fred()
{
var d = 2;
//Do something with Function
}
}
and in my html it is like so:
try { window.HtmlCommunicator.Fred(); } catch (err) { }
But this doesn't work either.
So is there a way to work around this rediculous limitation?
So I found this answer: C# class attributes not accessible in Javascript
It says:
I believe you need to define the method name starting with a lower case character.
For example: change GetIPAddress to getIPAddress.
I tested it on my side and found if I use the upper case name 'GetIPAddress', it won't work. But if I use getIPAddress, it works.
So I tried this:
I created a new project of type Windows Runtime Component
as suggested here and I changed my method names to lower case so I had:
[AllowForWeb]
public sealed class HtmlCommunicator
{
public HtmlCommunicator()
{
}
public void fred()
{
var d = 2;
//Do something with Function
}
}
In my javascript I then had:
try { window.HtmlCommunicator.fred(); } catch (err) { }
and in my main UWP project I referenced the new Windows Runtime Component
library and had the following:
public HtmlCommunicator communicator { get; set; }
private void Control_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
if (Control != null && Element != null)
{
communicator = new HtmlCommunicator();
Control.AddWebAllowedObject("HtmlCommunicator", communicator);
}
}
And this worked!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.