自古以来,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);
-
-
/*
-
* 定义NativeActivity的入口函数
-
*/
-
void ANativeActivity_onCreate(ANativeActivity *activity, void *savedState, size_t savedStateSize);
-
-
/*
-
* 处理事件队列的函数
-
*/
-
void *looper(void *args);
-
-
/**
-
* 定义onStart方法,对应Java中的onStart
-
*/
-
void onStart(ANativeActivity *activity);
-
-
/**
-
* 定义onResume方法,对应Java中的onResume
-
*/
-
void onResume(ANativeActivity *activity);
-
-
/**
-
* 定义储存静态对象状态方法
-
*/
-
void *onSaveInstanceState(ANativeActivity *activity, size_t *outSize);
-
-
/**
-
* 定义onPause方法,对应Java中的onPause
-
*/
-
void onPause(ANativeActivity *activity);
-
-
/**
-
* 定义onStop方法,对应Java中的onStop
-
*/
-
void onStop(ANativeActivity *activity);
-
-
/**
-
* 定义onDestory方法,对应Java中的onDestroy
-
*/
-
void onDestroy(ANativeActivity *activity);
-
-
/**
-
* 定义窗口焦点改变方法
-
*/
-
void onWindowFocusChanged(ANativeActivity *activity, int hasFocus);
-
-
/**
-
* 定义Native窗口创建方法
-
*/
-
void onNativeWindowCreated(ANativeActivity *activity, ANativeWindow *window);
-
-
/**
-
* 定义Native窗口销毁方法
-
*/
-
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);
-
}