Home

Awesome

JMI

JNI Modern Interface in C++

中文

Some Java Classes Written in JMI

Build status github

Features

Example:

    // 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");

jmethodID Cache

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

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");
    ...

Writting a C++ Class for a Java Class

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

Using Signatures Generated by Compiler

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),
        ...
    }

Known Issues

Why JObject is a Template?

Compilers

c++14/17 is required

TODO

MIT License

Copyright (c) 2016-2021 WangBin