Edited at

Flutterの難読化とマップファイル生成のススメ

Sentry上に表示された難読化されたDartコードのエラー


Tr;dl

Flutterアプリのデプロイ時にDartコードを難読化すると、Sentry等のエラーレポートも難読化されてしまうので、難読化時にmapファイルも同時に作っておきましょう。


iOSアプリのDartコードを難読化する

Flutterのアプリリリースドキュメントには、Dartコードの難読化に関する記述があります。

iOSでは、以下の2ファイルを修正することになります。


  • <ProjectRoot>/packages/flutter_tools/bin/xcode_backend.sh

  • <ProjectRoot>/ios/Flutter/Release.xcconfig

ドキュメントに従って編集した後、 fluuter buil ios を実行し、ビルド結果に含まれる App.framework を見てみると難読化されていることが確認できます。

$ strings build/ios/Release-iphoneos/Runner.app/Frameworks/App.framework/App

...
get:_vxa@7048458x
get:_aLa@9040228x
get:_DLa@7048458x
...

難読化しなかった場合の、 App.framework はこのようになっていました。

$ strings build/ios/Release-iphoneos/Runner.app/Frameworks/App.framework/App

...
get:_count@7048458
get:_onData@9040228
get:_isSubscribed@7048458
...

難読化により、コード内の各種の名前は無意味な文字列に変更されていることが確認できました。


Sentryによるエラートラッキング

この記事を書いているタイミングで、Crashlyticsに該当するサービスをFlutterで、となるとSentryを使うのが簡単です。

上記のドキュメントに従って設定した後は、以下のコードをFlutterで書いているコードのどこかに入れれば、クラッシュが正しくレポートされることの検証ができます。

throw new ArgumentError('Test error');

難読化前であれば、Sentryは以下のようにエラーをレポートしてくれます。

main.dart in SampleApp.build at line 48

しかし、難読化した後だとエラーは以下のようになります。

SEd in bZ.opa at line 48

開発している自分が読めなくなっている😇

このエラーの内容を読むため、 <ProjectRoot>/ios/Flutter/Release.xcconfig--save-obfuscation-map オプションを追加します。

EXTRA_GEN_SNAPSHOT_OPTIONS=--obfuscate,--save-obfuscation-map=build/ios_dart_symbols_${FLUTTER_BUILD_NUMBER}.json

生成されたファイルを見れば、難読化されたエラーレポートの関数名等を知ることができます。

$ cat ios_dart_symbols_1.json

...
"_BuildJsonListener"、 "_ Gf"、
"CustomSymbolRenderer"、 "cs"、
"devicePixelRatio"、 "saa"、
...


おわりに

今回、iOSのビルドを例にしましたが、Androidのビルドステップでも --save-obfuscation-map をつけることで、難読化されたマップファイルを生成することができます。

おそらく近いうちにFirebase CrashlyticsがFlutterを公式にサポートして、この辺りも楽にいい感じにやってくれるはずです。

それがリリースされるまでの間、Dartを難読化しつつSentryを利用する際は、mapファイルも生成しておきましょう🦆