网站底部备案号代码,凡科建站怎么删除网站建设,如何注册公司企业邮箱,上海网页制作机构使用NDK编写的本地代码具有高性能等特性#xff0c;在游戏、图形处理等领域有广泛应用#xff0c;下面介绍如何手动搭建一个纯C版的Android项目#xff0c;通过该项目可以理解Android的项目结构。 一、创建settings.gradle Android项目是基于Gradle构建的#xff0c;首先得… 使用NDK编写的本地代码具有高性能等特性在游戏、图形处理等领域有广泛应用下面介绍如何手动搭建一个纯C版的Android项目通过该项目可以理解Android的项目结构。 一、创建settings.gradle Android项目是基于Gradle构建的首先得有settings.gradle文件正常情况下该文件主要用于配置子模块但是这里没有子模块只配置了插件管理和依赖的远程仓库内容如下 pluginManagement {repositories {gradlePluginPortal()google()mavenCentral()}
}dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)repositories {google()mavenCentral()}
}二、创建build.gradle build.gradle 是Gradle的构建脚本,它用于定义项目的构建配置和依赖关系可以指定项目的编译版本、依赖库、插件等信息,以及定义构建任务和构建流程。本示例的build.gradle内容如下。
plugins {id com.android.application version 7.2.2
}android {compileSdk 29ndkVersion 25.1.8937393buildToolsVersion 30.0.3namespace com.sino.nativesampledefaultConfig {applicationId com.sino.nativesampleminSdkVersion 28 // for Vulkan, need at least 24versionCode 1versionName 1.0externalNativeBuild {cmake {cppFlags -stdc17arguments -DANDROID_STLc_sharedabiFilters armeabi-v7a, arm64-v8a}}}sourceSets {main {manifest.srcFile AndroidManifest.xmlres.srcDir res}}buildTypes {release {minifyEnabled false}}externalNativeBuild {cmake {path CMakeLists.txt}}}
build.gradle主要内容如下
1、使用插件com.android.application构建Android应用程序。
2、配置Android应用的构建信息这里的信息大部分与Android Studio自动生成的信息不一样的是sourceSets用于指定AndroidManifest.xml文件和resource目录这里分别使用根目录的AndroidManifest.xml和res目录。
3、本示例使用使用C语言开发在externalNativeBuild指定CMakeLists.txt文件路径这里使用根目录的CMakeLists.txt。 三、创建AndroidManifest.xml AndroidManifest.xml用于配置项目的权限及组件本示例的AndroidManifest.xml包含的内容如下。
?xml version1.0 encodingutf-8?
manifest xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:installLocationautoandroid:versionCode1android:versionName1.0applicationandroid:allowBackuptrueandroid:hasCodefalseandroid:iconmipmap/ic_launcherandroid:labelstring/app_nameandroid:roundIconmipmap/ic_launcheractivityandroid:nameandroid.app.NativeActivityandroid:configChangesscreenSize|screenLayout|orientation|keyboardHidden|keyboard|navigation|uiMode|densityandroid:excludeFromRecentsfalseandroid:launchModesingleTaskandroid:resizeableActivityfalseandroid:screenOrientationlandscapeandroid:themeandroid:style/Theme.Black.NoTitleBar.Fullscreenandroid:exportedtruetools:ignoreNonResizeableActivity!-- Tell NativeActivity the name of the .so --meta-dataandroid:nameandroid.app.lib_nameandroid:valuenative /intent-filteraction android:nameandroid.intent.action.MAIN /category android:nameandroid.intent.category.LAUNCHER //intent-filter/activity/application
/manifestAndroidManifest.xml主要内容解析如下。
1、在application标签中指定了应用的名称和图标这些信息依赖于res资源目录。
2、声明Activity组件这里使用NativeActivity这是框架提供的Activity能直接于Native层交互有了该Activity后就可以不用在项目中自定义其它Activity了。NativeActivity需要指定加载Native层的库需要在标签lib_name指定库名称这里使用native作为库名称。 四、创建CMakeLists.txt 定义Activity后接下来是为它生成对应的库文件库文件由CMakeLists.txt构建内容如下。
cmake_minimum_required(VERSION 3.18.1)# Declares and names the project.project(Native)option(ENABLE_ASAN enable address sanitizer ON)add_definitions(-DXR_USE_PLATFORM_ANDROID-DXR_OS_ANDROID-D__ANDROID__) #define macroset(CXX_STANDARD -stdc17)if (MSVC)set(CXX_STANDARD /std:clatest)set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${CXX_STANDARD} /W0 /Zc:__cplusplus)
else()set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${CXX_STANDARD} -fstrict-aliasing -Wno-unknown-pragmas -Wno-unused-function -Wno-deprecated-declarations)
endif()include_directories(${ANDROID_NDK}/sources/android/native_app_glue)add_library(native SHARED main.cpp${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)#android
set(CMAKE_SHARED_LINKER_FLAGS${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate
)#link all the module
target_link_libraries(native PRIVATE android log) 在add_library指定库名称为native正好于NativeActivity的lib_name对应起来源文件为main.cppandroid_native_app_glue.c是NDK提供的文件封装了NativeActivity的回调函数main.cpp正是基于这些回调进行开发。
五、程序开发 在main.cpp中可以开始基于C进行程序开发了这里的main.cpp的主要内容如下。 #include android_native_app_glue.h
#include jni.h
#include exception
#include android/log.h#define LOG_TAG Native
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)struct AndroidAppState {ANativeWindow* NativeWindow nullptr;bool Resumed false;
};static void handleAppCmd(struct android_app* app, int32_t cmd) {AndroidAppState* appState (AndroidAppState*)app-userData;switch (cmd) {case APP_CMD_START: {break;}case APP_CMD_RESUME: {appState-Resumed true;break;}case APP_CMD_PAUSE: {appState-Resumed false;break;}case APP_CMD_STOP: {break;}case APP_CMD_DESTROY: {appState-NativeWindow NULL;break;}case APP_CMD_INIT_WINDOW: {appState-NativeWindow app-window;break;}case APP_CMD_TERM_WINDOW: {appState-NativeWindow NULL;break;}}
}static int32_t handleInputEvent(struct android_app* app, AInputEvent* event)
{LOGI(android_main handleInputEvent);if(AInputEvent_getType(event) AINPUT_EVENT_TYPE_MOTION AInputEvent_getSource(event) AINPUT_SOURCE_TOUCHSCREEN){int32_t action AMotionEvent_getAction(event);float x AMotionEvent_getX(event,0);float y AMotionEvent_getY(event,0);switch(action){case AMOTION_EVENT_ACTION_DOWN:LOGI(android_main AMOTION_EVENT_ACTION_DOWN (x %f, y %f), x,y);break;case AMOTION_EVENT_ACTION_MOVE:LOGI(android_main AMOTION_EVENT_ACTION_MOVE);break;case AMOTION_EVENT_ACTION_UP:LOGI(android_main AMOTION_EVENT_ACTION_UP);break;default:break;}}return 0;
}void android_main(struct android_app* app)
{LOGI(android_main);try {JNIEnv* Env;app-activity-vm-AttachCurrentThread(Env, nullptr);JavaVM *vm;Env-GetJavaVM(vm);AndroidAppState appState {};app-userData appState;app-onAppCmd handleAppCmd;app-onInputEvent handleInputEvent;while (app-destroyRequested 0) {for (;;) {int events;struct android_poll_source *source;const int timeoutMilliseconds (!appState.Resumed app-destroyRequested 0) ? -1 : 0;if (ALooper_pollAll(timeoutMilliseconds, nullptr, events, (void **) source) 0) {break;}if (source ! nullptr) {source-process(app, source);}}if(appState.NativeWindow ! nullptr){ANativeWindow_setBuffersGeometry(appState.NativeWindow, 100, 100, WINDOW_FORMAT_RGBA_8888);ANativeWindow_Buffer buffer;if (ANativeWindow_lock(appState.NativeWindow, buffer, nullptr) 0) {uint32_t* bits static_castuint32_t*(buffer.bits);for (int i 0; i buffer.stride * buffer.height; i) {bits[i] 0xFFFFFFFF;//ABGR }ANativeWindow_unlockAndPost(appState.NativeWindow);}}LOGI(android_main loop);//why is 16//handle}app-activity-vm-DetachCurrentThread();} catch (const std::exception ex) {LOGE(%s,ex.what());} catch (...) {LOGE(Unknow Error);}
}main.cpp的主要方法如下
1、android_main是入口函数在该函数中主要定义循环在循环中处理程序的核心流程。
2、handleAppCmd处理Activity的回调事件
3、handleInputEvent处理输入事件。 六、准备构建工具 上面的文件准备好以后下一步是准备构建工具到Android Studio的工程中把gradle目录、gradle.properties、gradlew、gradlew.bat拷贝到当前工程的根目录就可以使用gradlew命令构建工程了 七、构建工程 本机已经准备好Android开发环境的情况下在命令窗口切换到工程根目录使用命令gradlew.bat assemble即可生成可以运行的apk 八、执行效果 通过脚本构建得到apk后安装到设备上即可在桌面上显示应用图标点击图标可启动应用下面是在模拟器上运行的效果如下图所示。 在图中显示的是白色背景这是由于在循环中对窗口的图形缓存的每个像素点都赋值为白色bits[i] 0xFFFFFFFF;//ABGR
九、完整工程路径
本示例的工程已上传到github链接如下。
示例工程地址
上面是手动搭建的工程地址下面是通过Android Studio生成的工程也是基于NativeActivity
Android Studio自动生成的工程 本示例是一个基础工程后续介绍的示例大部分基于上面的工程扩展而来。