android 編譯調用C代碼

博客地址:www.zalezone.cn



前言

需求來源

這幾天幫別人做一個簡單的android客戶端,也沒什麼功能,主要就是調用C代碼來對手機的Wifi網絡進行設置,於是也就引出了技術難點所在,如何去調用C程序達到我們所需要的效果。

解決方案

對於這個,我想出了兩種解決方案:

  1. 第一種方案是利用JNI來進行本地調用。關於什麼是JNI呢,JNI其實是Java Native Interface的簡稱,也就是java本地接口,它提供了若干API實現了java和其他語言的通信(主要是C和C++)。

  2. 第二種方法是將要執行的C代碼編譯成可執行文件,然後將這個可執行文件和程序一起打包成APK,在需要使用的時候調用這個可執行文件。

最終選擇

最後我選擇了第二種方案,理由是第二種方法在我已經有了可執行文件的條件下總體來說比較簡單,可操作性強。而第一種方案的話因爲還要下載android的NDK,NDK是一系列工具的集合,提供了幫助開發者快速開發C或則C++的動態庫,並能自動將so和java應用一起打包成apk,十分方便。

技術實現

可執行文件

首先需要得到一個可執行文件,當然想要的到可執行文件並不是想象中的那麼簡單,不是在linux中直接gcc就能到的,這裏需要對C代碼進行交叉編譯獲得可以在android機子上運行的可執行文件,具體如何對C文件進行交叉編譯,這裏就不再贅述,大家可以上網查找一下。另外,NDK也是個不錯的工具。

資源存儲

這裏的資源存儲頁算是個小坑,平常我們在寫java程序的時候,如果要打開一個文件的話就直接輸入路徑,比如如果所要使用的文件就在項目的目錄下,直接輸入文件名就可以調用了,但是這裏的運行環境是嵌入式設備,不是PC,這就涉及到一個問題,資源如何存儲了。

這裏先談一下Android中的asset文件夾res/raw文件夾的異同:

  • 相同點
    • 兩者目錄下的文件在打包後都會原封不動的保存在apk包中,不會被編譯成二進制。
  • 不同點
    • res/raw中的文件會被映射到R.java中,訪問的時候直接使用資源ID即可,而assets文件夾下的文件不會被映射到R.java。
    • res/raw不可以有目錄結構,而assets目錄下可以再建立文件夾。

資源獲取

這裏順帶說一下res/raw下的文件資源的讀取方法,通過以下方式獲取輸入流來進行寫操作

1
InputStream is =getResources().openRawResource(R.id.filename);

接下來纔是我用到的讀取assets下的方法,同樣也是通過獲取輸入流的方式來進行寫操作

1
2
3
AssetManager am = null;
am = getAssets();
InputStream is = am.open("filename");

注意點:據說Assert只能放單個文件不超過1M的文件,但是不是真的具體還沒考證過,如果碰到問題了應該考慮一下這個注意點。

雖然讀取是成功了,但是要用shell腳本執行的話,應該在手機的存儲上應該有這個文件,光是讀取的話在手機裏面是找不見的,所以我們需要一個存文件的操作。這裏我寫了一個存文件的函數,其中將獲取assets中數據的方法也結合進去了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void copyDataToSD(String outFileName)throws IOException
{
InputStream myInputStream;
OutputStream myOutputStream = new FileOutputStream(outFileName);
myInputStream = this.getAssets().open("a.out");
byte[] buffer = new byte[1024];
int length = myInputStream.read(buffer);
while (length > 0) {
myOutputStream.write(buffer, 0, length);
length = myInputStream.read(buffer);
}
myOutputStream.flush();
myInputStream.close();
myOutputStream.close();
}

然後我定義的傳入的outFileName是定義的文件路徑加文件名

1
2
private static String EXE_PATH = "data/data/com.example.g3wifi/a.out";
private static File exe_file;

shell命令執行

到這裏的話就是“萬事俱備,只欠東風”了,我們需要執行所得到的可執行文件,因爲android是基於linux的,所以一些基本的命令還是支持的,在android中要執行shell命令的話就按如下格式即可:

1
2
3
4
5
6
7
8
public void exeC(String cmd)throws IOException
{
Runtime runtime =Runtime.getRuntime();
Process process = runtime.exec(cmd);
//Process process = runtime.exec(new String[]{"su","reboot"});//可以執行兩條命令
//這可以得到執行shell命令後的結果
BufferedReader ie = new BufferedReader(new InputStreamReader(process.getErrorStream()));
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章