Android中使用NativeActivity进行APP开发

自古以来,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);
}




然后..............研究 OpenGL ES 去了.








  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值