Invoke Javascript event on control from C# web browser control - javascript

I am working on a web scraper in C# where I have a web browser control that loads a web page, I then collect data and depending on the data also acting on it. My problem is that I need to write some data to a input (textbox) that has listeners. The input control never shows a value in the html, it is handled by some Javascript that is fired from events on the control. I can set a value to the controls value parameter but it is as it is missing when I click OK on the form.
I have searched the web for days and I now know how to call Javascript from C# but it's the Javascript function on the input i cannot understand.
The input control looks like this:
<div id="size_1" class="incrementControl" style="width: 68px;">
<input id="size_1-input" class="hasListeners" maxlength="6" tabindex="103" value="" style="width:52px">
<a id="size_1-up" class="up hasListeners" style="left:52px" href="javascript:void(0)"> </a>
<a id="size_1-down" class="down hasListeners" style="left:52px" href="javascript:void(0)"> </a>
</div>
The input controls event keyup, keydown, change, keypress and blur all call this Javascript:
function (a)
{
return typeof f != "undefined" && (!a || f.event.triggered !== a.type) ? f.event.dispatch.apply(i.elem, arguments) : b;
}
I have tried invoking different events like onClick and clicking the control programmatically but nothing works?! I donĀ“t know how to call this Javascript function since it doesn't have a name and what to pass as a parameter?
Most grateful for any help or ideas!

You can use Watin. It support Webbrowser control and Internet Explorer.

