① 安卓apk解壓後得到的.so文件能直接放項目裡面調用裡面的方法嗎
使用Androidstudio創建一個Android項目
打開Androidstudio創建一個項目,命名為tryndk
在項目中新創建一個類,在其中聲明native方法在src/main目錄下創建一個工具類,用來存放native方法
在javautils類創建兩個方法,聲明為native
然後選中項目,點擊build->make project,在項目中的build->intermediates->classes->debug->com->example->tryndk下就能看見javautils.class文件了
在Androidstudio中打開終端(View->ToolWindows->Terminal)在terminal中進入到main目錄中,然後在鍵入javah -d jni -classpath ../../build/intermediates/classes/debug com.example.tryndk.javautils記得debug 後面有個空格。然後就能在src/main目錄下看到jni文件夾,裡面存放了一個頭文件com_example_tryndk_javautils.h,裡面生成了函數聲明,
Java_com_example_tryndk_javautils_getStringFromNative為方法名,其中getStringFromNative為在javautils文件中創建的getStringFromNative方法。
然後在jni目錄下創建一個c文件命名為MyJni.c,實現相應的方法
方法中就是返回了一個字元串。
② 如何動態載入android的so文件,如何壓縮apk尺寸
在Android中調用動態庫文件(*.so)都是通過jni的方式,而且往往在apk或jar包中調用so文件時,都要將對應so文件打包進apk或jar包,工程目錄下圖:
以上方式的存在的問題:
1、缺少靈活性比較類似靜態載入了(不是靜態載入),能載入的so文件綁定死了;
2、但so文件很多或很大時,會導致對應的apk和jar包很大;
3、不能動態的對so文件更新;
Android中載入so文件的提供的API:
void System.load(String pathName);
說明:
1、pathName:文件名+文件路勁;
2、該方法調用成功後so文件中的導出函數都將插入的系統提供的一個映射表(類型Map);
看到以上對System.load(String pathName);的函數說明可定有人會想到將so文件放到一個指定的目錄然後再通過參數pathName直接引用該目錄的路勁和對應的so文件問題不就解決了嗎?
這里有個問題被忽略了,那就是System.load只能載入兩個目錄路勁下的so文件:
1、/system/lib ;
2、安裝包的路勁,即:/data/data/<packagename>/…
而且這兩個路勁又是有許可權保護的不能直接訪問;
問題解決方法:
先從網路下載so文件到手機目錄(如:/test/device/test.so) –> 將test.so載入到內存(ByteArrayOutputStream) –> 然後保存到對用安裝包目錄;
具體代碼如下:
try {
String localPath = Environment.getExternalStorageDirectory() + path;
Log.v(TAG, "LazyBandingLib localPath:" + localPath);
String[] tokens = mPatterns.split(path);
if (null == tokens || tokens.length <= 0
|| tokens[tokens.length - 1] == "") {
Log.v(TAG, "非法的文件路徑!");
return -3;
}
// 開辟一個輸入流
File inFile = new File(localPath);
// 判斷需載入的文件是否存在
if (!inFile.exists()) {
// 下載遠程驅動文件
Log.v(TAG, inFile.getAbsolutePath() + " is not fond!");
return 1;
}
FileInputStream fis = new FileInputStream(inFile);
File dir = context.getDir("libs", Context.MODE_PRIVATE);
// 獲取驅動文件輸出流
File soFile = new File(dir, tokens[tokens.length - 1]);
if (!soFile.exists()) {
Log.v(TAG, "### " + soFile.getAbsolutePath() + " is not exists");
FileOutputStream fos = new FileOutputStream(soFile);
Log.v(TAG, "FileOutputStream:" + fos.toString() + ",tokens:"
+ tokens[tokens.length - 1]);
// 位元組數組輸出流,寫入到內存中(ram)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = fis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
// 從內存到寫入到具體文件
fos.write(baos.toByteArray());
// 關閉文件流
baos.close();
fos.close();
}
fis.close();
Log.v(TAG, "### System.load start");
// 載入外設驅動
System.load(soFile.getAbsolutePath());
Log.v(TAG, "### System.load End");
return 0;
} catch (Exception e) {
Log.v(TAG, "Exception " + e.getMessage());
e.printStackTrace();
return -1;
}
③ 怎麼把so打包打包進apk
在apk里打包進.so文件的方法
有兩種方法,
1 是在Android.mk文件里增加
LOCAL_JNI_SHARED_LIBRARIES := libxxx
這樣在編譯的時候,NDK自動會把這個libxxx打包進apk;
放在youapk/lib/目錄下。
2 是在應用的目錄下手工建
libs/armeabi
目錄,然後把libxxx.so拷貝到這個目錄下,
這樣NDK就會自動把這個libxxx.so打包進apk,位置還是在
放在youapk/lib/目錄下。
在代碼里,使用
System.loadLibrary("xxx");
就可以載入這個動態庫了。
這里要注意,參數只寫xxx就可以了,不需要寫libxxx,也不需要寫libxxx.so。
還有一點要說明,System.loadLibrary這個函數會在如下路徑搜索libxxx.so文件:
/system/lib
/data/data/you apk package/lib
但,如果libxxx.so還依賴其它.so文件,比如libyyy.so,則System.loadLibrary只會
在/system/lib目錄下去找,如果沒找到,它不會自動到/data/data/you apk package/lib
下去找,這個時候就會報動態庫沒找到的錯;
解決方法是在load libxxx.so之前,先load libyyy.so,如下:
System.loadLibrary("yyy");
System.loadLibrary("xxx");
④ 怎麼把so打包打包進apk
打包這個動作免去了:將libxxx.so文件push到/system/lib/目錄下而需要取得/system/lib 目錄 的寫許可權實現步驟如回下:
1、項目根目答錄下建立libs/armeabi目錄;
2、將libxxx.so文件到 libs/armeabi/下;
3、編譯輸出的.apk文件中已經包括.so文件了;
4、安裝APK文件,即可直接使用JNI中的方法。
~如果你認可我的回答,請及時點擊【採納為滿意回答】按鈕
~~手機提問的朋友在客戶端右上角評價點【滿意】即可。
~你的採納是我前進的動力
~~O(∩_∩)O,記得好評和採納,互相幫助,謝謝。
⑤ 如何載入so文件 android
android中載入so文件:
在Android中調用動態庫文件(*.so)都是通過jni的方式,而且往往在apk或jar包中調用so文件時,都要將對應so文件打包進apk或jar包,工程目錄下圖:
Android中載入so文件的提供的API:
void System.load(String pathName);
說明:
1、pathName:文件名+文件路勁;
2、該方法調用成功後so文件中的導出函數都將插入的系統提供的一個映射表(類型Map);
3、具體代碼如下:
try {
String localPath = Environment.getExternalStorageDirectory() + path;
Log.v(TAG, "LazyBandingLib localPath:" + localPath);
String[] tokens = mPatterns.split(path);
if (null == tokens || tokens.length <= 0
|| tokens[tokens.length - 1] == "") {
Log.v(TAG, "非法的文件路徑!");
return -3;
}
// 開辟一個輸入流
File inFile = new File(localPath);
// 判斷需載入的文件是否存在
if (!inFile.exists()) {
// 下載遠程驅動文件
Log.v(TAG, inFile.getAbsolutePath() + " is not fond!");
return 1;
}
FileInputStream fis = new FileInputStream(inFile);
File dir = context.getDir("libs", Context.MODE_PRIVATE);
// 獲取驅動文件輸出流
File soFile = new File(dir, tokens[tokens.length - 1]);
if (!soFile.exists()) {
Log.v(TAG, "### " + soFile.getAbsolutePath() + " is not exists");
FileOutputStream fos = new FileOutputStream(soFile);
Log.v(TAG, "FileOutputStream:" + fos.toString() + ",tokens:"
+ tokens[tokens.length - 1]);
// 位元組數組輸出流,寫入到內存中(ram)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = fis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
// 從內存到寫入到具體文件
fos.write(baos.toByteArray());
// 關閉文件流
baos.close();
fos.close();
}
fis.close();
Log.v(TAG, "### System.load start");
// 載入外設驅動
System.load(soFile.getAbsolutePath());
Log.v(TAG, "### System.load End");
return 0;
} catch (Exception e) {
Log.v(TAG, "Exception " + e.getMessage());
e.printStackTrace();
return -1;
}