如何用 纯C++(ndk)开发安卓应用 ?

开发 后端
如何安装安卓的开发环境以及怎么设置ndk的环境变量等在前边的文章已经有了详细的讲解,在这里我就不再说明,如果有不会安装和设置环境的,请先参考安卓环境搭建的内容。

如何安装安卓的开发环境以及怎么设置ndk的环境变量等在前边的文章已经有了详细的讲解,在这里我就不再说明,如果有不会安装和设置环境的,请先参考安卓环境搭建的内容。

好,假设以及安装好了ndk,使用纯c++开发安卓程序,下边是详细的步骤与说明:

1.编写入口函数

android_main为入口函数,和C++中的main函数是一样的。这里创建CELLAndroidApp的对象,直接调用main函数。

  1. void android_main(struct android_app* state)  
  2. {  
  3.     CELLAndroidApp    app(state);  
  4.  
  5.        app.main(0,0);  
  6. }  

说明:其中的 CELLAndroidApp是我们设计的一个图形绘制类,稍后将对其做详细说明

2.绘制类的实现说明

2.1类的成员说明

  1. protected:  
  2.     EGLConfig        _config;  
  3.     EGLSurface       _surface;  
  4.     EGLContext       _context;  
  5.     EGLDisplay       _display;  
  6.     android_app*     _app;  
  7.     int              _width;  
  8.     int              _height; 

部分参数说明:

_surface:用于绘制图形,相当于windows绘图中的位图

_context:可以看做是opengl对象

_display:用于绘图的设备上下文,类似于windows绘图中的dc

2.2 构造函数说明

 

  1. CELLAndroidApp(android_app* app):_app(app)  
  2.     {  
  3.         _surface    =    0;  
  4.         _context    =    0;   
  5.         _display    =    0;  
  6.         _width        =    64;  
  7.         _height        =    48;  
  8.         app->userData        =    this//用户数据  
  9.         app->onAppCmd         =     handle_cmd; //窗口的创建销毁等  
  10.         app->onInputEvent     =    handle_input; //回调函数  
  11.     } 

值得注意的是,这里的app中的userData,传入用户数据,这里直接传入this,onAppCmd传入的handle_cmd回调函数,onInputEvent传入的事handle_input回调函数

2.3 类中函数main()说明

  1. virtual    void     main(int argc,char** argv)  
  2.     {  
  3.         int ident;  
  4.         int    events;  
  5.         android_poll_source* source;  
  6.  
  7.         while (true)  
  8.         {          
  9.             while ((ident = ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0)   
  10.             {  
  11.                 if (source != NULL)  
  12.                     source->process(_app, source); //有触摸事件,调用input函数,相当于dispatchmessage  
  13.  
  14.                 if (_app->destroyRequested != 0)  
  15.                     return;  
  16.             }  
  17.             render();  
  18.         }  
  19.     } 

其中的android_poll_source相当于windows中的消息队列,用于存放消息,这个函数中模拟了windows中的消息机制。

ALooper_pollAll()函数,用于获取消息。值得注意的是第一个参数,如果第一个参数传入0,则不等待,调用后直接返回,类似于windows消息机制中的pickMessage()函数,如果传入-1,则类似于windows消息机制中的SendMessage()函数。 返回值:如果返回值大于大于等于0表示获取到数据,如果为-1则表示失败,未获取到数据。

其中发source如果不为空,则表示有触摸事件,则调用process()函数,相当于windows中调用dispatchMessage()函数。

最后,调用render()函数,绘制图形。

2.4 初始化设备函数initDevice()

  1. virtual void     initDevice()  
  2.     {  
  3.         const EGLint attribs[] =  
  4.         {  
  5.             EGL_SURFACE_TYPE, EGL_WINDOW_BIT,  
  6.             EGL_BLUE_SIZE, 8,   
  7.             EGL_GREEN_SIZE, 8,  
  8.             EGL_RED_SIZE, 8,  
  9.             EGL_NONE  
  10.         };  
  11.         EGLint     format;  
  12.         EGLint    numConfigs;  
  13.  
  14.         _display    =    eglGetDisplay(EGL_DEFAULT_DISPLAY);  
  15.  
  16.         eglInitialize(_display, 0, 0);  
  17.  
  18.         eglChooseConfig(_display, attribs, &_config, 1, &numConfigs);   
  19.  
  20.         eglGetConfigAttrib(_display, _config, EGL_NATIVE_VISUAL_ID, &format);  
  21.  
  22.         ANativeWindow_setBuffersGeometry(_app->window, 0, 0, format);   
  23.  
  24.         _surface    =     eglCreateWindowSurface(_display, _config, _app->window, NULL);  
  25.  
  26. #if 0  
  27.         EGLint contextAtt[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };  
  28.  
  29.         _context     =     eglCreateContext(_display, _config, 0, contextAtt);  
  30. #else  
  31.         _context     =     eglCreateContext(_display, _config, 0, 0);   
  32. #endif  
  33.  
  34.         if (eglMakeCurrent(_display, _surface, _surface, _context) == EGL_FALSE)  
  35.         {  
  36.             LOGW("Unable to eglMakeCurrent");   
  37.             return;  
  38.         }  
  39.  
  40.         eglQuerySurface(_display, _surface, EGL_WIDTH, &_width);   
  41.         eglQuerySurface(_display, _surface, EGL_HEIGHT, &_height);  
  42.  
  43.         onCreate();  
  44.  
  45.         // Initialize GL state.  
  46.         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);   
  47.         glEnable(GL_CULL_FACE);  
  48.         glShadeModel(GL_SMOOTH);  
  49.         glDisable(GL_DEPTH_TEST);  
  50.         glViewport(0,0,_width,_height);  
  51.         glOrthof(0,_width,_height,0,-100,100);  
  52.     } 

