1. 程式人生 > >Android呼叫so庫(c語言編寫) Codeblocks+adt-win-x86+ndk-r9c

Android呼叫so庫(c語言編寫) Codeblocks+adt-win-x86+ndk-r9c

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 

[[email protected] ~]$ 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
[
[email protected]
~]$ cat /proc/version Linux version 2.6.32-279.el6.x86_64 ([email protected]) (gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC) ) #1 SMP Wed Jun 13 18:24:36 EDT 2012 [[email protected] ~]$ 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,

/home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/lib
/home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/lib/gcc/arm-linux-androideabi/4.6
/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 : 

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

        S4: Search directories->Complier , Add

/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 (

    如下圖所示

    

    新建一個虛擬機器

    

3. SO庫編寫

    3.1)生成標頭檔案

        開啟adt-bundle-windows裡面的Eclipse

        新建Android專案JniTestAndroid ,建立包 com.lpr, 建類  JniTestAndroid

        JniTestAndroid.java

package com.lpr;
class JniTestAndroid {
    public native byte[]  recognition(byte arr[]);
      static {
	System.loadLibrary("AndroidCallsoDemo");//Load  AndroidCallsoDemo.so produce by code::blocks
    //  System.out.println(System.getProperty("java.library.path"));
    //  System.setProperty("java.library.path", ".");
      }
}

 用 Javac 編譯成 class檔案
>cd E:\JniTestAndroid
>javac com/lpr/JniTestAndroid.java
>javah com.lpr.JniTestAndroid
現在生成了 com_lpr_JniTestAndroid.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lpr_JniTestAndroid */

#ifndef _Included_com_lpr_JniTestAndroid
#define _Included_com_lpr_JniTestAndroid
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_lpr_JniTestAndroid
 * Method:    recognition
 * Signature: ([S)[B
 */
JNIEXPORT jbyteArray JNICALL Java_com_lpr_JniTestAndroid_recognition
  (JNIEnv *, jobject, jbyteArray);

#ifdef __cplusplus
}
#endif
#endif

現在將com_lpr_JniTestAndroid.h拷貝到 Redhat 下面

並將 $java_home/include/jni.h 和 ./linux/jni_md.h 拷貝到 redhat 下面

在此特給出 jni_md.h 原始碼

#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_

#define JNIEXPORT
#define JNIIMPORT
#define JNICALL 

typedef long jint;
typedef __int64 jlong;
typedef signed char jbyte;

#endif /* !_JAVASOFT_JNI_MD_H_ */

      3.2)編寫SO庫

             開啟Code::Block新建(動態庫)專案 AndroidCallsoDemo, 設定專案屬性  參考上面的【 1.2  配置專案的環境】

             新增 com_lpr_JniTestAndroid.h, jni.h,  jni_md.h 到專案(不新增也可以,只要放到專案的更目錄即可)

            main.cpp

#include "stdio.h"
#include "com_lpr_JniTestAndroid.h"

JNIEXPORT jbyteArray JNICALL Java_com_lpr_JniTestAndroid_recognition
(JNIEnv *jnienv, jobject jobj, jbyteArray byteArray)
{
    /*    short*  iArray ; //=new short[maxSize];
        jboolean jbool = true;
        //轉換陣列
        iArray = jnienv->GetShortArrayElements(shortArray, &jbool);
        //...
        //
        jnienv->ReleaseShortArrayElements(shortArray,iArray,0);
        // do something with iArray ...


        // carnumber;
    */
    char carnumber[64]= {"你輸入的是:"};

    jbyteArray  returnLPRArray = jnienv->NewByteArray( 64 );
    jbyte *retbytes = jnienv->GetByteArrayElements( returnLPRArray, 0);

    jbyte *bytes2 = jnienv->GetByteArrayElements(byteArray, 0);

    sprintf(carnumber, "%s %s",carnumber, bytes2);

    int nLPRLen = strlen(carnumber);
    //返回值最好是 byte,以免utf8造成漢字的影響
    for ( int i = 0; i < nLPRLen;  i++ )
    {
        retbytes[ i ] = carnumber[ i ];
    }

    jnienv->SetByteArrayRegion(returnLPRArray, 0, nLPRLen, retbytes );

    return   returnLPRArray ;
}

           幾點注意:

            1. 如果傳入引數或傳出引數有漢字或比較複雜的結構,建議都化為 jbyteArray, 特別是有關的漢字問題

