linux android ndk

1. 所需软件环境:

1)so库开发环境

操作系统: Redhat Server 6.3  x86_64

编译软件:Code::Blocks

Android native开发库:android-ndk-r9c-linux-x86.tar.bz2 

 

[xxx@www ~]$ uname -a
Linux www.teleframe.cn 2.6.32-279.el6.x86_64 #1 SMP Wed Jun 13 18:24:36 EDT 2012 x86_64 x86_64 x86_64 GNU/Linux
[xxx@www ~]$ cat /proc/version
Linux version 2.6.32-279.el6.x86_64 (mockbuild@x86-008.build.bos.redhat.com) (gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC) ) #1 SMP Wed Jun 13 18:24:36 EDT 2012
[xxx@www ~]$ cat /etc/issue
Red Hat Enterprise Linux Server release 6.3 (Santiago)
Kernel \r on an \m

 

2) Android客户端开发

操作系统:Windows 7 x86

测试环境: Android手机(系统4.0及以上)

开发工具和SDK包: adt-bundle-windows-x86-20131030.zip(里面含有Eclipse)

本文所需软件如下:

 

2. 环境搭建

1)Code::Blocks环境搭建

      首先安装Code::Blocks, 然后解压 android-ndk-r9c-linux-x86.tar.bz2 , 如解压到桌面  /home/UserName/Desktop/android-ndk-r9c/
      然后启动Code::Blocks,  进行系统环境配置

     1.1) 配置全局环境

           S1:  打开  Settings-> Compiler and debugger... 

           S2:  选择编译器Selected complier ->  GNU ARM GCC Complier,或自己新建一个

           S3:  选择 Toolchain executables

           S4:  设置android-ndk路径( Complier's installation directory ) ,如 /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86

           S5:  设置Program Files各个编译程序

                  C complier:                       arm-linux-androideabi-gcc

                  C++ compiler:                  arm-linux-androideabi-g++

                  Linker for dynamic libs:  arm-linux-androideabi-g++

                  Linker for static libs:        arm-linux-androideabi-ar

                  Debugger:                         arm-linux-androideabi-gdb

                  Resource compiler:        

                 

           S6: 设置Additional Paths,  增加(Add)  :  /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/arm-linux-androideabi/bin

           S7: 设置 Search directories -> Compiler,  增加(Add)  : /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/include

           S8: 设置 Search directories -> Linker,

 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/lib  
  2. /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/lib/gcc/arm-linux-androideabi/4.6  
  3. /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/lib/gcc/arm-linux-androideabi/4.6/armv7-a  

              

           S9:  设置完成,点击确定

    1.2) 配置项目的环境

         S1:  右击项目,选择Build options,  Selected Complier选择刚才设置的那个  GUN ARM GCC Compiler 

         S2:  Compler settings -> Other options , 写入  -fPIC

         S3:  设置 Search directories -> Linker,  Add : 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /home/xxx/Desktop/android-ndk-r9c/platforms/android-14/arch-arm/usr/lib  

        S4: Search directories->Complier , Add 

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /home/xxx/Desktop/android-ndk-r9c/platforms/android-14/arch-arm/usr/include  

 

2)Android 开发环境搭建

     直接解压 adt-bundle-windows-x86-20131030.zip , 如解压到  E:\Program Files\adt\adt-bundle-windows-x86-20131030 

     

     就可以看到里面以及放好了eclipse, 此处的eclipse默认已经配置好了 adt,  启动 eclipse.exe 配置android虚拟机

    菜单 Window -> Android Virtual Device Manager  管理虚拟机, Android SDK Manager 可以更新 SDK,由于此adt所带android系统是4.4,  建议再 更新 4.0.3 (

           手动更新详见: 手动下载Android开发SDK
                 sdk:platform -> https://dl-ssl.google.com/android/repository/android-14_r03.zip
                 sdk:system-image -> https://dl-ssl.google.com/android/repository/sysimg_armv7a-14_r02.zip  
     )

    如下图所示

    

    新建一个虚拟机

    

3. SO库编写

    3.1)生成头文件

        打开adt-bundle-windows里面的Eclipse

        新建Android项目JniTestAndroid ,建立包 com.lpr, 建类  JniTestAndroid

        JniTestAndroid.java

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. package com.lpr;  
  2. class JniTestAndroid {  
  3.     public native byte[]  recognition(byte arr[]);  
  4.       static {  
  5.     System.loadLibrary("AndroidCallsoDemo");//Load  AndroidCallsoDemo.so produce by code::blocks  
  6.     //  System.out.println(System.getProperty("java.library.path"));  
  7.     //  System.setProperty("java.library.path", ".");  
  8.       }  
  9. }  

 用 Javac 编译成 class文件
