Continuing on from my previous post about splitting an Android APK in unity, you may find if you are using a plug-in such as Vuforia that certain assets need to be copied out from the streaming assets folder which has now become zipped/compressed and lies within the OBB extension file before certain processes can be started or called.
Based on my previous post we had a small script that lies in an empty scene this scene is the first scene to get loaded and then calls another scene which contains the main content of your application, this allows the split apk to only have a small app apk size and puts the rest of your app data into the obb extension part.
In this version we add an array of streaming asset file paths which on loading the attempts to find these files and copy them over to the persistent data folder, which works fine with vuforia 3.09 or up, as it also searches in the persistant data folder for images targets etc.
The code now looks like below:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
using UnityEngine; using System.Collections; using System.IO; public class AndroidSplitLoadFirstScene: MonoBehaviour { //Only use in Preloader Scene for android split APK private string nextScene = "YourMainFirstSceneName"; public Texture2D background; public GUISkin mySkin; private bool obbisok=false; private bool loading=false; private bool replacefiles=false; //true if you wish to over copy each time private string[] paths={ "QCAR/yourtargets.dat", "QCAR/yourtargets.xml", "QCAR/Unity.txt", "mymovie1.m4v", "mymovie2.m4v" }; void Update() { if (Application.platform==RuntimePlatform.Android) { if (Application.dataPath.Contains(".obb")&&!obbisok) { StartCoroutine(CheckSetUp()); obbisok=true; } } else { if (!loading) { StartApp(); } } } void OnGUI() { GUI.skin = mySkin; GUILayout.BeginArea(new Rect(0,0,Screen.width,Screen.height)); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.BeginVertical(); GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Label(background,GUILayout.Width(background.width),GUILayout.Height(background.height)); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); if (!obbisok) { GUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); GUILayout.Label("There is an installation error with this application, Please re-install!"); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } GUILayout.FlexibleSpace(); GUILayout.EndVertical(); GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); GUILayout.EndArea(); } public void StartApp() { loading=true; Application.LoadLevel(nextScene); } public IEnumerator CheckSetUp() { //Check and install! for(int i=0;i<paths.Length;++i) { yield return StartCoroutine(PullStreamingAssetFromObb(paths[i])); } yield return new WaitForSeconds(1f); StartApp(); } //Alternatively with movie files these could be extracted on demand and destroyed or written over //saving device storage space, but creating a small wait time. public IEnumerator PullStreamingAssetFromObb(string sapath) { if (!File.Exists(Application.persistentDataPath+sapath)||replacefiles) { WWW unpackerWWW = new WWW(Application.streamingAssetsPath + "/" + sapath); while (!unpackerWWW.isDone) { yield return null; } if (!string.IsNullOrEmpty(unpackerWWW.error)) { Debug.Log("Error unpacking:" + unpackerWWW.error+" path: "+unpackerWWW.url); yield break; //skip it } else { Debug.Log ("Extracting "+sapath+" to Persistant Data"); if(!Directory.Exists(Path.GetDirectoryName(Application.persistentDataPath+"/"+sapath))) { Directory.CreateDirectory(Path.GetDirectoryName(Application.persistentDataPath+"/"+sapath)); } File.WriteAllBytes(Application.persistentDataPath+"/"+sapath,unpackerWWW.bytes); //could add to some kind of uninstall list? } } yield return 0; } } |
You may find if you are using any movie files from the streaming assets folder that in some of your scripts where the path was
streamingassetfolder/yourmovie.mp4
that you may want to correct the paths as below or in a similar fashion:
1 2 3 4 5 6 7 8 |
public string CorrectMoviePath(string filename) { if (Application.dataPath.Contains(".obb")) { filename = Application.persistentDataPath + "/" + filename } else { filename = Application.streamingAssetsPath + "/" + filename } return filename; } |
Hope that helps
Hi Jon! looks like this fixed my issue when I built a aplit apk straight from unity. Much appreciated!!
However, when I upload the apk and obb to the play store and after it’s all publish, I waited a day, I go to install it and then I get the error “There is an installation error with this application, Please re-install!”.
I check my phones obb directory and I don’t see it there. Do you have any pointers I could look into?
Thanks for you help!
Hi Gmiv, really not sure at all, obviously the obb is not there or didn’t auto download with app from store, either something is wrong with the obb detection code I wrote or the obb hasn’t downloaded and installed!
If your testing on a device on early android versions than Android 4, you will need to go back and work with the unity obb plug-in from the asset store, or write something to download the obb yourself as I don’t think anything pre android 4 will work this way, however if using 4 or higher:-
Im going to go with the latter the obb hasn’t downloaded, as the text should only display if Application.dataPath.Contains(“.obb”) is not true, this would fail if things have changed again with android possibly an untested version higher than 4.4 and the line Application.dataPath.Contains(“.obb”) is no longer valid for some reason, but I going to hold off on that thought right now.
When you uploaded the apk and obb file, I take it you renamed the obb part and uploaded both to alpha successfully testing, and also tested the download from google for this as alpha test user, if you did this and then promoted to published it should all work, so could be something with your upload to the store or possibly your download, did you try downloading over a mobile data connection perhaps, is the app still waiting for a wifi download signal to get the rest of the app???
Whatever you find out please get back, would love to know of any fixes to above, changes to android or caveats I haven’t explored.
Hi Jon,
thank you very much for sharing your work.
I work with vuforia 3.0.9 and unity 4.6.
I made a new scene with a Main Camera and attached your script to it. I added all my target .xml and .dat files and I changed the scene name in your script.
I set write access to external sd card, I also added the permission in my AndroidManifest. And I set the split binary in the player settings.
And I set the empty scene with only your script attached to Level 0, so it will this at start.
Now, when I do Build and Run it is loading my next scene with the ARCamera and targets. But it won’t target anything. What am I doing wrong?
Is it only working as an alpha version in google play store? What am I doing wrong.
I have an Samsung Note 3 with android 4.4 or something.
I hope you can help me 🙂
Hi Jenny,
If you uploaded it and have then downloaded and tested from the alpha version, then all is good you can just promote your alpha version to published on google, however I think what your doing is now editing the app and testing locally on the device, in which case you firstly must not build and run, you have to make sure version and bundle id remains the same as the alpha version online, have to have tested and downloaded the online alpha version at least once before doing these edits, rebuild the split obb & apk file (build only),then manually change the name of the obb, and drag the obb over onto the device and place in the android/data/obb folder under the right app folder name, replacing the one downloaded from the alpha test, you can then drag the apk across to any place and install manually, build and run method will always fail as it will not automatically put the correct matching obb file in the right place before running the apk. At least that’s my take on it, I may be wrong but I hope this helps,
Cheers Jon.
Just to add… I can see the .m4v video files on the phones sd card which is a directory above where the QCAR files are located. I even tried moving some video files in the QCAR directory where the .dat and .xml files are but I’ve had no joy thus far.
First make sure your video files are copied out of the zipped obb to persistant data folder by adding the filepath (which I believe you have done) as done with .dat and xml . Then have to amend your video playing functions to not look in streaming assets, where vuforia will look for them by default, so for instance if in your vuforia video texture player script you have mymovie.m4v, your going to need to edit the script that sends that pathname to videoplayerhelper, or edit videoplayerhelper itself to have the path Application.persistentdata+”/”+mymovie.m4v , I hope that helps.
Hi Jon,
Thanks for the quick reply! Much appreciated!
I took what you said on board and managed to get the videos working… Sort of…
I edited the VideoPlayerHelper file as you mentioned above but this seems to only let the videos play on full screen and not as part of the texture of the trigger. Not sure if I’m missing something obvious. Any ideas?
(I tested this as normal vuforia project without the split .obb interaction and it behaves as expected)
I did something along these lines, editing vuforia videoplayerhelper.cs , this gets called from videoplaybackbehaviour I believe:
///
///
public bool Load(string filename, MediaType requestedType, bool playOnTextureImmediately, float seekPosition)
{
SetFilename(filename);
if (Application.dataPath.Contains(".obb")&&Application.platform==RuntimePlatform.Android&&(!mFilename.Contains("http://"))) {
mFilename=Application.persistentDataPath+"/"+mFilename;
}
//normal
return videoPlayerLoad(mFilename, (int) requestedType, playOnTextureImmediately, seekPosition);
//
}
Hi Jon!
First of all, thanks for sharing your work!
Now here is my S.O.S. call:
I have an app that I made for a Tourism manager, so basically is a 360° Video Player which have 4 scenes:
– Splashscreen scene with my company name on it (this just last 5 seconds)
– A menu scene where you can pick a 2d or 3d scene
– the 2d scene
– the 3d scene
So I’m using the EasyMovieTexture asset to put my 360 video on a sphere and everything runs perfect in the full apk (230mb) when I install it on the test phone (samsung s5). Off course my .mp4 file is in the StremingAssets folder and there´s no problem with the playback. The BIG PROBLEM comes when I upload the app to the Google playstore. I just did it throught the regular way:
– Using the Split Application Binary
– Uploading the apk (17mb)
– Then uploading the obb (213mb) which name is changed automatically by the playstore to “main.x.x.x.obb”
Now, when the app is downloaded throught the playstore both files are downloaded (I can see the .obb file in the /Android/obb/com.x.x/ folder) but the thing is that it seems that the app is loading it from another location because there is no video playback. However the scene that contains the video is loaded.
So, I think that there is an issue with the reading of the .mp4 file wich is in the streamingassets folder, but I can’t get your code for correctmoviepath work with the MediaPlayerCtrl script
Please if you could help me that would be veeery nice!!
Thanks in advance.
Regards from Chile!
Hi Dario,
I think it could be that the EasyMovieTeture is obviously not finding the movie file, it was in streaming assets and is now hidden in an zipped obb folder, if you used my script above then this movie file will have now hopefully been copied out from the obb streaming assets to the local – persistant data folder, so what you are looking to do is to get your EasyMovieTeture plugin to look at the right path i.e. persistantdatafolder/yourmovie.mp4 not streaming assets, and it will only need to do this should the android path be an obb which is found by using the code:- if (Application.dataPath.Contains(“.obb”)) { //yourfunction }
Hello Jon,
Awesome info you got here. I followed your instructions and now Im able to successfully split a Vuforia apk, but I got a problem that I hope you could know more about. When I try to run a FullScreen video using Handheld.PlayFullScreenMovie and your function CorrectMoviePath in order to fix the video path, it just doesn’t play anything, screen goes black like it would play a video but then nothing happens. I also tried:
if (System.IO.File.Exists(CorrectMoviePath(“MyVideo.mp4”)) and some logs in order to see if video path exists, and actually it does, but my video player doesn’t play anything.
I also tried to fiscally look for the files on directory: Android>data>MyBundleID>files (That is also what I got if I print from Android “Application.persistentDataPath”) and in fact there are my videos but I just can’t make them play from my app.
Hi Gus,
Sorry for the late reply, I take it the video works in a non – obb file so it isn’t the video codec??, I also take it you have unity pro so can use the playmovie feature, although in unity 5 believe that’s been possibly unlocked for all for free now, I take it your also using the code to copy the files out of the obb file it the persistent data directory (which I think you clarified above), I do wonder as you’ve still got the extension .MP4 as written in your comment above, whether unity has inadvertently converted your video to Ogg-Theora format? I.e. when I drop any .mp4 into streaming assets it starts to auto-convert the file to a different format, so before I drop them into the streaming assets file I rename them to .M4V, this way unity doesn’t attempt to convert them and the inbuilt IOS and android players just play them as .MP4 files. However if its not that I am pretty stuck the file prefix below seemed to work for me?
// should work android
filename=Application.persistentDataPath+"/"+filename;
// this works for me on IOS, as not in a split obb, will not work for you
filename="file:/"+Application.streamingAssetsPath+"/"+filename;
//could try below if nothing above worked?
"file:/"+Application.persistentDataPath+"/"+filename;
//
Thanks for this
BUT
I get an error:
The name : ‘`dpack’ does not exist in the current context’
when I comment all the lines with dpack, the application fails to augment.
Hi bruno, yes I missed this sorry, will amend.
I’m very sorry to post again but I wanted it to be in the right place to avoid confusion. I too am getting the same “‘dpack’ does not exist in the current context” error after placing this C# in an empty scene on the main camera, and I am wondering if it was ever addressed. this post seems to be my best answer for including an .obb using vuforia and large video files. thank you so much.
Hi Jordon, sorry yes never got round to removing, the code is now clean and should work, what was missing was a ‘private string dpack;’ declaration at the top of the script, but i’ve removed it now.
Hi Jon,
thank you very much for sharing your work.i have a small question .why we should check the write access to external Sdcard ? if the user have not a Sdcard ,it make a problem ?
I think this was due to me having issue on a samsung tab 3 7″, there was a bit of on and off with this in the Android specs around version 4, I seem to recall, but hey whatever works for you!
Thank you very much !!! ^_^
Hi Jon Martin!
THANKS A LOT for this post, i was trying to get this “vuforia issue ” solve for a week an nothing still your script. You really save my project, it work PERFECT! i will keep comming and sharing this web.
Ty again.
i need help please respond
so just to be sure what exactly do i change/ replace in the script?
also i have my app set up like this… 1st scene is main menu and clicking start takes you to next scene which is vuforia stuff. do i have to make a new scene before my menu and have it lead to the menu scene or does it have to be directly in front of my vuforia scene?
Sorry its sooooooo late, basically if your app build is over 100mb now, and you have streaming assets, vuforia etc, you will need a first scene (could be just your menu scene if it doesn’t contain much and certainly doesn’t contain any AR code or refs to streaming assets etc), in this first scene this is where you’d copy over your stuff from obb to the main app.