分享

NDK

 mediatv 2016-07-18

NDK-JNI实战教程(一) 在Android Studio运行第一个NDK程序

NDK开发,其实是为了项目需要调用底层的一些C/C++的一些东西;另外就是为了效率更加高些。如果你在Eclipse+ADT下开发过NDK就能体会到要么是配置NDK还要下载Cygwin, 配置Cygwin ,然后需要编译生成,相当的蛋疼。要么是直接用Eclipse开发,但是前期配置也是一堆;真心蛋疼。但是现在在AS上Eclipse能做到的这边都OK,这边有的Eclipse 上没有的,而且Google亲生的支持下只会越来越比Eclipse下开发NDK更加牛逼,所以你还不准备上手吗?

在AS开发NDK JNI也需要配置,不过相当Easy。第一步就是去官方下载个NDK包就可以了,像我的直接放在D盘就行了。关于怎么下载安装看这里 AD NDK会有介绍。

第二步就是就是直接写代码了。哈哈,你没听错,是这样的, 方便吧?至于下载下来的NDK怎么和AS工程关联,也就是一行配置的问题,后文有说明带你一步一步体验。

Let’s Go!!!

在AS中新建一个Project,然后再新建一个class为NdkJniUtils,在内部声明native方法(jni使用的定义,后面系列教程会细说)。

package io.github.yanbober.ndkapplication;

public class NdkJniUtils {
    public native String getCLanguageString();
}

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

public class MainActivity extends ActionBarActivity {
    private TextView mTextView;

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

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

        NdkJniUtils jni = new NdkJniUtils();

        mTextView.setText(jni.getCLanguageString());
    }
}

然后build project得到其中中间文件,我们关注的是.class文件。编译OK以后生成的class文件在AS工程的如下目录: NDKApplication\app\build\intermediates\classes\debug。然后接下来的步骤就是根据生成的class文件,利用javah 生成对应的 .h头文件。

点开AS的Terminal标签,默认进入到该项目的app文件夹下。我在windows平台下输入如下命令跳转到class中间文件生成路径:

xxxxx\app> cd build\intermediates\classes\debug

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

xxxxx\debug> javah -jni io.github.yanbober.ndkapplication.NdkJniUtils

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

io_github_yanbober_ndkapplication_NdkJniUtils.h

其内容为:

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

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

#ifdef __cplusplus
}
#endif
#endif

在工程的main目录下新建一个名字为jni的目录,然后将刚才的 .h文件剪切过来。 在jni目录下新建一个c文件,随意取名,我的叫jnitest.c 。然后编辑代码如下(后面会解释啥意思,这里重在工具使用):

