With the below html file, that gets loaded into the document of a winform webBrowser, the functions and events in the scripts do not fire. When the winform displays, it only shows the button with id=paybutton (see form definition). It does not run the 1st script (window.YocoSDK etc) which references an online sdk (as in the src), and which adds a few more fields onto the form. This works in an online java test but not via c# winforms. Can anyone assist.
Secondly, the ShowMessage() function also does not fire on clicking the button.
My guess with both is that the inclusion of the online sdk in the "src" field is not happening.
HTMLPageSample.html file:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='https://js.yoco.com/sdk/v1/yoco-sdk-web.js'></script>
</head>
<body>
<form id='payform' method='POST' >
<div class='one-liner'>
<div id='card-frame'>
</div>
<button id='paybutton' onclick='ShowMessage()'>
PAY ZAR 2.00
</button>
</div>
<p class='success-payment-message' />
</form>
<script>
var sdk = new window.YocoSDK({
publicKey: 'pk_test_blahblah'
});
var inline = sdk.inline({
layout: 'field',
amountInCents: 2000,
currency: 'ZAR'
});
inline.mount('#card-frame');
</script>
<script>
function ShowMessage() {
var form = document.getElementById('payform');
var submitButton = document.getElementById('paybutton');
form.addEventListener('submit', function (event) {
event.preventDefault()
submitButton.disabled = true;
inline.createToken().then(function (result) {
submitButton.disabled = false;
if (result.error) {
const errorMessage = result.error.message;
errorMessage && alert('error occured: ' + errorMessage);
} else {
const token = result;
alert('card successfully tokenised: ' + token.id);
}
}).catch(function (error) {
submitButton.disabled = false;
alert('error occured: ' + error);
});
});
};
</script>
</body>
</html>
//c# code for the windows form
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApp1
{
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public partial class Form1 : Form
{
//Class example
//[ComVisible(true)]
public Form1()
{
InitializeComponent();
webBrowser1.ScriptErrorsSuppressed = true;
}
void Form1_Load(object sender, EventArgs e)
{
string path = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), #"..\..\");
//load the html into the webbrowser document. only the paybutton displays, the referenced library in "src" should call an online sdk that adds the payment fields to the form. these fields do not get added. so it seems the src reference is not working, or the script and form definitions cannot "see" each other?
webBrowser1.Navigate(System.IO.Path.Combine(path, "HTMLPageSample.html"));
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
webBrowser1.ObjectForScripting = this;
}
private void button1_Click(object sender, EventArgs e)
{
//on button click, invoke the script that processes payment (does nothing)
webBrowser1.Document.InvokeScript("ShowMessage" );
}
private void button2_Click(object sender, EventArgs e)
{
//on button click, locate paybutton and invoke click method (does nothing)
foreach (HtmlElement element in webBrowser1.Document.All)
{
if (element.InnerText != null && element.InnerText.ToLower().StartsWith("pay zar"))
{
element.InvokeMember("click");
}
}
}
}
}
When using WebBrowser, it defaults to IE7, unless there is an entry in the registry.
If the process is running as 64-bit, the following registry keys are searched:
HKLM\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
HKCU\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
If the process is running as 32-bit, the following registry keys are searched:
HKLM\SOFTWARE\WOW6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
HKCU\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION
Note: While different registry keys are searched in HKLM, when HKCU is searched, both 32-bit and 64-bit search the same subkey.
Here's a sample registry entry for a program named "MyApp.exe" that emulates IE11.
Below are step-by-step instructions that show how to run a JavaScript function when a button is clicked in C#. It uses a modified version of the HTML that's in the OP.
VS 2019:
Create a new project: Windows Forms App (.NET Framework) (name: WebBrowserTest)
Create a class (name: HelperRegistry.cs)
Note: The following code can be used to add the required entry in the registry when the Form loads. It's adapted from here.
HelperRegistry
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Win32;
using System.Diagnostics;
namespace WebBrowserTest
{
public enum BrowserEmulationVersion
{
Default = 0,
Version7 = 7000,
Version8 = 8000,
Version8Standards = 8888,
Version9 = 9000,
Version9Standards = 9999,
Version10 = 10000,
Version10Standards = 10001,
Version11 = 11000,
Version11Edge = 11001
};
public class HelperRegistry
{
public static BrowserEmulationVersion GetBrowserEmulationVersion()
{
//get browser emmulation version for this program (if it exists)
BrowserEmulationVersion result = BrowserEmulationVersion.Default;
try
{
string programName = System.IO.Path.GetFileName(Environment.GetCommandLineArgs()[0]);
object data = GetValueFromRegistry(RegistryHive.CurrentUser, #"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION", programName);
if (data != null)
{
result = (BrowserEmulationVersion)Convert.ToInt32(data);
}
}
catch (System.Security.SecurityException ex)
{
// The user does not have the permissions required to read from the registry key.
LogMsg("Error: (GetBrowserEmulationVersion - SecurityException) - " + ex.Message);
}
catch (UnauthorizedAccessException ex)
{
// The user does not have the necessary registry rights.
LogMsg("Error: (GetBrowserEmulationVersion - UnauthorizedAccessException) - " + ex.Message);
}
catch (Exception ex)
{
LogMsg("Error: (GetBrowserEmulationVersion) - " + ex.Message);
}
return result;
}
public static int GetInternetExplorerMajorVersion()
{
//get IE version
int result = 0;
string version = string.Empty;
try
{
string programName = System.IO.Path.GetFileName(Environment.GetCommandLineArgs()[0]);
object data = GetValueFromRegistry(RegistryHive.LocalMachine, #"Software\Microsoft\Internet Explorer", "svcVersion");
if (data == null)
data = GetValueFromRegistry(RegistryHive.CurrentUser, #"Software\Microsoft\Internet Explorer", "Version");
if (data != null)
{
version = data.ToString();
int separator = version.IndexOf('.');
if (separator != -1)
{
int.TryParse(version.Substring(0, separator), out result);
}
}
}
catch (System.Security.SecurityException ex)
{
// The user does not have the permissions required to read from the registry key.
LogMsg("Error: (GetInternetExplorerMajorVersion - SecurityException) - " + ex.Message);
}
catch (UnauthorizedAccessException ex)
{
// The user does not have the necessary registry rights.
LogMsg("Error: (GetInternetExplorerMajorVersion - UnauthorizedAccessException) - " + ex.Message);
}
catch (Exception ex)
{
LogMsg("Error: (GetInternetExplorerMajorVersion) - " + ex.Message);
}
return result;
}
private static object GetValueFromRegistry(RegistryHive hive, string subkey, string regValue)
{
//if running as 64-bit, get value from 64-bit registry
//if running as 32-bit, get value from 32-bit registry
RegistryView rView = RegistryView.Registry64;
object data = null;
if (!Environment.Is64BitProcess)
{
//running as 32-bit
rView = RegistryView.Registry32;
}
using (RegistryKey regBaseKey = RegistryKey.OpenBaseKey(hive, rView))
{
using (RegistryKey sKey = regBaseKey.OpenSubKey(subkey))
{
if (sKey != null)
{
data = sKey.GetValue(regValue, null);
if (data != null)
{
LogMsg("data: " + data.ToString());
}
else
{
LogMsg("data is null (" + data + ")");
}
}
}
}
return data;
}
public static bool IsBrowserEmulationSet()
{
return GetBrowserEmulationVersion() != BrowserEmulationVersion.Default;
}
private static void LogMsg(string msg)
{
string logMsg = String.Format("{0} {1}", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss:fff"), msg);
System.Diagnostics.Debug.WriteLine(logMsg);
}
public static bool SetBrowserEmulationVersion()
{
BrowserEmulationVersion emulationCode;
int ieVersion = GetInternetExplorerMajorVersion();
if (ieVersion >= 11)
{
emulationCode = BrowserEmulationVersion.Version11;
}
else
{
switch (ieVersion)
{
case 10:
emulationCode = BrowserEmulationVersion.Version10;
break;
case 9:
emulationCode = BrowserEmulationVersion.Version9;
break;
case 8:
emulationCode = BrowserEmulationVersion.Version8;
break;
default:
emulationCode = BrowserEmulationVersion.Version7;
break;
}
}
return SetBrowserEmulationVersion(emulationCode);
}
public static bool SetBrowserEmulationVersion(BrowserEmulationVersion browserEmulationVersion)
{
bool result = false;
//if running as 64-bit, get value from 64-bit registry
//if running as 32-bit, get value from 32-bit registry
RegistryView rView = RegistryView.Registry64;
if (!Environment.Is64BitProcess)
{
//running as 32-bit
rView = RegistryView.Registry32;
}
try
{
string programName = System.IO.Path.GetFileName(Environment.GetCommandLineArgs()[0]);
using (RegistryKey regBaseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, rView))
{
using (RegistryKey sKey = regBaseKey.OpenSubKey(#"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION", true))
{
if (sKey != null)
{
if (browserEmulationVersion != BrowserEmulationVersion.Default)
{
// if it's a valid value, update or create the value
sKey.SetValue(programName, (int)browserEmulationVersion, Microsoft.Win32.RegistryValueKind.DWord);
}
else
{
// otherwise, remove the existing value
sKey.DeleteValue(programName, false);
}
result = true;
}
}
}
}
catch (System.Security.SecurityException ex)
{
// The user does not have the permissions required to read from the registry key.
LogMsg("Error: (SetBrowserEmulationVersion - SecurityException) - " + ex.Message);
}
catch (UnauthorizedAccessException ex)
{
// The user does not have the necessary registry rights.
LogMsg("Error: (SetBrowserEmulationVersion - UnauthorizedAccessException) - " + ex.Message);
}
catch (Exception ex)
{
LogMsg("Error: (SetBrowserEmulationVersion) - " + ex.Message);
}
return result;
}
}
}
In the Form "Load" event handler add the following:
HelperRegistry.SetBrowserEmulationVersion();
If desired, the HTML can be embedded in the program.
Open Solution Explorer
In VS menu, click View
Select Solution Explorer
Open Properties Window
In VS menu, click View
Select Properties Window
Create HTML folder
In Solution Explorer, right-click <solution name>
Select Add
Select New Folder (rename to desired name; ex: HTML)
Right-click the folder you just created (ex: HTML) and select Add
Select New Item...
Select HTML Page (name: HTMLPageSample.html)
Click Add
Note: If you don't see "HTML Page" as an option, you'll need to open Visual Studio Installer and add a workload that includes HTML.
Set Properties for HTMLPageSample.html
In Solution Explorer, click HTMLPageSample.html
In the Properties Window, set Build Action = Embedded Resource
HTMLPageSample.html
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='https://js.yoco.com/sdk/v1/yoco-sdk-web.js'></script>
<script type="text/javascript">
var sdk = new window.YocoSDK({
publicKey: 'pk_test_blahblah'
});
var inline = sdk.inline({
layout: 'field',
amountInCents: 2000,
currency: 'ZAR'
});
inline.mount('#card-frame');
</script>
<script type="text/javascript">
function ShowMessage() {
try {
//alert('in ShowMessage...');
var form = document.getElementById('payform');
var submitButton = document.getElementById('paybutton');
form.addEventListener('submit', function (event) {
event.preventDefault()
submitButton.disabled = true;
inline.createToken().then(function (result) {
submitButton.disabled = false;
if (result.error) {
const errorMessage = result.error.message;
errorMessage && alert('error occured: ' + errorMessage);
} else {
const token = result;
alert('card successfully tokenised: ' + token.id);
}
}).catch(function (error) {
submitButton.disabled = false;
alert('error occured: ' + error);
});
});
}
catch (err) {
alert(err.message);
}
};
</script>
</head>
<body>
<form id='payform' method='POST'>
<div class='one-liner'>
<div id='card-frame'>
</div>
<button id='paybutton' onclick='ShowMessage()'>
PAY ZAR 2.00
</button>
</div>
<p class='success-payment-message' />
</form>
</body>
</html>
Now, we'll need some code to read the embedded HTML file. We'll use code from here.
Create a class (name: HelperLoadResource.cs)
HelperLoadResource
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using System.Diagnostics;
namespace WebBrowserTest
{
public static class HelperLoadResource
{
public static string ReadResource(string filename)
{
//use UTF8 encoding as the default encoding
return ReadResource(filename, Encoding.UTF8);
}
public static string ReadResource(string filename, Encoding fileEncoding)
{
string fqResourceName = string.Empty;
string result = string.Empty;
//get executing assembly
Assembly execAssembly = Assembly.GetExecutingAssembly();
//get resource names
string[] resourceNames = execAssembly.GetManifestResourceNames();
if (resourceNames != null && resourceNames.Length > 0)
{
foreach (string rName in resourceNames)
{
if (rName.EndsWith(filename))
{
//set value to 1st match
//if the same filename exists in different folders,
//the filename can be specified as <folder name>.<filename>
//or <namespace>.<folder name>.<filename>
fqResourceName = rName;
//exit loop
break;
}
}
//if not found, throw exception
if (String.IsNullOrEmpty(fqResourceName))
{
throw new Exception($"Resource '{filename}' not found.");
}
//get file text
using (Stream s = execAssembly.GetManifestResourceStream(fqResourceName))
{
using (StreamReader reader = new StreamReader(s, fileEncoding))
{
//get text
result = reader.ReadToEnd();
}
}
}
return result;
}
}
}
Usage:
string html = HelperLoadResource.ReadResource("HTMLPageSample.html");
Next, we'll work on our Form (name: Form1).
In Solution Explorer, right-click Form1.cs
Select View Designer
Open the Toolbox
In the VS menu, click View
Select Toolbox
Add WebBrowser to Form
In Toolbox, click on WebBrowser and drag it on top of the Form
Add Button to Form
In Toolbox, click on Button and drag it on top of the form
In the Properties Window, rename the button (name: btnSubmit)
Add Load event Handler to Form
In the Properties Window, click on
Double-click Load, to add the event handler
Whenever a page is loaded in the WebBrowser, either by using Navigate or by setting the DocumentText, it's important to wait until it is fully loaded. We'll create a method for the wait operation. I normally avoid using "DoEvents", but we'll use it this time.
private void WaitForBrowserToBeReady(int sleepTimeInMs = 125)
{
do
{
System.Threading.Thread.Sleep(sleepTimeInMs);
Application.DoEvents();
} while (webBrowser1.ReadyState != WebBrowserReadyState.Complete);
}
Now in Form1_Load, add the following code:
private void Form1_Load(object sender, EventArgs e)
{
//set browser emulation in registry
HelperRegistry.SetBrowserEmulationVersion();
//suppress script errors
webBrowser1.ScriptErrorsSuppressed = true;
//string path = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), #"..\..\");
//load the html into the webbrowser document. only the paybutton displays, the referenced library in "src"
//should call an online sdk that adds the payment fields to the form. these fields do not get added. so
//it seems the src reference is not working, or the script and form definitions cannot "see" each other?
//webBrowser1.Navigate(System.IO.Path.Combine(path, "HTMLPageSample.html"));
string html = HelperLoadResource.ReadResource("HTMLPageSample.html");
if (Environment.Is64BitProcess)
{
Debug.WriteLine("Running as 64-bit");
}
else
{
Debug.WriteLine("Running as 32-bit");
}
//initialize WebBrowser
webBrowser1.Navigate("about:blank");
WaitForBrowserToBeReady();
//set HTML
webBrowser1.DocumentText = html;
WaitForBrowserToBeReady();
//Debug.WriteLine(webBrowser1.DocumentText);
}
As stated in the OP, when the button is click it's desired that the ShowMessage() javascript function be called. Due to the way the JavaScript function is written, we'll do the following:
HtmlElementCollection col = webBrowser1.Document.GetElementsByTagName("button");
foreach (HtmlElement element in col)
{
if (element.GetAttribute("id").Equals("paybutton"))
{
element.InvokeMember("click"); // Invoke the "Click" member of the button
}
}
Note: While the following will also call ShowMessage(),
object result = webBrowser1.Document.InvokeScript("ShowMessage");
it won't give the desired result due to form.addEventListener('submit'... which requires a "click".
Here's the full code for Form1.cs.
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WebBrowserTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//set browser emulation in registry
HelperRegistry.SetBrowserEmulationVersion();
//suppress script errors
webBrowser1.ScriptErrorsSuppressed = true;
//string path = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), #"..\..\");
//load the html into the webbrowser document. only the paybutton displays, the referenced library in "src"
//should call an online sdk that adds the payment fields to the form. these fields do not get added. so
//it seems the src reference is not working, or the script and form definitions cannot "see" each other?
//webBrowser1.Navigate(System.IO.Path.Combine(path, "HTMLPageSample.html"));
string html = HelperLoadResource.ReadResource("HTMLPageSample.html");
if (Environment.Is64BitProcess)
{
Debug.WriteLine("Running as 64-bit");
}
else
{
Debug.WriteLine("Running as 32-bit");
}
//initialize WebBrowser
webBrowser1.Navigate("about:blank");
WaitForBrowserToBeReady();
//set HTML
webBrowser1.DocumentText = html;
WaitForBrowserToBeReady();
//Debug.WriteLine(webBrowser1.DocumentText);
}
private void LogMsg(string msg)
{
string logMsg = String.Format("{0} {1}", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss:fff"), msg);
System.Diagnostics.Debug.WriteLine(logMsg);
}
private void btnSubmit_Click(object sender, EventArgs e)
{
//object result = webBrowser1.Document.InvokeScript("ShowMessage", null);
//object result = webBrowser1.Document.InvokeScript("ShowMessage");
HtmlElementCollection col = webBrowser1.Document.GetElementsByTagName("button");
foreach (HtmlElement element in col)
{
if (element.GetAttribute("id").Equals("paybutton"))
{
element.InvokeMember("click"); // Invoke the "Click" member of the button
}
}
}
private void WaitForBrowserToBeReady(int sleepTimeInMs = 125)
{
do
{
System.Threading.Thread.Sleep(sleepTimeInMs);
Application.DoEvents();
} while (webBrowser1.ReadyState != WebBrowserReadyState.Complete);
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
}
}
}
Resources:
How to Click A Button Programmatically - Button in WebBrowser (IE)
Calling JavaScript functions in the Web Browser Control
Execute a JS function in WebBrowser C#
Configuring the Emulation Mode of an Internet Explorer WebBrowser Control
How to read embedded resource text file
C# WebBrowser control: window.external access sub object
Here's a version that uses WebView2. Below are step-by-step instructions that show how to run a JavaScript function when a button is clicked in C#. It uses a modified version of the HTML that's in the OP.
VS 2019:
Create a new project: Windows Forms App (.NET Framework) (name: WebView2SM)
If desired, the HTML can be embedded in the program.
Open Solution Explorer
In VS menu, click View
Select Solution Explorer
Open Properties Window
In VS menu, click View
Select Properties Window
Create HTML folder
In Solution Explorer, right-click <solution name>
Select Add
Select New Folder (rename to desired name; ex: HTML)
Right-click the folder you just created (ex: HTML) and select Add
Select New Item...
Select HTML Page (name: HTMLPageSample.html)
Click Add
Note: If you don't see "HTML Page" as an option, you'll need to open Visual Studio Installer and add a workload that includes HTML.
Set Properties for HTMLPageSample.html
In Solution Explorer, click HTMLPageSample.html
In the Properties Window, set Build Action = Embedded Resource
HTMLPageSample.html
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='https://js.yoco.com/sdk/v1/yoco-sdk-web.js'></script>
<script type="text/javascript">
var sdk = new window.YocoSDK({
publicKey: 'pk_test_blahblah'
});
var inline = sdk.inline({
layout: 'field',
amountInCents: 2000,
currency: 'ZAR'
});
inline.mount('#card-frame');
</script>
<script type="text/javascript">
function ShowMessage() {
try {
//alert('in ShowMessage...');
var form = document.getElementById('payform');
var submitButton = document.getElementById('paybutton');
form.addEventListener('submit', function (event) {
event.preventDefault()
submitButton.disabled = true;
inline.createToken().then(function (result) {
submitButton.disabled = false;
if (result.error) {
const errorMessage = result.error.message;
errorMessage && alert('error occured: ' + errorMessage);
} else {
const token = result;
alert('card successfully tokenised: ' + token.id);
}
}).catch(function (error) {
submitButton.disabled = false;
alert('error occured: ' + error);
});
});
}
catch (err) {
alert(err.message);
}
};
</script>
</head>
<body>
<form id='payform' method='POST'>
<div class='one-liner'>
<div id='card-frame'>
</div>
<button id='paybutton' onclick='ShowMessage()'>
PAY ZAR 2.00
</button>
</div>
<p class='success-payment-message' />
</form>
</body>
</html>
Now, we'll need some code to read the embedded HTML file. We'll use code from here.
Create a class (name: HelperLoadResource.cs)
HelperLoadResource
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using System.Diagnostics;
namespace WebView2SM
{
public static class HelperLoadResource
{
public static string ReadResource(string filename)
{
//use UTF8 encoding as the default encoding
return ReadResource(filename, Encoding.UTF8);
}
public static string ReadResource(string filename, Encoding fileEncoding)
{
string fqResourceName = string.Empty;
string result = string.Empty;
//get executing assembly
Assembly execAssembly = Assembly.GetExecutingAssembly();
//get resource names
string[] resourceNames = execAssembly.GetManifestResourceNames();
if (resourceNames != null && resourceNames.Length > 0)
{
foreach (string rName in resourceNames)
{
if (rName.EndsWith(filename))
{
//set value to 1st match
//if the same filename exists in different folders,
//the filename can be specified as <folder name>.<filename>
//or <namespace>.<folder name>.<filename>
fqResourceName = rName;
//exit loop
break;
}
}
//if not found, throw exception
if (String.IsNullOrEmpty(fqResourceName))
{
throw new Exception($"Resource '{filename}' not found.");
}
//get file text
using (Stream s = execAssembly.GetManifestResourceStream(fqResourceName))
{
using (StreamReader reader = new StreamReader(s, fileEncoding))
{
//get text
result = reader.ReadToEnd();
}
}
}
return result;
}
}
}
Usage:
string html = HelperLoadResource.ReadResource("HTMLPageSample.html");
Change/Verify NuGet Package Manager Settings (optional for .NET Framework; required for .NET)
In VS menu, click Tools
Select Options
Double-click NuGet Package Manager
Under "Package Management", set Default package management format: PackageReference
Click OK
See the following for more information:
Package references (PackageReference) in project files
Migrate from packages.config to PackageReference
Add WebView2 NuGet package
In Solution Explorer, right-click <solution name> (ex: WebView2SM)
Select Manage NuGet packages...
Click Browse
Optional: check Include prerelease box next to the search box
In search box, type: Microsoft.Web.WebView2
Select the desired version
Click Install
If you see a pop-up, click OK
Note: To add WebView2 to just the project, instead of the solution, right-click <project name> instead of <solution name>.
Next, we'll work on our Form (name: Form1).
In Solution Explorer, right-click Form1.cs
Select View Designer
Open the Toolbox
In the VS menu, click View
Select Toolbox
Add WebView2 to Form
In Toolbox, click on WebView2 Windows Control Form to expand it
Click on WebView2 and drag it on top of the Form
Resize the WebView2 control as desired
Add Button to Form
In Toolbox, click on Button and drag it on top of the form
In the Properties Window, rename the button (name: btnSubmit)
In the Properties Window, click
Double-click Click, to add the event handler
Add Load event Handler to Form
In the Properties Window, click
Double-click Load, to add the event handler
Add CoreWebView2InitializationCompleted event handler
In Solution Explorer, right-click Form1.cs
Select View Designer
In Properties Window, click
Click on the drop-down and select the WebView2 control (ex: webView21)
Double-click CoreWebView2InitializationCompleted
Optional: double-click NavigationCompleted (repeat for any other desired event handlers)
Now, it's we'll work on the code for the Form.
In Solution Explorer, right-click Form1.cs
Select View Code
For testing, we'll add a method named LogMsg.
private void LogMsg(string msg)
{
string logMsg = String.Format("{0} {1}", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss:fff"), msg);
System.Diagnostics.Debug.WriteLine(logMsg);
}
This method can be modified as desired. If desired, one could write the information to a log file. If you already have a method for logging, you can use that instead. I've included this one, because it's used in the code.
In order to set the desired location for the web cache that will be created, we'll explicitly initialize WebView2. We'll call it InitializeCoreWebView2Async. We'll also create a method that can be used to add code using AddScriptToExecuteOnDocumentCreatedAsync.
Note: It's necessary to use async when using await. Notice the use of Task instead of void. If void is used, execution will continue without waiting.
AddScriptToExecuteOnDocumentCreatedAsync
private async Task AddExecuteOnDocumentCreatedAsyncCode()
{
if (webView21 != null && webView21.CoreWebView2 != null)
{
string jsCode = string.Empty;
//ToDo: add desired code using 'AddScriptToExecuteOnDocumentCreatedAsync'
if (!String.IsNullOrEmpty(jsCode))
{
await webView21.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(jsCode);
}
}
}
InitializeCoreWebView2Async
public async Task InitializeCoreWebView2Async(WebView2 wv, string webCacheDir = "")
{
CoreWebView2EnvironmentOptions options = null;
string tempWebCacheDir = string.Empty;
CoreWebView2Environment webView2Environment = null;
//set value
tempWebCacheDir = webCacheDir;
if (String.IsNullOrEmpty(tempWebCacheDir))
{
//use temp folder
//get fully-qualified path to user's temp folder
tempWebCacheDir = System.IO.Path.GetTempPath();
//create a randomly named folder - this will create a new web cache folder each time
//creating a new web cache folder takes time. By re-using an existing web cache,
//the load time will be shorter. However, one may need to manage (clean-up)
//objects in the web cache that are no longer needed
//tempWebCacheDir = System.IO.Path.Combine(tempWebCacheDir, System.Guid.NewGuid().ToString("N"));
}
//webView2Environment = await CoreWebView2Environment.CreateAsync(#"C:\Program Files (x86)\Microsoft\Edge Dev\Application\1.0.902.49", tempWebCacheDir, options);
webView2Environment = await CoreWebView2Environment.CreateAsync(null, tempWebCacheDir, options);
//wait for CoreWebView2 initialization
await wv.EnsureCoreWebView2Async(webView2Environment);
//add desired code using AddScriptToExecuteOnDocumentCreatedAsync
await AddExecuteOnDocumentCreatedAsyncCode();
LogMsg("Info: Cache data folder set to: " + tempWebCacheDir);
}
Usage:
await InitializeCoreWebView2Async(webView21);
Now in Form1_Load, add the following code:
private async void Form1_Load(object sender, EventArgs e)
{
//initialize
await InitializeCoreWebView2Async(webView21);
string html = HelperLoadResource.ReadResource("HTMLPageSample.html");
webView21.NavigateToString(html);
}
Once WebView2 initialization is completed, we'll add any desired event handlers for CoreWebView2. We'll add them in CoreWebView2InitializationCompleted.
private void webView21_CoreWebView2InitializationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e)
{
//subscribe to events (add event handlers)
webView21.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;
}
Note: Don't place any code in the event handler that could cause "blocking".
As stated in the OP, when the button is click it's desired that the ShowMessage() javascript function be called. Due to the way the JavaScript function is written, we'll do the following:
var result = await webView21.CoreWebView2.ExecuteScriptAsync("document.getElementById('paybutton').click();");
Note: While the following will also call ShowMessage(),
var result = await webView21.CoreWebView2.ExecuteScriptAsync("ShowMessage();");
it won't give the desired result due to form.addEventListener('submit'... which requires a "click".
Here's the full code for Form1.cs.
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
namespace WebView2SM
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e)
{
//initialize
await InitializeCoreWebView2Async(webView21);
string html = HelperLoadResource.ReadResource("HTMLPageSample.html");
webView21.NavigateToString(html);
}
private async Task AddExecuteOnDocumentCreatedAsyncCode()
{
if (webView21 != null && webView21.CoreWebView2 != null)
{
string jsCode = string.Empty;
//ToDo: add desired code using 'AddScriptToExecuteOnDocumentCreatedAsync'
if (!String.IsNullOrEmpty(jsCode))
{
await webView21.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync(jsCode);
}
}
}
private async Task InitializeCoreWebView2Async()
{
//initialize CorewWebView2
await webView21.EnsureCoreWebView2Async();
//add desired code using AddScriptToExecuteOnDocumentCreatedAsync
await AddExecuteOnDocumentCreatedAsyncCode();
}
public async Task InitializeCoreWebView2Async(WebView2 wv, string webCacheDir = "")
{
CoreWebView2EnvironmentOptions options = null;
string tempWebCacheDir = string.Empty;
CoreWebView2Environment webView2Environment = null;
//set value
tempWebCacheDir = webCacheDir;
if (String.IsNullOrEmpty(tempWebCacheDir))
{
//use temp folder
//get fully-qualified path to user's temp folder
tempWebCacheDir = System.IO.Path.GetTempPath();
//create a randomly named folder - this will create a new web cache folder each time
//creating a new web cache folder takes time. By re-using an existing web cache,
//the load time will be shorter. However, one may need to manage (clean-up)
//objects in the web cache that are no longer needed
//tempWebCacheDir = System.IO.Path.Combine(tempWebCacheDir, System.Guid.NewGuid().ToString("N"));
}
//webView2Environment = await CoreWebView2Environment.CreateAsync(#"C:\Program Files (x86)\Microsoft\Edge Dev\Application\1.0.902.49", tempWebCacheDir, options);
webView2Environment = await CoreWebView2Environment.CreateAsync(null, tempWebCacheDir, options);
//wait for CoreWebView2 initialization
await wv.EnsureCoreWebView2Async(webView2Environment);
//add desired code using AddScriptToExecuteOnDocumentCreatedAsync
await AddExecuteOnDocumentCreatedAsyncCode();
LogMsg("Info: Cache data folder set to: " + tempWebCacheDir);
}
private void LogMsg(string msg)
{
string logMsg = String.Format("{0} {1}", DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss:fff"), msg);
System.Diagnostics.Debug.WriteLine(logMsg);
}
private void webView21_CoreWebView2InitializationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e)
{
//subscribe to events (add event handlers)
webView21.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;
}
private void CoreWebView2_DOMContentLoaded(object sender, Microsoft.Web.WebView2.Core.CoreWebView2DOMContentLoadedEventArgs e)
{
}
private void webView21_NavigationCompleted(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs e)
{
}
private async void btnSubmit_Click(object sender, EventArgs e)
{
//var result = await webView21.CoreWebView2.ExecuteScriptAsync("ShowMessage();");
var result = await webView21.CoreWebView2.ExecuteScriptAsync("document.getElementById('paybutton').click();");
}
}
}
Resources
Introduction to Microsoft Edge WebView2
Release notes for WebView2 SDK
Understand WebView2 SDK versions
Report An Issue With WebView2
Distribution of apps using WebView2
Get started with WebView2 in Windows Forms
Download the WebView2 Runtime
What is .NET Framework?
Introduction to .NET
.NET Core/5+ vs. .NET Framework for server apps
I'm having an issue with the functions to be called not firing off.
I have moved from hardcoding the buttons on HTML, to using the add controls method in the cs; and I have shifted from using Button and HtmlButton to using LinkButton. However none of these seem to work. In Onserverclick and onclick not work Anup Sharma recommends using the LinkButton, and Keyvan Sadralodabai indicates that if the runat="server" is displayed in the insect element, then he control was set up wrong.
So here's a stripped down simplified version of what I'm working with:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Services;
using System.Data;
using MySql.Data;
using MySql.Data.MySqlClient;
public partial class backCodeExper : System.Web.UI.Page
{
protected void saveRecord(string recordID, string buttonId, string dropdownId)
{
PlaceHolder db = Page.FindControl("TestingCS") as PlaceHolder;
HtmlTable tbl = db.FindControl("TestTable") as HtmlTable;
HtmlTableRow tr = tbl.FindControl("TheRow") as HtmlTableRow;
HtmlTableCell tc = tr.FindControl("TheCell2") as HtmlTableCell;
DropDownList ddl = tc.FindControl(dropdownId) as DropDownList;
var status = ddl.SelectedValue.ToString();
HttpContext context = HttpContext.Current;
MySqlConnection conn = new MySqlConnection();
conn.ConnectionString = "Server=localhost; Database********; User=********; Password=********; Port=3306";
conn.Open();
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "updatetesttable";
cmd.Parameters.AddWithValue("#param", status);
cmd.ExecuteNonQuery();
}
protected void Page_Load(object sender, EventArgs e)
{
HtmlTable myTable = new HtmlTable();
myTable.ID = "TestTable";
myTable.BorderColor = "teal";
myTable.BgColor = "black";
TestingCS.Controls.Add(myTable);
HtmlTableRow newRow;
HtmlTableCell cell;
DropDownList DropList;
LinkButton saveButton;
newRow = new HtmlTableRow();
newRow.ID = "TheRow";
cell = new HtmlTableCell();
cell.ID = "TheCell1";
DropList = new DropDownList();
DropList.ID = "StatusDD";
DropList.Items.Add(new ListItem("", "0"));
DropList.Items.Add(new ListItem("A", "1"));
DropList.Items.Add(new ListItem("B", "2"));
DropList.Items.Add(new ListItem("C", "3"));
cell.Controls.Add(DropList);
newRow.Cells.Add(cell);
cell = new HtmlTableCell();
cell.ID = "TheCell2";
cell.BgColor = "black";
saveButton = new LinkButton();
saveButton.ID = "saveButton";
saveButton.CommandName = "saveRecord";
saveButton.CommandArgument = "'1A',this.id,'StatusDD'";
saveButton.BackColor=Color.Green;
saveButton.ForeColor=Color.Cyan;
saveButton.BorderColor=Color.Maroon;
saveButton.Text = "Save";
saveButton.Visible = true;
cell.Controls.Add(saveButton);
newRow.Cells.Add(cell);
myTable.Rows.Add(newRow);
}
}
It loads the screen just fine with the simple dropdown and with the (unstylish) button (frankly the HtmlButton looks much nicer, but I'm aiming for functionality first).
When I select an item from the dropdown and then click save, the screen appears to refresh, keeping the value of the dropdown the same as that which was selected. However, when I check the database, the procedure hasn't fired. Additionally I cannot get this code segment Response.Write("<script>alert('Hello');</script>"); to execute when placed in the method/function saveRecord.
Furthermore, when I run the debugging mode and put break points in saveRecord, none of them are hit.
After inspecting element, this is what I get:
InspectElementResults
Any suggestions? What am I missing?
If I don't use LinkButton (or Button/HtmlButton with onServerClick) then I get errors saying the function isn't defined - which makes since as the function/method is define on the aspx.cs not the aspx within JS script tags.
I've got it figured out. At least, it is functional.
I was trying to set the function to pass the values I want in the format I wanted, but apparently the when you set up a LinkButton, it prefers the object and Event Args as parameters, and the object is the ListButton itself, so if that ListButton object holds the values you need in its attributes, then when the function is called you parse out the attributes you need. There's likely a better way than to assign the two values I need to CommandName and CommandArgument, but this works. (I had thought of using .Attributes.Add("ROW_ID","1a") and .Attributes.Add("DD_ID","StatusDD") ... but couldn't initially figure out how to retrieve those values from the sender object...to be investigated later, in the meantime, rolling forward with a functional solution.
...
protected void saveRecord(object sender, EventArgs e)
{
LinkButton lb = (LinkButton)sender;
string ROW_ID = (string)lb.CommandName;
string DD_ID = (string)lb.CommandArgument;
Response.Write("<script>alert('Hello');</script>");
...
}
protected void Page_Load(object sender, EventArgs e)
{
...
saveButton.CommandName = "1a";
saveButton.CommandArgument = "StatusDD";
saveButton.Click += new EventHandler(saveRecord);
...
}
}
I am trying to scrape the web page with C# and I am using HtmlAgilityPack it works good for me, but I got an issue with this website when I need to scrape data from another page of product list. Because link doesn't have page number so I cannot access it by changing link. I found out that page is changed by javascript "__doPostBack" function which doesn't changes the link, just reloads the page, and loads the data.
This is my code for scraping code and price of the product in this web site, however there are more products in other page e.g 2, 3, 4, 5... I need to scrape data from all of these. On other websites I can do just simply passing link to web.Load("Link"); and it works well because link is changing when you change page of product list. In this example link is not changing when other page of the list is selected.
public class CodeAndPrice
{
public string Code { get; set; }
public string Price { get; set; }
}
public partial class Form1 : Form
{
DataTable table;
HtmlWeb web = new HtmlWeb();
public Form1()
{
InitializeComponent();
InitTable();
}
private void InitTable()
{
table = new DataTable("DataTableTest");
table.Columns.Add("Code", typeof(string));
table.Columns.Add("Price", typeof(string));
dataGridView.DataSource = table;
}
private async Task<List<CodeAndPrice>> DataScraping (){
var page = await Task.Factory.StartNew(() => web.Load("https://www.kilobaitas.lt/Kompiuteriai/Plansetiniai_(Tablet)/CatalogStore.aspx?CatID=PL_626"));
var codesNodes = page.DocumentNode.SelectNodes("//td[#class='mainContent']//div[#class='itemNormal']//div[#class='itemCode']");
var pricesNodes = page.DocumentNode.SelectNodes("//td[#class='mainContent']//div[#class='itemNormal']//div[#class='itemCode']//parent::div//div[#class='itemBoxPrice']");
if (codesNodes == null || pricesNodes == null)
return new List<CodeAndPrice>();
var codes = codesNodes.Select(node => node.InnerText.Replace("kodas", "").Replace(" ", "").Replace(": ", ""));
var prices = pricesNodes.Select(node => node.InnerText.Replace(" ", "").Replace(" €", ""));
return codes.Zip(prices, (code,price)=> new CodeAndPrice() { Code = code, Price = price }).ToList();
}
private async void Form1_Load(object sender, EventArgs e)
{
var results = await DataScraping();
foreach (var rez in results) {
table.Rows.Add(rez.Code, rez.Price);
}
}
}
Passing __doPostBack('designer1$ctl11$ctl00$MainCatalogSquare1$XDataPaging1','paging.1'); into the browser's console, page 2 is loaded, by changing "paging.*", browser loads page *+1
What is the simplest way to manipulate javascript, that I will be able to change page while scraping data and scrape data from other pages of this website?
I'm making a very simple form in HTML which is viewed in android using the webview which takes in your name using a textbox and when you click on the button, it displays it into a paragraph and it's made using both html and javascript.
This is my html code:
<!DOCTYPE html>
<html>
<body>
<p> Write your name and win your favorite game console name and win it! The winners will be announced in 4 days.</p>
Type your name here: <input id="thebox" type="text" name="value" value=""><br>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<script>
function myFunction() {
var x = document.getElementById("thebox").value;
document.getElementById("demo").innerHTML = x;
}
</script>
</body>
</html>
NEW EDITED FORM
<form name="albert" action="" method="POST">
<label for="firstname"> First Name </label>
<br /><br />
<input type="text" name="firstname" id="firstname" />
<input type="submit" name="sbumit" value="Submit" />
</form>
I want to get the value from the input box called "thebox" in a variable in android on the button click and I tried lots of stuff before and I followed a method where you inject a JS file but since I know nothing about JS so I did fail trying that and here is the file that I put in my project and the file is called inject.js:
document.getElementsByTagName('form')[0].onsubmit = function () {
var objPWD, objAccount, objSave;
var str = '';
var inputs = document.getElementsByTagName('thebox');
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].name.toLowerCase() === 'thebox') {
objAccount = inputs[i];
}
}
if(objAccount != null) {
str += objAccount.value;
}
if(objPWD != null) {
str += ' , ' + objPWD.value;
}
if(objSave != null) {
str += ' , ' + objSave.value;
}
window.AndroidInterface.processHTML(str);
return true;
};
And later as I followed that article it said that I need to put some stuff in my MainActivity but since I'm using webview for the first time, I couldn't understand much and heres the code I put into my MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView = new WebView(this);
this.setContentView(webView);
// enable javascript
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new JavaScriptInterface(), "AndroidInterface");
// catch events
webView.setWebViewClient(new WebViewClient(){
#Override
public void onPageFinished(WebView view, String url) {
try {
view.loadUrl("javascript:" + buildInjection());
} catch (IOException e) {
e.printStackTrace();
}
}
});
webView.loadUrl("http://someurl.com");
}
A nested class that I made in my MainActivity:
class JavaScriptInterface {
#JavascriptInterface
public void processHTML(String formData) {
Log.d("AWESOME_TAG", "form data: " + formData);
}
}
And finally the method that injects the code:
private String buildInjection() throws IOException {
StringBuilder buf = new StringBuilder();
InputStream inject = getAssets().open("inject.js");// file from assets
BufferedReader in = new BufferedReader(new InputStreamReader(inject, "UTF-8"));
String str;
while ((str = in.readLine()) != null) {
buf.append(str);
}
in.close();
return buf.toString();
}
I want to get value from the html form(the-input-box) that I show in a webview in Android and is it really possible to do that and if yes how and please explain? Thanks and also please tell in what variable will I get the value.
Webview browser=(WebView)view.findViewById(R.id.webChart);
browser.getSettings().setJavaScriptEnabled(true);
browser.addJavascriptInterface(new WebAppInterface(getActivity()), "Android");
browser.loadUrl("file:///android_asset/yourHtmlFileName.html");
add this interface class, WebAppInterface
public class WebAppInterface {
Context mContext;
String data;
WebAppInterface(Context ctx){
this.mContext=ctx;
}
#JavascriptInterface
public void sendData(String data) {
//Get the string value to process
this.data=data;
}
}
your HTML code data
function loadChartData() {
var x = document.getElementById("thebox").value;
Android.sendData(x);
}
call this function when the html button click in android webview
UPDATE
1) By default javascript is disabled in webview . to enable it, get the settings of the webview and call the setJavaScriptEnabled(true); to true.
2) to create the interface between your Javascript code and your android code, you need to create Javacript interface class.
3) bind the interface between your javascript code to android code, you need to pass the reference of the interface class and an interface name that your javaScript can call to access the class.
4) pass the html file path to load into the webview(browser).
5) create the interface class like below(WebAppInterface).
see this link for more details
https://developer.android.com/guide/webapps/webview.html
6) in HTML file, create the button and add the click listener to that button and call the sendData("your value") function with interface name(Here Android).
Thats all. you can pass the value from html to your android code.
Yes you can, you can use javascript to get webpage content. Then use the webview jsInterface to return the content to you java code.
Refer this github project. and this answer and this article.
final Context myApp = this;
/* An instance of this class will be registered as a JavaScript interface */
class MyJavaScriptInterface
{
#JavascriptInterface
#SuppressWarnings("unused")
public void processHTML(String html)
{
// process the html as needed by the app
}
}
final WebView browser = (WebView)findViewById(R.id.browser);
/* JavaScript must be enabled if you want it to work, obviously */
browser.getSettings().setJavaScriptEnabled(true);
/* Register a new JavaScript interface called HTMLOUT */
browser.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");
/* WebViewClient must be set BEFORE calling loadUrl! */
browser.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url)
{
/* This call inject JavaScript into the page which just finished loading. */
browser.loadUrl("javascript:window.HTMLOUT.processHTML('<head>'+document.getElementsByTagName('html')[0].innerHTML+'</head>');");
}
});
/* load a web page */
browser.loadUrl("http://lexandera.com/files/jsexamples/gethtml.html");
Hope this helps.
For forms with method "GET" you can achieve this pretty simple just by overriding shouldOverrideUrlLoading method. Following solution works only if url was loaded through webview.loadUrl() method.
private class MWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// submit will end-up with url like "data:,?firstname=SomeInput&sbumit=Submit"
if (URLUtil.isDataUrl(url)) {
url = url.replace(":,?", ":/?"); //to be able to properly parse Uri
Uri uri = Uri.parse(url);
//here you can get params by field name
String firstname = uri.getQueryParameter("firstname");
//we handle this URL ourselves
return true;
}
return super.shouldOverrideUrlLoading(view, url);
}
}
To communicate a webView with native android,
this is a simple way :
in your js onClick on the button you should call url that contains your text, something like myPrefix://myData
and in android
webView.setWebViewClient(new WebViewClient()
{
#Override
public boolean shouldOverrideUrlLoading(final WebView view, final String url)
{
if(url.startsWith("myPrefix://"))
{
//get your data by split url
return true;
}
return false;
});
#Shariq
As many have already answered this question in a good way, but i think moreover you need clarification about how exactly data is flowing into the codes from webview to andorid so I won't waste bytes in writing that all redundant codes:
(I'm taking reference of your codes for better understanding )
Follow these steps in these codes to make better understanding:
Step 1:
We need to define some method on Android side that can accept some data from webview
#JavascriptInterface
//this 'formData' variable is going to accept the data from webview
public void processHTML(String formData) {
Log.d("AWESOME_TAG", "form data: " + formData);
}
Now the it's value will be available to java android side context.
Step 2:
here is your HTML side codes (webview).
if the URL you are accessing in webview is yours then you can easily write these codes to html page but if you are accessing some third party URL still you can inject this js code into webview simply by following line of code:
...
//partial code
webView.load("javascript:function myFunction() { var x = document.getElementById('thebox').value; Android.processHTML(x); } myFunction();";
...
So what's exactly happening here:
'x' is the variable in js holding the required value and then we are sending this 'x' variable to android context via method call Android.processHTML(x)
I hope it might help you in a better way
Yes, it is possible. Please try using the below code
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web_view_layout);
WebView webView = (WebView) findViewById(R.id.webView);
webView.getSettings().setPluginState(WebSettings.PluginState.ON);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
try {
progressDialog = new ProgressDialog(ActivityName);
progressDialog.setMessage("Loading.."); progressDialog.setCancelable(false);
webView.setWebViewClient(new MyWebViewClient());
webView.loadUrl(YOUR_URL);
} catch (Exception e) {
e.toString();
}
}
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
progressDialog.dismissProgress();
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
progressDialog.dismissProgress();
}
}
You can get data from WebView by catching alert messages.
Use WebChromeClient.
mWebview = (WebView)findViewById(R.id.yourwebviewlayout);
final class YourWebChromeClient extends WebChromeClient {
#Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Toast.makeText(getApplicationContext(),
"alert message = " + message,
Toast.LENGTH_SHORT).show();
result.confirm();
return true;
}
}
mWebview.setWebChromeClient(new YourWebChromeClient());
Best js to inject have used so far, it collects data from all forms on submit
document.getElementsByTagName("form")[0].addEventListener("submit", myFunction);
function myFunction()
{
var data="";
var inputs = document.forms[0].getElementsByTagName('input');
for (var i = 0; i < inputs.length; i++) {
var field = inputs[i];
if (field.type != 'submit' && field.type != 'reset' && field.type != 'button')
data += '' + field.name + '=' + field.value+'\n';
}
window.AndroidInterface.processHTML(data);
return true;
}