|
@@ -5,6 +5,7 @@
|
5
|
5
|
#import <React/UIView+React.h>
|
6
|
6
|
#import <React/RCTUtils.h>
|
7
|
7
|
#import <React/RCTConvert.h>
|
|
8
|
+#import <React/RCTScrollView.h>
|
8
|
9
|
#import <React/RCTUIManager.h>
|
9
|
10
|
#import <React/RCTBridge.h>
|
10
|
11
|
|
|
@@ -20,6 +21,18 @@ RCT_EXPORT_MODULE()
|
20
|
21
|
return self.bridge.uiManager.methodQueue;
|
21
|
22
|
}
|
22
|
23
|
|
|
24
|
+- (NSDictionary *)constantsToExport
|
|
25
|
+{
|
|
26
|
+ return @{
|
|
27
|
+ @"CacheDir" : [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject],
|
|
28
|
+ @"DocumentDir": [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject],
|
|
29
|
+ @"MainBundleDir" : [[NSBundle mainBundle] bundlePath],
|
|
30
|
+ @"MovieDir": [NSSearchPathForDirectoriesInDomains(NSMoviesDirectory, NSUserDomainMask, YES) firstObject],
|
|
31
|
+ @"MusicDir": [NSSearchPathForDirectoriesInDomains(NSMusicDirectory, NSUserDomainMask, YES) firstObject],
|
|
32
|
+ @"PictureDir": [NSSearchPathForDirectoriesInDomains(NSPicturesDirectory, NSUserDomainMask, YES) firstObject],
|
|
33
|
+ };
|
|
34
|
+}
|
|
35
|
+
|
23
|
36
|
// forked from RN implementation
|
24
|
37
|
// https://github.com/facebook/react-native/blob/f35b372883a76b5666b016131d59268b42f3c40d/React/Modules/RCTUIManager.m#L1367
|
25
|
38
|
|
|
@@ -42,18 +55,61 @@ RCT_EXPORT_METHOD(takeSnapshot:(nonnull NSNumber *)target
|
42
|
55
|
CGSize size = [RCTConvert CGSize:options];
|
43
|
56
|
NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
|
44
|
57
|
NSString *result = [RCTConvert NSString:options[@"result"] ?: @"file"];
|
45
|
|
-
|
|
58
|
+ BOOL snapshotContentContainer = [RCTConvert BOOL:options[@"snapshotContentContainer"] ?: @"false"];
|
|
59
|
+
|
46
|
60
|
// Capture image
|
|
61
|
+ BOOL success;
|
|
62
|
+
|
|
63
|
+ UIView* rendered;
|
|
64
|
+ UIScrollView* scrollView;
|
|
65
|
+ if (snapshotContentContainer) {
|
|
66
|
+ if (![view isKindOfClass:[RCTScrollView class]]) {
|
|
67
|
+ reject(RCTErrorUnspecified, [NSString stringWithFormat:@"snapshotContentContainer can only be used on a RCTScrollView. instead got: %@", view], nil);
|
|
68
|
+ return;
|
|
69
|
+ }
|
|
70
|
+ RCTScrollView* rctScrollView = view;
|
|
71
|
+ scrollView = rctScrollView.scrollView;
|
|
72
|
+ rendered = scrollView;
|
|
73
|
+ }
|
|
74
|
+ else {
|
|
75
|
+ rendered = view;
|
|
76
|
+ }
|
|
77
|
+
|
|
78
|
+ if (size.width < 0.1 || size.height < 0.1) {
|
|
79
|
+ size = snapshotContentContainer ? scrollView.contentSize : view.bounds.size;
|
|
80
|
+ }
|
47
|
81
|
if (size.width < 0.1 || size.height < 0.1) {
|
48
|
|
- size = view.bounds.size;
|
|
82
|
+ reject(RCTErrorUnspecified, [NSString stringWithFormat:@"The content size must not be zero or negative. Got: (%g, %g)", size.width, size.height], nil);
|
|
83
|
+ return;
|
|
84
|
+ }
|
|
85
|
+
|
|
86
|
+ CGPoint savedContentOffset;
|
|
87
|
+ CGRect savedFrame;
|
|
88
|
+ if (snapshotContentContainer) {
|
|
89
|
+ // Save scroll & frame and set it temporarily to the full content size
|
|
90
|
+ savedContentOffset = scrollView.contentOffset;
|
|
91
|
+ savedFrame = scrollView.frame;
|
|
92
|
+ scrollView.contentOffset = CGPointZero;
|
|
93
|
+ scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height);
|
49
|
94
|
}
|
50
|
95
|
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
|
51
|
|
- BOOL success = [view drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
|
|
96
|
+ success = [rendered drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
|
52
|
97
|
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
53
|
98
|
UIGraphicsEndImageContext();
|
54
|
99
|
|
55
|
|
- if (!success || !image) {
|
56
|
|
- reject(RCTErrorUnspecified, @"Failed to capture view snapshot", nil);
|
|
100
|
+ if (snapshotContentContainer) {
|
|
101
|
+ // Restore scroll & frame
|
|
102
|
+ scrollView.contentOffset = savedContentOffset;
|
|
103
|
+ scrollView.frame = savedFrame;
|
|
104
|
+ }
|
|
105
|
+
|
|
106
|
+ if (!success) {
|
|
107
|
+ reject(RCTErrorUnspecified, @"The view cannot be captured. drawViewHierarchyInRect was not successful. This is a potential technical or security limitation.", nil);
|
|
108
|
+ return;
|
|
109
|
+ }
|
|
110
|
+
|
|
111
|
+ if (!image) {
|
|
112
|
+ reject(RCTErrorUnspecified, @"Failed to capture view snapshot. UIGraphicsGetImageFromCurrentImageContext() returned nil!", nil);
|
57
|
113
|
return;
|
58
|
114
|
}
|
59
|
115
|
|
|
@@ -75,10 +131,22 @@ RCT_EXPORT_METHOD(takeSnapshot:(nonnull NSNumber *)target
|
75
|
131
|
NSString *res = nil;
|
76
|
132
|
if ([result isEqualToString:@"file"]) {
|
77
|
133
|
// Save to a temp file
|
78
|
|
- NSString *tempFilePath = RCTTempFilePath(format, &error);
|
79
|
|
- if (tempFilePath) {
|
80
|
|
- if ([data writeToFile:tempFilePath options:(NSDataWritingOptions)0 error:&error]) {
|
81
|
|
- res = tempFilePath;
|
|
134
|
+ NSString *path;
|
|
135
|
+ if (options[@"path"]) {
|
|
136
|
+ path = options[@"path"];
|
|
137
|
+ NSString * folder = [path stringByDeletingLastPathComponent];
|
|
138
|
+ NSFileManager * fm = [NSFileManager defaultManager];
|
|
139
|
+ if(![fm fileExistsAtPath:folder]) {
|
|
140
|
+ [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:&error];
|
|
141
|
+ [fm createFileAtPath:path contents:nil attributes:nil];
|
|
142
|
+ }
|
|
143
|
+ }
|
|
144
|
+ else {
|
|
145
|
+ path = RCTTempFilePath(format, &error);
|
|
146
|
+ }
|
|
147
|
+ if (path && !error) {
|
|
148
|
+ if ([data writeToFile:path options:(NSDataWritingOptions)0 error:&error]) {
|
|
149
|
+ res = path;
|
82
|
150
|
}
|
83
|
151
|
}
|
84
|
152
|
}
|
|
@@ -95,13 +163,13 @@ RCT_EXPORT_METHOD(takeSnapshot:(nonnull NSNumber *)target
|
95
|
163
|
reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unsupported result: %@. Try one of: file | base64 | data-uri", result], nil);
|
96
|
164
|
return;
|
97
|
165
|
}
|
98
|
|
- if (res != nil) {
|
|
166
|
+ if (res && !error) {
|
99
|
167
|
resolve(res);
|
100
|
168
|
return;
|
101
|
169
|
}
|
102
|
170
|
|
103
|
171
|
// If we reached here, something went wrong
|
104
|
|
- if (error != nil) reject(RCTErrorUnspecified, error.localizedDescription, error);
|
|
172
|
+ if (error) reject(RCTErrorUnspecified, error.localizedDescription, error);
|
105
|
173
|
else reject(RCTErrorUnspecified, @"viewshot unknown error", nil);
|
106
|
174
|
});
|
107
|
175
|
}];
|