NDK в Android, по шагам

NDK является комплексом инструментов для сборки нативных библиотек для последующего их использования в Android приложениях. Подобные средства могут оказаться очень полезными, если нам нужно использовать OpenGL или же производить массу математических операций, а так же мы можем собрать уже готовые сишные библиотеки, не реализовывая новый велосипед на Java.

И так. Для начала нам потребуется сам NDK который можно достать тут. Там есть краткое описание для начала работы с NDK. По сути этот пост является какого то рода изложением там написанного и того что можно найти в этой статье.

Допустим у нас уже есть Eclipse и в наличии телефон или виртуальная машина, где мы сможем все это затестить. Собственно, нам не обязательно включать в Eclipse поддержку сишного когда, но если у вас есть желание включить подсветку синтаксиса или прочих вкусных вещей, то это можно сделать в "Help – Install New Software". Пакет называется "Eclipse C/C++ Development Tools".

Пользователям Windows необходимо установить себе Cygwin, для эмуляции Unix среды. Установка не должна вызвать затруднений ( Ну так это же венда :) ). Честно говоря, не пользовался никогда Cygwin, так что для разрешения с ним каких либо проблем, прошу в гугл.

Так или иначе, вернемся к NDK. Самой идеей использования NDK является использование откомпилированные куски кода в виде библиотеки, которые в последующем загружаются посредством Java. Посему создадим, для начала, Java приложение, а потом уже займемся NDK. Так как нет каких жестких требований от Java приложения, при использовании NDK, то можете создать любой Android Application Project.

Далее, как и говориться на developer.android.com, создадим в корне проекта директорию jni, а в ней .mk-файлик - Android.mk. Текст для этого файлика можно посмотреть в скаченном вами архиве с NDK в директории "tests/build/" там полным полно разный проектов. Возьмем какой нить, например, ansi и составим свой файлик на основе их данных:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := test_ndk
LOCAL_SRC_FILES := test_ndk.c

include $(BUILD_SHARED_LIBRARY)

Про создание этого файлика, да и вообще подготовку модуля, можно прочесть все в том же архиве ndk, в документе "docs/IMPORT-MODULE.html". Возвращаясь к нашему модулю, создадим файлик с кодом модуля - test_ndk.c и напишем функцию, которую и будем испытывать в Android приложении.

#include <string.h>
#include <jni.h>

jstring Java_ftp27_ndk_test1_MainActivity_testNDKFunction(JNIEnv* env, jobject javaThis) {
  return (*env)->NewStringUTF(env, "Hello, World!");
}

Разберем то что у нас получилось, в котором нам немного поможет статья с хабра :) :

  • jstring - тип возвращаемых данных (что же еще это может быть :) )
  • Java_ - обязательный префикс
  • ftp27_ndk_test1 - имя пакета. Оно у меня, что очевидно, называется ftp27.ndk.test1 .
  • MainActivity_testNDKFunction - имя класса и функции в Java
  • JNIEnv* - JNI интерфейс, который можно расшифровать как Java Native Interface. Через него можно пользовать функциями и классами Java. Про него можно как следует начитаться в документации от ORACLE тут.

Если вы собираетесь и дальше использовать NDK, то вам будет просто необходимо научиться работать с JNI. Надеюсь, мне удастся про него немного написать в будущем. Но не будем отступать от нашего занятия. Зайдем в папку с проектом и запустим там скрипт ndk-build, но если быть точным то это будет выглядеть примерно так:

$ cd workspace/NDKTest-1/jni/
$ ~/android-ndk-r8e/ndk-build
/home/ftp27/android-ndk-r8e/build/core/add-application.mk:128: Android NDK: WARNING: APP_PLATFORM android-14 is larger than android:minSdkVersion 8 in /home/ftp27/workspace/NDKTest-1/AndroidManifest.xml    
Compile thumb  : test_ndk <= test_ndk.c
SharedLibrary  : libtest_ndk.so
Install        : libtest_ndk.so => libs/armeabi/libtest_ndk.so

Теперь, выполним функцию полученного модуля в нашем Android приложении:

В Layout создадим текстовое пустое поле

<TextView
android:id="@+id/testText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="" />

А в Activity укажем:

package ftp27.ndk.test1;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;

public class MainActivity extends Activity {

	// Загружаем библиотеку
	static {
	    System.loadLibrary("test_ndk");
	}

	//Объявим функцию 
	private native String testNDKFunction();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView testText = (TextView) findViewById(R.id.testText);

        //Заменяем текст в TextView нашим сообщением
        testText.setText((CharSequence) testNDKFunction());
    }
}

В результате получим наш результат: