Cross platform mobile development Part IV
How to pass a ByteBuffer from Java to C++ with Djinni
It’s been a while since my last article on Medium (There goes my 2018’s resolution to write an article every month). In NetVirta, I am responsible to integrate a brand new C++ library to an Android library, which itself can be consumed by an Android application be it native applications, React Native or even the spanking hot Flutter which I have so much fun playing with during my own free time.
So I was using Djinni to do all the heavy lifting for me to generate JNI codes. It took me a bit of time to get used to Djinni and I do not regret spending time learning and using it. I shuddered at the thoughts of writing and maintaining them manually. Without further ado, let’s dive straight back to the wonderful world of Djinni.
Djinni’s Data Types
The available data types for a record, argument, or return value are:
- Boolean (
- Primitives (
- Strings (
- Binary (
binary). This is implemented as
bytein Java, and
- Date (
date). This is
Datein Java, and
- List (
list<type>). This is
ArrayListin Java, and
NSArrayin Objective-C. Primitives in a list will be boxed in Java and Objective-C.
- Set (
set<type>). This is
HashSetin Java, and
NSSetin Objective-C. Primitives in a set will be boxed in Java and Objective-C.
- Map (
map<typeA, typeB>). This is
unordered_map<K, V>in C++,
HashMapin Java, and
NSDictionaryin Objective-C. Primitives in a map will be boxed in Java and Objective-C.
- Enumerations / Flags
- Optionals (
optional<typeA>). This is
std::experimental::optional<T>in C++11, object / boxed primitive reference in Java (which can be
null), and object / NSNumber strong reference in Objective-C (which can be
- Other record types. This is generated with a by-value semantic, i.e. the copy method will deep-copy the contents.
In this article I will demonstrate how to use types that are not generated by Djinni, such as java.nio.ByteBuffer. One of the use cases is doing OpenCV projects where we want to pass the ByteBuffer from a camera Image to the C++ side.
In dealing with C++ image recognition libraries, we often need to send a ByteBuffer from the camera to the C++ side as a char pointer (char*).
There are a few steps to achieve it. To understand how this works we need to look at the generated Djinni code for the types that are supported by Djinni. Checkout the generated JNI code to pass a simple string from the Java side to C++ side.
You can see on line 8 and line 14, they are
fromCpp() methods. So what are they? You should be able to guess it already. This is where Djinni convert Java to C++ and vice versa. From the repository README, it is written that:
These files can be created by hand as long as you follow the required format. This allows you to support types not generated by Djinni.
There are three steps:
- Create and update a header file containing the
toCpp()methods. Write the conversion code there.
- Create and update the YAML file to allow .djinni file to utilise the custom data type.
- Update the .djinni file
- Run Djinni to generate the JNI code.
Create and update a header file containing the
toCpp() methods. We can get the byte pointer from
env->GetDirectBufferAddress() and cast it to
Create and update the YAML file to allow .djinni file to utilise the custom data type.
There are a few notes that I have to point out.
- I left objc and objcpp with empty strings. Apparently it will only work if all the fields below are in place and will error out if you left them out.
- I put the value of header under cpp as
'<string>’because it doesn’t accept null value. And an empty string will generate a
#include ''linker file that prevents your code from compilation.
- The value of header under jni must be relative to the JNI code generated by Djinni.
Update the .djinni file.
Run djinni to generate the linking code. Do checkout the first post if you haven’t yet to learn how to do it. :)
Bringing them all together
So with the generated classes, we can now pass the RGB ByteBuffer to the C++ side as a pointer.
And finally use the code at the C++ side.
I hope that this article will be able to help you if you are facing this particular problem.
My previous posts about Djinni: