Пример: hello-jni

В этом примере рассматривается hello-jni – минимальное приложение на C/C++, созданное с помощью NDK. Этот пример находится в каталоге hello-jni репозитория ndk-samples в ветке android-mk.

Android.mk

В следующих двух строках указывается имя исходного файла и имя общей библиотеки, которую нужно создать. Полное название созданной библиотеки – libhello-jni.so. Оно формируется после того, как система сборки добавляет префикс lib и расширение .so.

LOCAL_SRC_FILES := hello-jni.c
LOCAL_MODULE    := hello-jni

Подробнее о том, для чего нужен файл Android.mk и как его использовать, рассказывается в статье Android.mk.

Application.mk

Эта строка указывает системе сборки, для какого ЦП и архитектуры нужно выполнить сборку. В этом примере система сборки создает сборки для всех поддерживаемых архитектур.

APP_ABI := all

Дополнительные сведения о файле Application.mk и о том, как его использовать, можно найти в статье Application.mk.

Реализация на стороне Java

Файл helloJNI.java находится в каталоге hellojni/src/com/example/hellojni/. Она вызывает функцию, которая получает строку из нативного кода и показывает ее на экране.

Исходный код содержит три строки, представляющие особый интерес для пользователя NDK. Они представлены в порядке использования, а не в порядке строк.

Этот вызов функции загружает файл .so при запуске приложения.

Kotlin

System.loadLibrary("hello-jni")

Java

System.loadLibrary("hello-jni");

Ключевое слово native в объявлении метода сообщает виртуальной машине, что функция находится в общей библиотеке (то есть реализована на стороне нативного кода).

Kotlin

external fun stringFromJNI(): String

Java

public native String stringFromJNI();

Фреймворк Android вызывает функцию, загруженную и объявленную на предыдущих шагах, и показывает строку на экране.

Kotlin

tv.text = stringFromJNI()

Java

tv.setText( stringFromJNI() );

Реализация на стороне клиента

Файл hello-jni.c находится в каталоге hello-jni/jni/. Он содержит функцию, которая возвращает строку, запрошенную Java. Объявление функции выглядит следующим образом:

JNIEXPORT jstring JNICALL
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )

Это объявление соответствует нативной функции, объявленной в исходном коде Java. Тип возвращаемого значения jstring – это тип данных, определенный в спецификации Java Native Interface. Это не строка, а указатель на строку Java.

После jstring указывается название функции, которое зависит от названия функции Java и пути к файлу, в котором она содержится. составленный по следующим правилам:

  • Добавьте в начало Java_.
  • Укажите путь к файлу относительно каталога с исходными файлами верхнего уровня.
  • Используйте вместо них символ подчеркивания.
  • Расширение имени файла .java указывать не нужно.
  • После последнего символа подчеркивания добавьте название функции.

В нашем примере название функции – Java_com_example_hellojni_HelloJni_stringFromJNI. Это название относится к функции Java stringFromJNI(), которая находится в hellojni/src/com/example/hellojni/HelloJni.java.

JNIEnv* – указатель на виртуальную машину, а jobject – указатель на неявный объект this, переданный из Java.

В следующей строке вызывается VM API (*env) и передается возвращаемое значение, то есть строка, которую запрашивала функция на стороне Java.

return (*env)->NewStringUTF(env, "Hello from JNI !
Compiled with ABI " ABI ".");