Gaëtan Renaudeau 7 years ago
commit
f4fe9bfaee

+ 7
- 0
.flowconfig View File

@@ -0,0 +1,7 @@
1
+[ignore]
2
+
3
+[include]
4
+
5
+[libs]
6
+
7
+[options]

+ 39
- 0
.gitignore View File

@@ -0,0 +1,39 @@
1
+# OSX
2
+#
3
+.DS_Store
4
+
5
+# Xcode
6
+#
7
+build/
8
+*.pbxuser
9
+!default.pbxuser
10
+*.mode1v3
11
+!default.mode1v3
12
+*.mode2v3
13
+!default.mode2v3
14
+*.perspectivev3
15
+!default.perspectivev3
16
+xcuserdata
17
+*.xccheckout
18
+*.moved-aside
19
+DerivedData
20
+*.hmap
21
+*.ipa
22
+*.xcuserstate
23
+project.xcworkspace
24
+
25
+# node.js
26
+#
27
+node_modules/
28
+npm-debug.log
29
+
30
+# android
31
+#
32
+android/build/
33
+android/.gradle/
34
+android/.idea/
35
+android/android.iml
36
+android/gradle/
37
+android/gradlew
38
+android/gradlew.bat
39
+android/local.properties

+ 90
- 0
README.md View File

