- 前言
- ndk環境配置
- 下載ndk
- 配置ndk路徑
- 配置ndk環境路徑
- ndk上手
- 實現c函數, 並編譯生成.so
- 其餘項目使用.so
- 最後
說下個人AndroidStudio版本是2.3.3, 尚未更新到3.x(手動委屈), 主要仍是想把手頭項目搞定了再跳坑. 而後此次添加了mac平臺的配置, 其實沒多大區別, 固然, linux也是大同小異, 畢竟android studio是通用的. 爲何要使用.so?從我本身的理解出發, 有幾點很是主要:java
- 你每每不是一我的在開發, 並且你的合做夥伴不可能把全部源碼給你編譯. 因此一個解決方案就是他編譯生成.so給你, 再給你個.h文件, 告訴你有哪些函數.對於這些函數, 你只須要知道功能而不須要知道實現細節.
- .so文件是依靠c/cpp編譯而成的, c/cpp語言的重要性不言而喻, 歷史地位也是不可撼動的, 並且一些原本已經寫好的庫, 不必說由於要寫Android就換成java從新實現一遍. 因此須要讓Android去支持那些已有的庫.
- java源碼反編譯一下很容易拿到的, 固然能夠加固apk, 會好一點. 而編譯生成.so以後, c的源碼就很難看到了.
有個比較頭痛的事情叫作配環境linux
- mac: 用vim打開.bash_profile, 在最後加入ndk所在路徑.
vim .bash_profile
複製代碼
更新配置文件並測試ndk-build指令android
- win:
打開PowerShell測試一下vim
終於能夠開始使用NDK了, 或者你能夠管它叫JNIbash
- 在包目錄下建立HellJNI類, 並寫入必要代碼
public class HelloJNI {
//一個加法函數, 用c實現
public native int AddC (int a, int b);
static {
//加載庫, 注意庫名的一致性
System.loadLibrary("HelloC");
}
}
複製代碼
使用javah命令生成頭文件, 注意! 這是重點, 要背!(滑稽臉)而後新建一個同名c/cpp.app
- mac:
- win:
- 拷貝.h文件中生成的函數, 在c/cpp中實現它.
/*
* Class: com_so_myapplication_HelloJNI
* Method: AddC
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_so_myapplication_HelloJNI_AddC
(JNIEnv *, jobject, jint, jint);
複製代碼
#include "com_so_myapplication_HelloJNI.h"
JNIEXPORT jint JNICALL Java_com_so_myapplication_HelloJNI_AddC
(JNIEnv * env, jobject obj, jint a, jint b){
return a + b;
}
複製代碼
在jni目錄下建立Android.mk和Application.mk文件並寫入內容, 重點! Android.mk內容以下:ide
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := HelloC
LOCAL_SRC_FILES := com_so_myapplication_HelloJNI.c
LOCAL_SRC_FILES += util.c
include $(BUILD_SHARED_LIBRARY)
複製代碼
有2個要點:函數
- LOCAL_MODULE的名稱要和以前
System.loadLibrary("HelloC");
中的名稱一致;- Win下須要再加一個空的
util.c
文件進行編譯, 不然會報錯, 不信能夠試試(手動滑稽), mac/linux下無需. Application.mk內容以下:
APP_ABI := all
#APP_ABI := armeabi armeabi-v7a x86 mips arm64-v8a mips64 x86_64
複製代碼
有2個要點:測試
- 我知道這樣不太專業, 不過這個ABI問題牽扯太多, 暫不細說, 主要是和不一樣cpu有關.
- armeabi彷佛已被淘汰. 配置build.gradle, 重中之重! 先是build.gradle一覽:
android {
compileSdkVersion 26
buildToolsVersion "26.0.3"
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
defaultConfig {
applicationId "com.so.myapplication"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
moduleName "HelloC" //System.loadLibrary("HelloC");
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
複製代碼
ndk須要配置, 注意名字匹配!gradle
ndk {
moduleName "HelloC" //System.loadLibrary("HelloC");
}
複製代碼
sourceSets配置
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
複製代碼
在gradle.properties中加上一句
android.useDeprecatedNdk=true
複製代碼
而後就是ndk-build了, 再查看是否生成成功!
你能夠在這個項目中使用這個由c實現的加法函數了, 可是咱們有更酷的事情要作, 那就是在__另外的項目__中用這個函數.
這件事其實沒有很難, 基本靠兩步. 第一步就是將前一個項目生成的libs目錄下的所有內容拷貝到AndroidStudio自帶的libs目錄下
第二步就是建立一個和前一個生成libs目錄的項目相同的包和類, 類中寫入的內容也是同樣的.順帶加下build.gradle中的sourceSets, 不記得位置, 參考以前的build.gradle一覽.
public class HelloJNI {
public native int AddC (int a, int b);
static {
System.loadLibrary("HelloC");
}
}
複製代碼
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
複製代碼
最後測試下效果, 這段代碼我就不解釋了, 這看不懂也就告別手錶了!
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv_testc = (TextView) findViewById(R.id.tv_testc);
tv_testc.setText("add: " + new HelloJNI().AddC(1, 2));
}
}
複製代碼
完結散花! 喜歡記得點贊或者關注我哦, 有問題和意見能夠評論區~~