加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

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

(2012-05-17 10:20:06)
标签:

android

c

jni

分类: Android

 Android平台已经开放纯C/C++编写的App了,不过必须在Android 2.2或更高的固件上才能运行。

 在NDK的Samples目录中,有一个名为native-activity的例子,这个例子就是纯C/C++编写的App。这个例子是不包含任何Java代码的。

 先来看AndroidManifest.xml


<?xml version="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">

    <uses-sdk android:minSdkVersion="9"/>

    <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>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>
需要注意的是:
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)
$(call import-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开始,这里必须包含这个,经过改进的伪入口点了。

//定义日志输出
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO"native-activity"__VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN"native-activity"__VA_ARGS__))

struct saved_state {
    float angle;
    int32_t x;
    int32_t y;
};

struct engine {
    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
static int engine_init_display(struct engine *engine) {
    const EGLint attribs[] {
            EGL_SURFACE_TYPEEGL_WINDOW_BIT,
            EGL_BLUE_SIZE8,
            EGL_GREEN_SIZE8,
            EGL_RED_SIZE8,
            EGL_NONE
    };

    EGLint whdummyformat;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display00);
    eglChooseConfig(displayattribs&config1&numConfigs);
    eglGetConfigAttrib(displayconfigEGL_NATIVE_VISUAL_ID&format);

    ANativeWindow_setBuffersGeometry(engine->app->window00format);

    surface eglCreateWindowSurface(displayconfigengine->app->windowNULL);
    context eglCreateContext(displayconfigNULLNULL);

    if (eglMakeCurrent(displaysurfacesurfacecontext== EGL_FALSE{
        LOGW("Unable to eglMakeCurrent");
        return -1;
    }

    eglQuerySurface(displaysurfaceEGL_WIDTH&w);
    eglQuerySurface(displaysurfaceEGL_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_HINTGL_FASTEST);
    glEnable(GL_CULL_FACE);
    glShadeModel(GL_SMOOTH);
    glDisable(GL_DEPTH_TEST);
    return 0;
}

static void engine_draw_frame(struct engine *engine) {
    if (engine->display == NULL{
        // No display.
        return;
    }

    glClearColor(((floatengine->state.xengine->widthengine->state.angle,
                 ((floatengine->state.yengine->height1);

    glClear(GL_COLOR_BUFFER_BIT);
    eglSwapBuffers(engine->displayengine->surface);
}

static void engine_term_display(struct engine *engine) {

    if (engine->display != EGL_NO_DISPLAY{
        eglMakeCurrent(engine->displayEGL_NO_SURFACEEGL_NO_SURFACEEGL_NO_CONTEXT);

        if (engine->context != EGL_NO_CONTEXT{
            eglDestroyContext(engine->displayengine->context);
        }

        if (engine->surface != EGL_NO_SURFACE{
            eglDestroySurface(engine->displayengine->surface);
        }

        eglTerminate(engine->display);
    }

    engine->animating 0;
    engine->display EGL_NO_DISPLAY;
    engine->context EGL_NO_CONTEXT;
    engine->surface EGL_NO_SURFACE;
}

static int32_t engine_handle_input(struct android_app *appAInputEvent *event) {
    struct engine *engine (struct engine *) app->userData;
    if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION{
        engine->animating 1;
        engine->state.AMotionEvent_getX(event0);
        engine->state.AMotionEvent_getY(event0);
        return 1;
    }

    return 0;
}

static void engine_handle_cmd(struct android_app *appint32_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->savedStateengine->state;
            engine->app->savedStateSize sizeof(struct saved_state);
            break;

        case APP_CMD_INIT_WINDOW:
            if (engine->app->window != NULL{
                engine_init_display(engine);
                engine_draw_frame(engine);
            }
            break;

        case APP_CMD_TERM_WINDOW:
            engine_term_display(engine);
            break;

        case APP_CMD_GAINED_FOCUS:
            if (engine->accelerometerSensor != NULL{
                ASensorEventQueue_enableSensor(engine->sensorEventQueueengine->accelerometerSensor);
                ASensorEventQueue_setEventRate(engine->sensorEventQueueengine->accelerometerSensor(1000L 601000);
            }
            break;

        case APP_CMD_LOST_FOCUS:
            if (engine->accelerometerSensor != NULL{
                ASensorEventQueue_disableSensor(engine->sensorEventQueueengine->accelerometerSensor);
            }

            engine->animating 0;
            engine_draw_frame(engine);
            break;
    }
}

&ltb>/</b>**
 这里是伪main入口点,所有的初始化的确从这里开始
 android_native_app_glue 库调用以下函数,向其传递预定义的状态结构。 它还起包装器作用,能够简化 NativeActivity 回调的处理。 
 @param state 
 */
void android_main(struct android_app *state) {

    struct engine engine;
    app_dummy();
    memset(&engine0sizeof(engine));
    state->userData &engine;
    state->onAppCmd engine_handle_cmd;
    state->onInputEvent engine_handle_input;

    engine.app state;
    engine.sensorManager ASensorManager_getInstance();
    engine.accelerometerSensor ASensorManager_getDefaultSensor(engine.sensorManagerASENSOR_TYPE_ACCELEROMETER);
    engine.sensorEventQueue ASensorManager_createEventQueue(engine.sensorManagerstate->looperLOOPER_ID_USERNULLNULL);

    if (state->savedState != NULL{
        // We are starting with previous saved state; restore from it.
        engine.state *(struct saved_state *) state->savedState;
    }

    // loop waiting for stuff to do.
    while (1{
        // Read all pending events.
        int ident;
        int events;
        struct android_poll_source *source;

        // If not animating, we will block forever waiting for events.
        // If animating, we loop until all events are read, then continue
        // to draw the next frame of animation.
        while ((ident ALooper_pollAll(engine.animating -1NULL&events(void **) &source)) >= 0{
            // Process this event.
            if (source != NULL{
                source->process(statesource);
            }

            // If sensor has data, process it now.
            if (ident == LOOPER_ID_USER{
                if (engine.accelerometerSensor != NULL{
                    ASensorEvent event;
                    while (ASensorEventQueue_getEvents(engine.sensorEventQueue&event10{
                        LOGI("accelerometer: x=%f y=%f z=%f",
                             event.acceleration.x,
                             event.acceleration.y,
                             event.acceleration.z);
                    }
                }
            }

            // Check if we are exiting.
            if (state->destroyRequested != 0{
                engine_term_display(&engine);
                return;
            }
        }


        if (engine.animating{
            // Done with events; draw next animation frame.
            engine.state.angle += .01f;
            if (engine.state.angle 1{
                engine.state.angle 0;
            }

            // Drawing is throttled to the screen update rate, so there
            // is no need to do timing here.
            engine_draw_frame(&engine);
        }
    }
}

运行程序后,显示效果如下:
程序运行时,可以看到颜色的变化,点击屏幕的时候,会暂停



0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有