Учимся работать с Android NDK или как использовать C код в java проектах

Android NDK nativeAndroid NDK представляет собой набор утилит, позволяющих Вам включать код, написанный на C и C++, в ваше приложение. Такой код называется нативным(native), поскольку он не может быть выполнен на виртуальной машине и компилируется непосредственно в машинный код требуемой процессорной архитектуры.

Данный урок относится к разряду продвинутых. Подразумевается, что читатель уже имеет некоторые навыки, в частности

  1. Вы умеете программировать на Java и C
  2. Вы умеете работать с командной строкой
  3. Вы знаете, как узнать версии Cygwin, awk и других инструментов, которыми нам придется пользоваться
  4. Вы умеете разрабатывать приложения для Android
  5. У Вас настроена среда разработки для Android (в момент написания автор использовал Android 2.2)
  6. Вы используете Eclipse или можете транслировать инструкции по работе с eclipse на свою IDE.


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

Когда нужно использовать Android NDK?

Обычно разработчики решают использовать нативный код в двух случаях: они хотят увеличить производительность своего приложения, или у них есть готовый C/C++ проект, который требуется с минимальными затратами портировать на Android. Давайте не будем спешить и разберемся, когда же целесообразно использовать NDK, а когда этого не нужно делать.

Наиболее часто программистами высказывается мнение, что NDK стоит использовать, когда приложение сильно нагружает процессор. Существуют алгоритмы, позволяющие полностью загрузить процессор через DalvikVM, в этом случае использование нативного кода действительно с большой вероятностью позволит получить выигрыш в производительности. Однако, не нужно забывать, что использование JIT компилятора также позволяет повысить производительность java кода. Многие думают, что использование в приложении машинного кода автоматически означает увеличение скорости работы приложения. На самом деле это не так. Переключение с выполнения java кода на машинный код и обратно несет с собой накладные расходы, поэтому использовать NDK стоит, только если у вас выполняется какой-нибудь долгий сложный расчет, полностью написанный на C, и в java коде не предполагается частое дерганье нативных функций.


Другой причиной, которая может побудить Вас использовать NDK является необходимость портирования готового приложения. Вполне логично не переписывать уже проверенные и отлаженные куски кода на java, а использовать NDK. Этот подход также позволит Вам в дальнейшем без особых затрат вносить параллельно правки в исходное и портированное на android приложение. В частности, такой подход оправдан в отношении приложений, использующих OpenGL ES.


Шаг 1: Установка Android NDK и настройка среды разработки


Прежде всего, Вам необходимо скачатьAndroid NDK. Для установки и нормальной работы нам также понадобятся утилиты Cygwin 1.7 или старше, awk последней версии, а также GNU Make 3.81 или старше.

После того, как Вы скачали архив с NDK, распакуйте его в какую-нибудь папку. Можно распаковать этот архив туда же, где лежит Android SDK. Путь к этой папке необходимо прописать в системной переменной PATH. В Windows для этих целей лучше настроить конфигурацию Cygwin.

Шаг 2: Создание нового проекта

Создайте новый Android проект. Чтобы избежать проблем в будущем сохраните проект так, чтобы путь к нему не содержал в себе символов пробела. Для примера создайте проект, в качестве названия пакета укажите "com.mamlambo.sample.ndk1", а в качестве Activity  -   "AndroidNDK1SampleActivity".

В корне проекта создайте папку с названием "jni". Именно здесь будет содержаться файлы с нативным кодом. Если Вы знакомы с JNI, то вам будет приятно узнать, что Android NDK по сути представляет собой JNI с ограниченным набором заголовочных файлов для компиляции C кода.

Шаг 3: Добавляем C код в Android проект

Создайте в папке jni файл с именем native.c и добавьте в него следующий код

#include <jni.h>
#include <string.h>
#include <android/log.h>

#define DEBUG_TAG "NDK_AndroidNDK1SampleActivity"

void Java_com_mamlambo_sample_ndk1_AndroidNDK1SampleActivity_helloLog(JNIEnv* env,
jobject this, jstring logThis)
{
jboolean isCopy;
const char* szLogThis=(*env)->GetStringUTFChars(env, logThis,&amp;isCopy);
 
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG,"NDK:LC: [%s]", szLogThis);
 
(*env)->ReleaseStringUTFChars(env, logThis, szLogThis);
}
 

Созданная таким образом функция берет параметр String у java объекта, конвертирует его в C-string и записывает в LogCat. Зубодробительное имя функции выбрано не случайно, оно несет в себе важную информацию: сначала указывается название паттерна ("Java"), затем идут название пакета, имя класса и название метода. Каждая часть имени отделяется знаком подчеркивания.

Первые два параметра у функции имеют особое значение. Первый параметр определяет JNI среду и часто используется со вспомогательными функциями. Второй параметр является объектом Java, частью которого является функция.

Шаг 4: Вызов нативного кода из Java

Давайте создадим в нашем проекте кнопку, при нажатии на которую будем вызывать следующий код:

