Android Native crash日誌分析

来源:http://www.cnblogs.com/willhua/archive/2017/04/16/6718379.html
-Advertisement-
Play Games

在Android應用crash的類型中,native類型crash應該是比較難的一種了,因為大家接觸的少,然後相對也要多轉幾道工序,所有大部分對這個都比較生疏。雖然相關文章也有很多了,但是我在剛開始學的過程中還是遇到一些問題,下麵一一記錄,以便將來翻閱。 分析native crash 日誌需要幾個東 ...


  在Android應用crash的類型中,native類型crash應該是比較難的一種了,因為大家接觸的少,然後相對也要多轉幾道工序,所有大部分對這個都比較生疏。雖然相關文章也有很多了,但是我在剛開始學的過程中還是遇到一些問題,下麵一一記錄,以便將來翻閱。

  分析native crash 日誌需要幾個東西:

  1. addr2line,objdump,ndk-stack等幾個工具
  2. 帶symbols的so文件
  3. log  

  log

  native crash的日誌都是從一行星號(*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***)開始,這行星號也是ndk-stack工具用來查找native crash的標誌。一個native crash日誌例子:

 1 04-16 11:18:00.323 26512 26512 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
 2 04-16 11:18:00.324 26512 26512 F DEBUG   : Build fingerprint: 'nubia/NX531J/NX531J:7.1.1/NMF26F/nubia04130311:user/release-keys'
 3 04-16 11:18:00.324 26512 26512 F DEBUG   : Revision: '0'
 4 04-16 11:18:00.324 26512 26512 F DEBUG   : ABI: 'arm'
 5 04-16 11:18:00.324 26512 26512 F DEBUG   : pid: 26452, tid: 26491, name: Thread-4  >>> com.willhua.opencvstudy <<<
 6 04-16 11:18:00.324 26512 26512 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc8080000
 7 04-16 11:18:00.324 26512 26512 F DEBUG   :     r0 c807a400  r1 c7e80000  r2 00000069  r3 00000069
 8 04-16 11:18:00.324 26512 26512 F DEBUG   :     r4 caa4ca9c  r5 007e9000  r6 00000964  r7 c69838f8
 9 04-16 11:18:00.324 26512 26512 F DEBUG   :     r8 00005c00  r9 00017002  sl 001fa400  fp cac6ec00
10 04-16 11:18:00.324 26512 26512 F DEBUG   :     ip e71aac64  sp c69838e8  lr caa8e949  pc caa8e97c  cpsr 800f0030
11 04-16 11:18:00.326 26512 26512 F DEBUG   : 
12 04-16 11:18:00.326 26512 26512 F DEBUG   : backtrace:
13 04-16 11:18:00.326 26512 26512 F DEBUG   :     #00 pc 0004097c  /data/app/com.willhua.opencvstudy-1/lib/arm/libOpenCV.so (_Z14darkGrayThreadPv+179)
14 04-16 11:18:00.326 26512 26512 F DEBUG   :     #01 pc 000475d3  /system/lib/libc.so (_ZL15__pthread_startPv+22)
15 04-16 11:18:00.326 26512 26512 F DEBUG   :     #02 pc 00019d3d  /system/lib/libc.so (__start_thread+6)

 

  帶symbols的so文件

  對於比如手機公司的開發人員來說,一般來說出問題的so對應的帶symbols的so都在out/target/product/<model_name>/symbols/system/lib/下麵,而對於常見的使用AndroidStudio開發的單個應用來說,其對應的帶symbols的在<PROJECT_ROOT>\app\src\main\obj\local\<ABI>\下麵的so,而不能是\app\src\main\libs\<ABI>的,這裡面的是不包含symbols信息的,拿這個去分析,輸出的結果就是“??:?”。其實這兩個so的體積對比也是很明顯的的,在我的應用中,前一個帶symbols的so的體積為7M多,而後一個只有2M。

 

  分析工具

  •   addr2line:用來分析單個pc地址對應的源碼行數,比如示例log中的第13行中的#00 pc 0004097c,0004097c就是crash時pc調用的堆棧地址,用這個地址就可以分析出對應在源碼中的行數;
  •   objdump:用來把相應的so變成彙編語言的asm文件,然後根據地址信息(比如0004097c)就可以找到更加詳細的相關函數信息;
  •   ndk-stack:用來把log信息全部翻譯成更加詳細的帶源碼行數信息的log,相當於是在整個crash堆棧信息都執行addr2line命令。

  對於使用linux系統作為開發環境的,linux就自帶addr2line命令。而對於筆者這種使用Windows的,在sdk中安裝了NDK之後,在ndk中就帶有這些工具。

  比如addr2line工具在:sdk\ndk-bundle\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin下麵,同時這個bin下麵包含很多其他工具,比如objdump,readelf等;

  ndk-stack工具則在sdk\ndk-bundle下麵;

  關於這些工具的具體使用,在https://www.oschina.net/question/2241352_213433這篇文章中講的很詳細,我也就不再重覆。

  但是提醒一點:crash log與對應的so一定要對應起來。即錯誤的情況是:你拿了一份舊的log,然後你修改了so相關的源碼,然後編譯出來了新的so,你拿著這個新的so以及舊log中的地址去讓addr2line等分析,那肯定是是得不到正確的結果的。

 

 

 

  剛剛提到的那篇文章講的很詳細,為了避免以後找不到所以我就把它複製到這裡。

