- Учимся работать с Android NDK или как использовать C код в java проектах
- Когда нужно использовать Android NDK?
- Шаг 1: Установка Android NDK и настройка среды разработки
- Шаг 2: Создание нового проекта
- Шаг 3: Добавляем C код в Android проект
- Шаг 4: Вызов нативного кода из Java
- Шаг 5: Создаем Make file для нативного кода
- Шаг 6: компиляция нативного кода
- Шаг 7: Запуск приложения
- Шаг 8: Как вернуть объект из нативной функции
- Замечания
- Заключение
- Gamedev suffering
- Блог о разработке игр и серверных технологиях
- Основы Android NDK: работа с C/C++ кодом
- Предварительная настройка
- Зачем нужен NDK?
- Java. Путешествие в Native (или туда и обратно).
- Создание файлов с C++ кодом
- Работа с Application.mk
- Работа с Android.mk
- Подключение библиотеки в Java и вызов C++ методов.
Учимся работать с Android NDK или как использовать C код в java проектах
Android NDK представляет собой набор утилит, позволяющих Вам включать код, написанный на C и C++, в ваше приложение. Такой код называется нативным(native), поскольку он не может быть выполнен на виртуальной машине и компилируется непосредственно в машинный код требуемой процессорной архитектуры.
Данный урок относится к разряду продвинутых. Подразумевается, что читатель уже имеет некоторые навыки, в частности
- Вы умеете программировать на Java и C
- Вы умеете работать с командной строкой
- Вы знаете, как узнать версии Cygwin, awk и других инструментов, которыми нам придется пользоваться
- Вы умеете разрабатывать приложения для Android
- У Вас настроена среда разработки для Android (в момент написания автор использовал Android 2.2)
- Вы используете 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 и добавьте в него следующий код
Созданная таким образом функция берет параметр String у java объекта, конвертирует его в C-string и записывает в LogCat. Зубодробительное имя функции выбрано не случайно, оно несет в себе важную информацию: сначала указывается название паттерна («Java»), затем идут название пакета, имя класса и название метода. Каждая часть имени отделяется знаком подчеркивания.
Первые два параметра у функции имеют особое значение. Первый параметр определяет JNI среду и часто используется со вспомогательными функциями. Второй параметр является объектом Java, частью которого является функция.
Шаг 4: Вызов нативного кода из Java
Давайте создадим в нашем проекте кнопку, при нажатии на которую будем вызывать следующий код:
Необходимо также объявить функцию helloLog в классе, где она вызывается. Сделать можно с помощью строки
Таким образом, мы сообщаем компилятору и линковщику, что реализацию этой функции стоит искать в папке с нативным кодом.
Наконец, нужно загрузить библиотеку, куда в конечном счете будет скомпилирован код. Добавьте следующую инициализацию в класс Activity.
System.loadLibrary() обеспечивает загрузку библиотеки по имени. Вы можете использовать любое название.
Шаг 5: Создаем Make file для нативного кода
Для компиляции нативного кода в папке jni должен находиться Make file с именем «Android.mk». Ниже приведен код этого фала для нашего примера, то есть когда функция находится в файле native.c и в качестве имени библиотеки указано ndk1
Шаг 6: компиляция нативного кода
После того, как Вы написали код и добавили make файл в папку jni можно приступать к компиляции. Для этого нужно в командной строке (Если вы работаете в windows, запустите Cygwin) запустить ndk-build из папки проекта. Утилита ndk-build входит в состав Android NDK. Если Вы все сделали правильно, то вы должны увидеть что-то вроде этого
Шаг 7: Запуск приложения
Теперь можно запустить проект, нажать на кнопку и посмотреть, как изменится LogCat.
Может произойти одна из двух вещей: 1) ваш проект может запуститься и работать, как Вы того ожидаете. В этом случае примите мои поздравления. 2) Возникнет ошибка, которая в LogCat отобразиться как «Could not execute method of activity.» Ничего страшного. Обычно Eclipse сконфигурирован так, что при запуске проекта автоматически происходит его перекомпиляция. В случае, если эта опция отключена, то нужно вручную заставить Eclips перекомпилировать проект. Для этого перед запуском нужно вызвать менюProject->Clean from the Eclipse toolbar.
Шаг 8: Как вернуть объект из нативной функции
Следующий пример демонстрирует возможность нативных функций возвращать объекты, например String. Добавьте код в файл native.c
С помощью команды malloc мы создали буфер, куда затем с помощью sprintf поместили строку. Чтобы функция возвращала корректный результат, мы использовали JNI helper функцию NewStringUTF(), которая фактически создает Java объект на основании C строки. После этого мы очистили память с помощью команды free().
Для успешной компиляции проекта необходимо в native.c подключить заголовочный файл stdio.h. В классе Activity нужно также объявить новую функцию:
после этого с функцией getString можно работать, например следующим образом:
Замечания
Android NDK для своей работы требует Android SDK 1.5. С помощью NDK можно получить доступ ко многим API, например к OpenGL ES.
Нативный код компилируется в машинный код, соответствующий архитектуре процессора, и поскольку на разных телефонах используются процессоры разной архитектуры, у Вас может возникнуть проблемы с переносимостью программы. По умолчанию NDK производит компиляцию для ARMv5TE. Когда Вы запускаете свое приложение на эмуляторе, а не на реальном устройстве, этот машинный код выполняется не напрямую, а через еще один эмулятор процессора.
Заключение
Ну вот собственно и все. Думаю теперь вам понятно, как работать с нативным кодом. Во многих случаях его применение оправдано, однако бездумное применеие нативного кода в своих проектах может оказаться губительным.
Источник
Gamedev suffering
Блог о разработке игр и серверных технологиях
Основы Android NDK: работа с C/C++ кодом
Использование нативного кода, написанного на C или С++ — это тема, которую многие разработчики не затрагивают вовсе. Но порой использование C++ в приложениях намного упрощает/ускоряет разработку. В этой статье будут рассмотрены основные принципы работы с native кодом.
Предварительная настройка
Если у вас ещё не настроен Eclipse, то читаем как настроить Eclipse для работы с Android. Только помимо того, что в статье сказано, при установке ещё необходимо выбрать и установить NDK плагин.
Так же вам необходимо установить CDT для Eclipse. Под Виндой вам вроде как ещё понадобиться установить Cygwin.
Теперь необходимо создать проект и прописать пути.
- Создать Android Application.
- Eclipse -> Window -> Preferences -> Android -> set path to SDK
- Eclipse -> Window -> Preferences -> Android -> NDK -> set path to the NDK
- Нажмите правой кнопкой мыши на проект и выберите Android Tools -> Add native support
В проекте будет создана папка jni, где вы должны размещать файлы с C++ кодом. В ранних версиях был баг, когда Eclipse не мог верно настроить пути до некоторых хэдеров из NDK. В последней версии всё нормально. Просто очистите проект (Clean project), а затем перестройте его (Build project).
Зачем нужен NDK?
Думаю, необходимо предварительно объяснить, когда вообще стоит (и стоит ли?) использовать ndk. Многие советуют использовать C++, когда требуются какие-то большие/сложные вычисления. Что значит сложно? =/ В общем, лучше назову конкретные случаи, когда использование NDK оправдано:
- Работа с OpenGL ES. Думаю, большинство тех, кто использует NDK, юзают его как раз для написания игр.
- Использование кросс-платформенных движков, вроде кокоса.
- Самый очевидный случай — это когда вам надо использовать уже написанный на C++ код. За десятилетия на C++ уже куча всего написано. Зачем переписывать такие вещи на Java, если можно просто использовать эти Open Source наработки. Да и не всё можно переписать, думаю тот же openCV бессмысленно бы было переписывать, в том время когда можно просто подключить готовые исходники.
Возможности NDK огромны. Вы можете из Java вызывать C++ методы. В то же время, вам ничто не машет вызывать Java методы из C++. Даже есть возможность создавать приложение практически без использования Java, используя NativeActivity (API 9 и выше).
Java. Путешествие в Native (или туда и обратно).
Да простит меня профессор за упоминание его работы (: И так, рассмотреть всё в рамках одной статьи невозможно. Поэтому, для начала реализуем лишь вызов native методов из Java.
Перечислю кратко основные моменты при работе с native:
- Создание файлов с C++ кодом.
- Определение C++ методов для экспорта.
- Создание .mk файлов.
- Генерация библиотеки.
- Подключение библиотеки в Java и вызов C++ методов.
Создание файлов с C++ кодом
В native определим всего 3 метода: передача строки, изменение строки, получение строки.
Создадим для начала файл def.h, подключим пару нужных файлов и определим методы для вывода в консоль.
Создадим файл MyNative.h и определим в нём спецификации методов для экспорта, чтоб вызывать их из Java кода потом.
Теперь все три метода можно вызвать из Java кода. Я этот код ручками писал. Но можно заюзать javah, которая будет сама генерить эти заголовки. extern «C» нужен, чтобы компилятор C++ не менял имена объявленных функций.
Стоит немного сказать про наименование методов. Java_ — обязательный префикс. ru_suvitruf_androidndk, так как у нас пакет ru.suvitruf.androidndk, ну а дальше наименование класса и метода на стороне Java. В каждой функции в качестве аргумента имеется JNIEnv* — интерфейс для работы с Java, при помощи него можно вызывать Java-методы, создавать Java-объекты. Второй обязательный параметр — jobject или j class — в зависимости от того, является ли метод статическим. Если метод статический, то аргумент будет типа jclass (ссылка на класс объекта, в котором объявлен метод), если не статический — jobject — ссылка на объект, у которого был вызван метод.
Ну и создадим MyNative.cpp с реализацией методов.
Работа с Application.mk
В этом файле описаны глобальные настройки для сборки либы.
Работа с Android.mk
Здесь указываем параметры/настройки по линковке и прочее, чтобы собрать либу.
В Android.mk вообще есть не мало всяких флагов и прочего. Можно добавлять в сборку уже готовые библиотеки и т.д. В следующих статьях напишу, как это делается.
После того, как вы создали C++ файлы и .mk сделали, можно забилдить проект, тогда в папке obj появится библиотека libAndroidNDK.so.
Подключение библиотеки в Java и вызов C++ методов.
Теперь остаётся только написать Java код. Сделаем простенькое приложение. Разместим поле для ввода текста, три кнопки (передача текста в native, изменение текста в native и возврат изменённой строки из native) и поле для нового текста, который получили из native кода.
Для того, чтобы использовать native методы создадим класс AndroidNDK.
Этот код выполнит загрузку нашей библиотеки, в которой реализованы методы. Обратите ещё раз внимание на этот класс и методы и вспомните наименование методов при экспорте в native коде: Java_ru_suvitruf_androidndk_AndroidNDK_ChangeString.
Java код по обработке нажатий на кнопки писать не буду, ибо это тривиальная задача. В любом случае, если понадобиться, можете посмотреть в исходниках к статье. В логе будет вот что:
Источник