Unity開啟Split Application Binary,打出apk+obb分包,如何進行安裝測試(Google、Unity國際版)

2021-04-30 13:00:15

一、前言

點關注不迷路,持續輸出Unity乾貨文章。
嗨,大家好,我是新發。
最近專案上架Google Play,因為Google限制上傳的APK不得超過150M,而實際專案APK300M+,這個時候,就需要用到UnitySplit Application Binary功能了。

二、Demo工程

為了演示,我弄個Demo工程,如下:
在這裡插入圖片描述
Resources目錄和StreamingAssets目錄分別放一張圖片。
場景如下,Canvas節點掛Main.cs指令碼,image節點顯示圖片。
在這裡插入圖片描述
場景中的image節點不要參照圖片資源,而是在Main.cs指令碼中動態賦值。
在這裡插入圖片描述
Main.cs指令碼程式碼如下:

using UnityEngine;
using UnityEngine.UI;

public class Main : MonoBehaviour {
    public Image img;
    void Start() {
        img.sprite = Resources.Load<Sprite>("bg");
    }
}

執行效果如下,可以看到動態載入了圖片。
在這裡插入圖片描述
此時我們打包apk,如果我們不開啟Split Application Binary,顯然,ResourcesStreamingAssets目錄都會打進包內。

關於ResourcesStreamingAssets兩個目錄的區別,可以參見我之前寫的這篇文章:《學Unity的貓》——第五章:規範Unity的工程目錄結構

三、開啟Split Application Binary,打包

Player SettingsPublishing Settings中開啟Split Application Binary
在這裡插入圖片描述
執行Build打包,如下,儲存為test.apk
在這裡插入圖片描述
最終生成的檔案如下,可以看到有一個apk和一個obb檔案。
在這裡插入圖片描述

四、什麼檔案進入了obb中

obb全稱是Opaque Binary Blob,它是apk的擴充套件檔案,它是壓縮檔案的格式,以zip格式居多,所以我們可以直接用7z開啟它,我們看看裡面有什麼。
進去裡面是一個assets資料夾,從這裡看,我們就可以知道obb主要是存放apk的資源和資料類檔案了。
在這裡插入圖片描述
往裡進,看到了pic2.png,這個就是UnityStreamingAssets目錄中的pic2.png,也就是說,StreamingAssets目錄中的檔案,會被丟到obb檔案中。
在這裡插入圖片描述
Resources目錄的資源,也是在obb中 嗎?我們往裡進,可以看到在assets\bin\Data目錄中有個data.unity3d檔案,我猜,我們Resources目錄中的那張bg.png就在這裡面。
在這裡插入圖片描述
我用AssetStudioGUI.exe無法反出這個data.unity3d檔案,那麼,我們就用反證法來證明Resources目錄檔案會在obb檔案中吧。

五、只安裝apk,不放obb

我們把apk安裝到安卓模擬器中,執行如下,可以看到,不能動態載入出圖片來,說明,Resources目錄的bg.png並不在apk中。
在這裡插入圖片描述
現在,另一個問題來了,這個obb檔案,如何使用,放在安卓中的哪個目錄呢?

六、放obb檔案

要使用這個obb檔案,需要先重新命名一下這個obb檔案,命名規則如下:main.<Bundle Version Code>.<包名>.obb
我打包apk時,包名是com.linxinfa.obbtestBundle Version Code2
在這裡插入圖片描述
所以最終obb重新命名如下:main.2.com.linxinfa.obbtest.obb
在這裡插入圖片描述
把它拷貝到Android/obb/包名目錄下,如下:
在這裡插入圖片描述

七、執行apk閃退

接著,我們執行apk,發現閃退了,為什麼?
adb偵錯一下,紀錄檔如下:

