我必须使用哪些类和方法从C ++调用Java?

时间:2017-10-24 10:12:09

标签: java android c++ djinni

我目前正在与Djinni合作,并希望从C ++中调用Java方法。

我有以下界面描述文件:

ExampleSO = interface +j {
  PerformAddition(a: i32, b: i32): i32;
}

它会生成以下文件:

  • src/main/cpp/ExampleSO.hpp:包含虚拟析构函数和虚拟ExampleSO方法的C ++ PerformAddition类。
  • src/main/java/com/name/group/ExampleSO.java:Java ExampleSO abtract包含public abstract PerformAddition方法的类。
  • src/main/jni/NativeExampleSO.hpp / .cpp:JNI绑定。

我想要做的是创建一个新的Java类,它将扩展ExampleSO Java类(在接口描述中使用+j指定),并且能够从c ++调用这些方法文件。

我可以在JNI绑定中看到有一个公共using CppType = std::shared_ptr<::ExampleSO>;。鉴于名称,我认为这将是通过JNI桥调用Java方法的方法,但是当我尝试执行以下操作时会导致段错误:

// SampleClass.hpp
#include "ExampleSO.hpp"

class SampleClass: ExampleSO {
private:
    NativeExampleSO::CppType neso;
public:
    int32_t PerformAddition(int32_t a, int32_t b) override;
}

// SampleClass.cpp
#include "SampleClass.hpp"

int32_t SampleClass::PerformAddition(int32_t a, int32_t b) {
    neso->PerformAddition(a, b); // Crash
}

我是否必须以某种方式初始化此neso字段?

提前致谢。

编辑:以下是NativeExampleSO.hpp(JNI桥接)的内容,它可以让回答更轻松:

// AUTOGENERATED FILE - DO NOT MODIFY!
// This file generated by Djinni from ExampleSO.djinni

#pragma once

#include "ExampleSO.hpp"
#include "djinni_support.hpp"

namespace djinni_generated {

class NativeExampleSO final : ::djinni::JniInterface<::ExampleSO, NativeExampleSO> {
public:
    using CppType = std::shared_ptr<::ExampleSO>;
    using CppOptType = std::shared_ptr<::ExampleSO>;
    using JniType = jobject;

    using Boxed = NativeExampleSO;

    ~NativeExampleSO();

    static CppType toCpp(JNIEnv* jniEnv, JniType j) { return ::djinni::JniClass<NativeExampleSO>::get()._fromJava(jniEnv, j); }
    static ::djinni::LocalRef<JniType> fromCppOpt(JNIEnv* jniEnv, const CppOptType& c) { return {jniEnv, ::djinni::JniClass<NativeExampleSO>::get()._toJava(jniEnv, c)}; }
    static ::djinni::LocalRef<JniType> fromCpp(JNIEnv* jniEnv, const CppType& c) { return fromCppOpt(jniEnv, c); }

private:
    NativeExampleSO();
    friend ::djinni::JniClass<NativeExampleSO>;
    friend ::djinni::JniInterface<::ExampleSO, NativeExampleSO>;

    class JavaProxy final : ::djinni::JavaProxyHandle<JavaProxy>, public ::ExampleSO
    {
    public:
        JavaProxy(JniType j);
        ~JavaProxy();

        int32_t PerformAddition(int32_t a, int32_t b) override;

    private:
        friend ::djinni::JniInterface<::ExampleSO, ::djinni_generated::NativeExampleSO>;
    };

    const ::djinni::GlobalRef<jclass> clazz { ::djinni::jniFindClass("com/name/group/ExampleSO") };
    const jmethodID method_PerformAddition { ::djinni::jniGetMethodID(clazz.get(), "PerformAddition", "(II)I") };
};

}  // namespace djinni_generated

1 个答案:

答案 0 :(得分:1)

正如您所注意到的,使用实现Djinni接口的对象需要首先创建一个对象,该对象只能以实现该对象的语言来完成。一旦你有了一个对象,你可以在语言之间传递它,并从任何语言自由地调用它。问题是你如何&#34; bootstrap&#34;获得你需要的对象。通常,bootstrapping总是必须从Java / ObjC开始。

Djinni不支持直接使用构造,但支持一个方向的静态方法(Java / ObjC - &gt; C ++)。您可以从Java调用以提供C ++的对象以便以后存储和使用,或者您可以反过来使用静态方法作为工厂,让Java要求C ++创建对象。  如果您不介意使用全局状态,或者您需要立即使用该对象,前者会更简单。

interface example_so_setup +c {
    set_example_so(obj: example_so)
}

Djinni test suite中有一个示例,其中test_helper是一个接口,其方法check_client_interface_ascii是从Java here调用的。 Java将aJava对象作为参数传递,然后C ++对其进行调用。

如果你想避免使用全局状态,你可以添加一个额外的步骤,其中Java首先调用静态工厂方法来创建某种类型的C ++&#34; manager&#34;对象,然后调用该对象以传递example_so以进行回调。具体如何发生可能取决于您的应用初始化需求。