>cd E:\JniTestAndroid
>javac com/lpr/JniTestAndroid.java
>javah com.lpr.JniTestAndroid
现在生成了 com_lpr_JniTestAndroid.h
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_lpr_JniTestAndroid */  
  4.   
  5. #ifndef _Included_com_lpr_JniTestAndroid  
  6. #define _Included_com_lpr_JniTestAndroid  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_lpr_JniTestAndroid 
  12.  * Method:    recognition 
  13.  * Signature: ([S)[B 
  14.  */  
  15. JNIEXPORT jbyteArray JNICALL Java_com_lpr_JniTestAndroid_recognition  
  16.   (JNIEnv *, jobject, jbyteArray);  
  17.   
  18. #ifdef __cplusplus  
  19. }  
  20. #endif  
  21. #endif  

现在将com_lpr_JniTestAndroid.h拷贝到 Redhat 下面

并将 $java_home/include/jni.h 和 ./linux/jni_md.h 拷贝到 redhat 下面

在此特给出 jni_md.h 源码

 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. #ifndef _JAVASOFT_JNI_MD_H_  
  2. #define _JAVASOFT_JNI_MD_H_  
  3.   
  4. #define JNIEXPORT  
  5. #define JNIIMPORT  
  6. #define JNICALL   
  7.   
  8. typedef long jint;  
  9. typedef __int64 jlong;  
  10. typedef signed char jbyte;  
  11.   
  12. #endif /* !_JAVASOFT_JNI_MD_H_ */  

 

      3.2)编写SO库

             打开Code::Block新建(动态库)项目 AndroidCallsoDemo, 设置项目属性  参考上面的【 1.2  配置项目的环境】

             添加 com_lpr_JniTestAndroid.h, jni.h,  jni_md.h 到项目(不添加也可以,只要放到项目的更目录即可)

            main.cpp

 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. #include "stdio.h"  
  2. #include "com_lpr_JniTestAndroid.h"  
  3.   
  4. JNIEXPORT jbyteArray JNICALL Java_com_lpr_JniTestAndroid_recognition  
  5. (JNIEnv *jnienv, jobject jobj, jbyteArray byteArray)  
  6. {  
  7.     /*    short*  iArray ; //=new short[maxSize]; 
  8.         jboolean jbool = true; 
  9.         //转换数组 
  10.         iArray = jnienv->GetShortArrayElements(shortArray, &jbool); 
  11.         //... 
  12.         // 
  13.         jnienv->ReleaseShortArrayElements(shortArray,iArray,0); 
  14.         // do something with iArray ... 
  15.  
  16.  
  17.         // carnumber; 
  18.     */  
  19.     char carnumber[64]= {"你输入的是:"};  
  20.   
  21.     jbyteArray  returnLPRArray = jnienv->NewByteArray( 64 );  
  22.     jbyte *retbytes = jnienv->GetByteArrayElements( returnLPRArray, 0);  
  23.   
  24.     jbyte *bytes2 = jnienv->GetByteArrayElements(byteArray, 0);  
  25.   
  26.     sprintf(carnumber, "%s %s",carnumber, bytes2);  
  27.   
  28.     int nLPRLen = strlen(carnumber);  
  29.     //返回值最好是 byte,以免utf8造成汉字的影响  
  30.     for ( int i = 0; i < nLPRLen;  i++ )  
  31.     {  
  32.         retbytes[ i ] = carnumber[ i ];  
  33.     }  
  34.   
  35.     jnienv->SetByteArrayRegion(returnLPRArray, 0, nLPRLen, retbytes );  
  36.   
  37.     return   returnLPRArray ;  
  38. }  

 

            

           几点注意:

            1. 如果传入参数或传出参数有汉字或比较复杂的结构,建议都化为 jbyteArray, 特别是有关的汉字问题

 

