First timer here.
I've been writing an app that's intended to be deployed onto mobile platforms (iOS and Android ). This uses Flash Builder 4.6's android build target - it uses a subdirectory in the /assets/ directory, that contains an arbitrary number of .png files.
I code a directory loader as such:
public function LoadFromDirectory(directoryName:String, store:Vector.<BitmapData>):Boolean
{
//Changed here: this should work on both the development environment, AND the device.
//Guess what...
imageDirectory = File.applicationDirectory.resolvePath("assets/" +directoryString);
//This is triggering on Android. Doesn't do so in ADL. Not tested on iOS yet,
//but come on, if it doesn't work here, it won't work on iOS...
if (!imageDirectory.isDirectory)
{
trace("Directory not found:" +imageDirectory.url);
return false;
}
/*Snip loop through the contents of this directory, loading anything that is
a PNG and storing the bitmapData of all loaded PNGs into the vector, one by one*/
/*This of course, ALL works in ADL*/
}
This works in the air virtual devices, but isn't working on the mobile devices or on deployment. This is where I'm stuck.
Edit: Ok, I've gone and reduced the File code to just one line. I should be using resolvePath for cross-platform compatibility; also, the packager from Flash Builder doesn't see the "assets\" subdirectory unless I put it inside "bin-debug\", because that's where the compiled SWF went.
Still doesn't solve the problem tho - at least for the Android build, I can see the assets folder in the apk (by renaming it to a .zip and extracting it all), and it's the correct one (alongside the app's XML files and the SWF).
The apk installs and runs, but isDirectory still returns false when I debug on the device itself (once again, not on ADL - on the device only). Commenting that entire if...segment will crash the app instead because well, it can't find the assets\ directory.
I'm this close to solving the problem; would appreciate if someone helped me with the final step, because it's taking bloody ages to figure out.
PS: I would love to simply just embed the images in a FLA or SWC which I've done before and it works. Unfortunately, the number and name of images in that particular directory is arbitrary; the only thing that I'm certain of is the supported extensions.
PPS: Usage of this function: LoadImagesFromDirectory("imagesdirectory"), which should look under app:/assets/imagesdirectory in any platform. The Boolean return is for debugging (returns false if a directory with that name doesn't exist.)
...alright, I don't know if this is documented, but apparently I was calling LoadImagesFromDirectory to a directory name that is all caps, because on the PC, the target directory was also in all caps.
So in the test platform, the directory resolved to "app:/assets/IMAGESDIRECTORY".
But upon export, the device showed the directory instead resolved to "app:/assets/Imagesdirectory", therefore making the call to IMAGESDIRECTORY invalid.
Oddly, looking for "Imagesdirectory" works for both the PC and the device without changing folder layout and names.
Looks like I've been Gotcha'd - remember never to give directories names in all caps...
Related
I'm using internalDataPath within my NativeActivity which when accessed at runtime looks something like this:
"/data/data/app.name/files"
I then try writing to the file like so:
- fopen("/data/data/app.name/files/test.txt", "wb");
- fwrite(buffer, size, count, m_handle);
- fclose(m_handle);
In this case, the fopen will fail and won't open the file which realistically means the other functions don't get called, I experimented by looking at the file system and instead, tried the following path.
"/Android/data/app.name/files/test.txt"
This works, it creates the file and allows for the other functions to write and close the file.
My question is, how come internalDataPath starts with /data/ instead of /Android/? Have I done something wrong in the setup of my application? Should I be calling a different function?
It's also worth mentioning that
externalDataPath = "/storage/emulated/0/Android/data/app.name/files"
Which means that for this device (which doesn't have an external SD) it points to the correct INTERNAL files path.
Let me know if any of this is unclear or you require more information.
Thanks
I added mkdir() to ensure the entire internalDataPath tree is definitely created and it seems to have worked on my Nexus 7, I can see the files being created with ES File Explorer.
It also works on my Galaxy S6, however I can't actually see the files in the ES File Explorer, but it works because the file is loaded and read upon the next restart so I can only assume I can't see the file because this device is not rooted.
It's worth noting that between versions of Android, internalData path has changed location, for example:
Nexus 7 (5.1.1):
internalDataPath = /data/data/app.name/files
Galaxy S6 (6.0.1):
internalDataPath = /data/user/0/app.name/files
These paths are absolute, or at least relative to the highest view-able root directory in ES File Explorer.
Not sure if this will help anybody, the main part of the problem was probably my own lack of knowledge of the Android file system since there seems to be lots of similarly structured directories, it's easy to get lost down the wrong one.
Thanks to Patrik and Dave for spending time looking into it with me.
So I'm trying to use Application.persistentDataPath to save to device. What I'm seeing though is that its coming back null. I looked on device and am not seeing a files folder on my device, which makes me think that's why I'm getting back null. So I'm wondering how I can make sure a files directory is made when built to device using Unity.
To work with Mobile devices, you should try saving and loading files from Resources folder. All the files in Resources will be copied to your devices.
Unity Load text from resources
I am porting an iOS application to Android and have run into resource access issues.
Ideally, I'd like to open supplemental files (in this case PDFs, MP4 movies, etc.) in the application; however, I have discovered that Android+Cordova does not work as seamlessly as iOS+Cordova in this fashion.
Knowing (and accepting) that I need to pass files of this sort off to a secondary application, I have encountered the obvious permissions issues (i.e. external resources cannot see inside the resource bundle/APK).
I figured I could copy the resource out to a user folder on the device using the Cordova File plugin, and then use something like the FileOpener plugin; however, the File plugin can access the device file system -- but not pull from the APK.
I have hopes that the Asset2SD plugin (https://github.com/gkcgautam/Asset2SD) may help here, since it has been recently updated to Cordova 3.
Is there a more appropriate/preferred means of doing this kind of thing? I have to think it's a relatively common task, but there doesn't seem to be much on the topic (short of "find another way...").
NOTE: I've already reached out to the PhoneGap/Cordova community (https://groups.google.com/forum/#!topic/phonegap/xh_4UrEl9Gw), but haven't had much success there.
EDIT-1: Additionally, file size on the APK is going to exceed the 50MB cap, requiring extension APKs. I've mentioned this in the off chance that this might make things simpler.
EDIT-2: I've managed to get my base APK size down and have redistributed some resources so that an expansion APK (OBB) isn't necessary. I have also managed to make use of Asset2SD to successfully extract resource. My remaining issue is pathing.
The code looks like so...
window.plugins.asset2sd.startActivity(
{
asset_file: "www/folder/" + filename,
destination_file_location: "MyApp/myfolder/",
destination_file: filename
},
// success on saving file
function(filename) {
window.plugins.fileOpener.open("file:///" + filename);
},
// failure on saving file
function() {
console.log("Could not open file");
}
);
I know that Asset2SD uses getExternalStorageDirectory() [Google seems to advocate using getExternalFilesDir() in their discussion on expansion APKs].
EDIT-3: Sorted out return value from Asset2SD (i.e. filename + path) which can be pushed to FileOpener. Code updated accordingly.
So, currently there is no way on Android, but to manually preload dependent shared libs. That's fine with me, not a big deal.
There is also some problem with android buildsystem (prebuild libraries feature), and for that reason I had to name differently different builds of my dependent shared library: libsal.so and libsal-slim.so. Depending on build settings one of these two makes it into the final apk. Then, on java side, I try to load libsal.so and if it fails, then I try to load libsal-slim.so.
It worked all fine, until we stumbled upon a phone that ships that libsal.so in default firmware installed into /system/lib. For that reason, my app stopped working on that phone if it's built with libsal-slim.so, since it tries to load libsal.so first and it loads wrong library from /system/lib.
Question: how can I ensure that only library from my install folder gets loaded? Maybe I can somehow retrieve install folder of my app and "calculate" full path of my shared lib? How can I do that java voodoo magic? I'm big time noob in java and android in general, if this questions looks too naive :) and yes, I don't speak English (or how they say), please rely in c++ [end-of-joke]
libsal.so isn't actual name, I used it only for example.
Using System.load(fullpath_of_the_lib)can probably solve your problem.
But your problem is to get the fullpath_of_the_lib. In fact the android API don't allow you to get the path of a resource. You can only get a stream to read it.
To workaround this limitation, what you can do is the following:
put your lib in your app assets folder.
open a InputStream on your lib : getAssets().open("libsal.so")
create a file named "libsal.so" (or whatever) in your sdcard
copy bytes from the inputstream to the file just created
get the absolute filepath of your "libsal.so" on the sdcard
call System.load(fullpath_of_the_lib_on_the_sd_card)
Of course you only need the last step in the lib is already on the sdcard.
An simpler alternative is maybe renaming your lib to something like libMyVeryUncommonLibraryName.so so that it won't conflict with another library name.
I've got a pretty thorny problem with Android 2.3: I have an app that gathers various logs for debugging and support purposes (my company does Linux for rugged hardware), and has stopped working lately, because it's failing to write to the SD card. Here are the symptoms I've seen and the investigations I've carried out:
Happens across multiple devices of multiple types with different SD cards, all of which have been checked for filesystem corruption (no issues found).
All devices report: Environment.getExternalStorageState() equals Environment.MEDIA_MOUNTED.
All devices also report that Environment.getExternalStorageDirectory().getAbsolutePath().canWrite() is false.
Via PackageManager.checkPermission(), my app reports that it has the WRITE_EXTERNAL_STORAGE permission.
OI File Manager is able to create directories and move files on the SD card; my app can do neither.
This code is sufficient to cause a failure:
String sdcardDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
File directory = new File(sdcardDirectory + "/logger");
if(!directory.mkdirs()){
//fails here.
Log.w("Logger", "Could not create logger directory.");
}
Since I have access to the keys for this device, I even went so far as to sign the app with the platform key and run it as android.uid.system, with no luck. Anyone have any ideas?
It turns out this is a case partly of bad diagnosis on my part, and partly an apparent change in 2.1 to 2.3.
The bad diagnosis was that the directory above was indeed being created. The apparent change between 2.1 and 2.3 may be Android internally, or it may be the way we're setting up paths, PATH, and symbolic links in our own builds. Further down from the code in the original post, there are a few calls to exec() to get e.g. output from logcat and copies of various bits of useful information in /proc; using absolute paths to the commands fixed the problem.
Thanks for the help in ruling things out.