###Eclipse下NDK開發流程
先來個Eclipse版本的,後續再上AS版本的。工具的使用不同而已。
###具體流程
- 編寫Java層Native方法
- javah命令生成標頭檔案
- 建立jni目錄
- 配置NDK路徑,新增本地支援add native support,配置ADT需要包含的標頭檔案
- 實現標頭檔案中定義的函式
- 編譯生成.so動態庫
- 載入動態庫
下面以建立一個簡單的檔案加密解決APP來作為示範:
####一、編寫Java層Native方法
我們專門建立一個Cryptor類用於檔案的加密解密:
public class Cryptor {
public static native void cryptFile(String src , String dest);
public static native void decryptFile(String src , String dest);
}
複製程式碼
這裡寫兩個native方法,分別用於檔案加密解密。
####二、使用javah命令生成對應的標頭檔案
在命令列下,通過cd命令轉到工程的src目錄(程式碼目錄),然後執行以下命令:
javah 完整類名
複製程式碼
就會生成對應的標頭檔案。
####三、建立jni目錄
直接通過Eclipse來建立即可,然後把我們剛剛生成的標頭檔案放進去。
####四、配置NDK路徑,新增本地支援add native support,配置ADT需要包含的標頭檔案
沒有配置NDK路徑的需要先配置一下:
Windows-->Preference-->Android-->NDK:
新增native support,右擊專案,選擇Android Tools,選擇add native support,然後彈出下面的介面,輸入lib的名字,字首系統預設為lib。
然後會在jni目錄自動生成一些檔案:
其中Application.mk是我們自己新增的,用於指定輸出什麼架構的so動態庫檔案,Application.mk如下:
# armeabi armeabi-v7a arm64-v8a mips mips64 x86 x86_64
APP_ABI := armeabi
複製程式碼
其中第一行是註釋。
配置ADT中需要包含的NDK標頭檔案:右擊工程-->屬性-->C/C++常規-->路徑和符號,新增NDK的以下目錄:
G:\android-ndk-r10\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9\include
G:\android-ndk-r10\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\lib\gcc\arm-linux-androideabi\4.9\include-fixed
G:\android-ndk-r10\platforms\android-L\arch-arm\usr\include
複製程式碼
######注意:筆者的版本可能跟你的版本不一樣,不過大同小異
配置好的圖如下:(某些目錄是後來生成的)
####五、實現標頭檔案中定義的函式
我們在crypt.c中實現吧,本來是cpp檔案的,我們目前先改為c實現:
#include "com_example_ndk_file_crypt_utils_Cryptor.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char password[] = "I AM MI MA";
JNIEXPORT void JNICALL Java_com_example_ndk_1file_1crypt_utils_Cryptor_cryptFile(
JNIEnv * env, jclass jclz, jstring src, jstring dest) {
const char* c_src = (*env)->GetStringUTFChars(env, src, NULL);
const char* c_dest = (*env)->GetStringUTFChars(env, dest, NULL);
FILE* f_read = fopen(c_src, "rb");
FILE* f_write = fopen(c_dest, "wb");
//判斷檔案是否正確開啟
if (f_read == NULL || f_write == NULL ) {
printf("file open field");
return;
}
//一次讀取一個字元
int ch;
int i = 0;
int pwd_len = strlen(password);
while ((ch = fgetc(f_read)) != EOF) {
//通過異或運算進行加密
fputc(ch ^ password[i % pwd_len], f_write);
i++;
}
//關閉檔案
fclose(f_read);
fclose(f_write);
}
JNIEXPORT void JNICALL Java_com_example_ndk_1file_1crypt_utils_Cryptor_decryptFile(
JNIEnv * env, jclass jclz, jstring src, jstring dest) {
const char* c_src = (*env)->GetStringUTFChars(env, src, NULL);
const char* c_dest = (*env)->GetStringUTFChars(env, dest, NULL);
FILE* f_read = fopen(c_src, "rb");
FILE* f_write = fopen(c_dest, "wb");
//判斷檔案是否正確開啟
if (f_read == NULL || f_write == NULL ) {
printf("file open field");
return;
}
//一次讀取一個字元
int ch;
int i = 0;
int pwd_len = strlen(password);
while ((ch = fgetc(f_read)) != EOF) {
//通過異或運算進行加密
fputc(ch ^ password[i % pwd_len], f_write);
i++;
}
//關閉檔案
fclose(f_read);
fclose(f_write);
}
複製程式碼
然後記得配置Android.mk檔案,把LOCAL_SRC_FILES的值改為crypt.c(原來是cpp)。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := crypt
LOCAL_SRC_FILES := crypt.c
include $(BUILD_SHARED_LIBRARY)
複製程式碼
####六、編譯生成.so動態庫
直接make project一下即可。
####七、載入動態庫
通過System.loadLibrary方法載入動態庫.so檔案,注意不用寫lib字首,系統會預設新增。
public class Cryptor {
static {
//載入動態庫.so檔案,注意不用寫lib字首,系統會預設新增
System.loadLibrary("crypt");
}
public static native void cryptFile(String src , String dest);
public static native void decryptFile(String src , String dest);
}
複製程式碼
剩下的就在Android佈局中寫兩個按鈕,測試一下即可,記得加上SD卡訪問許可權:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
複製程式碼
最後,說明一下,如果要適配所有平臺,需要修改Application.mk為:
APP_ABI := armeabi armeabi-v7a arm64-v8a mips mips64 x86 x86_64
複製程式碼
由於生成的過程需要交叉編譯,速度非常慢,大概五分鐘左右,因此,如果c程式碼沒有改變的話,我們可以通過下面的配置,不編譯c程式碼:
把兩個勾去掉即可。
如果覺得我的文字對你有所幫助的話,歡迎關注我的公眾號:
我的群歡迎大家進來探討各種技術與非技術的話題,有興趣的朋友們加我私人微信huannan88,我拉你進群交(♂)流(♀)。