Использование существующей общей библиотеки (.so) в приложении Android - PullRequest
10 голосов
/ 23 июня 2011

У меня есть следующий сценарий для работы.Мне дали общую библиотеку (libeffect.so) для использования в проекте Android, на котором я работаю для клиента.У меня нет исходного кода общей библиотеки, у меня есть только файл .so со мной.Библиотека предварительно скомпилирована для работы на устройствах Android.Наряду с общей библиотекой у меня есть метод сигнатуры

public static native void doEffect(int param1, IntBuffer intBuffer);

Так что теперь у меня есть некоторые вопросы о том, как сделать вызов этого нативного метода из source, если это возможно, имея только файл .so,вот они:

  1. Нужно ли размещать сигнатуру нативного метода в том же пакете / классе, который определен, когда был .so, или я могу использовать эту сигнатуру в любом пакете /класс в моем проекте, что во время выполнения jvm сможет найти метод в общей библиотеке?Например, если эта общая библиотека впервые использовалась в классе mypackage.MyClass, нужно ли мне создавать тот же пакет, класс и затем помещать туда сигнатуру метода?

  2. Где я могунужно разместить этот .so файл в моем проекте eclipse android, чтобы развернуть этот файл внутри моего apk-файла?

Этот вопрос может звучать нуб, но я никогда раньше не работал с jndi, поэтому яЯ немного обеспокоен, если можно вызвать метод doEffect без каких-либо ошибок.Любой ответ, который может мне помочь, очень приветствуется.

Большое спасибо Тьяго

Ответы [ 2 ]

6 голосов
/ 23 июня 2011
  1. Нужно ли размещать сигнатуру нативного метода в том же пакете / классе, что и те, которые определены, когда .so был или я можете использовать эту подпись в любом пакет / класс в моем проекте, который во время выполнения JVM сможет найти метод в общей библиотеке? Например, если эта общая библиотека впервые был использован в классе mypackage.MyClass, мне нужно создать тот же пакет, класс, а затем положить подпись метода есть?

Нет необходимости создавать тот же пакет / класс. Вы можете поместить подпись метода в любой пакет.

public class NativeLib {

  static {
    System.loadLibrary("so_file");
  }

  public static native void doEffect(int param1, IntBuffer intBuffer);

}

2.Где мне нужно разместить этот .so файл в моем проекте eclipse android? получить этот файл в моем файле apk?

Вы поместили этот .so-файл в папку lib вашего приложения. Если папка lib отсутствует, вы можете создать папку lib и поместить файл .so. Вы можете вызвать его, используя System.loadLibrary ("so_ file");

1 голос
/ 18 февраля 2013

1 Нужно ли размещать подпись нативного метода в той же пакет / класс, как те, которые определены, когда .so был, или я могу использовать это подпись в любом пакете / классе в моем проекте, который во время выполнения jvm сможет найти метод в общей библиотеке?

Согласно http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html вы должны использовать соответствующий пакет и имя класса.

Я наблюдал только методы JNI, в которых функции на стороне C называются такими вещами, как Java_com_company_whwhat_SomeClass_someMethod, что означает, что вы должны поместить «нативные» объявления в класс Java с аналогичным именем.

Используйте инструмент «nm» или «nm ++» (они находятся в предварительно скомпилированных папках в NDK), чтобы посмотреть файл .so и увидеть, как называются определенные в нем функции. Если вы видите стартовую Java_, это то, что вы хотите.

Я скептически отношусь к предыдущему утверждению, что вы можете вызывать функции, которые не названы в формате Java_PACKAGE_CLASS_METHOD; это может быть устаревшее поведение, если оно действительно работает, но даже если вы можете, это кажется опасным - вы можете ошибиться.

2 Где мне нужно разместить этот .so файл внутри моего затмения android проект для развертывания этого файла внутри моего apk-файла?

Ваш .so живет в libs / armeabi, libs / armeabi-v7a, libs / x86 и / или libs / mips, в зависимости от того, сколько платформ вы работаете, где libs является пэром src и «res». Я не знаю, выглядит ли Android в libs / без классификатора платформы, но в этом нет очевидного преимущества. Ситуация несколько усложняется большинством / всеми устройствами Intel, включая причудливую технологию, позволяющую им выполнять большинство библиотек ARM на оборудовании x86.

Кроме того, мне нравится объявлять интерфейс класса JNI и предоставлять фабрику (здесь для краткости это метод, но я предпочитаю фабричный класс), который обеспечивает реализацию интерфейса без операции, если что-то пойдет не так: облегчает модульное тестирование, а также избавляет от необходимости возиться с проверкой на нулевые значения перед вызовом ее методов (при условии, что вы уверены, что в вашей поставляемой библиотеке никогда не будет отсутствующих или измененных сигнатур методов - ваши интеграционные тесты должны это проверить):

public interface YourLibI {
    @Override
    public native yourMethod();

    public static final NO_OP = new YourLibI() {
        @Override
        public void yourMethod(){}
    }
}

public class YourLib extends YourLibI {
    public newYourLibI() {
        try {
            return new YourLib();
        }
        catch (UnsatisfiedLinkError e) {
            Log.e("YourLibJNI", "Load failed, returning NO-OP dummy", e);
            return YourLibI.NO_OP;
        }
    }

    static {
        System.loadLibrary("arbitronSDK");
    }

    private YourLib() {
    }

    @Override
    public native void yourMethod();
}

Обычно я не называю интерфейсы «xxxI», но я предполагаю, что класс JNI вашей библиотеки не называется чем-то хорошим, как UtilityJNI (после чего я бы назвал интерфейс «Utility»).

...