Here are a number of extension methods (built on top of WatiN) that allow you to (amongst other things) to wait for JS objects or events:
using System;
using System.Threading;
using FluentSharp.Web35;
using FluentSharp.WinForms;
using FluentSharp.CoreLib;
using FluentSharp.CoreLib.API;
namespace FluentSharp.Watin
{
public static class WatiN_IE_ExtensionMethods_Javascript
{
public static object invokeScript(this WatiN_IE ie, string functionName)
{
return ie.invokeScript(functionName, null);
}
public static object invokeScript(this WatiN_IE ie, string functionName, params object[] parameters)
{
//"[WatiN_IE] invokeScript '{0}' with parameters:{1}".info(functionName ,parameters.size());
return ie.invokeScript(true, functionName, parameters);
}
public static object invokeScript(this WatiN_IE ie, bool waitForExecutionComplete, string functionName, params object[] parameters)
{
var sync = new AutoResetEvent(false);
object responseValue = null;
ie.WebBrowser.invokeOnThread(
()=>{
var document = ie.WebBrowser.Document;
if (parameters.isNull())
responseValue = document.InvokeScript(functionName);
else
responseValue = document.InvokeScript(functionName, parameters);
sync.Set();
});
if (waitForExecutionComplete)
sync.WaitOne();
return responseValue;
}
public static object invokeEval(this WatiN_IE ie, string evalScript)
{
var evalParam = "(function() { " + evalScript + "})();";
//"[WatiN_IE] invokeEval evalParam: {0}".debug(evalParam);
return ie.invokeScript("eval", evalParam);
}
public static WatiN_IE.ToCSharp injectJavascriptFunctions(this WatiN_IE ie)
{
return ie.injectJavascriptFunctions(false);
}
public static WatiN_IE.ToCSharp injectJavascriptFunctions(this WatiN_IE ie, bool resetHooks)
{
if (ie.WebBrowser.isNull())
"in InjectJavascriptFunctions, ie.WebBrowser was null".error();
else
{
if (ie.WebBrowser.ObjectForScripting.isNull() || resetHooks)
{
ie.WebBrowser.ObjectForScripting = new WatiN_IE.ToCSharp();
"Injecting Javascript Hooks * Functions for page: {0}".debug(ie.url());
ie.eval("var o2Log = function(message) { window.external.write(message) };");
ie.invokeScript("o2Log","Test from Javascript (via toCSharp(message) )");
ie.eval("$o2 = window.external");
"Injection complete (use o2Log(...) or $o2.write(...) to talk back to O2".info();
return (ie.WebBrowser.ObjectForScripting as WatiN_IE.ToCSharp);
}
else
{
if((ie.WebBrowser.ObjectForScripting is WatiN_IE.ToCSharp))
return (ie.WebBrowser.ObjectForScripting as WatiN_IE.ToCSharp);
else
"in WatiN_IE injectJavascriptFunctions, unexpected type in ie.WebBrowser.ObjectForScripting: {0}".error(ie.WebBrowser.ObjectForScripting.typeName());
}
}
return null;
}
public static object downloadAndExecJavascriptFile(this WatiN_IE ie, string url)
{
"[WatiN_IE] downloadAndExecJavascriptFile: {0}".info(url);
var javascriptCode = url.uri().getHtml();
if (javascriptCode.valid())
ie.eval(javascriptCode);
return ie;
}
public static WatiN_IE injectJavascriptFunctions_onNavigate(this WatiN_IE ie)
{
ie.onNavigate((url)=> ie.injectJavascriptFunctions());
return ie;
}
public static WatiN_IE setOnAjaxLog(this WatiN_IE ie, Action<string, string,string,string> onAjaxLog)
{
(ie.WebBrowser.ObjectForScripting as WatiN_IE.ToCSharp).OnAjaxLog = onAjaxLog;
return ie;
}
public static WatiN_IE eval_ASync(this WatiN_IE ie, string script)
{
O2Thread.mtaThread(()=> ie.eval(script));
return ie;
}
public static WatiN_IE eval(this WatiN_IE ie, string script)
{
return ie.eval(script, true);
}
public static WatiN_IE eval(this WatiN_IE ie, string script, bool waitForExecutionComplete)
{
var executionThread = O2Thread.staThread(()=> ie.IE.RunScript(script));
if (waitForExecutionComplete)
executionThread.Join();
return ie;
}
public static WatiN_IE alert(this WatiN_IE ie, string alertScript)
{
return ie.eval("alert({0});".format(alertScript));
}
public static object getJsObject(this WatiN_IE ie)
{
var toCSharpProxy = ie.injectJavascriptFunctions();
if (toCSharpProxy.notNull())
return toCSharpProxy.getJsObject();
return null;
}
public static T getJsObject<T>(this WatiN_IE ie, string jsCommand)
{
var jsObject = ie.getJsObject(jsCommand);
if (jsObject is T)
return (T)jsObject;
return default(T);
}
public static bool doesJsObjectExists(this WatiN_IE ie, string jsCommand)
{
var toCSharpProxy = ie.injectJavascriptFunctions();
if (toCSharpProxy.notNull())
{
var command = "window.external.setJsObject(typeof({0}))".format(jsCommand);
ie.invokeEval(command);
ie.remapInternalJsObject();
return toCSharpProxy.getJsObject().str()!="undefined";
}
return false;
}
public static object getJsVariable(this WatiN_IE ie, string jsCommand)
{
return ie.getJsObject(jsCommand);
}
public static object getJsObject(this WatiN_IE ie, string jsCommand)
{
var toCSharpProxy = ie.injectJavascriptFunctions();
if (toCSharpProxy.notNull())
{
var command = "window.external.setJsObject({0})".format(jsCommand);
ie.invokeEval(command);
ie.remapInternalJsObject();
return toCSharpProxy.getJsObject();
}
return null;
}
public static WatiN_IE remapInternalJsObject(this WatiN_IE ie)
{
//"setting JS _jsObject variable to getJsObject()".info();
ie.invokeEval("_jsObject = window.external.getJsObject()"); // creates JS variable to be used from JS
return ie;
}
public static WatiN_IE setJsObject(this WatiN_IE ie, object jsObject)
{
var toCSharpProxy = ie.injectJavascriptFunctions();
if (toCSharpProxy.notNull())
{
toCSharpProxy.setJsObject(jsObject);
ie.remapInternalJsObject();
}
return ie;
}
public static object waitForJsObject(this WatiN_IE watinIe)
{
return watinIe.waitForJsObject(500, 20);
}
public static object waitForJsObject(this WatiN_IE watinIe, int sleepMiliseconds, int maxSleepTimes)
{
"[WatiN_IE][waitForJsObject] trying to find jsObject for {0} x {1} ms".info(maxSleepTimes, sleepMiliseconds);
watinIe.setJsObject(null);
for(var i = 0; i < maxSleepTimes ; i++)
{
var jsObject = watinIe.getJsObject();
if(jsObject.notNull())
{
"[watinIe][waitForJsObject] got value: {0} (n tries)".info(jsObject, i);
return jsObject;
}
watinIe.sleep(500, false);
}
"[WatiN_IE][waitForJsObject] didn't find jsObject after {0} sleeps of {1} ms".error(maxSleepTimes, sleepMiliseconds);
return null;
}
public static object waitForJsVariable(this WatiN_IE watinIe, string jsCommand)
{
return watinIe.waitForJsVariable(jsCommand, 500, WatiN_IE_ExtensionMethods.WAITFORJSVARIABLE_MAXSLEEPTIMES);
}
public static object waitForJsVariable(this WatiN_IE watinIe, string jsCommand, int sleepMiliseconds, int maxSleepTimes)
{
"[WatiN_IE][waitForJsVariable] trying to find jsObject called '{0}' for {1} x {2} ms".info(jsCommand, maxSleepTimes, sleepMiliseconds);
watinIe.setJsObject(null);
for(var i = 0; i < maxSleepTimes ; i++)
{
if (watinIe.doesJsObjectExists(jsCommand))
{
var jsObject = watinIe.getJsObject(jsCommand);
"[watinIe][waitForJsVariable] got value: {0} ({1} tries)".info(jsObject, i);
return jsObject;
}
watinIe.sleep(500, false);
}
"[WatiN_IE][waitForJsVariable] didn't find jsObject called '{0}' after {1} sleeps of {2} ms".error(jsCommand, maxSleepTimes, sleepMiliseconds);
return null;
}
public static WatiN_IE deleteJsVariable(this WatiN_IE watinIe, string jsVariable)
{
var evalString = "try { delete " + jsVariable + " } catch(exception) { }";
watinIe.eval(evalString);
return watinIe;
}
}
}
See https://github.com/o2platform/FluentSharp_Fork.WatiN/tree/master/FluentSharp.WatiN/ExtensionMethods for many more WatiN/WebBroser Extension Methods