#include "io_github_yanbober_ndkapplication_NdkJniUtils.h"
/*
 * Class:     io_github_yanbober_ndkapplication_NdkJniUtils
 * Method:    getCLanguageString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_io_github_yanbober_ndkapplication_NdkJniUtils_getCLanguageString
  (JNIEnv *env, jobject obj){
     return (*env)->NewStringUTF(env,"This just a test for Android Studio NDK JNI developer!");
  }

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

sdk.dir=D\:\\AndroidStdioSDK\\sdk
#add by 工匠若水
ndk.dir=D\:\\AndroidStdioSDK\\android-ndk-r10d-64bit

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

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

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

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

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

但是有些电脑好奇怪此时编译会报错,妹的,没辙,后来网上找到答案说这是NDK在Windows下一个bug,当只编译一个单一文件时出现,解决办法就是 再添加一个空的文件就行了,这个网站有介绍:NDK在Windows的一个bug。不过 你要是刚才能顺利编译就没必要蛋疼这个问题了。

好了,我的编译运行结果如下:

到此为止简单的体验AS下NDK开发的过程就结束了。期待下一篇再续深入。

(烦请令尊体谅作者劳动成果,转载麻烦声明文章链接。您的声明与讨论是鄙人写作的动力。JNI NDK系列文章依据时间及个人情况持续更新中......)


AmazingCounters.com
1
被顶起来的评论
  • 超级天才小浣熊

    博主你这篇帖子写的太棒了,居然没人顶,我帮你顶一下

    2015年7月12日回复转发
  • qingyu1625
    qingyu1625

    厉害,这篇是我看过的最正确的,最简单易懂的了

    2015年7月30日回复转发
  • 曌婉
    曌婉

    javah -jni io.github.yanbober.ndkapplication.NdkJniUtils,出现错误:错误: 找不到 'io.github.yanbober.ndkapplication.NdkJniUtils' 的类文件。

    2015年8月14日回复转发
  • 曌婉
    曌婉

    百度半天无果,博主,求解答啊

    2015年8月14日回复转发
  • 是的
    是的

    回复 曌婉: io.github.yanbober.ndkapplication这个再你的工程中要替换成你自己的报名吧

    2015年9月16日回复转发
  • KiLo_DaRiz

    请问解压的ndk包到底要放在什么目录下?怎么我放在d盘还是自定义的目录都无法被识别出来(注studio放在d:\software\android-studio目录里)。

    2015年9月23日回复转发
  • passerbywhu
    passerbywhu

    赞~~通俗易懂~非常感谢~

    2015年10月13日回复转发
  • UperOne

    我的编译通过了,但没有生成so是怎么回事,整个文件夹都是可写的,不存在不能创建文件的情况。

    2015年10月24日回复转发
  • 无的放矢

    ndk安装路径不能带空格!windows真是坑啊

    2015年10月26日回复转发
  • 无的放矢

    64位windows的abiFilters要加上"x86_64"

    2015年10月26日回复转发
  • 清子

    很不错的帖子

    2015年11月10日回复转发
  • Rinvay

    我遇到这个错误

    Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools./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

    2015年11月13日回复顶(2)转发
  • 就是我

    回复 UperOne: 嗯,我的也是这样,没有生成文件夹和so 文件, 请问你解决了吗?

    2015年11月26日回复转发
  • 欢乐的公鸡

    我用的Android Studio 1.5,并且gradle用了最新版本2.9. 在gradle.properties增加android.useDeprecatedNdk=true。其实你只需要仔细看错误输出,就有这个提示。

    2015年12月14日回复转发
  • corvofeng
    corvofeng

    写的真好, 我之前在google了好久, 老外写的那个没能看懂, 但你的博客看了一遍, 就学会了, 真的开心啊, 感觉到些提高了

    2015年12月14日回复转发
  • love_渔舟唱晚

    java8遇到个问题:
    UNEXPECTED TOP-LEVEL EXCEPTION:
    Error:com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
    =====================================================
    搜索了一下:
    the reason of this problem is java version. It should be jdk 1.7 or less. uninstall your 1.8 version and install 1.7 and change the path in environment variables.

  • NC
    NC

    最关键的地方没说!也就一个基础简谱的东西

  • 12312
    12312

    .mk 文件要用到,

  • 一个路人甲
    一个路人甲

    写的什么鬼啊 坑人么? getCLanguageString 不用static 你能生成.h文件?

  • 慢慢学
    慢慢学

    回复 一个路人甲: 谁告诉你必须static?别人不会写你来写?

  • captain
    captain

    回复 KiLo_DaRiz: 要声明变量路径吧

  • 天下大同
    天下大同

    求助大神,我遇到这个错误,希望指导我一下,我不知所措了make.exe: *** No rule to make target `F:\StudioProjects\NDKTest\app\build\intermediates\ndk\debug\obj/local/armeabi-v7a/objs/YanboberJniLibName/F_\StudioProjects\NDKTest\app\src\main\jni', needed by `F:\StudioProjects\NDKTest\app\build\intermediates\ndk\debug\obj/local/armeabi-v7a/objs/YanboberJniLibName/F_\StudioProjects\NDKTest\app\src\main\jni\jnitest.o'. Stop.,是要使用.mk文件吗??为什么要使用.mk?谢谢

  • 天下大同
    天下大同

    回复 12312: 你好,我遇到这个错误,希望指导我一下,make.exe: *** No rule to make target `F:\StudioProjects\NDKTest\app\build\intermediates\ndk\debug\obj/local/armeabi-v7a/objs/YanboberJniLibName/F_\StudioProjects\NDKTest\app\src\main\jni', needed by `F:\StudioProjects\NDKTest\app\build\intermediates\ndk\debug\obj/local/armeabi-v7a/objs/YanboberJniLibName/F_\StudioProjects\NDKTest\app\src\main\jni\jnitest.o'. Stop.,是要使用.mk文件吗??为什么要使用.mk?谢谢

  • 流水

    为什么我的so库没有生成 Couldn't load JniLibName from loader dalvik.system.PathClassLoader[dexPath=/data/app/com.scott.testndk-2.apk,libraryPath=/data/app-lib/com.scott.testndk-2]: findLibrary returned null 很郁闷

  • 锋子
    锋子

    之前试的时候用自己的包名,结果出了问题,今天再试了,完全一样的包名、代码,就没有问题。应该是我之前不小心。非常感谢!

  • 远方的云-原号停用
    远方的云-原号停用

    技术更新了,现在:Gradle DSL method not found: 'defaultConfig()'。在官网对应文档也没更新好,谁知道现在怎么配置。

社交账号登录:


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多