/****************************************************************************************************************************************/

轉自:https://www.oschina.net/question/2241352_213433

 

Android NDK是什麼,為什麼我們要用NDK?

Android NDK 是在SDK前面又加上了“原生”二字,即Native Development Kit,因此又被Google稱為“NDK”。眾所周知,Android程式運行在Dalvik虛擬機中,NDK允許用戶使用類似C / C++之類的原生代碼語言執行部分程式。NDK包括了:

  • 從C / C++生成原生代碼庫所需要的工具和build files。
  • 將一致的原生庫嵌入可以在Android設備上部署的應用程式包文件(application packages files,即.apk文件)中。
  • 支持所有未來Android平臺的一些列原生系統頭文件和庫

為何要用到NDK?概括來說主要分為以下幾種情況:

  • 代碼的保護,由於apk的java層代碼很容易被反編譯,而C/C++庫反匯難度較大。
  • 在NDK中調用第三方C/C++庫,因為大部分的開源庫都是用C/C++代碼編寫的。
  • 便於移植,用C/C++寫的庫可以方便在其他的嵌入式平臺上再次使用。

Android JNI是什麼?和NDK是什麼關係?

Java Native Interface(JNI)標準是java平臺的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI是本地編程介面,它使得在 Java 虛擬機(VM) 內部運行的 Java 代碼能夠與用其它編程語言(如 C、C++和彙編語言)編寫的應用程式和庫進行交互操作。

簡單來說,可以認為NDK就是能夠方便快捷開發.so文件的工具。JNI的過程比較複雜,生成.so需要大量操作,而NDK就是簡化了這個過程。

NDK的異常會不會導致程式Crash,NDK的常見的有哪些類型異常?

NDK編譯生成的.so文件作為程式的一部分,在運行發生異常時同樣會造成程式崩潰。不同於Java代碼異常造成的程式崩潰,在NDK的異常發生時,程式在Android設備上都會立即退出,即通常所說的閃退,而不會彈出“程式xxx無響應,是否立即關閉”之類的提示框。

