JNI Modern Interface in C++17
JNI Modern Interface in C++
Some Java Classes Written in JMI
to_string(jstring, JNIEnv*)
, from_string(std::string, JNIEnv*)
, android::application()
Setup java vm in JNI_OnLoad
: jmi::javaVM(vm);
Create a SurfaceTexture:
// define SurfaceTexture tag class in any scope visibile by jmi::JObject<SurfaceTexture>
struct SurfaceTexture : jmi::ClassTag { static constexpr auto name() {return JMISTR("android/graphics/SurfaceTexture");}}; // or JMISTR("android.graphics.SurfaceTexture")
...
GLuint tex = ...
...
jmi::JObject<SurfaceTexture> texture;
if (!texture.create(tex)) {
// texture.error() ...
}
struct Surface : jmi::ClassTag { static constexpr auto name() {return JMISTR("android.view.Surface");}}; // '.' or '/'
...
jmi::JObject<Surface> surface;
surface.create(texture);
texture.call("updateTexImage");
or
texture.call<void>("updateTexImage");
float mat4[16]; // or std::array<float, 16>, valarray<float>
texture.call("getTransformMatrix", std::ref(mat4)); // use std::ref() if parameter should be modified by jni method
If out parameter is of type JObject<...>
or it's subclass, std::ref()
is not required because the object does not change, only some fields may be changed. For example:
MediaCodec::BufferInfo bi;
bi.create();
codec.dequeueOutputBuffer(bi, timeout); // bi is of type MediaCodec::BufferInfo&
auto t = texture.call<jlong>("getTimestamp");
GetMethodID/GetStaticMethodID()
is always called in call/callStatic("methodName", ....)
every time, while it's called only once in overload one call/callStatic<...MTag>(...)
, where MTag
is a subclass of jmi:MethodTag
implementing static const char* name() { return "methodName";}
.
// GetMethodID() will be invoked only once for each method in the scope of MethodTag subclass
struct UpdateTexImage : jmi::MethodTag { static const char* name() {return "updateTexImage";}};
struct GetTimestamp : jmi::MethodTag { static const char* name() {return "getTimestamp";}};
struct GetTransformMatrix : jmi::MethodTag { static const char* name() {return "getTransformMatrix";}};
...
texture.call<UpdateTexImage>(); // or texture.call<void,UpdateTexImage>();
auto t = texture.call<jlong, GetTimestamp>();
texture.call<GetTransformMatrix>(std::ref(mat4)); // use std::ref() if parameter should be modified by jni method
Field api supports cacheable and uncacheable jfieldID. Field object can be JNI basic types, string, JObject and array of these types.
Cacheable jfieldID through FieldTag
JObject<MyClassTag> obj;
...
struct MyIntField : FieldTag { static const char* name() {return "myIntFieldName";} };
auto ifield = obj.field<jint, MyIntField>();
jfieldID ifid = ifield; // or ifield.id()
ifield.set(1234);
jint ivalue = ifield; // or ifield.get();
// static field is the same except using the static function JObject::staticField
struct MyStrFieldS : FieldTag { static const char* name() {return "myStaticStrFieldName";} };
auto& ifields = JObject<MyClassTag>::staticField<std::string, MyIntFieldS>(); // it can be an ref
jfieldID ifids = ifields; // or ifield.id()
ifields.set("JMI static field test");
ifields = "assign";
std::string ivalues = ifields; // or ifield.get();
Uncacheable jfieldID using field name string directly
auto ifield = obj.field<jint>("myIntFieldName");
...
Create a class inherits JObject<YouClassTag> or stores it as a member, or use CRTP JObject<YouClass>. Each method implementation is usually less then 2 lines of code. See JMITest and Project AND
The function template auto signature_of<T>()
returns the signature of type T. T can be JMI supported types (except jobject types because the class is determined at runtime), reference_wrapper, void, and function types whose return type and parameter types are of above types.
example:
void native_test_impl(JNIEnv *env , jobject thiz, ...) {}
staitc const JNINativeMethod gMethods[] = {
{"native_test", signature_of(native_test_impl).data(), native_test_impl},
...
};
You may find that a macro can simplify above example:
#define DEFINE_METHOD(M) {#M, signature_of(M##_impl).data(), M##_impl}
staitc const JNINativeMethod gMethods[] = {
DEFINE_METHOD(native_test),
...
}
c++14/17 is required
Copyright (c) 2016-2021 WangBin