我开始使用NDK与Android一起工作,我想检查设备在我的c代码上运行的Android API级别。我怎样才能做到这一点?如何使用c代码通过NDK检查运行API级别的设备?
起初我以为我可以使用/android/api-level.h下的定义__ANDROID_API__
,但这是一个错误的假设。
**注意:我不问如何通过java检查API级别。
我开始使用NDK与Android一起工作,我想检查设备在我的c代码上运行的Android API级别。我怎样才能做到这一点?如何使用c代码通过NDK检查运行API级别的设备?
起初我以为我可以使用/android/api-level.h下的定义__ANDROID_API__
,但这是一个错误的假设。
**注意:我不问如何通过java检查API级别。
我刚刚工作的一些JNI代码,并希望通过乔纳描述查询运行OS Build版本。我想尽早做到这一点(例如,在JNI_OnLoad),所以不要把它交给Java,如FUBUs所述。由于API级别4此信息已可与int场SDK_INT在android.os.Build.VERSION这就是我在这个片段中查找:
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提供的标题为“Java本地接口:程序员指南和规范”的PDF,以前可从Oracle的站点here获得,但也可作为书籍(例如here)购买。 JNI是一项非常强大的技术,我强烈建议任何希望掌握它的开发人员阅读PDF以及Android Developers的JNI Tips。
哦,最后,不能强调它是多么重要的是了解本地和全球的参考。 Android的开发人员博客有一篇很好的文章here,涵盖了ICS的变化(没有偏离JNI规范,但重申的重点!)。
您可以将JAVA中获得的API级别一次性传递给C代码并将其存储在全局变量中。对我而言,更简单的方法就是做到这一点。
有存在完全原生解决方案:
Android L
可以使用__system_property_get("ro.build.version.sdk")
从sys/system_properties.h
Android L
和更新,您可以使用popen("getprop ro.build.version.sdk")
使用编译时工具链持续检查#if __ANDROID_API__ < 21
在这两种实现之间切换。
您的代码是通过JNI接口运行还是直接在底层os层上作为可执行文件运行? – Samveen 2012-04-27 10:47:27
通过JNI接口。 – Jona 2012-04-28 03:37:42
然后FABUs的答案会完美解决。你只需要在c代码中定义一个函数,让'setVersion'将版本存储到一个静态变量中,其余的C代码就可以访问这个变量。 setVersion函数可以作为初始化的一部分被调用。有关在Java中获取Android API版本的信息,请参阅http://stackoverflow.com/questions/3423754/retrieving-android-api-version-programmatically。 – Samveen 2012-04-28 06:54:15