NDK是使用C/C++來進行開發的,熟悉C/C++的程式員都知道,指針和記憶體管理是最重要也是最容易出問題的地方,稍有不慎就會遇到諸如記憶體無效訪問、無效對象、記憶體泄露、堆棧溢出等常見的問題,最後都是同一個結果:程式崩潰。例如我們常說的空指針錯誤,就是當一個記憶體指針被置為空(NULL)之後再次對其進行訪問;另外一個經常出現的錯誤是,在程式的某個位置釋放了某個記憶體空間,而後在程式的其他位置試圖訪問該記憶體地址,這就會產生一個無效地址錯誤。常見的錯誤類型如下:

  • 初始化錯誤
  • 訪問錯誤
    • 數組索引訪問越界
    • 指針對象訪問越界
    • 訪問空指針對象
    • 訪問無效指針對象
    • 迭代器訪問越界
  • 記憶體泄露
  • 參數錯誤
  • 堆棧溢出
  • 類型轉換錯誤
  • 數字除0錯誤

NDK錯誤發生時,我們能拿到什麼信息?

利用Android NDK開發本地應用的時候,幾乎所有的程式員都遇到過程式崩潰的問題,但它的崩潰會在logcat中列印一堆看起來類似天書的堆棧信息,讓人舉足無措。單靠添加一行行的列印信息來定位錯誤代碼做在的行數,無疑是一件令人崩潰的事情。在網上搜索“Android NDK崩潰”,可以搜索到很多文章來介紹如何通過Android提供的工具來查找和定位NDK的錯誤,但大都晦澀難懂。下麵以一個實際的例子來說明,首先生成一個錯誤,然後演示如何通過兩種不同的方法,來定位錯誤的函數名和代碼行。

首先,看我們在hello-jni程式的代碼中做了什麼(有關如何創建或導入工程,此處略),看下圖:在JNI_OnLoad()的函數中,即so載入時,調用willCrash()函數,而在willCrash()函數中, std::string的這種賦值方法會產生一個空指針錯誤。這樣,在hello-jni程式載入時就會閃退。我們記一下這兩個行數:在61行調用了willCrash()函數;在69行發生了崩潰。

下麵來看看發生崩潰(閃退)時系統列印的logcat日誌:

[plain]  view plain copy  
  1. *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***  
  2.  Build fingerprint: 'vivo/bbk89_cmcc_jb2/bbk89_cmcc_jb2:4.2.1/JOP40D/1372668680:user/test-keys'  
  3.  pid: 32607, tid: 32607, name: xample.hellojni  >>> com.example.hellojni <<<  
  4.  signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000  
  5.      r0 00000000  r1 beb123a8  r2 80808080  r3 00000000  
  6.      r4 5d635f68  r5 5cdc3198  r6 41efcb18  r7 5d62df44  
  7.      r8 4121b0c0  r9 00000001  sl 00000000  fp beb1238c  
  8.      ip 5d635f7c  sp beb12380  lr 5d62ddec  pc 400e7438  cpsr 60000010  
  9.    
  10.  backtrace:  
  11.      #00  pc 00023438  /system/lib/libc.so   
  12.      #01  pc 00004de8  /data/app-lib/com.example.hellojni-2/libhello-jni.so  
  13.      #02  pc 000056c8  /data/app-lib/com.example.hellojni-2/libhello-jni.so  
  14.      #03  pc 00004fb4  /data/app-lib/com.example.hellojni-2/libhello-jni.so  
  15.      #04  pc 00004f58  /data/app-lib/com.example.hellojni-2/libhello-jni.so  
  16.      #05  pc 000505b9  /system/lib/libdvm.so  
  17.      #06  pc 00068005  /system/lib/libdvm.so  
  18.      #07  pc 000278a0  /system/lib/libdvm.so  
  19.      #08  pc 0002b7fc  /system/lib/libdvm.so  
  20.      #09  pc 00060fe1  /system/lib/libdvm.so  
  21.      #10  pc 0006100b  /system/lib/libdvm.so  
  22.      #11  pc 0006c6eb  /system/lib/libdvm.so  
  23.      #12  pc 00067a1f  /system/lib/libdvm.so  
  24.      #13  pc 000278a0  /system/lib/libdvm.so  
  25.      #14  pc 0002b7fc  /system/lib/libdvm.so  
  26.      #15  pc 00061307  /system/lib/libdvm.so  
  27.      #16  pc 0006912d  /system/lib/libdvm.so  
  28.      #17  pc 000278a0  /system/lib/libdvm.so  
  29.      #18  pc 0002b7fc  /system/lib/libdvm.so  
  30.      #19  pc 00060fe1  /system/lib/libdvm.so  
  31.      #20  pc 00049ff9  /system/lib/libdvm.so  
  32.      #21  pc 0004d419  /system/lib/libandroid_runtime.so  
  33.      #22  pc 0004e1bd  /system/lib/libandroid_runtime.so  
  34.      #23  pc 00001d37  /system/bin/app_process  
  35.      #24  pc 0001bd98  /system/lib/libc.so  
  36.      #25  pc 00001904  /system/bin/app_process  
  37.    
  38.  stack:  
  39.           beb12340  012153f8    
  40.           beb12344  00054290    
  41.           beb12348  00000035    
  42.           beb1234c  beb123c0  [stack]  
  43.        
  44. ……  

 

