|
| 1 | +--- |
| 2 | +id: debugging-release-builds |
| 3 | +title: Debugging Release Builds |
| 4 | +--- |
| 5 | + |
| 6 | +import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; import constants from '@site/core/TabsConstants'; |
| 7 | + |
| 8 | +## Symbolicating a stack trace |
| 9 | + |
| 10 | +If a React Native app throws an unhandled exception in a release build, the output may be obfuscated and hard to read. |
| 11 | + |
| 12 | +```shell |
| 13 | +07-15 10:58:25.820 18979 18998 E AndroidRuntime: FATAL EXCEPTION: mqt_native_modules |
| 14 | +07-15 10:58:25.820 18979 18998 E AndroidRuntime: Process: com.awesomeproject, PID: 18979 07-15 10:58:25.820 18979 18998 E AndroidRuntime: com.facebook.react.common.JavascriptException: Failed, js engine: hermes, stack: |
| 15 | +07-15 10:58:25.820 18979 18998 E AndroidRuntime: p@1:132161 |
| 16 | +07-15 10:58:25.820 18979 18998 E AndroidRuntime: p@1:132084 |
| 17 | +07-15 10:58:25.820 18979 18998 E AndroidRuntime: f@1:131854 |
| 18 | +07-15 10:58:25.820 18979 18998 E AndroidRuntime: anonymous@1:131119 |
| 19 | +``` |
| 20 | + |
| 21 | +In the above stack trace, entries like `p@1:132161` are minified function names and bytecode offsets. To debug these calls, we want to translate these into file, line, and function name, e.g. `AwesomeProject/App.js:54:initializeMap`. This is known as **symbolication.** |
| 22 | + |
| 23 | +You can symbolicate minified function names and bytecode like the above by passing the stack trace and a generated source map to [`metro-symbolicate`](https://npmjs.com/package/metro-symbolicate). |
| 24 | + |
| 25 | +### Enabling source maps |
| 26 | + |
| 27 | +Source maps are required to symbolicate stack traces. Make sure that source maps are enabled within the build config for the target platform. |
| 28 | + |
| 29 | +<Tabs groupId="platform" queryString defaultValue={constants.defaultPlatform} values={constants.platforms} className="pill-tabs"> |
| 30 | +<TabItem value="android"> |
| 31 | + |
| 32 | +:::info |
| 33 | +On Android, source maps are **enabled** by default. |
| 34 | +::: |
| 35 | + |
| 36 | +To enable source map generation, ensure the following `hermesFlags` are present in `android/app/build.gradle`. |
| 37 | + |
| 38 | +```groovy |
| 39 | +react { |
| 40 | + hermesFlags = ["-O", "-output-source-map"] |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +If done correctly you should see the output location of the source map during Metro build output. |
| 45 | + |
| 46 | +```text |
| 47 | +Writing bundle output to:, android/app/build/generated/assets/react/release/index.android.bundle |
| 48 | +Writing sourcemap output to:, android/app/build/intermediates/sourcemaps/react/release/index.android.bundle.packager.map |
| 49 | +``` |
| 50 | + |
| 51 | +</TabItem> |
| 52 | +<TabItem value="ios"> |
| 53 | + |
| 54 | +:::info |
| 55 | +On iOS, source maps are **disabled** by default. Use the following instructions to enable them. |
| 56 | +::: |
| 57 | + |
| 58 | +To enable source map generation: |
| 59 | + |
| 60 | +- Open Xcode and edit the build phase "Bundle React Native code and images". |
| 61 | +- Above the other exports, add a `SOURCEMAP_FILE` entry with the desired output path. |
| 62 | + |
| 63 | +```diff |
| 64 | ++ SOURCEMAP_FILE="$(pwd)/../main.jsbundle.map"; |
| 65 | + WITH_ENVIRONMENT="../node_modules/react-native/scripts/xcode/with-environment.sh" |
| 66 | +``` |
| 67 | + |
| 68 | +If done correctly you should see the output location of the source map during Metro build output. |
| 69 | + |
| 70 | +```text |
| 71 | +Writing bundle output to:, Build/Intermediates.noindex/ArchiveIntermediates/application/BuildProductsPath/Release-iphoneos/main.jsbundle |
| 72 | +Writing sourcemap output to:, Build/Intermediates.noindex/ArchiveIntermediates/application/BuildProductsPath/Release-iphoneos/main.jsbundle.map |
| 73 | +``` |
| 74 | + |
| 75 | +</TabItem> |
| 76 | +</Tabs> |
| 77 | + |
| 78 | +### Using `metro-symbolicate` |
| 79 | + |
| 80 | +With source maps being generated, we can now translate our stack traces. |
| 81 | + |
| 82 | +```shell |
| 83 | +# Print usage instructions |
| 84 | +npx metro-symbolicate |
| 85 | + |
| 86 | +# From a file containing the stack trace |
| 87 | +npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map < stacktrace.txt |
| 88 | + |
| 89 | +# From adb logcat (Android) |
| 90 | +adb logcat -d | npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map |
| 91 | +``` |
| 92 | + |
| 93 | +### Notes on source maps |
| 94 | + |
| 95 | +- Multiple source maps may be generated by the build process. Make sure to use the one in the location shown in the examples. |
| 96 | +- Make sure that the source map you use corresponds to the exact commit of the crashing app. Small changes in source code can cause large differences in offsets. |
| 97 | +- If `metro-symbolicate` exits immediately with success, make sure the input comes from a pipe or redirection and not from a terminal. |
0 commit comments