編輯:關於Android編程
在上一篇教程中,主要介紹了如何把OSG源代碼編譯成為能夠在Android項目下使用的函數庫。在這一篇教程中,我將針對如何在自己的Android項目中配置OSG函數庫進行詳細講解。
現階段網上關於OSGfor Android的配置方式教程有很多,但是大部分在實際使用起來都會或多或少的出現一些問題,無法完全照搬,需要一定的修改。而且,對於配置中的那些變量的具體含義,也很少有人能夠進行仔細的講解。這非常不利於新手的學習和理解,往往會造成出現bug後面對滿屏幕的錯誤log完全一臉茫然的情況。
所以我將在這篇教程中詳細介紹系統的介紹如何在Android項目中配置OSG函數庫,並對各個配置變量的含義進行詳細講解。
-------------------------------------------------------------------------------------------------
在一個項目中配置函數庫,是我們在進行項目開發時幾乎都要做的第一件事情。可以說,各種第三方函數庫幫助我們完成了很多通用的常用的功能,使我們從繁雜的基本算法、基本功能中脫離出來,能夠更專心的完成我們需要實現的業務功能。OSG就是一個非常好的開源三維引擎,提供了一套成熟的API用於實現三維場景功能的開發。
一、工具准備
OSG是基於C++平台的API,在開發時使用的都是標准的C++。眾所周知,開發Android項目,我們平常使用的都是Java,那麼,如何才能在Java語言中調用OSG的這些C++函數呢?Java中提供了Java本地接口,即JNI(Java Native Interface)。JNI是一個協議,用於溝通Java代碼和本地的C/C++代碼。而Google公司為Android開發了一套用於快速創建native工程的工具集合,即NDK(Native Development Kit)。在本文中,將使用Eclipese+NDK的方式進行配置開發。網上有許多的經驗教程用到了Cygwin。但是,從NDK的r7版本以上就包含了Cygwin,所以本文在配置項目時,並沒有單獨使用Cygwin。
這裡使用的NDK版本是r10d,可以在官方網站上下載,鏈接為:
http://developer.android.com/tools/sdk/ndk/index.html。
當然,由於一些原因,現在很多情況下是連接不上這個網站的,比如我就是。不過現在很多網盤上有共享的可以下載,大家可以自行搜一下。OSG函數庫可以根據我前一篇教程裡講的那樣自己進行編譯,不過時間花費比較大,當然也可以從網上下載別人已經編譯好的OSG函數庫,這樣省時省力。這裡我使用的是3.0.1版本的OSG。需要注意的是,上一篇教程講過,在編譯時根據參數不同,會有兩個版本的OSG庫,分別是GLES1和GLES2,這兩個版本在使用時,配置的參數會有所不同,甚至會對新手來說產生一些莫名其妙的錯誤。具體的區別,我會詳細的說明一下。
二、具體配置
首先,為了在項目中使用C/C++,在項目結構上會有一點不同,需要增加一個jni文件夾,其位置在項目的根目錄下,與src等文件夾在同一層。這個文件夾用於存放所有的C/C++文件,以及項目配置文件(.mk後綴)。下面進行詳細講解。
1. 配置文件
在OSG for Android項目中,配置文件有兩個,一個是Android.mk,另一個是Application.mk。這兩個文件都是存放在jni文件夾內的,用於在編譯項目時提供配置信息。
首先,我們來看Android.mk文件的配置方式。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := osgNativeLib #OSG_ANDROID_DIR := D:/MyTools/osggles2_3_0_1 OSG_ANDROID_DIR := D:/MyTools/osggles1_3_0_1 LIBDIR := $(OSG_ANDROID_DIR)/obj/local/armeabi ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) LOCAL_ARM_NEON := true LIBDIR := $(OSG_ANDROID_DIR)/obj/local/armeabi-v7a endif ### Add all source file names to be included in lib separated by a whitespace LOCAL_C_INCLUDES:= $(OSG_ANDROID_DIR)/include LOCAL_CFLAGS := -fno-short-enums LOCAL_CPPFLAGS := -DOSG_LIBRARY_STATIC LOCAL_LDLIBS := -L $(SYSROOT)/usr/lib -llog #LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lGLESv2 LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lGLESv1_CM LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -lz LOCAL_LDLIBS += -L $(SYSROOT)/usr/lib -gnustl_static LOCAL_LDLIBS += -landroid LOCAL_SRC_FILES :=osgMain.cpp osgNativeLib.cpp modelUtil.cpp AnimationUtil.cpp ExternVariables.cpp LOCAL_LDFLAGS := -L $(LIBDIR) -losgdb_dds\ -losgdb_openflight\ -losgdb_tga\ -losgdb_rgb\ -losgdb_osgterrain\ -losgdb_osg\ -losgdb_ive\ -losgdb_deprecated_osgviewer\ -losgdb_deprecated_osgvolume\ -losgdb_deprecated_osgtext\ -losgdb_deprecated_osgterrain\ -losgdb_deprecated_osgsim\ -losgdb_deprecated_osgshadow\ -losgdb_deprecated_osgparticle\ -losgdb_deprecated_osgfx\ -losgdb_deprecated_osganimation\ -losgdb_deprecated_osg\ -losgdb_serializers_osgvolume\ -losgdb_serializers_osgtext\ -losgdb_serializers_osgterrain\ -losgdb_serializers_osgsim\ -losgdb_serializers_osgshadow\ -losgdb_serializers_osgparticle\ -losgdb_serializers_osgmanipulator\ -losgdb_serializers_osgfx\ -losgdb_serializers_osganimation\ -losgdb_serializers_osg\ -losgViewer\ -losgVolume\ -losgTerrain\ -losgText\ -losgShadow\ -losgSim\ -losgParticle\ -losgManipulator\ -losgGA\ -losgFX\ -losgDB\ -losgAnimation\ -losgUtil\ -losg\ -lOpenThreads\ -lgnustl_static\ -lgdal include $(BUILD_SHARED_LIBRARY) #include $(BUILD_STATIC_LIBRARY)
LOCAL_PATH:這個變量用於在項目結構樹中查找源文件。在這個例子中,對其配置為$(call my-dir),這是一個宏函數,由編譯系統提供,表示返回當前路徑,也就是包含了這個Android.mk文件的路徑;
include $(CLEAR_VARS):這句配置的意思是清空之前的除了LOCAL_PATH以外的所有LOCAL_XXX的變量配置。可以看出,我們所需要配置的變量都必須在這條配置語句之後進行,不然即使配置了,也會被這句給清空掉;
LOCAL_MODULE:這個變量表示的是該配置文件描述的模塊的名稱,這個名稱是唯一的。而且這個配置變量必須配置。在編譯過程中,編譯系統根據這個變量自動生成庫動態庫的名稱,一般情況下,生成的動態庫會以libxxx.so為名,其中的xxx就是LOCAL_MODULE變量配置時的名稱;
OSG_ANDROID_DIR:這個配置變量表示的是OSG的所在位置,即經過編譯的OSG的位置。在這個例子中,我寫了兩個路徑,其中一個是被#注釋掉的。之前也我提到過,OSG for Android在編譯時根據參數不同,會產生兩個版本,分別是GLES1和GLES2,這兩個版本的OSG在配置時是不同的,這裡就是不同點之一;
LIBDIR:這個配置變量是指向OSG函數庫的位置,根據OSG_ANDROID_DIR所指向的OSG位置,向下尋找靜態庫的位置。其實,如果我們打開這個文件夾,我們可以發現一系列後綴為.a的文件,這些文件就是OSG的靜態庫。接下來的四行代碼,則是用於判斷目標ABI(即應用程序二進制接口),根據判斷結果重新配置靜態庫位置;
LOCAL_C_INCLUDES:這個變量指向相應版本OSG的include文件夾,用於指定OSG頭文件位置;
LOCAL_CFLAGS:這個變量是一個可選設置的變量,用於附加編譯選項。在編寫配置文件時,可以照搬此處的設置,無需修改;
LOCAL_CPPFLAGS:與上一個變量類似,區別是這個變量用於對cpp文件編譯進行設置,從字面意思就可以看出,同上,可照搬。
LOCAL_LDLIBS:用於添加系統。注意!在配置這個變量時,其中存在對GLES1和GLES2兩個版本配置的不同,這是第二個不同的地方。尤其需要注意的是,在選擇使用GLES1版本的OSG時,該變量配置的是-lGLESv1_CM,而不是想當然的-lGLESv1!新手在剛接觸時,很容易犯這個錯,而且很難察覺到。其余照搬即可。
LOCAL_SRC_FILES:在這裡列出需要編譯進動態庫的c和cpp文件。只要用到的c或cpp文件都要加進來,編譯系統會根據這個變量的值來尋找文件,如果不加進來,編譯系統就找不到相應的文件,就會造成編譯錯誤。
LOCAL_LDFLAGS:這個配置變量與LOCAL_LDLIBS變量功能類似,也是用於添加系統庫的功能。
include $(BUILD_SHARED_LIBRARY):這句代碼的意思是將該模塊定義為動態庫,即.so文件。該例子中最後還有一句被#注釋掉的include $(BUILD_STATIC_LIBRARY),這是指定該模塊生成靜態庫,即.a文件。
下面我們再來看一下另一個配置文件,即Application.mk文件的配置方法。
APP_BUILD_SCRIPT := $(call my-dir)/Android.mk APP_OPTIM := release APP_PLATFORM := android-10 APP_STL := gnustl_static APP_CPPFLAGS := -fexceptions -frtti APP_ABI := armeabi armeabi-v7a APP_MODULES := osgNativeLib
下面對各個變量進行詳細講解。
APP_BUILD_SCRIPT:這個變量將在當前路徑下尋找Android.mk,也就是之前我們進行配置的mk文件;
APP_OPTIM:這是個可選變量,其值可以設置為release或者debug。當設置為release時,將會生成高度優化的二進制代碼,而設置為debug時,生成的是未優化的二進制代碼,但可以檢測出很多的BUG,可以用於調試;
APP_PLATFORM:這個變量用於設置該項目的最小運行平台,需要注意的是,網上有很多教程,在這裡設置的是android-8,但是根據我的測試,如果設置為android-8,會出現一些找不到文件的錯誤,但是設置為android-10以上,則可以正常編譯;
APP_STL:這個變量設置為gnustl_static,表示使用GNU libstlc++作為靜態庫;
APP_CPPFLAGS:這個變量用於設置一個c++編譯器開關集合,在編譯任意模塊的任意C或C++源代碼時傳遞。它可以用於改變一個給定的應用程序需要依賴的模塊的構建,而不是修改它自身的Android.mk文件;
APP_ABI:用於設置二進制程序接口,默認情況下為armeabi,本文中的例子同時設置了armeabi和armeabi-v7a。注意!網上有的例子裡面在這裡同時設置了x86,根據我的測試,加上x86後會產生NDK的Abortting stop的錯誤,所以,不要添加-x86;
APP_MODULES:這個變量列出編譯所需要的模塊名稱。模塊名稱就是我們之前在Android.mk文件中設置的LOCAL_MODULE的值。
2. NDK Builder的配置
在eclipse左邊的project view裡右擊需要設置的項目,並選擇Properties,如圖所示:進入後在界面左側選擇Builder,然後點擊界面郵編的New按鈕,如圖所示:
在Choose configuration type的界面中選擇Program,點擊OK。如圖所示:
在出現的設置界面中,在Main選項卡內,Location設置為所用的NDK的安裝目錄下的nkd-build.cmd;Working directory設置為當前工程。在Refresh選項卡內,勾選上Refresh resources upon completion。在Build Options選項卡中,勾選Specify working set of relevent resouces,同時點擊Specify Resouces按鈕,選擇當前工程的jni文件夾。
3. Java中的配置
在Java中的配置比較簡單,但是也是容易遺忘的地方。因為在Android上顯示OSG窗口是基於GLSurfaceView的,那麼在創建GLSurfaceView時需要注意的是,應該根據自己使用的OSG版本對GLSurfaceView的GL版本。這個配置只需要一句代碼:
myGLSurfaceView.setEGLContextClientVersion(1);因為我的例子中使用的是GLES1版本的OSG庫,所以這裡的值設置為1;同理,如果使用的是GLES2版本的OSG庫,則將其設置為2。這裡是比較容易遺忘的地方。
三、總結
據我了解,很多剛接觸OSG for Android的新手老手,在配置項目時都會遇到這樣或那樣的問題,我在剛接觸時同樣是這樣。出問題的大部分都是對這個配置的內容不是很了解其中的意思,所以會在出了問題後不知道該怎麼辦。我總結了一下容易出錯的地方。
1. 亂加或亂減空格
在mk文件中,對空格似乎十分的敏感。我們很多人有意無意的會習慣性打空格,特別是在一行代碼的末尾處,很容易多一個空格。但是這種情況在mk文件中都有可能引起錯誤。我在剛接觸時,就試過逐行逐行地查看空格是否有多余或遺漏;
2. 在使用GLES1版本的庫時,-lGLESv1_CM的錯誤
也許在看到一些使用GLES2版本的例子上寫著-lGLES2時,會想當然的認為,使用GLES1版本就直接設置為-lGLES1就行了。結果編譯時就會發現出錯了。而且錯誤並沒有直接指向這裡,而是會出現一些找不到OSG頭文件的錯誤,會讓人很摸不著頭腦。其實這種錯誤很大可能就是出現在了這裡。
3. -x86的錯誤
我也看到過一些教程上面提到過,NDK在對x86的兼容上有一些問題,但是仍然有不少示例會加上-x86。這裡我的建議是不要在Application.mk文件的APP_ABI後面添加-x86。
---------------------------------------------------------
OSG for Android新手教程的下一篇將對一個HelloWorld的示例進行詳細講解,通過一個簡單的示例分析怎樣運行起一個最簡單的OSG for Android的程序。敬請關注。
SharedPreference:1.是一種輕型的數據存貯方式2.本質是基於xml文件存貯key_value鍵值對數據3.通常用來存貯一些簡單的配置信息(密碼,窗口狀態,
前面講到Vitamio可以支持一些流媒體,在這裡就用Vitamio來播放網絡上的一些流媒體,如:mms、rtsp、http,參考前輩的一些文章來寫一個網絡收音機程序,對於
Activity是什麼?我們都知道android中有四大組件(Activity 活動,Service 服務,Content Provider 內容提供者,Broadcas
復習一下view滑動的幾種實現方式1.通過layout實現通過不斷重新layout view 達到滑動的效果。 @Override public boolea