# How can I refer to Android assets in other directories?

My project was initially not meant for Android, and its assets are organised along the following directory structure (I hope the ASCII art renders reasonably well):

/
+- engine/
|    +- src/
|     |      enginefile1.cpp
|     |      ...
|     - textures/
|            texture1.tex
|            ...
+- game/
|    +- src/
|     |      gamefile1.cpp
|     |      ...
|    +- textures/
|     |      gametexture1.tex
|     |      ...
|    +- ios/
|     |      [various iOS-specific files]
|     - android/
|           | build.xml
|           | AndroidManifest.xml
|           +- jni/
|           |     Android.mk
|           +- assets/
|             [other Android-specific files]
- othergame/


My game/android/jni directory is almost empty because Android.mk points to the relative paths of the source files in engine/src and game/src. Actually, it even includes the proper Makefiles so that I never have to modify Android.mk when I add or remove a source file to the project.

Both engine and game provide assets that need to be shipped with the Android build. I would like build.xml to refer to these assets without having to manually copy them. A rule that copies the assets at build time then deletes them would be acceptable, but of course I would prefer a zero copy solution. Does this make sense? How did others solve this cross-platform build problem?

Yes, you can absolutely use files in other directories. Place the assets you have in to the assets directory (sibling to the res directory), and use the AssetManager to access them.

To load bitmaps, you'll want the BitmapFactory, and you'll have to do some extra work if you intend to load resolution dependent images.

Be careful about loading Bitmaps more than once. Because you will be dealing with raw file handles, you'll probably want to implement some resource/memory manager that allows you ot quickly look up references to existing Bitmap objects and the like. Depending on your architecture, you may need to do this with WeakReferences so you don't end up with the entire game data in memory. (With normal android resources, the ResourceManager handles all of this for you.)

• Placing the assets in the same directory (be it res or assets) is precisely what I do not want to do. As I said in the question, both engine and game provide assets that I want to ship. Apr 29 '11 at 11:32
• Add a pre-compile script to link or copy assets into the assets directory, allowing you to preserve any game specific directory structure. As for Windows symlinks: windows7home.net/how-to-create-symbolic-link-in-windows-7
– Anm
May 3 '11 at 20:01
• Though a pre-compile script is probably the most conventient solution, it would be nice if your answer mentioned it, maybe together with a short example, so that it could be accepted. (note that I'm making the exact same comment in the other answer) Oct 20 '11 at 22:42

Ant build property "asset.dir" is responsible for providing name of assets directory. It's "assets" by default, but you can change it to something like "../assets". This changes path of entire directory, but if you have Android-specific resources, you can still use "res" directory.

How strange that the other answers here do not answer your question...they all assume you want only one assets directory, or refer to res/ instead of assets/.

I also need more than one assets directory.

I fought with the <aapt> ant module for hours and hours and finally gave up and realized there's a much easier way.

I copied the <target name="-package-resources"...> tag from the master build file that ant uses, android_sdk_dir/tools/ant/build.xml, and pasted the tag into my project build.xml (you must paste the tag right before the master build.xml is included, as the comments at the end of the pre-made project build.xml explain), then added a second section to simply exec zip to add the assets to the .ap_ file (which is ${out.absolute.dir}/${resource.package.file.name} at that point in the ant file):

    <target name="-package-resources" depends="-crunch">
<!-- only package resources if *not* a library project -->
<do-only-if-not-library elseText="Library project: do not package resources..." >
<aapt executable="${aapt}" command="package" versioncode="${version.code}"
versionname="${version.name}" debug="${build.is.packaging.debug}"
manifest="${out.manifest.abs.file}" assets="${asset.absolute.dir}"
androidjar="${project.target.android.jar}" apkfolder="${out.absolute.dir}"
nocrunch="${build.packaging.nocrunch}" resourcefilename="${resource.package.file.name}"
resourcefilter="${aapt.resource.filter}" libraryResFolderPathRefid="project.library.res.folder.path" libraryPackagesRefid="project.library.packages" libraryRFileRefid="project.library.bin.r.file.path" previousBuildType="${build.last.target}"
buildType="${build.target}" ignoreAssets="${aapt.ignore.assets}">
<res path="${out.res.absolute.dir}" /> <res path="${resource.absolute.dir}" />
<!-- <nocompress /> forces no compression on any files in assets or res/raw -->
<!-- <nocompress extension="xml" /> forces no compression on specific file extensions in assets and res/raw -->
</aapt>
<!--
NEW XML STARTS HERE
-->
<exec executable="zip" failonerror="true">
<arg value="-r" />
<arg value="${out.absolute.dir}/${resource.package.file.name}" />
<arg value="my_assets_directory_1" />
<arg value="my_assets_directory_2" />
<arg value="my_assets_directory_3" />
</exec>
<!--
NEW XML ENDS HERE
-->
</do-only-if-not-library>
</target>


This method has the advantage that you are more free to define the directory structure of your assets in the source tree and in the apk (since you can exec zip multiple times with different arguments, and even wrap zip in a script that runs zip from multiple current directories in your source tree). You also have per-file control of compression (zip has a -0 option to suppress compression) and do not need to use the limited, per-extension-only nocompress tag.

Note this ant xml comes BEFORE zipalign in the ant build process, so we still get a "zip-compatible" archive that meets the alignment needs of APKs and Android Java.

In my case I have an NDK based app and I want to access these assets from C code only (where any apk path is OK). If you need to use the standard Android Java assets calls to access these items, I'm not sure whether or not they must be in a path inside the zip named assets/ or not. If so, you can adapt the trick above by execing a script that cds to the relevant source tree folder, then runs zip.

Off the top of my head, I don't think you can use anything outside of res/, but if you're looking to avoid added cost to your dev cycle with a copy, you might try moving them instead or maybe even using a symlink...

• I can definitely not move the files because some of them are shared across games and need to stay in the engine directory, which is in a separate repository. Symlinks might be acceptable but I am not sure they'd work well on Windows and then there is still the problem of having them synchronised automatically by build.xml. Apr 10 '11 at 9:35
• @Sam - You can leave the files in place in your repository, but create a pre-compile step in your build framework (apparent an Ant build.xml file) to copy the files to the places necessary for your Android project. This is common practice when share assets in a multi-platform game. See the Ant copy task: ant.apache.org/manual/Tasks/copy.html
– Anm
Apr 24 '11 at 20:06
• Though a pre-compile script is probably the most conventient solution, it would be nice if your answer mentioned it, maybe together with a short example, so that it could be accepted. (note that I'm making the exact same comment in the other answer) Oct 20 '11 at 22:42

If you were using a Maven project as opposed to an Ant project, you could easily redefine the res folder to be whatever you wanted via the resourceDirectory configuration option of the android:apk mojo in the android-maven-plugin.

  <plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>${android.maven.version}</version> <configuration> <resourceDirectory>${project.basedir}/res</resourceDirectory>
</configuration>
<extensions>true</extensions>
</plugin>


If you are on a unix OS you can hard-link them, and tell your version control to ignore the res/` directory.