Browse Source

Fix conflicts and update view support table

Ryan Linton 7 years ago
parent
commit
d5b53d65e2

+ 44
- 11
README.md View File

10
 ## Usage
10
 ## Usage
11
 
11
 
12
 ```js
12
 ```js
13
-import RNViewShot from "react-native-view-shot";
13
+import { takeSnapshot } from "react-native-view-shot";
14
 
14
 
15
-RNViewShot.takeSnapshot(viewRef, {
15
+takeSnapshot(viewRef, {
16
   format: "jpeg",
16
   format: "jpeg",
17
   quality: 0.8
17
   quality: 0.8
18
 })
18
 })
28
 
28
 
29
 ## Full API
29
 ## Full API
30
 
30
 
31
-### `RNViewShot.takeSnapshot(view, options)`
31
+### `takeSnapshot(view, options)`
32
 
32
 
33
 Returns a Promise of the image URI.
33
 Returns a Promise of the image URI.
34
 
34
 
35
 - **`view`** is a reference to a React Native component.
35
 - **`view`** is a reference to a React Native component.
36
 - **`options`** may include:
36
 - **`options`** may include:
37
- - **`width`** / **`height`** *(number)*: the width and height of the image to capture.
37
+ - **`width`** / **`height`** *(number)*: the width and height of the final image (resized from the View bound. don't provide it if you want the original pixel size).
38
  - **`format`** *(string)*: either `png` or `jpg`/`jpeg` or `webm` (Android). Defaults to `png`.
38
  - **`format`** *(string)*: either `png` or `jpg`/`jpeg` or `webm` (Android). Defaults to `png`.
39
  - **`quality`** *(number)*: the quality. 0.0 - 1.0 (default). (only available on lossy formats like jpeg)
39
  - **`quality`** *(number)*: the quality. 0.0 - 1.0 (default). (only available on lossy formats like jpeg)
40
  - **`result`** *(string)*, the method you want to use to save the snapshot, one of:
40
  - **`result`** *(string)*, the method you want to use to save the snapshot, one of:
41
     - `"file"` (default): save to a temporary file *(that will only exist for as long as the app is running)*.
41
     - `"file"` (default): save to a temporary file *(that will only exist for as long as the app is running)*.
42
     - `"base64"`: encode as base64 and returns the raw string. Use only with small images as this may result of lags (the string is sent over the bridge). *N.B. This is not a data uri, use `data-uri` instead*.
42
     - `"base64"`: encode as base64 and returns the raw string. Use only with small images as this may result of lags (the string is sent over the bridge). *N.B. This is not a data uri, use `data-uri` instead*.
43
     - `"data-uri"`: same as `base64` but also includes the [Data URI scheme](https://en.wikipedia.org/wiki/Data_URI_scheme) header.
43
     - `"data-uri"`: same as `base64` but also includes the [Data URI scheme](https://en.wikipedia.org/wiki/Data_URI_scheme) header.
44
- - **`filename`** *(string)*: the name of the generated file if any (Android only). Defaults to `ReactNative_snapshot_image_${timestamp}`.
45
- - **`snapshotContentContainer`** *(bool)*: if true and when view is a ScrollView, the "content container" height will be evaluated instead of the container height. (Android only)
44
+ - **`path`** *(string)*: The absolute path where the file get generated. See *`dirs` constants* for more information.
45
+ - **`snapshotContentContainer`** *(bool)*: if true and when view is a ScrollView, the "content container" height will be evaluated instead of the container height.
46
+
47
+### `dirs` constants
48
+
49
+By default, takeSnapshot will export in a temporary folder and the snapshot file will be deleted as soon as the app leaves. If you use the `path` option, you make the snapshot file more permanent and at a specific file location. To make file location more 'universal', the library exports some classic directory constants:
50
+
51
+```js
52
+import { takeSnapshot, dirs } from "react-native-view-shot";
53
+// cross platform dirs:
54
+const { CacheDir, DocumentDir, MainBundleDir, MovieDir, MusicDir, PictureDir } = dirs;
55
+// only available Android:
56
+const { DCIMDir, DownloadDir, RingtoneDir, SDCardDir } = dirs;
57
+
58
+takeSnapshot(viewRef, { path: PictureDir+"/foo.png" })
59
+.then(
60
+  uri => console.log("Image saved to", uri),
61
+  error => console.error("Oops, snapshot failed", error)
62
+);
63
+```
64
+
65
+## Supported views
66
+
67
+Model tested: iPhone 6 (iOS), Nexus 5 (Android).
68
+
69
+| System             | iOS                | Android           | Windows           |
70
+|--------------------|--------------------|-------------------|-------------------|
71
+| View,Text,Image,.. | YES                | YES               | YES               |                    
72
+| WebView            | YES                | YES<sup>1</sup>   | YES               |
73
+| gl-react v2        | YES                | NO<sup>2</sup>    | NO<sup>3</sup>    |
74
+| react-native-video | NO                 | NO                | NO
75
+| react-native-maps  | YES                | [NO](https://github.com/gre/react-native-view-shot/issues/36) | NO<sup>3</sup>
76
+
77
+>
78
+1. Only supported by wrapping a `<View collapsable={false}>` parent and snapshotting it.
79
+2. It returns an empty image (not a failure Promise).
80
+3. Component itself lacks platform support.
46
 
81
 
47
 ## Caveats
82
 ## Caveats
48
 
83
 
49
 Snapshots are not guaranteed to be pixel perfect. It also depends on the platform. Here is some difference we have noticed and how to workaround.
84
 Snapshots are not guaranteed to be pixel perfect. It also depends on the platform. Here is some difference we have noticed and how to workaround.
50
 
85
 
51
-- Support of special components like Video / GL views remains untested.
86
+- Support of special components like Video / GL views is not guaranteed to work. In case of failure, the `takeSnapshot` promise gets rejected (the library won't crash).
52
 - It's preferable to **use a background color on the view you rasterize** to avoid transparent pixels and potential weirdness that some border appear around texts.
87
 - It's preferable to **use a background color on the view you rasterize** to avoid transparent pixels and potential weirdness that some border appear around texts.
53
 
88
 
54
 ### specific to Android implementation
89
 ### specific to Android implementation
55
 
90
 
56
-- you need to make sure `collapsable` is set to `false` if you want to snapshot a **View**. Otherwise that view won't reflect any UI View. ([found by @gaguirre](https://github.com/gre/react-native-view-shot/issues/7#issuecomment-245302844))
57
-- if you want to share out the screenshoted file, you will have to copy it somewhere first so it's accessible to an Intent, see comment: https://github.com/gre/react-native-view-shot/issues/11#issuecomment-251080804 .
58
--  if you implement a third party library and want to get back a File, you must first resolve the `Uri`. the `file` result returns an `Uri` so it's consistent with iOS and you can give it to `Image.getSize` for instance.
91
+- you need to make sure `collapsable` is set to `false` if you want to snapshot a **View**. Some content might even need to be wrapped into such `<View collapsable={false}>` to actually make them snapshotable! Otherwise that view won't reflect any UI View. ([found by @gaguirre](https://github.com/gre/react-native-view-shot/issues/7#issuecomment-245302844))
92
+-  if you implement a third party library and want to get back a File, you must first resolve the `Uri`. (the `file` result returns an `Uri` so it's consistent with iOS and can be given to APIs like `Image.getSize`)
59
 
93
 
60
 ## Getting started
94
 ## Getting started
61
 
95
 
100
 3. In Visual Studio, in the solution explorer, right click on your Application project then select `Add` ➜ `Reference`
134
 3. In Visual Studio, in the solution explorer, right click on your Application project then select `Add` ➜ `Reference`
101
 4. Under the projects tab select `RNViewShot` (UWP) or `RNViewShot.Net46` (WPF)
135
 4. Under the projects tab select `RNViewShot` (UWP) or `RNViewShot.Net46` (WPF)
102
 
136
 
103
-
104
 ## Thanks
137
 ## Thanks
105
 
138
 
106
 - To initial iOS work done by @jsierles in https://github.com/jsierles/react-native-view-snapshot
139
 - To initial iOS work done by @jsierles in https://github.com/jsierles/react-native-view-snapshot

+ 9
- 6
android/build.gradle View File

25
     }
25
     }
26
 }
26
 }
27
 
27
 
28
-repositories {
29
-    mavenCentral()
30
-    maven {
31
-        // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
32
-        url "$projectDir/../../../node_modules/react-native/android"
28
+allprojects {
29
+    repositories {
30
+        mavenLocal()
31
+        jcenter()
32
+        maven {
33
+            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
34
+            url "$rootDir/../node_modules/react-native/android"
35
+        }
33
     }
36
     }
34
 }
37
 }
35
 
38
 
36
 dependencies {
39
 dependencies {
37
-    compile "com.facebook.react:react-native:+"  // From node_modules
40
+    compile 'com.facebook.react:react-native:+'
38
 }
41
 }

+ 40
- 11
android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java View File

4
 import android.content.Context;
4
 import android.content.Context;
5
 import android.graphics.Bitmap;
5
 import android.graphics.Bitmap;
6
 import android.os.AsyncTask;
6
 import android.os.AsyncTask;
7
+import android.os.Environment;
7
 import android.util.DisplayMetrics;
8
 import android.util.DisplayMetrics;
8
 import android.view.View;
9
 import android.view.View;
9
 
10
 
22
 import java.io.File;
23
 import java.io.File;
23
 import java.io.FilenameFilter;
24
 import java.io.FilenameFilter;
24
 import java.io.IOException;
25
 import java.io.IOException;
26
+import java.util.HashMap;
27
+import java.util.Map;
25
 
28
 
26
 public class RNViewShotModule extends ReactContextBaseJavaModule {
29
 public class RNViewShotModule extends ReactContextBaseJavaModule {
27
 
30
 
37
         return "RNViewShot";
40
         return "RNViewShot";
38
     }
41
     }
39
 
42
 
43
+    @Override
44
+    public Map<String, Object> getConstants() {
45
+        return getSystemFolders(this.getReactApplicationContext());
46
+    }
47
+
40
     @Override
48
     @Override
41
     public void onCatalystInstanceDestroy() {
49
     public void onCatalystInstanceDestroy() {
42
         super.onCatalystInstanceDestroy();
50
         super.onCatalystInstanceDestroy();
66
         String result = options.hasKey("result") ? options.getString("result") : "file";
74
         String result = options.hasKey("result") ? options.getString("result") : "file";
67
         Boolean snapshotContentContainer = options.hasKey("snapshotContentContainer") ? options.getBoolean("snapshotContentContainer") : false;
75
         Boolean snapshotContentContainer = options.hasKey("snapshotContentContainer") ? options.getBoolean("snapshotContentContainer") : false;
68
         try {
76
         try {
69
-            String name = options.hasKey("filename") ? options.getString("filename") : null;
70
-            File tmpFile = "file".equals(result) ? createTempFile(getReactApplicationContext(), format, name) : null;
77
+            File file = null;
78
+            if ("file".equals(result)) {
79
+                if (options.hasKey("path")) {
80
+                    file = new File(options.getString("path"));
81
+                    file.createNewFile();
82
+                }
83
+                else {
84
+                    file = createTempFile(getReactApplicationContext(), format);
85
+                }
86
+            }
71
             UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
87
             UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
72
-            uiManager.addUIBlock(new ViewShot(tag, format, compressFormat, quality, width, height, tmpFile, result, snapshotContentContainer, promise));
88
+            uiManager.addUIBlock(new ViewShot(tag, format, compressFormat, quality, width, height, file, result, snapshotContentContainer, promise));
73
         }
89
         }
74
         catch (Exception e) {
90
         catch (Exception e) {
75
             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);
76
         }
92
         }
77
     }
93
     }
78
 
94
 
79
-    private static final String TEMP_FILE_PREFIX = "ReactNative_snapshot_image_";
95
+    private static final String TEMP_FILE_PREFIX = "ReactNative-snapshot-image";
80
 
96
 
81
     /**
97
     /**
82
      * Asynchronous task that cleans up cache dirs (internal and, if available, external) of cropped
98
      * Asynchronous task that cleans up cache dirs (internal and, if available, external) of cropped
116
         }
132
         }
117
     }
133
     }
118
 
134
 
135
+    static private Map<String, Object> getSystemFolders(ReactApplicationContext ctx) {
136
+        Map<String, Object> res = new HashMap<>();
137
+        res.put("CacheDir", ctx.getCacheDir().getAbsolutePath());
138
+        res.put("DCIMDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath());
139
+        res.put("DocumentDir", ctx.getFilesDir().getAbsolutePath());
140
+        res.put("DownloadDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());
141
+        res.put("MainBundleDir", ctx.getApplicationInfo().dataDir);
142
+        res.put("MovieDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath());
143
+        res.put("MusicDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath());
144
+        res.put("PictureDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath());
145
+        res.put("RingtoneDir", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES).getAbsolutePath());
146
+        String state;
147
+        state = Environment.getExternalStorageState();
148
+        if (state.equals(Environment.MEDIA_MOUNTED)) {
149
+            res.put("SDCardDir", Environment.getExternalStorageDirectory().getAbsolutePath());
150
+        }
151
+        return res;
152
+    }
153
+
119
     /**
154
     /**
120
      * Create a temporary file in the cache directory on either internal or external storage,
155
      * Create a temporary file in the cache directory on either internal or external storage,
121
      * whichever is available and has more free space.
156
      * whichever is available and has more free space.
122
      */
157
      */
123
-    private File createTempFile(Context context, String ext, String name)
158
+    private File createTempFile(Context context, String ext)
124
             throws IOException {
159
             throws IOException {
125
         File externalCacheDir = context.getExternalCacheDir();
160
         File externalCacheDir = context.getExternalCacheDir();
126
         File internalCacheDir = context.getCacheDir();
161
         File internalCacheDir = context.getCacheDir();
139
         }
174
         }
140
         String suffix = "." + ext;
175
         String suffix = "." + ext;
141
         File tmpFile = File.createTempFile(TEMP_FILE_PREFIX, suffix, cacheDir);
176
         File tmpFile = File.createTempFile(TEMP_FILE_PREFIX, suffix, cacheDir);
142
-        if (name != null) {
143
-            File renamed = new File(cacheDir, name + suffix);
144
-            tmpFile.renameTo(renamed);
145
-            return renamed;
146
-        }
147
-
148
         return tmpFile;
177
         return tmpFile;
149
     }