D/Activity( 6326): on create, cpu abi: armeabi-v7a, brand: Android
D/updatePackage(  905): version com.linxinfa.obbtest 2
I/Launcher(  905): Deferring update until onResume
V/libnb   ( 6326): enter native_bridge2_isSupported /data/app/com.linxinfa.obbtest-1/lib/arm/libmain.so
D/libnb   ( 6326): enter native_bridge2_loadLibrary /data/app/com.linxinfa.obbtest-1/lib/arm/libmain.so
D/com.netease.nemu_vapi_android.thread.HttpServer(  842): http server response data: {"errcode":0,"message":"OK"}
D/houdini ( 6326): [6326] Added shared library /system/lib/arm/libaudio_rawdata.so for ClassLoader by Native Bridge.
D/houdini ( 6326): [6326] Added shared library /data/app/com.linxinfa.obbtest-1/lib/arm/libmain.so for ClassLoader by Native Bridge.
V/libnb   ( 6326): enter native_bridge2_getTrampoline JNI_OnLoad
D/com.netease.nemu_vapi_android.thread.HttpServer(  842): http server response data: {"errcode":0,"message":"OK"}
I/Mono    ( 6326): JNI_OnLoad called
D/com.netease.nemu_android_watchdog_lib.core.Watchdog(  842): upload server response: {"errcode": 100, "errmsg": "ok"}
D/com.netease.nemu_android_watchdog_lib.core.Watchdog(  842): upload result: true
D/        ( 6326): QemuPipeStream get vt: 1
D/        ( 6326): QemuPipeStream use_vt: 1
D/        ( 6326): HostConnection::get() New Host Connection established 0xbf269540, tid 6326 host arch 0
I/ActivityManager(  523): Displayed com.linxinfa.obbtest/com.unity3d.player.UnityPlayerActivity: +285ms
W/InputMethodManagerService(  523): Starting input on non-focused client com.android.internal.view.IInputMethodClient$Stub$Proxy@17cc531 (uid=10015 pid=3699)
I/Unity   ( 6326): MemoryManager: Using 'Dynamic Heap' Allocator.
I/Unity   ( 6326): check apk path fail, reported:/storage/emulated/0/Android/obb/com.linxinfa.obbtest/main.2.com.linxinfa.obbtest.obb, actual:/data/app/com.linxinfa.obbtest-1/base.apk
I/Unity   ( 6326):
I/Unity   ( 6326): Illegal usage of unity detected, shutdown unity.
I/Unity   ( 6326):
I/Process ( 6326): Sending signal. PID: 6326 SIG: 9
W/InputDispatcher(  523): channel 'aede570 com.linxinfa.obbtest/com.unity3d.player.UnityPlayerActivity (server)' ~ Consumer closed input channel or an error occurred.  events=0x9
E/InputDispatcher(  523): channel 'aede570 com.linxinfa.obbtest/com.unity3d.player.UnityPlayerActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
I/WindowState(  523): WIN DEATH: Window{aede570 u0 com.linxinfa.obbtest/com.unity3d.player.UnityPlayerActivity}
W/InputDispatcher(  523): Attempted to unregister already unregistered input channel 'aede570 com.linxinfa.obbtest/com.unity3d.player.UnityPlayerActivity (server)'
W/WindowManager(  523): Force-removing child win Window{8bc567a u0 SurfaceView} from container Window{aede570 u0 com.linxinfa.obbtest/com.unity3d.player.UnityPlayerActivity}
I/ActivityManager(  523): Process com.linxinfa.obbtest (pid 6326) has died
D/ActivityManager(  523): cleanUpApplicationRecord -- 6326
W/ActivityManager(  523): Force removing ActivityRecord{50e4779 u0 com.linxinfa.obbtest/com.unity3d.player.UnityPlayerActivity t547}: app died, no saved state
W/WindowManager(  523): Failed looking up window
W/WindowManager(  523): java.lang.IllegalArgumentException: Requested window android.os.BinderProxy@7d300e9 does not exist
W/WindowManager(  523):      at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:8881)
W/WindowManager(  523):      at com.android.server.wm.WindowManagerService.windowForClientLocked(WindowManagerService.java:8872)
W/WindowManager(  523):      at com.android.server.wm.WindowState$DeathRecipient.binderDied(WindowState.java:1216)
W/WindowManager(  523):      at android.os.BinderProxy.sendDeathNotice(Binder.java:558)
I/WindowState(  523): WIN DEATH: null
I/com.android.server.tabs.TabManagerService(  523): notifyClosing:741: notify tab closed in android as it's closed task com.linxinfa.obbtest, taskId: 547, elapseTime: 372
D/Interception(  523): result: allow, reason: calleePkg is system app, rule: runType===broadcast|||callerPkg===android|||calleePkg===com.mumu.acc|||calleeClass===com.mumu.acc.AccMsgReceiver|||action===uu.intent.action.STOP_ACCELERATE

在同事的提醒下,看到有一句關鍵的紀錄檔:

Illegal usage of unity detected, shutdown unity.

搜尋了一下,原來如此:
在這裡插入圖片描述
我們在國內下載Unity一般是在 https://unity.cn/ 下載,這裡下的,都是中國版的。
在這裡插入圖片描述
那麼,在哪裡下載國際版的Unity呢?

八、下載國際版Unity

國際版Unity官網:https://unity.com/ (需要科學上網)
在這裡插入圖片描述

九、國際版釋出apk+obb

最終,使用國際版打出了apk+obb包,
在這裡插入圖片描述
按照同樣的規則放好obb包,
在這裡插入圖片描述

執行apk,可以看到執行正常了。
在這裡插入圖片描述
由此,我們得出結論,Resources目錄的資源也是在obb檔案中。

十、結束語

完畢。
喜歡Unity的同學,不要忘記點選關注,如果有什麼Unity相關的技術難題,也歡迎留言或私信~