我開始使用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