Получаване на името на Android APK с помощта на C++ и класа NativeActivity

Пиша приложение за Android, използвайки NDK и NativeActivity. Приложението ми зависи от няколко бита код на трета страна, които се доставят като активи. В момента се опитвам да извлека тези активи, като същевременно запазя структурата на папките непокътната.

Опитах да използвам AssetManager, но за да запазя структурата на папките непокътната, изглеждаше, че ще има огромно количество включен код за проста задача като това, което споменах. Оттогава смених фокуса, за да се опитам да приложа третирането на APK като ZIP файл и да извлека съдържанието му по този начин. Но това изисква да намеря точния път до APK.

В нормално приложение за Android човек би използвал getPackageCodePath, но това е абстрактен метод, прикрепен към класа Context. Въпросът ми е как да получа точния път до APK, когато не използвам нормална активност?

Също така се опитах да извикам getPackageCodePath чрез JNI, но това срина приложението поради невъзможността да намеря метода.

РЕДАКТИРАНЕ: Това изобщо възможно ли е?


person rstat1    schedule 09.10.2011    source източник


Отговори (5)


Всъщност успях да се обадя на getPackageCodePath чрез JNI и да го накарам да работи. Следният код, поставен в горната част на android_main в примера за естествена активност в NDK r7, регистрира правилния път и не се срива:

void android_main(struct android_app* state) {
    struct engine engine;

    ANativeActivity* activity = state->activity;
    JNIEnv* env = activity->env;

    jclass clazz = (*env)->GetObjectClass(env, activity->clazz);
    jmethodID methodID = (*env)->GetMethodID(env, clazz, "getPackageCodePath", "()Ljava/lang/String;");
    jobject result = (*env)->CallObjectMethod(env, activity->clazz, methodID);

    const char* str;
    jboolean isCopy;
    str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
    LOGI("Looked up package code path: %s", str);

    ...
}

Чувствам обаче, че това може да не е чудесно решение. Има две неща, които ме притесняват:

  1. Безопасност на нишката - има грозно предупреждение за използването само на члена env на ANativeActivity в основната нишка на Java и ако разбирам нещата правилно, този код ще се изпълнява в нишката на основната дейност.
  2. Членът clazz на ANativeActivity изглежда е наречен погрешно и всъщност е екземплярът на Java NativeActivity вместо обекта клас. В противен случай този код нямаше да работи. Наистина мразя да разчитам на нещо, което очевидно е погрешно наречено по този начин.

Освен това работи и всъщност смятам да го използвам сам, за да се опитам да извлека активите от .apk с помощта на libzip и в директорията с данни.

person matt    schedule 09.12.2011
comment
Изглежда, че опитах нещо подобно, но не се получи. Хм, май съм пропуснал нещо. Благодаря за вашият отговор :) - person rstat1; 11.12.2011
comment
Относно моето безпокойство №1 по-горе: Оказва се, че безопасността на нишката може да бъде постигната чрез използване на функцията AttachCurrentThread на JavaVM. Това ще създаде/извлече JNIEnv, който трябва да се използва вместо този, който изброих по-горе. Членът на vm на ANativeActivity е JavaVM. Когато приключите с използването на JNIEnv в нишката, трябва да извикате DetachCurrentThread на JavaVM и да спрете да използвате JNIEnv. Оригиналният код, който дадох, всъщност се срива на някои устройства, но когато Attach/DetachCurrentThread започна да се извиква, той спря да се срива и работи чудесно. - person matt; 29.03.2012

Тъй като просто трябваше да потърся как точно да направя повикванията за прикачване/откачане, ще поставя актуализираната версия тук.

Следното изглежда получава правилното местоположение без срив (след минимално тестване)

    ANativeActivity* activity = state->activity;
    JNIEnv* env=0;

    (*activity->vm)->AttachCurrentThread(activity->vm, &env, 0);

    jclass clazz = (*env)->GetObjectClass(env, activity->clazz);
    jmethodID methodID = (*env)->GetMethodID(env, clazz, "getPackageCodePath", "()Ljava/lang/String;");
    jobject result = (*env)->CallObjectMethod(env, activity->clazz, methodID);

    const char* str;
    jboolean isCopy;
    str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
    LOGI("Looked up package code path: %s", str);

    (*activity->vm)->DetachCurrentThread(activity->vm);
person Kriss    schedule 24.07.2012

Опитахте ли да прочетете /proc/self/cmdline от вашето приложение? Трябва да можете да го отворите нормално (доколкото proc файловете са нормални :-), така че можете да четете от файла до EOF, но не и да търсите) c FILE и да четете от него.

Като пример за приложението за телефон, виждам от ps в android, че името на приложенията е очакваното име на приложението:

 # ps | grep phone 
 radio     1588  839   1467420 103740 SyS_epoll_ 7f7de374ac S com.android.phone

И проверката на cmdline за този pid връща добро име на приложението:

 # cat /proc/1588/cmdline
 com.android.phone
person renato    schedule 15.08.2016
comment
Не мисля, че това би проработило. Името на процеса обикновено не е същото като името на действителния apk файл. Понякога (особено след актуализации) номер се забива в края, който не е представен в името на процеса. Също така не търсех името на приложението, а името на пакетния файл. Отговорът, маркиран като отговор по-горе, реши проблема за мен. - person rstat1; 16.08.2016

Обадете се на getPackageCodePath() в Java и предайте jstring към вашето C++ приложение чрез естествен метод

person PiotrK    schedule 30.11.2011
comment
Ами да, за което знаех.. но в приложението NativeActivity няма Java код, така че не може да се използва. - person rstat1; 03.12.2011

Трябваше да го модифицирам до това през 2014 г.

ANativeActivity* activity = state->activity;
JNIEnv* env=0;

activity->vm->AttachCurrentThread(&env, NULL);

jclass clazz = env->GetObjectClass(activity->clazz);
jmethodID methodID = env->GetMethodID(clazz, "getPackageCodePath", "()Ljava/lang/String;");
jobject result = env->CallObjectMethod(activity->clazz, methodID);

jboolean isCopy;
std::string res = env->GetStringUTFChars((jstring)result, &isCopy);
LOG_DEBUG("Looked up package code path: %s", res.c_str());

activity->vm->DetachCurrentThread();
person iseletsky    schedule 27.07.2014