After creating a ‘register’ button in the webview, I want to navigate directly to a specific component when I click ‘func register’ in Kotlin.
Kotlin logic is structured like this.
// Android
inner class JavaScriptInterface
{
#JavascriptInterface
#SuppressWarnings("unused")
fun register(data: String){
navigate(
ridday202208Ev.actionHaydxn2208EventToEventJoinForm()
)
}
}
This is javascript code.
function register() {
}
return (
<button onClick={() => register()}></button>
)
When you click the register function in Javascript code, the webview recognizes the register function and wants to call navigate. I don't know how to deal with it.
If you want JS to be able to execute kotlin code, you need to call addJavascriptInterface(JavaScriptInterface(), "Native") That will create an object in JS called native with all the functions your annotated on that class. Calling one of them will call directly to Kotlin or Java. Remember that you'd call Native.register(), not just register() (the object name is the second parameter to the call above, change it to whatever you want).
Remember that any function you call like this can only take null, String, or Number (int, double, etc) as parameters. You can't pass objects. You can't pass arrays (you kind of can, but you need to pass a Java array, at which point its easier to write in Java). You can't pass functions. You can work around those limitations (except functions) by passing JSON strings and serializing/deserializing them as needed.
Related
I am trying to add a toCamelCase function to the String prototype in React with TypeScript.
Here is what I did, in a toCamelCase.d.ts file:
interface String {
toCamelCase(): string;
}
String.prototype.toCamelCase = function (): string {
return this[0].toUpperCase() + this.slice(1).toLowerCase();
};
Now I am just wondering when and in which file should I load this script so I can get access to it.
I am aware that I can simply define a function and use that.
However, I am curious how to do it with prototype and what would be the downside doing things like this if there are any.
Where to do it?
In main.js or index.js or any other file that bootstraps your application
What are the downsides?
You can never know if one of the libraries that you use using relies on String.prototype being unaltered. It can cause major issues that you will have a hard time finding.
I have loaded a webpage using WebView component and added a JavascriptInterface. Please check the code below,
val webview = WebView(this)
setContentView(webview)
webview.settings.javaScriptEnabled = true
webview.loadUrl(HOME_PAGE_URL)
webview.addJavascriptInterface(JavascriptInterface(),”javascript_bridge”)
And when I call the invoke from Javascript using window.javascript_bridge.showToast(“Information Saved”);
private inner class JavascriptInterface
{
#android.webkit.JavascriptInterface
fun showToast(text: String?)
{
Log.d("WEBVIEW", text);
}
}
I am able to call the method from Javascript to Kotlin without any trouble.
But now I want to pass an Object from Javascript to Kotlin like below,
var info = {
message: “Information Saved”,
ID: 123456
}
And when I call the invoke from Javascript using window.javascript_bridge.showToast(info);
I tried to change to the data type to Any, but the value passed from Javascript is null
private inner class JavascriptInterface
{
#android.webkit.JavascriptInterface
fun showToast(text: Any?)
{
Log.d("WEBVIEW", text.toString());
}
}
As far as i know, the javaScript interface methods only accepts primitive types of data as parameters (as discussed on this question).
If you still want to achieve that, you may serialize the object (to JSON format, for instance) in the javaScript and then Deserialize it in Java.
Hope it helps :)
I am coding in Unity using C# and developing for WebGL. I need to use browser JavaScript so have written a .jslib from which I call methods in C# using Marshalling.
Is it possible for me to set a JavaScript callback to a C# Action, Func, or Event Handler like so:
// Javascript in .jslib called from C# using static extern
// action being the C# method that I want to call
// On callback I get -> TypeError: action is not a function
SetOnOpen: function (action) {
$jsobj.onopen = function () {
action();
};
},
I've tried each of these, but don't appear to be doing it properly. I know that C++ can call C# functions, but JavaScript must communicate differently somehow.
Attempts:
[DllImport("__Internal")]
private static extern void SetOnOpen(ref OnOpenHandler handler);
[DllImport("__Internal")]
private static extern void SetOnOpen(ref Action action);
[DllImport("__Internal")]
private static extern void SetOnOpen(IntPtr handler);
No matter what I try, I get a TypeError stating that the object that I'm passing over to the JavaScript isn't a function. I've tried:
Using Action and Event Delegates
Using ref, IntPtr, and neither
Anyone know if this is even possible? Like I said, I successfully called a C# method in a C++ .dll before, so figured it would be possible to do so from a .jslib.
From my experience, the only way to make the two communicate is by SendMessage. If you need to carry over multiple parameters, you can attach an array.
So I have this decorate function that takes an object and a method-name and wraps it with external logic.
function decorate(object, methodName) {
var originalMethod = object[methodName];
object[methodName] = function () {
// pre-logic
var retVal = originalMethod.apply(this, arguments);
// post-logic
return retVal;
};
}
Now I want to wrap ALL of the functions in my application, i.e.
All the recursive public functions of the object
All private scope functions
All anonymous functions
Anything else I might have forgotten.
My purpose in doing this is to implement a "JS Profiler" that will run alongside my application during automated testing, and output performance data to logs.
I need this for testing purposes, so the solution must have minimal changes to the actual code of my application.
Possible solutions I've considered:
Public methods can be easily traversed and replaced using a recursive object traversal function.
Some hack using eval() to be able to access private methods.
Ideally, to handle all cases, I could use a proxy HTTP server (Node.js for example) that will transform each javascript file before sending it to the browser. This way my codebase will remain clean, but my tests will have the necessary changes.
The first 2 are only partial solutions, and the last one seems like an overkill and also a potential "bug factory"...
Does anyone have any other ideas on how to achieve what I need?
Awesomium easily allows for C++ code to call Javascript methods, but I haven't found a definite answer as to if it can do the opposite. This site seems to say that you can, but looking through the text and examples doesn't enlighten me.
So, I'm looking for a definite answer: can I call C++ variables/methods in my Javascript(Jquery), or not?
If you could include a simple example, that would be extremely appreciated as well.
Thank you!
You definitely can-- you'll just need to build an extra layer on top of WebView::setObjectCallback and WebViewListener::onCallback using delegates/function-pointers.
I wrote a quick JSDelegate.h class (view it here) that you can use to hookup "onCallback" events directly to C++ member functions.
The basic idea is to maintain a mapping of callback names to delegates:
typedef std::map<std::wstring, Awesomium::JSDelegate> DelegateMap;
DelegateMap _delegateMap;
And call the corresponding function from your WebViewListener::onCallback:
void MyListener::onCallback(Awesomium::WebView* caller, const std::wstring& objectName,
const std::wstring& callbackName, const Awesomium::JSArguments& args)
{
DelegateMap::iterator i = _delegateMap.find(callbackName);
if(i != _delegateMap.end())
i->second(caller, args);
}
And then, each time you wish to bind a specific C++ function, you would do it like so:
// Member function we wish to bind, must have this signature for JSDelegate
void MyClass::myFunction(Awesomium::WebView* caller, const Awesomium::JSArguments& args)
{
// handle args here
}
// Instantiate MyClass instance in C++
MyClass* myClass = new MyClass();
// Create corresponding 'MyClass' object in Javascript
webView->createObject(L"MyClass");
// Do the following for each member function:
// Bind MyClass::myFunction delegate to MyClass.myFunction in JS
_delegateMap[L"myFunction"] = Awesomium::JSDelegate(myClass, &MyClass::myFunction);
webView->setObjectCallback(L"MyClass", L"myFunction");
Then, you should be able to call MyClass::myFunction directly from Javascript like so:
MyClass.myFunction("foo", 1, 2 3)
Hope this helps! I haven't tested any of the code but I wrote it with Awesomium v1.6 RC4 SDK in mind.