I am building a Cordova application for all major operating systems (iOS, macOS, Android and Windows).
I wrote a native Plugin (WinRT) in C++/CLI to call some native functions, this Plugin uses delegates to asynchronously give back results.
I also wrote a test application in C# that allows me to easily test the C++/CLI code without having to compile the whole Cordova project.
I am able to bind to the C++/CLI delegate without any issue in C#, but I am not able to do so in Javascript.
C# Way (Works like a charm):
myCppClass.log += (string logString) =>
{
Debug.WriteLine(logString);
};
Javascript Way (Does not work at all):
myCppClass.addEventListener("log", function (msg) {
console.log(msg);
});
I got the Javascript way from: https://msdn.microsoft.com/en-us/library/hh779077.aspx
Does anyone know how to bind to C++/CLI delegates in Javascript?
Thanks
Take a look once again on the https://msdn.microsoft.com/en-us/library/hh779077.aspx#Anchor_4 sample.
Have you tried this way?
var instance = new MyCppClass();
instance.addEventListener("log", function (e) {
console.log(e.msg);
});
Related
is there a way to provide a global JavaScript function in an Angular App, which can be called by non-Angular JS code?
Background: Our Angular app is running inside a webview of a Qt application. Now we are investigating possibilities to provide an API, so that the Qt application can call functions of the Angular app.
Any front-end javascript code (including Angular) has access to global objects window and document. You can add any function or property into those 2.
window.myAPI = {
doIt: function () {...},
doItBetter: function () {...}
}
I'm not familiar with QT WebView, so I can not help you to understand if you can get access window or document from the QT code. I would rather expect you can.
As another solution - https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage. Don't know if QT code can react to those messages.
I am trying to use cefSharp for a WPF application. I can find "how to call a Javascript methods from .Net. But is there a way where I can get notified for Javascript functions or events in .Net?
e.g. if there is a Javascript function (with and without param) I can get the notification with or without values in .Net.
In short, YES!
There's bindings available for:
c# -> js use
webBrowser.ExecuteScriptAsync(script);
js -> c# use
webBrowser.RegisterJsObject(A_NAME_FROM_JS,
objectToBind);
Then from js you can call:
window.A_NAME_FROM_JS.MethodOnObj()
and this will invoke the
MethodOnObj()
on the passed
objectToBind
It works like a charm. Let me know if you've an issue and I'll help further!
The RegisterJsObject and ExecuteScriptAsync methods are both deprecated now. I found another solution that CefSharp supports here:
https://github.com/cefsharp/CefSharp/wiki/Frequently-asked-questions#JSEvent
More detailed information is here:
https://github.com/cefsharp/CefSharp/issues/2775#issuecomment-498454221
Essentially, from your javascript code on page, you can call:
CefSharp.PostMessage(someDataYouWantToPassBack)
And in C#, you register the event to your browser:
browser.JavascriptMessageReceived += OnBrowserJavascriptMessageReceived;
private void OnBrowserJavascriptMessageReceived(object sender, JavascriptMessageReceivedEventArgs e) { }
I'm writing a native plugin to raise an event in JavaScript when the keyboard is showing. I do this:
appView.sendJavascript("cordova.fireWindowEvent('show_keyboard')")
In my JavaScript I then do something like:
window.addEventListener('show_keyboard', handler);
However, this has been flagged as a big no no in PhoneGap by a PhoneGap expert on the team. What is wrong with this approach?
Looking for an answer drawing from credible and/or official sources.
Well I too am no PhoneGap expert, but Apache Cordova, the engine that powers PhoneGap has its source on GitHub.
What does the source say?
Well, as an example, let's look at how Cordova sends its volumedownbutton event. I present lines 613–621 of CordovaWebView.java:
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
return true;
}
// If volumeup key
else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
return true;
}
It would seem that Cordova employs a similar approach to sending events to JavaScript.
What's wrong with what you have?
I am not sure what the exact issue was that your coworker raised, but it does seem that sendJavascript is deprecated. So, there's that. But if your appView is a CordovaWebView, the you can just call loadUrl in the same way the that Cordova itself does it (as shown above).
I am no phonegap expert, but why don't you just call the method directly instead of using listeners?
for example
function keyboardShown() {
alert("test"); //or other code
}
and
appView.sendJavascript("keyboardShown();")
This way you remove the overhead which you have through the listener.
If this still doesn't satisfy your phonegap expert, ask him what he would do to improve this code.
Is it wise to use the same codebase for our mobile web app and phonegap app? They are meant to be similar, the phonegap version just lets us do more. Can we detect if it's not running on phonegap and sequester calls to the phonegap api or does it make more sense to separate them.
Sure, you can use most of the same codebase.
Some phonegap APIs are the same in html5 (for instance localStorage) so there's no difference in code there.
If you're using phonegap Build service, it will add the phonegap.js / cordova.js script file to your project root. Just include it in your html all the time. Then you can detect whether your application is running within phonegap:
var isPhonegap = function() {
return (typeof(cordova) !== 'undefined' || typeof(phonegap) !== 'undefined');
}
if (isPhonegap()) {
// phonegap.js/cordova.js exists.. now let's handle the onDeviceReady event
} else {
// in-browser
}
If you need some common startup code, put it in a function and call this function from the onDeviceReady handler and the else block above.
If the phonegap api you're calling doesn't have the exact same name as the html5 one (because it has the Moz* or WebKit* prefix for instance), just wrap both inside a new name. For instance:
var requestFileSystem = (isPhonegap() ? requestFileSystem : window.WebKitRequestFileSystem);
If the phonegap API you're using really has no html5 equivalent, try to duplicate the functionality yourself in javascript if possible, otherwise you'll just lose the functionality in your browser. But make sure it degrades gracefully enough without that feature.
Note: to test the mobile devices features like accelerometer, geolocation, etc.. in your browser checkout the Ripple Chrome extension.
I figured out a way to keep the web codebase intact...
The current problem with using the built in deviceready event, is that when the page is loaded, you have no way of telling the app: "Hey this is NOT running on an mobile device, there's no need to wait for the device to be ready to start".
In the native portion of the code, for example for iOS, in MainViewController.m there's a method viewDidLoad, I am sending a javascript variable that I later check for in the web code, if that variable is around, I will wait to start the code for my page until everything is ready (for example, navigator geolocation)
Under MainViewController.m:
- (void) viewDidLoad
{
[super viewDidLoad];
NSString* jsString = [NSString stringWithFormat:#"isAppNative = true;"];
[self.webView stringByEvaluatingJavaScriptFromString:jsString];
}
index.html the code goes like this:
function onBodyLoad()
{
document.addEventListener("deviceready", onDeviceReady, false);
}
function onDeviceReady(){;
myApp.run();
}
try{
if(isAppNative!=undefined);
}catch(err){
$(document).ready(function(){
myApp.run();
});
}
I would use the same codebase. The whole point of PhoneGap is to convert your mobile sites into apps. It isn't that difficult to detect features and screen realestate as appropriate. The trouble with seperate codebases is usually the cost of double-handling your content and styles. If necessary you could separate those out into a shared resource and bundle them at runtime/access but personally I'd still go with keeping it all together.
This blog covers the detection issue (see the comments too): http://bennolan.com/2011/08/22/phonegap-detection.html. The crux of it though is if (window.PhoneGap){...}
Android lets you add a Javascript Interface, that will let you use "window.interfacename.myfunction()" to call a function in the Java program.
Is there any similar feature that allows a PyGTK with embedded webkit browser to have similar functionality, to call a specific Python function from Javascript?
You can do it in C using the JavaScriptCore library that comes with WebKit. I don't know any examples in PyGTK, but I assume that JavaScriptCore is available through GObject Introspection.
I ended up adding a handler for special urls. I overrode the webkit with:
webview.connect("navigation-policy-decision-requested", self.webkitGo)
where self.webkitGo is the name of the function: def webkitGo(self, view, frame, net_req, nav_act, pol_dec):
In this function, you can receive the url data from net_req.get_uri() and decide what to do with it, and return true to not do the default behavior.