转载请注明出处:http://blog.csdn.net/allen315410/article/details/41826511
Android NDK开发经常因某些因素会出现一些意想不到的错误,很多时候调试这些错误的时候,显得比调试Java代码要复杂,一方面是导致错误的原因很多很杂,另一方面NDK开发涉及到C/C++代码的编写,很多程序员对此不熟悉。那么这篇博客就总结一下,在NDK开发中经常出现的一些问题,并且尝试提供一些正确的解决方案,方便在开发时能够快速定位到错误,更改错误,当然了,错误是多种多样的,很难把所有的错误都总结出来,在这里仅作为一个笔记吧,以后在NDK开发中发现一个错误或者解决一个错误后,我就在这里记录一下,日积月累,就不错了!
常见错误及解决方法
1,Android.mk文件不存在
/cygdrive/e/ndk/android-ndk-r10d/build/core/add-application.mk:199: *** Android NDK: Aborting... 。 停止。
解决方法:报这个错误就需要查看一下工程目录下的jni目录下,是否有Android.mk文件,或者Android.mk文件名是否输入错误了。
2,Android.mk文件配置出错
错误描述:/cygdrive/e/ndk/android-ndk-r10d/build/core/build-shared-library.mk:23: *** Android NDK: Missing LOCAL_MODULE before including BUILD_SHARED_LIBRARY in jni/Android.mk 。 停止。
解决方法:检查Android.mk文件配置信息。Missing LOCAL_MODULE表明LOCAL_MODULE配置出错,查看并修正。
3,C语言代码有错误
错误描述:[armeabi] Compile thumb : Hello <= Hello.c
jni/Hello.c: In function 'Java_com_example_ndk_MainActivity_java_1From_1JNI':
jni/Hello.c:17:9: warning: division by zero [-Wdiv-by-zero]
int i=5/0;
^
[armeabi] SharedLibrary : libHello.so
[armeabi] Install : libHello.so => libs/armeabi/libHello.so
解决方法:C语言报错通常错误信息很多,我们可以根据cygwin上的LOG定位到错误。
4,Java代码中没有找到C代码库
解决方法:说明Java代码在加载C代码库的时候弄粗了C代码库的名称,请在java层中改正。
5,C代码函数签名错误
错误描述:java.lang.UnsatisfiedLinkError: Native method not found: com.example.ndk.MainActivity.java_From_JNI:()Ljava/lang/String;
解决方法:Native method not found。这个应该不难吧,一看就知道是C语言中的函数签名出错了。
6,ndk版本问题
错误描述:Android NDK: WARNING: APP_PLATFORM android-19 is larger than android:minSdkVersion 8 in ./AndroidManifest.xml
[armeabi] Compile thumb : Hello <= Hello.c
[armeabi] SharedLibrary : libHello.so
[armeabi] Install : libHello.so => libs/armeabi/libHello.so
解决方法:这只是一个警告而已,不处理的话程序也照样运行。导致这个警告的原因是当前ndk的版本>工程中minSdkVersion,想要去掉这个警告就将minSdkVersion支持的最小版本号改成ndk版本号一致,当然了这是愚蠢的做法,但是我们可以使用ndk的低版本编译,也不太好。下面是个好的解决方法:
1,在工程目录jni下建立一个新的文件,文件名是 Application.mk
2,在Application.mk文件里加上这样的一句:
APP_PLATFORM := android-8
3,保存工程,编译一下,就看见这个警告没有了。
7,使用javah命令生成函数签名时,找不到class文件
错误描述:错误: 无法访问android.app.Activity
找不到android.app.Activity的类文件
解决方法:这个错误的具体原因应该没有找到对应的native方法所在的Java字节码文件,但是我这里确实路径是正确,还是报错了,很奇怪,不知道是不是Eclipse上的一个BUG。遇到这个问题时,可以这样解决,既然切换到\bin\classes目录下不行的话,那就切换到工程目录\src目录,再javah一下,这次居然生成了.h的头文件,不知道为什么这样,反正我测试的时候可行。
tip:获得本地方法头文件
jdk6.0:在Android工程的bin\classes目录下执行:javah 包名+类名
jdk7.0:在Android工程的src目录下执行:javah 包名+类名
8,中文乱码问题
错误描述:ndk开发中经常会在C语言代码中往Java代码返回一个中文字符串,偶尔在Java中调用的时候,程序结果会出现中文乱码情况,或者更有甚者导致程序直接崩溃掉,查看Log日志也是说明出现乱码的情况。
解决方法:
中文乱码的原因是英文C语言文件保存的格式不是UTF-8的格式,或者整个工程都不是UTF-8的格式,因为C语言jni传递字符串时采用的UTF-8编码,这一点可以在(*env)->NewStringUTF(env, "hello jni!")看出,NewStringUTF(env,char*)这个方法说明返回的是UTF-8编码形式的字符串。所以我们在建立工程的时候,或者新建一个C语言代码文件的时候,需要指定工程编码为UTF-8或者C语言代码文件的保存格式是UTF-8。
9,编码GBK的不可映射的字符
错误描述:编码GBK的不可映射字符。
解决方法:引起这个错误的原因是使用javah时没有指定java的编码集,这种情况下编译器自动根据windows默认的编码(GBK)编译,而Java支持UTF-8的编码集。解决这个问题的方法是在javah命令执行时为编译器指定一个编码集,使用javah命令的参数-encoding 编码集,如图
LOG日志的使用
上面列举了一些ndk开发中经常会遇见的问题以及解决方法,但是唯独没有列出的,也是最常见的错误,就是C语言代码中出现错误,这个不太好解决,而且出现的问题是各种各样,具体情况具体对待。已知在使用Java开发Android程序时,Google为了方便程序员调试,在SDK中提供了LOG输出功能,程序员用来输出程序中的日志使用。那么庆幸的是,Google在NDK中也提供了类似的LOG机制,帮助native层代码错误的定位。下面就尝试一下使用这个LOG机制。
在ndk解压目录下platforms\android-8\arch-arm\usr\include\android有个log.h的头文件,这个log.h的头文件用来管理C语言代码中的LOG输出,代码如下:
- #ifndef _ANDROID_LOG_H
- #define _ANDROID_LOG_H
- #include <stdarg.h>
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Android log priority values, in ascending priority order.
- */
- typedef enum android_LogPriority {
- ANDROID_LOG_UNKNOWN = 0,
- ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
- ANDROID_LOG_VERBOSE,
- ANDROID_LOG_DEBUG,
- ANDROID_LOG_INFO,
- ANDROID_LOG_WARN,
- ANDROID_LOG_ERROR,
- ANDROID_LOG_FATAL,
- ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
- } android_LogPriority;
- /*
- * Send a simple string to the log.
- */
- int __android_log_write(int prio, const char *tag, const char *text);
- /*
- * Send a formatted string to the log, used like printf(fmt,...)
- */
- int __android_log_print(int prio, const char *tag, const char *fmt, ...)
- #if defined(__GNUC__)
- __attribute__ ((format(printf, 3, 4)))
- #endif
- ;
- /*
- * A variant of __android_log_print() that takes a va_list to list
- * additional parameters.
- */
- int __android_log_vprint(int prio, const char *tag,
- const char *fmt, va_list ap);
- /*
- * Log an assertion failure and SIGTRAP the process to have a chance
- * to inspect it, if a debugger is attached. This uses the FATAL priority.
- */
- void __android_log_assert(const char *cond, const char *tag,
- const char *fmt, ...)
- #if defined(__GNUC__)
- __attribute__ ((noreturn))
- __attribute__ ((format(printf, 3, 4)))
- #endif
- ;
- #ifdef __cplusplus
- }
- #endif
- #endif /* _ANDROID_LOG_H */
上面的代码看不懂也没关系,我们只需要知道怎么用就行了。
1,在C语言代码中引用log.h的头文件,并且预定义LOG_TAG标记Tag名称,预定义输出规则:
2,用上面预定义的名称定义LOG输出的内容
- #include<stdio.h>
- #include<jni.h>
- #include"com_example_ndk_MainActivity.h"
- #include <android/log.h>
- #define LOG_TAG "System.out.c"
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
- JNIEXPORT jstring JNICALL Java_com_example_ndk_MainActivity_javaFromJNI(
- JNIEnv* env, jobject obj) {
- return (*env)->NewStringUTF(env, "hello jni!");
- }
- /*
- * Class: com_example_ndk_MainActivity
- * Method: java_From_JNI
- * Signature: ()Ljava/lang/String;
- */
- JNIEXPORT jstring JNICALL Java_com_example_ndk_MainActivity_java_1From_1JNI(
- JNIEnv* env, jobject obj) {
- LOGI("function called");
- LOGI("array init");
- char c1[3] = { 'a', 'b', 'c' };
- char c2[2] = { 'd', 'e' };
- LOGI("array init finish");
- LOGI("copy array");
- strcat(c1, c2); //把c2的内容放在c1的后面,要求c1长度>c2长度
- LOGI("copy array finish");
- return (*env)->NewStringUTF(env, "hello_jni__");
- }
上述的代码中
- #include <android/log.h>
- #define LOG_TAG "System.out.c"
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
是必须添加的,告诉编译器这里需要输出LOG,LOG的TAG标记是“System.out.c”,并且预定义LOGD(...)代表Debug输出,LOGI(...)代表Info输出。然后在C语言主题代码中就可以使用LOGD和LOGI了,传递字符串就可以了,需要注意的是传递的字符串要用英文字符,不支持中文。
3,在Android.mk文件中配置LOG输出
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := Hello
- LOCAL_SRC_FILES := Hello.c
- LOCAL_LDLIBS += -llog
- include $(BUILD_SHARED_LIBRARY)
注意:就一句 LOCAL_LDLIBS += -llog 就行了,但是必须得加在 include $(BUILD_SHARED_LIBRARY) 之前。
4,重新编译代码,运行看看效果
好了,我们在Logcat里面过滤出来System.out.c的TAG,可以看到在输出copy array之后程序停止了,说明LOGI("copy array");下面的strcat(c1, c2);出现了错误,这里需要修改代码中的错误,程序才能正确执行,是不是很方便啊?试试吧!
Android NDK 开发(三)--常见错误锦集合Log的使用【转】的更多相关文章
-
Android NDK开发三:java和C\C++交互
转自:http://www.cnblogs.com/shangdahao/archive/2013/05/02/3053971.html 1.定义native方法并加载动态链接库: public cl ...
-
Android NDK开发初识
神秘的Android NDK开发往往众多程序员感到兴奋,但又不知它为何物,由于近期开发应用时,为了是开发的.apk文件不被他人解读(反编译),查阅了很多资料,其中有提到使用NDK开发,怀着好奇的心理, ...
-
Android NDK开发
Android NDK 开发教程(极客学院) 一.Android NDK环境搭建 使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin( ...
-
Android NDK 开发(四)java传递数据到C【转】
转载请注明出处:http://blog.csdn.net/allen315410/article/details/41845701 前面几篇文章介绍了Android NDK开发的简单概念.常见错误及处 ...
-
!! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
http://hujiaweibujidao.github.io/blog/2013/11/18/android-ndk-and-opencv-development-3/ Android Ndk a ...
-
android NDK开发在本地C/C++源码中设置断点单步调试具体教程
近期在学android NDK开发,折腾了一天,最终可以成功在ADT中设置断点单步调试本地C/C++源码了.网上关于这方面的资料太少了,并且大都不全,并且调试过程中会出现各种各样的问题,真是非常磨人. ...
-
Android NDK开发Hello Word!
在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力.这里我们选择使用C+JAVA开发Android ...
-
android NDK开发环境搭建
android NDK开发环境搭建 2012-05-14 00:13:58 分类: 嵌入式 基于 Android NDK 的学习之旅-----环境搭建 工欲善其事必先利其器 , 下面介绍下 Eclip ...
-
Android NDK开发method GetStringUTFChars’could not be resolved
Android NDK开发method GetStringUTFChars'could not be resolved 图1 最近用到android的ndk,但在eclipse中提示method Ge ...
随机推荐
-
怎样去掉FireFox的导入向导
用robotframework的时候,用ride去打开firefox,但是每次都会出现导入向导,影响了后续的操作,怎样才能去掉呢? 网上查到的解决方案是:到firefox的profiles.ini所在 ...
-
php手册总结《安装与配置》
一:web服务器与php解释器的连接方式 有两个方法将 PHP 连接到服务器上. 1>通过SAPI模块来连接 对于很多服务器,PHP 均有一个直接的模块接口(也叫做 SAPI).这些服务器包括 ...
-
安卓四大组件的作用、安卓Service的作用
Activity好像是应用程式的眼睛,提供与user互动之窗. BroadcastReceiver好像是耳朵,接收来自各方的Intent. Service是在后台运行的. 一个Service 是一段长 ...
-
c# word文档与二进制数据的相互转换
最近项目出使用到了将word文档以二进制的方法存到数据库中,并再次读取出二进制数据转换为word文档.最后总结了一下,不多说看示例方法: 代码 , content.Length); ...
-
洛谷 P2904 [USACO08MAR]跨河River Crossing
题目 动规方程 f[i]=min(f[i],f[i−j]+sum) 我们默认为新加一头牛,自占一条船.想象一下,它不断招呼前面的牛,邀请它们坐自己这条船,当且仅当所需总时间更短时,前一头奶牛会接受邀请 ...
-
python:PATH、PYTHONPATH 和 sys.path 的区别
python:PATH.PYTHONPATH 和 sys.path 的区别 共同点 所有在它们的路径里面的 moduel 都可以被 import PATH 在 PATH 中的一些命令,例如 *.exe ...
-
centos crash debug
https://www.dedoimedo.com/computers/crash.html#mozTocId484074 http://people.redhat.com/anderson/cras ...
-
Impala 数值函数大全(转载)
官网:https://www.cloudera.com/documentation/enterprise/latest/topics/impala_math_functions.html 转载链接1: ...
-
Install Tomcat 6 on CentOS or RHEL --转载
source:http://www.davidghedini.com/pg/entry/install_tomcat_6_on_centos This post will cover installa ...
-
手把手教你写一个java的orm(五)
生成sql:where 上一篇里我们实现了生成insert的sql,下面要开始实现update,delete,select的sql语句了.但是这些语句有一个比较麻烦的地方是:它们一般后面都会有wher ...