Android и ошибка неудовлетворенной ссылки

#java-native-interface #android-ndk

#java-native-interface #android-ndk

Вопрос:

У меня особая проблема с Android и библиотекой JNI, которую я использую. Библиотека JNI называется libBase.so и должным образом включен в APK. Я могу выполнить System.LoadLibrary («База»), и библиотека загружается и может использоваться без каких-либо проблем.

Рассмотрим следующие фрагменты кода:

 /* NativeObject.java */
public class NativeObject
{
    /* ... */
    static
    {
        System.loadLibrary("Base");
    }
}

/* ObjectUtil.java */
public class ObjectUtil
{
    public static native NativeObject readNative(String path);
    public static native void writeNative(String path, NativeObject obj);
}
  

Когда я пытаюсь выполнить ObjectUtil.readNative() в начале моей программы, я получаю следующие проблемы в logcat:

 05-19 18:57:38.508: WARN/dalvikvm(365): No implementation found for native Lcom/navimatics/base/ObjectUtil;.readNative (Ljava/lang/String;)Lcom/navimatics/base/NativeObject;
05-19 18:59:15.409: ERROR/AndroidRuntime(365): java.lang.UnsatisfiedLinkError: readNative
  

Насколько я понимаю, поскольку класс ObjectUtil ссылается на NativeObject , загрузка класса ObjectUtil должна привести к загрузке класса NativeObject и, следовательно, к выполнению статического инициализатора NativeObject, который выполняет System.Вызов LoadLibrary(). Тогда непонятно, почему я получаю вышеупомянутые сообщения logcat.

Однако, если я изменю ObjectUtil.java читать следующим образом, исключений нет, и программа работает:

 /* ObjectUtil.java */
public class ObjectUtil
{
    public static native NativeObject readNative(String path);
    public static native void writeNative(String path, NativeObject obj);
    static
    {
        System.loadLibrary("Base");
    }
}
  

Это также работает, если я делаю это:

 /* ObjectUtil.java */
public class ObjectUtil extends NativeObject
{
    public static native NativeObject readNative(String path);
    public static native void writeNative(String path, NativeObject obj);
}
  

Любая помощь по этому вопросу была бы высоко оценена.

ОБНОВЛЕНИЕ: исходный код, о котором меня просили, это:

 static jobject JNICALL readNative(JNIEnv *env, jclass jcls, jstring jpath)
{
    // ...
}
static void JNICALL writeNative(JNIEnv *env, jclass jcls, jstring jpath, jobject jobj)
{
    // ...
}

static JNINativeMethod methods[] =
{
    { "readNative", "(Ljava/lang/String;)Lcom/navimatics/base/NativeObject;", readNative },
    { "writeNative", "(Ljava/lang/String;Lcom/navimatics/base/NativeObject;)V", writeNative },
};
  

Методы регистрируются с помощью JNIEnv.registerNatives().

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

1. Вы не предоставили код объявлений на собственной стороне, и ответ лежит там

2. Код добавлен в соответствии с запросом.

Ответ №1:

У вас есть две дополнительные круглые скобки при инициализации массива JNINativeMethod, этот код не должен компилироваться.

Проверьте код возврата registerNatives(), в случае успеха он должен быть равен нулю.

Также, если вы компилируете код на C , вам следует объявить собственные методы extern "C" , чтобы избежать их искажения.

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

1. Огниан, ты прав насчет круглых скобок. Однако дополнительные круглые скобки не существуют в исходном коде. Исходный код содержит ряд макросов, которые я расширил вручную, отсюда и проблемы, которые вы видели. Исправлено.

2. Однако я не согласен с наблюдением extern «C». Напомним, что registerNatives() регистрирует указатели на функции. Имена этих статических функций не имеют значения.

3. Вы правы насчет extern "C" . Вы проверили возвращаемое значение RegisterNatives , они были успешно зарегистрированы?

4. registerNatives() возвращает успех, если он вызывается. Как объяснялось, если я явно вызываю System.LoadLibrary (), а затем ObjectUtil.readNative(), он работает без проблем. Проблема возникает только тогда, когда я вызываю ObjectUtil.readNative (), предварительно не вызвав System.LoadLibrary(). Однако это не должно вызывать проблемы, потому что ObjectUtil ссылается на класс NativeObject, который вызывает System.LoadLibrary() в статическом инициализаторе. Пожалуйста, смотрите мой оригинальный пост для полного объяснения.