如果你看過logcat列印的NDK錯誤時的日誌就會知道,我省略了後面很多的內容,很多人看到這麼多密密麻麻的日誌就已經頭暈腦脹了,即使是很多資深的Android開發者,在面對NDK日誌時也大都默默的選擇了無視。

 

“符號化”NDK錯誤信息的方法

其實,只要你細心的查看,再配合Google 提供的工具,完全可以快速的準確定位出錯的代碼位置,這個工作我們稱之為“符號化”。需要註意的是,如果要對NDK錯誤進行符號化的工作,需要保留編譯過程中產生的包含符號表的so文件,這些文件一般保存在$PROJECT_PATH/obj/local/目錄下。

第一種方法:ndk-stack

這個命令行工具包含在NDK工具的安裝目錄,和ndk-build和其他一些常用的NDK命令放在一起,比如在我的電腦上,其位置是/android-ndk-r9d/ndk-stack。根據Google官方文檔,NDK從r6版本開始提供ndk-stack命令,如果你用的之前的版本,建議還是儘快升級至最新的版本。使用ndk –stack命令也有兩種方式

使用ndk-stack實時分析日誌

在運行程式的同時,使用adb獲取logcat日誌,並通過管道符輸出給ndk-stack,同時需要指定包含符號表的so文件位置;如果你的程式包含了多種CPU架構,在這裡需求根據錯誤發生時的手機CPU類型,選擇不同的CPU架構目錄,如:

[plain]  view plain copy  
  1. adb shell logcat | ndk-stack -sym $PROJECT_PATH/obj/local/armeabi  

當崩潰發生時,會得到如下的信息:

[plain]  view plain copy  
  1. ********** Crash dump: **********  
  2. Build fingerprint: 'vivo/bbk89_cmcc_jb2/bbk89_cmcc_jb2:4.2.1/JOP40D/1372668680:user/test-keys'  
  3. pid: 32607, tid: 32607, name: xample.hellojni  >>> com.example.hellojni <<<  
  4. signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000000  
  5. Stack frame #00  pc 00023438  /system/lib/libc.so (strlen+72)  
  6. Stack frame #01  pc 00004de8  /data/app-lib/com.example.hellojni-2/libhello-jni.so (std::char_traits<char>::length(char const*)+20): Routine std::char_traits<char>::length(char const*) at /android-ndk-r9d/sources/cxx-stl/stlport/stlport/stl/char_traits.h:229  
  7. Stack frame #02  pc 000056c8  /data/app-lib/com.example.hellojni-2/libhello-jni.so (std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)+44): Routine basic_string at /android-ndk-r9d/sources/cxx-stl/stlport/stlport/stl/_string.c:639  
  8. Stack frame #03  pc 00004fb4  /data/app-lib/com.example.hellojni-2/libhello-jni.so (willCrash()+68): Routine willCrash() at /home/testin/hello-jni/jni/hello-jni.cpp:69  
  9. Stack frame #04  pc 00004f58  /data/app-lib/com.example.hellojni-2/libhello-jni.so (JNI_OnLoad+20): Routine JNI_OnLoad at /home/testin/hello-jni/jni/hello-jni.cpp:61  
  10. Stack frame #05  pc 000505b9  /system/lib/libdvm.so (dvmLoadNativeCode(char const*, Object*, char**)+516)  
  11. Stack frame #06  pc 00068005  /system/lib/libdvm.so  
  12. Stack frame #07  pc 000278a0  /system/lib/libdvm.so  
  13. Stack frame #08  pc 0002b7fc  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+180)  
  14. Stack frame #09  pc 00060fe1  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+272)  
  15. ……(後面略)  

