Android JNI Demo

說在最前面斋攀,當(dāng)前使用的系統(tǒng)是 Windows 10,筆者使用過Mac,Linux 和 Windows感覺不同的系統(tǒng)的差異不過是在環(huán)境配置和指令參數(shù)方面的問題,使用其它系統(tǒng)的小伙伴可以靈活變化硕旗。

1 JNI 及 NDK工具的 Simply 介紹

不記錄啥大道理,筆者只是簡單粗暴地做一下說明

  • JNI(Java Native Interface) Java 本地化(C/C++)接口的集合女责,目的是在Java中使用C/C++的庫
  • NDK(Native Develop Kit) 本地(C/C++)開發(fā)工具集漆枚,包括了C/C++編譯需要的工具集合

2 使用NDK生成SO庫

  • 下載NDK
    有梯子的小伙伴可以去Google官方下載
    https://developer.android.com/ndk/downloads/index.html
    或者國內(nèi)Google Android
    https://developer.android.google.cn/ndk/downloads/revision_history
    或者國內(nèi)小伙伴常去的
    http://www.androiddevtools.cn/
    或者Android Studio中【使用國內(nèi)鏡像】直接下載
    總而言之 最終的目的就是下載NDK,條條大道通羅馬抵知!筆者有梯子墙基,所以到官方下了的,為了說明特意下載了一個(gè) r12r16 兩個(gè)版本

  • 環(huán)境變量配置
    首先說明刷喜,配置環(huán)境變量只是方便在命令行在所有目錄都可以使用ndk指令残制,否則需要使用NDK指令時(shí),必須cd到NDK的安裝目錄下執(zhí)行指令(很煩有沒有掖疮?)
    使用Windows打開環(huán)境變量配置的方法:"Win鍵 + Pause|Break鍵" 打開系統(tǒng)面板 -> 高級系統(tǒng)設(shè)置 -> 環(huán)境變量 -> 在系統(tǒng)變量那一塊中找到并選擇 Path 變量 -> 編輯 -> 點(diǎn)擊"添加" -> <輸入你的NDK build文件夾完整目錄> -> 一路點(diǎn)擊"確定"返回!!!

    NDK develop environment variables.png

    驗(yàn)證環(huán)境:命令行任意目錄執(zhí)行 ndk-build --version ,輸出如圖
    Verify NDK system variables.png

  • 編寫C/C++代碼(筆者寫C)
    在桌面新建一個(gè)"NDK-Test"文件夾(其它目錄和名字也隨意了初茶,這個(gè)小伙伴們都懂),在“NDK-Test”中新建文件 age.h age.c student.c浊闪,同一個(gè)目錄新建文件夾 include 如圖:

    image.png

接著將 .h 全部文件移動到 include 文件夾中恼布。
編輯 age.h

int get_five_years_later_age(int age);

編輯 age.c

#include<stdio.h>
#include "include/age.h"

int get_five_years_later_age(int age) {
    printf("In get_five_years_later_age: input age is -> %d", age);
    age+=5;
    return age;
}

編輯 student.c

#include <stdio.h>
#include "include/age.h"

int get_ten_years_later_age(int age) {
    int get_age = get_five_years_later_age(age);
    printf("In get_ten_years_later_age: get age is -> %d", get_age);
    get_age += 5;
    return get_age;
}

int main() {
    int final_age = get_ten_years_later_age(8);
    printf("In main: final age is -> %d", final_age);
    getchar();
    return 0;
}
  • 編寫 Android.mk 文件
#build-so.mk

# 初始化編譯目錄由編譯系統(tǒng)完成: 取得調(diào)用宏函數(shù)my-dir的返回值(當(dāng)前目錄)存放到LOCAL_PATH變量
LOCAL_PATH := $(call my-dir)
# 隔離系統(tǒng)變量(除了我們設(shè)置的LOCAL_PATH變量)
include $(CLEAR_VARS)
# 模塊名字(輸出庫的名字)
LOCAL_MODULE    := student
# 編譯中依賴的源文件(非頭文件)
LOCAL_SRC_FILES := student.c age.c
# 編譯中依賴的頭文件(系統(tǒng)頭文件自動依賴添加)
LOCAL_C_INCLUDES := include/age.h
# 輸出庫的類型 BUILD_SHARED_LIBRARY 動態(tài)庫 .so,BUILD_STATIC_LIBRARY 靜態(tài)庫 .a搁宾,可執(zhí)行文件 BUILD_EXECUTABLE
include $(BUILD_SHARED_LIBRARY)
  • 編譯.so動態(tài)庫
    打開命令行并 cdNDK-Test 目錄折汞,然后執(zhí)行:
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk

