使用 C++ 获取 Android APK 的名称和 NativeActivity 类

发布于 2024-12-08 21:11:54 字数 421 浏览 0 评论 0原文

我正在使用 NDK 和 NativeActivity 编写 Android 应用程序。我的应用程序依赖于一些作为资产提供的第三方代码。目前,我正在尝试提取这些资产,同时保持文件夹结构完整。

我尝试过使用 AssetManager,但为了保持文件夹结构完整,对于像我提到的这样的简单任务,似乎会涉及大量代码。此后,我将注意力转移到尝试将 APK 视为 ZIP 文件并以这种方式提取其内容。但这需要我找到 APK 的确切路径。

在普通的 Android 应用程序中,我们会使用 getPackageCodePath,但这是附加到 Context 类的一个抽象方法。我的问题是,在不使用正常 Activity 时如何获取 APK 的确切路径?

我还尝试通过 JNI 调用 getPackageCodePath,但由于无法找到该方法而导致应用程序崩溃。

编辑: 这可能吗?

I'm writing an Android app using the NDK and NativeActivity. My app depends on a few bits of third party code that are shipped as assets. Currently I'm working on trying to extract those assets while keeping the folder structure intact.

I've tried using the AssetManager, but to keep the folder structure intact it seemed like there would a huge amount of code involved, for a simple task such as what I've mentioned. I've since switched focus to try to implement treating the APK as a ZIP file and extract its contents that way. But that requires I find the exact path to the APK.

In a normal Android app one would use getPackageCodePath, but this is an abstract method attached to the Context class. My question is how do I obtain the exact path to the APK when not using a normal Activity?

Also I tried calling getPackageCodePath via JNI, but that crashed the app on account of not being able to find the method.

EDIT:
Is this even possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

不知在何时 2024-12-15 21:11:54

我实际上能够通过 JNI 调用 getPackageCodePath 并使其正常工作。以下代码放在 NDK r7 中本机活动示例中的 android_main 顶部,记录了正确的路径并且不会崩溃:

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. 线程安全 - 有一个丑陋的警告,关于仅在主 Java 线程中使用 ANativeActivityenv 成员,如果我理解正确的话,这段代码将在本机活动的线程中运行。
  2. ANativeActivityclazz 成员似乎命名错误,实际上是 Java NativeActivity 的实例而不是类对象。否则这段代码将无法工作。我真的很讨厌依赖像这样明显命名错误的东西。

除此之外,它确实有效,而且我实际上自己也打算使用它来尝试使用 libzip 将资产从 .apk 中提取出来并放入数据目录中。

I was actually able to call getPackageCodePath via JNI and get it to work. The following code put at the top of android_main in the native-activity sample in NDK r7 logs the correct path and doesn't crash:

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);

    ...
}

I feel like this might not be a great solution, though. There are two things that worry me:

  1. Thread safety - there's an ugly warning about only using the env member of ANativeActivity in the main Java thread, and if I understand things correctly, this code is going to get run in the native activity's thread.
  2. ANativeActivity's clazz member appears to be misnamed and is actually the instance of the Java NativeActivity instead of the class object. Otherwise this code wouldn't work. I really hate relying on something that is obviously misnamed like this.

Aside from that, it works, and I'm actually about to use it myself to try to extract the assets out of the .apk using libzip and into the data directory.

月依秋水 2024-12-15 21:11:54

由于我只需精确搜索如何执行附加/分离调用,因此我将在此处粘贴更新的版本。

以下似乎获得了正确的位置而不会崩溃(经过最少的测试)

    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);

Since I just had to search for exactly how to do the attach/detach calls I'll paste the updated version here.

The following seems to get the right location without crashing (after minimal testing)

    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);
单身狗的梦 2024-12-15 21:11:54

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();

Had to modify it to this in the year 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();
我只土不豪 2024-12-15 21:11:54

您是否尝试从应用程序中读取 /proc/self/cmdline ?
您应该能够像正常一样打开它(只要 proc 文件是正常的:-),这样您就可以从文件中读取直到 EOF,但不能查找)c FILE 并从中读取。

作为电话应用程序的示例,我可以从 android 中的 ps 看到应用程序的名称是预期的应用程序名称:

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

检查 cmdline 中的 pid 返回一个好的应用程序名称:

 # cat /proc/1588/cmdline
 com.android.phone

Did you try to read /proc/self/cmdline from your application?
You should be able to open it as a normal (as far as proc files are normal :-) so you can read from the file until EOF, but not seek) c FILE and read from it.

As an example for the phone app, I can see from ps in android that the name of the applications is the expected app name:

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

And checking the cmdline for that pid returns a good app name:

 # cat /proc/1588/cmdline
 com.android.phone
怼怹恏 2024-12-15 21:11:54

在 Java 中调用 getPackageCodePath() 并通过本机方法将 jstring 传递到您的 C++ 应用程序

Call getPackageCodePath() in Java and pass jstring to your C++ app via native method

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文