Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

APK with expansion file (OBB) fails to load the second scene until the phone has been restarted

Discussion in 'Editor & General Support' started by Playneer, Apr 11, 2017.

  1. DaReign

    DaReign

    Joined:
    Apr 12, 2013
    Posts:
    52
    I'm sorry for "typos" but forum doesn't allow me to edit and correct my post :(.
     
  2. JustAnotherDude

    JustAnotherDude

    Joined:
    Oct 28, 2013
    Posts:
    127
    I think there's a lot of misunderstanding going on in this thread.

    The solution you posted is the same I've been using since I detected the bug, but this is not a proper solution, as none of us can actually fix the bug, because it's a bug in android, as posted here : https://issuetracker.google.com/issues/37075181

    This is why I'm saying unity did not fix the bug, because asking for the permission is not the solution, the user can deny it and the game will not run, this is why I have been doing as you are, asking for the permission myself and preventing the user from going forward into the game if he denies it, the result is that I've already received some 1 star reviews in the store because I require the permission, when I shouldn't even have to ask for it in the first place if android wasn't bugged...

    The worst part is that google is refusing to accept it as a bug and fix the android OS, because apparently this is a bug that happens on all devices except their nexus devices, they are investigating the issue again here : https://issuetracker.google.com/issues/37544273

    Hope they recognize the issue and fix it now.
     
  3. pedroabgmarques

    pedroabgmarques

    Joined:
    Jun 21, 2017
    Posts:
    2
    I got it to work using Unity 5.6.2 and changing the manifest "SkipPermissionsDialog" to false (thanks 265lutab!):
    <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="false" />

    I can also confirm that this fix no longer works using Unity 2017.0.1f3!
     
    yoyyoffg likes this.
  4. namo2

    namo2

    Joined:
    May 28, 2013
    Posts:
    22
    I am using Unity 2017.1.0f3 and I have the same problem. In my VR game, I have to restart the phone for obb file to work. I don't think that there is a problem in the Android version. Everything works OK on LG G3 but restart is necessary on Xiaomi Redme Note 4. They both have Android 6 installed. Any suggestions?
     
  5. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    248
    You have to have the write external store permission. In API 19 they removed the need to ask for this permission to store the obb file on the sdcard. But in android 6 there was a regression bug that brought the issue back. The problem is that the obb file does get stored but doesn't have the correct user permissions so is unreadable by the app. Restarting resolves the file permissions. But having the write external storage permission there negates the issue, however it will unnecessarily add horrible user facing permissions to your play store listing.

    This issue I've spent weeks researching different work arounds, it's my single biggest annoyance with the android SDK and I believe Google could completely solve it in a retroactive way if they'd allow single apk installations over 100mb and they simply reworked how the over the air 100mb installation limitation is enforced, they already have a warning popup when you're using mobile data so there's no reason for this apk file size limitation anymore. Other android based platforms around the world don't have this horrible 100mb apk limitation and these large apk files install and run perfectly fine. Remove the need to use OBB expansion files I say, life would be much simpler.
     
  6. namo2

    namo2

    Joined:
    May 28, 2013
    Posts:
    22
    So... adding <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> to manifest should help? I thought that read external storage is enough...
     
  7. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    248
    Read will be enough for this particular permissions bug. But you have a second issue that by using obb files a percentage of devices will fail to install the obb file and is where you require a backup obb file loader. For this you need write permission, so you may as well add that. It’s pretty easy to replicate. Install your app on any Samsung phone running android 6, uninstall it, reinstall, the app gets installed but not the obb this time around. Obb files are so painful!!
     
    JustAnotherDude likes this.
  8. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    248
    You need to be doing proper install tests via the play store btw... uploading the apk and obb and testing them via the beta channel. You’ll see the issue occur pretty quickly.
     
  9. justdizzy

    justdizzy

    Joined:
    Mar 8, 2016
    Posts:
    45
    Here here!
     
  10. kiwipxl

    kiwipxl

    Joined:
    Jun 9, 2015
    Posts:
    11
    Just to expand on DaReign's answer for anyone else who needs to go through this pain:

    The bug should be fixed in Nougat and above (at least according to the documentation here https://developer.android.com/reference/android/content/Context.html#getObbDir()), but apparently it still occurs for some people. In our game, we check if the primary obb file can be read, and if it can't, then the permissions dialog will popup. If the primary obb file can be read, then we shouldn't need to ask for any permissions. This extra check is good so that devices that don't have this bug won't need to ask for the READ_EXTERNAL_STORAGE permission.
    Had to write a native android plugin for that, you can find the code here https://gist.github.com/kiwipxl/bd8c263e461be0a8de0b79794b2959dd

    Another thing is that if you're using the UnityAndroidPermissions plugin (https://github.com/Over17/UnityAndroidPermissions), after receiving the permission granted callback, you should wait til the next Update loop to actually change scenes. If you don't, the obb will not be correctly loaded. I think this is because the actual permissions are flushed only after the callbacks are called. This seems like a bug in the plugin though, it should probably flush first and then call the callbacks.
    Edit: We ended up actually having to restart the app after accepting read permissions for the first time as we were getting extremely odd bugs - UI elements were sometimes getting loaded and sometimes not, even for the same assets...
    You can do this in java by setting a PendingIntent alarm to start the app up in X seconds and then exiting the app immediately. The app will be restarted again once the alarm is activated. Here's the code for that https://gist.github.com/kiwipxl/a33874b7d2ee06a847035d9bcaab19fb Our app is now live and everything seems to be going well.

    Oh, and you can test the changes locally without having to wait 5 hours to upload to Google Play. First, you download the app from the play store and reproduce the bug. Your obb file should have "root" as the owner, which means the app can't read it without permission. Now, install an updated apk and replace the old one (make sure the version codes of both apks are the same). The old obb should still be there with root permissions. Note that you won't be able to test with this obb, since obb's must match the apk they were built with.
    If you upload a new obb into that folder, it should also have root permission, which is great, because it means you can test the permissions locally without uploading an alpha/beta build on google play.

    Maybe one day google will remove their apk size limit and we won't ever have to deal with this again.

    EDIT: Just wanted to quickly mention that this android bug sometimes does not occur. I've had it not occur for over a week when downloading from the google play store, but then it'll come back eventually at some point. This makes me think that this bug is isolated to specific google play servers. If this is true, then this is vital in fixing the issue on google's side because it means some servers already have the fix in them!
     
    Last edited: Mar 19, 2018
    JustAnotherDude likes this.
  11. JacobRichards

    JacobRichards

    Joined:
    Oct 16, 2017
    Posts:
    4
    I went through DaReign's tutorial and now the pop-up successfully appears in my app upon first starting it, and after I click "allow", storage access shows as "enabled" in Settings -> apps, but the OBB is still not loaded. Strangely, in previous builds of the app, when I MANUALLY enable storage access in settings, the OBB is loaded. Anyone know why this might be the case?
     
  12. JacobRichards

    JacobRichards

    Joined:
    Oct 16, 2017
    Posts:
    4
    I SOLVED IT ! I ~think~ it may have been that because I'm making a Google Cardboard App, I just needed to modify the manifest file "AndroidManifest-Cardboard" instead of the AndroidManifest as in DaReign's tutorial. Upon startup, I allow access to the SD card, and my first (menu scene) is reloaded. Once I click through it to start the next scene, which uses assets from the OBB file, it's all gravy :)
     
  13. TheKingOfTheRoad

    TheKingOfTheRoad

    Joined:
    Apr 24, 2013
    Posts:
    55
    Hello, im desperate trying to make OBB work as we have our game stuck on Android (IOS working and waiting for Review). It's a racing game. Can i ask how did you managed to Restart the App? Im not proeficient in Java PendingIntent or similar. I think im stuck with the same issue. I can read the OBB Scenes (the names for them), the OBB is there in Internal Storage, but it doesn't want to load my first scene and this is a nightmare. I've tried restarting, same.

    Galaxy J1 prime, Android 6.0.1

    Im using DownloaderOBB, API 19 , all published in Beta in Google, asking for Permissions at Runtime and Manifest has READ_EXTERNAL_STORAGE (im adding now as i write WRITE_EXTERNAL_STORAGE too).

    Please help! :eek::eek:
     
  14. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    248
    @TheKingOfTheRoad I don't believe you can force the device to restart, our solution tries to resolve it using permissions, then we test to see if something can be loaded from the OBB (I think from memory we try and load a prefab that only exists in the OBB). If this fails, we then display to the user a message something like 'This is a known Android bug, please restart the device and reopen this application. If the problem persists contact us on blah blah.'
     
    IgorAherne and TheKingOfTheRoad like this.
  15. TheKingOfTheRoad

    TheKingOfTheRoad

    Joined:
    Apr 24, 2013
    Posts:
    55
    Hello jason_yak, nice to meet you.

    Sure. That sounds good. I did that checking if an Scene exist too.
    I will check my code to see if i didn't commented that part. For now, i didn't
    tested on Oreo, so, i think will be safer if i test that asap. Thank you!

    Update: I will think about checking against a prefab too. You are super pro!!
    You saved my game from Google Bug i think! :cool:
     
    Last edited: Aug 13, 2018
  16. phoenixrider

    phoenixrider

    Joined:
    Feb 21, 2016
    Posts:
    1
    Hello everyone,

    I have been dealing with this obb issue for over a week now getting quite depressive :(, I have added the:

    <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    in my android manifest and have tried @DaReign solution, it got me until the ask for permission and once I press accept button, which is suppose to trigger the android dialog to get pop up(the allow/deny UI), nothing happen, I can press the accept button endlessly, it just seem to do nothing with it, the accept button call for the OnGrantButtonPress().

    Image of my UI:


    Here are all my line of codes:
    Code (CSharp):
    1.      
    2. [code=CSharp]      
    3.  
    4.         //UI to access android dialogue permission
    5.         public GameObject requestpermission;
    6.  
    7.          //UI to acess button to load the next scene
    8.          public GameObject loadnextscene;
    9.  
    10.     private const string STORAGE_PERMISSION = "android.permission.READ_EXTERNAL_STORAGE";
    11.  
    12.     void Start () {
    13.        
    14.         requestpermission.SetActive (false);
    15.         loadnextscene.SetActive (false);
    16.  
    17.         CheckPermissions();
    18.     }
    19.  
    20.    //load next scene
    21.    public void shownextscene(){
    22.  
    23.             SceneManager.LoadScene ("start page normal");
    24.     }
    25.  
    26. //close application if user refuse access
    27.     public void hideaccess(){
    28.  
    29.         Application.Quit();
    30. }
    31.  
    32. private bool MyCheckPermissions(){
    33.         if (Application.platform != RuntimePlatform.Android)
    34.         {
    35.             return true;
    36.         }
    37.  
    38.         return AndroidPermissionsManager.IsPermissionGranted(STORAGE_PERMISSION);
    39.     }
    40.  
    41.     public void CheckPermissions(){
    42.  
    43.         if (!MyCheckPermissions ()) {
    44.  
    45.             requestpermission.SetActive (true); //pop UI with accept or refuse button
    46.         }
    47.     }
    48.  
    49.     //if user press accept button, this method get called
    50.     public void OnGrantButtonPress()
    51.     {
    52.         AndroidPermissionsManager.RequestPermission(new []{STORAGE_PERMISSION}, new                  AndroidPermissionCallback(
    53.             grantedPermission =>
    54.             {
    55.  
    56.               // The permission was successfully granted, restart the change avatar routine
    57.               requestpermission.SetActive (false); //close UI
    58.               loadnextscene.SetActive (true);        //pop button
    59.              
    60.             },
    61.             deniedPermission =>
    62.             {
    63.                 // The permission was denied
    64.                 hideaccess();
    65.             },
    66.             deniedPermissionAndDontAskAgain =>
    67.             {
    68.                 //honestly dont care about this at this point
    69.                 // The permission was denied, and the user has selected "Don't ask again"
    70.             }));
    71.     }
    72. }
    73.  
    }[/code]

    Also restarting the device make no difference.

    The device I am testing on is LG G5 version 8.0 with Unity 2017.1.1.f1 It seem like I cant reach the Obb file no matter what I do.

    Any help would be greatly appreciated :).

    Thank you

    -Phoenixrider
     
  17. IgorAherne

    IgorAherne

    Joined:
    May 15, 2013
    Posts:
    339
    A bit late, but I think "Force Internal" inside ProjectSettings->Player is the way to bypass this particular issue.

    Also, in your case specifically, you will probably need to get rid of the
    Code (CSharp):
    1. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    maybe from this as well (try to see):
    Code (CSharp):
    1.  
    2. <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true"/>
    3.  
    that you currently had (if you had) in your custom manifest file, and thus, let unity decide, while it builds.

    "Forcing internal" helped me in that the obb is found, though only after a device restart...
    Once you have that, you should be able to do this

    Checking if obb is available on the first launch is done as this post suggests:
    or as these people suggest (and I think so too) trying to load an asset via Resources.Load() will do the job. Quoting unity:

    When the Split Application Binary option is enabled the player executable and data will be split up, with a generated .apk (main application binary) consisting only of the executable (Java, Native) code (around 10MB), any and all script / plugin code, and the data for the first scene. Everything else (all additional scenes, resources, streaming assets …) will be serialized separately to a APK Expansion File (.obb).

    Your initial scene should probably be super-tiny (I called mine "Pre-welcome scene"), which is the first one to launch. It should have an index of zero. It should only have 1 script that checks for obb, and can show a message. If your welcome scene has pictures, you might fail to display such a message, as parts of it might get placed in obb ...i'm not sure though ))

    For the same reason don't use TextMeshPro in this Pre-welcom-scene, as I think parts of it are placed into .obb; Just use the usual text. Don't use any fonts other than Arial. Don't use any sprites other than 'UISprite' - the default one provided by unity.

    My starting scene has no camera, just a simple canvas, set to "screen overlay" mode.
    My code looks like this:

    Code (CSharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4.  
    5. public class AndroidInstall_VerifyHasObb : MonoBehaviour{
    6.  
    7.     [SerializeField] GameObject _message_pannel = null;
    8.     [SerializeField] Button _confirmButton = null;
    9.     bool _firstUpdateInvoked = false;
    10.  
    11.  
    12.     // Update is called once per frame
    13.     void Update(){
    14.         if(_firstUpdateInvoked){ return; }
    15.         _firstUpdateInvoked = true;
    16.  
    17.         OnFirstUpdate();
    18.     }
    19.  
    20.  
    21.     void OnFirstUpdate(){
    22.         GameObject go = Resources.Load("PreWelcomeScene_ObbVerifying_Prefab") as GameObject;
    23.         if(go == null){
    24.             //the obb wasn't loaded!
    25.             //tell the user about this Google-bug, and tell them to restart the phone.
    26.             //https://forum.unity.com/threads/apk-with-expansion-file-obb-fails-to-load-the-second-scene-until-the-phone-has-been-restarted.465714/page-2#post-4132885
    27.  
    28.             _message_pannel.SetActive(true);//displays the message
    29.             _confirmButton.onClick.AddListener( onConfirmButtonClicked );
    30.             return;
    31.         }
    32.  
    33.         //otherwise, everything is ok. Load the scene:
    34.         UnityEngine.SceneManagement.SceneManager.LoadSceneAsync( 1, UnityEngine.SceneManagement.LoadSceneMode.Single );//load the "Welcome Scene" (with company logo, etc).
    35.     }
    36.  
    37.  
    38.     void onConfirmButtonClicked(){
    39.         Debug.Log("quitting");
    40.         Application.Quit();
    41.     }
    42.  
    43. }
    44.  

    Here is a bit more on dangers of WRITE_EXTERNAL_STORAGE:
    https://web.archive.org/web/2018061...ult.com:80/unity-on-android-save-data-pitfall
     
    Last edited: Feb 2, 2019
  18. jason_yak

    jason_yak

    Joined:
    Aug 25, 2016
    Posts:
    248
    Hi everyone,

    Recently there’s been some developments on Google Play which I believe might finally be the answer to all of these Obb file issues. Google have opened the door to effectively remove the of Obb expansion files through a couple of different means which completely side steps all of the related issues the Obb files have.

    Firstly using the Android App Bundle delivery format it is possible to organise your assets in a way that they’d eventually be split and delivered to users as a series of apk files. At the moment these apk files have a 100mb size limit which means that you still have a primary apk installed with extra resources ending up in other secondary apks, which fundamentally isn’t that much different to Obb files, but would take some massaging to get your compiler setup to support this new format. I haven’t tried this format yet, so don’t quote me, but I think another difference might be that secondary apks might need to be downloaded by the app at runtime, which means that if a user installed the primary apk, lost internet (say in on a plane in aeroplane mode) would not be able to download the remaining apk resouce files. But, at least no Obb file and no bugs associated with them. I think the AAB format is supported from Android 5.0 and up.
    https://blogs.unity3d.com/2018/10/03/support-for-android-app-bundle-aab-in-unity-2018-3-beta/

    All that said there’s another potential option. Google have announced that they’re increasing the size limit of self contained apk’s to 500mb, and for us this is the real solution. Users trying to download an apk over 100mb will be shown a popup warming that the app is a large size, do they want to wait until on wifi or continue using mobile data. I believe you need to put in a request to be whitelisted, you’d need to talk to you google account manager as the feature is currently in early access only.
    https://android-developers.googleblog.com/2018/10/playtime-2018.html?m=1
     
    JustAnotherDude likes this.
  19. i9mobile

    i9mobile

    Joined:
    Aug 8, 2013
    Posts:
    26
    All content included on the first scene on build settings will be placed at the .APK, and the rest on .OBB:

    How data is split between the APK and OBB
    When the Split Application Binary option is enabled, the app is split the following way:
    • APK - Consists of the executables (Java and native), plug-ins, scripts, and the data for the first Scene (with the index 0).
    • OBB - Contains everything else, including all of the remaining Scenes, resources, and streaming Assets

    https://docs.unity3d.com/Manual/android-OBBsupport.html
     
  20. AaronSaron

    AaronSaron

    Joined:
    Nov 30, 2012
    Posts:
    9
    Same issue here.
    I made some tests with a helpful user.
    His device is: HUAWEI CAM-L23
    The default install location of his device is set to external.
    Android version 6
    Unity version 2018.2.21f1

    I tried with different build setting combinations, the result is the same.
    Install Location: Force Internal
    Permission: Internal

    Install Location: Automatic
    Permission: Internal

    Install Location: Automatic
    Permission: External

    Manifest file:
    READ_EXTERNAL_STORAGE
    WRITE_EXTERNAL_STORAGE
    <meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />

    (Test build settings)
    Install Storage: Automatic
    Permission: Internal

    Steps:
    1- Install the app from Google Play Store
    2- Launch the first scene.
    3- Check if external storage is readable, if it is not, ask permission => storage was readable
    4- Check if obb file exists => returns True.
    (if returns false, ask write_external_storage permission, start downloading obb)
    5- Check if Application.dataPath equals to obb path. => Not equal
    Application.dataPath returns this path: /data/app/com.company.package-1/base.apk
    instead of Obb location. (https://docs.unity3d.com/ScriptReference/Application-dataPath.html))
    6- The second scene won't load.
    7- Ask the user to restart his device and re-launch the game.
    8- Now Application.dataPath equals to obb path
    9- Everything is working.

    I wonder whether asking the user for write_external_storage permission in step 5 may solve the issue. I could not test it because it is too difficult to communicate with the user who is speaking Spanish.

    Edit: I just figurated it out that asking runtime permission after obb is has mounted won't solve the issue

    https://github.com/Over17/UnityAndroidPermissions/issues/10
    .
    "Pausing/resuming the unity activity AFTER the user has clicked "accept" in the permission dialog"
    Is there anyone who has tried this way?
     
    Last edited: Mar 12, 2019