Skip to content

Commit 127cae6

Browse files
feat(replay): Add Mask and Unmask Android implementation (#4265)
1 parent 07257af commit 127cae6

File tree

11 files changed

+214
-5
lines changed

11 files changed

+214
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
### Features
1212

13-
- Add Replay Custom Masking for iOS ([#4224](https://github.com/getsentry/sentry-react-native/pull/4224))
13+
- Add Replay Custom Masking for iOS and Android ([#4224](https://github.com/getsentry/sentry-react-native/pull/4224), [#4265](https://github.com/getsentry/sentry-react-native/pull/4265))
1414

1515
```jsx
1616
import * as Sentry from '@sentry/react-native';

packages/core/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
import io.sentry.protocol.SentryPackage;
6565
import io.sentry.protocol.User;
6666
import io.sentry.protocol.ViewHierarchy;
67+
import io.sentry.react.replay.RNSentryReplayMask;
68+
import io.sentry.react.replay.RNSentryReplayUnmask;
6769
import io.sentry.util.DebugMetaPropertiesApplier;
6870
import io.sentry.util.FileUtils;
6971
import io.sentry.util.JsonSerializationUtils;
@@ -371,6 +373,9 @@ private SentryReplayOptions getReplayOptions(@NotNull ReadableMap rnOptions) {
371373
androidReplayOptions.addMaskViewClass("com.horcrux.svg.SvgView"); // react-native-svg
372374
}
373375

376+
androidReplayOptions.setMaskViewContainerClass(RNSentryReplayMask.class.getName());
377+
androidReplayOptions.setUnmaskViewContainerClass(RNSentryReplayUnmask.class.getName());
378+
374379
return androidReplayOptions;
375380
}
376381

packages/core/android/src/main/java/io/sentry/react/RNSentryPackage.java

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,35 @@
88
import com.facebook.react.module.model.ReactModuleInfo;
99
import com.facebook.react.module.model.ReactModuleInfoProvider;
1010
import com.facebook.react.uimanager.ViewManager;
11-
import java.util.Arrays;
11+
import io.sentry.react.replay.RNSentryReplayMaskManager;
12+
import io.sentry.react.replay.RNSentryReplayMaskManagerImpl;
13+
import io.sentry.react.replay.RNSentryReplayUnmaskManager;
14+
import io.sentry.react.replay.RNSentryReplayUnmaskManagerImpl;
1215
import java.util.HashMap;
1316
import java.util.List;
1417
import java.util.Map;
1518

1619
public class RNSentryPackage extends TurboReactPackage {
1720

21+
private static final boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
22+
1823
@Nullable
1924
@Override
2025
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
21-
if (name.equals(RNSentryModuleImpl.NAME)) {
26+
if (RNSentryModuleImpl.NAME.equals(name)) {
2227
return new RNSentryModule(reactContext);
28+
} else if (isTurboModule) {
29+
return getFabricComponentNativeModule(name);
30+
} else {
31+
return null;
32+
}
33+
}
34+
35+
private NativeModule getFabricComponentNativeModule(String name) {
36+
if (RNSentryReplayMaskManagerImpl.REACT_CLASS.equals(name)) {
37+
return new RNSentryReplayMaskManager();
38+
} else if (RNSentryReplayUnmaskManagerImpl.REACT_CLASS.equals(name)) {
39+
return new RNSentryReplayUnmaskManager();
2340
} else {
2441
return null;
2542
}
@@ -29,7 +46,6 @@ public NativeModule getModule(String name, ReactApplicationContext reactContext)
2946
public ReactModuleInfoProvider getReactModuleInfoProvider() {
3047
return () -> {
3148
final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
32-
boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
3349
moduleInfos.put(
3450
RNSentryModuleImpl.NAME,
3551
new ReactModuleInfo(
@@ -41,13 +57,40 @@ public ReactModuleInfoProvider getReactModuleInfoProvider() {
4157
false, // isCxxModule
4258
isTurboModule // isTurboModule
4359
));
60+
if (isTurboModule) {
61+
moduleInfos.put(
62+
RNSentryReplayMaskManagerImpl.REACT_CLASS,
63+
new ReactModuleInfo(
64+
RNSentryReplayMaskManagerImpl.REACT_CLASS, // name
65+
RNSentryReplayMaskManagerImpl.REACT_CLASS, // className
66+
false, // canOverrideExistingModule
67+
false, // needsEagerInit
68+
false, // hasConstants, required in RN 0.65
69+
false, // isCxxModule
70+
true // isTurboModule
71+
));
72+
moduleInfos.put(
73+
RNSentryReplayUnmaskManagerImpl.REACT_CLASS,
74+
new ReactModuleInfo(
75+
RNSentryReplayUnmaskManagerImpl.REACT_CLASS, // name
76+
RNSentryReplayUnmaskManagerImpl.REACT_CLASS, // className
77+
false, // canOverrideExistingModule
78+
false, // needsEagerInit
79+
false, // hasConstants, required in RN 0.65
80+
false, // isCxxModule
81+
true // isTurboModule
82+
));
83+
}
4484
return moduleInfos;
4585
};
4686
}
4787

4888
@NonNull
4989
@Override
5090
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
51-
return Arrays.asList(new RNSentryOnDrawReporterManager(reactContext));
91+
return List.of(
92+
new RNSentryOnDrawReporterManager(reactContext),
93+
new RNSentryReplayMaskManager(),
94+
new RNSentryReplayUnmaskManager());
5295
}
5396
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.sentry.react.replay;
2+
3+
import android.content.Context;
4+
import com.facebook.react.views.view.ReactViewGroup;
5+
6+
public class RNSentryReplayMask extends ReactViewGroup {
7+
public RNSentryReplayMask(Context context) {
8+
super(context);
9+
}
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.sentry.react.replay;
2+
3+
import androidx.annotation.NonNull;
4+
import com.facebook.react.uimanager.ThemedReactContext;
5+
6+
public final class RNSentryReplayMaskManagerImpl {
7+
8+
private RNSentryReplayMaskManagerImpl() {}
9+
10+
public static final String REACT_CLASS = "RNSentryReplayMask";
11+
12+
@NonNull
13+
public static RNSentryReplayMask createViewInstance(@NonNull ThemedReactContext context) {
14+
return new RNSentryReplayMask(context);
15+
}
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package io.sentry.react.replay;
2+
3+
import android.content.Context;
4+
import com.facebook.react.views.view.ReactViewGroup;
5+
6+
public class RNSentryReplayUnmask extends ReactViewGroup {
7+
public RNSentryReplayUnmask(Context context) {
8+
super(context);
9+
}
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.sentry.react.replay;
2+
3+
import androidx.annotation.NonNull;
4+
import com.facebook.react.uimanager.ThemedReactContext;
5+
6+
public final class RNSentryReplayUnmaskManagerImpl {
7+
8+
private RNSentryReplayUnmaskManagerImpl() {}
9+
10+
public static final String REACT_CLASS = "RNSentryReplayUnmask";
11+
12+
@NonNull
13+
public RNSentryReplayUnmask createViewInstance(@NonNull ThemedReactContext context) {
14+
return new RNSentryReplayUnmask(context);
15+
}
16+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.sentry.react.replay;
2+
3+
import androidx.annotation.NonNull;
4+
import com.facebook.react.module.annotations.ReactModule;
5+
import com.facebook.react.uimanager.ThemedReactContext;
6+
import com.facebook.react.uimanager.ViewGroupManager;
7+
import com.facebook.react.uimanager.ViewManagerDelegate;
8+
import com.facebook.react.viewmanagers.RNSentryReplayMaskManagerDelegate;
9+
import com.facebook.react.viewmanagers.RNSentryReplayMaskManagerInterface;
10+
11+
@ReactModule(name = RNSentryReplayMaskManagerImpl.REACT_CLASS)
12+
public class RNSentryReplayMaskManager extends ViewGroupManager<RNSentryReplayMask>
13+
implements RNSentryReplayMaskManagerInterface<RNSentryReplayMask> {
14+
private final RNSentryReplayMaskManagerDelegate<RNSentryReplayMask, RNSentryReplayMaskManager>
15+
delegate = new RNSentryReplayMaskManagerDelegate<>(this);
16+
17+
@Override
18+
public ViewManagerDelegate<RNSentryReplayMask> getDelegate() {
19+
return delegate;
20+
}
21+
22+
@NonNull
23+
@Override
24+
public String getName() {
25+
return RNSentryReplayMaskManagerImpl.REACT_CLASS;
26+
}
27+
28+
@NonNull
29+
@Override
30+
public RNSentryReplayMask createViewInstance(@NonNull ThemedReactContext context) {
31+
return new RNSentryReplayMask(context);
32+
}
33+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package io.sentry.react.replay;
2+
3+
import androidx.annotation.NonNull;
4+
import com.facebook.react.module.annotations.ReactModule;
5+
import com.facebook.react.uimanager.ThemedReactContext;
6+
import com.facebook.react.uimanager.ViewGroupManager;
7+
import com.facebook.react.uimanager.ViewManagerDelegate;
8+
import com.facebook.react.viewmanagers.RNSentryReplayUnmaskManagerDelegate;
9+
import com.facebook.react.viewmanagers.RNSentryReplayUnmaskManagerInterface;
10+
11+
@ReactModule(name = RNSentryReplayMaskManagerImpl.REACT_CLASS)
12+
public class RNSentryReplayUnmaskManager extends ViewGroupManager<RNSentryReplayUnmask>
13+
implements RNSentryReplayUnmaskManagerInterface<RNSentryReplayUnmask> {
14+
private final RNSentryReplayUnmaskManagerDelegate<
15+
RNSentryReplayUnmask, RNSentryReplayUnmaskManager>
16+
delegate = new RNSentryReplayUnmaskManagerDelegate<>(this);
17+
18+
@Override
19+
public ViewManagerDelegate<RNSentryReplayUnmask> getDelegate() {
20+
return delegate;
21+
}
22+
23+
@NonNull
24+
@Override
25+
public String getName() {
26+
return RNSentryReplayMaskManagerImpl.REACT_CLASS;
27+
}
28+
29+
@NonNull
30+
@Override
31+
public RNSentryReplayUnmask createViewInstance(@NonNull ThemedReactContext context) {
32+
return new RNSentryReplayUnmask(context);
33+
}
34+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.sentry.react.replay;
2+
3+
import androidx.annotation.NonNull;
4+
import com.facebook.react.module.annotations.ReactModule;
5+
import com.facebook.react.uimanager.ThemedReactContext;
6+
import com.facebook.react.uimanager.ViewGroupManager;
7+
8+
@ReactModule(name = RNSentryReplayMaskManagerImpl.REACT_CLASS)
9+
public class RNSentryReplayMaskManager extends ViewGroupManager<RNSentryReplayMask> {
10+
@NonNull
11+
@Override
12+
public String getName() {
13+
return RNSentryReplayMaskManagerImpl.REACT_CLASS;
14+
}
15+
16+
@NonNull
17+
@Override
18+
public RNSentryReplayMask createViewInstance(@NonNull ThemedReactContext context) {
19+
return new RNSentryReplayMask(context);
20+
}
21+
}

0 commit comments

Comments
 (0)