Related

why is the WebView.evaluateJavascript method called twice?

public static String dataFromJs;
public void androidMethod() {
// initialize static String dataFromJs.
dataFromJs = "";
webView.evaluateJavascript("javascript:jsFuction();", new ValueCallback<String>() {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onReceiveValue(String s) {
JsonReader reader = new JsonReader(new StringReader(s));
reader.setLenient(true);
try {
if (reader.peek() != JsonToken.NULL) {
if (reader.peek() == JsonToken.STRING) {
// get string value from javascript and I want to use the value
dataFromJs = reader.nextString();
}
}
} catch (IOException e) {
Log.e("TAG", "MainActivity: IOException", e);
} finally {
try {
reader.close();
} catch (IOException e) {
// NOOP
}
}
}
});
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if(url.endsWith("menu/page.do")) {
androidMethod();
// do something with dataFromJs..
}
}
The androidMethod is my method in android.
I try to use the str what I receieved from javascript.
but webView.evaluateJavascript method always return null at the first time,
the webView.evaluateJavascript is called again and return string value correctly.
Since the return value is null at the first time, so I can't use the androidMethod in another method.
Anyone has good solution??
is it have something to do with this log (The application may be doing too much work on its main thread.) ?
Thank you!

how to run a c# method from js inside of the webview app in xamarin

