Browse Source

Merge pull request #96 from foxmicha/master

add captureScreen
Gaëtan Renaudeau 7 years ago
parent
commit
796c34193d

+ 21
- 0
README.md View File

110
 
110
 
111
 NB: the tmpfile captures are automatically cleaned out after the app closes, so you might not have to worry about this unless advanced usecases. The `ViewShot` component will use it each time you capture more than once (useful for continuous capture to not leak files).
111
 NB: the tmpfile captures are automatically cleaned out after the app closes, so you might not have to worry about this unless advanced usecases. The `ViewShot` component will use it each time you capture more than once (useful for continuous capture to not leak files).
112
 
112
 
113
+## `captureScreen()` Android and iOS Only
114
+
115
+```js
116
+import { captureScreen } from "react-native-view-shot";
117
+
118
+captureScreen({
119
+  format: "jpg",
120
+  quality: 0.8
121
+})
122
+.then(
123
+  uri => console.log("Image saved to", uri),
124
+  error => console.error("Oops, snapshot failed", error)
125
+);
126
+```
127
+
128
+This method will capture the contents of the currently displayed screen as a native hardware screenshot. It does not require a ref input, as it does not work at the view level. This means that ScrollViews will not be captured in their entirety - only the portions currently visible to the user. 
129
+
130
+Returns a Promise of the image URI.
131
+
132
+- **`options`**: the same options as in `captureRef` method.
133
+
113
 ### Advanced Examples
134
 ### Advanced Examples
114
 
135
 
115
 [Checkout react-native-view-shot-example](example)
136
 [Checkout react-native-view-shot-example](example)

+ 6
- 1
android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java View File

85
               file = createTempFile(getReactApplicationContext(), format);
85
               file = createTempFile(getReactApplicationContext(), format);
86
             }
86
             }
87
             UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
87
             UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
88
-            uiManager.addUIBlock(new ViewShot(tag, format, compressFormat, quality, width, height, file, result, snapshotContentContainer,reactContext, promise));
88
+            uiManager.addUIBlock(new ViewShot(tag, format, compressFormat, quality, width, height, file, result, snapshotContentContainer,reactContext, getCurrentActivity(), promise));
89
         }
89
         }
90
         catch (Exception e) {
90
         catch (Exception e) {
91
             promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag "+tag);
91
             promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag "+tag);
92
         }
92
         }
93
     }
93
     }
94
 
94
 
95
+    @ReactMethod
96
+    public void captureScreen(ReadableMap options, Promise promise) {
97
+        captureRef(-1, options, promise);
98
+    }
99
+
95
     private static final String TEMP_FILE_PREFIX = "ReactNative-snapshot-image";
100
     private static final String TEMP_FILE_PREFIX = "ReactNative-snapshot-image";
96
 
101
 