我們重點看一下#03和#04,這兩行都是在我們自己生成的libhello-jni.so中的報錯信息,那麼會發現如下關鍵信息:

[plain]  view plain copy  
  1. #03 (willCrash()+68): Routine willCrash() at /home/testin/hello-jni/jni/hello-jni.cpp:69  
  2. #04 (JNI_OnLoad+20): Routine JNI_OnLoad at /home/testin/hello-jni/jni/hello-jni.cpp:61  

回想一下我們的代碼,在JNI_OnLoad()函數中(第61行),我們調用了willCrash()函數;在willCrash()函數中(第69行),我們製造了一個錯誤。這些信息都被準確無誤的提取了出來!是不是非常簡單?

先獲取日誌,再使用ndk-stack分析

這種方法其實和上面的方法沒有什麼大的區別,僅僅是logcat日誌獲取的方式不同。可以在程式運行的過程中將logcat日誌保存到一個文件,甚至可以在崩潰發生時,快速的將logcat日誌保存起來,然後再進行分析,比上面的方法稍微靈活一點,而且日誌可以留待以後繼續分析。

[plain]  view plain copy  
  1. adb shell logcat > 1.log  
  2. ndk-stack -sym $PROJECT_PATH/obj/local/armeabi –dump 1.log  

第二種方法:使用addr2line和objdump命令

這個方法適用於那些,不滿足於上述ndk-stack的簡單用法,而喜歡刨根問底的程式員們,這兩個方法可以揭示ndk-stack命令的工作原理是什麼,儘管用起來稍微麻煩一點,但是可以滿足一下程式員的好奇心。

先簡單說一下這兩個命令,在絕大部分的linux發行版本中都能找到他們,如果你的操作系統是linux,而你測試手機使用的是Intel x86系列,那麼你使用系統中自帶的命令就可以了。然而,如果僅僅是這樣,那麼絕大多數人要絕望了,因為恰恰大部分開發者使用的是Windows,而手機很有可能是armeabi系列。

別急,在NDK中自帶了適用於各個操作系統和CPU架構的工具鏈,其中就包含了這兩個命令,只不過名字稍有變化,你可以在NDK目錄的toolchains目錄下找到他們。以我的Mac電腦為例,如果我要找的是適用於armeabi架構的工具,那麼他們分別為arm-linux-androideabi-addr2line和arm-linux-androideabi-objdump;位置在下麵目錄中,後續介紹中將省略此位置:

[plain]  view plain copy  
  1. /Developer/android_sdk/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/  

假設你的電腦是windows, CPU架構為mips,那麼你要的工具可能包含在這個目錄中:

[plain]  view plain copy  
  1. D:\ android-ndk-r9d\toolchains\mipsel-linux-android-4.8\prebuilt\windows-x86_64\bin\  

 

好了言歸正傳,如何使用這兩個工具,下麵具體介紹:

1. 找到日誌中的關鍵函數指針

其實很簡單,就是找到backtrace信息中,屬於我們自己的so文件報錯的行。

首先要找到backtrace信息,有的手機會明確列印一行backtrace(比如我們這次使用的手機),那麼這一行下麵的一系列以“#兩位數字 pc”開頭的行就是backtrace信息了。有時可能有的手機並不會列印一行backtrace,那麼只要找到一段以“#兩位數字 pc ”開頭的行,就可以了。

