點關注不迷路,持續輸出Unity
乾貨文章。
嗨,大家好,我是新發。
最近專案上架Google Play
,因為Google
限制上傳的APK
不得超過150M
,而實際專案APK
有300M+
,這個時候,就需要用到Unity
的Split Application Binary
功能了。
為了演示,我弄個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
,顯然,Resources
和StreamingAssets
目錄都會打進包內。
關於
Resources
和StreamingAssets
兩個目錄的區別,可以參見我之前寫的這篇文章:《學Unity的貓》——第五章:規範Unity的工程目錄結構
在Player Settings
的Publishing Settings
中開啟Split Application Binary
。
執行Build
打包,如下,儲存為test.apk
。
最終生成的檔案如下,可以看到有一個apk
和一個obb
檔案。
obb
全稱是Opaque Binary Blob
,它是apk
的擴充套件檔案,它是壓縮檔案的格式,以zip格式居多,所以我們可以直接用7z
開啟它,我們看看裡面有什麼。
進去裡面是一個assets
資料夾,從這裡看,我們就可以知道obb
主要是存放apk
的資源和資料類檔案了。
往裡進,看到了pic2.png
,這個就是Unity
中StreamingAssets
目錄中的pic2.png
,也就是說,StreamingAssets
目錄中的檔案,會被丟到obb
檔案中。
那Resources
目錄的資源,也是在obb
中 嗎?我們往裡進,可以看到在assets\bin\Data
目錄中有個data.unity3d
檔案,我猜,我們Resources
目錄中的那張bg.png
就在這裡面。
我用AssetStudioGUI.exe
無法反出這個data.unity3d
檔案,那麼,我們就用反證法來證明Resources
目錄檔案會在obb
檔案中吧。
我們把apk
安裝到安卓模擬器中,執行如下,可以看到,不能動態載入出圖片來,說明,Resources
目錄的bg.png
並不在apk
中。
現在,另一個問題來了,這個obb
檔案,如何使用,放在安卓中的哪個目錄呢?
要使用這個obb
檔案,需要先重新命名一下這個obb
檔案,命名規則如下:main.<Bundle Version Code>.<包名>.obb
我打包apk
時,包名是com.linxinfa.obbtest
,Bundle Version Code
是2
。
所以最終obb
重新命名如下:main.2.com.linxinfa.obbtest.obb
把它拷貝到Android/obb/包名
目錄下,如下:
接著,我們執行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
官網:https://unity.com/ (需要科學上網)
最終,使用國際版打出了apk+obb
包,
按照同樣的規則放好obb
包,
執行apk
,可以看到執行正常了。
由此,我們得出結論,Resources
目錄的資源也是在obb
檔案中。
完畢。
喜歡Unity
的同學,不要忘記點選關注,如果有什麼Unity
相關的技術難題,也歡迎留言或私信~