什么是NDK?
定義:Native Development Kit,是Android的一種開發工具包(其實就是在安卓平臺編寫C和C++程序的開發包)
作用:最主要的就是開發so庫了,c或c++代碼編譯成動態鏈接庫供java代碼調用
優點:
運行效率高
代碼安全性高
跨平臺
使用場景
對性能要求比較高或者對安全要求比較高的Android程序可以使用NDK
ndk下載鏈接:https://developer.android.google.cn/ndk/downloads/
使用之后請自行配置環境變量
編寫可執行程序
- 創建一個目錄(這里我創建目錄為jni)
image.png
目錄中有三個文件Android.mk,Application.mk,hello-jni.c
下面我們分別介紹一下這三個文件 - hello-jni.c
#include <stdio.h>
int main()
{
printf("Hello Android!\n");
return 0;
}
hello-jni.c是源碼文件,編寫c或者c++代碼
- Application.mk
#### 0APP_ABI := arm64-v8a 后面接的是需要生成的.so平臺文件,
#### 正常手機使用arm64處理器的即可。 all是全平臺
#### APP_PLATFORM :=后面接的是使用SDK的最低等級
APP_ABI := all
Application.mk為指定平臺文件
- Android.mk
# 一個Android.mk file首先必須定義好LOCAL_PATH變量。
# 它用于在開發樹中查找源文件。在這個例子中,宏函數’my-dir’,
# 由編譯系統提供,用于返回當前路徑(即包含Android.mk file文件的目錄)。
LOCAL_PATH := $(call my-dir)
# CLEAR_VARS由編譯系統提供,
# 指定讓GNU MAKEFILE為你清除許多LOCAL_XXX變量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。這是必要的,
# 因為所有的編譯控制文件都在同一個GNU MAKE執行環境中,所有的變量都是全局的。
include $(CLEAR_VARS)
# LOCAL_MODULE變量必須定義,以標識你在Android.mk文件中描述的每個模塊。名稱必須是唯一的,而且不包含任何空格。
# 注意編譯系統會自動產生合適的前綴和后綴,換句話說,一個被命名為'foo'的共享庫模塊,將會生成'libfoo.so'文件。
LOCAL_MODULE := hello-jni
# LOCAL_SRC_FILES變量必須包含將要編譯打包進模塊中的C或C++源代碼文件。注意,你不用在這里列出頭文件和包含文件,
# 因為編譯系統將會自動為你找出依賴型的文件;僅僅列出直接傳遞給編譯器的源代碼文件就好。
LOCAL_SRC_FILES := hello-jni.c
# BUILD_EXECUTABLE 表示以一個可執行程序的方式進行編譯
# BUILD_SHARED_LIBRARY 表示動態鏈接庫的方式進行編譯
include $(BUILD_EXECUTABLE)
Android.mk指定編譯的一些參數(注釋比較詳細)
使用ndk-build
-
進入到創建的jni目錄使用ndk-build編譯
image.png - 在jni同級目錄下會出現libs文件夾,進入該文件夾如下:
image.png
可以看到所有的平臺,這里我們使用armeabi-v7a的,因為我們的虛擬機是armeabi-v7a
注意:這里一定要創建arm架構的虛擬機,因為我們的Android手機基本都是arm架構的
image.png -
進入armeabi-v7a文件夾可以看到有編譯好的可執行程序:
image.png - 下面就是將這個可執行程序push到手機上,然后運行它了(先啟動安卓虛擬機)
#進入手機shell
adb shell
#創建文件夾
mkdir /data/tmp/
#退出shell
exit
#push可執行程序進入手機(這里路徑根據自己的修改)
adb push C:\Users\15079\Desktop\libs\armeabi-v7a\hello-jni /data/tmp
#再次進入手機shell
adb shell
#進入到可執行程序的文件夾
cd /data/tmp
#給權限
chmod 777 hello-jni
#運行
./hello-jni
最后結果如下:
image.png
尾言
這里我們編寫一個簡單的NDK可執行程序作為例子,真正的情況一般是編譯為so庫,我將在下一章使用eclipse+NDK編寫一個簡單的so庫,并使用JNI技術在java中調用這個so庫,這也是我們項目中一般使用到的場景。
在IDA反匯編中so庫的源碼將變成ARM匯編代碼,而不是Intel X86的匯編,所以我們有必要學習一下ARM匯編
ARM手冊(需翻墻)
https://docs.google.com/viewer?url=http%3A%2F%2Fwww.scss.tcd.ie%2F%7Ewaldroj%2F3d1%2Farm_arm.pdf