【Android】纯C/C++编写Android应用程序

标签:
androidcjni |
分类: Android |
Android平台已经开放纯C/C++编写的App了,不过必须在Android 2.2或更高的固件上才能运行。
在NDK的Samples目录中,有一个名为native-activity的例子,这个例子就是纯C/C++编写的App。这个例子是不包含任何Java代码的。
先来看AndroidManifest.xml
<?xmlversion= "1.0"encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.native_activity"
android:versionCode="1"
android:versionName="1.0">
android:minSdkVersion="9"/> <uses-sdk
<application android:hasCode="false"
android:label="@string/app_name">
<activity android:name="android.app.NativeActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name">
<meta-data android:name="android.app.lib_name"
android:value="native-activity"/>
<intent-filter> android:name="android.intent.action.MAIN"/> <action
android:name="android.intent.category.LAUNCHER"/> <category
</intent-filter> </activity> </manifest> </application>
需要注意的是:
1)minSdkVersion>=9
2)在application标签中,增加属性“hasCode=false”,表示不需要Java代码
3)Activity的名称为固定的“android.app.NativeActivity”
4)还有meta-data的配置,也是固定的。
再来看一下Android.mk的配置
LOCAL_PATH:= $(call my-dir)
include$(CLEAR_VARS)
LOCAL_MODULE:= native-activity
LOCAL_SRC_FILES:= main.c
LOCAL_LDLIBS:= -llog -landroid -lEGL -lGLESv1_CM
LOCAL_STATIC_LIBRARIES:= android_native_app_glue
include$(BUILD_SHARED_LIBRARY)
$(callimport-module,android/native_app_glue)
需要注意的是:
1)模块名称为“native-activity”,这个也是固定的
2)由于C/C++是通过OpenGLES来进行画面渲染的,所以需要引入GLES库
3)需要引入静态库“android_native_app_glue”
4)最后需要引入另一个mk模块,“android/native_app_glue”
再来看看C++代码 main.c
#include<EGL/egl.h> 这里JNI目前提供的支持,不是很多,只有GL家族作为显示系统了//
#include<GLES/gl.h> #include<android/sensor.h> 感应器的支持//
#include<android/log.h> #include<android_native_app_glue.h> 这里提示大家,c程序必须从main开始,这里必须包含这个,经过改进的伪入口点了。//
//定义日志输出
#defineLOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
#defineLOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
structsaved_state {
float angle;
int32_t x;
int32_t y;
};
structengine {
struct android_app *app;
ASensorManager *sensorManager;
const ASensor *accelerometerSensor;
ASensorEventQueue *sensorEventQueue;
int animating;
EGLDisplay display;
EGLSurface surface;
EGLContext context;
int32_t width;
int32_t height;
struct saved_state state;
};
//初始化OpenGLES
staticint engine_init_display(structengine *engine) {
const EGLint attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_NONE
};
EGLint w, h, dummy, format;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
context = eglCreateContext(display, config, NULL, NULL);
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
LOGW("Unable to );eglMakeCurrent"
return -1;
}
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
engine->display = display;
engine->context = context;
engine->surface = surface;
engine->width = w;
engine->height = h;
engine->state.angle = 0;
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glDisable(GL_DEPTH_TEST);
return 0;
}
staticvoid engine_draw_frame(structengine *engine) {
if (engine->display == NULL) {
// No display. return;
}
glClearColor(((float) engine->state.x) / engine->width, engine->state.angle,
((float) engine->state.y) / engine->height, 1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(engine->display, engine->surface);
}
staticvoid engine_term_display(structengine *engine) {
if (engine->display != EGL_NO_DISPLAY) {
eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (engine->context != EGL_NO_CONTEXT) {
eglDestroyContext(engine->display, engine->context);
}
if (engine->surface != EGL_NO_SURFACE) {
eglDestroySurface(engine->display, engine->surface);
}
eglTerminate(engine->display);
}
engine->animating = 0;
engine->display = EGL_NO_DISPLAY;
engine->context = EGL_NO_CONTEXT;
engine->surface = EGL_NO_SURFACE;
}
staticint32_t engine_handle_input(struct android_app *app, AInputEvent *event) {
struct engine *engine = (struct engine *) app->userData;
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
engine->animating = 1;
engine->state.x = AMotionEvent_getX(event, 0);
engine->state.y = AMotionEvent_getY(event, 0);
return 1;
}
return 0;
}
staticvoid engine_handle_cmd(structandroid_app *app, int32_t cmd) {
struct engine *engine = (struct engine *) app->userData;
switch (cmd) {
case APP_CMD_SAVE_STATE:
engine->app->savedState = malloc(sizeof(struct saved_state));
*((struct saved_state *) engine->app->savedState) = engine->state;
engine->app->savedStateSize = sizeof(struct saved_state);
break;
case APP_CMD_INIT_WINDOW:
if (engine->app->window != NULL) {
engine_init_display(engine);