Можно ли создать новый объект задания прослушивателя java в JNI?

#java-native-interface #native

Вопрос:

В Android Studio MainActivity я пишу что-то вроде

 int itemA_num = 0;
int itemB_num = 0;

ABCListener mabclistener = new ABCListenter() {
    @Override
    public void onEventActivated(CustomResult result) {
        //do sth secret e.g.
        itemA_num   ;
    }
}

ABCobject mabcobject = (ABCobject) findviewById(R.id.abcobject1);
mabcobject.setListener(mabcListener);
 

Я не хочу, чтобы люди декомпилировали мой APK и изменяли код, изменяя значение или добавляя что-то подобное:

 ABCListener mabclistener = new ABCListenter() {
    @Override
    public void onEventActivated(CustomResult result) {
        //do sth secret e.g.
        itemA_num  = 10000; //possibly some general name read by those guys and modified as int1  =10000;
        itemB_num  = 500; //possibly some general name read by those guys and added this line int2  =500;
    }
}
 

Поэтому я хочу использовать JNI с Cmake. Внутри файла .cpp я хочу создать объект класса findviewById , setListener и создать ABCListener .
Я знаю, используя формат

 jclass cls = (jclass) env->FindClass("abc/def/GHI");
jmethodID mid = (jmethod) env->GetMethodID(cls, "methodname", "(xxxx)yyy");
jobject obj = (jobject) env->CallObjectMethod(cls, mid, params);
 

Однако, если я хочу написать код ABCListener и использовать jobject его, я не знаю, как и где сообщить машине, что я собираюсь написать некоторый код, относящийся к @Override public void onEventActivated(CustomResult result) { ... } ней . Я также хочу добавить несколько строк кода внутри ответа в JNI.

Я нашел веб-сайт, «похожий» на этот вопрос, но он с 2011 года и примерно доступен для запуска. https://community.oracle.com/tech/developers/discussion/2298550/overriding-interface-methods-via-jni Я не знаю, будет ли это по-прежнему работать в 2021 году.

Комментарии:

1. Если ваша модель угроз уже предполагает, что люди будут изменять ваш код, что помешает им снова заменить вашу собственную реализацию на Java?

Ответ №1:

Во-первых, определите новый класс на стороне Java:

 class NativeABCListener implements ABCListener {
  @Override public native void onEventActivated(CustomResult result);
}
 

Затем создайте экземпляр NativeABCListener либо на Java, либо в машинном коде и прикрепите его к своему mabcobject . Вы знаете, как это сделать, поэтому я не буду это повторять.

На родной стороне вы просто определяете метод C с соответствующим именем:

 JNIEXPORT void JNICALL Java_your_package_NativeABCListener_onEventActivated(JNIEnv *env, jobject thiz, jobject result) {
   ...
}
 

Если вам нужно несколько ABCListeners классов, которые выполняют разные действия, вы можете создать несколько NativeABCListener классов (каждый со своей собственной соответствующей собственной функцией) или изменить NativeABCListener , чтобы сохранить указатель функции C в long поле Java. В ..._onEventActivated функции вы затем извлекаете поле thiz и вызываете его как обычный указатель functino.