I'm trying to use some executables inside my app. This executable is C++ based (with images and logs as output), there may be other ways to use C++ code, but in this specific context, it might be the best to use it as an executable which only needs arguments. (NDK f.e. will be too much changing of the used library and I'm hoping there may be a way to parallelize this process some days)
My research showed that some other people were looking for similar problems. It seems that the best way was to add these external programs inside the assets folder (app/src/main/assets). That is what I did, but now I'm not quite sure how to get my data inside the assets folder. Some posting said that these files have to be extracted in another folder to get them work.
So I tried this method:
How to copy files from 'assets' folder to sdcard? (result: app shutdown)
I would like to add some code, but there isn't much for now. As I already told my executable should be inside assets and its name is f.e. exec, I also named it libexec.so, because I read somewhere that you have to name these files like lib"...".so to get them extracted. In general, my aim is to use this executable like:
data/exec
Now to my questions:
How can I get access my assets files?
Or should I use another folder instead of assets, will it be easier to use? How could I add an external executable there?
After some time I managed to get it work through:
https://github.com/flipagram/android-assetcopier
I just had to change something:
Example was:
File destDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
I've changed it to: File destDir = (MainActivity.this).getFilesDir(); - so there is no problem with permissions (I guess).
But be aware: Copying is successful, but I did not manage to run the program successfully. Maybe the whole process will get killed through a security manager or something else won't work.
Related
So, I'm pretty new to chaquopy and was wondering if there's anyway to get newly generated (ie: written post-build, while the app is running) .py files to run?
What I mean is:
Say I save the contents of a textEdit view into a file named 'newFile.py', and it goes into some specified external storage location. Is there anyway to specify that externalStorageDir in advance via source sets (which, as far as I can tell, only apply to src directories and not externalStorage) or something else so that getModule() can later locate it, making the functions in the newly written file callable?
Pretty niche question I know, but this package has me thinking of all kinds of possibilities.
You can modify sys.path at runtime, like this:
py.getModule("sys").get("path").callAttr("append", yourExternalDirectory);
And now any Python files in that directory can be loaded using py.getModule.
I am currently porting a library from Linux to Android and I am having some trouble.
The lib has an extension system : it will look for all the files with a particular extension in the folder /usr/local/lib/{thelibname}/extensions/, check if they are dynamic libraries, and load them and call a handler if it is the case.
However, I don't think it is possible to tinker with the base filesystem folders in Android.
I looked into assets but they did not convince me, it looks like they are more intended for images, audio, etc...
Is there another way to embed some files in an .apk and load them afterwards by enumerating a DIR* and calling dlopen ?
The other possibility would be to put the extensions with the app data but I don't know if there is a standard path for this that I could hardcode in the lib, is there? And I don't how to put some stuff in the data at the installation of the apk ? (I use QtCreator for the generation of the APK)
Okay, I found another question which helped me to solve my problem :
How to integrate native runtime library with dlopen on NDK?
You can easily load extension libraries from anywhere in the file system, including shared folders like /sdcard/ and her children. Any app (and native libraries therein) can gain full read access to /sdcard/ with READ_EXTERNAL_STORAGE permission.
This way you can establish a folder where the extensions will be updated not necessarily by a single APK (note the changes for WRITE_EXTERNAL_STORAGE in KitKat).
If you want to deploy all extension libraries as part of the APK, it's easiest to put them in the standard folder that is used to pack the APKs (for ADT, it's ${project_root}/libs/armeabi) and then they will be automagically installed in /data/app-lib/${app_package}. This approach allows to prepare an APK for multiple architectures, preparing appropriate files in ${project_root}/libs/x86, etc.
Note that all libraries must have lib prefix and .so suffix, so e.g. mylib.so or libcrypto.so.6 will not work, even though theoretically such libraries can be loaded by dlopen().
Your app has read access to the /data/app-lib/${app_package} directory, so you can scan it either from C code, or from Java. In Java, its easy to resolve the ${app_package} even if you don't want to hardcode this name. Simply call getApplicationContext().getPackageName().
In C, you can use /proc/${pid} to find the full path to your shared library, and this way you will also know the path to the extensions.
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'm very new to android. I would like to create a package that upon install would put files in the app folder (/data/data/my.app/...) of the android file system.
I would like to do this, so I could access the files using standard java File methods (in order to reuse my own code), and not have to use the android resource accessing methods.
The only way I thought might achieve something in this direction, is to put the files in the /res folder, and copy them to the file system in runtime (on first run, for example). This has the disadvantage of having two copies of each file for no reason.
Another way could be to get my app to download these files from a server (saw this option in another answer as well). This is possible, but I would wish to avoid having to put up a file server for such a simple task...
To my understanding, DDMS will not help here, as it only allows me to access the folder manually, after the application is installed.
My question is: Is there a different way to achieve my original goal (accessing files using standard java methods)? If not, is there a cleaner way to put files on the file system?
Thanks!
There are 3 methods I can think of that avoid duplication:
As you mentioned using the res/raw folder. You can avoid duplication if your existing code uses can use InputStream instead of File and use Resources.openRawResource().
Use the assets folder and access the file using file using AssetManager.openNotAssetFd(). Again this would require the use of Streams not File class. This can get a bit messy if your file is compressed because assets are memory mapped.
If you code is really tied to File (doesn't just use it to open an InputStream). To avoid duplication you could download the file from the web on the first time it is run and store it into the external storage.
You can put your files on under /res/raw and then use:
Resources res = context.getResources();
InputStream in_s = res.openRawResource(R.raw.myfile);
Or if you want the File object
File f = new File(context.getResources().openRawResource(R.raw.myfile));
Then you can use normal Java apis to work with your files.
I want to know that how can I directly access the resources like images, sound files etc. from native code i.e. C++ files. Actually I am looking for any example that could help me to use the asset_manager_jni.h methods.
Looking for suggestions. Thanks in advance.
With Regards,
Atul Prakash Singh
Well, you have access to stdio.h. So if it's in a known place (say on the SD card), you can just use that as a path. And there's lot's of tutorials on the net about hot to use stdio (fopen, fclose, etc).
The issue is that resources you bundle into the apk itself (either in res/raw, or assets), stay inside the apk after install. What's worse is that by default, they will be compressed which makes reading it not feasible. This can be avoided, and the easiest way is to rename the asset to have the .mp3 extension (or there are others). The reason for this is because by default, .mp3 is not compressed, regardless of whether or not it actually is an mp3 file). There are other extensions you can use, and ways to tell the tools not to compress your data if you don't like naming all of your assets with .mp3 at the end.
So, you have a few choices here:
Download your resources from the net on your first run, put them in an unobtrusive place (it's probably best to get that path from the sdk when you do the downloading), and use that.
Store your resources in the apk (remember the .mp3 extension, in the assets folder). On your first run, extract the assets to a folder you have access to (and doesn't annoy the user), and use the resources from there.
(what I do) Store your resources in the apk (.mp3 again), and use the jni to read directly from the apk. Yes, the jni is a bit slow, but you shouldn't be reading from the file system all that much anyway, and certainly not at a performance critical point. Nvidia has some very helpful code you can use, you can find it here, it's in the sample code if I remember. Inside the libs folder are some good general purpose libraries you can use that matches stdio, except it also reads from the apk itself.
Hope it helps.
I did use this trick once :
mv $file lib/lib%${file}.so