Move RCTTest & takeSnapshot to RNTester (#23721)

Summary:
Part of: #23313.

This moves the `RCTTest` lib from `Libraries/RCTTest` to `RNTester/RCTTest`. This also removes `takeSnapshot` from React Native, and implements it as a standalone module in RNTester called `ScreenshotManager`.

[General] [Removed] - RCTTest & ReactNative.takeSnapshot
Pull Request resolved: https://github.com/facebook/react-native/pull/23721

Differential Revision: D14434796

Pulled By: PeteTheHeat

fbshipit-source-id: d6e103a0ea0b6702701cdb5ce8449163ca4628ce
This commit is contained in:
ericlewis
2019-03-14 11:21:06 -07:00
committed by Facebook Github Bot
parent d17e061c0e
commit fc94ade11c
28 changed files with 189 additions and 179 deletions

View File

@@ -24,19 +24,6 @@ invariant(
'UIManager is undefined. The native module config is probably incorrect.',
);
// In past versions of ReactNative users called UIManager.takeSnapshot()
// However takeSnapshot was moved to ReactNative in order to support flat
// bundles and to avoid a cyclic dependency between UIManager and ReactNative.
// UIManager.takeSnapshot still exists though. In order to avoid confusion or
// accidental usage, mask the method with a deprecation warning.
UIManager.__takeSnapshot = UIManager.takeSnapshot;
UIManager.takeSnapshot = function() {
invariant(
false,
'UIManager.takeSnapshot should not be called directly. ' +
'Use ReactNative.takeSnapshot instead.',
);
};
const triedLoadingConfig = new Set();
UIManager.getViewManagerConfig = function(viewManagerName: string) {
if (

View File

@@ -56,8 +56,6 @@ module.exports = [
'StyleConstants',
'AccessibilityEventTypes',
'UIView',
'__takeSnapshot',
'takeSnapshot',
'getViewManagerConfig',
'blur',
'focus',

View File

@@ -1,47 +0,0 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
const ReactNative = require('ReactNative');
const UIManager = require('UIManager');
/**
* Capture an image of the screen, window or an individual view. The image
* will be stored in a temporary file that will only exist for as long as the
* app is running.
*
* The `view` argument can be the literal string `window` if you want to
* capture the entire window, or it can be a reference to a specific
* React Native component.
*
* The `options` argument may include:
* - width/height (number) - the width and height of the image to capture.
* - format (string) - either 'png' or 'jpeg'. Defaults to 'png'.
* - quality (number) - the quality when using jpeg. 0.0 - 1.0 (default).
*
* Returns a Promise.
* @platform ios
*/
module.exports = function takeSnapshot(
view?: 'window' | React$Element<any> | number,
options?: {
width?: number,
height?: number,
format?: 'png' | 'jpeg',
quality?: number,
},
): Promise<any> {
if (typeof view !== 'number' && view !== 'window') {
view = ReactNative.findNodeHandle(view) || 'window';
}
// Call the hidden '__takeSnapshot' method; the main one throws an error to
// prevent accidental backwards-incompatible usage.
return UIManager.__takeSnapshot(view, options);
};

View File

@@ -346,9 +346,6 @@ module.exports = {
get requireNativeComponent() {
return require('requireNativeComponent');
},
get takeSnapshot() {
return require('takeSnapshot');
},
// Prop Types
get ColorPropType() {

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {TurboModule} from 'RCTExport';
import * as TurboModuleRegistry from 'TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {||};
takeSnapshot(id: string): Promise<string>;
}
const NativeModule = TurboModuleRegistry.get<Spec>('ScreenshotManager');
export function takeSnapshot(id: string): Promise<string> {
if (NativeModule != null) {
return NativeModule.takeSnapshot(id);
}
return Promise.reject();
}

View File

@@ -0,0 +1,12 @@
//
// RNTTakeScreenshot.h
// RNTester
//
// Created by Eric Lewis on 3/1/19.
// Copyright © 2019 Facebook. All rights reserved.
//
#import <React/RCTViewManager.h>
@interface ScreenshotManager : RCTViewManager
@end

View File

@@ -0,0 +1,84 @@
//
// RNTTakeScreenshot.m
// RNTester
//
// Created by Eric Lewis on 3/1/19.
// Copyright © 2019 Facebook. All rights reserved.
//
#import "Screenshot.h"
#import <React/RCTUIManager.h>
@implementation ScreenshotManager
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(takeScreenshot:(id /* NSString or NSNumber */)target
withOptions:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
// Get view
UIView *view;
if (target == nil || [target isEqual:@"window"]) {
view = RCTKeyWindow();
} else if ([target isKindOfClass:[NSNumber class]]) {
view = viewRegistry[target];
if (!view) {
RCTLogError(@"No view found with reactTag: %@", target);
return;
}
}
// Get options
CGSize size = [RCTConvert CGSize:options];
NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
// Capture image
if (size.width < 0.1 || size.height < 0.1) {
size = view.bounds.size;
}
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
BOOL success = [view drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (!success || !image) {
reject(RCTErrorUnspecified, @"Failed to capture view snapshot.", nil);
return;
}
// Convert image to data (on a background thread)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data;
if ([format isEqualToString:@"png"]) {
data = UIImagePNGRepresentation(image);
} else if ([format isEqualToString:@"jpeg"]) {
CGFloat quality = [RCTConvert CGFloat:options[@"quality"] ?: @1];
data = UIImageJPEGRepresentation(image, quality);
} else {
RCTLogError(@"Unsupported image format: %@", format);
return;
}
// Save to a temp file
NSError *error = nil;
NSString *tempFilePath = RCTTempFilePath(format, &error);
if (tempFilePath) {
if ([data writeToFile:tempFilePath options:(NSDataWritingOptions)0 error:&error]) {
resolve(tempFilePath);
return;
}
}
// If we reached here, something went wrong
reject(RCTErrorUnspecified, error.localizedDescription, error);
});
}];
}
@end

View File

@@ -1,12 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
@@ -30,4 +30,6 @@ type SnapshotViewNativeType = Class<NativeComponent<NativeProps>>;
const requireNativeComponent = require('requireNativeComponent');
module.exports = ((requireNativeComponent('RCTSnapshot'):any): SnapshotViewNativeType);
module.exports = ((requireNativeComponent(
'RCTSnapshot',
): any): SnapshotViewNativeType);

View File

@@ -35,7 +35,6 @@
1497CFB01B21F5E400C1F8F2 /* RCTFontTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA81B21F5E400C1F8F2 /* RCTFontTests.m */; };
1497CFB11B21F5E400C1F8F2 /* RCTEventDispatcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */; };
1497CFB31B21F5E400C1F8F2 /* RCTUIManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */; };
14B6DA821B276C5900BF4DD1 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58005BEE1ABA80530062E044 /* libRCTTest.a */; };
14D6D7111B220EB3001FB087 /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14D6D7101B220EB3001FB087 /* libOCMock.a */; };
14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; };
14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134A8A251AACED6A00945AAE /* libRCTGeolocation.a */; };
@@ -43,7 +42,6 @@
14D6D7221B2222EF001FB087 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; };
14D6D7231B2222EF001FB087 /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DC67F11AB71876001358AB /* libRCTPushNotification.a */; };
14D6D7241B2222EF001FB087 /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 834C36D21AF8DA610019C93C /* libRCTSettings.a */; };
14D6D7251B2222EF001FB087 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58005BEE1ABA80530062E044 /* libRCTTest.a */; };
14D6D7261B2222EF001FB087 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FEF1AA914B8003F314A /* libRCTText.a */; };
14D6D7271B2222EF001FB087 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */; };
14D6D7281B2222EF001FB087 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; };
@@ -62,7 +60,6 @@
2D4624FB1DA2EAC300C74D09 /* RCTRootViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */; };
2D4624FD1DA2EAC300C74D09 /* RNTesterSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 143BC5A01B21E45C00462512 /* RNTesterSnapshotTests.m */; };
2D4624FE1DA2EAC300C74D09 /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; };
2D4625351DA2EBBE00C74D09 /* libRCTTest-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323CC1DA2DD8B000FE1B8 /* libRCTTest-tvOS.a */; };
2D4BD8D21DA2E20D005AC8A8 /* RCTURLUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B6C1A21C34225900D3FAF5 /* RCTURLUtilsTests.m */; };
2D4BD8D31DA2E20D005AC8A8 /* RCTBundleURLProviderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FF44371CF6111500720EFD /* RCTBundleURLProviderTests.m */; };
2D4BD8D41DA2E20D005AC8A8 /* RCTAllocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */; };
@@ -103,7 +100,6 @@
2DE7E8011FB2A4F3009E225D /* libRCTNetwork-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323C31DA2DD8B000FE1B8 /* libRCTNetwork-tvOS.a */; };
2DE7E8021FB2A4F3009E225D /* libRCTPushNotification-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D05746C1DE6008900184BB4 /* libRCTPushNotification-tvOS.a */; };
2DE7E8031FB2A4F3009E225D /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323C81DA2DD8B000FE1B8 /* libRCTSettings-tvOS.a */; };
2DE7E8041FB2A4F3009E225D /* libRCTTest-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323CC1DA2DD8B000FE1B8 /* libRCTTest-tvOS.a */; };
2DE7E8051FB2A4F3009E225D /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D01DA2DD8B000FE1B8 /* libRCTText-tvOS.a */; };
2DE7E8061FB2A4F3009E225D /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D51DA2DD8B000FE1B8 /* libRCTWebSocket-tvOS.a */; };
2DE7E8071FB2A4F3009E225D /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D91DA2DD8B000FE1B8 /* libReact.a */; };
@@ -121,6 +117,11 @@
3DD981D61D33C6FB007DC7BE /* RNTesterUnitTestsBundle.js in Resources */ = {isa = PBXBuildFile; fileRef = 3DD981D51D33C6FB007DC7BE /* RNTesterUnitTestsBundle.js */; };
52C11BBB1EEACA7100C1A058 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5281CA511EEAC9A700AC40CD /* libRCTBlob.a */; };
52C11BE11EEACA7800C1A058 /* libRCTBlob-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5281CA531EEAC9A700AC40CD /* libRCTBlob-tvOS.a */; };
6862DFC62229DCE600684E03 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6862DFAC2229DCC400684E03 /* libRCTTest.a */; };
6862DFC72229DD1000684E03 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6862DFAC2229DCC400684E03 /* libRCTTest.a */; };
6862DFC82229DD1900684E03 /* libRCTTest-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6862DFAE2229DCC400684E03 /* libRCTTest-tvOS.a */; };
6862DFC92229DD2100684E03 /* libRCTTest-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6862DFAE2229DCC400684E03 /* libRCTTest-tvOS.a */; };
6862DFCF2229DFCC00684E03 /* Screenshot.m in Sources */ = {isa = PBXBuildFile; fileRef = 6862DFCE2229DFCC00684E03 /* Screenshot.m */; };
68FF44381CF6111500720EFD /* RCTBundleURLProviderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 68FF44371CF6111500720EFD /* RCTBundleURLProviderTests.m */; };
834C36EC1AF8DED70019C93C /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 834C36D21AF8DA610019C93C /* libRCTSettings.a */; };
83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; };
@@ -286,13 +287,6 @@
remoteGlobalIDString = 2D2A28611D9B046600D4039D;
remoteInfo = "RCTSettings-tvOS";
};
2DD323CB1DA2DD8B000FE1B8 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 58005BE41ABA80530062E044 /* RCTTest.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 2D2A286E1D9B047700D4039D;
remoteInfo = "RCTTest-tvOS";
};
2DD323CF1DA2DD8B000FE1B8 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13417FEA1AA914B8003F314A /* RCTText.xcodeproj */;
@@ -419,13 +413,20 @@
remoteGlobalIDString = ADD01A681E09402E00F6D226;
remoteInfo = "RCTBlob-tvOS";
};
58005BED1ABA80530062E044 /* PBXContainerItemProxy */ = {
6862DFAB2229DCC400684E03 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 58005BE41ABA80530062E044 /* RCTTest.xcodeproj */;
containerPortal = 6862DF932229DCC400684E03 /* RCTTest.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 580C376F1AB104AF0015E709;
remoteInfo = RCTTest;
};
6862DFAD2229DCC400684E03 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 6862DF932229DCC400684E03 /* RCTTest.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 2D2A286E1D9B047700D4039D;
remoteInfo = "RCTTest-tvOS";
};
834C36D11AF8DA610019C93C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */;
@@ -558,7 +559,9 @@
3DB99D0B1BA0340600302749 /* RNTesterIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNTesterIntegrationTests.m; sourceTree = "<group>"; };
3DD981D51D33C6FB007DC7BE /* RNTesterUnitTestsBundle.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = RNTesterUnitTestsBundle.js; sourceTree = "<group>"; };
5281CA4B1EEAC9A700AC40CD /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = "<group>"; };
58005BE41ABA80530062E044 /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = ../Libraries/RCTTest/RCTTest.xcodeproj; sourceTree = "<group>"; };
6862DF932229DCC400684E03 /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = RCTTest/RCTTest.xcodeproj; sourceTree = "<group>"; };
6862DFCD2229DFCB00684E03 /* Screenshot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Screenshot.h; sourceTree = "<group>"; };
6862DFCE2229DFCC00684E03 /* Screenshot.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Screenshot.m; sourceTree = "<group>"; };
68FF44371CF6111500720EFD /* RCTBundleURLProviderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBundleURLProviderTests.m; sourceTree = "<group>"; };
83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManagerScenarioTests.m; sourceTree = "<group>"; };
8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderTests.m; sourceTree = "<group>"; };
@@ -588,7 +591,7 @@
14D6D7221B2222EF001FB087 /* libRCTNetwork.a in Frameworks */,
14D6D7231B2222EF001FB087 /* libRCTPushNotification.a in Frameworks */,
14D6D7241B2222EF001FB087 /* libRCTSettings.a in Frameworks */,
14D6D7251B2222EF001FB087 /* libRCTTest.a in Frameworks */,
6862DFC62229DCE600684E03 /* libRCTTest.a in Frameworks */,
14D6D7261B2222EF001FB087 /* libRCTText.a in Frameworks */,
14D6D7271B2222EF001FB087 /* libRCTVibration.a in Frameworks */,
14D6D7281B2222EF001FB087 /* libRCTWebSocket.a in Frameworks */,
@@ -624,7 +627,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
14B6DA821B276C5900BF4DD1 /* libRCTTest.a in Frameworks */,
6862DFC72229DD1000684E03 /* libRCTTest.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -632,7 +635,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2D4625351DA2EBBE00C74D09 /* libRCTTest-tvOS.a in Frameworks */,
6862DFC92229DD2100684E03 /* libRCTTest-tvOS.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -659,6 +662,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
6862DFC82229DD1900684E03 /* libRCTTest-tvOS.a in Frameworks */,
2DE7E7FD1FB2A4F3009E225D /* libRCTAnimation.a in Frameworks */,
2DE7E7FE1FB2A4F3009E225D /* libRCTBlob-tvOS.a in Frameworks */,
2DE7E7FF1FB2A4F3009E225D /* libRCTImage-tvOS.a in Frameworks */,
@@ -666,7 +670,6 @@
2DE7E8011FB2A4F3009E225D /* libRCTNetwork-tvOS.a in Frameworks */,
2DE7E8021FB2A4F3009E225D /* libRCTPushNotification-tvOS.a in Frameworks */,
2DE7E8031FB2A4F3009E225D /* libRCTSettings-tvOS.a in Frameworks */,
2DE7E8041FB2A4F3009E225D /* libRCTTest-tvOS.a in Frameworks */,
2DE7E8051FB2A4F3009E225D /* libRCTText-tvOS.a in Frameworks */,
2DE7E8061FB2A4F3009E225D /* libRCTWebSocket-tvOS.a in Frameworks */,
2DE7E8071FB2A4F3009E225D /* libReact.a in Frameworks */,
@@ -699,7 +702,7 @@
134180261AA91779003F314A /* RCTNetwork.xcodeproj */,
14DC67E71AB71876001358AB /* RCTPushNotification.xcodeproj */,
13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */,
58005BE41ABA80530062E044 /* RCTTest.xcodeproj */,
6862DF932229DCC400684E03 /* RCTTest.xcodeproj */,
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */,
D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */,
139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */,
@@ -778,6 +781,7 @@
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
AFEACAB12223EB2C004E5198 /* NativeExampleModules */,
6862DFD02229E1DE00684E03 /* NativeModuleExample */,
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
13B07FB71A68108700A75B9A /* main.m */,
1323F18D1C04ABAC0091BED0 /* Supporting Files */,
@@ -976,15 +980,24 @@
name = Products;
sourceTree = "<group>";
};
58005BE51ABA80530062E044 /* Products */ = {
6862DF942229DCC400684E03 /* Products */ = {
isa = PBXGroup;
children = (
58005BEE1ABA80530062E044 /* libRCTTest.a */,
2DD323CC1DA2DD8B000FE1B8 /* libRCTTest-tvOS.a */,
6862DFAC2229DCC400684E03 /* libRCTTest.a */,
6862DFAE2229DCC400684E03 /* libRCTTest-tvOS.a */,
);
name = Products;
sourceTree = "<group>";
};
6862DFD02229E1DE00684E03 /* NativeModuleExample */ = {
isa = PBXGroup;
children = (
6862DFCD2229DFCB00684E03 /* Screenshot.h */,
6862DFCE2229DFCC00684E03 /* Screenshot.m */,
);
path = NativeModuleExample;
sourceTree = "<group>";
};
834C36CE1AF8DA610019C93C /* Products */ = {
isa = PBXGroup;
children = (
@@ -1261,8 +1274,8 @@
ProjectRef = 13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */;
},
{
ProductGroup = 58005BE51ABA80530062E044 /* Products */;
ProjectRef = 58005BE41ABA80530062E044 /* RCTTest.xcodeproj */;
ProductGroup = 6862DF942229DCC400684E03 /* Products */;
ProjectRef = 6862DF932229DCC400684E03 /* RCTTest.xcodeproj */;
},
{
ProductGroup = 13417FEB1AA914B8003F314A /* Products */;
@@ -1428,13 +1441,6 @@
remoteRef = 2DD323C71DA2DD8B000FE1B8 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
2DD323CC1DA2DD8B000FE1B8 /* libRCTTest-tvOS.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libRCTTest-tvOS.a";
remoteRef = 2DD323CB1DA2DD8B000FE1B8 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
2DD323D01DA2DD8B000FE1B8 /* libRCTText-tvOS.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
@@ -1554,11 +1560,18 @@
remoteRef = 5281CA521EEAC9A700AC40CD /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
58005BEE1ABA80530062E044 /* libRCTTest.a */ = {
6862DFAC2229DCC400684E03 /* libRCTTest.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTTest.a;
remoteRef = 58005BED1ABA80530062E044 /* PBXContainerItemProxy */;
remoteRef = 6862DFAB2229DCC400684E03 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
6862DFAE2229DCC400684E03 /* libRCTTest-tvOS.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libRCTTest-tvOS.a";
remoteRef = 6862DFAD2229DCC400684E03 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
834C36D21AF8DA610019C93C /* libRCTSettings.a */ = {
@@ -1739,6 +1752,7 @@
27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
AFEACA842223EB05004E5198 /* CrashyCrash.m in Sources */,
6862DFCF2229DFCC00684E03 /* Screenshot.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -15,11 +15,12 @@ const ReactNative = require('react-native');
const {
ActionSheetIOS,
StyleSheet,
takeSnapshot,
Text,
View,
Alert,
NativeModules,
} = ReactNative;
const ScreenshotManager = NativeModules.ScreenshotManager;
const BUTTONS = ['Option 0', 'Option 1', 'Option 2', 'Delete', 'Cancel'];
const DESTRUCTIVE_INDEX = 3;
@@ -199,7 +200,7 @@ class ShareScreenshotExample extends React.Component<
showShareActionSheet = () => {
// Take the snapshot (returns a temp file uri)
takeSnapshot('window')
ScreenshotManager.takeScreenshot('window')
.then(uri => {
// Share image data
ActionSheetIOS.showShareActionSheetWithOptions(
@@ -254,7 +255,7 @@ class ShareScreenshotAnchorExample extends React.Component<
showShareActionSheet = () => {
// Take the snapshot (returns a temp file uri)
takeSnapshot('window')
ScreenshotManager.takeScreenshot('window')
.then(uri => {
// Share image data
ActionSheetIOS.showShareActionSheetWithOptions(

View File

@@ -11,7 +11,8 @@
const React = require('react');
const ReactNative = require('react-native');
const {Alert, Image, StyleSheet, Text, View} = ReactNative;
const {Alert, Image, NativeModules, StyleSheet, Text, View} = ReactNative;
const ScreenshotManager = NativeModules.ScreenshotManager;
class ScreenshotExample extends React.Component<{}, $FlowFixMeState> {
state = {
@@ -30,7 +31,7 @@ class ScreenshotExample extends React.Component<{}, $FlowFixMeState> {
}
takeScreenshot = () => {
ReactNative.takeSnapshot('window', {format: 'jpeg', quality: 0.8}) // See UIManager.js for options
ScreenshotManager.takeScreenshot('window', {format: 'jpeg', quality: 0.8}) // See UIManager.js for options
.then(uri => this.setState({uri}))
.catch(error => Alert.alert(error));
};

View File

@@ -1364,73 +1364,6 @@ RCT_EXPORT_METHOD(measureLayoutRelativeToParent:(nonnull NSNumber *)reactTag
RCTMeasureLayout(shadowView, shadowView.reactSuperview, callback);
}
RCT_EXPORT_METHOD(takeSnapshot:(id /* NSString or NSNumber */)target
withOptions:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
[self addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
// Get view
UIView *view;
if (target == nil || [target isEqual:@"window"]) {
view = RCTKeyWindow();
} else if ([target isKindOfClass:[NSNumber class]]) {
view = viewRegistry[target];
if (!view) {
RCTLogError(@"No view found with reactTag: %@", target);
return;
}
}
// Get options
CGSize size = [RCTConvert CGSize:options];
NSString *format = [RCTConvert NSString:options[@"format"] ?: @"png"];
// Capture image
if (size.width < 0.1 || size.height < 0.1) {
size = view.bounds.size;
}
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
BOOL success = [view drawViewHierarchyInRect:(CGRect){CGPointZero, size} afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if (!success || !image) {
reject(RCTErrorUnspecified, @"Failed to capture view snapshot.", nil);
return;
}
// Convert image to data (on a background thread)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data;
if ([format isEqualToString:@"png"]) {
data = UIImagePNGRepresentation(image);
} else if ([format isEqualToString:@"jpeg"]) {
CGFloat quality = [RCTConvert CGFloat:options[@"quality"] ?: @1];
data = UIImageJPEGRepresentation(image, quality);
} else {
RCTLogError(@"Unsupported image format: %@", format);
return;
}
// Save to a temp file
NSError *error = nil;
NSString *tempFilePath = RCTTempFilePath(format, &error);
if (tempFilePath) {
if ([data writeToFile:tempFilePath options:(NSDataWritingOptions)0 error:&error]) {
resolve(tempFilePath);
return;
}
}
// If we reached here, something went wrong
reject(RCTErrorUnspecified, error.localizedDescription, error);
});
}];
}
/**
* JS sets what *it* considers to be the responder. Later, scroll views can use
* this in order to determine if scrolling is appropriate.