5

NDK を使用して Android で作業を開始しています。デバイスが C コードで実行している Android API レベルを確認したいと考えています。どうやってやるの?

最初は /android/api-level.h の下の定義を使用できると思って__ANDROID_API__いましたが、それは間違った仮定でした。

**注: Java 経由で API レベルを確認する方法を尋ねているわけではありません。

4

3 に答える 3

9

私はいくつかの JNI コードに取り組んでおり、Jonaで説明されているように、実行中の OS ビルド バージョンを照会したいと考えていました。これをできるだけ早く(つまりJNI_OnLoadで)実行したかったので、 FUBUsで説明されているように Java から渡さないようにしました。API レベル 4 以降、この情報は、このスニペットで調べているandroid.os.Build.VERSIONの int フィールドSDK_INTとして利用できます。

static const char* TAG = "testjnjni";

static bool _disableHttpKeepAliveOnBuggyPlatforms(JNIEnv *env)
{
    // Based on article here:
    //   http://android-developers.blogspot.co.uk/2011/09/androids-http-clients.html
    // Which references the issue documented here:
    //   http://code.google.com/p/android/issues/detail?id=2939
    // We need to set "http.keepAlive" to "false" if running an OS version earlier than Froyo (API Level 8)

    if ((*env)->ExceptionCheck(env))
        return false; // already got an exception pending

    bool success = true;

    // VERSION is a nested class within android.os.Build (hence "$" rather than "/")
    jclass versionClass = (*env)->FindClass(env, "android/os/Build$VERSION");
    if (NULL == versionClass)
        success = false;

    jfieldID sdkIntFieldID = NULL;
    if (success)
        success = (NULL != (sdkIntFieldID = (*env)->GetStaticFieldID(env, versionClass, "SDK_INT", "I")));

    jint sdkInt = 0;
    if (success)
    {
        sdkInt = (*env)->GetStaticIntField(env, versionClass, sdkIntFieldID);
        __android_log_print(ANDROID_LOG_VERBOSE, TAG, "sdkInt = %d", sdkInt);
    }

    if (success && sdkInt < 8)
    {
        jclass systemClass = (*env)->FindClass(env, "java/lang/System");
        if (NULL == systemClass)
            success = false;

        jmethodID setPropertyMethodID = NULL;
        if (success)
            success = (NULL != (setPropertyMethodID = (*env)->GetStaticMethodID(env, systemClass, "setProperty", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")));

        jstring propString = NULL;
        if (success)
            success = (NULL != (propString = (*env)->NewStringUTF(env, "http.keepAlive")));

        jstring valueString = NULL;
        if (success)
            success = (NULL != (valueString = (*env)->NewStringUTF(env, "false")));

        jobject oldValueString = NULL;
        if (success)
        {
            __android_log_print(ANDROID_LOG_VERBOSE, TAG, "Disabling http.keepAlive");
             oldValueString = (*env)->CallStaticObjectMethod(env, systemClass, setPropertyMethodID, propString, valueString);
        }

        // cleanup
        (*env)->DeleteLocalRef(env, propString);
        (*env)->DeleteLocalRef(env, valueString);
        (*env)->DeleteLocalRef(env, oldValueString);
        (*env)->DeleteLocalRef(env, systemClass);
    }

    // cleanup
    (*env)->DeleteLocalRef(env, versionClass);

    return success;
}

このコードを書くために必要なすべての情報は、Sheng Liang による「The Java Native Interface: Programmer's Guide and Specification」というタイトルの PDF に明確に文書化されています)。JNI は非常に強力なテクノロジです。JNI を理解したい開発者は、その PDF と Android Developers のJNI Tipsを読むことを強くお勧めします。

最後に、ローカル参照とグローバル参照を理解することの重要性は強調してもしきれません。Android の開発者ブログには、ICS の変更点をカバーする優れた記事があります(JNI 仕様から逸脱するものは何もありませんが、繰り返し説明する良い点があります!)。

于 2012-05-09T07:47:34.143 に答える
4

完全にネイティブなソリューションが存在します:

  1. 事前からごAndroid L利用いただけます__system_property_get("ro.build.version.sdk")sys/system_properties.h
  2. Android Lおよび新しいものを使用できますpopen("getprop ro.build.version.sdk")

コンパイル時のツールチェーン定数チェックを使用して、#if __ANDROID_API__ < 21これら 2 つの実装を切り替えます。

于 2015-10-21T20:46:30.917 に答える
1

Javaで取得したAPIレベルをCコードに一度渡し、それをグローバル変数にストックできます。私にとっては、それを行うためのより簡単な方法です。

于 2012-04-18T16:41:04.900 に答える