97
     /**
102
     /**

+ 11
- 1
android/src/main/java/fr/greweb/reactnativeviewshot/ViewShot.java View File

44
     private Promise promise;
44
     private Promise promise;
45
     private Boolean snapshotContentContainer;
45
     private Boolean snapshotContentContainer;
46
     private  ReactApplicationContext reactContext;
46
     private  ReactApplicationContext reactContext;
47
+    private Activity currentActivity;
47
 
48
 
48
     public ViewShot(
49
     public ViewShot(
49
             int tag,
50
             int tag,
56
             String result,
57
             String result,
57
             Boolean snapshotContentContainer,
58
             Boolean snapshotContentContainer,
58
             ReactApplicationContext reactContext,
59
             ReactApplicationContext reactContext,
60
+            Activity currentActivity,
59
             Promise promise) {
61
             Promise promise) {
60
         this.tag = tag;
62
         this.tag = tag;
61
         this.extension = extension;
63
         this.extension = extension;
67
         this.result = result;
69
         this.result = result;
68
         this.snapshotContentContainer = snapshotContentContainer;
70
         this.snapshotContentContainer = snapshotContentContainer;
69
         this.reactContext = reactContext;
71
         this.reactContext = reactContext;
72
+        this.currentActivity = currentActivity;
70
         this.promise = promise;
73
         this.promise = promise;
71
     }
74
     }
72
 
75
 
73
     @Override
76
     @Override
74
     public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
77
     public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
75
         OutputStream os = null;
78
         OutputStream os = null;
76
-        View view = nativeViewHierarchyManager.resolveView(tag);
79
+        View view = null;
80
+
81
+        if (tag == -1) {
82
+            view = currentActivity.getWindow().getDecorView().findViewById(android.R.id.content);
83
+        } else {
84
+            view = nativeViewHierarchyManager.resolveView(tag);
85
+        }
86
+
77
         if (view == null) {
87
         if (view == null) {
78
             promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: "+tag);
88
             promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: "+tag);
79
             return;
89
             return;

+ 4
- 3
example/App.js View File

13
 } from "react-native";
13
 } from "react-native";
14
 import SvgUri from "react-native-svg-uri";
14
 import SvgUri from "react-native-svg-uri";
15
 import omit from "lodash/omit";
15
 import omit from "lodash/omit";
16
-import { captureRef } from "react-native-view-shot";
16
+import { captureRef, captureScreen } from "react-native-view-shot";
17
 import { Surface } from "gl-react-native";
17
 import { Surface } from "gl-react-native";
18
 import GL from "gl-react";
18
 import GL from "gl-react";
19
 import MapView from "react-native-maps";
19
 import MapView from "react-native-maps";
53
       snapshotContentContainer: false
53
       snapshotContentContainer: false
54
     }
54
     }
55
   };
55
   };
56
-
56
+  
57
   snapshot = refname => () =>
57
   snapshot = refname => () =>
58
-    captureRef(this.refs[refname], this.state.value)
58
+    (refname ? captureRef(this.refs[refname], this.state.value) : captureScreen(this.state.value))
59
       .then(
59
       .then(
60
         res =>
60
         res =>
61
           this.state.value.result !== "tmpfile"
61
           this.state.value.result !== "tmpfile"
149
             <Btn label="📷 MapView" onPress={this.snapshot("mapview")} />
149
             <Btn label="📷 MapView" onPress={this.snapshot("mapview")} />
150
             <Btn label="📷 WebView" onPress={this.snapshot("webview")} />
150
             <Btn label="📷 WebView" onPress={this.snapshot("webview")} />
151
             <Btn label="📷 Video" onPress={this.snapshot("video")} />
151
             <Btn label="📷 Video" onPress={this.snapshot("video")} />
152
+            <Btn label="📷 Native Screenshot" onPress={this.snapshot()}/>
152
             <Btn
153
             <Btn
153
               label="📷 Empty View (should crash)"
154
               label="📷 Empty View (should crash)"
154
               onPress={this.snapshot("empty")}
155
               onPress={this.snapshot("empty")}

+ 16
- 1
ios/RNViewShot.m View File

19
   return RCTGetUIManagerQueue();
19
   return RCTGetUIManagerQueue();
20
 }
20
 }
21
 
21
 
22
+RCT_EXPORT_METHOD(captureScreen: (NSDictionary *)options
23
+                  resolve:(RCTPromiseResolveBlock)resolve
24
+                  reject:(RCTPromiseRejectBlock)reject) 
25
+{
26
+  [self captureRef: [NSNumber numberWithInt:-1] withOptions:options resolve:resolve reject:reject];
27
+}
22
 
28
 
23
 RCT_EXPORT_METHOD(releaseCapture:(nonnull NSString *)uri)
29
 RCT_EXPORT_METHOD(releaseCapture:(nonnull NSString *)uri)
24
 {
30
 {
41
 
47
 
42
     // Get view
48
     // Get view
43
     UIView *view;
49
     UIView *view;
44
-    view = viewRegistry[target];
50
+
51
+    if ([target intValue] == -1) {
52
+      UIWindow *window = [[UIApplication sharedApplication] keyWindow];
53
+      view = window.rootViewController.view;
54
+    } else {
55
+      view = viewRegistry[target];
56
+    }
57
+
45
     if (!view) {
58
     if (!view) {
46
       reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", target], nil);
59
       reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", target], nil);
47
       return;
60
       return;
88
       scrollView.contentOffset = CGPointZero;
101
       scrollView.contentOffset = CGPointZero;
89
       scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height);
102
       scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height);
90
     }
103
     }
104
+
91
     UIGraphicsBeginImageContextWithOptions(size, NO, 0);
105
     UIGraphicsBeginImageContextWithOptions(size, NO, 0);
106
+    
92
     success = [rendered drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
107
     success = [rendered drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
93
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
108
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
94
     UIGraphicsEndImageContext();
109
     UIGraphicsEndImageContext();

+ 13
- 0
src/index.js View File

114
   }
114
   }
115
 }
115
 }
116
 
116
 
117
+export function captureScreen(
118
+  optionsObject?: Options
119
+): Promise<string> {
120
+  const { options, errors } = validateOptions(optionsObject);
121
+  if (__DEV__ && errors.length > 0) {
122
+    console.warn(
123
+      "react-native-view-shot: bad options:\n" +
124
+        errors.map(e => `- ${e}`).join("\n")
125
+    );
126
+  }
127
+  return RNViewShot.captureScreen(options);
128
+}
129
+
117
 type Props = {
130
 type Props = {
118
   options?: Object,
131
   options?: Object,
119
   captureMode?: "mount" | "continuous" | "update",
132
   captureMode?: "mount" | "continuous" | "update",