android studio 使用NDK和swig编译c++示例

使用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

1、配置篇

系统环境变量的配置,加在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路径即可

2、编译接口jar

编译生成接口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 使用NDK和swig编译c++示例_第1张图片

双击编译即可,前提是你的android studio只打开一个,相信很多小伙伴都知道的吧。

自动编译生成的代码:

android studio 使用NDK和swig编译c++示例_第2张图片

编译生成接口的包名,后面使用时候不能再改了,因为生成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"
    }
}

2、生成so库

在android studio 的Terminal命令终端去找到你要编译项目下的jni目录

然后输入ndk-build 即可,如下图

android studio 使用NDK和swig编译c++示例_第3张图片

如果图片看不清楚,就可下面这个

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>

3、打包jar

后面我又弄了一个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那里找到的。

4、测试jar和so

android studio 使用NDK和swig编译c++示例_第4张图片

5、过程中遇到问题

包括编译其他项目

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文章还是有几篇,有需要的可以看一下。




你可能感兴趣的:(Android,移动开发,Android,常用开发技术,ndk,jni,android,studio,swig,android,ndk)