1. 程式人生 > >ReactNative 錯誤收集 (Bugly)

ReactNative 錯誤收集 (Bugly)

一、概述

      APP的錯誤收集產品有很多,例如友盟統計、阿里雲等。本文討論的是由騰訊開發的Bugly。在使用的時候在網上找了一下,發現有一個外掛(https://github.com/canyara/react-native-bugly)。至於這個外掛的使用,我估計我的道行不夠吧,總之搞不通。然後在直接按照官方的文件配置的,可以統計了。

    本文分三部分:第一部分是講解原理、第二部分是原理講解、第三部分是配置並演示。

二、原理講解

2.1 ReactNative 的編譯模式

     在 ReactNative 的程式中,實際上執行的是 Js 的程式碼,而它也是分 Debug 和 Release 的。

    在 Debug 模式下,會從本地開啟一個 Packager 服務,然後 App 執行起來之後,直接從服務里拉取最新的編譯後的 JS 程式碼,這樣可以在開發階段,做到程式碼實時更新的效果,只需要在裝置上,重新 Load 一下即可。  

     在 Release 模式下,ReactNative 會將 JS 程式碼,整體打包,然後放到 assets 目錄下,然後從這裡去載入 JS 程式碼。

    這樣的邏輯被封裝在 ReactInstanceManager 類的 recreateReactContextInBackgroundInner() 方法中,有興趣可以自行看看。

    ReactNative 在 Debug 的情況下,如果出現崩潰的 Bug,會直接出現紅屏,提示你崩潰的棧的具體資訊,這些內容可以幫助你快速的定位問題。如果在Release模式下,則出現閃退(或者ANR)。

2.2 Release 版本說明:

     Android 舉例:

         Android打包時會把,所有的JS檔案,混淆並且壓縮到asstes資料夾下的index.android.bundle中。圖:2.2-1

    該檔案生成的原理是ReactNative使用瞭如下命令處理(node/modules/react.gradle 程式碼片段)

      if (Os.isFamily(Os.FAMILY_WINDOWS)) {
             commandLine("cmd", "/c", *nodeExecutableAndArgs, cliPath, bundleCommand, "--platform", "android", "--dev", "${devEnabled}",
            "--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir, *extraArgs)
      } else {
            commandLine(*nodeExecutableAndArgs, cliPath, bundleCommand, "--platform", "android", "--dev", "${devEnabled}",
            "--reset-cache", "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir, *extraArgs)
       }

2.3 報錯說明(此處只說明原理,實現在第三章講解)

    對於Debug模式下,報錯了直接紅屏並顯示報錯的地方。但是Release模式應用程式報錯則程式就崩潰了,無法查得原因。因此整合Bugly進行Bug收集。而使用Bugly收集Bug時得到是混淆並壓縮版的錯誤,這樣無法定位到錯誤的地方。

    從圖中可以看出報錯的是344行、868列([email protected]:868),報錯原因是找不到變數(Can't find variable...),然後我們找到3.2步驟的壓縮檔案相應的地方。

    可以在檔案中找到了此處,這裡能看到是Button找不到,但是這只是一個演示Demo當,內容不懂。當專案大了內容就多了,一個一個Button的找?所以得找到對映檔案。細節將在第三章講解。

三、配置、演示

    切入正題,配置專案,整合Bugly。

3.1 前往Bugly配置APP資訊

 (使用QQ登入,然後配置APP資訊獲取APP ID,傻瓜式的操作很容易)           

 3.2  Android專案配置

          3.2.1 在android/app/build.gradle配置內容如下:

        android {
          ...
          defaultConfig {
          ...
          ndk {
              abiFilters "armeabi-v7a", "x86"
          }
          packagingOptions {
              exclude "lib/arm64-v8a/libimagepipeline.so"
          }
       }
       ...
      dependencies {
         ...
         compile 'com.tencent.bugly:crashreport:latest.release' //其中latest.release指代最新Bugly SDK版本號,也可以指定明確的版本號,例如2.2.0
        compile 'com.tencent.bugly:nativecrashreport:latest.release' //其中latest.release指代最新Bugly NDK版本號,也可以指定明確的版本號,例如3.0
      }

          3.2.2 在MainApplication.java中修改如下:

                 匯入包

           import com.tencent.bugly.crashreport.CrashReport;

                在onCreate()方法中新增:

         @Override
         public void onCreate() {
           super.onCreate();
           CrashReport.initCrashReport(getApplicationContext(), "f7b76b8463", false); //新增此句話 f7b76b8463 為App Id
           ...
         }

       3.2.3 在AndroidManifest.xml中新增許可權

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />

      3.2.4 執行示例

           此處使用的測試Demo,大家可以自行搞一個報錯的進行演示。在DetailsScreen下使用Button元件,在此我將,Button不引入,導致報錯

             將此APP簽名打包,執行時點選詳情頁,程式閃退。 開啟Bugly的控制檯,可以看到如下錯誤,在@342:1028 (分別表示行列)。

             然後在專案的根目錄執行如下命令:(此處是生成對映檔案)

$ react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/ --sourcemap-output android-release.bundle.map

             此時你會發現在專案的根目錄中出現android-release.bundle.map檔案,開啟可以看到裡面就是assets下的index.android.bundle對映檔案。

             在專案根部新建檔案analyze/analyzeAndroid.js(此處的目的是使用node自帶的解析功能個)

              在檔案中新增內容如下:

var sourceMap = require('source-map');
var fs = require('fs');

fs.readFile('../android-release.bundle.map', 'utf8', function (err, data) {
    var smc = new sourceMap.SourceMapConsumer(data);

    console.log(smc.originalPositionFor({
        line: 344, //報錯的行
        column: 868 //報錯的列
    }));
});

               執行JS會得到如下的內容:

              可以看到定位到報錯的地方。

3.3 IOS 的配置

    3.3.1 在ios目錄下新建檔案Podfile

           填入如下內容:       

      target:"NavigationActions" do
      pod 'Bugly'
      end

            NavigationActions為專案名,Bugly為新增的依賴,然後進入ios目錄下,執行命令:$ pod install    (注意:執行此命令時請關閉所有Xcode的會話,模擬器一併關閉,防止撞鬼)      

     3.3.2 使用Xcode開啟檔案專案

             開啟專案後點擊Product --> Clean  然後 再  Product --> Build (注意此步非常重要,因為新增了Bugly庫,不Build的專案會報錯) 

             Build後會提示錯誤:Library not fount for -LPods-專案名稱     例如下圖。

             解決方案:

               移除報錯的Library,然後重新Clean  Build即可。

               開啟AppDelegate.m檔案             

         在圖中的位置新增圖中的內容,#import <Bugly/Bugly.h>; 和 [Bugly startWithAppId:@"bf1eb7a4a9"];(bf1eb7a4a9為APP ID  注意IOS的Id和Android的ID不一樣)。

          在Xcode的選單欄中,選擇Product --> Schame --> Edit Schame ...

           執行Release版本。執行裝置上,同樣點選詳情按鈕,出現閃退。

    3.3.3 執行示例

        在Bugly控制檯中可以看到如下的錯誤:

          可以看到報錯的行列分別是 344行 868列。         

          在專案的根目錄下執行命令(此處是生成對映檔案)

$ react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios-release.bundle --sourcemap-output ios-release.bundle.map

          在專案的根目錄中可以看到多了個檔案ios-release.bundle,接著在專案根部新建檔案analyze/analyzeIOS.js(此處的目的是使用node自帶的解析功能個)

              在檔案中新增內容如下:

var sourceMap = require('source-map');
var fs = require('fs');

fs.readFile('../ios-release.bundle.map', 'utf8', function (err, data) {
    var smc = new sourceMap.SourceMapConsumer(data);

    console.log(smc.originalPositionFor({
        line: 344, //報錯的行
        column: 868 //報錯的列
    }));
});

               執行JS會得到如下的內容:

              可以看到定位到報錯的地方。

四、寫在後面的話

       為了方便打擊更快整合Bugly所以寫下了這篇文章。創作不易,如果這邊文章對您有所幫助,就幫我點個贊,鼓勵下我吧。

       最後感謝@承香墨影的部落格的部落格,本文很多地方出自他的內容,謝謝作者。

傳送門: