Over-the-air updates
Symbolicate crashes in over-the-air updates by uploading the matching symbols for each patch.
Over-the-air (OTA) updates let you ship changes without a full native app release. When a crash happens in a patched bundle, Measure needs the matching sourcemap to symbolicate the stack trace.
React Native
Each OTA update needs its own sourcemap, tied to a patch ID so Measure can match a crash to the exact bundle it came from. How you set that patch ID depends on whether you're on Expo.
Set a patch version
Alongside the patch ID, you can attach an optional patch version, a human-readable label for the OTA update. The patch ID is a UUID Measure uses internally to match a crash to its sourcemap; the patch version is what you read in the dashboard to tell one release apart from another.
Set it in two places for each OTA update, using the same value:
- In
MeasureConfigvia thepatchVersionfield, so every event and crash from the patched bundle is tagged with it. - In the
upload_patch.shscript via the--patch_versionflag, so the uploaded sourcemap carries the same label.
new MeasureConfig({
patchVersion: "v1.2.3-hotfix",
})On Expo, set the patch version to the same message you pass to eas update --message. Using one string in both places lets you match a release in Expo to the same release in Measure at a glance.
eas update --branch production --message "v1.2.3-hotfix"Expo
The Metro plugin sets the patch ID for you. Export with source maps and upload them after every deploy.
Step 1: Add withMeasureConfig to metro.config.js
The plugin injects a patch ID into each bundle at build time, with no changes to your SDK initialization code.
const { getDefaultConfig } = require('expo/metro-config');
const { withMeasureConfig } = require('@measuresh/react-native/metro');
const config = getDefaultConfig(__dirname);
module.exports = withMeasureConfig(config);Step 2: Export with source maps
npx expo export --platform all --source-maps --output-dir distThe export produces .hbc.map files under dist/_expo/static/js/ios/ and dist/_expo/static/js/android/.
Step 3: Upload the sourcemaps
Run upload_patch.sh after deploying each OTA update. The plugin already put the patch ID in the bundle, so the script reads it straight from the sourcemap. The script ships with the SDK package.
./node_modules/@measuresh/react-native/scripts/upload_patch.sh \
--api_key "your-api-key" \
--api_url "https://your-measure-url" \
--path_to_sourcemap "./dist/_expo/static/js/ios/entry-abc123.hbc.map" \
--patch_version "v1.2.3-hotfix"Manual
Without the Metro plugin, generate the patch ID yourself and pass it to MeasureConfig.
Step 1: Generate a patch ID
Generate a UUID v4 for the patch. Use any UUID library, or the shell command below:
uuidgen | tr '[:upper:]' '[:lower:]'Step 2: Pass the patch ID to MeasureConfig
import { Measure, MeasureConfig } from '@measuresh/react-native';
Measure.init({
config: new MeasureConfig({
autoStart: true,
patchId: 'your-patch-uuid',
patchVersion: 'v1.2.3-hotfix',
}),
});The patchId field must match the UUID you pass to the upload script.
Step 3: Generate the sourcemap
Generate the JavaScript sourcemap when you build the OTA bundle. The exact command depends on your OTA provider. For a manual React Native bundle:
npx react-native bundle \
--platform ios \
--dev false \
--entry-file index.js \
--bundle-output main.jsbundle \
--sourcemap-output main.jsbundle.mapStep 4: Upload the sourcemap
Pass the sourcemap and the patch ID you set to upload_patch.sh:
./node_modules/@measuresh/react-native/scripts/upload_patch.sh \
--api_key "your-api-key" \
--api_url "https://your-measure-url" \
--path_to_sourcemap "./path/to/main.jsbundle.map" \
--patch_id "your-patch-uuid" \
--patch_version "v1.2.3-hotfix"Flutter
Flutter ships over-the-air updates through Shorebird. Support for symbolicating Shorebird patches is coming soon.
Think this page can be better?
Open an issue