构建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)
#endif

static 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 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值