結(jié)果:


Compile output.png

說明,NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk這兩個(gè)必須指定猛铅,NDK_APPLICATION_MK=./Application.mk 可選指定字支,不指定的時(shí)候?qū)⑹褂媚J(rèn)的Application.mk,也就是指定Android版本為android-14,輸出所有架構(gòu)的.so庫堕伪。假使以可執(zhí)行的方式進(jìn)行編譯揖庄,則需要在Android pak運(yùn)行時(shí),使得linux fork新的進(jìn)程執(zhí)

  • 關(guān)于Application.mk

未完待續(xù) ~~

3 在 Eclipse 中編譯 .so庫

這里說明一下欠雌,前面是在命令行執(zhí)行代碼蹄梢,其實(shí)在Eclipse配置編譯的program就是指定路徑過程

  • 新建NDKDemo項(xiàng)目
    在配置好Android SDK和NDK環(huán)境后可以直接新建Android項(xiàng)目,這里順帶提一下幾個(gè)問題:
  1. min SDK 最低SDK版本(4.2+)富俄,選擇過低的版本比如 Android 2.2等禁炒,會報(bào)style的theme找不到的錯(cuò)。
  2. target version 編譯版本霍比,一般推薦的是 6.0了幕袱,6.0是個(gè)分水嶺,想知道的留言悠瞬,筆者給你Google一下
  3. compile version 使用已經(jīng)下載的最高版本吧
  • 拷貝源文件到 NDKDemo 項(xiàng)目
    在新建的項(xiàng)目中们豌,右鍵項(xiàng)目新建 jni 文件夾,將我們前面的 NDK-Test 中的文件夾和源文件拷貝到j(luò)ni文件夾下浅妆,

  • 配置項(xiàng)目 NDK builde program
    右鍵項(xiàng)目 -> 屬性 -> Builders -> New -> Program ->

Setting main.png
Setting refresh.png
image.png

Then -> project -> clean


image.png

We make it!!!

4 在 Eclipse 中編譯使用現(xiàn)有的 .so 庫(第三方庫)并運(yùn)行

還是基于上面的項(xiàng)目進(jìn)行

  • 獲取一個(gè) armeabi-v7a 架構(gòu)的 .so 庫作為我們的引用庫
    這里小伙伴們可以刪除 libs目錄下的所有文件望迎,和JNI中的源文件(.c),筆者這里為了保留上次編譯痕跡凌外,就不刪除了辩尊。我們把 armeabi-v7a 中的 libstudent.so 庫到 jni目錄下

  • 編寫調(diào)用符合JNI格式文件
    在jni目錄下新建并編寫我們調(diào)用庫的 teacher.c 文件,這里注意 teacher.c 中供 Java 使用的方法必須按照 JNI 格式寫康辑!(com_example_ndkdemo_MainActivity 這是java調(diào)用類的權(quán)限類名)

#include <jni.h>
#include "include/age.h"


int add_one(int age) {
    age += 1;
    return age;
}

JNIEXPORT jint JNICALL Java_com_example_ndkdemo_MainActivity_get(JNIEnv *env,
        jobject obj);

JNIEXPORT jint JNICALL Java_com_example_ndkdemo_MainActivity_get(JNIEnv *env,
        jobject obj) {
    int result = get_five_years_later_age(12);
    result = add_one(result);
    return result;
}
  • 編寫我們的Android.mk
LOCAL_PATH := $(call my-dir)

# 重新打包已存在的 .so 庫
include $(CLEAR_VARS)
LOCAL_MODULE    := student
LOCAL_SRC_FILES := libstudent.so
# .so 頭文件
LOCAL_EXPORT_C_INCLUDES := include
include $(PREBUILT_SHARED_LIBRARY)

# 
include $(CLEAR_VARS)
LOCAL_MODULE    := teacher
LOCAL_SRC_FILES := teacher.c
LOCAL_LDLIBS    += -L$(SYSROOT) -llog
LOCAL_CFLAGS    := -g
# 引用重新打包后的 .so 庫
LOCAL_SHARED_LIBRARIES := student
include $(BUILD_SHARED_LIBRARY)
  • !!! 編寫我們的 Application.mk

