Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@

- Adds GraphQL integration ([#5299](https://github.com/getsentry/sentry-react-native/pull/5299))
- Adds Supabase integration ([#5296](https://github.com/getsentry/sentry-react-native/pull/5296))
- Add new _experimental_ Canvas Capture Strategy for Session Replay ([#5301](https://github.com/getsentry/sentry-react-native/pull/5301))
- A new screenshot capture strategy that uses Android's Canvas API for more accurate and reliable text and image masking
- Any `.drawText()` or `.drawBitmap()` calls are replaced by rectangles, ensuring no text or images are present in the resulting output
- Note: If this strategy is used, all text and images will be masked, regardless of any masking configuration
- To enable this feature, set the `screenshotStrategy` to `canvas`:
```js
import * as Sentry from '@sentry/react-native';

Sentry.init({
integrations: [
Sentry.mobileReplayIntegration({
screenshotStrategy: 'canvas',
}),
],
});
```

### Dependencies

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import io.sentry.ISerializer;
import io.sentry.Integration;
import io.sentry.ScopesAdapter;
import io.sentry.ScreenshotStrategyType;
import io.sentry.Sentry;
import io.sentry.SentryDate;
import io.sentry.SentryDateProvider;
Expand Down Expand Up @@ -415,12 +416,32 @@ private SentryReplayOptions getReplayOptions(@NotNull ReadableMap rnOptions) {
androidReplayOptions.addMaskViewClass("com.horcrux.svg.SvgView"); // react-native-svg
}

if (rnMobileReplayOptions.hasKey("screenshotStrategy")) {
final String screenshotStrategyString = rnMobileReplayOptions.getString("screenshotStrategy");
final ScreenshotStrategyType screenshotStrategy =
parseScreenshotStrategy(screenshotStrategyString);
androidReplayOptions.setScreenshotStrategy(screenshotStrategy);
}

androidReplayOptions.setMaskViewContainerClass(RNSentryReplayMask.class.getName());
androidReplayOptions.setUnmaskViewContainerClass(RNSentryReplayUnmask.class.getName());

return androidReplayOptions;
}

private ScreenshotStrategyType parseScreenshotStrategy(@Nullable String strategyString) {
if (strategyString == null) {
return ScreenshotStrategyType.PIXEL_COPY;
}

switch (strategyString.toLowerCase(Locale.ROOT)) {
case "canvas":
return ScreenshotStrategyType.CANVAS;
default:
return ScreenshotStrategyType.PIXEL_COPY;
}
}

private SentryReplayQuality parseReplayQuality(@Nullable String qualityString) {
if (qualityString == null) {
return SentryReplayQuality.MEDIUM;
Expand Down
22 changes: 22 additions & 0 deletions packages/core/src/js/replay/mobilereplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ import { enrichXhrBreadcrumbsForMobileReplay } from './xhrUtils';

export const MOBILE_REPLAY_INTEGRATION_NAME = 'MobileReplay';

/**
* Screenshot strategy type for Android Session Replay.
*
* - `'canvas'`: Canvas-based screenshot strategy. This strategy does **not** support any masking options, it always masks text and images. Use this if your application has strict PII requirements.
* - `'pixelCopy'`: Pixel copy screenshot strategy (default). Supports all masking options.
*/
export type ScreenshotStrategy = 'canvas' | 'pixelCopy';

export interface MobileReplayOptions {
/**
* Mask all text in recordings
Expand Down Expand Up @@ -69,6 +77,19 @@ export interface MobileReplayOptions {
* @default false
*/
enableFastViewRendering?: boolean;

/**
* Sets the screenshot strategy used by the Session Replay integration on Android.
*
* If your application has strict PII requirements we recommend using `'canvas'`.
* This strategy does **not** support any masking options, it always masks text and images.
*
* - Experiment: In case you are noticing issues with the canvas screenshot strategy, please report the issue on [GitHub](https://github.com/getsentry/sentry-java).
*
* @default 'pixelCopy'
* @platform android
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alwx @antonis What do you think of updating other platform specific options with @platform?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's a good idea 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened an issue keep keep track of this.

*/
screenshotStrategy?: ScreenshotStrategy;
}

const defaultOptions: Required<MobileReplayOptions> = {
Expand All @@ -78,6 +99,7 @@ const defaultOptions: Required<MobileReplayOptions> = {
enableExperimentalViewRenderer: false,
enableViewRendererV2: true,
enableFastViewRendering: false,
screenshotStrategy: 'pixelCopy',
};

function mergeOptions(initOptions: Partial<MobileReplayOptions>): Required<MobileReplayOptions> {
Expand Down
1 change: 1 addition & 0 deletions samples/react-native/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ Sentry.init({
maskAllVectors: true,
maskAllText: true,
enableViewRendererV2: true,
screenshotStrategy: 'canvas', // if you have strict PII requirements
}),
Sentry.appStartIntegration({
standalone: false,
Expand Down
Loading