一、
- linux开发环境搭建
- -----程序被运行要经历两个步骤(1.编译 2.链接)
- .java ---> .class ----> java虚拟机解释,链接
- .c ---> .o(中间文件)--> 根据不同的操作系统不同的cpu平台生产对应平台的可执行代码(windows .exe linux elf)
- 交叉编译: 在一种操作系统平台或者cpu平台下 编译生成 另外一个平台(cpu)可以运行的二进制代码
- 工具一: 交叉编译的工具链: NDK
- 在ndk的交叉编译的工具链里面 有很多.sh 的linux系统下的脚本文件.
- 要在windows下使用ndk的工具,必须要提供一个工具(linux环境的模拟器)
- 工具二: cygwin(windows下linux系统环境的模拟器, 主要是为了能够运行ndk的工具).安装 devel shell
- linux 特点:所有的设备 硬件 都是以文件的方式定义的.
- 工具三: cdt(c/c++ develop tools) eclipse 的一个插件 用来让c\c++代码 语法高亮显示.
- adt(android develop tools)
- -----程序被运行要经历两个步骤(1.编译 2.链接)
- 配置sygwin的环境变量:sygwin的安装目录下的etc子目录下的profile文件第32行添加ndk的目录
- PATH="/usr/local/bin:/usr/bin:/cygdrive/d/heima/android/JNI/ziliao/android-ndk-r7b:${PATH}"
- 蓝色部分为ndk的解压目录。cygdrive表示的是linux下的盘符
- ndk-helloworld调用C代码
- JNI的适配器文件:
- D:\heima\android\JNI\ziliao\android-ndk-r7b\platforms\android-8\arch-arm\usr\include\jni.h
- 6大步骤:
- 1.activity中定义一个native方法
- public native String callHelloFromC(); //由c代码实现
- 2.工程下新建jni目录,编写c代码,实现native中定义的方法. 注意方法名。
- jstring Java_com_itheima_ndkhelloworld_MainActivity_callHelloFromC(JNIEnv* env,jobject obj){
- return (*(*env)).NewStringUTF(env,"hello from c.");
- // return (*env)-> NewStringUTF(env,"hello from c.");等价于上一句代码,开发常用
- }
- 3.将写好的c代码编译成二进制可执行文件 -> .so
- 使用交叉编译工具编译.c文件。cd cygdrive/f
- 4.jni目录下编写Android.mk文件,将c代码编译成 .so文件。mk写法参照ndk的
- LOCAL_MODULE := Hello //可随便起
- LOCAL_SRC_FILES := Hello.c
- 5.activity中通过静态代码块 加载 动态库
- static{ System.loadLibrary("Hello"); } //去掉前后缀
- 6.调用c代码
- 直接调用native的方法名。
- 1.activity中定义一个native方法
- native方法名出现下划线的问题: call_from_c。在Hello.c文件中加1。MainActivity_call_1From_1c
- JNI的适配器文件:
- 采用javah生成头文件。
- dos命令下,进到activity的 classes目录,执行 javah com.itheima.ndkhelloworld2.MainActivity,生成头文件获取签名,一定要在classes文件下
- 拷贝生成的.h文件到工程的jni目录,并在 Hello.c 中引用 .h文件
- Android.mk文件
- JNI开发常见的错误
- 忘记创建Android.mk文件或Android.mk文件为空
- 中文的回车或者换行
- java.lang.UnsatisfiedLinkError: hello
- 忘记加载了c代码的.so库 或者 函数的签名不正确,没有找到与之对应的c代码
- 没有找到对应的c代码库
- *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***07-30 11:53:17.898: INFO/DEBUG(31): Build fingerprint: 'generic/sdk/generic/:2.2/FRF91/43546:eng/test-keys'
- c代码里面有严重的逻辑错误,产生内存的泄露.
- make: *** [obj/local/armeabi/objs/Hello/Hello.o] Error 1
- 编译的时候 程序出现了问题,c语言的语法有问题
- c语言代码编译错误的时候 先去解决第一个错误.
- java传递数据给c语言,c返回数据给java
- 在c中使用logcat打印日志?
- public native int add(int x , int y);
- c代码的int 类型和java的int类型不需转换
- JNIEXPORT jint JNICALL Java_com_itheima_ndk3_DataProvider_add(JNIEnv * env, jobject jobj, jint x, jint y){
- LOGI("int x = %d", x);
- LOGD("int y = %d", y);
- return x+y;
- }
- public native String sayHello(String name);
- char* cstr = Jstring2CStr(env,jstr);
- LOGI(cstr);
- strcat(cstr," hello"); //导入 <stdlib.h> 文件
- LOGI(cstr);
- return (*env)->NewStringUTF( env , cstr );
- public native int[] getArrayFromc( int[] arr );
- jint* arrint = (*env)->GetIntArrayElements(env,jarr,0);
- int len = (*env)->GetArrayLength(env,jarr);
- int i;
- for(i=0;i<len;i++){
- LOGI( "arr[%d]=%d" , i , arrint[i] );
- *(arrint+i)+=10;
- }
- return jarr;
- 实际开发流程
- c语言回调用java方法.
- c语言回调java的一个应用场景.
- 如果有一个操作已经有方便的java实现,才用c调用java可以避免重复发明一个轮子.
- c语言回调java的第二个应用场景.
- 想在c代码里面通知界面更新ui.
- 哪个对象调用了本地方法,哪个对象就是 jobject,不是同一个类中的方法调用,c中使用AllocObject类
- jobject (*AllocObject)(JNIEnv*, jclass);
- c调用java的静态方法:
- void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
- c语言回调java的一个应用场景.