4. Android編寫

  建立android專案 JniTestAndroid

  activity_karl.xml // 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#F5F6F2"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".KarlActivity" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:text="result"
        android:textSize="20sp" />


    <Button
        android:id="@+id/button1"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_below="@+id/textView"
        android:gravity="center_horizontal"
        android:text="Button" />

</RelativeLayout>

 拷貝  com.lpr.JniTestAndroid  到專案 src 下面

karlActivity.java

package com.karl.jnitestandroid;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.lpr.JniTestAndroid;

public class KarlActivity extends Activity {

	private JniTestAndroid jni = new JniTestAndroid();
	private Button bt;
	private TextView textView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_karl);
		
		textView = (TextView)findViewById(R.id.textView);  
		bt = (Button) findViewById(R.id.button1);  
		bt.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View arg0) {
				String str="中國北京123ABC";
				byte data[] =  jni.recognition(str.getBytes());
				String text = new String(data); //new String(data, "GB2312");
				textView.setText(text);
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.karl, menu);
		return true;
	}

}

執行結果


5.  常見錯誤

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

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
/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)
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  
/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
/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
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

/home/xxx/Desktop/android-ndk-r9c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-readelf -a AndroidCallsoDemo.so
或者
/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新增如下包含目錄即可
/home/xxx/Desktop/android-ndk-r9c/sources/cxx-stl/gnu-libstdc++/4.6/include
/home/xxx/Desktop/android-ndk-r9c/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include

QQ: 1505974441

[2014.2.18 14:26:00]

相關推薦

Android呼叫soc語言編寫 Codeblocks+adt-win-x86+ndk-r9c

Android呼叫so庫, so庫是c語言編寫, 在linux 64位系統+ndk(32位)生成 lib*.so (32位) 1. 所需軟體環境: 1)so庫開發環境 作業系統: Redhat Server 6.3  x86_64 編譯軟體:Code::Blocks And

1004 成績排名 PAT (Basic Level) Practice 中文C語言編寫

1004 成績排名 (20 分) 讀入 n(>0)名學生的姓名、學號、成績,分別輸出成績最高和成績最低學生的姓名和學號。 輸入格式: 每個測試輸入包含 1 個測試用例,格式為 第 1 行:正整數 n 第 2 行:第 1 個學生的姓名 學號 成績 第 3 行:第

二叉排序樹新建,插入,查詢,刪除C語言編寫

#include<stdio.h> #include <stdlib.h> typedef struct BSTNode{         int data;         struct BSTNode *lchild,*rchild; }BSTN

01揹包的四種解法詳解:動態規劃,貪心法,回溯法,優先佇列式分支限界法C語言編寫

