【移動應用開發(fā)技術】Android中怎么利用Robolectric加載運行本地So動態(tài)庫_第1頁
【移動應用開發(fā)技術】Android中怎么利用Robolectric加載運行本地So動態(tài)庫_第2頁
【移動應用開發(fā)技術】Android中怎么利用Robolectric加載運行本地So動態(tài)庫_第3頁
【移動應用開發(fā)技術】Android中怎么利用Robolectric加載運行本地So動態(tài)庫_第4頁
【移動應用開發(fā)技術】Android中怎么利用Robolectric加載運行本地So動態(tài)庫_第5頁
免費預覽已結束,剩余2頁可下載查看

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(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. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論