Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

[Enhancement] Add EvaluateJavaScript method to WebView #2140

Merged

Conversation

alanag13
Copy link
Contributor

@alanag13 alanag13 commented Mar 20, 2018

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:

  • Android
  • iOS
  • macOS
  • UWP
  • WPF
  • Tizen (no native platform support)
  • GTK (no native platform support)

API Changes

Added:
Task WebView.EvaluateJavaScriptAsync

PR Checklist

  • Has tests (if omitted, state reason in description)
  • Rebased on top of master at time of PR
  • Changes adhere to coding standard
  • Consolidate commits as makes sense

@alanag13
Copy link
Contributor Author

Question: should WebView.Eval be deprecated in favor of this?

if (Xamarin.Forms.Device.RuntimePlatform != "Android")
{
script = EscapeJsString(script);
script = "try{JSON.stringify(eval('" + script + "'))}catch(e){'null'};";
Copy link
Contributor Author

@alanag13 alanag13 Mar 20, 2018

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.

Copy link

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?

@alanag13
Copy link
Contributor Author

@rmarinho can you give me any insight into why this failed (it looks like only on Windows)?

@samhouts samhouts changed the title Feature/1699 webview evaluate js [Enhancement] Add EvaluateJavaScript method to WebView Mar 20, 2018
@xamarin-release-manager xamarin-release-manager added the API-change Heads-up to reviewers that this PR may contain an API change label Mar 20, 2018
@hartez
Copy link
Contributor

hartez commented Mar 20, 2018

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.

@@ -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)
Copy link
Contributor Author

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.

@alanag13
Copy link
Contributor Author

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.

@xamarin-release-manager xamarin-release-manager added the API-change Heads-up to reviewers that this PR may contain an API change label Mar 21, 2018
Copy link
Member

@rmarinho rmarinho left a 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


static string EscapeJsString(string js)
{
if (!js.Contains("'"))
Copy link
Member

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

Copy link
Contributor Author

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);
Copy link
Member

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;
Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this per @jassmith's recommendation in the issue thread: #1699

@@ -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 });
Copy link
Member

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

@alanag13
Copy link
Contributor Author

@rmarinho updated with your changes

@xamarin-release-manager xamarin-release-manager added the API-change Heads-up to reviewers that this PR may contain an API change label Mar 22, 2018
@rmarinho rmarinho requested a review from samhouts March 22, 2018 14:19
@alanag13
Copy link
Contributor Author

@rmarinho @samhouts are the ui tests failures unrelated? these were all green yesterday before my most recent commit, which seems like it should be pretty harmless . Should I rebase?

@jassmith
Copy link

Doesn't impact fast renderers, therefor merging :)

@jassmith jassmith merged commit 578c0eb into xamarin:master Mar 22, 2018
@alanag13
Copy link
Contributor Author

@jassmith do we want to deprecate Eval in favor of this? To users, the only difference is that this returns a value. Only reason I can think of to not do this is that GTK and Tizen always return null , but it still seems potentially confusing to have both Eval and EvaluateJavaScriptAsync.

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
API-change Heads-up to reviewers that this PR may contain an API change community-sprint F100 t/enhancement ➕
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Enhancement] Add EvaluateJavaScript method to WebView
7 participants