转载请注明出处:http://blog.csdn.net/allen315410/article/details/41826511 

Android NDK开发经常因某些因素会出现一些意想不到的错误,很多时候调试这些错误的时候,显得比调试Java代码要复杂,一方面是导致错误的原因很多很杂,另一方面NDK开发涉及到C/C++代码的编写,很多程序员对此不熟悉。那么这篇博客就总结一下,在NDK开发中经常出现的一些问题,并且尝试提供一些正确的解决方案,方便在开发时能够快速定位到错误,更改错误,当然了,错误是多种多样的,很难把所有的错误都总结出来,在这里仅作为一个笔记吧,以后在NDK开发中发现一个错误或者解决一个错误后,我就在这里记录一下,日积月累,就不错了!

常见错误及解决方法

 

1,Android.mk文件不存在

 
错误描述:Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: ./jni/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代码库

错误描述:AndroidRuntime(1171): java.lang.UnsatisfiedLinkError: Couldn't load Hello1 from loader dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ndk-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.ndk-1, /system/lib]]]: findLibrary returned null

解决方法:说明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输出,代码如下:

  1. #ifndef _ANDROID_LOG_H
  2. #define _ANDROID_LOG_H
  3. #include <stdarg.h>
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7. /*
  8. * Android log priority values, in ascending priority order.
  9. */
  10. typedef enum android_LogPriority {
  11. ANDROID_LOG_UNKNOWN = 0,
  12. ANDROID_LOG_DEFAULT,    /* only for SetMinPriority() */
  13. ANDROID_LOG_VERBOSE,
  14. ANDROID_LOG_DEBUG,
  15. ANDROID_LOG_INFO,
  16. ANDROID_LOG_WARN,
  17. ANDROID_LOG_ERROR,
  18. ANDROID_LOG_FATAL,
  19. ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
  20. } android_LogPriority;
  21. /*
  22. * Send a simple string to the log.
  23. */
  24. int __android_log_write(int prio, const char *tag, const char *text);
  25. /*
  26. * Send a formatted string to the log, used like printf(fmt,...)
  27. */
  28. int __android_log_print(int prio, const char *tag,  const char *fmt, ...)
  29. #if defined(__GNUC__)
  30. __attribute__ ((format(printf, 3, 4)))
  31. #endif
  32. ;
  33. /*
  34. * A variant of __android_log_print() that takes a va_list to list
  35. * additional parameters.
  36. */
  37. int __android_log_vprint(int prio, const char *tag,
  38. const char *fmt, va_list ap);
  39. /*
  40. * Log an assertion failure and SIGTRAP the process to have a chance
  41. * to inspect it, if a debugger is attached. This uses the FATAL priority.
  42. */
  43. void __android_log_assert(const char *cond, const char *tag,
  44. const char *fmt, ...)
  45. #if defined(__GNUC__)
  46. __attribute__ ((noreturn))
  47. __attribute__ ((format(printf, 3, 4)))
  48. #endif
  49. ;
  50. #ifdef __cplusplus
  51. }
  52. #endif
  53. #endif /* _ANDROID_LOG_H */

上面的代码看不懂也没关系,我们只需要知道怎么用就行了。

1,在C语言代码中引用log.h的头文件,并且预定义LOG_TAG标记Tag名称,预定义输出规则:

2,用上面预定义的名称定义LOG输出的内容

  1. #include<stdio.h>
  2. #include<jni.h>
  3. #include"com_example_ndk_MainActivity.h"
  4. #include <android/log.h>
  5. #define LOG_TAG "System.out.c"
  6. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
  7. #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
  8. JNIEXPORT jstring JNICALL Java_com_example_ndk_MainActivity_javaFromJNI(
  9. JNIEnv* env, jobject obj) {
  10. return (*env)->NewStringUTF(env, "hello jni!");
  11. }
  12. /*
  13. * Class:     com_example_ndk_MainActivity
  14. * Method:    java_From_JNI
  15. * Signature: ()Ljava/lang/String;
  16. */
  17. JNIEXPORT jstring JNICALL Java_com_example_ndk_MainActivity_java_1From_1JNI(
  18. JNIEnv* env, jobject obj) {
  19. LOGI("function called");
  20. LOGI("array init");
  21. char c1[3] = { 'a', 'b', 'c' };
  22. char c2[2] = { 'd', 'e' };
  23. LOGI("array init finish");
  24. LOGI("copy array");
  25. strcat(c1, c2); //把c2的内容放在c1的后面,要求c1长度>c2长度
  26. LOGI("copy array finish");
  27. return (*env)->NewStringUTF(env, "hello_jni__");
  28. }

