Android Studio 中关于NDK编译及jni header生成的问题
之前由于工作原因使用grails这个基于groovy的框架做项目,对groovy感觉很好。
基于groovy的gradle构建系统对我而言自然也是好的没得说。
Android Studio 正式版出来没多久,不完善的地方自然很多,对于从eclipse转来的伙伴们而言,不了解groovy的话对于gradle android的dsl自然是一头雾水,其实groovy蛮好,花点时间学学,目前已经支持android开发了。
最近干的活设计到NDK开发,在编译时遇到一些不好搞定的问题。
gradle 的NDK编译
使用gradle编译ndk后会发现,gradle其实是自己按dsl生成了android.mk
,然后执行ndk-build
命令,仔细对比会发现,它没有生成application.mk
。那么问题来了,对于我的项目而言,使用gradle总是编译不过去,而自己运行ndk-build
则不会出现问题。
构建系统本来就是解决了这种批处理问题,不想抛开gradle而手动去编译,干脆就让gradle执行自己的ndkbuild Task。
通过不断试错,整理如下Task:
// 编译NDK代码
task ndkBuild(type: Exec, description: 'Compile JNI source via NDK') {
// android.mk 地址 ,自行更改
def androidMK = "$projectDir/src/main/jni/Android.mk"
// application.mk 地址, 自行更改
def applicationMK = "$projectDir/src/main/jni/Application.mk"
def ndkDir = project.plugins.findPlugin('com.android.application').getNdkFolder()
def cmd = ["$ndkDir/ndk-build", "NDK_PROJECT_PATH=$buildDir",
"APP_BUILD_SCRIPT=$androidMK", "NDK_APPLICATION_MK=$applicationMK"]
commandLine cmd
}
// 打包native库, 会在编译java代码后执行
task ndkLibsToJar(type: Zip, dependsOn: ["compileDebugJava", ndkBuild],
description: 'Create a JAR file of the native libs') {
destinationDir new File(projectDir, 'libs')
baseName 'ndk-libs'
extension 'jar'
from(new File(buildDir, 'libs')) { include '**/*.so' }
into 'lib/'
}
dependencies {
compile fileTree(dir: new File(projectDir, 'libs'), include: ['*.jar'])
}
当然,首先要确保项目根目录下 local.properties
中有ndk的目录位置的设定 ndk.dir=/YOUR_NDK_FOLDER
生成JNI头文件
本来javah
的参数就麻烦,有其实classpath
的设定,还得指定包名,很是麻烦,如果包含native声明方法的类中包含了android库,不指定好android.jar就更麻烦。
// 生成jni头文件,在编译java后运行
task generateJNI(dependsOn: "compileDebugJava",
description: 'Create jni header'){
//要生成的类名, 可以多个
def classes = ["org.jcuraengine.JCuraEngine"]
//jni生成到哪里
def destdir = "$projectDir/src/main/jni/jcuraengine"
// 获取android jar
def rootDir = project.rootDir
def localProperties = new File(rootDir, "local.properties")
Properties properties = new Properties()
localProperties.withInputStream { instr ->
properties.load(instr)
}
def sdkDir = properties.getProperty('sdk.dir')
def androidJarPath = sdkDir + "/platforms/" + android.compileSdkVersion + "/android.jar"
def classesName = ""
classes.each{
classesName += " $it"
}
// 调用 javah
try {
// exec会出现错误,这里使用ant
// 第一次运行这个task时,会出现错误,是android studio导致的,运行两次既可,忽视第一次执行时的异常
// 当然,注意观察第一次的异常,确保不是代码自身问题。
ant.javah(class: classesName, destdir: destdir, classpath:"$androidJarPath:$buildDir/intermediates/classes/debug/")
} catch (def e) {
println e
}
}
这两个task,在android stuido右侧gradle tasks
版面中会自动添加的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库