Writing native code in Codename One is pretty simple, however one piece is relatively vague and that is the ability to call back from native code into the Java code. The reason we left this relatively vague is due to the complexity involved in exposing/documenting this across multiple OS's/languages so we chose to document this on a case by case basis.
A common trick for calling back is to just define a static method and then trigger it from native code. This works nicely for Android, J2ME & Blackberry however mapping this to iOS requires some basic understanding of how the iOS VM works. Worse, due to the changes we made in the new VM if you are using such code you will need to adapt it as we migrate to the new VM or your code will stop working.
For the purpose of this explanation lets pretend we have a class called NativeCallback in the src hierarchy under the package com.mycompany that has the method: public static void callback().
So if we want to invoke that method from Objective-C we normally would have just done the following. Added an include as such:
Then when we want to trigger the method just do:
This will not compile with the new VM. The new VM now passes the thread context along method calls to save on API calls (thread context is heavily used in Java for synchronization, gc and more). However, to keep code compatible we added a few macros that allow us to maintain XMLVM/newVM portability and they are defined as blank when running under XMLVM. So to do something like this in the new VM all we need to do is add an include for CodenameOne_GLViewController.h as such:
Then we can invoke the method like this:
But what if we defined the method as such: public static void callback(int arg)
This would map under XMLVM to something like this:
(notice the extra _ before int). You can adapt this for the new VM like this:
Notice that there is no comma between the CN1_THREAD_GET_STATE_PASS_ARG and the value! This is important since under XMLVM CN1_THREAD_GET_STATE_PASS_ARG is defined as nothing, yet under the new VM it will include the necessary comma. Its not an ideal solution but it solves the portability issue as we slowly migrate to the new VM.
Many of you have been passing string values to the Java side, or really NSString* which is iOS equivalent. So assuming a method like this: public static void callback(String arg)
You would need to convert the NSString value you already have to a java.lang.String which the callback expects. We used to do this as such:
However, the from NSString method also needs this special argument so you will need to modify the method as such:
com_mycompany_NativeCallback_callback___int(CN1_THREAD_GET_STATE_PASS_ARG fromNSString(CN1_THREAD_GET_STATE_PASS_ARG nsStringValue));
And finally you might want to return a value from callback as such: public static int callback(int arg)
This is tricky since we had to change the method signatures to support covariant return types and so the signature of that method under XMLVM would be:
But under the new VM it is:
The upper case R allows us to differentiate between void callback(int,int) and int callback(int). Unfortunately portability here isn't trivial so ifdef's are the only way. What we do is something like this:
JAVA_INT val = com_mycompany_NativeCallback_callback___int_R_int(intValue);
JAVA_INT val = com_mycompany_NativeCallback_callback___int(intValue);
Notice: This post was automatically converted using a script from an older blogging system. Some elements might not have come out as intended.... If that is the case please let us know via the comments section below.