Android Studio运行NDK程序,简单的JNI实例

一、JNI概述
JNI 是Java Native Interface的缩写,中文翻译为“Java本地调用”,JNI 是本地编程接口。它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行互操作。就是说,JNI是一种技术,通过这种技术可以做到两点:
1.Java程序中的函数可以调用Native语言写的函数,Native一般指的是C/C++编写的函数。
2.Native程序中的函数可以调用Java层的函数,也就是说C/C++程序可以调用Java函数。

二、JNI应用

1、在AS中新建一个Project,然后再新建一个class为NdkJniUtils,在内部声明native方法。

public class NdkJniUtils {
    public native String getCLanguageString();
    public native int getAdd(int x, int y);
}

2、在工程主文件Activity中写入如下代码调运JNI的东西显示在UI上。

public class MainActivity extends Activity {
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) this.findViewById(R.id.tv1);

        NdkJniUtils jni = new NdkJniUtils();

        mTextView.setText(jni.getCLanguageString()+"\n3和4相加是"+jni.getAdd(3,4));
    }
}


3、然后build project得到其中中间文件,我们关注的是.class文件。编译OK以后生成的class文件在AS工程的如下目录:

NDKApplication\app\build\intermediates\classes\debug


4、然后接下来的步骤就是根据生成的class文件,利用javah生成对应的 .h头文件。点开AS的Terminal标签,默认进入到该项目的app文件夹下。
xxxxx\app> cd build\intermediates\classes\debug


5、然后执行如下javah命令生成h文件。

xxxxx\debug> javah -jni com.haier.oet.androidplayerground.NdkJniUtils


6、执行完之后你可以在文件夹NDKApplication\app\build\intermediates\classes\debug下看见生成的 .h头文件为:

com_haier_oet_androidplayerground_NdkJniUtils.h

其内容为:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_haier_oet_androidplayerground_NdkJniUtils */

#ifndef _Included_com_haier_oet_androidplayerground_NdkJniUtils
#define _Included_com_haier_oet_androidplayerground_NdkJniUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_haier_oet_androidplayerground_NdkJniUtils
 * Method:    getCLanguageString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_haier_oet_androidplayerground_NdkJniUtils_getCLanguageString
  (JNIEnv *, jobject);

/*
 * Class:     com_haier_oet_androidplayerground_NdkJniUtils
 * Method:    getAdd
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_haier_oet_androidplayerground_NdkJniUtils_getAdd
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

7、在工程的main目录下新建一个名字为jni的目录,然后将刚才的 .h文件剪切过来。在jni目录下新建一个c文件,随意取名,我的叫jnitest.c。然后编辑代码如下:

#include "com_haier_oet_androidplayerground_NdkJniUtils.h"
/*
 * Class:     io_github_yanbober_ndkapplication_NdkJniUtils
 * Method:    getCLanguageString
 * Signature: ()Ljava/lang/String;
 */

JNIEXPORT jstring JNICALL Java_com_haier_oet_androidplayerground_NdkJniUtils_getCLanguageString
        (JNIEnv *env, jobject obj){
    return (*env)->NewStringUTF(env,"我是一个Android Studio NDK JNI开发的程序!");
}

JNIEXPORT jint JNICALL Java_com_haier_oet_androidplayerground_NdkJniUtils_getAdd(JNIEnv *env, jobject obj,
                                                    jint x, jint y) {
    int res = x + y;
    return res;
}


8、接下来在工程的local.properties文件中添加NDK路径(上面下载好的那个NDK),类似其中的SDK路径一样,我的添加后如下:

sdk.dir=/Users/oet/Library/Android/sdk
ndk.dir=/Users/oet/Library/Android/android-ndk-r11b

9、接下来在app module目录下的build.gradle中设置库文件名(生成的so文件名)。找到gradle文件的defaultConfig这项,在里面添加如下内容:

defaultConfig {
    ......
	ndk{
	    moduleName "JniLibNameXM"       //生成的so名字
	    abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库。目前可有可无。
	}
}


10、现在生成的so库名字也有了,那就去代码的NdkJniUtils java文件添加静态初始化load代码,添加如下:

static {
    System.loadLibrary("JniLibNameXM");   //defaultConfig.ndk.moduleName
}

好了,到此AS下NDK JNI开发的代码编写和设置就OK了,接下来就是编译工程运行就可以了。运行效果如下图:

三、报错处理

1、Error:(14, 1) A problem occurred evaluating project ':app'.
> Error: NDK integration is deprecated in the current plugin.  Consider trying the new experimental plugin.  For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.  Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.
解决方法:
在gradle.properties加入如下配置:
android.useDeprecatedNdk=true


2、unsatisfiedlinkError错误
解决方法:
1.unsatisfiedlinkError:dll名,那说明你没有把dll放到合适的位置,一般就和要调用原生函数的类放在一起,当然前提是你成功的生成dll了。
2.unsatisfiedlinkError:方法名,这个时候你其实dll已经成功生成了,而且位置也正确,它的意思就是你没有定义那个函数,你可能会说,我明明定义了,其实当你发现问题所在,你只能自虐了,肯定是你在C文件中定义函数时有些字母大小写错了,因为其他地方是自动生成的,不会出错。(我犯这个问题是因为引用的时候包名写错了!)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二一点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值