cobrowse-sdk-react-native 2.14.0 → 2.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +7 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/io/cobrowse/reactnative/CobrowseIOCommonDelegates.java +3 -3
- package/android/src/main/java/io/cobrowse/reactnative/CobrowseIOModule.java +23 -0
- package/android/src/main/java/io/cobrowse/reactnative/CommonDelegates.java +20 -83
- package/cobrowse-sdk-react-native.podspec +1 -1
- package/ios/RCTCobrowseIO.m +20 -71
- package/js/CBIOBroadcastPickerView.tsx +15 -0
- package/js/CobrowseAccessibilityService.ts +15 -0
- package/js/CobrowseIO.ts +156 -0
- package/js/CobrowseView.tsx +150 -0
- package/js/{Redacted.js → Redacted.tsx} +3 -2
- package/js/Session.ts +128 -0
- package/js/SessionControl.ts +38 -0
- package/js/Unredacted.tsx +106 -0
- package/js/{index.js → index.ts} +1 -0
- package/js/{useSession.js → useSession.ts} +5 -4
- package/lib/commonjs/CBIOBroadcastPickerView.js +15 -0
- package/lib/commonjs/CBIOBroadcastPickerView.js.map +1 -0
- package/lib/commonjs/CobrowseAccessibilityService.js +22 -0
- package/lib/commonjs/CobrowseAccessibilityService.js.map +1 -0
- package/lib/commonjs/CobrowseIO.js +149 -0
- package/lib/commonjs/CobrowseIO.js.map +1 -0
- package/lib/commonjs/CobrowseView.js +146 -0
- package/lib/commonjs/CobrowseView.js.map +1 -0
- package/lib/commonjs/Redacted.js +14 -0
- package/lib/commonjs/Redacted.js.map +1 -0
- package/lib/commonjs/Session.js +100 -0
- package/lib/commonjs/Session.js.map +1 -0
- package/lib/commonjs/SessionControl.js +39 -0
- package/lib/commonjs/SessionControl.js.map +1 -0
- package/lib/commonjs/Unredacted.js +82 -0
- package/lib/commonjs/Unredacted.js.map +1 -0
- package/lib/commonjs/index.js +77 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/useSession.js +35 -0
- package/lib/commonjs/useSession.js.map +1 -0
- package/lib/module/CBIOBroadcastPickerView.js +8 -0
- package/lib/module/CBIOBroadcastPickerView.js.map +1 -0
- package/lib/module/CobrowseAccessibilityService.js +13 -0
- package/lib/module/CobrowseAccessibilityService.js.map +1 -0
- package/lib/module/CobrowseIO.js +141 -0
- package/lib/module/CobrowseIO.js.map +1 -0
- package/lib/module/CobrowseView.js +136 -0
- package/lib/module/CobrowseView.js.map +1 -0
- package/lib/module/Redacted.js +7 -0
- package/lib/module/Redacted.js.map +1 -0
- package/lib/module/Session.js +93 -0
- package/lib/module/Session.js.map +1 -0
- package/lib/module/SessionControl.js +31 -0
- package/lib/module/SessionControl.js.map +1 -0
- package/lib/module/Unredacted.js +71 -0
- package/lib/module/Unredacted.js.map +1 -0
- package/lib/module/index.js +9 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/useSession.js +28 -0
- package/lib/module/useSession.js.map +1 -0
- package/lib/typescript/CBIOBroadcastPickerView.d.ts +8 -0
- package/lib/typescript/CBIOBroadcastPickerView.d.ts.map +1 -0
- package/lib/typescript/CobrowseAccessibilityService.d.ts +8 -0
- package/lib/typescript/CobrowseAccessibilityService.d.ts.map +1 -0
- package/lib/typescript/CobrowseIO.d.ts +30 -0
- package/lib/typescript/CobrowseIO.d.ts.map +1 -0
- package/lib/typescript/CobrowseView.d.ts +25 -0
- package/lib/typescript/CobrowseView.d.ts.map +1 -0
- package/lib/typescript/Redacted.d.ts +4 -0
- package/lib/typescript/Redacted.d.ts.map +1 -0
- package/lib/typescript/Session.d.ts +42 -0
- package/lib/typescript/Session.d.ts.map +1 -0
- package/lib/typescript/SessionControl.d.ts +17 -0
- package/lib/typescript/SessionControl.d.ts.map +1 -0
- package/lib/typescript/Unredacted.d.ts +10 -0
- package/lib/typescript/Unredacted.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +10 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/useSession.d.ts +3 -0
- package/lib/typescript/useSession.d.ts.map +1 -0
- package/package.json +35 -7
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +28 -0
- package/js/CBIOBroadcastPickerView.js +0 -11
- package/js/CobrowseAccessibilityService.js +0 -11
- package/js/CobrowseIO.js +0 -141
- package/js/CobrowseView.js +0 -129
- package/js/Session.js +0 -107
- package/js/SessionControl.js +0 -26
- package/js/Unredacted.js +0 -82
- package/ts/CBIOBroadcastPickerView.d.ts +0 -8
- package/ts/CobrowseAccessibilityService.d.ts +0 -6
- package/ts/CobrowseIO.d.ts +0 -29
- package/ts/CobrowseView.d.ts +0 -20
- package/ts/Redacted.d.ts +0 -8
- package/ts/Session.d.ts +0 -58
- package/ts/SessionControl.d.ts +0 -9
- package/ts/Unredacted.d.ts +0 -15
- package/ts/index.d.ts +0 -7
- package/ts/useSession.d.ts +0 -3
package/android/build.gradle
CHANGED
|
@@ -5,9 +5,9 @@ import com.facebook.react.bridge.ReadableArray;
|
|
|
5
5
|
|
|
6
6
|
import io.cobrowse.CobrowseIO;
|
|
7
7
|
|
|
8
|
-
interface CobrowseIOCommonDelegates extends
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
interface CobrowseIOCommonDelegates extends CobrowseIO.Delegate, CobrowseIO.SessionRequestDelegate,
|
|
9
|
+
CobrowseIO.SessionLoadDelegate, CobrowseIO.RedactionDelegate, CobrowseIO.UnredactionDelegate,
|
|
10
|
+
CobrowseIO.RemoteControlRequestDelegate, CobrowseIO.FullDeviceRequestDelegate {
|
|
11
11
|
|
|
12
12
|
public void findNodeManager();
|
|
13
13
|
public void setUnredactedTags(final ReadableArray reactTags, final Promise promise);
|
|
@@ -79,6 +79,19 @@ public class CobrowseIOModule extends ReactContextBaseJavaModule {
|
|
|
79
79
|
CobrowseIO.instance().customData(customData.toHashMap());
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
@ReactMethod
|
|
83
|
+
public void capabilities(ReadableArray capabilities) {
|
|
84
|
+
String[] capabilitiesArray = new String[capabilities.size()];
|
|
85
|
+
for (int i = 0; i < capabilities.size(); i++) {
|
|
86
|
+
try {
|
|
87
|
+
capabilitiesArray[i] = capabilities.getString(i);
|
|
88
|
+
} catch (UnexpectedNativeTypeException e) {
|
|
89
|
+
Log.w("CobrowseIO", "Failed to process capabilities: " + e.getMessage());
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
CobrowseIO.instance().capabilities(capabilitiesArray);
|
|
93
|
+
}
|
|
94
|
+
|
|
82
95
|
@ReactMethod
|
|
83
96
|
public void deviceToken(String token) {
|
|
84
97
|
if (getReactApplicationContext().getCurrentActivity() != null)
|
|
@@ -240,4 +253,14 @@ public class CobrowseIOModule extends ReactContextBaseJavaModule {
|
|
|
240
253
|
|
|
241
254
|
CobrowseIO.instance().setDelegate(delegatesWithSessionControls);
|
|
242
255
|
}
|
|
256
|
+
|
|
257
|
+
@ReactMethod
|
|
258
|
+
public void addListener(String eventName) {
|
|
259
|
+
// Keep: Required for RN built in Event Emitter Calls.
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@ReactMethod
|
|
263
|
+
public void removeListeners(Integer count) {
|
|
264
|
+
// Keep: Required for RN built in Event Emitter Calls.
|
|
265
|
+
}
|
|
243
266
|
}
|
|
@@ -7,7 +7,6 @@ import android.view.ViewGroup;
|
|
|
7
7
|
import android.view.ViewParent;
|
|
8
8
|
|
|
9
9
|
import androidx.annotation.NonNull;
|
|
10
|
-
import androidx.annotation.Nullable;
|
|
11
10
|
import androidx.core.util.Predicate;
|
|
12
11
|
|
|
13
12
|
import com.facebook.react.bridge.Promise;
|
|
@@ -40,7 +39,25 @@ class CommonDelegates implements CobrowseIOCommonDelegates {
|
|
|
40
39
|
this.reactApplicationContext = context;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
@Override
|
|
43
|
+
public void handleFullDeviceRequest(@NonNull Activity activity, @NonNull Session session) {
|
|
44
|
+
// no-op, this will be handed on the JS side via an "updated" event handler
|
|
45
|
+
// this stub just disables the default native prompt in the SDK
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@Override
|
|
49
|
+
public List<View> redactedViews(@NonNull Activity activity) {
|
|
50
|
+
HashSet<View> redacted = new HashSet<>(RedactedViewManager.redactedViews.keySet());
|
|
51
|
+
if (CobrowseIOModule.delegate instanceof io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) {
|
|
52
|
+
List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) CobrowseIOModule.delegate).redactedViews(activity);
|
|
53
|
+
if (views != null) redacted.addAll(views);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return new ArrayList<>(redacted);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@Override
|
|
60
|
+
public List<View> unredactedViews(@NonNull Activity activity) {
|
|
44
61
|
synchronized (unredactedTags) {
|
|
45
62
|
HashSet<View> unredacted = new HashSet<>();
|
|
46
63
|
for (Integer i : unredactedTags) {
|
|
@@ -54,89 +71,9 @@ class CommonDelegates implements CobrowseIOCommonDelegates {
|
|
|
54
71
|
List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) CobrowseIOModule.delegate).unredactedViews(activity);
|
|
55
72
|
if (views != null) unredacted.addAll(views);
|
|
56
73
|
}
|
|
57
|
-
return unredacted;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
HashSet<View> redacted = new HashSet<>(RedactedViewManager.redactedViews.keySet());
|
|
63
|
-
if (CobrowseIOModule.delegate instanceof io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) {
|
|
64
|
-
List<View> views = ((io.cobrowse.reactnative.CobrowseIO.RedactionDelegate) CobrowseIOModule.delegate).redactedViews(activity);
|
|
65
|
-
if (views != null) redacted.addAll(views);
|
|
75
|
+
return new ArrayList<>(unredacted);
|
|
66
76
|
}
|
|
67
|
-
return redacted;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
@Override
|
|
71
|
-
public void handleFullDeviceRequest(@NonNull Activity activity, @NonNull Session session) {
|
|
72
|
-
// no-op, this will be handed on the JS side via an "updated" event handler
|
|
73
|
-
// this stub just disables the default native prompt in the SDK
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@Override
|
|
77
|
-
public List<View> redactedViews(@NonNull Activity activity) {
|
|
78
|
-
final Set<View> redacted = this.getRedactedViews(activity);
|
|
79
|
-
final Set<View> unredacted = this.getUnredactedViews(activity);
|
|
80
|
-
|
|
81
|
-
// Project all unredactions to the root to get the full set of unredacted nodes
|
|
82
|
-
HashSet<View> projectedUnredacted = new HashSet<>();
|
|
83
|
-
for (View view : unredacted) {
|
|
84
|
-
projectedUnredacted.add(view);
|
|
85
|
-
projectedUnredacted.addAll(TreeUtils.allParents(view));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Work out which nodes are explicitly redacted but need to be unredacted
|
|
89
|
-
// due to a nested unredaction tag (these redactions will be moved towards the
|
|
90
|
-
// leaves of the view hierarchy instead)
|
|
91
|
-
HashSet<View> redactedProjectedUnredactions = new HashSet<>(redacted);
|
|
92
|
-
redactedProjectedUnredactions.retainAll(projectedUnredacted);
|
|
93
|
-
|
|
94
|
-
// Start to build the set of redactions we should actually apply. We start off with
|
|
95
|
-
// the set of explicitly redacted nodes
|
|
96
|
-
HashSet<View> toRedact = new HashSet<>(redacted);
|
|
97
|
-
|
|
98
|
-
// remove any redactions that have unredacted decendants (i.e. any that appear in the
|
|
99
|
-
// projection of the unredaction). These are the redacted nodes we need to move towards
|
|
100
|
-
// the leaves of the tree
|
|
101
|
-
toRedact.removeAll(redactedProjectedUnredactions);
|
|
102
|
-
|
|
103
|
-
// Work out the set of all nodes that are siblings of any projected unredacted node
|
|
104
|
-
HashSet<View> projectedUnredactionSiblings = new HashSet<>();
|
|
105
|
-
for (View view : projectedUnredacted) {
|
|
106
|
-
ViewParent parent = view.getParent();
|
|
107
|
-
if (parent instanceof ViewGroup)
|
|
108
|
-
projectedUnredactionSiblings.addAll(TreeUtils.directChildren((ViewGroup) parent));
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Subtract the projected unredactions from the set of all siblings of projected
|
|
112
|
-
// unredactions. i.e. subtract things that should be definitely unredacted to leave
|
|
113
|
-
// a set we're not sure yet whether to redact or not
|
|
114
|
-
HashSet<View> potentiallyRedactedUnredactedSiblings = new HashSet<View>(projectedUnredactionSiblings);
|
|
115
|
-
potentiallyRedactedUnredactedSiblings.removeAll(projectedUnredacted);
|
|
116
|
-
|
|
117
|
-
// for each node we're not sure about yet, check if the closest redacted or unredacted ancestor
|
|
118
|
-
// is a redacted node, if so this descendant should also be redacted
|
|
119
|
-
for (View view : potentiallyRedactedUnredactedSiblings) {
|
|
120
|
-
View closest = TreeUtils.closest(view, new Predicate<View>() {
|
|
121
|
-
@Override
|
|
122
|
-
public boolean test(View view) {
|
|
123
|
-
return redacted.contains(view) || unredacted.contains(view);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
if (redacted.contains(closest)) toRedact.add(view);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Remove any empty ViewGroup from the redacted set, they're often used for wrapping
|
|
130
|
-
// or sizing other elements, and do not usually need to be redacted
|
|
131
|
-
// If it's absolutely necessary they are redacted, they can always be replaced with
|
|
132
|
-
// a <Redacted> tag instead
|
|
133
|
-
for (View v : new HashSet<>(toRedact)) {
|
|
134
|
-
if (v instanceof ViewGroup && ((ViewGroup) v).getChildCount() == 0) {
|
|
135
|
-
toRedact.remove(v);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return new ArrayList<>(toRedact);
|
|
140
77
|
}
|
|
141
78
|
|
|
142
79
|
@Override
|
|
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
|
|
|
11
11
|
s.homepage = package["homepage"]
|
|
12
12
|
s.source = { :git => 'https://github.com/cobrowseio/cobrowse-sdk-react-native.git' }
|
|
13
13
|
s.platform = :ios, '11.0'
|
|
14
|
-
s.dependency 'CobrowseIO/XCFramework', '2.
|
|
14
|
+
s.dependency 'CobrowseIO/XCFramework', '2.25.0'
|
|
15
15
|
s.dependency 'React'
|
|
16
16
|
s.source_files = 'ios/*.{h,m}'
|
|
17
17
|
end
|
package/ios/RCTCobrowseIO.m
CHANGED
|
@@ -67,28 +67,6 @@ RCT_EXPORT_MODULE();
|
|
|
67
67
|
if (hasListeners) [self sendEventWithName:@SESSION_LOADED body:[session toDict]];
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
-(NSSet<UIView*>*) redactedViews: (UIViewController*) vc {
|
|
71
|
-
NSMutableSet* views = [CBIOCobrowseRedactedManager.redactedViews mutableCopy];
|
|
72
|
-
if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseRedactedViewsForViewController:)]) {
|
|
73
|
-
[views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseRedactedViewsForViewController:vc]];
|
|
74
|
-
}
|
|
75
|
-
return views;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
-(NSSet<UIView*>*) unredactedViews: (UIViewController*) vc {
|
|
79
|
-
NSMutableSet* views = [NSMutableSet set];
|
|
80
|
-
@synchronized(unredactedTags) {
|
|
81
|
-
for (id tag in unredactedTags) {
|
|
82
|
-
UIView* v = [self.bridge.uiManager viewForReactTag: tag];
|
|
83
|
-
if (v != nil) [views addObject:v];
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseUnredactedViewsForViewController:)]) {
|
|
87
|
-
[views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseUnredactedViewsForViewController:vc]];
|
|
88
|
-
}
|
|
89
|
-
return views;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
70
|
-(void)cobrowseSessionDidUpdate:(CBIOSession *)session {
|
|
93
71
|
if (hasListeners) [self sendEventWithName:@SESSION_UPDATED body:[session toDict]];
|
|
94
72
|
}
|
|
@@ -107,60 +85,27 @@ RCT_EXPORT_MODULE();
|
|
|
107
85
|
}
|
|
108
86
|
|
|
109
87
|
-(NSArray<UIView *> *)cobrowseRedactedViewsForViewController:(UIViewController *)vc {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// Project all unredactions to the root to get the full set of unredacted nodes
|
|
114
|
-
NSMutableSet* projectedUnredacted = [NSMutableSet set];
|
|
115
|
-
for (id view in unredacted) {
|
|
116
|
-
[projectedUnredacted addObject:view];
|
|
117
|
-
[projectedUnredacted addObjectsFromArray: [RCTCBIOTreeUtils allParents: view]];
|
|
88
|
+
NSMutableSet* views = [CBIOCobrowseRedactedManager.redactedViews mutableCopy];
|
|
89
|
+
if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseRedactedViewsForViewController:)]) {
|
|
90
|
+
[views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseRedactedViewsForViewController:vc]];
|
|
118
91
|
}
|
|
119
92
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
[
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
// remove any redactions that have unredacted decendants (i.e. any that appear in the
|
|
131
|
-
// projection of the unredaction). These are the redacted nodes we need to move towards
|
|
132
|
-
// the leaves of the tree
|
|
133
|
-
[toRedact minusSet: redactedProjectedUnredactions];
|
|
134
|
-
|
|
135
|
-
// Work out the set of all nodes that are siblings of any projected unredacted node
|
|
136
|
-
NSMutableSet* projectedUnredactionSiblings = [NSMutableSet set];
|
|
137
|
-
for (UIView* view in projectedUnredacted) {
|
|
138
|
-
[projectedUnredactionSiblings addObjectsFromArray: view.superview.subviews];
|
|
93
|
+
return [views allObjects];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
- (NSArray<UIView *> *)cobrowseUnredactedViewsForViewController:(UIViewController *)vc {
|
|
97
|
+
NSMutableSet* views = [NSMutableSet set];
|
|
98
|
+
@synchronized(unredactedTags) {
|
|
99
|
+
for (id tag in unredactedTags) {
|
|
100
|
+
UIView* v = [self.bridge.uiManager viewForReactTag: tag];
|
|
101
|
+
if (v != nil) [views addObject:v];
|
|
102
|
+
}
|
|
139
103
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// unredactions. i.e. subtract things that should be definitely unredacted to leave
|
|
143
|
-
// a set we're not sure yet whether to redact or not
|
|
144
|
-
NSMutableSet* potentiallyRedactedUnredactedSiblings = [projectedUnredactionSiblings mutableCopy];
|
|
145
|
-
[potentiallyRedactedUnredactedSiblings minusSet:projectedUnredacted];
|
|
146
|
-
|
|
147
|
-
// for each node we're not sure about yet, check if the closest redacted or unredacted ancestor
|
|
148
|
-
// is a redacted node, if so this descendant should also be redacted
|
|
149
|
-
for (UIView* view in potentiallyRedactedUnredactedSiblings) {
|
|
150
|
-
UIView* closest = [RCTCBIOTreeUtils closest:^BOOL(UIView *v) {
|
|
151
|
-
return [redacted containsObject:v] || [unredacted containsObject:v];
|
|
152
|
-
} from: view];
|
|
153
|
-
if ([redacted containsObject: closest]) [toRedact addObject: view];
|
|
104
|
+
if ([RCTCobrowseIO.delegate respondsToSelector:@selector(cobrowseUnredactedViewsForViewController:)]) {
|
|
105
|
+
[views addObjectsFromArray: [RCTCobrowseIO.delegate cobrowseUnredactedViewsForViewController:vc]];
|
|
154
106
|
}
|
|
155
107
|
|
|
156
|
-
|
|
157
|
-
// or sizing other elements, and do not usually need to be redacted
|
|
158
|
-
// If it's absolutely necessary they are redacted, they can always be replaced with
|
|
159
|
-
// a <Redacted> tag instead
|
|
160
|
-
for (UIView* v in [toRedact copy])
|
|
161
|
-
if ([v isKindOfClass:RCTView.class] && v.subviews.count == 0) [toRedact removeObject: v];
|
|
162
|
-
|
|
163
|
-
return toRedact.allObjects;
|
|
108
|
+
return [views allObjects];
|
|
164
109
|
}
|
|
165
110
|
|
|
166
111
|
- (bool) cobrowseShouldCaptureWindow:(UIWindow *)window {
|
|
@@ -216,6 +161,10 @@ RCT_EXPORT_METHOD(customData: (NSDictionary*) customData) {
|
|
|
216
161
|
CobrowseIO.instance.customData = customData;
|
|
217
162
|
}
|
|
218
163
|
|
|
164
|
+
RCT_EXPORT_METHOD(capabilities: (NSArray*) capabilities) {
|
|
165
|
+
CobrowseIO.instance.capabilities = capabilities;
|
|
166
|
+
}
|
|
167
|
+
|
|
219
168
|
RCT_EXPORT_METHOD(deviceToken: (NSString*) token) {
|
|
220
169
|
CobrowseIO.instance.device.token = [token dataUsingEncoding:NSUTF16StringEncoding];
|
|
221
170
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { Platform, requireNativeComponent, type ViewProps } from 'react-native'
|
|
3
|
+
|
|
4
|
+
const CBIOBroadcastPickerViewNativeView = requireNativeComponent(
|
|
5
|
+
'CBIOBroadcastPickerView'
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
type CBIOBroadcastPickerViewProps = {
|
|
9
|
+
buttonColor: string
|
|
10
|
+
} & ViewProps
|
|
11
|
+
|
|
12
|
+
export default function CBIOBroadcastPickerView (props: CBIOBroadcastPickerViewProps): JSX.Element | null {
|
|
13
|
+
// this native component is only available on iOS
|
|
14
|
+
return Platform.OS === 'ios' ? <CBIOBroadcastPickerViewNativeView {...props} /> : null
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NativeModules } from 'react-native'
|
|
2
|
+
const CobrowseIONative = NativeModules.CobrowseIO
|
|
3
|
+
|
|
4
|
+
export function showSetup (): void {
|
|
5
|
+
return CobrowseIONative.accessibilityServiceShowSetup()
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function isRunning (): boolean {
|
|
9
|
+
return CobrowseIONative.accessibilityServiceIsRunning()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
showSetup,
|
|
14
|
+
isRunning
|
|
15
|
+
}
|
package/js/CobrowseIO.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Platform, Alert, NativeEventEmitter, EmitterSubscription, NativeModules } from 'react-native'
|
|
2
|
+
import Session, { type CobrowseSessionEvents, type SessionLike } from './Session'
|
|
3
|
+
const CobrowseIONative = NativeModules.CobrowseIO
|
|
4
|
+
|
|
5
|
+
const emitter = new NativeEventEmitter(CobrowseIONative)
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
8
|
+
export default class CobrowseIO {
|
|
9
|
+
private static sessionRequestShown = false
|
|
10
|
+
private static remoteControlRequestShown = false
|
|
11
|
+
|
|
12
|
+
/** @deprecated */
|
|
13
|
+
static get SESSION_UPDATED (): 'session.updated' {
|
|
14
|
+
return 'session.updated' as const
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** @deprecated */
|
|
18
|
+
static get SESSION_ENDED (): 'session.ended' {
|
|
19
|
+
return 'session.ended' as const
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static handleSessionRequest (session: Session): void {
|
|
23
|
+
if (this.sessionRequestShown) return
|
|
24
|
+
this.sessionRequestShown = true
|
|
25
|
+
Alert.alert(
|
|
26
|
+
'Support Request',
|
|
27
|
+
'A support agent would like to use this app with you. Do you accept?',
|
|
28
|
+
[{
|
|
29
|
+
text: 'Reject',
|
|
30
|
+
onPress: () => {
|
|
31
|
+
this.sessionRequestShown = false
|
|
32
|
+
void session.end()
|
|
33
|
+
},
|
|
34
|
+
style: 'cancel'
|
|
35
|
+
}, {
|
|
36
|
+
text: 'Accept',
|
|
37
|
+
onPress: () => {
|
|
38
|
+
this.sessionRequestShown = false
|
|
39
|
+
void session.activate()
|
|
40
|
+
}
|
|
41
|
+
}], { cancelable: false })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static handleRemoteControlRequest (session: Session): void {
|
|
45
|
+
if (this.remoteControlRequestShown) return
|
|
46
|
+
this.remoteControlRequestShown = true
|
|
47
|
+
Alert.alert(
|
|
48
|
+
'Remote Control Request',
|
|
49
|
+
'A support agent would like to take remote control of this app. Do you accept?',
|
|
50
|
+
[{
|
|
51
|
+
text: 'Reject',
|
|
52
|
+
onPress: () => {
|
|
53
|
+
this.remoteControlRequestShown = false
|
|
54
|
+
void session.setRemoteControl('rejected')
|
|
55
|
+
},
|
|
56
|
+
style: 'cancel'
|
|
57
|
+
}, {
|
|
58
|
+
text: 'Accept',
|
|
59
|
+
onPress: () => {
|
|
60
|
+
this.remoteControlRequestShown = false
|
|
61
|
+
void session.setRemoteControl('on')
|
|
62
|
+
}
|
|
63
|
+
}], { cancelable: false })
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static addListener (event: CobrowseSessionEvents | 'session.requested', cb: (session: Session) => void): EmitterSubscription {
|
|
67
|
+
return emitter.addListener(event, (session: SessionLike) => cb(new Session(session)))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static start (): void {
|
|
71
|
+
CobrowseIONative.start()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static stop (): void {
|
|
75
|
+
CobrowseIONative.stop()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// eslint-disable-next-line accessor-pairs
|
|
79
|
+
static set api (api: string) {
|
|
80
|
+
CobrowseIONative.api(api)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// eslint-disable-next-line accessor-pairs
|
|
84
|
+
static set license (license: string) {
|
|
85
|
+
CobrowseIONative.license(license)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// eslint-disable-next-line accessor-pairs
|
|
89
|
+
static set customData (customData: Record<string, unknown>) {
|
|
90
|
+
CobrowseIONative.customData(customData)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// eslint-disable-next-line accessor-pairs
|
|
94
|
+
static set capabilities (capabilities: Array<'drawing' | 'full_device' | 'keypress' | 'laser' | 'pointer'>) {
|
|
95
|
+
CobrowseIONative.capabilities(capabilities)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// eslint-disable-next-line accessor-pairs
|
|
99
|
+
static set deviceToken (token: string) {
|
|
100
|
+
CobrowseIONative.deviceToken(token)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static currentSession (): Session | null {
|
|
104
|
+
return CobrowseIONative.currentSession().then((session: SessionLike | null) => (session != null) ? new Session(session) : null)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static createSession (): Session | null {
|
|
108
|
+
return CobrowseIONative.createSession().then((session: SessionLike | null) => (session != null) ? new Session(session) : null)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static getSession (codeOrId: string): Session | null {
|
|
112
|
+
return CobrowseIONative.getSession(codeOrId).then((session: SessionLike | null) => (session != null) ? new Session(session) : null)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** @deprecated */
|
|
116
|
+
static activateSession (): Session | null {
|
|
117
|
+
return CobrowseIONative.activateSession().then((session: SessionLike | null) => (session != null) ? new Session(session) : null)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** @deprecated */
|
|
121
|
+
static endSession (): void {
|
|
122
|
+
return CobrowseIONative.endSession()
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static showSessionControls: Boolean | null = null
|
|
126
|
+
static handleFullDeviceRequest: null | ((s: Session) => void) = null
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// the session.requested event is considered internal, it should
|
|
130
|
+
// not be used outside these bindings
|
|
131
|
+
CobrowseIO.addListener('session.requested', (session) => {
|
|
132
|
+
if (CobrowseIO.showSessionControls === false) {
|
|
133
|
+
CobrowseIONative.overwriteSessionIndicator()
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (Platform.OS === 'ios' && (CobrowseIO.handleFullDeviceRequest != null)) {
|
|
137
|
+
CobrowseIONative.overwriteFullControlUI()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
CobrowseIO.handleSessionRequest(session)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
CobrowseIO.addListener('session.updated', (session) => {
|
|
144
|
+
if (session.isActive() && session.remote_control === 'requested') {
|
|
145
|
+
CobrowseIO.handleRemoteControlRequest(session)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (session.isActive() && session.full_device_state === 'requested') {
|
|
149
|
+
if (CobrowseIO.handleFullDeviceRequest != null) {
|
|
150
|
+
CobrowseIO.handleFullDeviceRequest(session)
|
|
151
|
+
} else if (Platform.OS === 'android') {
|
|
152
|
+
// accept the incoming connection by default
|
|
153
|
+
void session.setFullDevice('on')
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
})
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import React, { Component } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
ActivityIndicator,
|
|
6
|
+
TouchableOpacity,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
EmitterSubscription
|
|
9
|
+
} from 'react-native'
|
|
10
|
+
import CobrowseIO from './CobrowseIO'
|
|
11
|
+
import type Session from './Session'
|
|
12
|
+
|
|
13
|
+
const styles = StyleSheet.create({
|
|
14
|
+
container: {
|
|
15
|
+
flex: 1,
|
|
16
|
+
justifyContent: 'flex-end'
|
|
17
|
+
},
|
|
18
|
+
text: {
|
|
19
|
+
textAlign: 'center',
|
|
20
|
+
margin: 15,
|
|
21
|
+
fontSize: 15,
|
|
22
|
+
lineHeight: 20
|
|
23
|
+
},
|
|
24
|
+
code: {
|
|
25
|
+
fontSize: 29,
|
|
26
|
+
padding: 20,
|
|
27
|
+
fontWeight: 'bold',
|
|
28
|
+
textAlign: 'center'
|
|
29
|
+
},
|
|
30
|
+
button: {
|
|
31
|
+
color: 'rgb(0, 122, 255)',
|
|
32
|
+
fontSize: 18,
|
|
33
|
+
margin: 10
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
interface CobrowseViewProps {
|
|
38
|
+
// @deprecated
|
|
39
|
+
license?: string
|
|
40
|
+
onEnded?: () => void
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface CobrowseViewState {
|
|
44
|
+
error: Error | null
|
|
45
|
+
session: Session | null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default class CobrowseView extends Component<CobrowseViewProps, CobrowseViewState> {
|
|
49
|
+
private _updateListener: EmitterSubscription | null = null
|
|
50
|
+
private _endListener: EmitterSubscription | null = null
|
|
51
|
+
|
|
52
|
+
constructor (props: CobrowseViewProps) {
|
|
53
|
+
super(props)
|
|
54
|
+
this.state = { error: null, session: null }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async componentDidMount (): Promise<void> {
|
|
58
|
+
if (this.props.license != null) {
|
|
59
|
+
console.warn('Passing license to view is deprecated. Use CobrowseIO.license = "..." instead')
|
|
60
|
+
CobrowseIO.license = this.props.license
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const current = await CobrowseIO.currentSession()
|
|
65
|
+
if (current != null) this.setState({ session: current })
|
|
66
|
+
else {
|
|
67
|
+
const session = await CobrowseIO.createSession()
|
|
68
|
+
this.setState({ session })
|
|
69
|
+
}
|
|
70
|
+
} catch (error) {
|
|
71
|
+
this.setState({ error: error as Error })
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this._updateListener = CobrowseIO.addListener('session.updated', (session) => {
|
|
75
|
+
this.setState({ session })
|
|
76
|
+
})
|
|
77
|
+
this._endListener = CobrowseIO.addListener('session.ended', () => {
|
|
78
|
+
if (this.props.onEnded != null) this.props.onEnded()
|
|
79
|
+
this.setState({ session: null })
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
componentWillUnmount (): void {
|
|
84
|
+
if (this._updateListener != null) this._updateListener.remove()
|
|
85
|
+
if (this._endListener != null) this._endListener.remove()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async endSession (): Promise<void> {
|
|
89
|
+
try {
|
|
90
|
+
const { session } = this.state
|
|
91
|
+
|
|
92
|
+
if (session == null) {
|
|
93
|
+
throw new Error('No session to end')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await session.end()
|
|
97
|
+
this.setState({ session: null })
|
|
98
|
+
} catch (error) {
|
|
99
|
+
this.setState({ error: error as Error })
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
renderError (error: Error): JSX.Element {
|
|
104
|
+
return (
|
|
105
|
+
<Text style={[styles.text]}>{error.message}</Text>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
renderCode (): JSX.Element {
|
|
110
|
+
let code = this.state.session?.code
|
|
111
|
+
if (code != null) code = code.substr(0, 3) + '-' + code.substr(3)
|
|
112
|
+
return (
|
|
113
|
+
<View>
|
|
114
|
+
<Text style={[styles.code, { opacity: code != null ? 1 : 0.2 }]}>{code ?? '000-000'}</Text>
|
|
115
|
+
<Text style={[styles.text]}>Provide this code to your support agent to begin screen sharing.</Text>
|
|
116
|
+
<ActivityIndicator />
|
|
117
|
+
</View>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
renderManageSession (): JSX.Element {
|
|
122
|
+
return (
|
|
123
|
+
<View>
|
|
124
|
+
<Text style={[styles.text]}>You're sharing screens from this app with a support agent.</Text>
|
|
125
|
+
<TouchableOpacity onPress={() => this.endSession}>
|
|
126
|
+
<Text style={[styles.text, styles.button]}>End Session</Text>
|
|
127
|
+
</TouchableOpacity>
|
|
128
|
+
</View>
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
renderContent (): JSX.Element {
|
|
133
|
+
const { error, session } = this.state
|
|
134
|
+
if (error != null) {
|
|
135
|
+
return this.renderError(error)
|
|
136
|
+
} else if ((session == null) || (session.state === 'pending' || session.state === 'authorizing')) {
|
|
137
|
+
return this.renderCode()
|
|
138
|
+
} else {
|
|
139
|
+
return this.renderManageSession()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
render (): JSX.Element {
|
|
144
|
+
return (
|
|
145
|
+
<View style={styles.container}>
|
|
146
|
+
{this.renderContent()}
|
|
147
|
+
</View>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import { requireNativeComponent } from 'react-native'
|
|
2
|
+
import { requireNativeComponent, type ViewProps } from 'react-native'
|
|
3
|
+
|
|
3
4
|
const CBIOCobrowseRedacted = requireNativeComponent('CBIOCobrowseRedacted')
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
export default function Redacted (props: ViewProps): JSX.Element {
|
|
6
7
|
return <CBIOCobrowseRedacted {...props}>{props.children}</CBIOCobrowseRedacted>
|
|
7
8
|
}
|