浏览代码

Merge pull request #96 from foxmicha/master

add captureScreen
Gaëtan Renaudeau 6 年前
父节点
当前提交
796c34193d

+ 21
- 0
README.md 查看文件

@@ -110,6 +110,27 @@ This method release a previously captured `uri`. For tmpfile it will clean them
110 110
 
111 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 134
 ### Advanced Examples
114 135
 
115 136
 [Checkout react-native-view-shot-example](example)

+ 6
- 1
android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java 查看文件

@@ -85,13 +85,18 @@ public class RNViewShotModule extends ReactContextBaseJavaModule {
85 85
               file = createTempFile(getReactApplicationContext(), format);
86 86
             }
87 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 90
         catch (Exception e) {
91 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 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 查看文件

@@ -44,6 +44,7 @@ public class ViewShot implements UIBlock {
44 44
     private Promise promise;
45 45
     private Boolean snapshotContentContainer;
46 46
     private  ReactApplicationContext reactContext;
47
+    private Activity currentActivity;
47 48
 
48 49
     public ViewShot(
49 50
             int tag,
@@ -56,6 +57,7 @@ public class ViewShot implements UIBlock {
56 57
             String result,
57 58
             Boolean snapshotContentContainer,
58 59
             ReactApplicationContext reactContext,
60
+            Activity currentActivity,
59 61
             Promise promise) {
60 62
         this.tag = tag;
61 63
         this.extension = extension;
@@ -67,13 +69,21 @@ public class ViewShot implements UIBlock {
67 69
         this.result = result;
68 70
         this.snapshotContentContainer = snapshotContentContainer;
69 71
         this.reactContext = reactContext;
72
+        this.currentActivity = currentActivity;
70 73
         this.promise = promise;
71 74
     }
72 75
 
73 76
     @Override
74 77
     public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
75 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 87
         if (view == null) {
78 88
             promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "No view found with reactTag: "+tag);
79 89
             return;

+ 4
- 3
example/App.js 查看文件

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

+ 16
- 1
ios/RNViewShot.m 查看文件

@@ -19,6 +19,12 @@ RCT_EXPORT_MODULE()
19 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 29
 RCT_EXPORT_METHOD(releaseCapture:(nonnull NSString *)uri)
24 30
 {
@@ -41,7 +47,14 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)target
41 47
 
42 48
     // Get view
43 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 58
     if (!view) {
46 59
       reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", target], nil);
47 60
       return;
@@ -88,7 +101,9 @@ RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)target
88 101
       scrollView.contentOffset = CGPointZero;
89 102
       scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height);
90 103
     }
104
+
91 105
     UIGraphicsBeginImageContextWithOptions(size, NO, 0);
106
+    
92 107
     success = [rendered drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
93 108
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
94 109
     UIGraphicsEndImageContext();

+ 13
- 0
src/index.js 查看文件

@@ -114,6 +114,19 @@ export function releaseCapture(uri: string): void {
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 130
 type Props = {
118 131
   options?: Object,
119 132
   captureMode?: "mount" | "continuous" | "update",