helloLog("This will log to LogCat via the native call.");


Необходимо также объявить функцию helloLog в классе, где она вызывается. Сделать можно с помощью строки

private native void helloLog(String logThis);


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

Наконец, нужно загрузить библиотеку, куда в конечном счете будет скомпилирован код. Добавьте следующую инициализацию в класс Activity.

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

System.loadLibrary() обеспечивает загрузку библиотеки по имени. Вы можете использовать любое название.

Шаг 5: Создаем Make file для нативного кода

Для компиляции нативного кода в папке jni должен находиться Make file с именем "Android.mk". Ниже приведен код этого фала для нашего примера, то есть когда функция находится в файле native.c и в качестве имени библиотеки указано ndk1

LOCAL_PATH := $(call my-dir) 
 
include $(CLEAR_VARS) 
 
LOCAL_LDLIBS := -llog 
 
LOCAL_MODULE    := ndk1 
LOCAL_SRC_FILES := native.c 
 
include $(BUILD_SHARED_LIBRARY)


Шаг 6: компиляция нативного кода

После того, как Вы написали код и добавили make файл в папку jni можно приступать к компиляции. Для этого нужно в командной строке (Если вы работаете в windows, запустите Cygwin) запустить ndk-build из папки проекта. Утилита ndk-build входит в состав Android NDK. Если Вы все сделали правильно, то вы должны увидеть что-то вроде этого

NDK компиляция

Шаг 7: Запуск приложения

Теперь можно запустить проект, нажать на кнопку и посмотреть, как изменится LogCat.

Может произойти одна из двух вещей: 1) ваш проект может запуститься и работать, как Вы того ожидаете. В этом случае примите мои поздравления. 2) Возникнет ошибка, которая в LogCat отобразиться как "Could not execute method of activity." Ничего страшного. Обычно Eclipse сконфигурирован так, что при запуске проекта автоматически происходит его перекомпиляция. В случае, если эта опция отключена, то нужно вручную заставить Eclips перекомпилировать проект. Для этого перед запуском нужно вызвать менюProject->Clean from the Eclipse toolbar.

Шаг 8: Как вернуть объект из нативной функции

Следующий пример демонстрирует возможность нативных функций возвращать объекты, например String. Добавьте код в файл native.c

jstring Java_com_mamlambo_sample_ndk1_AndroidNDK1SampleActivity_getString(JNIEnv* env,
jobject this, jint value1, jint value2)
{
char*szFormat="The sum of the two numbers is: %i";
char*szResult;
 
// добавляем две переменные
jlong sum= value1+value2;
 
// malloc для строки результата
szResult= malloc(sizeof(szFormat)+20);
 
// standard sprintf
sprintf(szResult, szFormat, sum);
 
// получаем объект string
jstring result=(*env)->NewStringUTF(env, szResult);
 
// очищаем память
free(szResult);
 
return result;
}

С помощью команды malloc мы создали буфер, куда затем с помощью sprintf поместили строку. Чтобы функция возвращала корректный результат, мы использовали JNI helper функцию NewStringUTF(), которая фактически создает Java объект на основании C строки. После этого мы очистили память с помощью команды free().

Для успешной компиляции проекта необходимо в native.c подключить заголовочный файл stdio.h. В классе Activity нужно также объявить новую функцию:

private native String getString(int value1, int value2);

после этого с функцией getString  можно работать, например следующим образом:

String result= getString(5,2);
Log.v(DEBUG_TAG,"Result: "+result);
result= getString(105,1232);
Log.v(DEBUG_TAG,"Result2: "+result);


Замечания

Android NDK для своей работы требует Android SDK 1.5. С помощью NDK можно получить доступ ко многим API, например к OpenGL ES.

Нативный код компилируется в машинный код, соответствующий архитектуре процессора, и поскольку на разных телефонах используются процессоры разной архитектуры, у Вас может возникнуть проблемы с переносимостью программы. По умолчанию NDK производит компиляцию для  ARMv5TE. Когда Вы запускаете свое приложение на эмуляторе, а не на реальном устройстве, этот машинный код выполняется не напрямую, а через еще один эмулятор процессора.

Заключение

Ну вот собственно и все. Думаю теперь вам понятно, как работать с нативным кодом. Во многих случаях его применение оправдано, однако бездумное применеие нативного кода в своих проектах может оказаться губительным.

Авторы:Lauren Darcey и Shane Conder
Источник:Advanced Android: Getting Started with the NDK
Перевод:Александр Ледков





Наши соцсети

Подписаться Facebook Подписаться Вконтакте Подписаться Twitter Подписаться Google Подписаться Telegram

Популярное

Ссылки

Новости [1] [2] [3]... Android/ iOS/ J2ME[1] [2] [3]) Android / Архив

Рейтинг@Mail.ru Яндекс.Метрика
MobiLab.ru © 2005-2018
При использовании материалов сайта ссылка на www.mobilab.ru обязательна