安卓工程接第三方SDK遇到回調函數字元串參數亂碼的問題
在做《老王麻将》的時候,安卓工程接第三方語音SDK,出現了一個字元串亂碼問題,現在總結一下。
- 出現的問題:
- 在對方發送語音的時候,SDK會通過一個接口提醒用戶端有語音要去下載下傳,這個時候用戶端會傳一個存語音的位址給SDK然後開始下載下傳。下載下傳成功之後呢,SDK會回調一個函數,把一些語音檔案的具體資訊還有之前用戶端傳入的位址一起回調回來。但是,收到的回調裡面,路徑字元串是亂碼。
SDK接口如下:
//下載下傳語音
virtual YIMErrorcode DownloadFile(XUINT64 messageID, const XCHAR* savePath) = 0;
//下載下傳語音回調
void OnDownload(YIMErrorcode errorcode, std::shared_ptr message, const XString& savePath)override;
排除了編碼方式,代碼邏輯等問題,對方的技術小哥哥指出,問題在于安卓工程中application.mk的APP_STL配置。
下圖是我們安卓項目的application.mk:

技術小哥哥說:“cocos 預設是gnustl_static,gnustl_static 是gcc編譯器 ,c++_static 是llvm” 。
╭(°A°`)╮大寫的懵逼!哈哈哈哈哈哈哈哈哈哈哈~好吧,get到新知識,就好好學習一下。
(づ ̄3 ̄)づ (づ ̄3 ̄)づ (づ ̄3 ̄)づ
首先是Application.mk:
Application.mk是用來描述你的應用程式需要哪些子產品,以及這些子產品所要具有的一些特性。
而相對的Android.mk是用來描述要編譯某個具體的子產品,所需要的一些資源,包括要編譯的源碼、要連結的庫等等。
Application.mk所要描述的内容主要包括:
- 你程式正常運作,所需要到子產品的具體清單;
- 程式要編譯成什麼機器指令集的;
- 所有子產品要被編譯成Release版本還是Debug版本的;
- 傳遞給C或者C++編譯器的編譯參數。
當然,Application.mk檔案其實是可選的。預設情況下,如果ndk-build指令找不到Application.mk檔案的話,就會使用如下規則進行編譯:
- 會編譯全部在Android.mk檔案中列出的子產品;
- 對于所有子產品,NDK編譯系統會根據“armeabi” ABI來生成機器代碼,即指令集是ARMv5TE。
具體來說,Application.mk檔案中,可以包含對下面幾個變量的定義:
- APP_PROJECT_PATH
- APP_MODULES
- APP_OPTIM
- APP_CFLAGS
- APP_CPPFLAGS
- APP_BUILD_SCRIPT
- APP_ABI
- APP_STL
- APP_GNUSTL_FORCE_CPP_FEATURES
那麼再來說說這個APP_STL是神馬東東:
預設情況下,Android 平台提供很小的 C++ 運作時支援庫 (libstdc++)。這種很小的支援不包含如下支援:
- 标準 C++ 庫支援(幾個無關緊要的标頭除外)。
- C++ 異常支援
- RTTI 支援
然而,NDK還帶有其它一些可選的C++運作庫的實作,你可以選擇在你自己的應用程式中,通過在Application.mk中定義APP_STL變量,來使用或連結其中某一個。
上面這個表是在官網上找到的,但是在百度搜到的資料裡面,普遍說的是下面這個規則:
對此我表示很疑惑,不知道是不是官方有修改。(對于上面有出入的地方,cocos項目沒有用到,也沒有進一步實際驗證。)
(๑• . •๑)好哒,看到這裡,知道這個配置項是用來幹嘛的了,但是心裡還是有很多疑惑的地方,繼續學習~
神馬是GNU:
簡單的說就是個作業系統。
按照技術小哥哥的說法,選擇gnustl的時候,使用的是GCC編譯器。
而選擇c++static的時候,使用的是LLVM編譯器。是以說兩種連結庫的編譯器是不一樣的。
根據官網上面的解釋:
GNU STL 運作時:
運作的是 GNU 标準 C++ 庫 (libstdc++)。其共享庫檔案名為 libgnustl_shared.so。
libc++ 運作時:
運作的是 LLVM libc++ 的 Android 端口。其共享庫檔案名為 libc++_shared.so。
那麼現在,問題又來了,libstdc++和libc++是什麼,差別是什麼。
從libc說起。libc是Linux下原來的标準C庫,也就是當初寫hello world時包含的頭檔案#include < stdio.h> 定義的地方。
寫C++的時候,還有兩個重要的庫,libc++/libstdc++。
libc++ 為 LLVM 項目重新編寫,包含 C++ 11 标準庫。
libstdc++ 是 GNU 項目的标準庫。
知識學習到這裡,大概也能get到為什麼我在回調函數裡面拿到的字元串是亂碼了。
在下載下傳函數裡面,我傳入的是char,但是在回調的時候傳出來的卻是string。
我的安卓工程使用的是libc++的庫和LLVM的編譯器,但是他們SDK卻使用的是libstdc++的庫和GCC的編譯器。這樣一來, string的實作方式不一樣,我的用戶端和他們的SDK讀寫同一記憶體,最後拿到的string值就不一樣了。
p.s. 在接SDK的時候,一遇到這個問題我就聯系了群裡的技術人員,但是列印了各種參數值,猜想了各種可能出現的問題,甚至最後對方技術遠端了我的電腦看了我的代碼也找不到原因,還說是我c++代碼邏輯的問題ヾ(༎ຶД༎ຶ)ノ” 然後,我找了公司的幾個大牛看了這個問題,也都沒找到原因。最後對方換了個技術小哥哥,問了幾句之後,就讓我截圖Application.mk。這個真的是,不懂這一塊的人再怎麼看也看不出問題吧。遇到這種坑,也算是一個經驗的積累。最後,對于我一個換UI的懶程式,這次為神馬會有動力學習,那肯定是為了以後跟帥氣的技術小哥哥溝通的時候不懵逼啊!٩(ˊvˋ*)و