最近剛完成了演算法課程設計,題目是用多種解法解決01揹包問題,經過一番探索,終於成功的用四種方法完成了本次實驗,下面記錄分享一下成果: 首先解釋下什麼是01揹包問題:給定一組共n個物品,每種物品都有自己的重量wi, i=1~n和價值vi, i=1~n,在限定的總重量(揹包的

單鏈表的輸入和輸出c語言編寫

#include<stdio.h> #include<stdlib.h> struct link2 {     int data;     struct link2 *next; }*head; void creat(); void Ouput();

[解問題篇]2.根據利潤提成發獎金C++語言編寫

                                           “人所缺乏的不是才幹而是志向,不是成功的能力而是勤勞的意志。” —— 部爾衛 (如有轉載,請標明出處,謝謝o(* ̄︶ ̄*)o) 參考:菜鳥教程,C語言經典案例100例(我把這些翻譯成C+

UE4 呼叫第三方C++dll例子

1.建立工程時選擇Visual C++>Win32,建立的工程名稱為Test。之後在工程引導中選擇DLL和空工程即可。建立完成之後新增新類。此處命名為Test。點選儲存後,設定BuildSet

Codeblocks建立和呼叫DLL動態連結C語言

建立一個最簡單的只有一個get_id() 函式的DLL庫  一、建立C語言動態連結庫 1.新建一個動態庫的工程 File - New - Project - DLL - Go 新建的工程原來的main.cpp和main.h刪除,新建兩個檔案simple.h, simple

Android 靜態和動態的呼叫soJNI

優點 為什麼我們需要動態載入?因為靜態載入中CPU的資料夾我們可能需要相容的話需要放在不同arm資料夾下,那麼就會導致apk 包體過大,還有安卓Android SDK系統版本導致的差異,所以我們採用動態載入 so 庫檔案的話最主要的好處就是可以減小

漢諾塔遞迴呼叫C語言實現

1.遞迴演算法 遞迴演算法:是一種直接或者間接地呼叫自身的演算法。在計算機編寫程式中,遞迴演算法對解決一大類問題是十分有效的,它往往使演算法的描述簡潔而且易於理解。 遞迴過程一般通過函式或子過程來實現。 遞迴演算法的實質:是把問題轉化為規模縮小了的同類問題的子問題。然後

Android 呼叫so全過程

一、前言 Android中有時候為了效率以及平臺開發庫的支援,難免會用到NDK開發,那麼都會產生一個so檔案,通過native方法進行呼叫,開發和呼叫步驟很簡單,這裡就不多說了,本文主要來介紹,我們在使用so的時候總是會出現一些常見的問題,而現在外掛化開發也很普遍了,有時候外掛中也會包含一些s

python中呼叫動態連結C++,linux

1,建立並編譯C++程式 #include <fstream> #include <assert.h> #include <malloc.h> #incl

二十四進制編碼串轉換為32位無符號整數C語言實現

bool while open 參數錯誤 hint div 第一個字符 bsp opened typedef int BOOL; #define TRUE 1; #define FALSE 0; #define UINT_MAX 0xffffffff

堆排序C語言實現

names 博客 鏈接 c語言實現 建立 ron 要求 clas [1] 之前的博客介紹介紹了數組的兩種排序算法:插入排序和歸並排序(採用遞歸),見鏈接http://blog.csdn.net/u013165521/article/detai

雙向循環鏈表C語言描述

雙向循環鏈表 還要 ons 函數 保存 hat 加載 dir dict   下面以一個電子英漢詞典程序(以下簡稱電子詞典)為例,應用雙向循環鏈表。分離數據結構,可以使邏輯代碼獨立於數據結構操作代碼,程序結構更清晰,代碼更簡潔;電子詞典的增、刪、查、改操作分別對應於鏈表的插入

雙向循環鏈表C語言描述

open color end int fin spa assert not des 代碼清單 1 // dictionary.h 2 #ifndef __DICTIONARY_H__ 3 #define __DICTIONARY_H__ 4 5 #i

算法 - 棧與隊列C 語言實現

元素 語言 訪問規則 並且 下標 出棧 數據結構 規則 算法 目標: 理解 棧 與 隊列 這兩種數據結構, 並且知道如何應用。 算法 + 數據結構 = 程序 一、堆棧 堆棧是一組元素的集合,類似於數組,但數組可以按下標訪問,堆棧的訪問規則只能為push 與

歸並排序C語言實現

ngs 基本 merge 兩個 它的 efi 分別是 void rec 合並排序(MERGE SORT)是又一類不同的排序方法,合並的含義就是將兩個或兩個以上的有序數據序列合並成一個新的有序數據序列,因此它又叫歸並算法。 它的基本思想就是假

隊列的實現及操作C語言描述

img tdi 定義數據 上一個 判斷 free 隊列的單鏈表 插入數據 尾指針 // 隊列的單鏈表實現 // 頭節點:哨兵作用,不存放數據,用來初始化隊列時使隊頭隊尾指向的地方 // 首節點:頭節點後第一個節點,存放數據 #include&

數據結構-線性表的鏈式存儲相關算法C語言實現

存儲位置 lib 方法 lis 逆序 順序 程序 查詢 c語言 鏈表的簡單介紹 為什麽需要線性鏈表 當然是為了克服順序表的缺點,在順序表中,做插入和刪除操作時,需要大量的移動元素,導致效率下降。 線性鏈表的分類 按照鏈接方式: 按照實現角度: 線性鏈表的創建和簡單遍歷