自古以来,Android的主要开发语言都是以Java为主,也有很多开发者使用其他语言,当然也有混合开发的,比如Java&C or Java&C++等,一直以来,android的开发语言层出不穷
现在看来,Android的开发语言相当多,像什么C# for Android 使用C#进行Android开发,也有Qt for Android 使用Qt图形库(C++)进行Android开发(PS:这玩意空包打出来都极其笨重)等等.不过,这无疑为Android的开发者添加了更多的选择,对于开发者来说也是件好事情.
好吧,进入正题,我们使用纯C | C++来开发Android程序
实际上,Android中使用纯C来开发,其原理也并非纯C,只是将Java层封装好了,使用Jni来调用C | C++的library,不过呢,我们不需要去管那些Java层已经封装好的东西,只需要安心写C | C++代码就行了.
为了方便,我就直接使用AndroidStudio吧(自从这货支持NDK了以后,我就觉得这玩意写Native代码贼方便)
好吧,首先打开AndroidStudio->File->New->New Project...
切记,一定得吧 Include C++ Support 勾上,至于为什么,不用我多解释吧
然后继续吧,其实就相当于创建一个NDK项目只不过到最后使用的不是Java代码,而是C代码而已
接着一路Next
然后到Activity选择界面时,选择 Add No Activity ,然后继续,一直到Finish
如果中途报出 NDK not configured. 的错误,表示AndroidStudio没有检测到你的NDK路径,你需要手动选择
那么手动选择怎么操作呢?很简单的File->Project Structure...然后在弹出的窗口中对NDK的路径进行配置
选择完了就OK吧,然后等待AndroidStudio创建工程创建完成.
创建完成之后的项目结构大概就是这样的
Java文件夹内虽然有包存在,但是包内是不包含Java代码的
接下来,我们需要对一些文件进行修改
首先AndroidMainfest.xml
因为我们没有使用Java代码,所以要在AndroidMainfest.xml文件中的Application节点中添加
android:hasCode="false"
修改完成后大致就是这样的吧
然后,对着里有几点做简单的解释
android:hasCode="false" 表示该应用不包含Java代码
android.app.NativeActivity 这是固定的,前面提到程序的工作机制是使用Jni加载.so文件,而这个NativeActivity就是用Java封装的用来加载,so用的,固定写法
<meta-data
android:name="android.app.lib_name" <!--这点表示加载lib声明-->
android:value="native-main" <!--这里表示你的代码编译过后的.so文件的名称,比如我的项目编译出来的名称为libnative-main.so,这里就填写native-main,去掉lib & .so-->
/>
然后<intent-filter>里边的东西是默认启动Activity的配置
到这里,整个项目就弄的差不多了,然后开始我们的代码编写工作
至于那个native-lib.cpp没啥用,干脆删了吧
首先,在cpp目录中添加一个.h文件,名称随意吧,比如我的叫做NativeMain.h
然后在里边导入native_activity.h并添加NativeActivity的一些生命周期函数声明
- #ifndef _ANDROID_NATIVE_MAIN_H_
- #define _ANDROID_NATIVE_MAIN_H_
-
- #include <android/native_activity.h>
-
-
-
-
- void bindLifeCycle(ANativeActivity *activity);
-
-
-
-
- void ANativeActivity_onCreate(ANativeActivity *activity, void *savedState, size_t savedStateSize);
-
-
-
-
- void *looper(void *args);
-
-
-
-
- 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);
-
-
-
-
- void onWindowFocusChanged(ANativeActivity *activity, int hasFocus);
-
-
-
-
- void onNativeWindowCreated(ANativeActivity *activity, ANativeWindow *window);
-
-
-
-
- void onNativeWindowDestroyed(ANativeActivity *activity, ANativeWindow *window);
-
-
-
-
- void onInputQueueCreated(ANativeActivity *activity, AInputQueue *queue);
-
-
-
-
- void onInputQueueDestroyed(ANativeActivity *activity, AInputQueue *queue);
-
-
-
-
- void onConfigurationChanged(ANativeActivity *activity);
-
-
-
-
- void onLowMemory(ANativeActivity *activity);
-
- #endif // !_ANDROID_NATIVE_MAIN_H_
这些方法在native_activity.h中有引用,所以我们要自行设置方法回调,但是在这之前,我们需要先进行方法的实现
我们在创建一个cpp文件,用来编写方法的实现名称随意,比如我的叫做NativeMain.cpp
在这里边对刚才在NativeMain.h里边声明的方法进行实现和绑定回调
- #include <android/log.h>
-
- #include "NativeMain.h"
-
- #define LOG_TAG "NATIVE_MAIN_CPP"
- #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR ,LOG_TAG ,__VA_ARGS__)
-
- 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) {
-
- }
-
- void onWindowFocusChanged(ANativeActivity *activity, int hasFocus) {
-
- }
-
- void onNativeWindowCreated(ANativeActivity *activity, ANativeWindow *window) {
-
- }
-
- void onNativeWindowDestroyed(ANativeActivity *activity, ANativeWindow *window) {
-
- }
-
- void onInputQueueCreated(ANativeActivity *activity, AInputQueue *queue) {
-
- }
-
- void onInputQueueDestroyed(ANativeActivity *activity, AInputQueue *queue) {
-
- }
-
- void onConfigurationChanged(ANativeActivity *activity) {
-
- }
-
- void onLowMemory(ANativeActivity *activity) {
-
- }
-
- void ANativeActivity_onCreate(ANativeActivity *activity, void *savedState, size_t savedStateSize) {
-
- }
接着,我们要对声明周期函数绑定回调
实现bindLifeCycle(ANativeActivity *activity);方法,并在里边设置回调
- void bindLifeCycle(ANativeActivity *activity) {
- activity->callbacks->onStart = onStart;
- activity->callbacks->onResume = onResume;
- activity->callbacks->onSaveInstanceState = onSaveInstanceState;
- activity->callbacks->onPause = onPause;
- activity->callbacks->onStop = onStop;
- activity->callbacks->onDestroy = onDestroy;
- activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
- activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
- activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
- activity->callbacks->onInputQueueCreated = onInputQueueCreated;
- activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
- activity->callbacks->onConfigurationChanged = onConfigurationChanged;
- activity->callbacks->onLowMemory = onLowMemory;
- }
回调设置完了,但是需要在ANativeActivity_onCreate()方法中调用,这个方法则相当于Java中的onCreate()方法,就是程序的入口点
void ANativeActivity_onCreate(ANativeActivity *activity, void *savedState, size_t savedStateSize) {
bindLifeCycle(activity);
}
然后编译成.so我们需要在CMakeLists.txt中添加我们的源码文件
为了方便查看,我就将这里边的注释全部去掉了
- cmake_minimum_required(VERSION 3.4.1)
-
- add_library( native-main SHARED
- src/main/cpp/NativeMain.cpp
- )
-
- find_library( log-lib log )
-
- target_link_libraries( native-main ${log-lib} )
添加完了之后,就可以编译运行了
如果你需要在APP里边进行事件的处理,那就需要自己写looper
- static bool isLoop = false;
- static pthread_t loopID;
- void *looper(void *args) {
- ANativeActivity *activity = (ANativeActivity *) args;
- AInputQueue *queue = (AInputQueue *) activity->instance;
- AInputEvent *event = NULL;
- while (isLoop) {
- if (!AInputQueue_hasEvents(queue)) {
- continue;
- }
- AInputQueue_getEvent(queue, &event);
- float mx = AMotionEvent_getX(event, 0);
- float my = AMotionEvent_getY(event, 0);
- switch (AInputEvent_getType(event)) {
- case AINPUT_EVENT_TYPE_MOTION: {
- switch (AMotionEvent_getAction(event)) {
- case AMOTION_EVENT_ACTION_DOWN: {
- LOGE("Touch Scerrn Down");
- break;
- }
- case AMOTION_EVENT_ACTION_UP: {
- LOGE("Touch Scerrn UP");
- break; } default: break; } break; } case AINPUT_EVENT_TYPE_KEY: { switch (AKeyEvent_getAction(event)) { case AKEY_EVENT_ACTION_DOWN: { LOGE("key down"); switch (AKeyEvent_getKeyCode(event)) { case AKEYCODE_BACK: {
- LOGE("BACK down");
- ANativeActivity_finish(activity);
- break;
- }
- default:
- break;
- }
- break;
- }
- case AKEY_EVENT_ACTION_UP: {
- LOGE("key up");
- break;
- }
- default:
- break;
- }
- }
- default:
- break;
- }
- AInputQueue_finishEvent(queue, event, 1);
- }
- return args;
- }
消息处理写好了,还需要在onInputQueueCreated()方法中进行启动,在onInputQueueDestroyed();方法中停止,消息处理其实是启动一条线程来进行消息处理,所以别忘了在顶部导入pthread.h
void onInputQueueCreated(ANativeActivity *activity, AInputQueue *queue) {
isLoop = true;
activity->instance = (void *) queue;
pthread_create(&loopID, NULL, looper, activity);
}
void onInputQueueDestroyed(ANativeActivity *activity, AInputQueue *queue) {
isLoop = false;
}
至此,这个项目就差不多了,剩下的界面啥的,用EGL & GLES来画吧,这里我就不多写了,因为OpenGL ES & EGL 我也一窍不通,没办法写了
最后,贴出整个NativeMain.cpp的代码
- #include <android/log.h>
- #include <pthread.h>
-
- #include "NativeMain.h"
-
- #define LOG_TAG "MAIN_CPP"
- #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR ,LOG_TAG ,__VA_ARGS__)
-
- static bool isLoop = false;
- static pthread_t loopID;
-
- void onStart(ANativeActivity *activity) {
- LOGE("Application is start");
- }
-
- void onResume(ANativeActivity *activity) {
-
- }
-
- void *onSaveInstanceState(ANativeActivity *activity, size_t *outSize) {
-
- }
-
- void onPause(ANativeActivity *activity) {
-
- }
-
- void onStop(ANativeActivity *activity) {
-
- }
-
- void onDestroy(ANativeActivity *activity) {
-
- }
-
- void onWindowFocusChanged(ANativeActivity *activity, int hasFocus) {
-
- }
-
- void onNativeWindowCreated(ANativeActivity *activity, ANativeWindow *window) {
-
- }
-
- void onNativeWindowDestroyed(ANativeActivity *activity, ANativeWindow *window) {
-
- }
-
- void onInputQueueCreated(ANativeActivity *activity, AInputQueue *queue) {
- isLoop = true;
- activity->instance = (void *) queue;
- pthread_create(&loopID, NULL, looper, activity);
- }
-
- void onInputQueueDestroyed(ANativeActivity *activity, AInputQueue *queue) {
- isLoop = false;
- }
-
- void onConfigurationChanged(ANativeActivity *activity) {
-
- }
-
- void onLowMemory(ANativeActivity *activity) {
-
- }
-
- void bindLifeCycle(ANativeActivity *activity) {
- activity->callbacks->onStart = onStart;
- activity->callbacks->onResume = onResume;
- activity->callbacks->onSaveInstanceState = onSaveInstanceState;
- activity->callbacks->onPause = onPause;
- activity->callbacks->onStop = onStop;
- activity->callbacks->onDestroy = onDestroy;
- activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
- activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
- activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
- activity->callbacks->onInputQueueCreated = onInputQueueCreated;
- activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
- activity->callbacks->onConfigurationChanged = onConfigurationChanged;
- activity->callbacks->onLowMemory = onLowMemory;
- }
-
- void *looper(void *args) {
- ANativeActivity *activity = (ANativeActivity *) args;
- AInputQueue *queue = (AInputQueue *) activity->instance;
- AInputEvent *event = NULL;
- while (isLoop) {
- if (!AInputQueue_hasEvents(queue)) {
- continue;
- }
- AInputQueue_getEvent(queue, &event);
- float mx = AMotionEvent_getX(event, 0);
- float my = AMotionEvent_getY(event, 0);
- switch (AInputEvent_getType(event)) {
- case AINPUT_EVENT_TYPE_MOTION: {
- switch (AMotionEvent_getAction(event)) {
- case AMOTION_EVENT_ACTION_DOWN: {
- LOGE("Touch Screen Down");
- break;
- }
- case AMOTION_EVENT_ACTION_UP: {
- LOGE("Touch Screen UP");
- break;
- }
- default:
- break;
- }
- break;
- }
- case AINPUT_EVENT_TYPE_KEY: {
- switch (AKeyEvent_getAction(event)) {
- case AKEY_EVENT_ACTION_DOWN: {
- LOGE("key down");
- switch (AKeyEvent_getKeyCode(event)) {
- case AKEYCODE_BACK: {
- LOGE("BACK down");
- ANativeActivity_finish(activity);
- break;
- }
- default:
- break;
- }
- break;
- }
- case AKEY_EVENT_ACTION_UP: {
- LOGE("key up");
- break;
- }
- default:
- break;
- }
- }
- default:
- break;
- }
- AInputQueue_finishEvent(queue, event, 1);
- }
- return args;
- }
-
- void ANativeActivity_onCreate(ANativeActivity *activity, void *savedState, size_t savedStateSize) {
- LOGE("init LifeCycle");
- bindLifeCycle(activity);
- }