上述的代码中

  1. #include <android/log.h>
  2. #define LOG_TAG "System.out.c"
  3. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
  4. #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输出

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE    := Hello
  4. LOCAL_SRC_FILES := Hello.c
  5. LOCAL_LDLIBS += -llog
  6. 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的使用【转】的更多相关文章

  1. Android NDK开发三:java和C\C++交互

    转自:http://www.cnblogs.com/shangdahao/archive/2013/05/02/3053971.html 1.定义native方法并加载动态链接库: public cl ...

  2. Android NDK开发初识

    神秘的Android NDK开发往往众多程序员感到兴奋,但又不知它为何物,由于近期开发应用时,为了是开发的.apk文件不被他人解读(反编译),查阅了很多资料,其中有提到使用NDK开发,怀着好奇的心理, ...

  3. Android NDK开发

    Android NDK 开发教程(极客学院) 一.Android NDK环境搭建 使用最新ndk,直接抛弃cygwin,以前做Android的项目要用到NDK就必须要下载NDK,下载安装Cygwin( ...

  4. Android NDK 开发(四)java传递数据到C【转】

    转载请注明出处:http://blog.csdn.net/allen315410/article/details/41845701 前面几篇文章介绍了Android NDK开发的简单概念.常见错误及处 ...

  5. !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结

    http://hujiaweibujidao.github.io/blog/2013/11/18/android-ndk-and-opencv-development-3/ Android Ndk a ...

  6. android NDK开发在本地C/C++源码中设置断点单步调试具体教程

    近期在学android NDK开发,折腾了一天,最终可以成功在ADT中设置断点单步调试本地C/C++源码了.网上关于这方面的资料太少了,并且大都不全,并且调试过程中会出现各种各样的问题,真是非常磨人. ...

  7. Android NDK开发Hello Word!

    在之前的博客中已经为大家介绍了,如何在win环境下配置DNK程序,本篇我将带大家实现一个简单的Hello jni程序,让大家真正感受一下NDK开发的魅力.这里我们选择使用C+JAVA开发Android ...

  8. android NDK开发环境搭建

    android NDK开发环境搭建 2012-05-14 00:13:58 分类: 嵌入式 基于 Android NDK 的学习之旅-----环境搭建 工欲善其事必先利其器 , 下面介绍下 Eclip ...

  9. Android NDK开发method GetStringUTFChars’could not be resolved

    Android NDK开发method GetStringUTFChars'could not be resolved 图1 最近用到android的ndk,但在eclipse中提示method Ge ...

随机推荐

  1. 56个睿智帅气貌美的CTO大牛陪你叨逼叨

    技术领域门槛高,苦读十年有时不如大牛一指点 可CTO级别的大牛何处找? 别急,别急 他们1月12日都去参加APICloud新品发布会了! (没图说啥子) 各路大牛们云集,不仅是为APICloud新品发 ...

  2. 01 viewport

    <meta name="viewport" content="width=device-width,initial-scale=1.0">

  3. Winforms-GePlugin-Control-library

    Winforms-GePlugin-Control-library http://download.csdn.net/download/xm379303813/4247029

  4. MFC和GDI+一起使用

    VS2010,新建MFC项目,在头文件stdafx.h中添加: #include <gdiplus.h> using namespace Gdiplus; #pragma comment ...

  5. git merge

    1. git 解决冲突 ***** <<<<<<< HEAD *** *** ======= **** **** ** >>>>> ...

  6. iOS调用HTML

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. Basic认证

    Basic 概述 Basic 认证是HTTP 中非常简单的认证方式,因为简单,所以不是很安全,不过仍然非常常用. 当一个客户端向一个需要认证的HTTP服务器进行数据请求时,如果之前没有认证过,HTTP ...

  8. 使用JavaScript闭包,以工厂模式实现定时器对象

    原始对象写法 一般工作中写Javascript代码,主要写全局函数,并组织函数之间的调用,确实比较低级, 于是想利用面向对象的思想应用到JS编码中. 在火狐浏览器开发者网站上,看到一个实例利用对象技术 ...

  9. 使用Jquery+EasyUI 进行框架项目开发案例讲解之三---角色管理源码分享

    使用Jquery+EasyUI 进行框架项目开发案例讲解之三 角色管理源码分享    在上两篇文章  <使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享> ...

  10. Postfix Completion 的使用

    Postfix Completion 的介绍 Postfix Completion 功能本质上也是代码模板,只是它比 Live Templates 来得更加便捷一点点而已.具体它是做什么的,我们通过下 ...