Получение имени 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

И проверка командной строки для этого 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