178
     }
150
 
179
 

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

124
         }
124
         }
125
 
125
 
126
         //evaluate real height
126
         //evaluate real height
127
-        if (this.snapshotContentContainer){
127
+        if (snapshotContentContainer) {
128
             h=0;
128
             h=0;
129
             ScrollView scrollView = (ScrollView)view;
129
             ScrollView scrollView = (ScrollView)view;
130
             for (int i = 0; i < scrollView.getChildCount(); i++) {
130
             for (int i = 0; i < scrollView.getChildCount(); i++) {

+ 25
- 11
index.js View File

1
 //@flow
1
 //@flow
2
-
3
 import { NativeModules, findNodeHandle } from "react-native";
2
 import { NativeModules, findNodeHandle } from "react-native";
4
-
5
 const { RNViewShot } = NativeModules;
3
 const { RNViewShot } = NativeModules;
6
 
4
 
5
+export const dirs = {
6
+  // cross platform
7
+  CacheDir: RNViewShot.CacheDir,
8
+  DocumentDir: RNViewShot.DocumentDir,
9
+  MainBundleDir: RNViewShot.MainBundleDir,
10
+  MovieDir: RNViewShot.MovieDir,
11
+  MusicDir: RNViewShot.MusicDir,
12
+  PictureDir: RNViewShot.PictureDir,
13
+  // only Android
14
+  DCIMDir: RNViewShot.DCIMDir,
15
+  DownloadDir: RNViewShot.DownloadDir,
16
+  RingtoneDir: RNViewShot.RingtoneDir,
17
+  SDCardDir: RNViewShot.SDCardDir,
18
+};
19
+
7
 export function takeSnapshot(
20
 export function takeSnapshot(
8
   view: number | ReactElement<any>,
21
   view: number | ReactElement<any>,
9
-  options ?: {
10
-    width ?: number;
11
-    height ?: number;
12
-    filename ?: string;
13
-    format ?: "png" | "jpg" | "jpeg" | "webm";
14
-    quality ?: number;
15
-    result ?: "file" | "base64" | "data-uri";
16
-  }
22
+  options?: {
23
+    width?: number,
24
+    height?: number,
25
+    path?: string,
26
+    format?: "png" | "jpg" | "jpeg" | "webm",
27
+    quality?: number,
28
+    result?: "file" | "base64" | "data-uri",
29
+    snapshotContentContainer?: bool
30
+  } = {}
17
 ): Promise<string> {
31
 ): Promise<string> {
18
   if (typeof view !== "number") {
32
   if (typeof view !== "number") {
19
     const node = findNodeHandle(view);
33
     const node = findNodeHandle(view);
23
   return RNViewShot.takeSnapshot(view, options);
37
   return RNViewShot.takeSnapshot(view, options);
24
 }
38
 }
25
 
39
 
26
-export default { takeSnapshot };
40
+export default { takeSnapshot, dirs };

+ 79
- 11
ios/RNViewShot.m View File

5
 #import <React/UIView+React.h>
5
 #import <React/UIView+React.h>
6
 #import <React/RCTUtils.h>
6
 #import <React/RCTUtils.h>
7
 #import <React/RCTConvert.h>
7
 #import <React/RCTConvert.h>
8
+#import <React/RCTScrollView.h>
8
 #import <React/RCTUIManager.h>
9
 #import <React/RCTUIManager.h>
9
 #import <React/RCTBridge.h>
10
 #import <React/RCTBridge.h>
10
 
11
 
20
   return self.bridge.uiManager.methodQueue;
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
 // forked from RN implementation
36
 // forked from RN implementation
24
 // https://github.com/facebook/react-native/blob/f35b372883a76b5666b016131d59268b42f3c40d/React/Modules/RCTUIManager.m#L1367
37
 // https://github.com/facebook/react-native/blob/f35b372883a76b5666b016131d59268b42f3c40d/React/Modules/RCTUIManager.m#L1367
25
 
38
 
42
     CGSize size = [RCTConvert CGSize:options];
55
     CGSize size = [RCTConvert CGSize:options];
43
     NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
56
     NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
44
     NSString *result = [RCTConvert NSString:options[@"result"] ?: @"file"];
57
     NSString *result = [RCTConvert NSString:options[@"result"] ?: @"file"];
45
-    
58
+    BOOL snapshotContentContainer = [RCTConvert BOOL:options[@"snapshotContentContainer"] ?: @"false"];
59
+
46
     // Capture image
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
     if (size.width < 0.1 || size.height < 0.1) {
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
     UIGraphicsBeginImageContextWithOptions(size, NO, 0);
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
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
97
     UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
53
     UIGraphicsEndImageContext();
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
       return;
113
       return;
58
     }
114
     }
59
     
115
     
75
       NSString *res = nil;
131
       NSString *res = nil;
76
       if ([result isEqualToString:@"file"]) {
132
       if ([result isEqualToString:@"file"]) {
77
         // Save to a temp file
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
         reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unsupported result: %@. Try one of: file | base64 | data-uri", result], nil);
163
         reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unsupported result: %@. Try one of: file | base64 | data-uri", result], nil);
96
         return;
164
         return;
97
       }
165
       }
98
-      if (res != nil) {
166
+      if (res && !error) {
99
         resolve(res);
167
         resolve(res);
100
         return;
168
         return;
101
       }
169
       }
102
       
170
       
103
       // If we reached here, something went wrong
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
       else reject(RCTErrorUnspecified, @"viewshot unknown error", nil);
173
       else reject(RCTErrorUnspecified, @"viewshot unknown error", nil);
106
     });
174
     });
107
   }];