首先需要说明的是attribs数组,改数组中主要存储了绘制图形的一些属性信息,他们是成对出现的,如EGL_SURFACE_TYPE则表示绘制图形类型, EGL_WINDOW_BIT则表示绘制到窗口上。

eglGetDisplay()函数:表示获取一个显示设备

eglInitialize():表示初始化获取到的显示设备

eglChooseConfig():绘制属性的配置

eglGetConfigAttrib():设置绘制格式

ANativeWindow_setBuffersGeometry():将格式应用到窗口

eglCreateWindowSurface():创建绘图窗口

eglCreateContext():创建opengl的绘图上下文

eglMakeCurrent():绑定到绘图设备上下文

eglQuerySurface():获取图片的宽度和高度,具体获取哪一个根据最后一个参数确定

glHint()、glEnable()和glOrthof()等函数则是与绘图的投影相关的内容,包括初始化、设置模式等内容。

#p#

2.5 绘制函数render()

  1. virtual    void     render()  
  2.     {  
  3.         if(_display == 0)  
  4.         {  
  5.             return;  
  6.         }  
  7.         glClearColor(0,0,0, 1);   
  8.         glClear(GL_COLOR_BUFFER_BIT);  
  9.  
  10.         glEnableClientState(GL_VERTEX_ARRAY);   
  11.         if(g_arVertex.size() >= 2)  
  12.         {  
  13.             glColor4f(1,1,1,1);   
  14.             glVertexPointer(3,GL_FLOAT,0,&g_arVertex[0]);   
  15.             glDrawArrays(GL_LINE_STRIP,0,g_arVertex.size());  
  16.         }  
  17.  
  18.         eglSwapBuffers(_display,_surface); //双缓存的交换缓冲区  
  19.     } 

render()函数主要用于绘制点,对主要的几个函数做如下说明:

glClearColor():用于将屏幕清为黑色

glClear():清空颜色缓冲区

glEnableClientState():启动定点数组

glVertexPointer():制定定点缓冲区

glDrawArrays():绘制点数组

eglSwapBuffers():类似双缓存的交换缓冲区

2.6 handle_cmd()函数

  1. static void     handle_cmd(android_app* app, int32_t cmd)  
  2.     {  
  3.         CELLAndroidApp*    pThis    =    (CELLAndroidApp*)app->userData;  
  4.         pThis->cmd(app,cmd);  
  5.     }  

2.7 handle_input()函数

  1. static void     handle_input(android_app* app, AInputEvent* event)  
  2.     {  
  3.         CELLAndroidApp*    pThis    =    (CELLAndroidApp*)app->userData;  
  4.         pThis->input(app,event);  
  5.     }  