I have a problem with running a c# method from js that is inside of a webview in xamarin.
I have a c# method like this:
public void simpleMethod(int a,string b,bool c){
string[] data;
if(c){
data[a] = b;
}
}
Now how do I call this method from the javasript?
You can create a Custom Renderer of WebView
Create a custom WebView in Forms
public class HybridWebView : View
{
Action<int, string, bool> action;
public static readonly BindableProperty UriProperty = BindableProperty.Create (
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));
public string Uri {
get { return (string)GetValue (UriProperty); }
set { SetValue (UriProperty, value); }
}
public void RegisterAction (Action<int, string, bool> callback)
{
action = callback;
}
public void Cleanup ()
{
action = null;
}
public void InvokeAction (int a,string b,bool c)
{
if (action == null ) {
return;
}
action.Invoke (a,b,c);
}
}
in ContentPage
The HybridWebView instance will be used to display a native web control on each platform. It's Uri property is set to an HTML address , and which will be displayed by the native web control.
The HybridWebViewPage registers the action to be invoked from JavaScript, as shown in the following code example:
public partial class xxxPage : ContentPage
{
public xxxPage ()
{
//...
hybridWebView.RegisterAction ((a,b,c) => simpleMethod(a,b,c));
}
public void simpleMethod(int a,string b,bool c)
{
string[] data;
if(c){
data[a] = b;
}
}
}
<ContentPage.Content>
<local:HybridWebView x:Name="hybridWebView" Uri="https://learn.microsoft.com"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</ContentPage.Content>
in your html file
For example you want to call the method when click a button
<button type="button" onclick="javascript:invokeCSCode(a,b,c);">Invoke C# Code</button>
//...
<script type="text/javascript">
function invokeCSCode(a,b,c) {
try {
invokeCSharpAction(a,b,c);
}
catch (err){
log(err);
}
}
Creating the Custom Renderer on iOS
[assembly: ExportRenderer (typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.iOS
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, WKWebView>, IWKScriptMessageHandler
{
const string JavaScriptFunction = "function invokeCSharpAction(a,b,c){window.webkit.messageHandlers.invokeAction.postMessage(a,b,c);}";
WKUserContentController userController;
protected override void OnElementChanged (ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged (e);
if (e.OldElement != null) {
userController.RemoveAllUserScripts ();
userController.RemoveScriptMessageHandler ("invokeAction");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup ();
}
if (e.NewElement != null) {
if (Control == null) {
userController = new WKUserContentController ();
var script = new WKUserScript (new NSString (JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript (script);
userController.AddScriptMessageHandler (this, "invokeAction");
var config = new WKWebViewConfiguration { UserContentController = userController };
var webView = new WKWebView (Frame, config);
SetNativeControl (webView);
}
Control.LoadRequest (new NSUrlRequest (new NSUrl (Element.Uri, false)));
}
}
public void DidReceiveScriptMessage (WKUserContentController userContentController, WKScriptMessage message)
{
Element.InvokeAction (message.Body.ToString ());
}
}
}
In addition, Info.plist must be updated to include the following values:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Creating the Custom Renderer on Android
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace CustomRenderer.Droid
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
const string JavascriptFunction = "function invokeCSharpAction(a,b,c){jsBridge.invokeAction(a,b,c);}";
Context _context;
public HybridWebViewRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
var hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
if (Control == null)
{
var webView = new Android.Webkit.WebView(_context);
webView.Settings.JavaScriptEnabled = true;
webView.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
SetNativeControl(webView);
}
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
Control.LoadUrl(Element.Uri);
}
}
}
}
public class JavascriptWebViewClient : WebViewClient
{
string _javascript;
public JavascriptWebViewClient(string javascript)
{
_javascript = javascript;
}
public override void OnPageFinished(WebView view, string url)
{
base.OnPageFinished(view, url);
view.EvaluateJavascript(_javascript, null);
}
}
public class JSBridge : Java.Lang.Object
{
readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;
public JSBridge (HybridWebViewRenderer hybridRenderer)
{
hybridWebViewRenderer = new WeakReference <HybridWebViewRenderer> (hybridRenderer);
}
[JavascriptInterface]
[Export ("invokeAction")]
public void InvokeAction (int a,string b,bool c)
{
HybridWebViewRenderer hybridRenderer;
if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget (out hybridRenderer))
{
hybridRenderer.Element.InvokeAction (a,b,c);
}
}
}
You don't.
Basically you have to detect / trigger a piece of javascript code, detect it with your C# webview configuration/initialization code, and then execute your C#.
Take a look at https://developer.android.com/reference/android/webkit/JavascriptInterface for android to understand what I'm saying, and implement it on Android.
For iOS you have a WKWebview listener that you can use to receive informations from your webpage.

