Trying to implement JS library with my C# code.
Is very simple but I am getting this error:
EntryPointNotFoundException: Test
TalkDB.Start () (at Assets/Scripts/TalkDB.cs:30)
C# code is in scripts folder and JS library at plugins/webgl with .jslib extension.
Also read this article, but no idea what I am missing: https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html?_ga=1.27144893.1658401563.1487328483
C# Code:
public class TalkDB : MonoBehaviour
{
[DllImport("__Internal")]
private static extern void Test();
void Start()
{
Test();
}
}
JS Library:
var HighscorePlugin = {
Test: function()
{
window.alert("Testing 1, 2, 3,...");
}
};
mergeInto(LibraryManager.library, HighscorePlugin);
Found the answer, is quite simple in fact.
I does not work when running locally, just when running from a server.
To prevent this error this should be done:
#if UNITY_WEBGL && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void Test();
#else
// something else to emulate what you want to do
#endif
And do this also when calling the function.
Happy programming :)
EntryPointNotFoundExceptionmeans means that the function "Test" is either (A) not marked as exportable (not visible) or (B) signature does not match C# definition.
Most likely your issue is the former (A).
I would recommend running DUMPBIN.EXE against your library to verify your "test" function is getting exported and that the its respective signature matches your C# definition. Could be some code-injection on JS-side.
Related
I've got some native JS test code here (mydialog.js)
var MyDialog = {
foo : function()
{
console.log("foo");
}
};
I'm injecting using the following code using GWT:
ScriptInjector.fromUrl("mydialog.js").setCallback(new Callback<Void, Exception>()
{
#Override
public void onFailure(Exception reason)
{
Window.alert("Dialog Injection Failed!" + reason);
}
#Override
public void onSuccess(Void result) {}
}).inject();
}
Then, I'm trying to set up a JSInterop class here:
#JsType(isNative=true, namespace=JsPackage.GLOBAL, name="MyDialog")
public class MyDialog
{
public static native void foo();
}
The problem, is that the namesoace JsPackage.GLOBAL isn't accurate. The injected code doesn't live under the global namespace, but rather the one generated by GWT and presumably inside the GWT iframe I believe. What is the namespace I need?
In other words, what should this be:
...namespace=???...
JsInterop assumes that the code it is reasoning about lives in the main window - this isn't the difference of a namespace, but a different global context that it runs under (with different Object, Array types, etc). In Java terms you might consider this not just "wrong package", but "wrong classloader", though in a way that you can't correct very nicely.
Instead, direct the ScriptInjector to put your created JS into the main page, and you can interact with it directly with setWindow:
ScriptInjector.fromUrl(...)
.setWindow(ScriptInjector.TOP_WINDOW)
.setCallback(...);
Alternatively, you can use the "magic" string of "<window>", which will mean "don't provide any namespace at all". This isn't an official part of JsInterop (the constant isn't declared in the jsinterop annotations themselves), but at least presently is a way you can work around this.
I am currently working on a GWT project and it now needs to used by an external JavaScript file. I am creating a test prototype right now to ensure both sides are working properly.
When I run and compile, I see the console logs in the browser from the events being called. However, the GWT java methods are not being called.
After trying many scenarios, I also noticed that if I remove the $entry wrapper from the exportStaticMethods(), the opposite occurs. I see the System.outs being called in my java code, however the console logs from the JavaScript in the browser are not being called.
I am trying to figure what is causing the behavior and if there is a small missing piece I overlooked.
I have already reviewed the GWT JSNI documentation for calling a Java method from js and tried to find a solution from other related questions on StackOverflow.
GWT and Java side
I have gone into the onModuleLoad() method of my EntryPoint class and added a static method called exportStaticMethods(). I also created the PokePingClass.java file listed below.
EntryPointClass.java
public class EntryPointClass implements EntryPoint {
#Override public void onModuleLoad() {
exportStaticMethods();
// load application here.
}
public static native void exportStaticMethods() /*-{
$wnd.pingApp = $entry((function) {
#com.application.PokePingClass::pingApp()();
});
$wnd.pokeApp = $entry((function) {
#com.application.PokePingClass::pokeApp()();
});
}-*/
}
PokePingClass.java
public class PokePingClass {
public static void pokeApp() {
System.out.println("pokeApp() called");
}
public static void pingApp() {
System.out.println("pingApp() called");
}
}
HTML and js
In the .html file of the project, I added a hidden div element of id 'pokePing', as well as the pokeping.js file.
<html>
<head>
.
. <!-- other stuff -->
.
<script type='text/javascript' src='pokeping.js</script>
</head>
<body>
.
. <!-- other stuff -->
.
<div id="pokePing" style="visibility: hidden;"></div>
</body>
</html>
pokeping.js
$(document).ready(function) {
var $pp = $('#pokePing');
var pokeApp = function() {
console.log("app handling poke event");
window.parent.pokeApp();
}
var pingApp = function() {
console.log("app handling ping event");
window.parent.pingApp();
}
$pp.trigger('pokeApp');
$pp.trigger('pingApp');
}
public static native void exportStaticMethods() /*-{
$wnd.pingApp = $entry(function) {
#com.application.PokePingClass.pingApp()();
}
$wnd.pokeApp = $entry(function) {
#com.application.PokePingClass.pokeApp()();
}
}-*/
This isn't valid JS, and doesn't make sense as JSNI. Try this instead:
$wnd.pingApp = $entry(function() {
#com.application.PokePingClass::pingApp()();
});
$wnd.pokeApp = $entry(function() {
#com.application.PokePingClass::pokeApp()();
});
Edit because I still had it wrong, forgot the :: operator for members.
I found a similar post but the key was to actually return the method calls in the JSNI functions. After that, all works well.
public static native void exportStaticMethods() /*-{
$wnd.pingApp = $entry((function) {
return #com.application.PokePingClass::pingApp()();
});
$wnd.pokeApp = $entry((function) {
return #com.application.PokePingClass::pokeApp()();
});
}-*/
I'm new to Windows Runtime Component, and have been trying to figure out how to achieve the following.
The C++ interface I want to extend from in Javascript.
namespace MySDK {
public interface class LoggerPlugin
{
public:
virtual void Log (Platform::String^ Tag, Platform::String^ Messsage);
};
}
The C++
namespace MySDK {
public ref class Logger sealed : public Platform::Object
{
public:
static Logger^ GetInstance ();
void SetPlugin (LoggerPlugin^ Plugin);
};
}
What I tried, may seem silly, but I have no idea how to achieve it.
var plugin = {
log: function(tag, message) {
console.log(tag + ':' + message);
}
};
MySdk.Logger.getInstance().setPlugin(plugin);
The error that I get is
JavaScript runtime error: Type mismatch
I couldn't find any documentation or examples on how to achieve this, will appreciate if anyone could provide me an example of how this can be done.
JavaScript cannot implement WinRT interfaces. If you want to have a JavaScript implementation of your plugin, then you will need to build a concrete type that raises events (that JavaScript can subscribe to) rather than defining virtual methods (that C++ or C# could implement).
I'm using Java to run simple scripts written in JavaScript using the default Rhino bundled by the JRE. I would like to be able to use the same script within the application and from the command-line version, so I cannot use java.lang.System.exit(3) (it would exit the host application prematurely.) I cannot use the security manager to block it, as people complain about performance issues when a security manager is in effect.
Is there perhaps some function in JavaScript for exiting a script?
No, there isn't. But you can create an exception called, say, ExitError:
public class ExitError extends Error {
private final int code;
public ExitError(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
Now, in your application's script runner, you can do this:
public int runScript() {
try {
// Invoke script via Rhino
} catch (ExitError exc) {
return exc.getCode();
}
}
And in the command-line version:
public static void main(String[] args) {
try {
// Invoke script via Rhino
} catch (ExitError exc) {
System.exit(exc.getCode());
}
}
Also, in your JS code, write a wrapper function:
function exit(code) {
throw new ExitError(code);
}
Here is an idea:
Wrap your script in a function and call it. Returning from this function will exit your script.
//call main
main();
//The whole work is done in main
function main(){
if(needToExit){
//log error and return. It will essentially exit the script
return;
}
//your script goes here
}
In my first GWT module I want to store a JavaScript object, later on I want to receive this object in my second GWT module.
Everything works fine for primitive types, but my complex type will always have all fields set to "undefined".
My class, that I want to transfer from one module to the other:
public class SomeThing {
public Set<String> strings = new HashSet<String>();
}
The entry point of my first module looks like this:
public class EntryA implements EntryPoint {
#Override
public void onModuleLoad() {
// define test data
SomeThing someThing = new SomeThing();
someThing.strings.add("hallo123");
// save data to JavaScript
saveToJavaScript(someThing);
// read and show saved data
Window.alert("ModuleA:"+readFromJavaScript());
Window.alert("ModuleA strings:"+readFromJavaScript().strings);
}
private native void saveToJavaScript(SomeThing thing) /*-{
$wnd.storedThing = thing;
}-*/;
private native SomeThing readFromJavaScript() /*-{
return $wnd.storedThing;
}-*/;
}
The entry point of my second module looks like this:
public class EntryB implements EntryPoint {
#Override
public void onModuleLoad() {
// run delayed, so that ModuleA will be executed first
new Timer() {
#Override
public void run() {
// read and show saved data
Window.alert("ModuleB:"+readFromJavaScript());
Window.alert("ModuleB strings:"+readFromJavaScript().strings);
}
}.schedule(5000);
}
private native SomeThing readFromJavaScript() /*-{
return $wnd.storedThing;
}-*/;
}
I am compiling each module separately. Both generated JavaScript files are included in one html file.
The output is:
ModuleA:moduleA.client.SomeThing#a
ModuleA strings:[hallo123]
ModuleB:moduleA.client.SomeThing#a
ModuleB strings:undefined
Does anyone have an idea how to store such complex types? Let me know, if you need some more information.
UPDATE
I found out, that it actually works, if I am "refreshing" the fields in JavaScript. I have no idea why this works!
private native SomeThing readFromJavaScript() /*-{
var a = $wnd.storedThing;
a.#moduleA.client.SomeThing::strings = a['moduleA_client_SomeThing_strings'];
return $wnd.storedThing;
}-*/;
Nevertheless I need a generic approach, which allows to transfer any object - and I don't want to have to mention every possible field... :(
Maybe this has something to do the way modules are loaded.
The preferred way to load multiple modules it is described in: Loading multiple modules in an HTML host page:
If you have multiple GWT modules in your application, there are two ways to
approach loading them.
1. Compile each module separately and include each module with a separate
<script> tag in your HTML host page.
2. Create a top level module XML definition that includes all the modules you
want to include. Compile the top level module to create a single set of
JavaScript output.
...[cut for brevity] The second approach is strongly recommended.
The reason that you can't read fields between GWT modules is that each module is compiled and obfuscated independently. This means that SomeThing.strings could be mapped to .a in one module and `.q' in another. Your "refresh" trick only works because compiling the module in detailed mode usually results in the same name.
You might want to consider using the AutoBeans framework, which supports JSON-encoding the objects in a stable manner.