Android JNI/NDK开发之基本姿势<一>
2016-10-23 09:57
302 查看
开发环境信息
列举下本篇文章编写的Demo基本信息
操作系统 | Windows 10 家庭中文版 |
---|---|
开发工具 | Android Studio 2.1 |
SDK | new |
NDK | new |
扫盲之SDK、JDK、NDK的区别
SDK | 软件开发工具包;英语全称:Software Development Kit |
---|---|
JDK | Java语言的软件开发工具包;英语全称:Java Development Kit |
NDK | 原生软件开发工具包;英语全称:Native Development Kit;被Google称为NDK |
XDK,都可以叫
SDK,可能为了有很好的区分,便有了
JDK、
NDK,所以我们有的时候常说的
SDK并不是特指
安卓开发工具包,而只是我们都是同行,交流的时候都知道指的是什么,其实你们会发现,我们常常接三方平台的时候,那些工具包也是叫
SDK,但可能我们在交流的时候就会加个前缀,比如:微信分享SDK、支付宝SDK、xxSDK。
学习目标
1.配置NDK环境并学会合理利用
Android Studio工具进行
NDK的编译
2.点击某个按钮显示由
native方法返回的一段文本信息;Java > native
3.点击某个按钮调用某个
native方法,在由此
native方法调用
java方法;java > native > java
创建工程并配置NDK路径
快速利用Android Studio创建一个简单的
Hello Word工程,相信这个大家都已经熟门熟路了,如果你还不知道使用
Android Studio,我只能说你太不
open了。
配置工程NDK有两种方法,和配置SDK一模一样,这里就说说两个
SDK
1 的配置方法吧
1.直接在
local.properties文件中手动配置
ndk.dir=E:\\Android\\sdk\\ndk-bundle //NDK路径
sdk.dir=E:\\Android\\sdk //SDK路径
2.Open Module Settings
选中工程名,鼠标右键>Open Module Settings或直接按下F4功能键
编写带有Native方法的类
1.创建JniDemoClass文件并创建一个
native方法
public native String getHelloWordText(),用来获取
Hello Word文本
public class JniDemo {
public native String getHelloWordText();
}
编译含有Native方法的类
javac JniDemo.java
得到
JniDemo.class文件后继续用
javah命令编译
JniDemo.class,格式:
javah package name + class name,示例:
javah com.jay.ndkdemo.JniDemo
其中
com.jay.ndkdemo是此类所在的包名,编译成功会在当前目录生成一个
*.h文件,这种文件类是C或C++所支持的头文件类型。内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jay_ndkdemo_JniDemo */
#ifndef _Included_com_jay_ndkdemo_JniDemo
#define _Included_com_jay_ndkdemo_JniDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_jay_ndkdemo_JniDemo
* Method: getHelloWordText
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_jay_ndkdemo_JniDemo_getHelloWordText
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
本文示例生成的名称叫:
com_jay_ndkdemo_JniDemo.h,很明显,以包名+类名生成一个文件名,我们在工程中创建一个文件夹
jni,此目录与工程中的
java目录同级,并把生成的
*.h文件放置到
jni文件夹中。
编写C/C++代码并实现*.h中声明的方法
创建*.c<C>或
*.cpp<C++>文件,编写Code,本文编写的是
*.c文件,也就是采用C语法来实现
#include <com_jay_ndkdemo_JniDemo.h>
/*
* Class: com_jay_ndkdemo_JniDemo
* Method: getHelloWordText
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_jay_ndkdemo_JniDemo_getHelloWordText
(JNIEnv * env, jobject obj)
{
return (*env)->NewStringUTF(env,"Hello Word From Jni");
}
简单说下编写方法:
1.include 下我们前面生成的
*.h文件
2.实现
*.h中未实现的方法,注意方法名要与
*.h中保持一致
到这里,我们的工作已经完成了90%,剩下的只是配置与调用了
NDK编译
这个时候我们就要发挥Android Studio工具的方便性了,怎么利用NDK编译了?前面我们已经配置好了
NDK路径,那么直接利用
Android Studio的菜单
build > Rebuild
JNIEXPORT jstring JNICALL Java_com_jay_ndkdemo_JniDemo_getHelloWordText
(JNIEnv * env, jobject obj)
{
return (*env)->NewStringUTF(env,"Hello Word From Jni");
}
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:compileDebugNdk'.
> 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.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug
其实这个错误信息中已经告诉我们怎么解决
Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration
叫我们在
gradle.properties文件中输入
android.useDeprecatedNdk=true,输入后我们再次编译,这次编译成功,但发现一个警告:
警告信息:
<code class="hljs applescript has-numbering">Warning: Native C/C++ source code <span class="hljs-keyword">is</span> found, <span class="hljs-keyword">but</span> <span class="hljs-keyword">it</span> seems <span class="hljs-keyword">that</span> NDK option <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> configured. Note <span class="hljs-keyword">that</span> <span class="hljs-keyword">if</span> you have an Android.mk, <span class="hljs-keyword">it</span> <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> used <span class="hljs-keyword">for</span> compilation. The recommended workaround <span class="hljs-keyword">is</span> <span class="hljs-keyword">to</span> remove <span class="hljs-keyword">the</span> default jni source code directory <span class="hljs-keyword">by</span> adding: android { sourceSets { main { jni.srcDirs = [] } } } <span class="hljs-keyword">to</span> build.gradle, manually compile <span class="hljs-keyword">the</span> code <span class="hljs-keyword">with</span> ndk-build, <span class="hljs-keyword">and</span> <span class="hljs-keyword">then</span> place <span class="hljs-keyword">the</span> resulting shared object <span class="hljs-keyword">in</span> src/main/jniLibs.</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><div class="save_code tracking-ad" style="display: none;" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
大概意思就是我们缺少一个文件:
Android.mk,但人家给了我们推荐的方法,那就是在对应module工程中的
build.gradle文件中添加如下代码:
<code class="hljs bash has-numbering"><span class="hljs-built_in">source</span>Sets { main { jni.srcDirs = [] } }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul><div class="save_code tracking-ad" style="display: none;" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>
添加后我们再次编译,这次编译成功并没错误也没警告,终于NDK编译通过了,我们查看编译结果:
\NdkDemo\app\build\intermediates\ndk
我们可以看到,生成了一系列的
*.so文件,是不是感觉很熟悉了?但我们发现
*.so文件名叫
libapp.so,这个文件名是怎么来的了?可以更改吗?答案是肯定的。
先说说默认文件名的生成格式:
lib + module name.so
更改默认文件名名称:
<code class="hljs lasso has-numbering">android { <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span> defaultConfig { <span class="hljs-attribute">...</span><span class="hljs-attribute">...</span> ndk { moduleName <span class="hljs-string">'jnidemo'</span><span class="hljs-comment">//自定义名称</span> } } }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><div class="save_code tracking-ad" style="display: none;" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
好,我们再次编译,编译完成后我们查看编译路径下,闷B了吧,没看到
ndk目录了,有人就会说了,你这个坑货,骗人的,友谊的小船说翻就翻。
<code class="hljs cs has-numbering">sourceSets { main { <span class="hljs-comment">// jni.srcDirs=[]</span> jniLibs.srcDir <span class="hljs-string">'src/main/jni_src'</span><span class="hljs-comment">//告知jni源码目录</span> } }</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><div class="save_code tracking-ad" style="display: none;" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>
还记得这个配置不,对,就是我们之前第一次编译的时候解决一个警告按照警告的推荐写的配置代码,只要改成和上面一样,编译后就又可以看到编译目录下的
ndk文件夹了,查看编译后的
*.so文件,发现文件名已经改了,并且生成的格式和我之前说的一样。
为什么我们按照推荐方法会有问题了?
1.可能是bug
2.我觉得应该是我们既然了默认的一些参数,当然就要对其它参数做出相应的修改
好了,看完这篇文章,我们基本实现了我们的学习目标的第一点,后面两点请看后续系列文章
此处
SDK包含NDK与安卓SDK
↩
After updating Android Studio to version 1.3.0
I am getting “NDK integration is deprecated in the current plugin” Error
add
gradle.propertiesfile to root folder of your project
add
'android.useDeprecatedNdk=true'to
gradle.propertiesfile
Here is my gradle.properties :
# Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. # Default value: -Xmx10248m -XX:MaxPermSize=256m # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true android.useDeprecatedNdk=true
And add it to root of your project :
![](http://i.stack.imgur.com/SKDLj.png)
相关文章推荐
- Android JNI/NDK开发之基本姿势<一>
- Android JNI/NDK开发之基本姿势<一>
- Android JNI/NDK开发之基本姿势<二>
- Android JNI/NDK开发之基本姿势
- 【android】NDK开发编译C++文件出现Type 'jint' could not be resolved和Unresolved inclusion: <jni.h>的解决办法
- android通讯录开发<一> 导出数据库
- Android gradle使用教程<一> 基本使用方法
- Android中NDK和JNI开发基本流程
- Android开发收集<一>
- Android <Android应用开发实战> 资源类型<一>
- NDK学习笔记<一> 初步认识JNI|成功搭建NDK开发环境
- Android React-Native系列之<一>零基础搭建React-Native开发环境
- Android OpenGL ES 简明开发教程 03 <3D绘图基本概念>
- Eclipse NDK 开发Unresolved inclusion:<jni.h>
- (转)Android开发工具——ADB(Android Debug Bridge) <一>概览
- android studio开发<一> 按钮事件
- Android_NDK问题:APP_BUILD_SCRIPT points to an unknown file: <project_path>/jni/Android.mk
- Android 插件平台技术 <一> 基本介绍和dynamic-load-apk介绍
- android NDK jni下的c文件 Unresolved inclusion:<jni.h>
- 【Android开发学习45】使用google语音识别引擎(Google Speech API)<一>