Android Studio加入jni模块并调试jni代码

最新Android Studio支持jni啦! 但是google上搜索资料是说使用experimental版本插件(Experimental Plugin User Guide)来集成jni模块,我试过的确好用,会自动帮你生成对应的jni方法,不用使用javah生成头文件,再用ndk工具编译出so库再使用了。但是experimental版本插件现在还在测试中,而且进度缓慢,另外对build.gradle的配置也和普通的不一样,不知道是否有不稳定的情况。

然而,最近有个同事在研究一门技术时发现普通的android gradle插件也可以加入jni模块,和experimental版本插件差不多。瞬间觉得很高大上,但是google有没用相关的说明,觉得奇怪,莫非也是在测试阶段?管它呢,先知道一下怎么玩再说。

运行环境

  • Android Studio 2.0
  • android build tool 插件版本:2.0.0(‘com.android.tools.build:gradle:2.0.0’)
  • gradle 2.10

步骤

  1. 使用studio新建一个普通的android应用项目
  2. 检查local.properties文件中是否有指定ndk的路径,如无参考sdk路径配置ndk的路径,如:

    1
    2
    ndk.dir=/Users/suyouxiong/Library/Android/sdk/ndk-bundle
    sdk.dir=/Users/suyouxiong/Library/Android/sdk
  3. 在build.gradle中添加ndk模块

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"
    defaultConfig {
    ... ...
    ndk {
    moduleName "hello-ndk"
    }
    }
    }

    此时sync会报错:

    Error:(14, 0) NDK integration is deprecated in the current plugin.

    Consider trying the new experimental plugin
    Set “android.useDeprecatedNdk=true” in gradle.properties to continue using the current NDK integration

    从错误信息可以看到要么使用experimental版本插件(Experimental Plugin User Guide),要么是在gradle.properties添加android.useDeprecatedNdk=true配置。这里我们是要用平常的插件来集成jni,所以采用后面的解决方法。在项目根目录的gradle.properties文件添加android.useDeprecatedNdk=true,再次sync问题解决。

  4. src/main目录下创建jni目录用于存放本地代码,也可以选中app之后执行File > New > Folder > JNI Folder创建

  5. 在MainActivity中加载jni模块并声明native方法:

    1
    2
    3
    4
    5
    static {
    System.loadLibrary("hello-ndk");
    }
    private native String getStringNative();

    此时studio会提示找不到该方法。使用快捷键alt+enter,这时会弹出解决方法列表,选择创建c方法,studio会自动创建一个和模块名相同的c文件,但并不会自动创建方法。

  6. 手动编写c方法,如果没有显式去配置java方法和c方法的对应关系,c方法名默认应该是Java+包路径(.用下划线_替换)+类名+加方法名,对应getStringNative方法,这样写:

    1
    2
    3
    4
    5
    JNIEXPORT jstring JNICALL Java_com_meizu_flyme_awesomendk_MainActivity_getStringNative(JNIEnv *env, jobject instance) {
    // TODO
    return (*env)->NewStringUTF(env, "Hello from JNI !");
    }

    ps:如果你是copy上面这段代码,注意方法名要和你应用的实际情况相符

  7. 在MainActivity中使用getStringNative方法,直接使用一个TextView来显示即可:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ... ...
    TextView tv = (TextView) findViewById(R.id.hello_ndk);
    tv.setText(getStringNative());
    }
  8. 运行,ok

jni代码调试

有个同事突然和我说现在studio可以调试本地代码,我立马感到吃惊。虽然我不写jni模块,但是可以让大家知道怎么回事啊。

  1. 首先在build.gradle中打开jni调试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    android {
    ... ...
    buildTypes {
    release {
    ... ...
    }
    debug {
    jniDebuggable true
    }
    }
    }
  2. 选择Run > Edit Configurations,进入运行调试设置窗口,选择Debugger便签页,在debug type下拉选项中选择native,此时你可能会看到下面的error(如果没有那么可以退出设置,跳过后面步骤直接debug运行调试了):

  3. studio给我们提供了快速解决方法,点击error信息后面的fix按钮,弹出相关包的安装信息,和安装sdk中的其它工具一样,选择Accept,点击下一步进行安装

  4. 安装完成后回到Run > Edit Configurations窗口,发现error解决了,这时需要把debug type选回Java,因为app这个运行配置应该对应java代码的(这是我后面才明白过来,在Android Application下面还有个Android Native,这个才是配置native运行配置的,前面的操作无非是要安装那个c++调试包)

  5. 安装完之后点击OK按钮退出Run > Edit Configurations窗口,回到主窗口,在运行配置选择下拉框就多出了native的配置项

  6. 选择app-native,在c代码打上断点,开始调试咯

  7. 进入Run > Edit Configurations窗口看看app-native的配置,会发现其debug type默认是Hybrid,另外还有native选择,经过测试选择native也是可以调试的,但是只能调试c代码,不能调试java代码,而Hybrid是都可以的(好方便)。

以上

想想还是附上源码作为参考吧:https://github.com/you-x/AwesomNdk

Comments