這個(gè)在現(xiàn)在才提出來摄欲,其實(shí)是有原因的,跟著一起編下來的小伙伴會發(fā)現(xiàn)晾捏,如果沒有 Application.mk 中指定的參數(shù)蒿涎,會導(dǎo)致各種的方法索引不到,庫的格式錯(cuò)誤的問題惦辛。筆者大概是在編armeabi-v8a過程中劳秋,引發(fā)這個(gè)問題,這才在這里提出Application.mk胖齐,讓小伙伴們可以更加貼切地感受Application.mk的強(qiáng)大之處玻淑!

Application.mk

APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti -fexceptions 
APP_ABI := armeabi-v7a armeabi

這里筆者只說明Application.mk用到的變量:

APP_STL:=gnustl_static
# APP_STL := stlport_static    --> static STLport library
# APP_STL := stlport_shared    --> shared STLport library
# APP_STL := system            --> default C++ runtime library

APP_CPPFLAGS:=-frtti -fexceptions 
# C++代碼的編譯, < r15 此變量只適用于C++呀伙,> 15 適用于C和C++

APP_ABI := armeabi armeabi-v7a x86 # 指定輸出架構(gòu) 
  • 編譯我們的 .so 庫
    project -> clean


    Package existed so.png
  • 編寫我們的Java調(diào)用類
    上面我們有提到 com_example_ndkdemo_MainActivity补履, 也就是我們JNI格式方法中包含的字段,而且剿另,本地方法需要在這個(gè)類中加載庫和本地方法箫锤,而其它類可以調(diào)用該類中的方法贬蛙,但不能在其它類中再次加載動態(tài)庫的本地方法

package com.example.ndkdemo;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity"; 
    
    static {
        System.loadLibrary("student");
        System.loadLibrary("teacher");
    }
    public static native int get();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "get() = " + get());
    }

}
  • Run!!!


    Make you a hello world.png

寫在最后

Android NDK Eclipse 入門篇目到這里就結(jié)束了,之前開發(fā)過程中都是簡簡單單地了解谚攒,現(xiàn)在特意花兩天時(shí)間整理了基礎(chǔ)的流程阳准,感覺吧,寫文章還是比較費(fèi)時(shí)費(fèi)勁的馏臭,但是可以分享給一起工作的小伙伴們野蝇,我也是拼了老命堅(jiān)持寫下來了,筆者也會多寫寫總結(jié)括儒,多輸出輸出绕沈。而NDK的編譯遠(yuǎn)不止于此,還有更多的功能帮寻,我也希望能夠抽空整理一番分享給小伙伴們乍狐。

JNIDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市固逗,隨后出現(xiàn)的幾起案子澜躺,更是在濱河造成了極大的恐慌,老刑警劉巖抒蚜,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異耘戚,居然都是意外死亡嗡髓,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進(jìn)店門收津,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饿这,“玉大人,你說我怎么就攤上這事撞秋〕づ酰” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵吻贿,是天一觀的道長串结。 經(jīng)常有香客問我,道長舅列,這世上最難降的妖魔是什么肌割? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮帐要,結(jié)果婚禮上把敞,老公的妹妹穿的比我還像新娘。我一直安慰自己榨惠,他們只是感情好奋早,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布盛霎。 她就那樣靜靜地躺著,像睡著了一般耽装。 火紅的嫁衣襯著肌膚如雪愤炸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天剂邮,我揣著相機(jī)與錄音摇幻,去河邊找鬼。 笑死挥萌,一個(gè)胖子當(dāng)著我的面吹牛绰姻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播引瀑,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼狂芋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了憨栽?” 一聲冷哼從身側(cè)響起帜矾,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屑柔,沒想到半個(gè)月后屡萤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掸宛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年死陆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唧瘾。...
    茶點(diǎn)故事閱讀 38,650評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡措译,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饰序,到底是詐尸還是另有隱情领虹,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布求豫,位于F島的核電站塌衰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏注祖。R本人自食惡果不足惜猾蒂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望是晨。 院中可真熱鬧肚菠,春花似錦、人聲如沸罩缴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至烙荷,卻和暖如春镜会,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背终抽。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工添祸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留著隆,地道東北人具壮。 一個(gè)月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓溯壶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親圃郊。 傳聞我的和親對象是個(gè)殘疾皇子价涝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容