2.8 input()函数

  1. virtual    int     input(struct android_app* app, AInputEvent* event)  
  2.     {  
  3.         int32_t    evtType    =    AInputEvent_getType(event);  
  4.         switch(evtType)  
  5.         {  
  6.         case AINPUT_EVENT_TYPE_KEY:   
  7.             break;  
  8.         case AINPUT_EVENT_TYPE_MOTION:   
  9.             {  
  10.                 int32_t    sourceId    =     AInputEvent_getSource(event);  
  11.                 if(AINPUT_SOURCE_TOUCHSCREEN == sourceId)  
  12.                 {  
  13.                     int32_t id = AMotionEvent_getAction(event);   
  14.                     switch(id)  
  15.                     {  
  16.                     case AMOTION_EVENT_ACTION_MOVE:  
  17.                         {  
  18.                             size_t    cnt = AMotionEvent_getPointerCount(event);   
  19.                             forint i = 0 ;i < cnt; ++ i )  
  20.                             {  
  21.                                 float x = AMotionEvent_getX(event,i);  
  22.                                 float y = AMotionEvent_getY(event,i);  
  23.                                 float3 pt;  
  24.                                 pt.x = x;  
  25.                                 pt.y = y;  
  26.                                 pt.z = 0;  
  27.                                 g_arVertex.push_back(pt);  
  28.                             }  
  29.  
  30.                         }  
  31.                         break;  
  32.                     case AMOTION_EVENT_ACTION_DOWN:  
  33.                         {  
  34.                             size_t    cnt = AMotionEvent_getPointerCount(event);  
  35.                             forint i = 0 ;i < cnt; ++ i )  
  36.                             {  
  37.                                 float x = AMotionEvent_getX(event,i);  
  38.                                 float y = AMotionEvent_getY(event,i);  
  39.                             }  
  40.                         }  
  41.                         break;  
  42.                     case AMOTION_EVENT_ACTION_UP:  
  43.                         {  
  44.                             size_t    cnt = AMotionEvent_getPointerCount(event);  
  45.                             forint i = 0 ;i < cnt; ++ i )  
  46.                             {  
  47.                                 float x = AMotionEvent_getX(event,i);  
  48.                                 float y = AMotionEvent_getY(event,i);  
  49.                             }  
  50.                         }  
  51.                         break;  
  52.                     }  
  53.                 }  
  54.                 else if(AINPUT_SOURCE_TRACKBALL == sourceId)  
  55.                 {  
  56.                 }  
  57.             }  
  58.             break;  
  59.         }  
  60.         return    0;  
  61.     } 

该函数主要用于对输入进行判断,以确定是吉键盘、鼠标或遥感等,根据具体输入做相应的操纵,这里就不再做过多的说明

AMotionEvent_getPointerCount():如果是多点触控,则将各个点保存到vector中。

2.9 cmd()函数

  1. virtual int    cmd(struct android_app* app, int32_t cmd)  
  2.     {  
  3.         switch(cmd)  
  4.         {  
  5.         case APP_CMD_SAVE_STATE:  
  6.             break;  
  7.         case APP_CMD_INIT_WINDOW:  
  8.             initDevice();  
  9.             break;  
  10.         case APP_CMD_TERM_WINDOW:  
  11.             shutDownDevice();  
  12.             break;  
  13.         case APP_CMD_GAINED_FOCUS:  
  14.             break;  
  15.         case APP_CMD_LOST_FOCUS:  
  16.             break;  
  17.         }  
  18.         return    0;  
  19.     } 

根据传入的命令,对窗口做相应的处理。

APP_CMD_INIT_WINDOW:表示初始化窗口

2.10 shutDownDevice()函数

  1. virtual void     shutDownDevice()  
  2.     {  
  3.         onDestroy();  
  4.  
  5.         if (_display != EGL_NO_DISPLAY)  
  6.         {  
  7.             eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);  
  8.             if (_context != EGL_NO_CONTEXT)  
  9.             {  
  10.                 eglDestroyContext(_display, _context);  
  11.             }  
  12.             if (_surface != EGL_NO_SURFACE)  
  13.             {  
  14.                 eglDestroySurface(_display, _surface);  
  15.             }  
  16.             eglTerminate(_display);  
  17.         }  
  18.         _display = EGL_NO_DISPLAY;  
  19.         _context = EGL_NO_CONTEXT;  
  20.         _surface = EGL_NO_SURFACE;  
  21.     } 

关闭设备,主要是将与设备相关的绑定清除,释放绑定。

 

编写完上边的代码后,编译程序,将程序导入到模拟器中,最终运行的效果图如下:

好了,该说的基本都说玩了,下边附上源码地址,赶紧去尝试吧:

 示例程序下载

 
 
责任编辑:林师授 来源: OpenG
相关推荐

2021-04-04 08:00:39

C++编程语言软件开发

2010-01-28 10:33:10

C++开发程序

2011-09-26 17:02:05

安卓蜂窝冰激凌三明治

2013-02-22 09:28:45

MEAP软件移动应用开发HTML5

2017-11-27 17:29:43

深度学习TensorFlow安卓设备

2017-12-09 21:08:35

C++人工智能机器学习

2018-06-04 09:30:07

编程语言安卓应用开发

2010-01-28 09:44:08

C++应用程序

2013-05-02 13:06:05

C++遇到iOS应用开SQLITE

2021-09-23 14:41:58

鸿蒙HarmonyOS应用

2012-07-16 10:21:23

iPhone

2010-01-26 11:06:50

C++开发

2014-06-26 15:17:17

安卓应用保存数据

2021-06-02 09:07:33

手机存储垃圾清理雪豹速清

2010-01-14 11:14:47

C++应用程序

2010-01-25 16:41:08

C++应用程序

2013-07-19 15:39:25

2013-10-29 11:06:30

安卓应用游戏

2010-01-26 15:51:06

C++变量

2014-07-18 13:37:23

Android开发App Widget
点赞
收藏

51CTO技术栈公众号