Android纯原生NativeActivity机制解析

##NativeActivity 机制

刚使用cocos2dx V3的最大感受就是没有 Cocos2dxActivity 这个java了…为啥? 就是cocos2dx V3 是真正的Native了;

1
2
3
4
5
6
7
8
9
10
11
12
13
public class testgame extends Cocos2dxActivity {
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
        }

        public Cocos2dxGLSurfaceView onCreateView() {
                return new LuaGLSurfaceView(this);
        }

        static {
                System.loadLibrary("cocos2dlua");
        }
}

相对的, 是android原来编写应用的方式: JavaActivity;
而NativeActivity是Android SDK提供的编写Native应用的辅助类, 它帮助管理Android 框架和应用之间的事件通信;
查看 $NDK_ROOT/platforms/android-14/arch-x86/usr/include/android/native_activity.h,这个是NativeActivity的机制说明

要编写一个NativeActivity, 你可以使用最原始的方法:

  1. 实现NativeActivity创建和注册方法:

    typedef void ANativeActivity_createFunc(ANativeActivity* activity,
            void* savedState, size_t savedStateSize);
    
    //默认的ANativeActivity_createFunc
    extern ANativeActivity_createFunc ANativeActivity_onCreate;
    
  2. 设置callback

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef struct ANativeActivity {
    struct ANativeActivityCallbacks* callbacks;

    ......

} ANativeActivity;

typedef struct ANativeActivityCallbacks {
    /**
     * 当NativeActivity 启动时回调.  就像原来 JAVAActivity.onStart()一样
     */
    void (*onStart)(ANativeActivity* activity);

    //类似的还有
    void (*onResume)(ANativeActivity* activity);
    void* (*onSaveInstanceState)(ANativeActivity* activity, size_t* outSize);
    void (*onPause)(ANativeActivity* activity);
    void (*onStop)(ANativeActivity* activity);
    void (*onDestroy)(ANativeActivity* activity);

    ......

} ANativeActivityCallbacks;

一个简单的 NativeActivity就像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void onStart(ANativeActivity* activity) {
    printf("hello world");
}

static void onDestroy(ANativeActivity* activity) {
    printf("bye...");
}

//实现入口点函数, 就像main一样
void ANativeActivity_onCreate(ANativeActivity* activity,void* savedState, size_t savedStateSize) {
    //实现设置回调函数
    activity->callbacks->onDestroy = onDestroy;
    activity->callbacks->onStart = onStart;
}

就什么简单: ANativeActivity_onCreate就相当于main函数, 然后作为app它有生命周期和,你就需要监听一下生命周期事件, 完事!

##android_native_app_glue 编写Native应用有两种方式,

1.  自己实现native_activity.h中的回调函数; 
2.  利用android_native_app_glue 

android_native_app_glue它将input事件单独起了一个线程,将实现使用pipe管道进行流水处理, 避免事件处理造成的ui hang住
cocos2dx就是使用第二种

$NDK_ROOT/sources/android/native_app_glue/android_native_app_glue.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//实现入口点回调函数
void ANativeActivity_onCreate(ANativeActivity* activity,
        void* savedState, size_t savedStateSize) {
    LOGV("Creating: %p\n", activity);

    //设置activity回调函数
    activity->callbacks->onDestroy = onDestroy;
    activity->callbacks->onStart = onStart;
    ......
    activity->callbacks->onInputQueueCreated = onInputQueueCreated;
    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;

    //生成android_app
    activity->instance = android_app_create(activity, savedState, savedStateSize);
}

static struct android_app* android_app_create(ANativeActivity* activity,
        void* savedState, size_t savedStateSize) {

    ......

    //声明事件管道
    android_app->msgread = msgpipe[0];
    android_app->msgwrite = msgpipe[1];

    //在新线程中让app_entry
    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);

    ......
}

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;

    /**
     *  这里使用了ALooper辅助类, 实现源码暂时找不到, 推测就是会监听刚才声明的`事件管道`的读取端
     *  当有消息来的时候就调用cmdPollSource.process指定的回调函数process_cmd
     */
    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);

    //调用app实现的android_main
    android_main(android_app);

    android_app_destroy(android_app);
    return NULL;
}

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);
    //调用app实现的onAppCmd
    if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
    android_app_post_exec_cmd(app, cmd);
}

##为什么

按照原来Java Activity的方式, JavaActivity里去load一下jni的.so库,然后JavaActivity.onCreate()里再调用jni里的onCreate()之类的东西;
然后JavaActivity.onTouchXXX 什么的时间都要通过jni转一下, 编写很麻烦, 对于jni这种中转依赖的很重;
而使用NativeActivity, 就完全是Native的; 所有onXXX()都是直接C++里实现就好;