Flutter外掛引入第三方jar包之armeabi

樂凡丶發表於2021-06-01

上次開發的相機外掛廠家提供的是一個AAR庫,匯入就可以使用,可以直接用原生UI控制元件渲染介面,也可以用外掛內方法回撥的資料傳遞到Flutter層進行展示。

今天公司又提供了另一臺相機的sdk,本來想著已經學會了aar外掛開發,這次又提供了一套jar和so檔案,又給我出難題。根據百度得知,jar檔案封裝了方法供開發者呼叫,而so檔案是和底層打交道的函式庫,所以和手機的CPU架構有關,一般分為armeabiarmeabi-v7aarm64-v8a等其他型別的架構。最原始的版本就是32位armeabi,而現在主流的手機一般都採用64位arm64-v8a,。

所以一般來說要對不同架構的手機提供不同的sdk包,當然也可以只使用armeabi,因為後兩種架構是可以向下相容的。所以一部分第三方服務商雖然提供的SDK包含各種架構的,也會順帶一句:只引入armeabi也能正常執行,還能減小包的體積。

然而我們這個相機廠商只提供armeabi架構的包

由於測試機是v8a的架構,而且flutter經過多個版本更新後,不能直接flutter run的時候指定平臺架構為32位的,則無法呼叫到so檔案,所以有不小的麻煩。這先按下不表。

一、匯入jar包和so檔案

匯入jar包

首先還是在plugin/android的目錄新建一個libs資料夾,然後將jar檔案放進去就好

image.png

然後在依賴裡一個一個匯入就好。

dependencies {
    implementation files('libs/hyfisheyepano.jar')
    implementation files('libs/mid-core-sdk-4.0.7.jar')
    implementation files('libs/org.apache.http.legacy.jar')
    implementation files('libs/wup-1.0.0.E-SNAPSHOT.jar')
    implementation files('libs/Xg_sdk_4.0.3_20180720_1441.jar')
    implementation files('libs/nv_sdk_v1.0.0.jar')
}
複製程式碼

匯入so檔案

so檔案包在編輯器中只需要放入指定位置,就可以被找到,在Android studio中需要放在src/main/jniLibs中,所以直接將檔案包一下子複製進去。

image.png

如果有多種架構的so檔案,同樣也是把包整體複製進來。

執行一下

這個時候,程式是可以正常跑起來了,不涉及到外掛功能的時候執行正常,一旦需要呼叫一下外掛的方法的時候,程式會直接奔潰退出,檢視控制檯,提示出Can't link the lib

image.png

這裡的提示語句是sdk裡使用try catch返回出來的,本意就是coundn't find "xxx.so",無法在程式裡面找到所需要的檔案,按照方法匯入了,怎麼又無法連結到,接著往下看。

二、載入so檔案

上面我們執行了一下,發現是jar包裡的方法需求呼叫so檔案,但是怎麼都呼叫不到,這又是什麼問題?

驗證安裝包

首先想到的是驗證一下檔案是否引入成功,如果檔案引入成功,可以直接檢視apk裡檢視到引入的檔案。所以首先找到安裝包的位置

當flutter執行於debug模式的時候,程式會先生成一個app-debug.apk的檔案,儲存在專案目錄中build/app/outputs/flutter-apk的這個位置,當然這裡同時也儲存了release版的安裝包。

在Android studio的選單欄中,找到build -> Analyze Apk這個功能,開啟我們的app-debug.apk

image.png

可以發現裡面包含了多種架構的jniLibs,而我們的手機是arm64-v8a,程式非常符合邏輯的就去對應的架構中去尋找需要檔案,而我們的檔案只有armeabi的版本,找不到檔案,外掛方法無法呼叫,程式就報錯崩潰

image.png

根據開頭提到的:armeabi-v7aarm64-v8a這兩種架構是可以向下相容的,聰明的你肯定想到可以把其他架構的檔案包刪掉就好,只有保留有內容的。

解決方法

解決方法就一句話,在build.gradle檔案中加上以下這句話:

android{
    defaultConfig{
        ndk {
            abiFilters 'armeabi'
        }
    }
}
複製程式碼

在這裡是通過 abiFilters 來指定我們需要的 ABI,也就是指定需要的CPU架構,加上上面語句後,在通過Analyze Apk的功能,可以看到:

image.png

安裝包裡只剩armeabi了,這樣的話,基本的3中架構呼叫檔案的時候,都會呼叫到這個包裡的檔案,程式就不會崩潰了。

這裡不得不插一句,因為我在開發外掛,在得知這個解決方法的時候,我將這個語句放入了android/build.gradle,沒有任何效果,而是應該寫在example/android/build.gradle的這個檔案裡,這裡才是安裝包生成時候所依賴的引數和配置。這個小問題卡了近我3個小時。

三、還是跑不起來?

在指定了ABI之後,程式不會崩潰了,因為程式直接跑不起來了。

9A6B5CF1532A01F43963CC2F848B6CD9.jpg

話不多說,還是直接看控制檯的報錯,發現缺少了最核心的檔案-libflutter.so。而在開始未指定ABI的時候,v8a的檔案包裡是有這個檔案的,現在這個檔案隨它一起蒸發了。

image.png

依然先開啟百度,輸入這個關鍵詞,有無數的答案。萬語千言就一個原因,在flutter構建apk的時候,需要指定對應的平臺,才會生成對應架構的libflutter.so檔案。

在舊版本的flutter中,可以直接執行flutter run --target-platform android-arm命名來指定平臺,新版又去掉了這個功能。只有釋出release的時候才能指定平臺,但不可能每修改一點,需要除錯了就打包一份吧。

網上還有很多其他方法,試了都不太管用。其實有個最不優雅但很實用的方法,直接再別的包裡拿一個libflutter.so檔案,放進armeabi包裡,執行成功。

image.png

  • 1、複製一份未指定ABI前的app-debug.apk
  • 2、修改檔案字尾apkzip並解壓
  • 3、將資料夾裡libs\arm64-v8a裡的libflutter.so拿出來
  • 4、放進外掛裡armeabi
  • 5、重新執行,沒報錯了。

四、總結

研究怎麼匯入aar的時候,3行程式碼花了3天,研究怎麼匯入jar&so的時候,Ctrl C + Ctrl V幾個檔案又花了3天,果然是萬事開頭難。

大部分時間都是對一個語句的反覆嘗試,多次懷疑自己哪的單詞是不是拼錯了,結果還是對解決方法的原理理解不到位。最開始只知道so放到指定位置就可以了,請求不到的時候報錯也不知道什麼意思,然後發現,不同的CPU架構會請求不同的包,就開始找指定ABI的方法。方法很簡單啊,就一句話,但放錯了位置,沒任何效果,半天開不了竅。終於在最後把每一塊理解到位了,才解決了問題。

相關文章