环境搭建之创建nativeactivity

Android-Studio-NativeActivity创建流程

1. Android-Studio和Android.mk方案 - 配置解析

1. 新建Android-studio工程

选择Native C++就可以了

2. 修改AndroidManifest.xml文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.opensl_triangle">

    <!-- 1. 没有java代码,设置android:hasCode="false" -->
    <application
        android:allowBackup="true"
        android:hasCode="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <!-- 2. 将activity替换为nativeactivity -->
        <activity android:name="android.app.NativeActivity">
            <!-- 告诉nativeactivity它的库名为Hello_Triangle -->
            <meta-data android:name="android.app.lib_name"
                android:value="Hello_Triangle" />
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

3. ndk配置

1. 打开local.properties,添加:
ndk.dir=C\:\\Users\\jetson\\AppData\\Local\\Android\\Sdk\\ndk\\22.0.7026061

2. 打开gradle.properties,添加:
android.useDeprecatedNdk=true

3. 右键cpp文件夹,然后选link c++ project with gradle,选择jni下的Android.mk文件

4. 删除java文件夹

5. 配置Android.mk文件,调整文件夹

LOCAL_PATH          := $(call my-dir)
COMMON_PATH         := $(LOCAL_PATH)/../Common
COMMON_INC_PATH     := $(COMMON_PATH)/Include/
COMMON_SRC_PATH     := $(COMMON_PATH)/Source

include $(CLEAR_VARS)

# 要编译生成的库,和上面AndroidManifest.xml文件中<meta-data android:name="android.app.lib_name" android:value="Hello_Triangle" />配置一致
LOCAL_MODULE    := Hello_Triangle
# 定义ANDROID宏
LOCAL_CFLAGS    += -DANDROID


LOCAL_SRC_FILES := $(COMMON_SRC_PATH)/esShader.c \
                   $(COMMON_SRC_PATH)/esShapes.c \
                   $(COMMON_SRC_PATH)/esTransform.c \
                   $(COMMON_SRC_PATH)/esUtil.c \
                   $(COMMON_SRC_PATH)/esUtil_Android.c \
                   $(LOCAL_PATH)/Hello_Triangle.c
                   
                   

LOCAL_C_INCLUDES    := $(COMMON_INC_PATH)

# 需要链接EGL的库
LOCAL_LDLIBS    := -llog -landroid -lEGL -lGLESv3

# 需要android_native_app_glue静态库
LOCAL_STATIC_LIBRARIES := android_native_app_glue

include $(BUILD_SHARED_LIBRARY)

# 需要import native_app_glue
$(call import-module,android/native_app_glue)

2. 源码解析

1. nativeactivity实现框架

1. 进入到android_main函数

///
//  android_main()
//
//    Main entrypoint for Android application
//
void android_main ( struct android_app *pApp )
{
   ESContext esContext;
   float lastTime;

   // Make sure glue isn't stripped.
   app_dummy();

   // Initialize the context
   memset ( &esContext, 0, sizeof ( ESContext ) );

   esContext.platformData = ( void * ) pApp->activity->assetManager;

   // 1. 设置轮询回调函数
   pApp->onAppCmd = HandleCommand;
   // 2. 设置私有的数据,可以在各个函数中获取,如回调函数中
   pApp->userData = &esContext;

   lastTime = GetCurrentTime();

   while ( 1 )
   {
      int ident;
      int events;
      struct android_poll_source *pSource;

       // 3. 调用onAppCmd中的回调函数来处理事件
      while ( ( ident = ALooper_pollAll ( 0, NULL, &events, ( void ** ) &pSource ) ) >= 0 )
      {

         if ( pSource != NULL )
         {
            pSource->process ( pApp, pSource );
         }

         if ( pApp->destroyRequested != 0 )
         {
            return;
         }

      }

      if ( esContext.eglNativeWindow == NULL )
      {
         continue;
      }

      // Call app update function
      if ( esContext.updateFunc != NULL )
      {
         float curTime = GetCurrentTime();
         float deltaTime =  ( curTime - lastTime );
         lastTime = curTime;
         esContext.updateFunc ( &esContext, deltaTime );
      }

       // 处理完事件之后,就进行绘制操作
      if ( esContext.drawFunc != NULL )
      {
         esContext.drawFunc ( &esContext );
         eglSwapBuffers ( esContext.eglDisplay, esContext.eglSurface );
      }
   }
}

2. 进入到HandleCommand函数中

static void HandleCommand ( struct android_app *pApp, int32_t cmd )
{
   ESContext *esContext = ( ESContext * ) pApp->userData;

   switch ( cmd )
   {
      case APP_CMD_SAVE_STATE:
         // the OS asked us to save the state of the app
         break;

      case APP_CMD_INIT_WINDOW:

         // 进行初始化操作
         esContext->eglNativeDisplay = EGL_DEFAULT_DISPLAY;
         esContext->eglNativeWindow = pApp->window;

         // Call the main entrypoint for the app
         if ( esMain ( esContext ) != GL_TRUE )
         {
            exit ( 0 ); //@TEMP better way to exit?
         }

         break;

      case APP_CMD_TERM_WINDOW:

         // Cleanup on shutdown
         if ( esContext->shutdownFunc != NULL )
         {
            esContext->shutdownFunc ( esContext );
         }

         if ( esContext->userData != NULL )
         {
            free ( esContext->userData );
         }

         memset ( esContext, 0, sizeof ( ESContext ) );
         break;

      case APP_CMD_LOST_FOCUS:
         // if the app lost focus, avoid unnecessary processing (like monitoring the accelerometer)
         break;

      case APP_CMD_GAINED_FOCUS:
         // bring back a certain functionality, like monitoring the accelerometer
         break;
   }
}

///
//  Global extern.  The application must declare this function
//  that runs the application.
//
extern int esMain ( ESContext *esContext );

//////////////////////////////////////////////////////////////////
//
//  Public Functions
//
//


综上所述,总的流程为:

初始化操作  ->  进行绘制  ->  退出

问题

1. avd emulator不支持OpenGL 3.0

点击emulator的... -> Settings -> Advanced -> OpenGL ES API level -> 选择3.1 -> 重启即可

参考

1. 示例:native-activity
https://developer.android.com/ndk/samples/sample_na?hl=zh-cn
2. native-activity的示例代码:
https://github.com/android/ndk-samples/tree/main/native-activity
3. NativeActivity开发示例-使用AndroidStudio和CMake
https://www.jianshu.com/p/f91ba94b60f4
4. avd emulator不支持OpenGL 3.0
https://stackoverflow.com/questions/40797975/android-emulator-and-opengl-es3-egl-bad-config
5. 源码位置:
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容