跳到主內容

混淆 Dart 程式碼

如何從 Dart 二進位制檔案中移除函式和類名稱。

什麼是程式碼混淆?

#

程式碼混淆 是修改應用二進位制檔案以使其難以被人理解的過程。混淆會隱藏編譯後的 Dart 程式碼中的函式和類名,用其他符號替換每個符號,從而使攻擊者難以對你的專屬應用進行逆向工程。

侷限性與警告

#

Flutter 的程式碼混淆僅適用於 釋出構建 (release build)

程式碼混淆不會加密資源,也不能防止逆向工程。它只是用更晦澀的名稱重新命名了符號。

Web 應用不支援混淆。Web 應用可以進行壓縮 (minification),這能達到類似的效果。當你構建 Flutter Web 應用的釋出版本時,Web 編譯器會自動壓縮應用。欲瞭解更多資訊,請參閱 構建併發布 Web 應用

支援的目標平臺

#

以下構建目標支援本頁面介紹的混淆過程:

  • aar
  • apk
  • appbundle
  • ios
  • ios-framework
  • ipa
  • linux
  • macos
  • macos-framework
  • windows

有關特定構建目標可用命令列選項的詳細資訊,請執行以下命令。輸出中應列出 --obfuscate--split-debug-info 選項。如果沒有顯示,你需要安裝較新版本的 Flutter 才能混淆程式碼。

flutter build <build-target> -h
  • <build-target>:構建目標。例如 apk

混淆你的應用

#

要混淆應用並建立符號對映表,請在釋出模式下使用 flutter build 命令,並帶上 --obfuscate--split-debug-info 選項。如果你將來需要除錯混淆後的應用,則必須保留該符號對映表。

  1. 執行以下命令以混淆你的應用並生成符號 (SYMBOLS) 檔案:

    flutter build <build-target> \
       --obfuscate \
       --split-debug-info=/<symbols-directory>
    
    • <build-target>:構建目標。例如 apk
    • <symbols-directory>:存放符號檔案的目錄。例如 out/android
  2. 一旦混淆了二進位制檔案,請備份符號檔案。如果你丟失了原始的符號檔案,又想對堆疊跟蹤進行反混淆,你將會需要它。

解讀混淆後的堆疊跟蹤

#

要除錯由混淆後的應用生成的堆疊跟蹤,請按照以下步驟將其轉換為可讀格式:

  1. 找到匹配的符號檔案。例如,來自 Android arm64 裝置的崩潰日誌需要使用 app.android-arm64.symbols

  2. 將堆疊跟蹤檔案(儲存在檔案中)和符號檔案一同提供給 flutter symbolize 命令。

    flutter symbolize \
       -i <stack-trace-file> \
       -d <obfuscated-symbols-file>
    
    • <stack-trace-file>:堆疊跟蹤的檔案路徑。例如 ???
    • <obfuscated-symbols-file>:包含混淆符號的符號檔案路徑。例如 out/android/app.android-arm64.symbols

    有關 symbolize 命令的更多資訊,請執行 flutter symbolize -h

解讀混淆後的名稱

#

你可以生成一個包含混淆對映的 JSON 檔案。混淆對映是一個 JSON 陣列,其中包含原始名稱與混淆名稱的配對。例如 ["MaterialApp", "ex", "Scaffold", "ey"],其中 exMaterialApp 的混淆名稱。

要生成混淆對映,請使用以下命令:

flutter build <build-target> \
   --obfuscate \
   --split-debug-info=/<symbols-directory> \
   --extra-gen-snapshot-options=--save-obfuscation-map=/<obfuscation-map-file>
  • <build-target>:構建目標。例如 apk
  • <symbols-directory>:存放符號的目錄。例如 out/android
  • <obfuscation-map-file>:應放置 JSON 混淆對映的檔案路徑。例如 out/android/map.json

注意事項

#

在編寫最終會成為混淆二進位制檔案的應用時,請注意以下事項:

  • 依賴匹配特定類名、函式名或庫名的程式碼將會失敗。例如,以下對 expect() 的呼叫在混淆後的二進位制檔案中將無法工作:

    dart
    expect(foo.runtimeType.toString(), equals('Foo'));
    
  • 列舉 (Enum) 名稱目前不會被混淆。