linux android ndk

时间:2022-02-22 06:18:38

Android调用so库, so库是c语言编写, 在linux 64位系统+ndk(32位)生成 lib*.so (32位)

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:

linux android ndk

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,

  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

linux android ndk

S9:  设置完成,点击确定

1.2) 配置项目的环境

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

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

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

  1. /home/xxx/Desktop/android-ndk-r9c/platforms/android-14/arch-arm/usr/lib

linux android ndk

S4: Search directories->Complier , Add

  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

linux android ndk

就可以看到里面以及放好了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  
     )

如下图所示

linux android ndk

新建一个虚拟机

linux android ndk

3. SO库编写

3.1)生成头文件

打开adt-bundle-windows里面的Eclipse

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

JniTestAndroid.java

  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

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class com_lpr_JniTestAndroid */
  4. #ifndef _Included_com_lpr_JniTestAndroid
  5. #define _Included_com_lpr_JniTestAndroid
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*
  10. * Class:     com_lpr_JniTestAndroid
  11. * Method:    recognition
  12. * Signature: ([S)[B
  13. */
  14. JNIEXPORT jbyteArray JNICALL Java_com_lpr_JniTestAndroid_recognition
  15. (JNIEnv *, jobject, jbyteArray);
  16. #ifdef __cplusplus
  17. }
  18. #endif
  19. #endif

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

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

在此特给出 jni_md.h 源码

  1. #ifndef _JAVASOFT_JNI_MD_H_
  2. #define _JAVASOFT_JNI_MD_H_
  3. #define JNIEXPORT
  4. #define JNIIMPORT
  5. #define JNICALL
  6. typedef long jint;
  7. typedef __int64 jlong;
  8. typedef signed char jbyte;
  9. #endif /* !_JAVASOFT_JNI_MD_H_ */

3.2)编写SO库

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

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

main.cpp

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

几点注意:

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

4. Android编写

建立android项目 JniTestAndroid

activity_karl.xml //

  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. <TextView
  12. android:id="@+id/textView"
  13. android:layout_width="match_parent"
  14. android:layout_height="wrap_content"
  15. android:gravity="center_horizontal"
  16. android:text="result"
  17. android:textSize="20sp" />
  18. <Button
  19. android:id="@+id/button1"
  20. android:layout_width="match_parent"
  21. android:layout_height="40dp"
  22. android:layout_below="@+id/textView"
  23. android:gravity="center_horizontal"
  24. android:text="Button" />
  25. </RelativeLayout>

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

karlActivity.java

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

运行结果

linux android ndk

5.  常见错误

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

  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

  1. /home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-readelf -a AndroidCallsoDemo.so

或者

  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添加如下包含目录即可

  1. /home/xxx/Desktop/android-ndk-r9c/sources/cxx-stl/gnu-libstdc++/4.6/include
  1. /home/xxx/Desktop/android-ndk-r9c/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include