什麼是程式碼混淆?

#

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

侷限性和警告

#

Flutter 的程式碼混淆僅在 釋出版本 中有效。

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

Web 應用不支援混淆。Web 應用可以被 最小化,這提供了類似的結果。構建 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

混淆您的應用

#

要混淆您的應用並建立符號對映,請使用帶有 --obfuscate--split-debug-info 選項的釋出模式下的 flutter build 命令。如果您將來想除錯混淆後的應用,則需要符號對映。

  1. 執行以下命令混淆您的應用並生成 SYMBOLS 檔案

    flutter build <build-target> \ 
       --obfuscate \ 
       --split-debug-info=/<symbols-directory>
    • <build-target>:構建目標。例如 apk
    • <symbols-directory>:應放置 SYMBOLS 檔案的目錄。例如 out/android
  2. 混淆二進位制檔案後,請備份 SYMBOLS 檔案。如果您丟失了原始 SYMBOLS 檔案並想解混淆堆疊跟蹤,您可能會用到它。

讀取混淆後的堆疊跟蹤

#

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

  1. 找到匹配的 SYMBOLS 檔案。例如,來自 Android arm64 裝置的崩潰需要 app.android-arm64.symbols

  2. 將堆疊跟蹤(儲存在檔案中)和 SYMBOLS 檔案一起提供給 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'));
  • 列舉名稱目前不進行混淆。