175
   }];

+ 1
- 1
package.json View File

1
 {
1
 {
2
   "name": "react-native-view-shot",
2
   "name": "react-native-view-shot",
3
-  "version": "1.7.0",
3
+  "version": "1.8.0",
4
   "description": "Snapshot a React Native view and save it to an image",
4
   "description": "Snapshot a React Native view and save it to an image",
5
   "main": "index.js",
5
   "main": "index.js",
6
   "keywords": [
6
   "keywords": [

+ 1
- 1
windows/RNViewShot/RNViewShot.csproj View File

118
     <EmbeddedResource Include="Properties\RNViewShot.rd.xml" />
118
     <EmbeddedResource Include="Properties\RNViewShot.rd.xml" />
119
   </ItemGroup>
119
   </ItemGroup>
120
   <ItemGroup>
120
   <ItemGroup>
121
-    <ProjectReference Include="$(SolutionDir)..\node_modules\react-native-windows\ReactWindows\ReactNative\ReactNative.csproj">
121
+    <ProjectReference Include="..\..\..\react-native-windows\ReactWindows\ReactNative\ReactNative.csproj">
122
       <Project>{c7673ad5-e3aa-468c-a5fd-fa38154e205c}</Project>
122
       <Project>{c7673ad5-e3aa-468c-a5fd-fa38154e205c}</Project>
123
       <Name>ReactNative</Name>
123
       <Name>ReactNative</Name>
124
     </ProjectReference>
124
     </ProjectReference>

+ 2
- 1
windows/RNViewShot/project.json View File

1
 {
1
 {
2
   "dependencies": {
2
   "dependencies": {
3
-    "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2"
3
+    "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2",
4
+    "Newtonsoft.Json": "10.0.1-beta1"
4
   },
5
   },
5
   "frameworks": {
6
   "frameworks": {
6
     "uap10.0": {}
7
     "uap10.0": {}