Access Java Enum fields in javascript

I'm trying to access the facility String of this enum in java script
public enum FacilityEnum {
CAR_VALET("carValet"),
INDOOR("indoorPark"),
DISABLED_ACCESS("disabledAccess"),
EV_CHARGE("evCharge"),
private String facility;
private FacilityEnum(String facility) {
this.facility = facility;
}
public String getFacility() {
return facility;
}
public void setFacility(String facility) {
this.facility = facility;
}
}
This enum is used in a Facility.class
#Entity
public class Facility {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long facilityId;
#Enumerated(EnumType.STRING)
private FacilityEnum service;
#ManyToMany(mappedBy = "facilities")
#JsonBackReference("parks-facilities-services")
private Set<Park> parks;
}
public FacilityEnum getService() {
return service;
}
public void setService(FacilityEnum service) {
this.service = service;
}
which has a ManyToMany relation with Park.class.
The problem comes when i need to use the facility String in javascript
This the javascript interested part, i'm using Spring + Thymleaf
var parcheggi = JSON.parse([[${parks}]]); //my list of Parks
parcheggi.forEach(function (arrayItem) { //it's ok
var parcheggio = arrayItem;
var services = parcheggio.facilities; //it's ok, i get Facility objects
var servicesDiv = '<div>';
services.forEach(function (service){
var s = service; //the single Facility
servicesDiv += '<img src="/images/park_icons/facilities/' + s.service + '.png" />'
});
servicesDiv += '</div>';
//rest of the code...
In this case s.service is the rough Enum (CAR_VALET, INDOOR...) if i try s.service.facility I get undefined.. I need to have carValet, indoor, disabledAccess and so on...
One way to do what you want is to configure object mapper to serialize enums using toString method. You would add the following to the object mapper configuration:
objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
(Note that previous Jackson versions have equivalent to this property but it's different).
Then just add toString to your enum:
#Override
public String toString ()
{
return facility;
}
You are getting undefined because your Enum can't be deserialized in JSON, you have two options here:
Either change the Implementation of your Enum, so it contains only the Stringconstants and it will be correctly mapped by Jackson.
Your code would be:
public enum FacilityEnum {
CAR_VALET,
INDOOR,
DISABLED_ACCESS,
EV_CHARGE;
}
Or you should override the toString() method in your Enum so it can
be deserialized and returned as a String.
Your code would be:
public enum FacilityEnum {
CAR_VALET("carValet"),
INDOOR("indoorPark"),
DISABLED_ACCESS("disabledAccess"),
EV_CHARGE("evCharge"),
private String facility;
private FacilityEnum(String facility) {
this.facility = facility;
}
public String getFacility() {
return facility;
}
public void setFacility(String facility) {
this.facility = facility;
}
#Override
public String toString() {
return facility;
}
}

Android & Javascript - From two functions to one

MainActivity.java
public String URI = null;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == RESULT_OK)
{
Uri pickedImage = data.getData();
URI = pickedImage.toString();
}
}
public String GetURI()
{
return URI;
}
WebAppInterface.java
#JavascriptInterface
public void GetPicture()
{
Intent galleryIntent = new Intent(Intent.ACTION_PICK);
galleryIntent.setType("image/*");
((MainActivity) mContext).startActivityForResult(galleryIntent, 0);
}
#JavascriptInterface
public String GetURI()
{
return getRealPathFromURI(mContext, Uri.parse(((MainActivity) mContext).GetURI()));
}
I'm using the following Javascript functions
function GetPicture()
{
Android.GetPicture();
}
function loadImage()
{
document.getElementById("img").src = Android.GetURI();
}
The first one is used to get the picture and store the full path in a string. The second function is used to obtain the the full path from the string.
Currently this is working because I'm first calling GetPicture and then loadImage.
But I want to "merge" the functions.
So the Javascript would be:
function loadImage()
{
document.getElementById("img").src = Android.GetPicture();
}
So I changed the code from WebAppInterface.java to this:
#JavascriptInterface
public String GetPicture()
{
Intent galleryIntent = new Intent(Intent.ACTION_PICK);
galleryIntent.setType("image/*");
((MainActivity) mContext).startActivityForResult(galleryIntent, 0);
return ((MainActivity) mContext).GetURI();
}
But it's not working. I think I know why because GetURI is being called before the string URI has been set.
So how do I fix this problem?
If somebody knows a better title please let me know.
OK I think I found a solution but I don't know if this is the best way to do it.
So for those who want to know how I fixed it:
I changed the GetPicture method
#JavascriptInterface
public String GetPicture()
{
Intent galleryIntent = new Intent(Intent.ACTION_PICK);
galleryIntent.setType("image/*");
((MainActivity) mContext).startActivityForResult(galleryIntent, 0);
while(((MainActivity) mContext).IsFinished == false){}
return ((MainActivity) mContext).GetURI();
}
In MainActivity.java I added a public boolean called IsFinished (set to false) and it is going to be true when the user picked an image (onActivityResult).
So the code will be:
public String URI = null;
public boolean IsFinished = false;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == RESULT_OK)
{
Uri pickedImage = data.getData();
URI = pickedImage.toString();
IsFinished = true;
}
}
public String GetURI()
{
return URI;
}

