使用NDK和swig工具来批量编译c++代码还是很方便的。我之前写过一篇eclipse版本的,现在终于有空把android studio的版本弄好。eclipse版本地址:Android ndk开发swig编译jni接口 。在这篇博客我会介绍相关配置,生成自动生成接口jar以及so库。这期间涉及很多踩坑,做好准备。本篇博客篇幅比较长。
官方网址:http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/
swig官网:http://www.swig.org/exec.html
swig工具下载网址:http://www.swig.org/download.html
我的博客资源提供的swig工具资源:http://download.csdn.net/download/qq_16064871/10046580
这篇博客的代码:http://download.csdn.net/download/qq_16064871/10044371
GitHub 的大神写示例代码:https://github.com/sureshjoshi/android-ndk-swig-example
系统环境变量的配置,加在path那里
E:\Android\sdk\platform-tools; 方便使用adb命令
C:\Program Files\Android\Android Studio\gradle\gradle-2.14.1;
F:\software\swigwin-3.0.2; swig编译需要
E:\Android\sdk\ndk-bundle; 这个是android studio 的自动下载的NDK目录,编译生成so需要
有了这些,我们可以在Android studio 的Terminal命令行操作。
注意:swig工具包解压就行,然后配置在path路径即可
编译生成接口jar的build配置如下
// For this to work, it's assumed SWIG is installed
// TODO: This only works when called from Command Line (gradlew runSwig)
task runSwig(type:Exec, dependsOn: ['createCoreWrapperDir']) {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("windows")) {
workingDir '/src/main/jni' // This implicitly starts from $(projectDir) evidently
commandLine 'cmd', '/c', 'swig'
args '-c++', '-java', '-package', 'com.swig.test', '-outdir', coreWrapperDir.absolutePath, 'Unix.i'
}
else {
commandLine 'swig'
args '-c++', '-java', '-package', 'com.swig.test', '-outdir', coreWrapperDir.absolutePath, "${projectDir}/src/main/jni/Unix.i"
}
}
有了这个配置:
可以在项目找到grade project 里面的 other 里面找到你的配置
双击编译即可,前提是你的android studio只打开一个,相信很多小伙伴都知道的吧。
自动编译生成的代码:
编译生成接口的包名,后面使用时候不能再改了,因为生成so是根据jni文件下下面Unix_wrap.cxx这个文件生成的。里面类的函数已经包括编译的包名,所以变了包名,使用时候报错。
生成jar时候记得在jni那个类里面加上加载库的代码,(这个先提前说了)
public class JniDmeoLibJNI {
static {
System.loadLibrary("JniDmeoLib");
}
public final static native long new_CTest();
public final static native void delete_CTest(long jarg1);
public final static native double CTest_getTest(long jarg1, CTest jarg1_, double jarg2, double jarg3);
public final static native long new_CoutputChar();
public final static native void delete_CoutputChar(long jarg1);
public final static native String CoutputChar_getfileName(long jarg1, CoutputChar jarg1_);
public final static native void CoutputChar_setfileName(long jarg1, CoutputChar jarg1_, String jarg2);
}
下面看一下完整的ndkBuild的配置
apply plugin: 'com.android.library'
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
ndk {
moduleName "JniDmeoLib"
abiFilters "armeabi"
}
}
lintOptions{
abortOnError false
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.2.1'
}
// Location of where to store the jni wrapped files
def coreWrapperDir = new File("${projectDir}/src/main/java/com/swig/test")
task createCoreWrapperDir {
coreWrapperDir.mkdirs()
}
// For this to work, it's assumed SWIG is installed
// TODO: This only works when called from Command Line (gradlew runSwig)
task runSwig(type:Exec, dependsOn: ['createCoreWrapperDir']) {
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("windows")) {
workingDir '/src/main/jni' // This implicitly starts from $(projectDir) evidently
commandLine 'cmd', '/c', 'swig'
args '-c++', '-java', '-package', 'com.swig.test', '-outdir', coreWrapperDir.absolutePath, 'Unix.i'
}
else {
commandLine 'swig'
args '-c++', '-java', '-package', 'com.swig.test', '-outdir', coreWrapperDir.absolutePath, "${projectDir}/src/main/jni/Unix.i"
}
}
在android studio 的Terminal命令终端去找到你要编译项目下的jni目录
然后输入ndk-build 即可,如下图
如果图片看不清楚,就可下面这个
D:\SwigNdkDemo>cd D:\SwigNdkDemo\buildNdk\src\main\jni
D:\SwigNdkDemo\buildNdk\src\main\jni>ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-14.
Android NDK: WARNING: APP_PLATFORM android-14 is higher than android:minSdkVersion 1 in D:/SwigNdkDemo/buildNdk/src/main/AndroidManifest.xml. NDK binaries will *not* be comptible wit
h devices older than android-14. See https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md for more information.
[armeabi] Install : libJniDmeoLib.so => libs/armeabi/libJniDmeoLib.so
D:\SwigNdkDemo\buildNdk\src\main\jni>
后面我又弄了一个library打包jar。把之前那个生成目录代码,原封不动拷贝到那个工程,记得包名也不变。
然后配置
task makeJar(type: Copy){
delete'libs/JniDmeoLib.jar'
from('build/intermediates/bundles/release/')
into('libs/')
include('classes.jar')
rename('classes.jar','JniDmeoLib.jar')
}
makeJar.dependsOn(build)
这个配置也是可以在other那里找到的。
包括编译其他项目
Error:Execution failed for task ':app:runSwig'.
> Process 'command 'cmd'' finished with non-zero exit value 1
出现这个错误的原因是
swig没有在系统环境变量里面path配置。
E:\Android\Sdk\ndk-bundle\build\core\add-application.mk
Error:(101) *** Android NDK: Aborting... . Stop.
Error:Execution failed for task ':app:compileDebugNdk'.
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException:
Process 'command 'E:\Android\sdk\ndk-bundle\ndk-build.cmd'' finished with non-zero exit value 2
这个错误主要是项目的目录层级太深,移动一下即可。这个问题比较奇怪。
编译so,就是使用Terminal命令行在进入要编译项目的jni文件夹。然后输入ndk-build,一回车就可以了。
F:\SVN Android studio\Android_Lib>cd F:\SVN Android studio\Android_Lib\jnidemo\src\main\jni
F:\SVN Android studio\Android_Lib\jnidemo\src\main\jni>ndk-build
Android NDK: Your Android application project path contains spaces: 'F: . studio/Android_Lib/jnidemo/src/main'
Android NDK: The Android NDK build cannot work here. Please move your project to a different location.
E:\Android\sdk\ndk-bundle\build\\..\build\core\build-local.mk:158: *** Android NDK: Aborting. . Stop.
出现上面这个错误,就是说你的工程需要换个目录编译,一般来说目录层级不能太深
编译成功的结果
F:\Android_Lib>cd F:\Android_Lib\jnidemo\src\main\jni
F:\Android_Lib\jnidemo\src\main\jni>ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-14.
Android NDK: WARNING: APP_PLATFORM android-14 is higher than android:minSdkVersion 1 in F:/Android_Lib/jnidemo/src/main/AndroidManifest.xml. NDK binaries will *not* be comptible
with devices older than android-14. See https://android.googlesource.com/platform/ndk/+/master/docs/user/common_problems.md for more information.
[arm64-v8a] Install : libcurvelib.so => libs/arm64-v8a/libcurvelib.so
[x86_64] Install : libcurvelib.so => libs/x86_64/libcurvelib.so
[mips64] Install : libcurvelib.so => libs/mips64/libcurvelib.so
[armeabi-v7a] Install : libcurvelib.so => libs/armeabi-v7a/libcurvelib.so
[armeabi] Install : libcurvelib.so => libs/armeabi/libcurvelib.so
[x86] Install : libcurvelib.so => libs/x86/libcurvelib.so
[mips] Install : libcurvelib.so => libs/mips/libcurvelib.so
其他代码就不贴了。可能会有一些疏漏。还是自已尝试编译跑一遍好。
我博客关于swig文章还是有几篇,有需要的可以看一下。