




下載本文檔
版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
【移動應用開發(fā)技術】Android中怎么利用Robolectric加載運行本地So動態(tài)庫
這篇文章將為大家詳細講解有關Android中怎么利用Robolectric加載運行本地So動態(tài)庫,文章內(nèi)容質(zhì)量較高,因此在下分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。前言Robolectric是Android的單元測試框架,運行無需Android真機環(huán)境直接運行在JVM之上,所以在testcase
運行速度效率上有了很大提升,接近于JavaJUnittest(JUnittest>Robolectric?
androidTest)。不過框架本身并不支持so本地庫的加載使用,加載時會直接報錯,因為實際上運行環(huán)境是電腦機器,而我們打出的so
文件是給手機上用的所以當然會報錯。雖然在GitHub上很多人問過關于使用so
的問題但基本都建議說不要在單元測試中去加載本地庫,這在原則上是要這么做,但可能有些項目中做起來就有些困難了,比如在代碼結構不夠好、依賴耦合較大或者本身就對so
庫依賴很大的情況下。所以下面說說在項目中Robolectric要怎么解決需要加載運行本地so庫這個問題。動態(tài)庫動態(tài)庫又稱動態(tài)鏈接庫(Dynamic-linklibrary縮寫DLL),是一個包含可由多個程序同時使用的代碼和數(shù)據(jù)的庫,DLL
不是可執(zhí)行文件。動態(tài)鏈接提供了一種方法,使進程可以調(diào)用不屬于其可執(zhí)行代碼的函數(shù)。函數(shù)的可執(zhí)行代碼位于一個DLL中,該DLL
包含一個或多個已被編譯、鏈接并與使用它們的進程分開存儲的函數(shù)。DLL還有助于共享數(shù)據(jù)和資源。多個應用程序可同時訪問內(nèi)存中單個DLL副本的內(nèi)容。DLL
是一個包含可由多個程序同時使用的代碼和數(shù)據(jù)的庫。Windows下動態(tài)庫為.dll后綴(一般為PE格式),在Linux在為.so后綴(一般為
ELF格式),macOS下為.dylib后綴(一般為Mach-O格式)。由于CPU
架構和動態(tài)庫文件格式的不同因而在不同平臺下不能通用。其它細節(jié)的東西就不展開了因為也不會:-)而Android本身是Linux系統(tǒng),所以用的動態(tài)庫也是.so的文件,因而運行與JVM的Robolectric
是不能直接加載使用的(Linux某些情況下可用,下面提到)。Robolectric中使用動態(tài)庫我們知道動態(tài)庫一般都是打給特定平臺、特定CPU架構用的,所以要解決在Robolectric下加載運行so動態(tài)庫的問題的思路就是在不同
Robolectric運行平臺下去處理加載不同的動態(tài)庫,所以你要在Ronbolectriv中使用的so動態(tài)庫***要有源碼不然在macOS和
Windows下就不就好處理了。Note:注意動態(tài)庫名稱已lib開頭。Linux下Robolectric中使用動態(tài)庫Android與Linux同氣連枝,所以底層的東西很多是通用的,動態(tài)庫也一樣。我們Android使用so時一般也要對不同CPU
架構的手機下使用不同的so文件,譬如:armeabi-v7a、mips、x86。而我們使用的LInux發(fā)行版一般都是64
位的,所以原理上我們使用x86-64的動態(tài)庫是可以的,不過可能需要處理依賴庫問題如果你的本地代碼里有include其它依賴的話。如果沒加進來
Robolectric運行就會報如下的錯誤:java.lang.UnsatisfiedLinkError:
xxx/xxx.so
xxx
動態(tài)庫找不到。xxx.so就是你所使用so的依賴,比如把新浪微博SDK的x86-64的libweibosdkcore.so加載進來的話就會報
liblog.so等找不到,因為libweibosdkcore中有對Androidliblog等so庫的依賴。那這個問題怎么解決呢。我們想想打包
so庫時用的是ndk,需要使用ndk-bundle工具,我們想想,跟編譯apk差不多,apk打包需要sdk工具,compileSdk
里就是我們編譯的依賴,里面有android.jar。所以我們可以到ndk-bundle里找找,***我們發(fā)現(xiàn)不同CPU架構下的so
依賴庫都是有的,像我們一般的電腦64位CPU即可使用arch-x86_64下的so動態(tài)庫,所以我們只需要在加載我們程序的so
庫之前加載這些必須的依賴即可。處理代碼后面貼出。注意ndk-bundle里的so也是只能在Linux下用的,如果用于其它平臺會報錯,原因前面已說明。java.lang.UnsatisfiedLinkError:
xxx.so:
unknown
file
type,
first
eight
bytes:
0x7F
0x45
0x4C
0x46
0x02
0x01
0x01
0x00macOS下Robolectric中使用動態(tài)庫前面已提到,不同平臺下動態(tài)鏈接庫是不通用的,所以必須對源碼重新編譯打包以移植到不同平臺下,如果你的so沒有源碼的話那在macOS和Windows
下就行不通了。重新打包我們可以按如下兩步進行:#
先生成
.o
,-I
后加進
Java
jni
的編譯依賴
cc
-c
-I/System/Library/Frameworks/JavaVM.framework/Headers
*.cpp
#
打包成
.dylib
g++
-dynamiclib
-undefined
suppress
-flat_namespace
*.o
-o
something.dylib某些依賴庫可以到/usr/lib下找找,比如libc和libstdc++。Windows下Robolectric中使用動態(tài)庫本人沒有在Windows下開發(fā)所以這部分就略過了,思路是一樣的。Sample下面是簡單的處理代碼示例。首先新建一個包含jni的工程,里面寫個基本的本地庫,如下:正常流程//
native-lib.cpp
#include
<jni.h>
#include
<string>
extern
"C"
jstring
Java_xyz_rocko_rsnl_nativeinterface_NativeSample_stringFromJNI(
JNIEnv
*env,
jobject
/*
this
*/)
{
//
簡單返回個字符串
std::string
hello
=
"Hello
from
Native.";
return
env->NewStringUTF(hello.c_str());
}然后在Application啟動時會加載這個本地庫://NativeLibsApplication.javapublic
class
NativeLibsApplication
extends
Application
{
//
Used
to
load
the
'native-lib'
library
on
application
startup.
static
{
System.loadLibrary("native-lib");
}
}此時運行Robolectric的testcase就發(fā)生如下報錯:java.lang.UnsatisfiedLinkError:
no
native-lib
in
java.library.path處理后的流程首先流程應該在我們的代碼里避免可以直接加載so動態(tài)庫,然后Robolectric在啟動時自己去加載需要的動態(tài)庫。//NativeLibsApplication.javapublic
class
NativeLibsApplication
extends
Application
{
@Override
public
void
onCreate()
{
super.onCreate();
loadNativeLibraries();
}
/**
*
簡單讓子類可自己實現(xiàn)
*/
protected
void
loadNativeLibraries()
{
//
代碼里真正加載本地庫的地方,當然你自己的可以處理地更解耦一點。
NativeLibrariesManager.loadNativeLibraries();
}
}然后我們的Robolectric里自定義自己的Application,里面根據(jù)需要在不同運行平臺下自己加載需要的本地動態(tài)庫,首先復制我們給
Robolectric用的本地庫到test的libs文件夾里,按不同平臺分類,如下圖:Linux下的我們從ndk-bundle里復制我們需要的.so,然后我們自己的本地庫打一個x86-64的即可,注意
compileSdkVersion選上高一點支持x86-64的版本。然后重新移植打出macOS下的動態(tài)庫,簡單寫個打包腳本如下://make_macOS_dylib.sh#!/usr/bin/env
bash
OUTPUT=../../../build/intermediates/dylibs
mkdir
-p
${OUTPUT}
#
.o
file
cc
-c
-I/System/Library/Frameworks/JavaVM.framework/Headers
*.cpp
-o
${OUTPUT}/libnative-lib.o
#
.dylib
file
g++
-dynamiclib
-undefined
suppress
-flat_namespace
${OUTPUT}/*.o
-o
${OUTPUT}/libnative-lib.dyliblibnative-lib.dylib就是我們要的。然后我們自定義Application處理加載這些動態(tài)庫://RobolectricApplication.javapublic
class
RobolectricApplication
extends
NativeLibsApplication
{
static
{
ShadowLog.stream
=
System.out;
//Android
logcat
output.
}
@Override
protected
void
loadNativeLibraries()
{
//Disable
super
class
load
so
file.
//super.loadNativeLibraries();
Log.d(TAG,
"=====>>
Robolectric
start
native
libraries.");
String
libsBasePath
=
new
File(new
File("").getAbsolutePath()
+
"/src/test/libs").getAbsolutePath();
String
os
=
System.getProperty("");
os
=
!TextUtils.isEmpty(os)
?
os
:
"";
List<File>
soFileList
=
new
ArrayList<>();
String
systemArchPath
=
libsBasePath
+
"/framework/";
//!!!
64
位機器下處理
if
(os.contains("Mac"))
{
//load
system
library
if
need
String
macSysSoBasePath
=
systemArchPath
+
"macOS/";
soFileList.addAll(addLibs(macSysSoBasePath));
//
App
so...
String
macAppSoPath
=
libsBasePath
+
"/macOS_x86-64/";
//
mac下so要使用macOS專用庫
soFileList.addAll(addLibs(macAppSoPath));
}
else
if
(os.contains("Linux"))
{
//load
system
library
if
need
String
linuxSysSoBasePath
=
systemArchPath
+
"arch_x86-64/";
soFileList.addAll(addLibs(linuxSysSoBasePath));
//
App
so...
String
linuxAppSoPath
=
libsBasePath
+
"/linux_x86-64/";
soFileList.addAll(addLibs(linuxAppSoPath));
}
else
if
(os.contains("Windows"))
{
//
ignore
}
for
(File
soFie
:
soFileList)
{
System.load(soFie.getAbsolutePath());
}
}
private
List<File>
addLibs(@NonNull
String
path)
{
File[]
basePathFiles
=
new
File(path).listFiles();
List<File>
pathFilesList
=
new
ArrayList<>();
if
(basePathFiles
!=
null
&&
basePathFiles.length
>
0)
{
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 修橋合同范本
- 2025年安徽道路運輸從業(yè)資格證考試內(nèi)容是什么
- 包工料水電裝修合同范本
- 公司退休返聘合同范例
- 醫(yī)院人事勞務合同范本
- 全套合同范本目錄
- 傭金合同范本道客
- 全職抖音主播合同范本
- 農(nóng)村改水電合同范本
- 出租生態(tài)大棚合同范本
- 【道法】開學第一課 課件-2024-2025學年統(tǒng)編版道德與法治七年級下冊
- 中華民族共同體概論專家講座第一講中華民族共同體基礎理論
- 衛(wèi)生部病歷管理規(guī)定
- 2023年浙江省統(tǒng)招專升本考試英語真題及答案解析
- GB 9706.202-2021醫(yī)用電氣設備第2-2部分:高頻手術設備及高頻附件的基本安全和基本性能專用要求
- 神經(jīng)外科疾病健康宣教
- 2. SHT 3543-2017施工過程文件表格
- 分部分項工程項目清單
- 跌倒護理不良事件案列分析 - 腎內(nèi)科
- 電纜防火分析及措施
- 南水北調(diào)中線渠首段白蟻防治綜合治理試驗研究
評論
0/150
提交評論