android-javascript: using prototype to object injected in webview by add javascriptinterface

Im using addJavaScriptInterface to inject my object "myObj" into webview.
Here part of code
private void portalInit() {
CookieSyncManager.createInstance(this);
CookieSyncManager.getInstance().startSync();
wv.getSettings().setJavaScriptEnabled(true);
wv.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
wv.getSettings().setAllowContentAccess(true);
wv.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.d("From JavaScript",
cm.message() + " -- From line " + cm.lineNumber()
+ " of " + cm.sourceId());
return true;
}
});
wv.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
wv.addJavascriptInterface(new myObj(this, wv), "myOBJ");
wv.loadUrl("http://dl.dropbox.com/u/16515769/gradient.html");
wv.requestFocus(View.FOCUS_DOWN);
}
And i have HTML page that i can't change, where onload doing some crazy stuff
<script>
function f1(){
this.do1 = function(par){
console.log("1: "+par);
};
this.do2 = function(num){
console.log("2: "+num);
};
}
function f2(){
this.do3 = function(par){
console.log("3: "+par);
};
this.do4 = function(num){
console.log("4: "+num);
};
}
var myobj;
var myobj_e = myOBJ;
f1.prototype = myobj_e;
f2.prototype = new f1();
myobj = new f2();
function keydown(e){
var key = e.keyCode || e.which;
switch(key){
case 13:
myobj.Debug("turn it on!!!!");
break;
case 27:
myobj.do1("turn it on!!!!");
break;
case 49:
myobj.do4("fsdfd")
break;
}
}
this constuction work fine in our hardware device where object injected to real webkit browser, but not work in android webview, and accesing to myobj.Debug post error in logcat (Javascript error)
Uncaught ReferenceError: NPMethod called on non-NPObject -- From line 36 of http://dl.dropbox.com/u/16515769/gradient.html
Note: if i call in javascript myOBJ.Debug("something"); it work fine, so i think that part "f1.prototype = myobj_e;" not working.
I will be very glad to get some help.
So i find a workaround. Its not a solution, but i cant do it in other way.
We can not change object that was added to webview by addJavascriptInterface in webpage side.
So I need to make my own object, which will retranslate calls to interface. I injected javascript onPageStarted and changeed object name to myOBJ_tmp
wv.setWebViewClient(new WebViewClient() {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onPageStarted (WebView view, String url, Bitmap favicon){
String script= "javascript:var func_list = ['Debug'];";
script+="var myOBJ = {};"
script+="func_list.map(function(id){"
script+="myOBJ[id]= function() {"
script+="try{return myOBJ_tmp[id].apply(myOBJ_tmp, arguments);}"
script+="catch(e) { console.log('ERROR: ' + e + ', method ' + id);"
script+="return false;}}})"
view.loadUrl(script);
}
});
Hope this will help somebody.

Categories

Resources