本文主要是介绍构建NativeActivity 没有dex 没有java代码的apk也能在手机上跑起来,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
干了几年安卓开发 ,某次经历刷新了我的世界观了
清单文件application节点设置为<application android:label="@string/app_name" android:hasCode="false">
就可以实现了。
定义application节点
<application android:label="@string/app_name" android:hasCode="false"><!-- Our activity is the built-in NativeActivity framework class.This will take care of integrating with our NDK code. --><activity android:name="android.app.NativeActivity" android:label="@string/app_name" android:configChanges="orientation|keyboardHidden"><!-- Tell NativeActivity the name of our .so --><meta-data android:name="android.app.lib_name" android:value="$(AndroidAppLibName)"/><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity></application>
完整的
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.AndroidNativeActivity" platformBuildVersionCode="21" platformBuildVersionName="5.0.1-1624448"><uses-sdk android:minSdkVersion="9" android:targetSdkVersion="21" /><application android:label="@string/app_name" android:hasCode="false" android:debuggable="true"><activity android:label="@string/app_name" android:name="android.app.NativeActivity" android:configChanges="keyboardHidden|orientation"><meta-data android:name="android.app.lib_name" android:value="AndroidNativeActivity" /><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest>
其中AndroidNativeActivity
就是libAndroidNativeActivity.so
入口函数void android_main(struct android_app* state) {
完整c代码
/** 版权所有 (C) 2010 Android 开放源码代码项目** 按照 Apache 许可 2.0 版本(称为“许可”)授予许可;* 要使用此文件,必须遵循“许可”中的说明。* 你可以从以下位置获取“许可”的副本** http://www.apache.org/licenses/LICENSE-2.0** 除非适用法律要求或书面同意,根据* “许可”分配的软件“按原样”分配,* 不提供任何形式(无论是明示还是默示)的担保和条件。* 参见“许可”了解“许可”中管理权限和* 限制的指定语言。*
*/#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "AndroidProject1.NativeActivity", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "AndroidProject1.NativeActivity", __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;
};/**
* 初始化当前显示的 EGL 上下文。
*/
static int engine_init_display(struct engine* engine) {//初始化 OpenGL ES 和 EGL/** 此处指定了所需配置的属性。*下面,我们选择与屏上窗口* 兼容的至少每个颜色有 8 个位的 EGLConfig */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, format;EGLint numConfigs;EGLConfig config;EGLSurface surface;EGLContext context;EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);eglInitialize(display, 0, 0);/*此处,应用程序选择了所需的配置。 在本*示例中,我们有非常简化的选择流程,*其中我们选取了与我们的标准匹配的第一个 EGLConfig */eglChooseConfig(display, attribs, &config, 1, &numConfigs);/* EGL_NATIVE_VISUAL_ID 是*保证会被 ANativeWindow_setBuffersGeometry() 接受的 EGLConfig 的属性。* 只要我们选取 EGLConfig,就可使用 EGL_NATIVE_VISUAL_ID 安全地重新配置* ANativeWindow 缓冲区以进行匹配。*/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;//初始化 GL 状态。glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_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) {//无显示。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);
}/**
* 关闭当前与显示关联的 EGL 上下文。
*/
static void engine_term_display(struct engine* 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;
}/**
*处理下一输入事件。
*/
static int32_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->state.x = AMotionEvent_getX(event, 0);engine->state.y = AMotionEvent_getY(event, 0);return 1;}return 0;
}/**
*处理下一主命令。
*/
static void engine_handle_cmd(struct android_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);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->sensorEventQueue,engine->accelerometerSensor);//我们想要每秒获得 60 个事件(在美国)。ASensorEventQueue_setEventRate(engine->sensorEventQueue,engine->accelerometerSensor, (1000L / 60) * 1000);}break;case APP_CMD_LOST_FOCUS://当我们的应用程序失去焦点时,我们会停止监控加速计。//这可在不使用时避免使用电池。if (engine->accelerometerSensor != NULL) {ASensorEventQueue_disableSensor(engine->sensorEventQueue,engine->accelerometerSensor);}//另外,停止动画。engine->animating = 0;engine_draw_frame(engine);break;}
}/**
* 这是使用 android_native_app_glue
* 的本地应用程序的主要入口点。它在其自己的线程中运行,具有自己的
* 事件循环用于接收输入事件并执行其他操作。
*/
void android_main(struct android_app* state) {struct engine engine;memset(&engine, 0, sizeof(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.sensorManager,ASENSOR_TYPE_ACCELEROMETER);engine.sensorEventQueue = ASensorManager_createEventQueue(engine.sensorManager,state->looper, LOOPER_ID_USER, NULL, NULL);if (state->savedState != NULL) {//我们从之前保存的状态开始;从它还原。engine.state = *(struct saved_state*)state->savedState;}engine.animating = 1;//循环等待事情以进行处理。while (1) {//读取所有挂起的事件。int ident;int events;struct android_poll_source* source;//如果没有动态效果,我们将一直阻止等待事件。//如果有动态效果,我们进行循环,直到读取所有事件,然后继续//绘制动画的下一帧。while ((ident = ALooper_pollAll(engine.animating ? 0 : -1, NULL, &events,(void**)&source)) >= 0) {//处理此事件。if (source != NULL) {source->process(state, source);}//如果传感器有数据,立即处理。if (ident == LOOPER_ID_USER) {if (engine.accelerometerSensor != NULL) {ASensorEvent event;while (ASensorEventQueue_getEvents(engine.sensorEventQueue,&event, 1) > 0) {LOGI("accelerometer: x=%f y=%f z=%f",event.acceleration.x, event.acceleration.y,event.acceleration.z);}}}//检查,我们是否存在。if (state->destroyRequested != 0) {engine_term_display(&engine);return;}}if (engine.animating) {//事件完成;绘制下一动画帧。engine.state.angle += .01f;if (engine.state.angle > 1) {engine.state.angle = 0;}//绘图被降低到屏幕更新速率,//因此,没有必要在此处计时。engine_draw_frame(&engine);}}
}
某c
/** 版权所有 (C) 2010 Android 开放源代码项目** 按照 Apache 许可 2.0 版本(称为“许可”)授予许可;* 要使用此文件,必须遵循“许可”中的说明。* 你可以从以下位置获取“许可”的副本** http://www.apache.org/licenses/LICENSE-2.0** 除非适用法律要求或书面同意,根据* “许可”分配的软件“按原样”分配,* 不提供任何形式(无论是明示还是默示)的担保和条件。* 参见“许可”了解“许可”中管理权限和* 限制的指定语言。**/#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__))/*对于调试版本,始终在此库中启用调试跟踪*/
#ifndef NDEBUG
# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__))
#else
# define LOGV(...) ((void)0)
#endifstatic void free_saved_state(struct android_app* android_app) {pthread_mutex_lock(&android_app->mutex);if (android_app->savedState != NULL) {free(android_app->savedState);android_app->savedState = NULL;android_app->savedStateSize = 0;}pthread_mutex_unlock(&android_app->mutex);
}int8_t android_app_read_cmd(struct android_app* android_app) {int8_t cmd;if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {switch (cmd) {case APP_CMD_SAVE_STATE:free_saved_state(android_app);break;}return cmd;} else {LOGE("No data on command pipe!");}return -1;
}static void print_cur_config(struct android_app* android_app) {char lang[2], country[2];AConfiguration_getLanguage(android_app->config, lang);AConfiguration_getCountry(android_app->config, country);LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d ""keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d ""modetype=%d modenight=%d",AConfiguration_getMcc(android_app->config),AConfiguration_getMnc(android_app->config),lang[0], lang[1], country[0], country[1],AConfiguration_getOrientation(android_app->config),AConfiguration_getTouchscreen(android_app->config),AConfiguration_getDensity(android_app->config),AConfiguration_getKeyboard(android_app->config),AConfiguration_getNavigation(android_app->config),AConfiguration_getKeysHidden(android_app->config),AConfiguration_getNavHidden(android_app->config),AConfiguration_getSdkVersion(android_app->config),AConfiguration_getScreenSize(android_app->config),AConfiguration_getScreenLong(android_app->config),AConfiguration_getUiModeType(android_app->config),AConfiguration_getUiModeNight(android_app->config));
}void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {switch (cmd) {case APP_CMD_INPUT_CHANGED:LOGV("APP_CMD_INPUT_CHANGED\n");pthread_mutex_lock(&android_app->mutex);if (android_app->inputQueue != NULL) {AInputQueue_detachLooper(android_app->inputQueue);}android_app->inputQueue = android_app->pendingInputQueue;if (android_app->inputQueue != NULL) {LOGV("Attaching input queue to looper");AInputQueue_attachLooper(android_app->inputQueue,android_app->looper, LOOPER_ID_INPUT, NULL,&android_app->inputPollSource);}pthread_cond_broadcast(&android_app->cond);pthread_mutex_unlock(&android_app->mutex);break;case APP_CMD_INIT_WINDOW:LOGV("APP_CMD_INIT_WINDOW\n");pthread_mutex_lock(&android_app->mutex);android_app->window = android_app->pendingWindow;pthread_cond_broadcast(&android_app->cond);pthread_mutex_unlock(&android_app->mutex);break;case APP_CMD_TERM_WINDOW:LOGV("APP_CMD_TERM_WINDOW\n");pthread_cond_broadcast(&android_app->cond);break;case APP_CMD_RESUME:case APP_CMD_START:case APP_CMD_PAUSE:case APP_CMD_STOP:LOGV("activityState=%d\n", cmd);pthread_mutex_lock(&android_app->mutex);android_app->activityState = cmd;pthread_cond_broadcast(&android_app->cond);pthread_mutex_unlock(&android_app->mutex);break;case APP_CMD_CONFIG_CHANGED:LOGV("APP_CMD_CONFIG_CHANGED\n");AConfiguration_fromAssetManager(android_app->config,android_app->activity->assetManager);print_cur_config(android_app);break;case APP_CMD_DESTROY:LOGV("APP_CMD_DESTROY\n");android_app->destroyRequested = 1;break;}
}void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {switch (cmd) {case APP_CMD_TERM_WINDOW:LOGV("APP_CMD_TERM_WINDOW\n");pthread_mutex_lock(&android_app->mutex);android_app->window = NULL;pthread_cond_broadcast(&android_app->cond);pthread_mutex_unlock(&android_app->mutex);break;case APP_CMD_SAVE_STATE:LOGV("APP_CMD_SAVE_STATE\n");pthread_mutex_lock(&android_app->mutex);android_app->stateSaved = 1;pthread_cond_broadcast(&android_app->cond);pthread_mutex_unlock(&android_app->mutex);break;case APP_CMD_RESUME:free_saved_state(android_app);break;}
}static void android_app_destroy(struct android_app* android_app) {LOGV("android_app_destroy!");free_saved_state(android_app);pthread_mutex_lock(&android_app->mutex);if (android_app->inputQueue != NULL) {AInputQueue_detachLooper(android_app->inputQueue);}AConfiguration_delete(android_app->config);android_app->destroyed = 1;pthread_cond_broadcast(&android_app->cond);pthread_mutex_unlock(&android_app->mutex);//此后,无法接触 android_app 项目。
}static void process_input(struct android_app* app, struct android_poll_source* source) {AInputEvent* event = NULL;while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {LOGV("New input event: type=%d\n", AInputEvent_getType(event));if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {continue;}int32_t handled = 0;if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);AInputQueue_finishEvent(app->inputQueue, event, handled);}
}static void process_cmd(struct android_app* app, struct android_poll_source* source) {int8_t cmd = android_app_read_cmd(app);android_app_pre_exec_cmd(app, cmd);if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);android_app_post_exec_cmd(app, cmd);
}static void* android_app_entry(void* param) {struct android_app* android_app = (struct android_app*)param;android_app->config = AConfiguration_new();AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);print_cur_config(android_app);android_app->cmdPollSource.id = LOOPER_ID_MAIN;android_app->cmdPollSource.app = android_app;android_app->cmdPollSource.process = process_cmd;android_app->inputPollSource.id = LOOPER_ID_INPUT;android_app->inputPollSource.app = android_app;android_app->inputPollSource.process = process_input;ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,&android_app->cmdPollSource);android_app->looper = looper;pthread_mutex_lock(&android_app->mutex);android_app->running = 1;pthread_cond_broadcast(&android_app->cond);pthread_mutex_unlock(&android_app->mutex);android_main(android_app);android_app_destroy(android_app);return NULL;
}// --------------------------------------------------------------------
//本地活动交互(从主线程调用)
// --------------------------------------------------------------------static struct android_app* android_app_create(ANativeActivity* activity,void* savedState, size_t savedStateSize) {struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));memset(android_app, 0, sizeof(struct android_app));android_app->activity = activity;pthread_mutex_init(&android_app->mutex, NULL);pthread_cond_init(&android_app->cond, NULL);if (savedState != NULL) {android_app->savedState = malloc(savedStateSize);android_app->savedStateSize = savedStateSize;memcpy(android_app->savedState, savedState, savedStateSize);}int msgpipe[2];if (pipe(msgpipe)) {LOGE("could not create pipe: %s", strerror(errno));return NULL;}android_app->msgread = msgpipe[0];android_app->msgwrite = msgpipe[1];pthread_attr_t attr; pthread_attr_init(&attr);pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);pthread_create(&android_app->thread, &attr, android_app_entry, android_app);//等待线程启动。pthread_mutex_lock(&android_app->mutex);while (!android_app->running) {pthread_cond_wait(&android_app->cond, &android_app->mutex);}pthread_mutex_unlock(&android_app->mutex);return android_app;
}static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {LOGE("Failure writing android_app cmd: %s\n", strerror(errno));}
}static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {pthread_mutex_lock(&android_app->mutex);android_app->pendingInputQueue = inputQueue;android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);while (android_app->inputQueue != android_app->pendingInputQueue) {pthread_cond_wait(&android_app->cond, &android_app->mutex);}pthread_mutex_unlock(&android_app->mutex);
}static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {pthread_mutex_lock(&android_app->mutex);if (android_app->pendingWindow != NULL) {android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);}android_app->pendingWindow = window;if (window != NULL) {android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);}while (android_app->window != android_app->pendingWindow) {pthread_cond_wait(&android_app->cond, &android_app->mutex);}pthread_mutex_unlock(&android_app->mutex);
}static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {pthread_mutex_lock(&android_app->mutex);android_app_write_cmd(android_app, cmd);while (android_app->activityState != cmd) {pthread_cond_wait(&android_app->cond, &android_app->mutex);}pthread_mutex_unlock(&android_app->mutex);
}static void android_app_free(struct android_app* android_app) {pthread_mutex_lock(&android_app->mutex);android_app_write_cmd(android_app, APP_CMD_DESTROY);while (!android_app->destroyed) {pthread_cond_wait(&android_app->cond, &android_app->mutex);}pthread_mutex_unlock(&android_app->mutex);close(android_app->msgread);close(android_app->msgwrite);pthread_cond_destroy(&android_app->cond);pthread_mutex_destroy(&android_app->mutex);free(android_app);
}static void onDestroy(ANativeActivity* activity) {LOGV("Destroy: %p\n", activity);android_app_free((struct android_app*)activity->instance);
}static void onStart(ANativeActivity* activity) {LOGV("Start: %p\n", activity);android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
}static void onResume(ANativeActivity* activity) {LOGV("Resume: %p\n", activity);android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
}static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {struct android_app* android_app = (struct android_app*)activity->instance;void* savedState = NULL;LOGV("SaveInstanceState: %p\n", activity);pthread_mutex_lock(&android_app->mutex);android_app->stateSaved = 0;android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);while (!android_app->stateSaved) {pthread_cond_wait(&android_app->cond, &android_app->mutex);}if (android_app->savedState != NULL) {savedState = android_app->savedState;*outLen = android_app->savedStateSize;android_app->savedState = NULL;android_app->savedStateSize = 0;}pthread_mutex_unlock(&android_app->mutex);return savedState;
}static void onPause(ANativeActivity* activity) {LOGV("Pause: %p\n", activity);android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
}static void onStop(ANativeActivity* activity) {LOGV("Stop: %p\n", activity);android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
}static void onConfigurationChanged(ANativeActivity* activity) {struct android_app* android_app = (struct android_app*)activity->instance;LOGV("ConfigurationChanged: %p\n", activity);android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
}static void onLowMemory(ANativeActivity* activity) {struct android_app* android_app = (struct android_app*)activity->instance;LOGV("LowMemory: %p\n", activity);android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
}static void onWindowFocusChanged(ANativeActivity* activity, int focused) {LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);android_app_write_cmd((struct android_app*)activity->instance,focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
}static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {LOGV("NativeWindowCreated: %p -- %p\n", activity, window);android_app_set_window((struct android_app*)activity->instance, window);
}static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);android_app_set_window((struct android_app*)activity->instance, NULL);
}static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {LOGV("InputQueueCreated: %p -- %p\n", activity, queue);android_app_set_input((struct android_app*)activity->instance, queue);
}static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);android_app_set_input((struct android_app*)activity->instance, NULL);
}void ANativeActivity_onCreate(ANativeActivity* activity,void* savedState, size_t savedStateSize) {LOGV("Creating: %p\n", activity);activity->callbacks->onDestroy = onDestroy;activity->callbacks->onStart = onStart;activity->callbacks->onResume = onResume;activity->callbacks->onSaveInstanceState = onSaveInstanceState;activity->callbacks->onPause = onPause;activity->callbacks->onStop = onStop;activity->callbacks->onConfigurationChanged = onConfigurationChanged;activity->callbacks->onLowMemory = onLowMemory;activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;activity->callbacks->onInputQueueCreated = onInputQueueCreated;activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;activity->instance = android_app_create(activity, savedState, savedStateSize);
}
某h
/** 版权所有 (C) 2010 Android 开放源代码项目** 按照 Apache 许可 2.0 版本(称为“许可”)授予许可;* 要使用此文件,必须遵循“许可”中的说明。* 你可以从以下位置获取“许可”的副本** http://www.apache.org/licenses/LICENSE-2.0** 除非适用法律要求或书面同意,根据* “许可”分配的软件“按原样”分配,* 不提供任何形式(无论是明示还是默示)的担保和条件。* 参见“许可”了解“许可”中管理权限和* 限制的指定语言。**/#ifndef _ANDROID_NATIVE_APP_GLUE_H
#define _ANDROID_NATIVE_APP_GLUE_H#include <poll.h>
#include <pthread.h>
#include <sched.h>#include <android/configuration.h>
#include <android/looper.h>
#include <android/native_activity.h>#ifdef __cplusplus
extern "C" {
#endif/*** 由 <android/native_activity.h> 提供的本地活动界面* 基于一组应用程序提供的回调,* 发生某些事件时,活动的主线程将调用这些回调。** 这意味着,这些回调中的每个回调不应堵塞,否则会有系统* 强制关闭应用程序的风险。此编程* 模型直接、轻型,但是有约束。**“threaded_native_app”静态库用于提供不同的* 执行模型,其中应用程序可在其他* 线程中实施它自己的主要事件循环。其工作方式如下:** 1/ 应用程序必须提供名为“android_main()”的函数,* 当在不同于活动的主线程的* 新线程中创建活动时,将调用该函数。** 2/ android_main() 接收到指向有效的“android_app”结构的指针,* 该结构包含对其他重要对象(例如,* 应用程序正在其中运行的 ANativeActivity 对象实例)的引用。** 3/“android_app”对象保留已经* 在侦听以下两项重大事件的 ALooper 实例:** - 活动生命周期事件(例如“暂停”、“恢复”)。参见下文的 APP_CMD_XXX* 声明。** - 来自附加到活动的 AInputQueue 的输入事件。** 每个事件都对应于一个由值分别为 LOOPER_ID_MAIN 和 LOOPER_ID_INPUT 的* ALooper_pollOnce 返回的 ALooper* 标识符。** 你的应用程序可使用相同的 ALooper 侦听其他* 文件描述符。它们可基于回调或带有以* LOOPER_ID_USER 开头的返回标识符。** 4/ 无论在何时收到 LOOPER_ID_MAIN 或 LOOPER_ID_INPUT 事件,* 返回的数据都将指向 android_poll_source 结构。你* 可对它调用 process() 函数,并填入要调用的 android_app->onAppCmd* 和 android_app->onInputEvent,以处理你自己的* 事件。** 另外,你还可调用低级别函数直接* 读取和处理数据... 查看附加的 process_cmd() 和 process_input()* 实现,以了解如何进行此操作。** 查看包含完整用例的 NDK 中提供的名为 *“native-activity”的示例。另请查看 NativeActivity 的 JavaDoc。*/struct android_app;/*** 当该源的数据准备就绪后,* 与 ALooper fd 相关的数据将作为“outData”返回。*/
struct android_poll_source {//此源的标识符。 可能是 LOOPER_ID_MAIN 或// LOOPER_ID_INPUT。int32_t id;//此 ident 关联的 android_app。struct android_app* app;//要从此源调用以执行标准数据处理的//函数。void (*process)(struct android_app* app, struct android_poll_source* source);
};/*** 这是针对线程化应用程序的标准粘附代码的* 界面。 在此模型中,应用程序的代码在* 其自己的线程中运行,该线程独立于进程的主线程。* 此线程不必与 Java* VM 关联,尽管它们需要相互关联以使 JNI 调用任何* Java 对象。*/
struct android_app {//如果愿意,应用程序可将指向其自己的状态对象的指针//放在这里。void* userData;//在此处填充用于处理主应用命令(APP_CMD_*)的函数void (*onAppCmd)(struct android_app* app, int32_t cmd);//在此处填充用于处理输入事件的函数。此时,//事件已经提前分派,一经返回将立即//完成。如果你已处理该事件,则返回 1,对于任何默认//分派返回 0。int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);//此应用在其中运行的 ANativeActivity 对象实例。ANativeActivity* activity;//正在运行的应用采用的当前配置。AConfiguration* config;//这是创建时提供的上一个实例的已保存状态。//如果没有状态,则为 NULL。你可根据需要使用;//内存将保持可用,直到你为 APP_CMD_RESUME 调用 android_app_exec_cmd(),//此时,将释放内存,并且 savedState 设置为 NULL。//仅当处理 APP_CMD_SAVE_STATE 时才可更改这些变量,//此时,这些变量将初始化为 NULL,并且你能够为你的//状态分配内存并将信息放在此处。这种情况下,将稍后//为你释放内存。void* savedState;size_t savedStateSize;//与应用的线程关联的 ALooper。ALooper* looper;//不为 NULL 时,这是一个输入队列,应用将通过它//接收用户输入序列。AInputQueue* inputQueue;//不为 NIULL 时,这是应用可在其中进行绘制的窗口界面。ANativeWindow* window;//窗口的当前内容矩形;这是//应放置窗口的内容以供用户查看的区域。ARect contentRect;//应用的活动的当前状态。可能是 APP_CMD_START、//APP_CMD_RESUME、APP_CMD_PAUSE 或 APP_CMD_STOP;请参见下文。int activityState;//应用程序的 NativeActivity 被破坏并且正在//等待应用线程完成时,这为非零值。int destroyRequested;// -------------------------------------------------//以下是粘附代码的“私有”实现。pthread_mutex_t mutex;pthread_cond_t cond;int msgread;int msgwrite;pthread_t thread;struct android_poll_source cmdPollSource;struct android_poll_source inputPollSource;int running;int stateSaved;int destroyed;int redrawNeeded;AInputQueue* pendingInputQueue;ANativeWindow* pendingWindow;ARect pendingContentRect;
};enum {/***命令的 Looper 数据 ID,其中的命令来自应用的主线程,该数据 ID 作为一个标识符从*ALooper_pollOnce() 返回。 此* 标识符的数据是指向 android_poll_source structure 结构的指针。* 可使用 android_app_read_cmd()* 和 android_app_exec_cmd() 检索和处理这些数据。*/LOOPER_ID_MAIN = 1,/*** 事件的 Looper 数据 ID,其中的事件来自应用程序窗口的 AInputQueue,* 该数据 ID 作为一个标识符从* ALooper_pollOnce() 返回。此标识符的数据是指向* android_poll_source 结构的指针。这些数据可通过*android_app 的 inputQueue 对象读取。*/LOOPER_ID_INPUT = 2,/*** 用户定义的 ALooper 标识符的开头。*/LOOPER_ID_USER = 3,
};enum {/*** 来自主线程的命令: AInputQueue 已更改。 处理* 此命令时,android_app->inputQueue 将更新到新的队列* (或 NULL)。*/APP_CMD_INPUT_CHANGED,/*** 来自主线程的命令: 新的 ANativeWindow 已准备就绪可供使用。 接收到* 此命令后,android_app->window 将包含新的窗口* 界面。*/APP_CMD_INIT_WINDOW,/*** 来自主线程的命令: 需要终止* 目前的 ANativeWindow。 收到此命令后,android_app->window 仍* 包含现有窗口;调用 android_app_exec_cmd 后,* 它将被设置为 NULL。*/APP_CMD_TERM_WINDOW,/*** 来自主线程的命令: 已调整当前 ANativeWindow 的大小。* 请根据它的新大小重新绘制。*/APP_CMD_WINDOW_RESIZED,/*** 来自主线程的命令: 系统需要重新绘制* 当前 ANativeWindow。 你应该在进行相关处理之前将窗口重新绘制到* android_app_exec_cmd(),以避免短暂的绘制故障。*/APP_CMD_WINDOW_REDRAW_NEEDED,/***来自主线程的命令: 窗口的内容区域已更改,* 例如,从显示或隐藏的软输入窗口更改为其他区域。 你可在*android_app::contentRect 中找到新的内容矩形。*/APP_CMD_CONTENT_RECT_CHANGED,/*** 来自主线程的命令: 应用的活动窗口已获得* 输入焦点。*/APP_CMD_GAINED_FOCUS,/*** 来自主线程的命令: 应用的活动窗口已丢失*输入焦点。*/APP_CMD_LOST_FOCUS,/*** 来自主线程的命令: 当前设备配置已更改。*/APP_CMD_CONFIG_CHANGED,/*** 来自主线程的命令: 系统在运行时内存不足。* 尝试减少你的内存使用。*/APP_CMD_LOW_MEMORY,/*** 来自主线程的命令: 应用的活动已启动。*/APP_CMD_START,/*** 来自主线程的命令: 应用的活动已恢复。*/APP_CMD_RESUME,/*** 来自主线程的命令: 应用应为它自己生成新的已保存状态,* 以便今后在需要时从其进行还原。 如果你有已保存状态,* 通过分配内存对其进行分配并将其以* android_app.savedStateSize 中的大小放在 android_app.savedState 中。 这样会稍后为你* 释放内存。*/APP_CMD_SAVE_STATE,/*** 来自主线程的命令: 应用的活动已暂停。*/APP_CMD_PAUSE,/*** 来自主线程的命令: 应用的活动已停止。*/APP_CMD_STOP,/*** 来自主线程的命令: 应用的活动已被破坏,* 正在等待应用程清理并退出,然后继续。*/APP_CMD_DESTROY,
};/*** ALooper_pollAll() 返回 LOOPER_ID_MAIN 时调用,读取下一* 应用命令消息。*/
int8_t android_app_read_cmd(struct android_app* android_app);/*** 用 android_app_read_cmd() 返回的命令调用,以对* 给定的命令进行初始预处理。调用此函数后,你可对* 命令执行你自己的操作。*/
void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);/*** 用 android_app_read_cmd() 返回的命令调用,以对* 给定的命令进行最终后处理。调用此函数前,必须先对* 命令执行你自己的操作。*/
void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);/*** 这是应用程序代码必须实现的函数,表示* 应用的主索引项。*/
extern void android_main(struct android_app* app);#ifdef __cplusplus
}
#endif#endif /* _ANDROID_NATIVE_APP_GLUE_H */
这篇关于构建NativeActivity 没有dex 没有java代码的apk也能在手机上跑起来的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!