一、前言

UnityGoogle PlayGoogleAPK150MAPK300M+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
,显然,
Resources
StreamingAssets
目录都会打进包内。

三、开启Split Application Binary,打包

Player SettingsPublishing SettingsSplit Application Binary

执行
Build
打包,如下,保存为
test.apk


最终生成的文件如下,可以看到有一个
apk
和一个
obb
文件。

四、什么文件进入了obb中

obbOpaque Binary Blobapk7zassetsobbapk

往里进,看到了
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,不放obb

apkResourcesbg.pngapk

现在,另一个问题来了,这个
obb
文件,如何使用,放在安卓中的哪个目录呢?

六、放obb文件

obbobbmain..<包名>.obbapkcom.linxinfa.obbtestBundle Version Code2

所以最终
obb
重命名如下:
main.2.com.linxinfa.obbtest.obb


把它拷贝到
Android/obb/包名
目录下,如下:

七、运行apk闪退

apkadb
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

九、国际版发布apk+obb

apk+obb

按照同样的规则放好
obb
包,
apk

由此,我们得出结论,
Resources
目录的资源也是在
obb
文件中。

十、您上传的APK没有经过Zipalign处理

apkobbGoogle Console您上传的APK没有经过Zipalign处理,请对APK 运行 Zipalign 工具,然后重新上传
Android 1.6SDKbuild-tools\26.0.2zipalign
zipalign -v 4 源文件 对齐之后的文件

例:

zipalign -v 4 test.apk test_aligned.apk

十一、Google Play Console后台在哪里上传apk、obb

Google ConsoleAPK

APK
上传成功后,点击这个
...
按钮

然后选择
上传拓展文件(.obb)


然后上传
obb
就可以啦。

十二、结束语

UnityUnity