首先在此之前希望你已經掌握了基本JNI常識的運用,比如Java代碼如何調用本地native的方法,native方法如何訪問本地變量,本地方法等以及其他相關的基礎知識。在此我還是貼上Activity的部分代碼,如下:
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
public String name = "test";
private int source[] = { 1, 4, 0, 7, 33, 11 };
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
public native String updateNameFromC();//屬性訪問
public native String getMethod();//方法訪問
public native void getArray(int arrays[]);
//引用解決什么問題呢,什么時候通知JVM回收JNI的對象
public native void getLocalReference();
//緩存策略,對象生命周期的問題
public native void cachede();
//測試
public native String test(String str);
同理,本地cpp的代碼如下:
#include <jni.h>
#include <string>
#include <string.h>
#include "stdlib.h"
#include <android/log.h>
//首先將a強制聲明為指向整數的指針,然后讀取指針對應的整數
int compare(const void *a,const void *b){
return (*(int *)a-*(int *)b);
}
#define TAG "myDemo-jni" // 這個是自定義的LOG的標識
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定義LOGD類型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定義LOGI類型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定義LOGW類型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定義LOGE類型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定義LOGF類型
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_ee_ndkdemo_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
運行程序,則會發現在下面的目錄中生成了不同的.so庫,如下:
好的,第一步已經完成。
其次,新建一個項目,將其不同的.so庫拷貝到項目的目錄下,這里有兩種方法,第一種,將.so庫拷貝到項目src->main->jniLibs下,不同的架構放在這個目錄的不同文件夾下面即可,這是最簡單的;第二種,將.so庫拷貝到項目app->libs中,不同的架構放在這個目錄的不同文件夾下面即可,但是這時候要在build.gradle中配置
rceSets{
main{
jniLibs.srcDirs = ['libs']
}
}
這時候就會涉及到如何引用.so庫里面的方法了,其實調用So庫里的方法也有兩種方式:
(1)So庫有對應的jar包,把jar包放進libs里就可以調用so庫里面的方法了,當然得先把so放進jniLibs里;
(2)只有So庫,沒有jar包,下面詳細討論這種情況…..
沒有jar包又想調用so里的方法,其實也是很簡單的,前提當然是要把so庫放進jniLibs里,然后看下面的代碼
public class MainActivity {
static {
System.loadLibrary("native-lib");
}
public String hh(){
return stringFromJNI();
}
public static native String stringFromJNI();
public static native String getMethod();
}
實際上我這是希望在另外一個項目中調用之前打包成so庫的本地方法
stringFromJNI(),事實上中間有一個必須要注意的細節,就是調用已經打包so庫的那個類,必須要與已經生成的so庫的類名,包名都要一致,否則就會出現問題,這是一個細節。所以筆者最后發現只有so庫的調用實際上還是相對麻煩一下,因為你要調用的一些第三方的so庫,比人不會告訴你他們的報名,已經加載這個so庫所在的類名。相反例如百度推送以及七牛云等相關的so庫,別人會額外再提供你一個相關的jar包,我們只需要操作jar包就Ok了,所以最終我認為對第三方so庫里面方法的調用,so庫配jar包的使用比單純的so庫的使用要簡潔的多。