您好,登錄后才能下訂單哦!
我們平時使用的動態庫都是由C/C++開發最后生成的.so文件。
可以先看看一個JNI的開發過程。
一. 開發JNI
有兩種方式,現在一種比較快的方式是AndroidStudio你在創建項目選擇Module的時候它會給你個JNI的模板,直接使用那個就行。
但是我還是比較喜歡傳統的方法。
簡單來說傳統的方式就是你用命令來把java文件變成C++的頭文件
簡單演示一遍,先寫個java類
public class TestJni { static { System.loadLibrary("KylimTest"); } public static native String getMsg(); }
定義了一個native修飾的方法,在代碼調用這個方法之后JNI就會自動調用到動態庫中相應的方法。
將這個類用命令生成頭文件,來到文件夾路徑下輸入命令
javah -jni 包名.類名
可以看到默認會生成一個.h的頭文件,自動命名為 包名_類名.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_kylim_nativetest_TestJni */ #ifndef _Included_com_kylim_nativetest_TestJni #define _Included_com_kylim_nativetest_TestJni #ifdef __cplusplus extern "C" { #endif /* * Class: com_kylim_nativetest_TestJni * Method: getMsg * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_kylim_nativetest_TestJni_getMsg (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
主要的核心就是這句
JNIEXPORT jstring JNICALL Java_com_kylim_nativetest_TestJni_getMsg (JNIEnv *, jclass);
其它的我也不清楚,都是C相關的, 如果你嫌用命令生成麻煩,你可以自己創建一個.h文件然后方法命名就按照這樣的規范去寫
頭文件只是為了定義,我們需要自己寫原文件,所以要創建一個.cpp結尾的文件
#include "com_kylim_nativetest_TestJni.h" JNIEXPORT jstring JNICALL Java_com_kylim_nativetest_TestJni_getMsg (JNIEnv *env, jclass cls){ jstring result = env->NewStringUTF("結果是"); return result; }
方法命名是有規范的,看Demo也知道怎么規范了,沒必要多解釋,這樣兩端的代碼就寫完了,但是僅僅這樣是無法運行項目的。
還需要些一些配置,因為在AndroidStudio中是Gradle去幫我們編譯C++的代碼,所以需要寫這些配置。如果你不是用AS開發,你用其它工具開發直接生成.so文件再丟進AS中的話,可以忽略這一步。
先看看我的Jni目錄
要創建一個Android.mk
#固定寫法 LOCAL_PATH:=$(call my-dir) #固定寫法 include $(CLEAR_VARS) #生成so名稱 LOCAL_MODULE := KylimTest LOCAL_SRC_FILES := testone.cpp #固定寫法 include $(BUILD_SHARED_LIBRARY)
具體的配置可自行去查找,這里不是主要講JNI的,所以就不講這么細。
還需要一個Application.mk
# 選擇不同的 ABI,多個使用空格作為分隔符,全部是all # APP_ABI := armeabi armeabi-v7a APP_ABI := armeabi-v7a # 指定要使用的運行時 APP_STL := c++_static
當然這樣還不行,都說了是Gradle進行編譯,那么肯定還要在Gradle中寫一些配置
android { defaultConfig { ndkBuild { //指定 Application.mk 的路徑 arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk" //指定生成哪些平臺的 so 文件 abiFilters "armeabi-v7a" //cFlags 和 cppFlags 是用來設置環境變量的, 一般不需要動 cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2" cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2" } } sourceSets { main { jni.srcDirs = ['src/main/jni'] } } externalNativeBuild { ndkBuild { path file('src/main/jni/Android.mk') } } }
這樣就能簡單的跑一個JNI的Demo,總的來說就是Java這邊寫一個類定義一些native方法和加載,C++這邊寫具體的方法實現。
二.用Go開發動態庫
上面說的原生方法是用C/C++進行開發的,那么如果你不會C++的話怎么辦,C++的學習也并非這么容易,就拿兩邊的類型來說,一開始新手肯定會碰到類型轉換的問題,往往會先勸退一些人,但是Go不一樣,有Java基礎的話學起go還是挺快的。
那么用Go開發的動態庫是怎樣的?也是SO文件嗎,是不是也像C++一樣,編譯后經過某步操作生成SO文件。
我看到網上有些文章確實是寫怎么生成so的,但是說得太少,感覺不可靠,直到我看到官方有寫。
可以在官方中看到是有一個mobile的庫的
https://github.com/golang/mobile
讀下去它會指引你去wiki
https://github.com/golang/go/wiki/Mobile
可以看出它會打出一個aar的文件,那么aar對于我們接入來說確實很方法,但我很想探究這個aar里面究竟是什么,所以我們需要打出一個aar然后解壓看看它里面到底是什么
這里先說一下,下載這個庫之前,你本地肯定先要配置好Go的環境
然后按照這里的流程就行下載
go get -d golang.org/x/mobile/example/basic
但這輸入這條命令需要科學上網的方式才能下載,總的來說很麻煩。
所以我們可以直接克隆mobile的庫,就是上面的這個鏈接 https://github.com/golang/mobile
直接下載下來,除此之外,還需要tools,這些都在Go中,鏈接 https://github.com/golang/tools
將這兩個下載下來,然后拷貝到你的Go的以下路徑
go/src 創建一個文件夾golang.org/x ,把這兩個文件夾丟進去
然后輸入命令
gomobile init
可以輸入命令 查看安裝配置是否成功
gomobile bind -help
如果配置成功會給你一些提示
我感覺文檔寫得還是不算清楚,但是它有告訴你用什么命令生成aar
gomobile bind -o app/hello.aar -target=android golang.org/x/mobile/example/bind/hello
你在GoPath中創建一個Go文件,我是用GoLand進行開發的,項目的目錄設置成GoPath,編寫完之后,可以直接在文件中運行
gomobile bind -o 輸入文件名.aar -target=android
這樣就能在文件夾中生成一個aar
接著我們看看aar里面是什么,解壓
首先可以看到生成這些ABI的so文件,再看看Manifest
這里有限制最低版本,所以如果你的版本比他還低的話就需要注意一下了
然后res里面是可以看到沒有文件的。
最后我們反編譯class文件
因為這不是Demo,直接是寫公司的項目,所以有些地方要碼,但是不影響。
從這里看得出,go幫我們生成了一個java文件,這個java文件定義了再Go中命名的原生方法。
其實從這里就可以看出,Go用的也基本是我們最上面寫的JNI的方法,只是他幫你封裝起來了而已
但是他的原生代碼是不是轉成C++的我就不清楚了,因為我不會反編譯SO文件。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。