NDK入门(Android Studio)
来源:互联网 发布:蔡夫人知乎 编辑:程序博客网 时间:2024/06/11 19:56
JNI介绍
JNI概念 : Java本地接口,Java Native Interface, 它是一个协议, 该协议用来沟通Java代码和外部的本地C/C++代码, 通过该协议 Java代码可以调用外部的本地代码, 外部的C/C++ 代码可以调用Java代码。
C和Java的侧重 :
– C语言 : C语言中最重要的是 函数 function;
– Java语言 : Java中最重要的是 JVM, class类, 以及class中的方法;
C与Java如何交流 :
– JNI规范 : C语言与Java语言交流需要一个适配器, 中间件, 即 JNI, JNI提供了一种规范;
– C语言中调用Java方法 : 可以让我们在C代码中找到Java代码class中的方法, 并且调用该方法;
– Java语言中调用C语言方法 : 同时也可以在Java代码中, 将一个C语言的方法映射到Java的某个方法上;
– JNI桥梁作用 : JNI提供了一个桥梁, 打通了C语言和Java语言之间的障碍;
JNI中的一些概念 :
– native : Java语言中修饰本地方法的修饰符, 被该修饰符修饰的方法没有方法体;
– Native方法 : 在Java语言中被native关键字修饰的方法是Native方法;
– JNI层 : Java声明Native方法的部分;
– JNI函数 : JNIEnv提供的函数, 这些函数在jni.h中进行定义;
– JNI方法 : Native方法对应的JNI层实现的 C/C++方法, 即在jni目录中实现的那些C语言代码;
NDK详解
1.交叉编译库文件
C代码执行 : C代码被编译成库文件之后, 才能执行, 库文件分为动态库 和静态库 两种;
– 动态库 : unix环境下.so 后缀的是动态库, windows环境下.dll 后缀的是动态库; 动态库可以依赖静态库加载一些可执行的C代码;
– 静态库 :.a 后缀是静态库的扩展名;
库文件来源 : C代码 进行 编译 链接操作之后, 才会生成库文件, 不同类型的CPU 操作系统 生成的库文件是不一样;
– CPU分类 : arm结构, 嵌入式设备处理器; x86结构, pc 服务器处理器; 不同的CPU指令集不同;
– 交叉编译 :windows x86编译出来的库文件可以在arm平台运行的代码;
– 交叉编译工具链 : Google提供的 NDK 就是交叉编译工具链, 可以在linux环境下编译出在arn平台下执行的二进制库文件;
NDK作用 : 是Google提供了交叉编译工具链, 能够在linux平台编译出在arm平台下执行的二进制库文件;
2.NDK优点:
1.java易被反编译,C/C++反编译难度大
2.调用第三方库,如OpenCV是用C/C++写
3.方便代码调用,c/c++所写库,可被Android/iOS所调用
3.NDK使用场合
NDK就是可以直接使用底层接口,主要用来开发大型游戏
SDK提供的是Java的接口,主要用来开发常见的应用,如QQ、微信等
如果要区分,NDK适合有大量计算和图形计算的应用,除此之外的都适合使用SDK
NDK下载
下载链接:http://www.android-dev.cn/tools/sdk/ndk/index.html
之后就可以选择适合的版本了,下载完了之后直接是一个zip的压缩包,解压即可。
编译环境配置
点击OK之后,在local.properties文件中看到:
NDK环境搭建还有最后一步,在gradle.properties的文件末尾加上android.useDeprecatedNdk=true。
这样NDK的编译环境就搭建好了。
第一个NDK项目
1、创建一个Android项目
2、创建JNI目录,放置所需要的c/c++/头文件等
3、编写nativejava层方法
4、生成JNI头文件
1 ) 编写java Native代码
2)介绍一个命令javah
首先创建一个工程,这个和普通的Android工程一样,就不说明。
然后新建一个NdkString类,这个类是我自定义的。写上一些代码。
public class NdkString { //java调C中的方法都需要用native声明且方法名必须和c的方法名一样 public static native String getFromC();}
写完之后重新Make Project,NdkString的class文件就会生成。
...\app\build\intermediates\classes\debug\com\example\ndk
在这个目录下,就能看到所有编译好的class文件。
然后就是生成.h文件,在Android Studio打开Terminal命令行工具,打开步骤是View->Tool Windows->Terminal (或直接按Alt+F12)。
然后在命令行中先进入到工程的main目录下
输入命令:javah -d jni -classpath 自己编译后的class文件的绝对路径
javah -d jni -classpath ..\app\build\intermediates\classes\debug com.example.ndk.NdkString(注意debug后的空格)
命令行中是直接进入到了工程的main目录下(在哪个目录下运行就会在哪个目录下自动生成jni文件夹),按回车之后就会在main目录下生成jni文件夹,同时生成.h文件。
这个文件.h文件不需要做任何修改,默认即可。
现在我们来写一个test的C文件Hello.c同.h文件一样放到jni文件夹下,代码如下:
#include "com_example_ndk_NdkString.h"JNIEXPORT jstring JNICALL Java_com_ht_asndk_NdkString_getFromC (JNIEnv *env, jclass jclass) { return (*env)->NewStringUTF(env, "这是我测试的jni");}
函数就是上面定义的native方法getFromC(),我们可以从.h文件中copy函数的引用到.c文件中。
/* * Class: com_example_ndk_NdkString * Method: getFromC * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_ndk_NdkString_getFromC (JNIEnv *, jclass);#ifdef __cplusplus}#endif#endif
这样我们就写完了.c文件,这时我们要在NdkString.java里加上一个static的代码块。
public class NdkString { static { System.loadLibrary("Hello"); } public static native void updateFile(String path); public static native String getFromC();}
用来调用刚编写的Hello.c。
最后在构建文件中的默认配置中加上:
//ndk编译生成.so文件 ndk { moduleName "Hello" //生成的so名字 abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库。 }
android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.example.ndk" minSdkVersion 19 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { moduleName "Hello" //生成的so名字 ldLibs "log"//实现__android_log_print abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库。 } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}
接着再用Make Project编译就可以发现在与classes相同的目录下新建了一个ndk的目录,在里面可以找到你设定好的各种体系下的.so文件和自动生成的Android.mk。
但是这里要注意一个地方,如果你要生成.so文件的时候,报出了下面的错误的话:
那么我们还需要在jni目录下再创建一个空的.c文件,名字可以随便,这可能是一个开发的bug吧,默认需要两个.c文件。
到这里,通过jni调C就完成了,现在我们来测试一下,写个Button通过点击显示一下调用的C:
public class MainActivity extends AppCompatActivity { private Button bt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt = (Button) findViewById(R.id.bt); } public void onClick(View view) { bt.setText(NdkString.getFromC()); }}
这样我们的第一个NDK项目就完成了。
log打印
相信很多人在刚开始学习Android JNI编程的时候,需要输出Log,在百度Google搜索的时候都是说需要在Android.mk中加入LOCAL_LDLIBS+= -L$(SYSROOT)/usr/lib -llog ,其实这是在eclipse开发上的方式,Android Studio并不是这么使用。
Android Studio的Android.mk是自动生成的,就算修改也是没用了,实际Android Studio的Android.mk是根据gradle文件生成的,那么就需要修改gradle文件。
如果不修改gradle,直接使用__android_log_print就会报错。
Error: undefined reference to '__android_log_print'
现在只需要在jni Module中得build.gradle 添加一些代码即可实现输出Log
build.gradle文件完成代码:
android { compileSdkVersion 25 buildToolsVersion "25.0.2" defaultConfig { applicationId "com.example.ndk" minSdkVersion 19 targetSdkVersion 25 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" ndk { moduleName "Hello" //生成的so名字 ldLibs "log"//实现__android_log_print abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种abi体系结构下的so库。 } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }}
ldLibs “log” 是关键代码
c文件中的修改,如何用c添加log
#include "com_example_ndk_NdkString.h"#include <android/log.h>#define TAG "HTG"#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)JNIEXPORT jstring JNICALL Java_com_ht_asndk_NdkString_getFromC (JNIEnv *env, jclass jclass) { LOGV("hello log from C"); return (*env)->NewStringUTF(env, "这是我测试的jni");}
这句代表应用log的头文件,这样就可以使用print的函数了。
#include <android/log.h>
这两句定义宏,将函数和标签申请好,ANDROID_LOG_VERBOSE代表log的等级是verbose。LOGV()中就只用输出log信息了。
#define TAG "HTG"#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
LOGV("hello log from C");
编译运行:
log确实打印成功了。
结束语:本文仅用来学习记录,参考查阅。
- NDK入门(Android Studio)
- NDK快速入门(android studio)
- Android Studio NDK开发入门
- Android Studio NDK入门学习
- Android Studio NDK开发入门
- Android Studio NDK 入门demo
- Android Studio NDK 入门demo
- Android的NDK入门配置(Android Studio环境)
- 使用Android Studio开发ndk-Jni(入门)
- Android studio如何导出.so库(NDK开发入门)
- Android Studio NDK JNI开发入门记录
- android studio NDK 配置及入门案例
- Android Studio NDK,JNI编程入门
- Android studio之Jni/ndk入门
- Android Studio NDK开发简单入门
- Android Studio 2.2 NDK CMake方式入门
- Android Studio 进行NDK开发入门
- Android Studio 2.2 NDK CMake方式入门
- 《快学Scala》习题详解 第11章 操作符
- springmvc使用json
- Java中的static关键字
- 字符数据类型
- Android (ImageLoader、Fresco、Gilde)三大图片缓存原理、缓存对比
- NDK入门(Android Studio)
- 算法竞赛入门经典(刘汝佳)习题3-4 UVa455
- memset
- A
- python中添加tab模块
- Android硬件访问服务框架
- 九度OJ-1076-N的阶乘
- android之videoplayer视频实现示例收集
- VMR技术(Video Mixer Render)