其次要找到屬於自己的so文件報錯的行,這就比較簡單了。找到這些行之後,記下這些行中的函數地址

2. 使用addr2line查找代碼位置

執行如下的命令,多個指針地址可以在一個命令中帶入,以空格隔開即可

[plain]  view plain copy  
  1. arm-linux-androideabi-addr2line –e obj/local/armeabi/libhello-jni.so 00004de8 000056c8 00004fb4 00004f58  

結果如下 [plain]  view plain copy  
  1. /android-ndk-r9d/sources/cxx-stl/stlport/stlport/stl/char_traits.h:229  
  2. /android-ndk-r9d/sources/cxx-stl/stlport/stlport/stl/_string.c:639  
  3. /WordSpaces/hello-jni/jni/hello-jni.cpp:69  
  4. /WordSpaces hello-jni/jni/hello-jni.cpp:6  

從addr2line的結果就能看到,我們拿到了我們自己的錯誤代碼的調用關係和行數,在hello-jni.cpp的69行和61行(另外兩行因為使用的是標準函數,可以忽略掉),結果和ndk-stack是一致的,說明ndk-stack也是通過addr2line來獲取代碼位置的。

3. 使用objdump獲取函數信息

通過addr2line命令,其實我們已經找到了我們代碼中出錯的位置,已經可以幫助程式員定位問題所在了。但是,這個方法只能獲取代碼行數,並沒有顯示函數信息,顯得不那麼“完美”,對於追求極致的程式員來說,這當然是不夠的。下麵我們就演示怎麼來定位函數信息。

 

使用如下命令導出函數表:

[plain]  view plain copy  
  1. arm-linux-androideabi-objdump –S obj/local/armeabi/libhello-jni.so > hello.asm  

 

在生成的asm文件中查找剛剛我們定位的兩個關鍵指針00004fb4和00004f58

 

 

從這兩張圖可以清楚的看到(要註意的是,在不同的NDK版本和不同的操作系統中,asm文件的格式不是完全相同,但都大同小異,請大家仔細比對),這兩個指針分別屬於willCrash()和JNI_OnLoad()函數,再結合剛纔addr2line的結果,那麼這兩個地址分別對應的信息就是:

[plain]  view plain copy  
  1. 00004fb4: willCrash() /WordSpaces/hello-jni/jni/hello-jni.cpp:69  
  2. 00004f58: JNI_OnLoad()/WordSpaces/hello-jni/jni/hello-jni.cpp:61  

 

相當完美,和ndk-stack得到的信息完全一致!

 

使用Testin崩潰分析服務定位NDK錯誤

以上提到的方法,只適合在開發測試期間,如果你的應用或者游戲已經發佈上線,而用戶經常反饋說崩潰、閃退,指望用戶幫你收集信息定位問題,幾乎是不可能的。這個時候,我們就需要用其他的手段來捕獲崩潰信息。

目前業界已經有一些公司推出了崩潰信息收集的服務,通過嵌入SDK,在程式發生崩潰時收集堆棧信息,發送到雲服務平臺,從而幫助開發者定位錯誤信息。在這方面,處於領先地位的是國內的Testin和國外的crittercism,其中crittercism需要付費,而且沒有專門的中國開發者支持,我們更推薦Testin,其崩潰分析服務是完全免費的。

Testin從1.4版本開始支持NDK的崩潰分析,其最新版本已經升級到1.7。當程式發生NDK錯誤時,其內嵌的SDK會收集程式在用戶手機上發生崩潰時的堆棧信息(主要就是上面我們通過logcat日誌獲取到的函數指針)、設備信息、線程信息等等,SDK將這些信息上報至Testin雲服務平臺,只要登陸到Testin平臺,就可以看到所有用戶上報的崩潰信息,包括NDK;並且這些崩潰做過歸一化的處理,在不同系統和ROM的版本上列印的信息會略有不同,但是在Testin的網站上這些都做了很好的處理,避免了我們一些重覆勞動。

 

 

