【问题标题】:Obtaining the name of an Android APK using C++ and the NativeActivity class使用 C++ 和 NativeActivity 类获取 Android APK 的名称
【发布时间】:2011-12-03 20:19:53
【问题描述】:

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

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

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

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

编辑: 这甚至可能吗?

【问题讨论】:

    标签: android android-ndk native-activity


    【解决方案1】:

    我实际上可以通过 JNI 调用 getPackageCodePath 并让它工作。以下代码放在 NDK r7 的 native-activity 示例中的 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 中提取到数据目录中。

    【讨论】:

    • 似乎我尝试了类似的方法,但没有成功。嗯,我想我遗漏了一些东西。谢谢你的回答:)
    • 关于我上面的第 1 个问题:事实证明,线程安全可以通过使用 JavaVM 的 AttachCurrentThread 函数来实现。这将创建/检索应该使用的 JNIEnv,而不是我上面列出的那个。 ANativeActivity 的 vm 成员是一个 JavaVM。在线程中使用 JNIEnv 完成后,您应该调用 JavaVM 的 DetachCurrentThread 并停止使用 JNIEnv。我给出的原始代码实际上在某些设备上崩溃了,但是当开始调用 Attach/DetachCurrentThread 时,它停止了崩溃并且运行良好。
    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

      以手机应用为例,我可以从 android 中的 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
      

      【讨论】:

      • 我认为这行不通。进程名称通常与实际 apk 文件的名称不同。有时(尤其是在更新之后)一个数字会卡在进程名称中未表示的末尾。我也不是在寻找应用程序名称,而是在寻找包文件的名称。标记为上述答案的响应为我解决了问题。
      【解决方案4】:

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

      【讨论】:

      • 嗯是的,我知道..但是在 NativeActivity 应用程序中没有 Java 代码,所以不能使用。
      【解决方案5】:

      不得不在 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();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-22
        • 2013-08-08
        • 2015-07-06
        • 2013-12-20
        • 2018-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多