@@ -0,0 +1,90 @@
1
+
2
+# react-native-view-shot
3
+
4
+Snapshot a view and save to an image.
5
+
6
+The image will be stored in a temporary file that will only exist for as long as the app is running.
7
+
8
+## Getting started
9
+
10
+```
11
+npm install --save react-native-view-shot
12
+```
13
+
14
+### Mostly automatic installation
15
+
16
+```
17
+react-native link react-native-view-shot
18
+```
19
+
20
+### Manual installation
21
+
22
+#### iOS
23
+
24
+1. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]`
25
+2. Go to `node_modules` ➜ `react-native-view-shot` and add `RNViewShot.xcodeproj`
26
+3. In XCode, in the project navigator, select your project. Add `libRNViewShot.a` to your project's `Build Phases` ➜ `Link Binary With Libraries`
27
+4. Run your project (`Cmd+R`)<
28
+
29
+#### Android
30
+
31
+1. Open up `android/app/src/main/java/[...]/MainActivity.java`
32
+  - Add `import com.reactlibrary.RNViewShotPackage;` to the imports at the top of the file
33
+  - Add `new RNViewShotPackage()` to the list returned by the `getPackages()` method
34
+2. Append the following lines to `android/settings.gradle`:
35
+  	```
36
+  	include ':react-native-view-shot'
37
+  	project(':react-native-view-shot').projectDir = new File(rootProject.projectDir, 	'../node_modules/react-native-view-shot/android')
38
+  	```
39
+3. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
40
+  	```
41
+      compile project(':react-native-view-shot')
42
+  	```
43
+
44
+#### Windows
45
+
46
+No support yet. Feel free to PR.
47
+
48
+## Usage
49
+
50
+```js
51
+import { findNodeHandle } from "react-native";
52
+import RNViewShot from "react-native-view-shot";
53
+
54
+RNViewShot.takeSnapshot(findNodeHandle(aRef), {
55
+  format: "jpeg",
56
+  quality: 0.8
57
+})
58
+.then(
59
+  uri => console.log("Image saved to", uri),
60
+  error => console.error("Oops, snapshot failed", error)
61
+);
62
+```
63
+
64
+## Example
65
+
66
+[Checkout react-native-view-shot-example](https://github.com/gre/react-native-view-shot-example)
67
+
68
+## Full API
69
+
70
+### `RNViewShot.takeSnapshot(view, options)`
71
+
72
+Returns a Promise of the image URI.
73
+
74
+- **`view`** references to a React Native component.
75
+- **`options`** may include:
76
+ - **`width`** / **`height`** *(number)*: the width and height of the image to capture.
77
+ - **`format`** *(string)*: either `png` or `jpg`/`jpeg` or `webm` (Android). Defaults to `png`.
78
+ - **`quality`** *(number)*: the quality. 0.0 - 1.0 (default). (only available on lossy formats like jpeg)
79
+
80
+## Notes
81
+
82
+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.
83
+
84
+- Support of special components like Video / GL views remains untested.
85
+- 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.
86
+
87
+## Thanks
88
+
89
+- To initial iOS work done by @jsierles in https://github.com/jsierles/react-native-view-snapshot
90
+- To React Native implementation of takeSnapshot in iOS by @nicklockwood

+ 38
- 0
android/build.gradle View File

@@ -0,0 +1,38 @@
1
+buildscript {
2
+    repositories {
3
+        jcenter()
4
+    }
5
+
6
+    dependencies {
7
+        classpath 'com.android.tools.build:gradle:2.1.3'
8
+    }
9
+}
10
+
11
+apply plugin: 'com.android.library'
12
+
13
+android {
14
+    compileSdkVersion 23
15
+    buildToolsVersion "23.0.1"
16
+
17
+    defaultConfig {
18
+        minSdkVersion 16
19
+        targetSdkVersion 22
20
+        versionCode 1
21
+        versionName "1.0"
22
+    }
23
+    lintOptions {
24
+        abortOnError false
25
+    }
26
+}
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"
33
+    }
34
+}
35
+
36
+dependencies {
37
+    compile "com.facebook.react:react-native:+"  // From node_modules
38
+}

+ 6
- 0
android/src/main/AndroidManifest.xml View File

@@ -0,0 +1,6 @@
1
+
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+          package="com.reactlibrary">
4
+
5
+</manifest>
6
+  

+ 138
- 0
android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotModule.java View File

@@ -0,0 +1,138 @@
1
+
2
+package fr.greweb.reactnativeviewshot;
3
+
4
+import android.content.Context;
5
+import android.graphics.Bitmap;
6
+import android.os.AsyncTask;
7
+import android.util.DisplayMetrics;
8
+
9
+import com.facebook.react.bridge.ReactApplicationContext;
10
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
11
+import com.facebook.react.bridge.ReactMethod;
12
+
13
+import com.facebook.react.bridge.GuardedAsyncTask;
14
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
15
+import com.facebook.react.bridge.Promise;
16
+import com.facebook.react.bridge.ReactContext;
17
+import com.facebook.react.bridge.ReadableMap;
18
+import com.facebook.react.uimanager.UIBlock;
19
+import com.facebook.react.uimanager.UIManagerModule;
20
+
21
+import java.io.File;
22
+import java.io.FilenameFilter;
23
+import java.io.IOException;
24
+
25
+public class RNViewShotModule extends ReactContextBaseJavaModule {
26
+
27
+    private final ReactApplicationContext reactContext;
28
+
29
+    public RNViewShotModule(ReactApplicationContext reactContext) {
30
+        super(reactContext);
31
+        this.reactContext = reactContext;
32
+    }
33
+
34
+    @Override
35
+    public String getName() {
36
+        return "RNViewShot";
37
+    }
38
+
39
+    @Override
40
+    public void onCatalystInstanceDestroy() {
41
+        super.onCatalystInstanceDestroy();
42
+        new CleanTask(getReactApplicationContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
43
+    }
44
+
45
+    @ReactMethod
46
+    public void takeSnapshot(int tag, ReadableMap options, Promise promise) {
47
+        ReactApplicationContext context = getReactApplicationContext();
48
+        String format = options.hasKey("format") ? options.getString("format") : "png";
49
+        Bitmap.CompressFormat compressFormat =
50
+                format.equals("png")
51
+                        ? Bitmap.CompressFormat.PNG
52
+                        : format.equals("jpg")||format.equals("jpeg")
53
+                        ? Bitmap.CompressFormat.JPEG
54
+                        : format.equals("webm")
55
+                        ? Bitmap.CompressFormat.WEBP
56
+                        : null;
57
+        if (compressFormat == null) {
58
+            throw new JSApplicationIllegalArgumentException("Unsupported image format: " + format);
59
+        }
60
+        double quality = options.hasKey("quality") ? options.getDouble("quality") : 1.0;
61
+        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
62
+        Integer width = options.hasKey("width") ? (int)(displayMetrics.density * options.getDouble("width")) : null;
63
+        Integer height = options.hasKey("height") ? (int)(displayMetrics.density * options.getDouble("height")) : null;
64
+        try {
65
+            File tmpFile = createTempFile(getReactApplicationContext(), format);
66
+            UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
67
+            uiManager.addUIBlock(new ViewShot(tag, compressFormat, quality, width, height, tmpFile, promise));
68
+        }
69
+        catch (Exception e) {
70
+            promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag "+tag);
71
+        }
72
+    }
73
+
74
+    private static final String TEMP_FILE_PREFIX = "ReactNative_snapshot_image_";
75
+
76
+    /**
77
+     * Asynchronous task that cleans up cache dirs (internal and, if available, external) of cropped
78
+     * image files. This is run when the catalyst instance is being destroyed (i.e. app is shutting
79
+     * down) and when the module is instantiated, to handle the case where the app crashed.
80
+     */
81
+    private static class CleanTask extends GuardedAsyncTask<Void, Void> {
82
+        private final Context mContext;
83
+
84
+        private CleanTask(ReactContext context) {
85
+            super(context);
86
+            mContext = context;
87
+        }
88
+
89
+        @Override
90
+        protected void doInBackgroundGuarded(Void... params) {
91
+            cleanDirectory(mContext.getCacheDir());
92
+            File externalCacheDir = mContext.getExternalCacheDir();
93
+            if (externalCacheDir != null) {
94
+                cleanDirectory(externalCacheDir);
95
+            }
96
+        }
97
+
98
+        private void cleanDirectory(File directory) {
99
+            File[] toDelete = directory.listFiles(
100
+                    new FilenameFilter() {
101
+                        @Override
102
+                        public boolean accept(File dir, String filename) {
103
+                            return filename.startsWith(TEMP_FILE_PREFIX);
104
+                        }
105
+                    });
106
+            if (toDelete != null) {
107
+                for (File file: toDelete) {
108
+                    file.delete();
109
+                }
110
+            }
111
+        }
112
+    }
113
+
114
+    /**
115
+     * Create a temporary file in the cache directory on either internal or external storage,
116
+     * whichever is available and has more free space.
117
+     */
118
+    private File createTempFile(Context context, String ext)
119
+            throws IOException {
120
+        File externalCacheDir = context.getExternalCacheDir();
121
+        File internalCacheDir = context.getCacheDir();
122
+        File cacheDir;
123
+        if (externalCacheDir == null && internalCacheDir == null) {
124
+            throw new IOException("No cache directory available");
125
+        }
126
+        if (externalCacheDir == null) {
127
+            cacheDir = internalCacheDir;
128
+        }
129
+        else if (internalCacheDir == null) {
130
+            cacheDir = externalCacheDir;
131
+        } else {
132
+            cacheDir = externalCacheDir.getFreeSpace() > internalCacheDir.getFreeSpace() ?
133
+                    externalCacheDir : internalCacheDir;
134
+        }
135
+        return File.createTempFile(TEMP_FILE_PREFIX, ext, cacheDir);
136
+    }
137
+
138
+}

+ 28
- 0
android/src/main/java/fr/greweb/reactnativeviewshot/RNViewShotPackage.java View File

@@ -0,0 +1,28 @@
1
+
2
+package fr.greweb.reactnativeviewshot;
3
+
4
+import java.util.Arrays;
5
+import java.util.Collections;
6
+import java.util.List;
7
+
8
+import com.facebook.react.ReactPackage;
9
+import com.facebook.react.bridge.NativeModule;
10
+import com.facebook.react.bridge.ReactApplicationContext;
11
+import com.facebook.react.uimanager.ViewManager;
12
+import com.facebook.react.bridge.JavaScriptModule;
13
+public class RNViewShotPackage implements ReactPackage {
14
+    @Override
15
+    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
16
+      return Arrays.<NativeModule>asList(new RNViewShotModule(reactContext));
17
+    }
18
+
19
+    @Override
20
+    public List<Class<? extends JavaScriptModule>> createJSModules() {
21
+      return Collections.emptyList();
22
+    }
23
+
24
+    @Override
25
+    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
26
+      return Collections.emptyList();
27
+    }
28
+}

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

@@ -0,0 +1,95 @@
1
+package fr.greweb.reactnativeviewshot;
2
+
3
+import javax.annotation.Nullable;
4
+import android.graphics.Bitmap;
5
+import android.net.Uri;
6
+import android.view.View;
7
+
8
+import com.facebook.react.bridge.Promise;
9
+import com.facebook.react.uimanager.NativeViewHierarchyManager;
10
+import com.facebook.react.uimanager.UIBlock;
11
+
12
+import java.io.File;
13
+import java.io.FileOutputStream;
14
+import java.io.IOException;
15
+
16
+/**
17
+ * Snapshot utility class allow to screenshot a view.
18
+ */
19
+public class ViewShot implements UIBlock {
20
+
21
+    static final String ERROR_UNABLE_TO_SNAPSHOT = "E_UNABLE_TO_SNAPSHOT";
22
+
23
+    private int tag;
24
+    private Bitmap.CompressFormat format;
25
+    private double quality;
26
+    private Integer width;
27
+    private Integer height;
28
+    private File output;
29
+    private Promise promise;
30
+
31
+    public ViewShot(
32
+            int tag,
33
+            Bitmap.CompressFormat format,
34
+            double quality,
35
+            @Nullable Integer width,
36
+            @Nullable Integer height,
37
+            File output,
38
+            Promise promise) {
39
+        this.tag = tag;
40
+        this.format = format;
41
+        this.quality = quality;
42
+        this.width = width;
43
+        this.height = height;
44
+        this.output = output;
45
+        this.promise = promise;
46
+    }
47
+
48
+    @Override
49
+    public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
50
+        FileOutputStream fos = null;
51
+        View view = nativeViewHierarchyManager.resolveView(tag);
52
+        try {
53
+            fos = new FileOutputStream(output);
54
+            captureView(view, fos);
55
+            String uri = Uri.fromFile(output).toString();
56
+            promise.resolve(uri);
57
+        }
58
+        catch (Exception e) {
59
+            promise.reject(ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag "+tag);
60
+        }
61
+        finally {
62
+            if (fos != null) {
63
+                try {
64
+                    fos.close();
65
+                } catch (IOException e) {
66
+                    e.printStackTrace();
67
+                }
68
+            }
69
+        }
70
+    }
71
+
72
+    /**
73
+     * Screenshot a view and return the captured bitmap.
74
+     * @param view the view to capture
75
+     * @return the screenshot or null if it failed.
76
+     */
77
+    private void captureView (View view, FileOutputStream fos) {
78
+        int w = view.getWidth();
79
+        int h = view.getHeight();
80
+        if (w <= 0 || h <= 0) {
81
+            throw new RuntimeException("Impossible to snapshot the view: view is invalid");
82
+        }
83
+        Bitmap bitmap = view.getDrawingCache();
84
+        if (bitmap == null)
85
+            view.setDrawingCacheEnabled(true);
86
+        bitmap = view.getDrawingCache();
87
+        if (width != null && height != null && (width != w || height != h)) {
88
+            bitmap = Bitmap.createScaledBitmap(bitmap, width, height, true);
89
+        }
90
+        if (bitmap == null) {
91
+            throw new RuntimeException("Impossible to snapshot the view");
92
+        }
93
+        bitmap.compress(format, (int)(100.0 * quality), fos);
94
+    }
95
+}

+ 22
- 0
index.js View File

@@ -0,0 +1,22 @@
1
+//@flow
2
+
3
+import { NativeModules, findNodeHandle } from "react-native";
4
+
5
+const { RNViewShot } = NativeModules;
6
+
7
+export function takeSnapshot(
8
+  view: number | ReactElement<any>,
9
+  options ?: {
10
+    width ?: number;
11
+    height ?: number;
12
+    format ?: "png" | "jpg" | "jpeg" | "webm";
13
+    quality ?: number;
14
+  }
15
+): Promise<string> {
16
+  if (typeof view !== "number") {
17
+    view = findNodeHandle(view);
18
+  }
19
+  return RNViewShot.takeSnapshot(view, options);
20
+}
21
+
22
+export default { takeSnapshot };

+ 7
- 0
ios/RNViewShot.h View File

@@ -0,0 +1,7 @@
1
+
2
+#import "RCTBridgeModule.h"
3
+
4
+@interface RNViewShot : NSObject <RCTBridgeModule>
5
+
6
+@end
7
+  

+ 90
- 0
ios/RNViewShot.m View File

@@ -0,0 +1,90 @@
1
+
2
+#import "RNViewShot.h"
3
+#import <AVFoundation/AVFoundation.h>
4
+#import "RCTLog.h"
5
+#import "UIView+React.h"
6
+#import "RCTUtils.h"
7
+#import "RCTConvert.h"
8
+#import "RCTUIManager.h"
9
+#import "RCTBridge.h"
10
+
11
+
12
+@implementation RNViewShot
13
+
14
+RCT_EXPORT_MODULE()
15
+
16
+@synthesize bridge = _bridge;
17
+
18
+- (dispatch_queue_t)methodQueue
19
+{
20
+  return self.bridge.uiManager.methodQueue;
21
+}
22
+
23
+// forked from RN implementation
24
+// https://github.com/facebook/react-native/blob/f35b372883a76b5666b016131d59268b42f3c40d/React/Modules/RCTUIManager.m#L1367
25
+
26
+RCT_EXPORT_METHOD(takeSnapshot:(nonnull NSNumber *)target
27
+                  withOptions:(NSDictionary *)options
28
+                  resolve:(RCTPromiseResolveBlock)resolve
29
+                  reject:(RCTPromiseRejectBlock)reject)
30
+{
31
+    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
32
+
33
+        // Get view
34
+        UIView *view;
35
+        view = viewRegistry[target];
36
+        if (!view) {
37
+            reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", target], nil);
38
+            return;
39
+        }
40
+
41
+        // Get options
42
+        CGSize size = [RCTConvert CGSize:options];
43
+        NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
44
+
45
+        // Capture image
46
+        if (size.width < 0.1 || size.height < 0.1) {
47
+            size = view.bounds.size;
48
+        }
49
+        UIGraphicsBeginImageContextWithOptions(size, NO, 0);
50
+        BOOL success = [view drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
51
+        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
52
+        UIGraphicsEndImageContext();
53
+
54
+        if (!success || !image) {
55
+            reject(RCTErrorUnspecified, @"Failed to capture view snapshot.", nil);
56
+            return;
57
+        }
58
+
59
+        // Convert image to data (on a background thread)
60
+        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
61
+
62
+            NSData *data;
63
+            if ([format isEqualToString:@"png"]) {
64
+                data = UIImagePNGRepresentation(image);
65
+            } else if ([format isEqualToString:@"jpeg"] || [format isEqualToString:@"jpg"]) {
66
+                CGFloat quality = [RCTConvert CGFloat:options[@"quality"] ?: @1];
67
+                data = UIImageJPEGRepresentation(image, quality);
68
+            } else {
69
+                reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unsupported image format: %@", format], nil);
70
+                return;
71
+            }
72
+
73
+            // Save to a temp file
74
+            NSError *error = nil;
75
+            NSString *tempFilePath = RCTTempFilePath(format, &error);
76
+            if (tempFilePath) {
77
+                if ([data writeToFile:tempFilePath options:(NSDataWritingOptions)0 error:&error]) {
78
+                    resolve(tempFilePath);
79
+                    return;
80
+                }
81
+            }
82
+
83
+            // If we reached here, something went wrong
84
+            reject(RCTErrorUnspecified, error.localizedDescription, error);
85
+        });
86
+    }];
87
+}
88
+
89
+
90
+@end

+ 252
- 0
ios/RNViewShot.xcodeproj/project.pbxproj View File

@@ -0,0 +1,252 @@
1
+// !$*UTF8*$!
2
+{
3
+	archiveVersion = 1;
4
+	classes = {
5
+	};
6
+	objectVersion = 46;
7
+	objects = {
8
+
9
+/* Begin PBXBuildFile section */
10
+		B3E7B58A1CC2AC0600A0062D /* RNViewShot.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNViewShot.m */; };
11
+/* End PBXBuildFile section */
12
+
13
+/* Begin PBXCopyFilesBuildPhase section */
14
+		58B511D91A9E6C8500147676 /* CopyFiles */ = {
15
+			isa = PBXCopyFilesBuildPhase;
16
+			buildActionMask = 2147483647;
17
+			dstPath = "include/$(PRODUCT_NAME)";
18
+			dstSubfolderSpec = 16;
19
+			files = (
20
+			);
21
+			runOnlyForDeploymentPostprocessing = 0;
22
+		};
23
+/* End PBXCopyFilesBuildPhase section */
24
+
25
+/* Begin PBXFileReference section */
26
+		134814201AA4EA6300B7C361 /* libRNViewShot.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNViewShot.a; sourceTree = BUILT_PRODUCTS_DIR; };
27
+		B3E7B5881CC2AC0600A0062D /* RNViewShot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNViewShot.h; sourceTree = "<group>"; };
28
+		B3E7B5891CC2AC0600A0062D /* RNViewShot.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNViewShot.m; sourceTree = "<group>"; };
29
+/* End PBXFileReference section */
30
+
31
+/* Begin PBXFrameworksBuildPhase section */
32
+		58B511D81A9E6C8500147676 /* Frameworks */ = {
33
+			isa = PBXFrameworksBuildPhase;
34
+			buildActionMask = 2147483647;
35
+			files = (
36
+			);
37
+			runOnlyForDeploymentPostprocessing = 0;
38
+		};
39
+/* End PBXFrameworksBuildPhase section */
40
+
41
+/* Begin PBXGroup section */
42
+		134814211AA4EA7D00B7C361 /* Products */ = {
43
+			isa = PBXGroup;
44
+			children = (
45
+				134814201AA4EA6300B7C361 /* libRNViewShot.a */,
46
+			);
47
+			name = Products;
48
+			sourceTree = "<group>";
49
+		};
50
+		58B511D21A9E6C8500147676 = {
51
+			isa = PBXGroup;
52
+			children = (
53
+				B3E7B5881CC2AC0600A0062D /* RNViewShot.h */,
54
+				B3E7B5891CC2AC0600A0062D /* RNViewShot.m */,
55
+				134814211AA4EA7D00B7C361 /* Products */,
56
+			);
57
+			sourceTree = "<group>";
58
+		};
59
+/* End PBXGroup section */
60
+
61
+/* Begin PBXNativeTarget section */
62
+		58B511DA1A9E6C8500147676 /* RNViewShot */ = {
63
+			isa = PBXNativeTarget;
64
+			buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNViewShot" */;
65
+			buildPhases = (
66
+				58B511D71A9E6C8500147676 /* Sources */,
67
+				58B511D81A9E6C8500147676 /* Frameworks */,
68
+				58B511D91A9E6C8500147676 /* CopyFiles */,
69
+			);
70
+			buildRules = (
71
+			);
72
+			dependencies = (
73
+			);
74
+			name = RNViewShot;
75
+			productName = RCTDataManager;
76
+			productReference = 134814201AA4EA6300B7C361 /* libRNViewShot.a */;
77
+			productType = "com.apple.product-type.library.static";
78
+		};
79
+/* End PBXNativeTarget section */
80
+
81
+/* Begin PBXProject section */
82
+		58B511D31A9E6C8500147676 /* Project object */ = {
83
+			isa = PBXProject;
84
+			attributes = {
85
+				LastUpgradeCheck = 0610;
86
+				ORGANIZATIONNAME = Facebook;
87
+				TargetAttributes = {
88
+					58B511DA1A9E6C8500147676 = {
89
+						CreatedOnToolsVersion = 6.1.1;
90
+					};
91
+				};
92
+			};
93
+			buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNViewShot" */;
94
+			compatibilityVersion = "Xcode 3.2";
95
+			developmentRegion = English;
96
+			hasScannedForEncodings = 0;
97
+			knownRegions = (
98
+				en,
99
+			);
100
+			mainGroup = 58B511D21A9E6C8500147676;
101
+			productRefGroup = 58B511D21A9E6C8500147676;
102
+			projectDirPath = "";
103
+			projectRoot = "";
104
+			targets = (
105
+				58B511DA1A9E6C8500147676 /* RNViewShot */,
106
+			);
107
+		};
108
+/* End PBXProject section */
109
+
110
+/* Begin PBXSourcesBuildPhase section */
111
+		58B511D71A9E6C8500147676 /* Sources */ = {
112
+			isa = PBXSourcesBuildPhase;
113
+			buildActionMask = 2147483647;
114
+			files = (
115
+				B3E7B58A1CC2AC0600A0062D /* RNViewShot.m in Sources */,
116
+			);
117
+			runOnlyForDeploymentPostprocessing = 0;
118
+		};
119
+/* End PBXSourcesBuildPhase section */
120
+
121
+/* Begin XCBuildConfiguration section */
122
+		58B511ED1A9E6C8500147676 /* Debug */ = {
123
+			isa = XCBuildConfiguration;
124
+			buildSettings = {
125
+				ALWAYS_SEARCH_USER_PATHS = NO;
126
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
127
+				CLANG_CXX_LIBRARY = "libc++";
128
+				CLANG_ENABLE_MODULES = YES;
129
+				CLANG_ENABLE_OBJC_ARC = YES;
130
+				CLANG_WARN_BOOL_CONVERSION = YES;
131
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
132
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
133
+				CLANG_WARN_EMPTY_BODY = YES;
134
+				CLANG_WARN_ENUM_CONVERSION = YES;
135
+				CLANG_WARN_INT_CONVERSION = YES;
136
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
137
+				CLANG_WARN_UNREACHABLE_CODE = YES;
138
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
139
+				COPY_PHASE_STRIP = NO;
140
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
141
+				GCC_C_LANGUAGE_STANDARD = gnu99;
142
+				GCC_DYNAMIC_NO_PIC = NO;
143
+				GCC_OPTIMIZATION_LEVEL = 0;
144
+				GCC_PREPROCESSOR_DEFINITIONS = (
145
+					"DEBUG=1",
146
+					"$(inherited)",
147
+				);
148
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
149
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
150
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
151
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
152
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
153
+				GCC_WARN_UNUSED_FUNCTION = YES;
154
+				GCC_WARN_UNUSED_VARIABLE = YES;
155
+				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
156
+				MTL_ENABLE_DEBUG_INFO = YES;
157
+				ONLY_ACTIVE_ARCH = YES;
158
+				SDKROOT = iphoneos;
159
+			};
160
+			name = Debug;
161
+		};
162
+		58B511EE1A9E6C8500147676 /* Release */ = {
163
+			isa = XCBuildConfiguration;
164
+			buildSettings = {
165
+				ALWAYS_SEARCH_USER_PATHS = NO;
166
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
167
+				CLANG_CXX_LIBRARY = "libc++";
168
+				CLANG_ENABLE_MODULES = YES;
169
+				CLANG_ENABLE_OBJC_ARC = YES;
170
+				CLANG_WARN_BOOL_CONVERSION = YES;
171
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
172
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
173
+				CLANG_WARN_EMPTY_BODY = YES;
174
+				CLANG_WARN_ENUM_CONVERSION = YES;
175
+				CLANG_WARN_INT_CONVERSION = YES;
176
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
177
+				CLANG_WARN_UNREACHABLE_CODE = YES;
178
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
179
+				COPY_PHASE_STRIP = YES;
180
+				ENABLE_NS_ASSERTIONS = NO;
181
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
182
+				GCC_C_LANGUAGE_STANDARD = gnu99;
183
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
184
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
185
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
186
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
187
+				GCC_WARN_UNUSED_FUNCTION = YES;
188
+				GCC_WARN_UNUSED_VARIABLE = YES;
189
+				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
190
+				MTL_ENABLE_DEBUG_INFO = NO;
191
+				SDKROOT = iphoneos;
192
+				VALIDATE_PRODUCT = YES;
193
+			};
194
+			name = Release;
195
+		};
196
+		58B511F01A9E6C8500147676 /* Debug */ = {
197
+			isa = XCBuildConfiguration;
198
+			buildSettings = {
199
+				HEADER_SEARCH_PATHS = (
200
+				"$(inherited)",
201
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
202
+					"$(SRCROOT)/../../../React/**",
203
+					"$(SRCROOT)/../../react-native/React/**",
204
+				);
205
+				LIBRARY_SEARCH_PATHS = "$(inherited)";
206
+				OTHER_LDFLAGS = "-ObjC";
207
+				PRODUCT_NAME = RNViewShot;
208
+				SKIP_INSTALL = YES;
209
+			};
210
+			name = Debug;
211
+		};
212
+		58B511F11A9E6C8500147676 /* Release */ = {
213
+			isa = XCBuildConfiguration;
214
+			buildSettings = {
215
+				HEADER_SEARCH_PATHS = (
216
+					"$(inherited)",
217
+					/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
218
+					"$(SRCROOT)/../../../React/**",
219
+					"$(SRCROOT)/../../react-native/React/**",
220
+				);
221
+				LIBRARY_SEARCH_PATHS = "$(inherited)";
222
+				OTHER_LDFLAGS = "-ObjC";
223
+				PRODUCT_NAME = RNViewShot;
224
+				SKIP_INSTALL = YES;
225
+			};
226
+			name = Release;
227
+		};
228
+/* End XCBuildConfiguration section */
229
+
230
+/* Begin XCConfigurationList section */
231
+		58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNViewShot" */ = {
232
+			isa = XCConfigurationList;
233
+			buildConfigurations = (
234
+				58B511ED1A9E6C8500147676 /* Debug */,
235
+				58B511EE1A9E6C8500147676 /* Release */,
236
+			);
237
+			defaultConfigurationIsVisible = 0;
238
+			defaultConfigurationName = Release;
239
+		};
240
+		58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNViewShot" */ = {
241
+			isa = XCConfigurationList;
242
+			buildConfigurations = (
243
+				58B511F01A9E6C8500147676 /* Debug */,
244
+				58B511F11A9E6C8500147676 /* Release */,
245
+			);
246
+			defaultConfigurationIsVisible = 0;
247
+			defaultConfigurationName = Release;
248
+		};
249
+/* End XCConfigurationList section */
250
+	};
251
+	rootObject = 58B511D31A9E6C8500147676 /* Project object */;
252
+}

+ 15
- 0
package.json View File

@@ -0,0 +1,15 @@
1
+
2
+{
3
+  "name": "react-native-view-shot",
4
+  "version": "1.0.0",
5
+  "description": "",
6
+  "main": "index.js",
7
+  "keywords": [
8
+    "react-native"
9
+  ],
10
+  "author": "",
11
+  "license": "",
12
+  "peerDependencies": {
13
+    "react-native": ">=0.30.0"
14
+  }
15
+}