4. Android编写

  建立android项目 JniTestAndroid

  activity_karl.xml // 

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:background="#F5F6F2"  
  6.     android:paddingBottom="@dimen/activity_vertical_margin"  
  7.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  8.     android:paddingRight="@dimen/activity_horizontal_margin"  
  9.     android:paddingTop="@dimen/activity_vertical_margin"  
  10.     tools:context=".KarlActivity" >  
  11.   
  12.     <TextView  
  13.         android:id="@+id/textView"  
  14.         android:layout_width="match_parent"  
  15.         android:layout_height="wrap_content"  
  16.         android:gravity="center_horizontal"  
  17.         android:text="result"  
  18.         android:textSize="20sp" />  
  19.   
  20.   
  21.     <Button  
  22.         android:id="@+id/button1"  
  23.         android:layout_width="match_parent"  
  24.         android:layout_height="40dp"  
  25.         android:layout_below="@+id/textView"  
  26.         android:gravity="center_horizontal"  
  27.         android:text="Button" />  
  28.   
  29. </RelativeLayout>  

 拷贝  com.lpr.JniTestAndroid  到项目 src 下面

 

karlActivity.java

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. package com.karl.jnitestandroid;  
  2.   
  3. import android.os.Bundle;  
  4. import android.app.Activity;  
  5. import android.view.Menu;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9. import android.widget.TextView;  
  10.   
  11. import com.lpr.JniTestAndroid;  
  12.   
  13. public class KarlActivity extends Activity {  
  14.   
  15.     private JniTestAndroid jni = new JniTestAndroid();  
  16.     private Button bt;  
  17.     private TextView textView;  
  18.     @Override  
  19.     protected void onCreate(Bundle savedInstanceState) {  
  20.         super.onCreate(savedInstanceState);  
  21.         setContentView(R.layout.activity_karl);  
  22.           
  23.         textView = (TextView)findViewById(R.id.textView);    
  24.         bt = (Button) findViewById(R.id.button1);    
  25.         bt.setOnClickListener(new OnClickListener(){  
  26.   
  27.             @Override  
  28.             public void onClick(View arg0) {  
  29.                 String str="中国北京123ABC";  
  30.                 byte data[] =  jni.recognition(str.getBytes());  
  31.                 String text = new String(data); //new String(data, "GB2312");  
  32.                 textView.setText(text);  
  33.             }  
  34.         });  
  35.     }  
  36.   
  37.     @Override  
  38.     public boolean onCreateOptionsMenu(Menu menu) {  
  39.         // Inflate the menu; this adds items to the action bar if it is present.  
  40.         getMenuInflater().inflate(R.menu.karl, menu);  
  41.         return true;  
  42.     }  
  43.   
  44. }  

运行结果

5.  常见错误

  5.1)  ld: error: cannot open crtbegin_so.o: No such file or directory

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. arm-linux-androideabi-g++ -Wall -fexceptions  -O2 -fPIC    -I../android-ndk-r9c/platforms/android-14/arch-arm/usr/include  -c main.cpp -o obj/Release/main.o  
  2. /home/haifeng/android/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/as: /lib/libz.so.1: no version information available (required by /home/haifeng/android/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/as)  
  3. arm-linux-androideabi-g++ -shared -L../android-ndk-r9c/platforms/android-14/arch-arm/usr/lib -L/home/haifeng/android/android-ndk-r9c/platforms/android-14/arch-arm/usr/lib  obj/Release/main.o   -o bin/Release/libAndroidCallsoDemo.so -s    
  4. /home/haifeng/android/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: error: cannot open crtbegin_so.o: No such file or directory  
  5. /home/haifeng/android/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: error: cannot open crtend_so.o: No such file or directory  
  6. collect2: ld returned 1 exit status  
 
原因是ld找不到  crtbegin_so.o 和 crteng_so.o, 解决方法是,在项目源码下面建立软连接

cd /home/xxx/android/AndroidCallsoDemo/
ln -s /home/xxx/android/android-ndk-r9c/platforms/android-14/arch-arm/usr/lib/crtend_so.o ./
ln -s /home/xxx/android/android-ndk-r9c/platforms/android-14/arch-arm/usr/lib/crtbegin_so.o ./

    5.2) 查看SO库的依赖库

        查看PC linux  平台是用 ldd,  查看嵌入式的用  arm-linx-*-readelf

[python] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-readelf -a AndroidCallsoDemo.so  
或者
[python] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-readelf -a AndroidCallsoDemo.so | grep "Shared"  

   5.3) 使用STL
   直接使用STL或用Opencv间接调用STL, 提示找不到  #include <algorithm> 等,  在工程的 Build Options ->  Search directories -> Complier添加如下包含目录即可
[python] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /home/xxx/Desktop/android-ndk-r9c/sources/cxx-stl/gnu-libstdc++/4.6/include  
[plain] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /home/xxx/Desktop/android-ndk-r9c/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include  
posted @ 2015-11-27 16:47  fireflyover  阅读(1046)  评论(0编辑  收藏  举报