Интеграция работы с нативным кодом на С/С++ для android в Eclipce (на примере, под Ubuntu). – часть 1
10/06/2011 Комментарии (7)
Создание проекта.
1)Необходимо добавить путь к директории с ndk в переменные среды, без этого все дальнейшее бесполезно.
2)Для создания андроид проекта с нативным кодом на С и С++ необходимо учесть несколько важных следующих замечаний (в качестве рекомендаций, можно и без них, но будет сложнее):
Расположение папки workspace для Eclipce должно быть таким, чтобы ndk имел права записи в эту папку и мог изменять свойства файлов расположенных в этой папке. То есть например чтобы папка с ndk и папка workspace находились в домашней директории пользователя, а не на смонтированном носителе.
Крайне желательно чтобы пути к SDK, NDK и проекту содержали только латинские символы без пробелов.
Версия ndk желательна выше 5. В этом случае вы без особого труда сможете использовать stdlib
В случае если Вы собираетесь отлаживать нативный код:
Target SDK версия для проекта должна быть не меньше 9
android:minSdkVersion="9"
В AndroidManifest.xml должен быть установлен флаг
android:debuggable="true"
3)Необходимо установить CDT(C and C++ Development Tools) для Eclipce. Help->Install New Software выбираем репозиторий Вашей версии Eclipce(например Helios – http://download.eclipse.org/releases/helios) в ней Programming Languages и в ней C and C++ Development Tools.
4) Следующим шагом нам необходимо сконвертировать Ваш уже созданый андроид проект в совместный проект Java и C++. Нажимаем на проекте правой кнопкой New->Other (или Ctrl+n) и в открывшемся окне выбираем Convert to C/C++ Project жмем Next
на втором шаге выбираем Makefile project->–Other Toolchain–
Жмем Finish и в консоли Eclipce видим ошибку: «**** Build of configuration Default for project NativeExample **** make all make: *** Нет правила для сборки цели `all’. Останов.»
Все правильно — среда не видит ни правил сборки нативного кода ни самого кода.
5)Работа с JNI: Создадим класс- обертку для вызова наших нативных функций.
package com.example;
public class NativeLib {
static{
System.loadLibrary("native_lab");
}
public native String function(byte[] string);
}
Создаем папке проекта папку jni. В ней будет находится весь код на С и С++ и правила сборки. Переходим в деррикторию bin нашего проекта и выполняем из терминала следующую команду javah -jni com.example.NativeLib, которая генерирует заголовочный файл вызова Ваших нативных функций для С в соответствии с правилами JNI.
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_NativeLib */
#ifndef _Included_com_example_NativeLib
#define _Included_com_example_NativeLib
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_NativeLib
* Method: function
* Signature: ([B)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_NativeLib_function
(JNIEnv *, jobject, jbyteArray);
#ifdef __cplusplus
}
#endif
#endif
Переносим сгенерированный h файл в директорию jni. Осталось добавить только реализацию на С нашей функции в новом файле (например native.cpp):
#include <cstdlib>
#include "android_log.h"
#include "com_example_NativeLib.h"
jstring JNICALL Java_com_example_NativeLib_function
(JNIEnv * env, jobject obj, jbyteArray string){
// get "string" from JVM
const size_t STRING_LENGTH = env->GetArrayLength(string);
char * buffer = new char[STRING_LENGTH];
env->GetByteArrayRegion(string, 0, STRING_LENGTH, (jbyte*) buffer);
env->ReleaseByteArrayElements(string, (jbyte*) buffer, 0);
LOGI(buffer);
jstring result = env->NewStringUTF("done");
return result;
}
6)Создаем правила сборки С/С++ библиотеки, для этого необходимо создать два мейкфайла Application.mk Android.mk в папке jni. Первый отвечает за общую сборку, второй за сборку модулей.
Application.mk:
# как будет оптимизироватся библиотека #APP_OPTIM := debug # подключение stllib #only if you platform upper then 2.2 #APP_STL :=gnustl_static # platform 1.6 APP_STL :=stlport_static # библиотека которую собираем APP_MODULES := native_lab
Android.mk:
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) # библиотека которую собираем LOCAL_MODULE := native_lab # исходные файлы через пробел LOCAL_SRC_FILES := native.cpp # библиотека для работы с логом андроида LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY)
7)Пишем в лог андроида. Для удобства создадим заголовочный файл android_log.h следующего вида:
#include <android/log.h> #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "NativeExample native",__VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "NativeExample native",__VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO , "NativeExample native",__VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN , "NativeExample native",__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "NativeExample native",__VA_ARGS__)
Пример использования виден выше в native.cpp.
Продолжение следует…



А root для отладки нативного кода на телефоне нужен?
в третей части ответил
А куда надо добавить jni.h, чтобы эклипс не подсвечивал его? Вроде и без него все собирается, но все же как-то в глаза бросается.
мануал отличный, сэкономил много времени, автору спасибо)
В глаза он не бросается
jni.h – это описание типов данных виртуальной машины java для С/С++, поэтому если вы его не пропишите, то код для передачи данных в JVM у Вас не заработает – так что не советую
А что означает, когда gdb говорит, что моя функция not defined? Ну, и соответственно, в дебаг не перекидывает тоже.
Надо код смотреть, скорее всего – или пакет забыли указать или синтаксическая ошибка в имени. Больше на вскидку пока ничего не приходит.
Вообще, я название функции скопировал из полученного h-файла. Так же, библиотека подгружается, и до некоторого момента исполняется, по крайней мере, я вижу то, что пишется в лог из той функции.