最新的 Android 2.3 无需 Java 就可以开发应用,详情请看 http://www.oschina.net/news/14732/android-ndk-updates-no-more-java-required。
这里是官方给的例子程序 ,来自:http://developer.android.com/reference/android/app/NativeActivity.html
[代码] AndroidManifest.xml
01
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
02
package="com.example.native_activity"
03
android:versionCode="1"
04
android:versionName="1.0">
05
06
<!-- This is the platform API where NativeActivity was introduced. -->
07
<uses-sdk android:minSdkVersion="8" />
08
09
<!-- This .apk has no Java code itself, so set hasCode to false. -->
10
<application android:label="@string/app_name" android:hasCode="false">
11
12
<!-- Our activity is the built-in NativeActivity framework class.
13
This will take care of integrating with our NDK code. -->
14
<activity android:name="android.app.NativeActivity"
15
android:label="@string/app_name"
16
android:configChanges="orientation|keyboardHidden">
17
<!-- Tell NativeActivity the name of or .so -->
18
<meta-data android:name="android.app.lib_name"
19
android:value="native-activity" />
20
<intent-filter>
21
<action android:name="android.intent.action.MAIN" />
22
<category android:name="android.intent.category.LAUNCHER" />
23
</intent-filter>
24
</activity>
25
</application>
26
27
</manifest>
[代码] Demo.c
001
#include <jni.h>
002
#include <errno.h>
003
004
#include <EGL/egl.h>
005
#include <GLES/gl.h>
006
007
#include <android/sensor.h>
008
#include <android/log.h>
009
#include <android_native_app_glue.h>
010
011
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
012
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
013
014
/**
015
* Our saved state data.
016
*/
017
struct saved_state {
018
float angle;
019
int32_t x;
020
int32_t y;
021
};
022
023
/**
024
* Shared state for our app.
025
*/
026
struct engine {
027
struct android_app* app;
028
029
ASensorManager* sensorManager;
030
const ASensor* accelerometerSensor;
031
ASensorEventQueue* sensorEventQueue;
032
033
int animating;
034
EGLDisplay display;
035
EGLSurface surface;
036
EGLContext context;
037
int32_t width;
038
int32_t height;
039
struct saved_state state;
040
};
041
042
/**
043
* Initialize an EGL context for the current display.
044
*/
045
static int engine_init_display(struct engine* engine) {
046
// initialize OpenGL ES and EGL
047
048
/*
049
* Here specify the attributes of the desired configuration.
050
* Below, we select an EGLConfig with at least 8 bits per color
051
* component compatible with on-screen windows
052
*/
053
const EGLint attribs[] = {
054
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
055
EGL_BLUE_SIZE, 8,
056
EGL_GREEN_SIZE, 8,
057
EGL_RED_SIZE, 8,
058
EGL_NONE
059
};
060
EGLint w, h, dummy, format;
061
EGLint numConfigs;
062
EGLConfig config;
063
EGLSurface surface;
064
EGLContext context;
065
066
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
067
068
eglInitialize(display, 0, 0);
069
070
/* Here, the application chooses the configuration it desires. In this
071
* sample, we have a very simplified selection process, where we pick
072
* the first EGLConfig that matches our criteria */
073
eglChooseConfig(display, attribs, &config, 1, &numConfigs);
074
075
/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
076
* guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
077
* As soon as we picked a EGLConfig, we can safely reconfigure the
078
* ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
079
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
080
081
ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
082
083
surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
084
context = eglCreateContext(display, config, NULL, NULL);
085
086
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
087
LOGW("Unable to eglMakeCurrent");
088
return -1;
089
}
090
091
eglQuerySurface(display, surface, EGL_WIDTH, &w);
092
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
093
094
engine->display = display;
095
engine->context = context;
096
engine->surface = surface;
097
engine->width = w;
098
engine->height = h;
099
engine->state.angle = 0;
100
101
// Initialize GL state.
102
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
103
glEnable(GL_CULL_FACE);
104
glShadeModel(GL_SMOOTH);
105
glDisable(GL_DEPTH_TEST);
106
107
return 0;
108
}
109
110
/**
111
* Just the current frame in the display.
112
*/
113
static void engine_draw_frame(struct engine* engine) {
114
if (engine->display == NULL) {
115
// No display.
116
return;
117
}
118
119
// Just fill the screen with a color.
120
glClearColor(((float)engine->state.x)/engine->width, engine->state.angle,
121
((float)engine->state.y)/engine->height, 1);
122
glClear(GL_COLOR_BUFFER_BIT);
123
124
eglSwapBuffers(engine->display, engine->surface);
125
}
126
127
/**
128
* Tear down the EGL context currently associated with the display.
129
*/
130
static void engine_term_display(struct engine* engine) {
131
if (engine->display != EGL_NO_DISPLAY) {
132
eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
133
if (engine->context != EGL_NO_CONTEXT) {
134
eglDestroyContext(engine->display, engine->context);
135
}
136
if (engine->surface != EGL_NO_SURFACE) {
137
eglDestroySurface(engine->display, engine->surface);
138
}
139
eglTerminate(engine->display);
140
}
141
engine->animating = 0;
142
engine->display = EGL_NO_DISPLAY;
143
engine->context = EGL_NO_CONTEXT;
144
engine->surface = EGL_NO_SURFACE;
145
}
146
147
/**
148
* Process the next input event.
149
*/
150
static int32_t engine_handle_input(struct android_app* app, AInputEvent* event) {
151
struct engine* engine = (struct engine*)app->userData;
152
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
153
engine->animating = 1;
154
engine->state.x = AMotionEvent_getX(event, 0);
155
engine->state.y = AMotionEvent_getY(event, 0);
156
return 1;
157
}
158
return 0;
159
}
160
161
/**
162
* Process the next main command.
163
*/
164
static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
165
struct engine* engine = (struct engine*)app->userData;
166
switch (cmd) {
167
case APP_CMD_SAVE_STATE:
168
// The system has asked us to save our current state.Do so.
169
engine->app->savedState = malloc(sizeof(struct saved_state));
170
*((struct saved_state*)engine->app->savedState) = engine->state;
171
engine->app->savedStateSize = sizeof(struct saved_state);
172
break;
173
case APP_CMD_INIT_WINDOW:
174
// The window is being shown, get it ready.
175
if (engine->app->window != NULL) {
176
engine_init_display(engine);
177
engine_draw_frame(engine);
178
}
179
break;
180
case APP_CMD_TERM_WINDOW:
181
// The window is being hidden or closed, clean it up.
182
engine_term_display(engine);
183
break;
184
case APP_CMD_GAINED_FOCUS:
185
// When our app gains focus, we start monitoring the accelerometer.
186
if (engine->accelerometerSensor != NULL) {
187
ASensorEventQueue_enableSensor(engine->sensorEventQueue,
188
engine->accelerometerSensor);
189
// We'd like to get 60 events per second (in us).
190
ASensorEventQueue_setEventRate(engine->sensorEventQueue,
191
engine->accelerometerSensor, (1000L/60)*1000);
192
}
193
break;
194
case APP_CMD_LOST_FOCUS:
195
// When our app loses focus, we stop monitoring the accelerometer.
196
// This is to avoid consuming battery while not being used.
197
if (engine->accelerometerSensor != NULL) {
198
ASensorEventQueue_disableSensor(engine->sensorEventQueue,
199
engine->accelerometerSensor);
200
}
201
// Also stop animating.
202
engine->animating = 0;
203
engine_draw_frame(engine);
204
break;
205
}
206
}
207
208
/**
209
* This is the main entry point of a native application that is using
210
* android_native_app_glue.It runs in its own thread, with its own
211
* event loop for receiving input events and doing other things.
212
*/
213
void android_main(struct android_app* state) {
214
struct engine engine;
215
216
// Make sure glue isn't stripped.
217
app_dummy();
218
219
memset(&engine, 0, sizeof(engine));
220
state->userData =
221
state->onAppCmd = engine_handle_cmd;
222
state->onInputEvent = engine_handle_input;
223
engine.app = state;
224
225
// Prepare to monitor accelerometer
226
engine.sensorManager = ASensorManager_getInstance();
227
engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
228
ASENSOR_TYPE_ACCELEROMETER);
229
engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,
230
state->looper, LOOPER_ID_USER, NULL, NULL);
231
232
if (state->savedState != NULL) {
233
// We are starting with a previous saved state; restore from it.
234
engine.state = *(struct saved_state*)state->savedState;
235
}
236
237
// loop waiting for stuff to do.
238
239
while (1) {
240
// Read all pending events.
241
int ident;
242
int events;
243
struct android_poll_source* source;
244
245
// If not animating, we will block forever waiting for events.
246
// If animating, we loop until all events are read, then continue
247
// to draw the next frame of animation.
248
while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,
249
(void**)&source)) >= 0) {
250
251
// Process this event.
252
if (source != NULL) {
253
source->process(state, source);
254
}
255
256
// If a sensor has data, process it now.
257
if (ident == LOOPER_ID_USER) {
258
if (engine.accelerometerSensor != NULL) {
259
ASensorEvent event;
260
while (ASensorEventQueue_getEvents(engine.sensorEventQueue,
261
&event, 1) > 0) {
262
LOGI("accelerometer: x=%f y=%f z=%f",
263
event.acceleration.x, event.acceleration.y,
264
event.acceleration.z);
265
}
266
}
267
}
268
269
// Check if we are exiting.
270
if (state->destroyRequested != 0) {
271
engine_term_display(&engine);
272
return;
273
}
274
}
275
276
if (engine.animating) {
277
// Done with events; draw next animation frame.
278
engine.state.angle += .01f;
279
if (engine.state.angle > 1) {
280
engine.state.angle = 0;
281
}
282
283
// Drawing is throttled to the screen update rate, so there
284
// is no need to do timing here.
285
engine_draw_frame(&engine);
286
}
287
}
288
}