4

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

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

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

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

编辑:这甚至可能吗?

4

5 回答 5

7

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

除此之外,它还可以工作,我实际上将自己使用它来尝试使用 libzip 将资产从 .apk 中提取出来并放入数据目录中。

于 2011-12-09T22:01:01.463 回答
4

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

以下似乎在没有崩溃的情况下获得了正确的位置(经过最少的测试)

    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);
于 2012-07-24T11:07:32.880 回答
3

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

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

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

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

 # cat /proc/1588/cmdline
 com.android.phone
于 2016-08-15T13:10:34.760 回答
2

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

于 2011-11-30T17:20:41.500 回答
2

不得不在 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();
于 2014-07-27T04:42:04.300 回答