对于Android studio中的ndk编译,是相对比较简单方便的一种方式之一:
在AS中新建一个Project,然后再新建一个class为NdkJniUtils,在内部声明native方法(jni使用的定义,后面系列教程会细说)。
<span style="font-size:18px;"><code class="language-java hljs has-numbering"><span class="hljs-keyword">package</span> io.github.yanbober.ndkapplication; <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">NdkJniUtils</span> {</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">native</span> String <span class="hljs-title">getCLanguageString</span>(); }</code></span>
在工程主文件Activity中写入如下代码调运JNI的东西显示在UI上。
<span style="font-size:18px;"><code class="language-java hljs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MainActivity</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActionBarActivity</span> {</span> <span class="hljs-keyword">private</span> TextView mTextView; <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span>(Bundle savedInstanceState) { <span class="hljs-keyword">super</span>.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) <span class="hljs-keyword">this</span>.findViewById(R.id.test); NdkJniUtils jni = <span class="hljs-keyword">new</span> NdkJniUtils(); mTextView.setText(jni.getCLanguageString()); } }</code></span>
然后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
其内容为:
<span style="font-size:18px;"><code class="language-c++ hljs vala has-numbering"><span class="hljs-comment">/* DO NOT EDIT THIS FILE - it is machine generated */</span> <span class="hljs-preprocessor">#include <jni.h></span> <span class="hljs-comment">/* Header for class io_github_yanbober_ndkapplication_NdkJniUtils */</span> <span class="hljs-preprocessor">#ifndef _Included_io_github_yanbober_ndkapplication_NdkJniUtils</span> <span class="hljs-preprocessor">#define _Included_io_github_yanbober_ndkapplication_NdkJniUtils</span> <span class="hljs-preprocessor">#ifdef __cplusplus</span> extern <span class="hljs-string">"C"</span> { <span class="hljs-preprocessor">#endif</span> <span class="hljs-comment">/* * Class: io_github_yanbober_ndkapplication_NdkJniUtils * Method: getCLanguageString * Signature: ()Ljava/lang/String; */</span> JNIEXPORT jstring<span class="hljs-constant"> JNICALL </span>Java_io_github_yanbober_ndkapplication_NdkJniUtils_getCLanguageString (JNIEnv *, jobject); <span class="hljs-preprocessor">#ifdef __cplusplus</span> } <span class="hljs-preprocessor">#endif</span> <span class="hljs-preprocessor">#endif</span></code></span>
在工程的main目录下新建一个名字为jni的目录,然后将刚才的 .h文件剪切过来。在jni目录下新建一个c文件,随意取名,我的叫jnitest.c 。然后编辑代码如下(后面会解释啥意思,这里重在工具使用):
<span style="font-size:18px;"><code class="language-c++ hljs scala has-numbering">#include <span class="hljs-string">"io_github_yanbober_ndkapplication_NdkJniUtils.h"</span> <span class="hljs-comment">/* * Class: io_github_yanbober_ndkapplication_NdkJniUtils * Method: getCLanguageString * Signature: ()Ljava/lang/String; */</span> JNIEXPORT jstring JNICALL Java_io_github_yanbober_ndkapplication_NdkJniUtils_getCLanguageString (JNIEnv *env, j<span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">obj</span>){</span> <span class="hljs-keyword">return</span> (*env)->NewStringUTF(env,<span class="hljs-string">"This just a test for Android Studio NDK JNI developer!"</span>); }</code></span>
接下来在工程的local.properties文件中添加NDK路径(上面下载好的那个NDK),类似其中的SDK路径一样,我的添加后如下:
<span style="font-size:18px;"><code class="language-java hljs has-numbering">sdk.dir=D\:\\AndroidStdioSDK\\sdk #add by ndk.dir=D\:\\AndroidStdioSDK\\android-ndk-r10d-<span class="hljs-number">64</span>bit</code></span>
接下来在app module目录下的build.gradle中设置库文件名(生成的so文件名)。找到gradle文件的defaultConfig这项,在里面添加如下内容:
<span style="font-size:18px;"><code class="language-groovy hljs lasso has-numbering">defaultConfig { <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span> ndk{ moduleName <span class="hljs-string">"YanboberJniLibName"</span> <span class="hljs-comment">//生成的so名字</span> abiFilters <span class="hljs-string">"armeabi"</span>, <span class="hljs-string">"armeabi-v7a"</span>, <span class="hljs-string">"x86"</span> <span class="hljs-comment">//输出指定三种abi体系结构下的so库。目前可有可无。</span> } }</code></span>
现在生成的so库名字也有了,那就去代码的NdkJniUtils Java文件添加静态初始化load代码,添加如下:
<span style="font-size:18px;"><code class="language-java hljs has-numbering"><span class="hljs-keyword">static</span> { System.loadLibrary(<span class="hljs-string">"YanboberJniLibName"</span>); <span class="hljs-comment">//defaultConfig.ndk.moduleName</span> }</code></span>
好了,到此AS下NDK JNI开发的代码编写和设置就OK了,接下来就是编译工程运行就可以了。
但是有些电脑好奇怪此时编译会报错,妹的,没辙,后来网上找到答案说这是NDK在Windows下一个bug,当只编译一个单一文件时出现,解决办法就是再添加一个空的文件就行了,这个网站有介绍:NDK在Windows的一个bug。不过你要是刚才能顺利编译就没必要蛋疼这个问题了。
好了,我的编译运行结果如下:
到此为止简单的体验AS下NDK开发的过程就结束了。期待下一篇再续深入。