Issue
I wonder how to make file hierarchy of assets folder in Android from native code. I'm using AAssetManager_openDir but AAssetDir_getNextFileName doesn't return any directory names so basically I have no way to dive deeper into hierarchy because I can't obtain names of subfolders. Is there any way to resolve this issue with AAssetManager or should I implement this in Java?
Example
Assets looks like
a/
file1
file2
b/
file3
c/
file4
C++ code
AAssetDir* assetDir = AAssetManager_openDir(env, "");
// filename is NULL since there is only folders at the root folder
const char* filename = AAssetDir_getNextFileName(assetDir);
AAssetDir_close(assetDir);
AAssetDir* assetDir = AAssetManager_openDir(env, "a");
// filename is "file1"
const char* filename = AAssetDir_getNextFileName(assetDir);
// filename is "file2"
filename = AAssetDir_getNextFileName(assetDir);
AAssetDir_close(assetDir);
EDIT:
I found out that AAssetDir_getNextFileName implementation literally filters directories from output.
Link to source code
You can achieve your goal in three steps, each requires some programming. The bottom line is, your assets all live in the APK file, and your app can find and read the APK file, and its format is a ZIP archive.
Find your APK file name.
Open this file for read as zip archive.
Iterate the zip contents for assets/<whatever>.
For 1), you can use Java or if you must stay in c++, filter /proc/self/fd. You may find some system APK files (framework), but your APK will be the only one that is not system.
For 2), see use zlib to list directory structure of apk file in android. Note that zlib is part of public NDK libraries.
Related
I believe that every application can get access to its own files, for example - to classes.dex file.
I wonder how the application get access to its files?
and another question, can I fake this access and get access to another application.?
you can point to the apk file of your application using ApplicationInfo.publicSourceDir
File yourApk = new File(this.getApplicationInfo().publicSourceDir);
//create the destination dir
File tempDir = new File(getFilesDir(), "temp_dir");
//and then unzip the apk to that dir
unzip(yourApk , tempDir);
//now the tempDir will contain all the resources including the dex file and its accessible
this file is a zip file you can decompress that file using this link
How to unzip files programmatically in Android?
so you will have the access to all resources plus the classes.dex
hope this will help
I am trying to get an instance of an image in Unity that is in:
/assets/texture/image.png
Here is what I did:
path = Application.persistentDataPath;
path2 = Application.dataPath;
path3 = Application.streamingAssetsPath;
iTextSharp.text.Image imageHeader = iTextSharp.text.Image.GetInstance("jar:file://" + path2 + "!/assets/texture/image.png");
I did try with all the paths, and I am getting:
NotSupportedException:
jar:file:/data/app/com.myapk!/assets/texture/image.png.
Any help?
To access a file in the assets folder of your apk:
String path = getAssets() + "/texture/image.png";
iTextSharp.text.Image imageHeader = iTextSharp.text.Image.GetInstance(path);
The path should be something like:
file:///android_asset/texture/image.png
EDIT: Can't use getAssets in Unity - Then there will not be a direct system-mounted file path for files in the assets folder.
What I usually do for C++/NDK applications with graphical assets is to decompress the assets directory to the SDCard to have a direct path access. On first launch of the app, you extract your assets folder to /mnt/sdcard (getExternalStorageDirectory) then use that. Otherwise I have no Idea how to do it in Unity directly, but there must be something.
If you want to make this easy on yourself, put your texture in the Resources/ folder and use Resources.Load to load it. Or put it in StreamingAssets/ and use the WWW class to load if from the jar file.
I use libzip to read APK content in native code.
assets/sounds/voice folder "disappeared" for libzip functions only.
libzip still see other files.
I still can see it in assets/sounds/voice in project folder.
I did clean many times.
I still can unzip APK file from bin folder and I see all required files. (including files from assets/sounds/voice folder)
I added small logging command and it does not print files from assets/sounds/voice folder. All other files are present.
int inum = zip_get_num_files(apkzip);
for(int i = 0; i < inum; i++){
const char * name = zip_get_name(apkzip, i, 0);
__android_log_print(ANDROID_LOG_INFO,"FILEZIP", "zip: %s", name);
}
I have no idea what at what step it is wrong. Had eclipse compressed ZPK with new format that my libzip does not able to read? or what could be a reason.
This is not an answer for libzip, but why you have to use libzip to read apk file in NDK application? In Android NDK, you can use AAsset APIs to get file from the apk. Take a look at "How To Get File In Assets From Android NDK".
EDITED
It is not available in android-5 that I still use
Ok. So how about Cocos2d-x's ZipFile? It is based on Minizip.
How to use ZipFile from cocos2dx/platform/android/CCFileUtilsAndroid.cpp
s_pZipFile = new ZipFile(resourcePath, "assets/");
pData = s_pZipFile->getFileData(fullPath.c_str(), pSize);
I am current working on an Android project.
Since the android apk file is essentially a zip file with a different file extension, is it possible to use zlib to file the directory structure of the asset folder?
The goal is to write some interfaces like opendir() and readdir() so that I can do something like:
DIR* dir = zip_opendir("somedirectory");
struct dirent* entry;
while (0 != (entry = zip_readdir(dir))){
__android_log_print(ANDROID_LOG_ERROR, "DIR", "entry: %s\n", entry->d_name);
}
except that all the operations take place inside a zip file.
You can use libzip (which itself uses zlib) to work with zip files. It does all you want and more.
Need to use a shared lib for android from 3rd party, the lib's soname and file name are same, in format libxx.so.1.2.3, which is common on linux. I rename the lib file to libxx.so, and link libxx.so in libmyjni.so using ndk-build. In my java code, before calling the functions in libmyjni.so, I load them like this:
System.load("/data/local/tmp/libxx.so.1.2.3");
System.loadLibrary("myjni");
I have to manually copy libxx.so.1.2.3 to /data/local/tmp/. It works well in this way, after above loading, I can call functions in libmyjni.so.
In code "System.loadLibrary("myjni");", system always trying to get libxx.so.1.2.3 from somewhere. I want to know, in the real world, how could I copy libxx.so.1.2.3 to a specific location on android device during installation? so that I can System.load() it.
Or android has official way to install self made lib to /system/lib/?
If libxx.so.1.2.3 is in format libxx.so then I can use System.loadLibrary("xx") to load it.
Here is finally what I did, keep the libxx.so.1.2.3 untouched and do all stuff in Java:
Put libxx.so.1.2.3 in android assets.
In MainApp.OnCreate(), copy the file to private file folder and load it from there:
AssetManager am = applicationContext.getAssets();
in = am.open(OPENSSL_SO_LIB_NAME); // source instream
File privateStorageDir = applicationContext.getFilesDir();
String libPath = privateStorageDir.getAbsolutePath(); // copy the lib to here ...
System.load(libPath + "/" + SO_LIB_NAME);