We are porting an iPad application to Android tablet, that use a lot write and read data from the disk(memory). On the iPad and Editor we get the cache path in this way:
public string GetCachePath ()
{
string cachePath="Noset";
if (Application.isEditor) {
return "cache/";
}
if(Application.platform == RuntimePlatform.IPhonePlayer)
{
//for iPhone
//path should be <Application_Home>/Library/Caches
//app data Path is /<Application_Home>/AppName.app/Data
string dataPath = Application.dataPath;
cachePath = dataPath.Replace ("/Data", "");
//find index of "/" in /AppName.app
int index = cachePath.LastIndexOf ("/");
cachePath = cachePath.Substring (0, cachePath.Length - (cachePath.Length - index));
cachePath = cachePath + "/Library/Caches/";
}
...
So, first thanks for the RC2 that fix Application.dataPath on Android just in time but it´s seems that is not enough to write files, we are trying this:
if(Application.platform == RuntimePlatform.Android)
{
// Application.dataPath returns: /data/app/net.xorgames.mapp.apk/
// maybe the cache path should be this:
// -> /data/<package_name>/files/ OR
// /Android/data/<package_name>/cache/
string dataPath = Application.dataPath;
cachePath = dataPath.Replace(".apk", "/files/");
cachePath = cachePath.Replace("app/", "");
}
...
But doesn´t work according with Android SDK Documentation: 数据和文件存储概览 | Android Developers , there are different locations to write a file, and each one is calling by a method that returns the FileStreaming ready to use and not a path.
We pretend to use internal or external(SD memory) storage.
Yeah, that won’t work. And with RC2 there is no built-in function to solve that either, unfortunately. What you need to get is either the Context.getCacheDir() or (which is way easier) the Environment.getExternalStorageDirectory().
So, these live in Java land, and we cant call directly to java but instead we need to go through a native layer.
As getExternalStorageDirectory is a static method it’s actually quite easy to write this code directly in native code (using JNI) instead of calling a java method and do it in java land.
Ok, so there might be typo or two there, but this is more or less how you interact with Java objects from a native plugin.
We will of course solve this in a more elegant way in future releases.
EDIT: I accidentally used the non-static version of the JNI method functions. I.e. it should be GetStaticMethodID instead of GetMethodID, and CallStaticObjectMethod instead of CallObjectMethod (because the method we are trying to call is static).
I’ve added two plugin examples to our online documentation.
One is a very simple how to create your first plugin type. The other shows how to call Java code (via a native code bridge) and interact with the Android OS. I think you may find the second particularly interesting as it shows how to retrieve the CacheDir(). (For use with RC3 and later)
Hello, I’m testing the android output, thus i’m interest for the exemple. But when I try to access it, I have the page 403…
Can you help me, please?
Thanks
Is this still the only way to get a path to a folder we can write to? I agree with the earlier suggestion that Application.datapath should return a useable folder on all platforms. Couldn’t we at least have a few prebuilt plugins for things like this which are currently missing/broken? Surely it couldn’t take long if you know what you’re doing, but it’s reinventing the wheel for us all to do it independently.
EDIT: Well here’s some C++ code which apparently works. Now all I have to do is figure out the NDK, the JDK, how plugins work and I’m there.
Would anyone be so kind as to modify the GetCacheDir example above to use GetFilesDir instead? I’ve tried. My inane ramblings on this forum alone demonstrate that I’ve tried. I can’t do it though. I can’t even understand what is there. It grabs a method called getActivityCacheDir but googling that function name turns up precisely zero, so where am I suppose to get this method name from?
EDIT: Oh never mind. I thought this circumvented all the SDK stuff, but I see now that it doesn’t. So disregard.
Well, I can’t seem to get this to work with XML using C#. I’ve gotten it to work on the Mac, but when
I do it on the android I don’t know what goes wrong. Took a look at that zip and I seem to be doing the saving
and loading the same way and still it doesn’t work.
How about getting Environment.SpecialFolder on Android?
I want to load some photo from SD Card, but it keep crashing when I call this line in c#:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal)
edit:
When I use absolute path /sdcard/ to do other file operation and use www to load local texture on sd is ok,
Just Environment.GetFolderPath(Environment.SpecialFolder.Personal) keep crashing the player on android.
Is it made not to work on android by design?
Environment is a part of the .NET/Mono Framework and it usually reads out the Windows special folder structure. I don’t think there is such a structure for android, especially since Android basically have a per-app folder structure.
Every android app has a data folder in /data/data/com.yourcompany.yourgame.packagename/, where you have subfolders (files, databases, cache, pictures) etc. Then you also have a similar structure on the SD-card, just that the path is /sdcard/Android/com.yourcompany.yourgame.packagename/).
But the only secure way to get the right folder is by using the getExternalFilesDir, if you want to save content on the SD Card or getFilesDir for internal storage via JNI.
If you take a look at the Android Documentation, with getExternalFilesDir you get folder path to androids “specialfolders”