上圖的紅框部分,就是從用戶手機上報的,我們自己的so中報錯的函數指針地址堆棧信息,就和我們開發時從logcat讀到的日誌一樣,是一些晦澀難懂的指針地址,Testin為NDK崩潰提供了符號化的功能,只要將我們編譯過程中產生的包含符號表的so文件上傳(上文我們提到過的obj/local/目錄下的適用於各個CPU架構的so),就可以自動將函數指針地址定位到函數名稱和代碼行數。符號化之後,看起來就和我們前面在本地測試的結果是一樣的了,一目瞭然。

而且使用這個功能還有一個好處:這些包含符號表的so文件,在每次我們自己編譯之後都會改變,很有可能我們剛剛發佈一個新版本,這些目錄下的so就已經變了,因為開發者會程式的修改程式;在這樣的情況下,即使我們拿到了崩潰時的堆棧信息,那也無法再進行符號化了。所以我們在編譯打包完成後記得備份我們的so文件。這時我們可以將這些文件上傳到Testin進行符號化的工作,Testin會為我們保存和管理不同版本的so文件,確保信息不會丟失。來看一下符號化之後的顯示:

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 雪花飄落的效果實現步驟:1.使用setInterval定時器每800毫秒創建一個雪花;2.把每一個雪花作為參數傳進動態下落的方法中即可。 js實現代碼: 效果圖如下: 這樣雪花飄落的效果就做好了。有什麼不足的地方請指正! ...
  • 在上一篇文章《iOS之ProtocolBuffer搭建和示例demo》分享環境的搭建, 我們和伺服器進行IM通訊用了github有名的框架CocoaAsynSocket, 然後和伺服器之間的數據媒介是ProtoBuf。然後後面在開發的過程中也碰到了拆包和粘包問題,這方面網上資料很少,曲折了一下才解決 ...
  • Android保持屏幕常亮,PowerManager.WakeLock的使用 需要在AndroidManifest.xml中添加許可權<uses-permission android:name="android.permission.WAKE_LOCK"/> SCREEN_BRIGHT_WAKE_LO ...
  • 在使用一些產品列如微信、QQ之類的,如果有新消息來時,手機屏幕即使在鎖屏狀態下也會亮起並提示聲音,這時用戶就知道有新消息來臨了。但是,一般情況下手機鎖屏後,Android系統為了省電以及減少CPU消耗,在一段時間後會使系統進入休眠狀態,這時,Android系統中CPU會保持在一個相對較低的功耗狀態。 ...
  • 第一步: 為mac電腦配置 adb 命令的環境變數,分為2小步 1.找到 Android Studio 為你安裝的 SDK : 打開電腦中 Android studio 的工具的軟體,在啟動 Android studio 的軟體的界面中,點擊下方列表中的”configure“的選項。在點擊列表中的“ ...
  • 轉載請註明出處:http://www.cnblogs.com/cnwutianhao/p/6719380.html 作為Android開發者,一定不會對 GreenDao 和 ReactiveX 陌生。 GreenDao 號稱Android最快的關係型資料庫 ReactiveX Rx是一個編程模型, ...
  • 在使用pthread進行NDK中的多線程開發時,自己寫了一個BUG, 這個是啟動函數,即相當於Java中的Thread的run方法。初一看沒啥問題,編譯也能過,APP也能跑,但是每次都會crash。我把crash線程的log貼出來如下: 從log中看出,是記憶體訪問錯誤,然後使用addr2line工具 ...
  • 作者:Antonio Leiva 時間:Apr 11, 2017 原文鏈接:https://antonioleiva.com/dagger-android-kotlin/ 在Android上,創建去耦以及容易測試代碼的幾乎每位遲早都要訴諸Dagger。 雖然,在Kotlin中設置Dagger有一些不 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...