jni讀取assets資原始檔
阿新 • • 發佈:2019-01-22
assets目錄底下的檔案會被打包到一個apk檔案裡,這些資源在安裝時他們並沒被解壓,使用時是直接從apk中讀取的。這裡介紹下怎麼在jni內使用ndk自帶api的介面函式讀取assets資原始檔,和libzip庫函式的使用,可以用來讀建立修改壓縮文件,這裡也是以讀取apk安裝包內的資原始檔為例。
在應用程式內使用定義和使用如下
logcat測試結果
上面例子使用android.mk如下
log.txt內容如下
1 用ndk自帶的介面函式讀apk包
從2.3開始提供這些介面函式,具體看標頭檔案assert.h android/asset_manager.h android/asset_manager_jni.h,可以參考ndk自帶例子中samples/native-audio/ jni/native-audio-jni.c。
/******************************************************************************* * Function Name : java_com_fontlose_ReadAssets_readFromAssets * Description : 定義:public native void readFromAssets(AssetManager ass,String filename); * Input : AssetManager物件 filename資源名 * Output : None * Return : None *******************************************************************************/ void Java_com_fontlose_ReadAssets_readFromAssets(JNIEnv* env,jclass tis,jobject assetManager,jstring filename) { LOGI("ReadAssets"); AAssetManager* mgr = AAssetManager_fromJava(env, assetManager); if(mgr==NULL) { LOGI(" %s","AAssetManager==NULL"); return ; } /*獲取檔名並開啟*/ jboolean iscopy; const char *mfile = (*env)->GetStringUTFChars(env, filename, &iscopy); AAsset* asset = AAssetManager_open(mgr, mfile,AASSET_MODE_UNKNOWN); (*env)->ReleaseStringUTFChars(env, filename, mfile); if(asset==NULL) { LOGI(" %s","asset==NULL"); return ; } /*獲取檔案大小*/ off_t bufferSize = AAsset_getLength(asset); LOGI("file size : %d\n",bufferSize); char *buffer=(char *)malloc(bufferSize+1); buffer[bufferSize]=0; int numBytesRead = AAsset_read(asset, buffer, bufferSize); LOGI(": %s",buffer); free(buffer); /*關閉檔案*/ AAsset_close(asset); }
在應用程式內使用定義和使用如下
public native void readFromAssets(AssetManager ass,String filename);
readFromAssets(getAssets(),"log.txt");
logcat測試結果
12-15 15:27:33.290: INFO/ReadAssets(3570): ReadAssets 12-15 15:27:33.290: INFO/ReadAssets(3570): file size : 138 12-15 15:27:33.290: INFO/ReadAssets(3570): : 。。。。。。。。。。。。。。。。 12-15 15:27:33.290: INFO/ReadAssets(3570): 這個例子從jni讀取assets內檔案 12-15 15:27:33.290: INFO/ReadAssets(3570): 。。。。。。。。。。。。。。。。
2 使用libzip庫讀apk包
libzip 使用 C 庫來 讀建立修改壓縮文件,關於libzip在andorid的移植可以參考老外做的android-ndk-assets.zip這個工程,已在NDK下可以編譯了,修改下編譯生成libzip.so,利用libzip.so和zip.h建立工程,使用libzip還可以讀取apk包內其他壓縮檔案如AndroidManifest.xml佈局xml等。void Java_com_fontlose_ReadAssets_readFromAssetsLibzip(JNIEnv* env,jclass tis,jstring assetpath,jstring filename)
{
LOGI("ReadAssets");
int i=0;
jboolean iscopy;
const char *mpath = (*env)->GetStringUTFChars(env, assetpath, &iscopy);
struct zip* apkArchive=zip_open(mpath, 0, NULL);;
(*env)->ReleaseStringUTFChars(env, filename, mpath);
struct zip_stat fstat;
zip_stat_init(&fstat);
int numFiles = zip_get_num_files(apkArchive);
LOGI("File numFiles %i \n",numFiles);
for (i=0; i<numFiles; i++) {
const char* name = zip_get_name(apkArchive, i, 0);
if (name == NULL) {
LOGE("Error reading zip file name at index %i : %s", zip_strerror(apkArchive));
return;
}
zip_stat(apkArchive,name,0,&fstat);
LOGI("File %i:%s Size1: %d Size2: %d", i,fstat.name,fstat.size ,fstat.comp_size) ;
}
const char *fname = (*env)->GetStringUTFChars(env, filename, &iscopy);
struct zip_file* file = zip_fopen(apkArchive, fname, 0);
if (!file) {
LOGE("Error opening %s from APK", fname);
return;
}
zip_stat(apkArchive,fname,0,&fstat);
(*env)->ReleaseStringUTFChars(env, filename, fname);
char *buffer=(char *)malloc(fstat.size+1);
buffer[fstat.size]=0;
int numBytesRead = zip_fread(file, buffer,fstat.size);;
LOGI(": %s\n",buffer);
free(buffer);
zip_fclose(file);
zip_close(apkArchive);
}
在應用程式內使用定義和使用如下
public native void readFromAssetsLibzip(String apkpath,String filename);
readFromAssetsLibzip(getPackageResourcePath(),"assets/log.txt");
logcat測試結果
12-15 15:28:03.430: INFO/ReadAssets(3570): ReadAssets
12-15 15:28:03.440: INFO/ReadAssets(3570): File numFiles 14
12-15 15:28:03.440: INFO/ReadAssets(3570): File 0:assets/log 2.txt Size1: 138 Size2: 55
12-15 15:28:03.440: INFO/ReadAssets(3570): File 1:assets/log.txt Size1: 138 Size2: 55
12-15 15:28:03.440: INFO/ReadAssets(3570): File 2:res/layout/main.xml Size1: 956 Size2: 337
12-15 15:28:03.440: INFO/ReadAssets(3570): File 3:AndroidManifest.xml Size1: 1348 Size2: 531
12-15 15:28:03.440: INFO/ReadAssets(3570): File 4:resources.arsc Size1: 1480 Size2: 1480
12-15 15:28:03.440: INFO/ReadAssets(3570): File 5:res/drawable-hdpi/icon.png Size1: 3966 Size2: 3966
12-15 15:28:03.440: INFO/ReadAssets(3570): File 6:res/drawable-ldpi/icon.png Size1: 1537 Size2: 1537
12-15 15:28:03.440: INFO/ReadAssets(3570): File 7:res/drawable-mdpi/icon.png Size1: 2200 Size2: 2200
12-15 15:28:03.440: INFO/ReadAssets(3570): File 8:classes.dex Size1: 3468 Size2: 1680
12-15 15:28:03.440: INFO/ReadAssets(3570): File 9:lib/armeabi/libzip.so Size1: 217246 Size2: 46140
12-15 15:28:03.440: INFO/ReadAssets(3570): File 10:lib/armeabi/libreadres.so Size1: 3820 Size2: 1779
12-15 15:28:03.440: INFO/ReadAssets(3570): File 11:META-INF/MANIFEST.MF Size1: 852 Size2: 443
12-15 15:28:03.440: INFO/ReadAssets(3570): File 12:META-INF/CERT.SF Size1: 905 Size2: 487
12-15 15:28:03.440: INFO/ReadAssets(3570): File 13:META-INF/CERT.RSA Size1: 776 Size2: 606
12-15 15:28:03.440: INFO/ReadAssets(3570): : 。。。。。。。。。。。。。。。。
12-15 15:28:03.440: INFO/ReadAssets(3570): 這個例子從jni讀取assets內檔案
12-15 15:28:03.440: INFO/ReadAssets(3570): 。。。。。。。。。。。。。。。。
上面例子使用android.mk如下
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := readres
LOCAL_SRC_FILES := readres.c
LOCAL_C_INCLUDES+= /opt/android-ndk-r5/platforms/android-9/arch-arm/usr/include
LOCAL_LDLIBS += -L/opt/android-ndk-r5/platforms/android-9/arch-arm/usr/lib/ -llog
LOCAL_LDLIBS += -landroid
LOCAL_LDLIBS += -lz
LOCAL_LDLIBS += -L$(LOCAL_PATH) -lzip
include $(BUILD_SHARED_LIBRARY)
log.txt內容如下
。。。。。。。。。。。。。。。。
這個例子從jni讀取assets內檔案
。。。。。。。。。。。。。。。。