我刚刚熟悉 jni/java 以及我们想要调用用本机代码编写的方法的工作流程,但我尚无法理解的是,如果本机 C++ 库具有像这样的 C++ 抽象类,则如何利用 JNI下面都可以由 C++ 继承来创建具体的 C++ 类,但也可以由 java 类扩展
class NumberInterface {
public:
using Numbers = std::unordered_set<unsigned int>;
/**
* Getter to receive all numbers.
*
* @return Numbers.
*/
virtual Numbers getSupportedNumbers() = 0;
virtual bool handleNumber(unsigned int number) = 0;
virtual bool cancelNumber(unsigned int number) = 0;
};
因此,如果这是一个共享库而不是本机端,则某些库可以链接到它,并且它可以具有如下所示的数字类
class Number : public NumberInterface {
public:
Numbers getSupportedNumbers() override;
bool handleNumber(unsigned int number) override;
bool cancelNumber(unsigned int number) override;
...
};
到目前为止我无法弄清楚的是,在Java方面,如果我有一个需要使用这个本机实用程序库的库/apk,我如何构建我的实用程序或jni,以便我们可以拥有一个java可以扩展 NumberInterface 的类。
class JavaNumber extends JavaNumberInterfaceEquivalent {
...
}
----编辑添加移动代码片段---
我希望 util 类也有一个 NumberManagerInterface ,如下所示
/// NumberManagerInterface that can handle numbers.
class NumberInterface {
public:
/**
* Register modules that handle numbers.
*
* @return true if successful, false otherwise.
*/
virtual bool registerNumberModule(const std::shared_ptr<NumberModuleInterface>& module) = 0;
virtual bool handleNumber(const unsigned int number) = 0;
virtual bool cancelNumber(const unsigned int number) = 0;
};
/**
* Sample NumberManager class.
*
*/
class NumberManager : public NumberManagerInterface{
public:
static std::shared_ptr<NumberManagerInterface> createNumberManagerInstance(...);
bool registerNumberModule(const std::shared_ptr<NumberModuleInterface>& module) override;
bool handleNumber(const unsigned int number) override;
bool cancelNumber(const unsigned int number) override;
...
private:
std::vector<std::shared_ptr<NumberModuleInterface>> m_numberHandlers;
...
};
bool NumberManager::registerNumberModule(const std::shared_ptr<NumberModuleInterface>& module){
// do some validation
m_numberHandlers.insert(module);
...
return true;
}
bool NumberManager::handleNumber(const unsigned int number){
//find the correct handler from m_numberHandlers
//call the correct handler
return handler->handleNumber(number);
}
void NumberManager::cancelNumber(const unsigned int number){
...
}
从 Java 调用
NumberManager
非常简单:使用一些 native
方法定义 Java 类,并通过参数进行探索。
提供
NumberInterface
的 Java 实现更加复杂。
在Java端,我们定义了一个接口:
// java
interface NumberInterface {
long[] getSupportedNumbers();
void handleNumber(long);
void cancelNumber(long);
static native void registerNumberInterface(NumberInterface);
}
我们在这里使用
long
,因为Java没有无符号整数。
我们可以像这样定义包装器:
class JavaNumberInterface : public NumberInterface {
public:
JavaNumberInterface(jobject o) {
JNIEnv *env = getEnv();
obj = env->NewGlobalRef(o);
}
Numbers getSupportedNumbers() override {
JNIEnv *env = getEnv();
jclass cls = env->GetObjectClass(obj);
jmethodID mid = env->GetMethodID(cls, "getSupportedNumbers", "()[J");
jlongArray jarr = (jlongArray) env->CallObjectMethod(obj, mid);
jsize len = env->GetArrayLength(jarr);
jlong* arr = env->GetLongArrayElements(jarr, nullptr);
Numbers ret;
for (auto x: std::span(arr, len)) {
ret.insert(int(x));
}
env->ReleaseLongArrayElements(jarr);
env->DeleteLocalRef(jarr);
env->DeleteLocalRef(cls);
return ret;
}
bool handleNumber(unsigned int number) override { /* similar */ }
bool cancelNumber(unsigned int number) override { /* similar */ }
private:
jobject obj;
JNIEnv *getEnv();
};
registerNumberInterface
的本机实现是:
JNIEXPORT void JNICALL Java_NumberInterface_registerNumberInterface(JNIEnv *env, jclass cls, jobject obj) {
NumberManager& nm = getNumberManagerSomehow();
nm.registerNumberModule(std::make_shared<JavaNumberInterface>(obj));
}