2013-08-06 25 views
5

Tôi chỉ có thể tìm thấy giải pháp từ năm 2010 trở về trước. Vì vậy, tôi muốn xem liệu có một lập trường cập nhật hơn về điều này không.fopen/fread APK Nội dung từ NativeActivity trên Android

Tôi muốn tránh sử dụng Java và sử dụng thuần túy C++, để truy cập các tệp (ít hơn một hoặc nhiều hơn 1MB) được lưu trữ trong APK. Sử dụng AssetManager có nghĩa là tôi không thể truy cập các tệp như mọi tệp khác trên mọi hệ điều hành khác (bao gồm iOS).

Nếu không, có phương pháp nào trong C++ mà tôi có thể ánh xạ fopen/fread tới API AssetManager bằng cách nào đó không?

+1

Vì nội dung không phải là tệp, câu trả lời có thể là "không". Nội dung là các mục nhập trong kho lưu trữ ZIP là APK. – CommonsWare

+0

'Tis là một điểm tốt ... –

+0

Về mặt kỹ thuật, vì APK không có gì hơn một tệp zip lạ mắt, bạn hoàn toàn có thể truy cập bất kỳ tệp nào ở bất kỳ đâu trong APK như thể đó là tệp zip trong C++. Nó tuy nhiên yêu cầu * một số * java, nhưng chỉ để có được vị trí cài đặt apk của bạn. Tôi biết để thực tế là không phải là một vấn đề nhưng tôi chưa bao giờ thử viết một APK. – Erik

Trả lời

6

Câu trả lời ngắn

lập bản đồ số AFAIK fread/fopen trong C++ để AAssetManager là không thể. Và nếu nó có thể sẽ giới hạn bạn vào các tập tin trong thư mục tài sản. Tuy nhiên, có một cách giải quyết khác, nhưng nó không đơn giản.

dài trả lời

thể truy cập bất kỳ tập tin bất cứ nơi nào trong APK sử dụng zlib và libzip trong C++. Yêu cầu: một số java, zlib và/hoặc libzip (để dễ sử dụng, vì vậy đó là những gì tôi đã giải quyết). Bạn có thể tải libzip tại đây: http://www.nih.at/libzip/

libzip có thể cần một số tinkering để làm cho nó hoạt động trên Android, nhưng không có gì nghiêm trọng.

Bước 1: lấy apk vị trí trong Java và vượt qua JNI/C++

String PathToAPK; 
ApplicationInfo appInfo = null; 
PackageManager packMgmr = parent.getPackageManager(); 
try { 
    appInfo = packMgmr.getApplicationInfo("com.your.application", 0); 
} catch (NameNotFoundException e) { 
    e.printStackTrace(); 
    throw new RuntimeException("Unable to locate APK..."); 
} 

PathToAPK = appInfo.sourceDir; 

Đi qua PathToAPK C++/JNI

JNIEXPORT jlong JNICALL Java_com_your_app(JNIEnv *env, jobject obj, jstring PathToAPK) 
{ 
    // convert strings 
    const char *apk_location = env->GetStringUTFChars(PathToAPK, 0); 

    // Do some assigning, data init, whatever... 
    // insert code here 

    //release strings 
    env->ReleaseStringUTFChars(PathToAPK, apk_location); 

    return 0; 
} 

Giả sử bây giờ bạn có một std :: string với vị trí APK của bạn và bạn có zlib trên libzip hoạt động, bạn có thể làm điều gì đó như sau:

if(apk_open == false) 
{ 
    apk_file = zip_open(apk_location.c_str(), 0, NULL); 

    if(apk_file == NULL) 
    { 
     LOGE("Error opening APK!"); 
     result = ASSET_APK_NOT_FOUND_ERROR; 
    }else 
    { 
     apk_open = true; 
     result = ASSET_NO_ERROR; 
    } 
} 

Và để đọc một tập tin từ APK:

if(apk_file != NULL){ 
    // file you wish to read; **any** file from the APK, you're not limited to regular assets 
    const char *file_name = "path/to/file.png"; 

    int file_index; 
    zip_file *file; 
    struct zip_stat file_stat; 

    file_index = zip_name_locate(apk_file, file_name, 0); 

    if(file_index == -1) 
    { 
     zip_close(apk_file); 
     apk_open = false; 

     return; 
    } 

    file = zip_fopen_index(apk_file, file_index, 0); 
    if(file == NULL) 
    { 
     zip_close(apk_file); 
     apk_open = false; 

     return; 
    } 

    // get the file stats 
    zip_stat_init(&file_stat); 
    zip_stat(apk_file, file_name, 0, &file_stat); 
    char *buffer = new char[file_stat.size]; 

    // read the file 
    int result = zip_fread(file, buffer, file_stat.size); 
    if(result == -1) 
    { 
     delete[] buffer; 
     zip_fclose(file); 

     zip_close(apk_file); 
     apk_open = false; 

     return; 
    } 

    // do something with the file 
    // code goes here 

    // delete the buffer, close the file and apk 
    delete[] buffer; 
    zip_fclose(file); 

    zip_close(apk_file); 
    apk_open = false; 

Không chính xác fopen/fread nhưng nó được công việc làm. Nó sẽ được khá dễ dàng để bọc này vào chức năng đọc tập tin của riêng bạn để trừu tượng lớp zip.

+0

libz được cung cấp bởi chuỗi công cụ Android những ngày này - sẽ có bất kỳ mối nguy hiểm nào khi sử dụng nó trên libzip? Họ có khác nhau/giống nhau không? –

+0

Không có gì cả. Tôi cũng sử dụng libz được cung cấp cho android; libzip chỉ là một thư viện nằm trên libz hàng đầu để giúp việc đọc/ghi dễ dàng hơn một chút. – Erik

+1

Một sửa chữa nhanh chóng bạn cần xóa [] không xóa trên bộ đệm. –

8

Tôi thực sự đã tìm thấy câu trả lời khá thanh lịch cho vấn đề và blogged about it here.

Bản tóm tắt là:

  • Các AAssetManager API đã gán NDK. Điều này cho phép bạn tải nội dung từ APK.
  • Có thể kết hợp một tập hợp các hàm biết cách đọc/ghi/tìm kiếm bất kỳ thứ gì và ngụy trang chúng dưới dạng con trỏ tệp (FILE *).
  • Nếu chúng ta tạo hàm có tên nội dung, hãy sử dụng AssetManager để mở nó, sau đó cải trang kết quả thành FILE * thì chúng ta có một cái gì đó rất giống với fopen.
  • Nếu chúng tôi xác định macro có tên fopen, chúng tôi có thể thay thế tất cả các lần sử dụng chức năng đó bằng chức năng của chúng tôi.

Blog của tôi có ghi đầy đủ và tất cả mã bạn cần triển khai trong C. Tôi sử dụng tính năng này để xây dựng lua và libogg cho Android.

+1

cho kích thước tệp: 'size_t file_size (FILE * fp) { android_seek (fp, 0L, SEEK_END); size_t sz = ftell (fp); android_seek (fp, 0L, SEEK_SET); trả lại sz; } ' –

Các vấn đề liên quan