如何在Android中使用NDK?及转换com.android.model.application至com.android.application
在Android里用NDK主要是为了编写C/C++代码并编译成原生库供Java/Kotlin调用,下面是完整的实操步骤:
第一步:搞定环境准备
打开Android Studio的SDK Manager,切换到「SDK Tools」标签,勾选NDK (Side by side)和CMake,点击应用完成安装。安装后Android Studio会自动配置NDK路径,你也可以手动在项目根目录的local.properties里指定:ndk.dir=/你的NDK安装路径。第二步:创建JNI相关文件
在项目的src/main目录下新建jni文件夹,把你的C/C源码(比如Test_Jni.c)和必要的头文件放进去。如果有外部的C/C文件,也可以放在这里或者后续在Gradle里指定其他路径。第三步:配置Gradle
如果你用的是新版的com.android.application插件(也就是你要转换的目标),可以直接在模块级build.gradle里配置NDK参数,具体可以参考第二个问题的配置示例。要是需要更灵活的编译控制,也可以用CMakeLists.txt来管理,简单场景下直接Gradle配置就足够。第四步:编写JNI接口
在Java类里声明native方法,比如:public class JniUtils { static { System.loadLibrary("Test_Jni"); // 这里的名字要和Gradle里的moduleName一致 } public native String getNativeString(); }之后可以用
javah命令,或者Android Studio的「Generate JNI Headers」功能生成对应的头文件,再在C/C++文件里实现这个native方法。第五步:编译运行
点击Android Studio的「Make Project」按钮,Gradle会自动编译C/C++代码生成.so库并打包进APK。运行App后就能调用native方法啦。
com.android.model.application到com.android.application并解决CFlags.add问题 旧的com.android.model.application是Android Experimental插件的用法,现在已经被官方的com.android.application取代了,两者的配置语法差异不小,尤其是NDK部分。针对你的Gradle代码,修改后的版本如下,我会逐点说明改动:
apply plugin: 'com.android.application' android { compileSdkVersion 27 buildToolsVersion '27.0.0' defaultConfig { applicationId "com.update.myapp" minSdkVersion 19 targetSdkVersion 26 versionCode 1 versionName "1.0.2" multiDexEnabled true // NDK核心配置移到defaultConfig的ndk块里 ndk { moduleName "Test_Jni" ldLibs "log" // 直接指定需要链接的系统库 } // C编译选项和头文件路径放在externalNativeBuild的ndkBuild块中 externalNativeBuild { ndkBuild { // 替换原来的CFlags.add,直接用逗号分隔多个编译宏 cFlags "-DCOMPANION_DEVICE", "-DDISABLE_LOGS" // 通过arguments传递头文件路径参数,对应原来的CFlags.addAll里的-I选项 arguments "-I${file("src/main/jni/Folder1/")}".toString(), "-I${file("src/main/jni/Folder2")}".toString(), "-I${file("C:\\Program Files (x86)\\MyFile\\folder1_Cfiles/")}".toString(), "-I${file("C:\\Program Files (x86)\\MyFile\\folder2_Cfiles/")}".toString() } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } // 指定JNI源码的目录,替换原来的sources配置 sourceSets { main { jni.srcDirs = [ "src/main/jni", "C:\\Program Files (x86)\\MyFile\\folder1_Cfiles", "C:\\Program Files (x86)\\MyFile\\folder2_Cfiles" ] } } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:27.0.2' implementation 'com.android.support:multidex:1.0.3' // 开启multiDex后建议添加这个依赖,避免运行时崩溃 }
关键改动点说明:
- 替换插件:把
com.android.model.application换成官方标准的com.android.application。 - 移除
model块:所有配置直接放在android块下,不再嵌套层级。 - NDK配置迁移:原来
android.ndk里的moduleName和ldLibs移到defaultConfig.ndk块中。 - CFlags语法调整:原来的
CFlags.add换成externalNativeBuild.ndkBuild.cFlags,多个编译宏用逗号分隔;头文件路径通过arguments传递,对应原来的-I参数。 - 源码路径配置:原来的
android.sources.main.jni.source.srcDirs改成sourceSets.main.jni.srcDirs,用赋值方式指定多个目录。 - 依赖更新:把旧的
compile换成Gradle推荐的implementation;另外加上multidex依赖,因为你开启了multiDexEnabled,防止运行时出现类找不到的问题。
这样修改后,Gradle就能正确识别你的NDK配置,解决原来CFlags.add的语法问题了。
内容的提问来源于stack exchange,提问作者Anass Hb




