-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[Enhancement] Add EvaluateJavaScript method to WebView #2140
[Enhancement] Add EvaluateJavaScript method to WebView #2140
Conversation
Question: should |
if (Xamarin.Forms.Device.RuntimePlatform != "Android") | ||
{ | ||
script = EscapeJsString(script); | ||
script = "try{JSON.stringify(eval('" + script + "'))}catch(e){'null'};"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A fair amount of effort was involved in finding a way to be able to pass a js string that would resolve the same on all platforms due to some inconsistencies:
- UWP/WPF only returns a value if the result of the function is a string and throws a generic exception otherwise (even for what I would think should be easily convertible types like bool and int). It also throws if there is an error in the script.
- iOS/macOS will return String.Empty when the result is an array, object, or there is a script error.
Android was the only implementation that nicely handled all types. Wrapping the result of the script in JSON.stringify
and catching script errors allows all platforms to behave consistently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the use of eval
affect CSP?
@rmarinho can you give me any insight into why this failed (it looks like only on Windows)? |
@alanag13 Nothing wrong on your end - the Windows build failure was a VSTS hiccup. That build stage should be green now. |
Xamarin.Forms.Core/WebView.cs
Outdated
@@ -184,7 +178,7 @@ public void SendNavigating(WebNavigatingEventArgs args) | |||
return _platformConfigurationRegistry.Value.On<T>(); | |||
} | |||
|
|||
private static string EscapeJsString(string js) | |||
static string EscapeJsString(string js) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we add an extra eval function in the code I added for standardizing platforms, we need to add an extra level of escaping to any single quotes the user may have passed in for their script. I really don't like this but it was all I could come up with to solve this problem. I'm open to suggestions here.
GitHub is hiding a comment I made on WebView.cs, since I made a change to it after opening this PR, so just make sure you show outdated or go to the full changes to see it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple of checks and recomendations
Xamarin.Forms.Core/WebView.cs
Outdated
|
||
static string EscapeJsString(string js) | ||
{ | ||
if (!js.Contains("'")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check if this is null or it will throw NRE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, will do
{ | ||
if (Control != null) | ||
{ | ||
Control.ExecuteScript(script); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Control?.ExecuteScript(script);
{ | ||
Control.ExecuteScript(script); | ||
} | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we always return null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -140,6 +143,11 @@ void Load() | |||
await Control.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () => await Control.InvokeScriptAsync("eval", new[] { eventArg.Script })); | |||
} | |||
|
|||
async Task<string> OnEvaluateJavaScriptRequested(string script) | |||
{ | |||
return await Control.InvokeScriptAsync("eval", new[] { script }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code style issue, extra tabs I think
@rmarinho updated with your changes |
Doesn't impact fast renderers, therefor merging :) |
@jassmith do we want to deprecate I can open another PR to do that if you think it's the right call, but let me know the version number you want to appear in the deprecation message. |
Description of Change
fixes #1699 .
Adds the ability to execute and return the result of a passed javascript string from a platform's webview.
Platform support:
API Changes
Added:
Task WebView.EvaluateJavaScriptAsync
PR Checklist