Updates from Tue 9 Jun

This commit is contained in:
Spencer Ahrens 2015-06-09 17:20:30 -07:00
commit 205e2659a1
104 changed files with 3914 additions and 1357 deletions

View File

@ -45,7 +45,7 @@ var NavigatorIOSColors = React.createClass({
render: function() {
// Set StatusBar with light contents to get better contrast
StatusBarIOS.setStyle(StatusBarIOS.Style.lightContent);
StatusBarIOS.setStyle('light-content');
return (
<NavigatorIOS
@ -55,7 +55,7 @@ var NavigatorIOSColors = React.createClass({
title: '<NavigatorIOS>',
rightButtonTitle: 'Done',
onRightButtonPress: () => {
StatusBarIOS.setStyle(StatusBarIOS.Style['default']);
StatusBarIOS.setStyle('default');
this.props.onExampleExit();
},
passProps: {

View File

@ -7,20 +7,42 @@
objects = {
/* Begin PBXBuildFile section */
004D28A31AAF61C70097A701 /* UIExplorerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 004D28A21AAF61C70097A701 /* UIExplorerTests.m */; };
13417FE91AA91432003F314A /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FE81AA91428003F314A /* libRCTImage.a */; };
134180011AA9153C003F314A /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FEF1AA914B8003F314A /* libRCTText.a */; };
1341802C1AA9178B003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341802B1AA91779003F314A /* libRCTNetwork.a */; };
134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1344545A1AAFCAAE003F0779 /* libRCTAdSupport.a */; };
134A8A2A1AACED7A00945AAE /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134A8A251AACED6A00945AAE /* libRCTGeolocation.a */; };
1353F5461B0E64F9009B4FAC /* ClippingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1353F5451B0E64F9009B4FAC /* ClippingTests.m */; };
139FDEDB1B0651FB00C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDED91B0651EA00C62182 /* libRCTWebSocket.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
141FC1211B222EBB004D5FFB /* IntegrationTestsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 141FC1201B222EBB004D5FFB /* IntegrationTestsTests.m */; };
143BC5A11B21E45C00462512 /* UIExplorerIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 143BC5A01B21E45C00462512 /* UIExplorerIntegrationTests.m */; };
144D21241B2204C5006DB32B /* RCTClippingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 144D21231B2204C5006DB32B /* RCTClippingTests.m */; };
147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; };
1497CFAC1B21F5E400C1F8F2 /* RCTAllocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */; };
1497CFAD1B21F5E400C1F8F2 /* RCTBridgeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */; };
1497CFAE1B21F5E400C1F8F2 /* RCTContextExecutorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
1497CFAF1B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA71B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m */; };
1497CFB01B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA81B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m */; };
1497CFB11B21F5E400C1F8F2 /* RCTEventDispatcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */; };
1497CFB21B21F5E400C1F8F2 /* RCTSparseArrayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFAA1B21F5E400C1F8F2 /* RCTSparseArrayTests.m */; };
1497CFB31B21F5E400C1F8F2 /* RCTUIManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */; };
14AADF051AC3DBB1002390C9 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; };
14D6D7111B220EB3001FB087 /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14D6D7101B220EB3001FB087 /* libOCMock.a */; };
14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; };
14D6D71F1B2222EF001FB087 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1344545A1AAFCAAE003F0779 /* libRCTAdSupport.a */; };
14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 134A8A251AACED6A00945AAE /* libRCTGeolocation.a */; };
14D6D7211B2222EF001FB087 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13417FE81AA91428003F314A /* libRCTImage.a */; };
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 */; };
14D6D7291B2222EF001FB087 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; };
14DC67F41AB71881001358AB /* libRCTPushNotification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14DC67F11AB71876001358AB /* libRCTPushNotification.a */; };
58005BF21ABA80A60062E044 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58005BEE1ABA80530062E044 /* libRCTTest.a */; };
834C36EC1AF8DED70019C93C /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 834C36D21AF8DA610019C93C /* libRCTSettings.a */; };
@ -28,13 +50,6 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
004D28A41AAF61C70097A701 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = UIExplorer;
};
13417FE71AA91428003F314A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13417FE31AA91428003F314A /* RCTImage.xcodeproj */;
@ -77,6 +92,13 @@
remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
remoteInfo = RCTWebSocket;
};
143BC59B1B21E3E100462512 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = UIExplorer;
};
147CED4A1AB34F8C00DA3E4C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */;
@ -122,15 +144,12 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
004D289E1AAF61C70097A701 /* UIExplorerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIExplorerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
004D28A11AAF61C70097A701 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
004D28A21AAF61C70097A701 /* UIExplorerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UIExplorerTests.m; sourceTree = "<group>"; };
004D289E1AAF61C70097A701 /* UIExplorerUnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIExplorerUnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
13417FE31AA91428003F314A /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
1353F5451B0E64F9009B4FAC /* ClippingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ClippingTests.m; sourceTree = "<group>"; };
139FDECA1B0651EA00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* UIExplorer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIExplorer.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = UIExplorer/AppDelegate.h; sourceTree = "<group>"; };
@ -140,7 +159,37 @@
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = UIExplorer/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = UIExplorer/main.m; sourceTree = "<group>"; };
13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../../Libraries/Settings/RCTSettings.xcodeproj; sourceTree = "<group>"; };
141FC1201B222EBB004D5FFB /* IntegrationTestsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IntegrationTestsTests.m; sourceTree = "<group>"; };
143BC57E1B21E18100462512 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
143BC5811B21E18100462512 /* testLayoutExampleSnapshot_1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testLayoutExampleSnapshot_1@2x.png"; sourceTree = "<group>"; };
143BC5821B21E18100462512 /* testSliderExampleSnapshot_1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testSliderExampleSnapshot_1@2x.png"; sourceTree = "<group>"; };
143BC5831B21E18100462512 /* testSwitchExampleSnapshot_1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testSwitchExampleSnapshot_1@2x.png"; sourceTree = "<group>"; };
143BC5841B21E18100462512 /* testTabBarExampleSnapshot_1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testTabBarExampleSnapshot_1@2x.png"; sourceTree = "<group>"; };
143BC5851B21E18100462512 /* testTextExampleSnapshot_1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testTextExampleSnapshot_1@2x.png"; sourceTree = "<group>"; };
143BC5861B21E18100462512 /* testViewExampleSnapshot_1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testViewExampleSnapshot_1@2x.png"; sourceTree = "<group>"; };
143BC5951B21E3E100462512 /* UIExplorerIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIExplorerIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
143BC5981B21E3E100462512 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
143BC5A01B21E45C00462512 /* UIExplorerIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIExplorerIntegrationTests.m; sourceTree = "<group>"; };
144D21231B2204C5006DB32B /* RCTClippingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTClippingTests.m; sourceTree = "<group>"; };
1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAllocationTests.m; sourceTree = "<group>"; };
1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBridgeTests.m; sourceTree = "<group>"; };
1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTContextExecutorTests.m; sourceTree = "<group>"; };
1497CFA71B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert_NSURLTests.m; sourceTree = "<group>"; };
1497CFA81B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert_UIFontTests.m; sourceTree = "<group>"; };
1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTEventDispatcherTests.m; sourceTree = "<group>"; };
1497CFAA1B21F5E400C1F8F2 /* RCTSparseArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSparseArrayTests.m; sourceTree = "<group>"; };
1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManagerTests.m; sourceTree = "<group>"; };
14AADEFF1AC3DB95002390C9 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = "<group>"; };
14D6D7021B220AE3001FB087 /* NSNotificationCenter+OCMAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OCMAdditions.h"; sourceTree = "<group>"; };
14D6D7031B220AE3001FB087 /* OCMArg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMArg.h; sourceTree = "<group>"; };
14D6D7041B220AE3001FB087 /* OCMConstraint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMConstraint.h; sourceTree = "<group>"; };
14D6D7051B220AE3001FB087 /* OCMLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMLocation.h; sourceTree = "<group>"; };
14D6D7061B220AE3001FB087 /* OCMMacroState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMMacroState.h; sourceTree = "<group>"; };
14D6D7071B220AE3001FB087 /* OCMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMock.h; sourceTree = "<group>"; };
14D6D7081B220AE3001FB087 /* OCMockObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMockObject.h; sourceTree = "<group>"; };
14D6D7091B220AE3001FB087 /* OCMRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMRecorder.h; sourceTree = "<group>"; };
14D6D70A1B220AE3001FB087 /* OCMStubRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMStubRecorder.h; sourceTree = "<group>"; };
14D6D7101B220EB3001FB087 /* libOCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libOCMock.a; sourceTree = "<group>"; };
14DC67E71AB71876001358AB /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = ../../Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj; sourceTree = "<group>"; };
14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../../Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
58005BE41ABA80530062E044 /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = ../../Libraries/RCTTest/RCTTest.xcodeproj; sourceTree = "<group>"; };
@ -152,6 +201,19 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */,
14D6D71F1B2222EF001FB087 /* libRCTAdSupport.a in Frameworks */,
14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */,
14D6D7211B2222EF001FB087 /* libRCTImage.a in Frameworks */,
14D6D7221B2222EF001FB087 /* libRCTNetwork.a in Frameworks */,
14D6D7231B2222EF001FB087 /* libRCTPushNotification.a in Frameworks */,
14D6D7241B2222EF001FB087 /* libRCTSettings.a in Frameworks */,
14D6D7251B2222EF001FB087 /* libRCTTest.a in Frameworks */,
14D6D7261B2222EF001FB087 /* libRCTText.a in Frameworks */,
14D6D7271B2222EF001FB087 /* libRCTVibration.a in Frameworks */,
14D6D7281B2222EF001FB087 /* libRCTWebSocket.a in Frameworks */,
14D6D7291B2222EF001FB087 /* libReact.a in Frameworks */,
14D6D7111B220EB3001FB087 /* libOCMock.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -174,27 +236,16 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
143BC5921B21E3E100462512 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
004D289F1AAF61C70097A701 /* UIExplorerTests */ = {
isa = PBXGroup;
children = (
004D28A21AAF61C70097A701 /* UIExplorerTests.m */,
1353F5451B0E64F9009B4FAC /* ClippingTests.m */,
004D28A01AAF61C70097A701 /* Supporting Files */,
);
path = UIExplorerTests;
sourceTree = "<group>";
};
004D28A01AAF61C70097A701 /* Supporting Files */ = {
isa = PBXGroup;
children = (
004D28A11AAF61C70097A701 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
1316A21D1AA397F400C0188E /* Libraries */ = {
isa = PBXGroup;
children = (
@ -275,6 +326,65 @@
name = UIExplorer;
sourceTree = "<group>";
};
143BC57C1B21E18100462512 /* UIExplorerUnitTests */ = {
isa = PBXGroup;
children = (
1497CFA41B21F5E400C1F8F2 /* RCTAllocationTests.m */,
1497CFA51B21F5E400C1F8F2 /* RCTBridgeTests.m */,
144D21231B2204C5006DB32B /* RCTClippingTests.m */,
1497CFA61B21F5E400C1F8F2 /* RCTContextExecutorTests.m */,
1497CFA71B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m */,
1497CFA81B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m */,
1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */,
1497CFAA1B21F5E400C1F8F2 /* RCTSparseArrayTests.m */,
1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */,
143BC57E1B21E18100462512 /* Info.plist */,
14D6D7101B220EB3001FB087 /* libOCMock.a */,
14D6D7011B220AE3001FB087 /* OCMock */,
143BC57F1B21E18100462512 /* ReferenceImages */,
);
path = UIExplorerUnitTests;
sourceTree = "<group>";
};
143BC57F1B21E18100462512 /* ReferenceImages */ = {
isa = PBXGroup;
children = (
143BC5801B21E18100462512 /* Examples-UIExplorer-UIExplorerApp */,
);
path = ReferenceImages;
sourceTree = "<group>";
};
143BC5801B21E18100462512 /* Examples-UIExplorer-UIExplorerApp */ = {
isa = PBXGroup;
children = (
143BC5811B21E18100462512 /* testLayoutExampleSnapshot_1@2x.png */,
143BC5821B21E18100462512 /* testSliderExampleSnapshot_1@2x.png */,
143BC5831B21E18100462512 /* testSwitchExampleSnapshot_1@2x.png */,
143BC5841B21E18100462512 /* testTabBarExampleSnapshot_1@2x.png */,
143BC5851B21E18100462512 /* testTextExampleSnapshot_1@2x.png */,
143BC5861B21E18100462512 /* testViewExampleSnapshot_1@2x.png */,
);
path = "Examples-UIExplorer-UIExplorerApp";
sourceTree = "<group>";
};
143BC5961B21E3E100462512 /* UIExplorerIntegrationTests */ = {
isa = PBXGroup;
children = (
141FC1201B222EBB004D5FFB /* IntegrationTestsTests.m */,
143BC5A01B21E45C00462512 /* UIExplorerIntegrationTests.m */,
143BC5971B21E3E100462512 /* Supporting Files */,
);
path = UIExplorerIntegrationTests;
sourceTree = "<group>";
};
143BC5971B21E3E100462512 /* Supporting Files */ = {
isa = PBXGroup;
children = (
143BC5981B21E3E100462512 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
147CED471AB34F8C00DA3E4C /* Products */ = {
isa = PBXGroup;
children = (
@ -291,6 +401,29 @@
name = Products;
sourceTree = "<group>";
};
14D6D6EA1B2205C0001FB087 /* OCMock */ = {
isa = PBXGroup;
children = (
);
path = OCMock;
sourceTree = "<group>";
};
14D6D7011B220AE3001FB087 /* OCMock */ = {
isa = PBXGroup;
children = (
14D6D7021B220AE3001FB087 /* NSNotificationCenter+OCMAdditions.h */,
14D6D7031B220AE3001FB087 /* OCMArg.h */,
14D6D7041B220AE3001FB087 /* OCMConstraint.h */,
14D6D7051B220AE3001FB087 /* OCMLocation.h */,
14D6D7061B220AE3001FB087 /* OCMMacroState.h */,
14D6D7071B220AE3001FB087 /* OCMock.h */,
14D6D7081B220AE3001FB087 /* OCMockObject.h */,
14D6D7091B220AE3001FB087 /* OCMRecorder.h */,
14D6D70A1B220AE3001FB087 /* OCMStubRecorder.h */,
);
path = OCMock;
sourceTree = "<group>";
};
14DC67E81AB71876001358AB /* Products */ = {
isa = PBXGroup;
children = (
@ -320,7 +453,9 @@
children = (
13B07FAE1A68108700A75B9A /* UIExplorer */,
1316A21D1AA397F400C0188E /* Libraries */,
004D289F1AAF61C70097A701 /* UIExplorerTests */,
143BC57C1B21E18100462512 /* UIExplorerUnitTests */,
143BC5961B21E3E100462512 /* UIExplorerIntegrationTests */,
14D6D6EA1B2205C0001FB087 /* OCMock */,
83CBBA001A601CBA00E9B192 /* Products */,
);
indentWidth = 2;
@ -331,7 +466,8 @@
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* UIExplorer.app */,
004D289E1AAF61C70097A701 /* UIExplorerTests.xctest */,
004D289E1AAF61C70097A701 /* UIExplorerUnitTests.xctest */,
143BC5951B21E3E100462512 /* UIExplorerIntegrationTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@ -347,9 +483,9 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
004D289D1AAF61C70097A701 /* UIExplorerTests */ = {
004D289D1AAF61C70097A701 /* UIExplorerUnitTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 004D28AD1AAF61C70097A701 /* Build configuration list for PBXNativeTarget "UIExplorerTests" */;
buildConfigurationList = 004D28AD1AAF61C70097A701 /* Build configuration list for PBXNativeTarget "UIExplorerUnitTests" */;
buildPhases = (
004D289A1AAF61C70097A701 /* Sources */,
004D289B1AAF61C70097A701 /* Frameworks */,
@ -358,11 +494,10 @@
buildRules = (
);
dependencies = (
004D28A51AAF61C70097A701 /* PBXTargetDependency */,
);
name = UIExplorerTests;
name = UIExplorerUnitTests;
productName = UIExplorerTests;
productReference = 004D289E1AAF61C70097A701 /* UIExplorerTests.xctest */;
productReference = 004D289E1AAF61C70097A701 /* UIExplorerUnitTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
13B07F861A680F5B00A75B9A /* UIExplorer */ = {
@ -382,6 +517,24 @@
productReference = 13B07F961A680F5B00A75B9A /* UIExplorer.app */;
productType = "com.apple.product-type.application";
};
143BC5941B21E3E100462512 /* UIExplorerIntegrationTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 143BC59D1B21E3E100462512 /* Build configuration list for PBXNativeTarget "UIExplorerIntegrationTests" */;
buildPhases = (
143BC5911B21E3E100462512 /* Sources */,
143BC5921B21E3E100462512 /* Frameworks */,
143BC5931B21E3E100462512 /* Resources */,
);
buildRules = (
);
dependencies = (
143BC59C1B21E3E100462512 /* PBXTargetDependency */,
);
name = UIExplorerIntegrationTests;
productName = UIExplorerIntegrationTests;
productReference = 143BC5951B21E3E100462512 /* UIExplorerIntegrationTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@ -393,6 +546,9 @@
TargetAttributes = {
004D289D1AAF61C70097A701 = {
CreatedOnToolsVersion = 6.1.1;
};
143BC5941B21E3E100462512 = {
CreatedOnToolsVersion = 6.3.2;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
};
@ -461,7 +617,8 @@
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* UIExplorer */,
004D289D1AAF61C70097A701 /* UIExplorerTests */,
004D289D1AAF61C70097A701 /* UIExplorerUnitTests */,
143BC5941B21E3E100462512 /* UIExplorerIntegrationTests */,
);
};
/* End PBXProject section */
@ -570,6 +727,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
143BC5931B21E3E100462512 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -577,8 +741,15 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
004D28A31AAF61C70097A701 /* UIExplorerTests.m in Sources */,
1353F5461B0E64F9009B4FAC /* ClippingTests.m in Sources */,
1497CFB01B21F5E400C1F8F2 /* RCTConvert_UIFontTests.m in Sources */,
144D21241B2204C5006DB32B /* RCTClippingTests.m in Sources */,
1497CFB21B21F5E400C1F8F2 /* RCTSparseArrayTests.m in Sources */,
1497CFAF1B21F5E400C1F8F2 /* RCTConvert_NSURLTests.m in Sources */,
1497CFAE1B21F5E400C1F8F2 /* RCTContextExecutorTests.m in Sources */,
1497CFAD1B21F5E400C1F8F2 /* RCTBridgeTests.m in Sources */,
1497CFB11B21F5E400C1F8F2 /* RCTEventDispatcherTests.m in Sources */,
1497CFB31B21F5E400C1F8F2 /* RCTUIManagerTests.m in Sources */,
1497CFAC1B21F5E400C1F8F2 /* RCTAllocationTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -591,13 +762,22 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
143BC5911B21E3E100462512 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
141FC1211B222EBB004D5FFB /* IntegrationTestsTests.m in Sources */,
143BC5A11B21E45C00462512 /* UIExplorerIntegrationTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
004D28A51AAF61C70097A701 /* PBXTargetDependency */ = {
143BC59C1B21E3E100462512 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 13B07F861A680F5B00A75B9A /* UIExplorer */;
targetProxy = 004D28A41AAF61C70097A701 /* PBXContainerItemProxy */;
targetProxy = 143BC59B1B21E3E100462512 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
@ -617,47 +797,59 @@
004D28A61AAF61C70097A701 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"FB_REFERENCE_IMAGE_DIR=\"\\\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\\\"\"",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/UIExplorerUnitTests/**",
);
INFOPLIST_FILE = UIExplorerTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
INFOPLIST_FILE = UIExplorerUnitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/UIExplorerUnitTests",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
XCTest,
"-ObjC",
);
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
};
name = Debug;
};
004D28A71AAF61C70097A701 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/UIExplorerUnitTests/**",
);
INFOPLIST_FILE = UIExplorerTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
INFOPLIST_FILE = UIExplorerUnitTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/UIExplorerUnitTests",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
XCTest,
"-ObjC",
);
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
};
name = Release;
};
@ -698,6 +890,47 @@
};
name = Release;
};
143BC59E1B21E3E100462512 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_NO_COMMON_BLOCKS = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"FB_REFERENCE_IMAGE_DIR=\"\\\"$(SOURCE_ROOT)/$(PROJECT_NAME)IntegrationTests/ReferenceImages\\\"\"",
);
INFOPLIST_FILE = UIExplorerIntegrationTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
};
name = Debug;
};
143BC59F1B21E3E100462512 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = UIExplorerIntegrationTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/UIExplorer.app/UIExplorer";
};
name = Release;
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -787,7 +1020,7 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
004D28AD1AAF61C70097A701 /* Build configuration list for PBXNativeTarget "UIExplorerTests" */ = {
004D28AD1AAF61C70097A701 /* Build configuration list for PBXNativeTarget "UIExplorerUnitTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
004D28A61AAF61C70097A701 /* Debug */,
@ -805,6 +1038,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
143BC59D1B21E3E100462512 /* Build configuration list for PBXNativeTarget "UIExplorerIntegrationTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
143BC59E1B21E3E100462512 /* Debug */,
143BC59F1B21E3E100462512 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "UIExplorer" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View File

@ -29,8 +29,22 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "004D289D1AAF61C70097A701"
BuildableName = "UIExplorerTests.xctest"
BlueprintName = "UIExplorerTests"
BuildableName = "UIExplorerUnitTests.xctest"
BlueprintName = "UIExplorerUnitTests"
ReferencedContainer = "container:UIExplorer.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "143BC5941B21E3E100462512"
BuildableName = "UIExplorerIntegrationTests.xctest"
BlueprintName = "UIExplorerIntegrationTests"
ReferencedContainer = "container:UIExplorer.xcodeproj">
</BuildableReference>
</BuildActionEntry>
@ -47,8 +61,18 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "004D289D1AAF61C70097A701"
BuildableName = "UIExplorerTests.xctest"
BlueprintName = "UIExplorerTests"
BuildableName = "UIExplorerUnitTests.xctest"
BlueprintName = "UIExplorerUnitTests"
ReferencedContainer = "container:UIExplorer.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "143BC5941B21E3E100462512"
BuildableName = "UIExplorerIntegrationTests.xctest"
BlueprintName = "UIExplorerIntegrationTests"
ReferencedContainer = "container:UIExplorer.xcodeproj">
</BuildableReference>
</TestableReference>

View File

@ -36,7 +36,7 @@
* on the same Wi-Fi network.
*/
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.includeRequire.runModule.bundle?dev=true"];
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/Examples/UIExplorer/UIExplorerApp.ios.includeRequire.runModule.bundle?dev=true"];
/**
* OPTION 2

View File

@ -0,0 +1,125 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @providesModule UIExplorerApp
* @flow
*/
'use strict';
var React = require('react-native');
var Dimensions = require('Dimensions');
var DrawerLayoutAndroid = require('DrawerLayoutAndroid');
var ToolbarAndroid = require('ToolbarAndroid');
var UIExplorerList = require('./UIExplorerList');
var {
StyleSheet,
View,
} = React;
var DRAWER_WIDTH_LEFT = 56;
var UIExplorerApp = React.createClass({
getInitialState: function() {
return {
example: {
title: 'UIExplorer',
component: this._renderHome(),
},
};
},
render: function() {
return (
<DrawerLayoutAndroid
drawerPosition={DrawerLayoutAndroid.positions.Left}
drawerWidth={Dimensions.get('window').width - DRAWER_WIDTH_LEFT}
ref={(drawer) => { this.drawer = drawer; }}
renderNavigationView={this._renderNavigationView}>
{this._renderNavigation()}
</DrawerLayoutAndroid>
);
},
_renderNavigationView: function() {
return (
<UIExplorerList
onSelectExample={this.onSelectExample}
isInDrawer={true}
/>
);
},
onSelectExample: function(example) {
this.drawer.closeDrawer();
if (example.title === 'UIExplorer') {
example.component = this._renderHome();
}
this.setState({
example: {
title: example.title,
component: example.component,
},
});
},
_renderHome: function() {
var onSelectExample = this.onSelectExample;
return React.createClass({
render: function() {
return (
<UIExplorerList
onSelectExample={onSelectExample}
isInDrawer={false}
/>
);
}
});
},
_renderNavigation: function() {
var Component = this.state.example.component;
return (
<View style={styles.container}>
<ToolbarAndroid
logo={require('image!launcher_icon')}
navIcon={require('image!ic_menu_black_24dp')}
onIconClicked={() => this.drawer.openDrawer()}
style={styles.toolbar}
title={this.state.example.title}
/>
<Component />
</View>
);
},
});
var styles = StyleSheet.create({
messageText: {
fontSize: 17,
fontWeight: '500',
padding: 15,
marginTop: 50,
marginLeft: 15,
},
container: {
flex: 1,
},
toolbar: {
backgroundColor: '#E9EAED',
height: 56,
},
});
module.exports = UIExplorerApp;

View File

@ -43,22 +43,22 @@ var UIExplorerApp = React.createClass({
/>
);
}
return (
<NavigatorIOS
style={styles.container}
initialRoute={{
title: 'UIExplorer',
component: UIExplorerList,
passProps: {
onExternalExampleRequested: (example) => {
this.setState({ openExternalExample: example, });
},
}
}}
itemWrapperStyle={styles.itemWrapper}
tintColor='#008888'
/>
);
return (
<NavigatorIOS
style={styles.container}
initialRoute={{
title: 'UIExplorer',
component: UIExplorerList,
passProps: {
onExternalExampleRequested: (example) => {
this.setState({ openExternalExample: example, });
},
}
}}
itemWrapperStyle={styles.itemWrapper}
tintColor="#008888"
/>
);
}
});

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.facebook.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>com.facebook.React.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>

View File

@ -30,10 +30,10 @@
#endif
NSString *version = [[UIDevice currentDevice] systemVersion];
RCTAssert([version integerValue] == 8, @"Tests should be run on iOS 8.x, found %@", version);
_runner = RCTInitRunnerForApp(@"IntegrationTests/IntegrationTestsApp");
_runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerIntegrationTests/js/IntegrationTestsApp");
// If tests have changes, set recordMode = YES below and run the affected
// tests on an iPhone5, iOS 8.1 simulator.
// tests on an iPhone5, iOS 8.3 simulator.
_runner.recordMode = NO;
}
@ -71,7 +71,7 @@
[_runner runTest:_cmd module:@"AsyncStorageTest"];
}
- (void)testLayoutEvents
- (void)DISABLED_testLayoutEvents // #7149037
{
[_runner runTest:_cmd module:@"LayoutEventsTest"];
}
@ -81,6 +81,11 @@
[_runner runTest:_cmd module:@"AppEventsTest"];
}
- (void)testPromises
{
[_runner runTest:_cmd module:@"PromiseTest"];
}
#pragma mark Snapshot Tests
- (void)testSimpleSnapshot

View File

@ -39,7 +39,7 @@
#endif
NSString *version = [[UIDevice currentDevice] systemVersion];
RCTAssert([version isEqualToString:@"8.3"], @"Snapshot tests should be run on iOS 8.3, found %@", version);
_runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerApp");
_runner = RCTInitRunnerForApp(@"Examples/UIExplorer/UIExplorerApp.ios");
// If tests have changes, set recordMode = YES below and run the affected
// tests on an iPhone5, iOS 8.1 simulator.

View File

@ -28,6 +28,7 @@ var TESTS = [
require('./LayoutEventsTest'),
require('./AppEventsTest'),
require('./SimpleSnapshotTest'),
require('./PromiseTest'),
];
TESTS.forEach(

View File

@ -0,0 +1,50 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule PromiseTest
*/
'use strict';
var RCTTestModule = require('NativeModules').TestModule;
var React = require('react-native');
var PromiseTest = React.createClass({
shouldResolve: false,
shouldReject: false,
componentDidMount() {
Promise.all([
this.testShouldResolve(),
this.testShouldReject(),
]).then(() => RCTTestModule.finish(
this.shouldResolve && this.shouldReject
));
},
testShouldResolve() {
return RCTTestModule
.shouldResolve()
.then(() => this.shouldResolve = true)
.catch(() => this.shouldResolve = false);
},
testShouldReject() {
return RCTTestModule
.shouldReject()
.then(() => this.shouldReject = false)
.catch(() => this.shouldReject = true);
},
render() {
return <React.View />;
}
});
module.exports = PromiseTest;

View File

@ -20,6 +20,7 @@ var {
AppRegistry,
ListView,
PixelRatio,
Platform,
StyleSheet,
Text,
TextInput,
@ -34,51 +35,67 @@ import type { ExampleModule } from 'ExampleTypes';
var createExamplePage = require('./createExamplePage');
var COMPONENTS = [
require('./ActivityIndicatorIOSExample'),
require('./DatePickerIOSExample'),
require('./ImageExample'),
require('./ListViewExample'),
require('./ListViewPagingExample'),
require('./MapViewExample'),
require('./Navigator/NavigatorExample'),
require('./NavigatorIOSColorsExample'),
require('./NavigatorIOSExample'),
require('./PickerIOSExample'),
require('./ProgressViewIOSExample'),
require('./ScrollViewExample'),
require('./SegmentedControlIOSExample'),
require('./SliderIOSExample'),
require('./SwitchIOSExample'),
require('./TabBarIOSExample'),
require('./TextExample.ios'),
require('./TextInputExample'),
require('./TouchableExample'),
var COMMON_COMPONENTS = [
require('./ViewExample'),
require('./WebViewExample'),
];
var APIS = [
require('./AccessibilityIOSExample'),
require('./ActionSheetIOSExample'),
require('./AdSupportIOSExample'),
require('./AlertIOSExample'),
require('./AppStateIOSExample'),
require('./AsyncStorageExample'),
require('./BorderExample'),
require('./CameraRollExample.ios'),
var COMMON_APIS = [
require('./GeolocationExample'),
require('./LayoutEventsExample'),
require('./LayoutExample'),
require('./NetInfoExample'),
require('./PanResponderExample'),
require('./PointerEventsExample'),
require('./PushNotificationIOSExample'),
require('./StatusBarIOSExample'),
require('./TimerExample'),
require('./VibrationIOSExample'),
];
if (Platform.OS === 'ios') {
var COMPONENTS = COMMON_COMPONENTS.concat([
require('./ActivityIndicatorIOSExample'),
require('./DatePickerIOSExample'),
require('./ImageExample'),
require('./ListViewExample'),
require('./ListViewPagingExample'),
require('./MapViewExample'),
require('./Navigator/NavigatorExample'),
require('./NavigatorIOSColorsExample'),
require('./NavigatorIOSExample'),
require('./PickerIOSExample'),
require('./ProgressViewIOSExample'),
require('./ScrollViewExample'),
require('./SegmentedControlIOSExample'),
require('./SliderIOSExample'),
require('./SwitchIOSExample'),
require('./TabBarIOSExample'),
require('./TextExample.ios'),
require('./TextInputExample'),
require('./TouchableExample'),
]);
var APIS = COMMON_APIS.concat([
require('./AccessibilityIOSExample'),
require('./ActionSheetIOSExample'),
require('./AdSupportIOSExample'),
require('./AlertIOSExample'),
require('./AppStateIOSExample'),
require('./AsyncStorageExample'),
require('./BorderExample'),
require('./CameraRollExample.ios'),
require('./LayoutEventsExample'),
require('./NetInfoExample'),
require('./PointerEventsExample'),
require('./PushNotificationIOSExample'),
require('./StatusBarIOSExample'),
require('./TimerExample'),
require('./VibrationIOSExample'),
require('./XHRExample'),
]);
} else if (Platform.OS === 'android') {
var COMPONENTS = COMMON_COMPONENTS.concat([
]);
var APIS = COMMON_APIS.concat([
]);
}
var ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
sectionHeaderHasChanged: (h1, h2) => h1 !== h2,
@ -114,10 +131,10 @@ COMPONENTS.concat(APIS).forEach((Example) => {
type Props = {
navigator: Array<{title: string, component: ReactClass<any,any,any>}>,
onExternalExampleRequested: Function,
onSelectExample: Function,
isInDrawer: bool,
};
class UIExplorerList extends React.Component {
props: Props;
@ -128,7 +145,7 @@ class UIExplorerList extends React.Component {
components: COMPONENTS,
apis: APIS,
}),
searchText: Settings.get('searchText'),
searchText: Platform.OS === 'ios' ? Settings.get('searchText') : '',
};
}
@ -137,8 +154,12 @@ class UIExplorerList extends React.Component {
}
render() {
return (
<View style={styles.listContainer}>
if (Platform.OS === 'ios' ||
(Platform.OS === 'android' && !this.props.isInDrawer)) {
var platformTextInputStyle =
Platform.OS === 'ios' ? styles.searchTextInputIOS :
Platform.OS === 'android' ? styles.searchTextInputAndroid : {};
var textInput = (
<View style={styles.searchRow}>
<TextInput
autoCapitalize="none"
@ -146,10 +167,24 @@ class UIExplorerList extends React.Component {
clearButtonMode="always"
onChangeText={this._search.bind(this)}
placeholder="Search..."
style={styles.searchTextInput}
style={[styles.searchTextInput, platformTextInputStyle]}
value={this.state.searchText}
/>
</View>
</View>);
}
var homePage;
if (Platform.OS === 'android' && this.props.isInDrawer) {
homePage = this._renderRow({
title: 'UIExplorer',
description: 'List of examples',
}, -1);
}
return (
<View style={styles.listContainer}>
{textInput}
{homePage}
<ListView
style={styles.list}
dataSource={this.state.dataSource}
@ -173,7 +208,7 @@ class UIExplorerList extends React.Component {
);
}
_renderRow(example: ExampleModule, i: number) {
_renderRow(example: any, i: number) {
return (
<View key={i}>
<TouchableHighlight onPress={() => this._onPressRow(example)}>
@ -205,16 +240,23 @@ class UIExplorerList extends React.Component {
Settings.set({searchText: text});
}
_onPressRow(example: ExampleModule) {
_onPressRow(example: any) {
if (example.external) {
this.props.onExternalExampleRequested(example);
return;
}
var Component = makeRenderable(example);
this.props.navigator.push({
title: Component.title,
component: Component,
});
if (Platform.OS === 'ios') {
this.props.navigator.push({
title: Component.title,
component: Component,
});
} else if (Platform.OS === 'android') {
this.props.onSelectExample({
title: Component.title,
component: Component,
});
}
}
}
@ -267,9 +309,14 @@ var styles = StyleSheet.create({
borderColor: '#cccccc',
borderRadius: 3,
borderWidth: 1,
height: 30,
paddingLeft: 8,
},
searchTextInputIOS: {
height: 30,
},
searchTextInputAndroid: {
padding: 2,
},
});
module.exports = UIExplorerList;

View File

@ -0,0 +1,79 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
@interface LayoutSubviewsOrderingTest : XCTestCase
@end
@implementation LayoutSubviewsOrderingTest
/**
* This test exists to insure that didLayoutSubviews is always called immediately after layoutSubviews for a VC:View
* pair. In Catalyst we have multiple levels of ViewController containment, and we rely on this ordering
* to insure that layoutGuides are set on RKViewControllers before Views further down in the heirarchy have
* their layoutSubviews called (and need to use the aforementioned layoutGuides)
*/
- (void)testLayoutSubviewsOrdering
{
// create some Views and ViewControllers
UIViewController *parentVC = [[UIViewController alloc] init];
UIView *parentView = [[UIView alloc] init];
UIViewController *childVC = [[UIViewController alloc] init];
UIView *childView = [[UIView alloc] init];
// The ordering we expect is:
// parentView::layoutSubviews
// parentVC::didLayoutSubviews
// childView::layoutSubviews
// childVC::didLayoutSubviews
id parentViewMock = [OCMockObject partialMockForObject:parentView];
id parentVCMock = [OCMockObject partialMockForObject:parentVC];
id childViewMock = [OCMockObject partialMockForObject:childView];
id childVCMock = [OCMockObject partialMockForObject:childVC];
__block int layoutOrderCount = 0;
[[[parentViewMock stub] andDo:^(NSInvocation *inv) {
if (layoutOrderCount < 4) {
layoutOrderCount++;
XCTAssertEqual(layoutOrderCount, 1, @"Expect parentView::layoutSubviews to be called first");
}
}] layoutSubviews];
[[[parentVCMock stub] andDo:^(NSInvocation *inv) {
if (layoutOrderCount < 4) {
layoutOrderCount++;
XCTAssertEqual(layoutOrderCount, 2, @"Expect parentVC::viewDidLayoutSubviews to be called 2nd");
}
}] viewDidLayoutSubviews];
[[[childViewMock stub] andDo:^(NSInvocation *inv) {
if (layoutOrderCount < 4) {
layoutOrderCount++;
XCTAssertEqual(layoutOrderCount, 3, @"Expect childView::layoutSubviews to be called 3rd");
}
}] layoutSubviews];
[[[childVCMock stub] andDo:^(NSInvocation *inv) {
if (layoutOrderCount < 4) {
layoutOrderCount++;
XCTAssertEqual(layoutOrderCount, 4, @"Expect childVC::viewDidLayoutSubviews to be called last");
[childVCMock stopMocking];
}
}] viewDidLayoutSubviews];
// setup View heirarchy and force layout
parentVC.view = parentView;
childVC.view = childView;
[parentVC addChildViewController:childVC];
[childVC didMoveToParentViewController:parentVC];
[parentView addSubview:childView];
[childViewMock setNeedsLayout];
[parentViewMock layoutIfNeeded];
XCTAssertEqual(layoutOrderCount, 4, @"Expect layoutSubviews/viewDidLayoutSubviews to be called");
}
@end

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2009-2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <Foundation/Foundation.h>
@class OCObserverMockObject;
@interface NSNotificationCenter(OCMAdditions)
- (void)addMockObserver:(OCObserverMockObject *)notificationObserver name:(NSString *)notificationName object:(id)notificationSender;
@end

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2009-2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <Foundation/Foundation.h>
@interface OCMArg : NSObject
// constraining arguments
+ (id)any;
+ (SEL)anySelector;
+ (void *)anyPointer;
+ (id __autoreleasing *)anyObjectRef;
+ (id)isNil;
+ (id)isNotNil;
+ (id)isEqual:(id)value;
+ (id)isNotEqual:(id)value;
+ (id)isKindOfClass:(Class)cls;
+ (id)checkWithSelector:(SEL)selector onObject:(id)anObject;
+ (id)checkWithBlock:(BOOL (^)(id obj))block;
// manipulating arguments
+ (id *)setTo:(id)value;
+ (void *)setToValue:(NSValue *)value;
// internal use only
+ (id)resolveSpecialValues:(NSValue *)value;
@end
#define OCMOCK_ANY [OCMArg any]
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define OCMOCK_VALUE(variable) \
({ __typeof__(variable) __v = (variable); [NSValue value:&__v withObjCType:@encode(__typeof__(__v))]; })
#else
#define OCMOCK_VALUE(variable) [NSValue value:&variable withObjCType:@encode(__typeof__(variable))]
#endif

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2007-2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <Foundation/Foundation.h>
@interface OCMConstraint : NSObject
+ (instancetype)constraint;
- (BOOL)evaluate:(id)value;
// if you are looking for any, isNil, etc, they have moved to OCMArg
// try to use [OCMArg checkWith...] instead of the constraintWith... methods below
+ (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject;
+ (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject withValue:(id)aValue;
@end
@interface OCMAnyConstraint : OCMConstraint
@end
@interface OCMIsNilConstraint : OCMConstraint
@end
@interface OCMIsNotNilConstraint : OCMConstraint
@end
@interface OCMIsNotEqualConstraint : OCMConstraint
{
@public
id testValue;
}
@end
@interface OCMInvocationConstraint : OCMConstraint
{
@public
NSInvocation *invocation;
}
@end
@interface OCMBlockConstraint : OCMConstraint
{
BOOL (^block)(id);
}
- (instancetype)initWithConstraintBlock:(BOOL (^)(id))block;
@end
#define CONSTRAINT(aSelector) [OCMConstraint constraintWithSelector:aSelector onObject:self]
#define CONSTRAINTV(aSelector, aValue) [OCMConstraint constraintWithSelector:aSelector onObject:self withValue:(aValue)]

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <Foundation/Foundation.h>
@interface OCMLocation : NSObject
{
id testCase;
NSString *file;
NSUInteger line;
}
+ (instancetype)locationWithTestCase:(id)aTestCase file:(NSString *)aFile line:(NSUInteger)aLine;
- (instancetype)initWithTestCase:(id)aTestCase file:(NSString *)aFile line:(NSUInteger)aLine;
- (id)testCase;
- (NSString *)file;
- (NSUInteger)line;
@end
extern OCMLocation *OCMMakeLocation(id testCase, const char *file, int line);

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <Foundation/Foundation.h>
@class OCMLocation;
@class OCMRecorder;
@class OCMStubRecorder;
@class OCMockObject;
@interface OCMMacroState : NSObject
{
OCMRecorder *recorder;
}
+ (void)beginStubMacro;
+ (OCMStubRecorder *)endStubMacro;
+ (void)beginExpectMacro;
+ (OCMStubRecorder *)endExpectMacro;
+ (void)beginVerifyMacroAtLocation:(OCMLocation *)aLocation;
+ (void)endVerifyMacro;
+ (OCMMacroState *)globalState;
- (OCMRecorder *)recorder;
- (void)switchToClassMethod;
@end

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <Foundation/Foundation.h>
@class OCMockObject;
@class OCMInvocationMatcher;
@interface OCMRecorder : NSProxy
{
OCMockObject *mockObject;
OCMInvocationMatcher *invocationMatcher;
}
- (instancetype)init;
- (instancetype)initWithMockObject:(OCMockObject *)aMockObject;
- (void)setMockObject:(OCMockObject *)aMockObject;
- (OCMInvocationMatcher *)invocationMatcher;
- (id)classMethod;
- (id)ignoringNonObjectArgs;
@end

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2004-2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import "OCMRecorder.h"
@interface OCMStubRecorder : OCMRecorder
- (id)andReturn:(id)anObject;
- (id)andReturnValue:(NSValue *)aValue;
- (id)andThrow:(NSException *)anException;
- (id)andPost:(NSNotification *)aNotification;
- (id)andCall:(SEL)selector onObject:(id)anObject;
- (id)andDo:(void (^)(NSInvocation *invocation))block;
- (id)andForwardToRealObject;
@end
@interface OCMStubRecorder (Properties)
#define andReturn(aValue) _andReturn(({ __typeof__(aValue) _v = (aValue); [NSValue value:&_v withObjCType:@encode(__typeof__(_v))]; }))
@property (nonatomic, readonly) OCMStubRecorder *(^ _andReturn)(NSValue *);
#define andThrow(anException) _andThrow(anException)
@property (nonatomic, readonly) OCMStubRecorder *(^ _andThrow)(NSException *);
#define andPost(aNotification) _andPost(aNotification)
@property (nonatomic, readonly) OCMStubRecorder *(^ _andPost)(NSNotification *);
#define andCall(anObject, aSelector) _andCall(anObject, aSelector)
@property (nonatomic, readonly) OCMStubRecorder *(^ _andCall)(id, SEL);
#define andDo(aBlock) _andDo(aBlock)
@property (nonatomic, readonly) OCMStubRecorder *(^ _andDo)(void (^)(NSInvocation *));
#define andForwardToRealObject() _andForwardToRealObject()
@property (nonatomic, readonly) OCMStubRecorder *(^ _andForwardToRealObject)(void);
@end

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2004-2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <OCMock/OCMockObject.h>
#import <OCMock/OCMRecorder.h>
#import <OCMock/OCMStubRecorder.h>
#import <OCMock/OCMConstraint.h>
#import <OCMock/OCMArg.h>
#import <OCMock/OCMLocation.h>
#import <OCMock/OCMMacroState.h>
#import <OCMock/NSNotificationCenter+OCMAdditions.h>
#define OCMClassMock(cls) [OCMockObject niceMockForClass:cls]
#define OCMStrictClassMock(cls) [OCMockObject mockForClass:cls]
#define OCMProtocolMock(protocol) [OCMockObject niceMockForProtocol:protocol]
#define OCMStrictProtocolMock(protocol) [OCMockObject mockForProtocol:protocol]
#define OCMPartialMock(obj) [OCMockObject partialMockForObject:obj]
#define OCMObserverMock() [OCMockObject observerMock]
#define OCMStub(invocation) \
({ \
_OCMSilenceWarnings( \
[OCMMacroState beginStubMacro]; \
invocation; \
[OCMMacroState endStubMacro]; \
); \
})
#define OCMExpect(invocation) \
({ \
_OCMSilenceWarnings( \
[OCMMacroState beginExpectMacro]; \
invocation; \
[OCMMacroState endExpectMacro]; \
); \
})
#define ClassMethod(invocation) \
_OCMSilenceWarnings( \
[[OCMMacroState globalState] switchToClassMethod]; \
invocation; \
);
#define OCMVerifyAll(mock) [mock verifyAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]
#define OCMVerifyAllWithDelay(mock, delay) [mock verifyWithDelay:delay atLocation:OCMMakeLocation(self, __FILE__, __LINE__)]
#define OCMVerify(invocation) \
({ \
_OCMSilenceWarnings( \
[OCMMacroState beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]; \
invocation; \
[OCMMacroState endVerifyMacro]; \
); \
})
#define _OCMSilenceWarnings(macro) \
({ \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wunused-value\"") \
macro \
_Pragma("clang diagnostic pop") \
})

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2004-2014 Erik Doernenburg and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use these files except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#import <Foundation/Foundation.h>
@class OCMLocation;
@class OCMInvocationStub;
@class OCMStubRecorder;
@class OCMInvocationMatcher;
@class OCMInvocationExpectation;
@interface OCMockObject : NSProxy
{
BOOL isNice;
BOOL expectationOrderMatters;
NSMutableArray *stubs;
NSMutableArray *expectations;
NSMutableArray *exceptions;
NSMutableArray *invocations;
}
+ (id)mockForClass:(Class)aClass;
+ (id)mockForProtocol:(Protocol *)aProtocol;
+ (id)partialMockForObject:(NSObject *)anObject;
+ (id)niceMockForClass:(Class)aClass;
+ (id)niceMockForProtocol:(Protocol *)aProtocol;
+ (id)observerMock;
- (instancetype)init;
- (void)setExpectationOrderMatters:(BOOL)flag;
- (id)stub;
- (id)expect;
- (id)reject;
- (id)verify;
- (id)verifyAtLocation:(OCMLocation *)location;
- (void)verifyWithDelay:(NSTimeInterval)delay;
- (void)verifyWithDelay:(NSTimeInterval)delay atLocation:(OCMLocation *)location;
- (void)stopMocking;
// internal use only
- (void)addStub:(OCMInvocationStub *)aStub;
- (void)addExpectation:(OCMInvocationExpectation *)anExpectation;
- (BOOL)handleInvocation:(NSInvocation *)anInvocation;
- (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation;
- (BOOL)handleSelector:(SEL)sel;
- (void)verifyInvocation:(OCMInvocationMatcher *)matcher;
- (void)verifyInvocation:(OCMInvocationMatcher *)matcher atLocation:(OCMLocation *)location;
@end

View File

@ -0,0 +1,192 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import "RCTBridge.h"
#import "RCTContextExecutor.h"
#import "RCTRootView.h"
#define RUN_RUNLOOP_WHILE(CONDITION, TIMEOUT) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wshadow\"") \
NSDate *timeout = [[NSDate date] dateByAddingTimeInterval:TIMEOUT]; \
while ((CONDITION) && [timeout timeIntervalSinceNow] > 0) { \
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; \
} \
_Pragma("clang diagnostic pop")
#define DEFAULT_TIMEOUT 2
@interface RCTBridge (RCTAllocationTests)
@property (nonatomic, weak) RCTBridge *batchedBridge;
@end
@interface RCTJavaScriptContext : NSObject
@property (nonatomic, assign, readonly) JSGlobalContextRef ctx;
@end
@interface AllocationTestModule : NSObject<RCTBridgeModule, RCTInvalidating>
@end
@implementation AllocationTestModule
RCT_EXPORT_MODULE();
@synthesize valid = _valid;
- (id)init
{
if ((self = [super init])) {
_valid = YES;
}
return self;
}
- (void)invalidate
{
_valid = NO;
}
@end
@interface RCTAllocationTests : XCTestCase
@end
@implementation RCTAllocationTests
- (void)testBridgeIsDeallocated
{
__weak RCTBridge *weakBridge;
@autoreleasepool {
RCTRootView *view = [[RCTRootView alloc] initWithBundleURL:nil
moduleName:@""
launchOptions:nil];
weakBridge = view.bridge;
XCTAssertNotNil(weakBridge, @"RCTBridge should have been created");
(void)view;
}
sleep(DEFAULT_TIMEOUT);
XCTAssertNil(weakBridge, @"RCTBridge should have been deallocated");
}
- (void)testModulesAreInvalidated
{
AllocationTestModule *module = [[AllocationTestModule alloc] init];
@autoreleasepool {
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
moduleProvider:^{
return @[module];
}
launchOptions:nil];
XCTAssertTrue(module.isValid, @"AllocationTestModule should be valid");
(void)bridge;
}
/**
* Sleep on the main thread to allow js thread deallocations then run the runloop
* to allow the module to be deallocated on the main thread
*/
sleep(1);
RUN_RUNLOOP_WHILE(module.isValid, 1)
XCTAssertFalse(module.isValid, @"AllocationTestModule should have been invalidated by the bridge");
}
- (void)testModulesAreDeallocated
{
__weak AllocationTestModule *weakModule;
@autoreleasepool {
AllocationTestModule *module = [[AllocationTestModule alloc] init];
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
moduleProvider:^{
return @[module];
}
launchOptions:nil];
weakModule = module;
XCTAssertNotNil(weakModule, @"AllocationTestModule should have been created");
(void)bridge;
}
/**
* Sleep on the main thread to allow js thread deallocations then run the runloop
* to allow the module to be deallocated on the main thread
*/
sleep(1);
RUN_RUNLOOP_WHILE(weakModule, 1)
XCTAssertNil(weakModule, @"AllocationTestModule should have been deallocated");
}
- (void)testJavaScriptExecutorIsDeallocated
{
__weak id<RCTJavaScriptExecutor> weakExecutor;
@autoreleasepool {
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
moduleProvider:nil
launchOptions:nil];
weakExecutor = [bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
XCTAssertNotNil(weakExecutor, @"JavaScriptExecutor should have been created");
(void)bridge;
}
RUN_RUNLOOP_WHILE(weakExecutor, 1);
sleep(1);
XCTAssertNil(weakExecutor, @"JavaScriptExecutor should have been released");
}
- (void)testJavaScriptContextIsDeallocated
{
__weak id weakContext;
@autoreleasepool {
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil
moduleProvider:nil
launchOptions:nil];
id executor = [bridge.batchedBridge valueForKey:@"javaScriptExecutor"];
RUN_RUNLOOP_WHILE(!(weakContext = [executor valueForKey:@"context"]), DEFAULT_TIMEOUT);
XCTAssertNotNil(weakContext, @"RCTJavaScriptContext should have been created");
(void)bridge;
}
RUN_RUNLOOP_WHILE(weakContext, 1);
sleep(1);
XCTAssertNil(weakContext, @"RCTJavaScriptContext should have been deallocated");
}
- (void)testContentViewIsInvalidated
{
RCTBridge *bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:nil launchOptions:nil];
__weak id rootContentView;
@autoreleasepool {
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@""];
RUN_RUNLOOP_WHILE(!(rootContentView = [rootView valueForKey:@"contentView"]), DEFAULT_TIMEOUT)
XCTAssertTrue([rootContentView isValid], @"RCTContentView should be valid");
(void)rootView;
}
sleep(DEFAULT_TIMEOUT);
XCTAssertFalse([rootContentView isValid], @"RCTContentView should have been invalidated");
}
- (void)testUnderlyingBridgeIsDeallocated
{
RCTBridge *bridge;
__weak id batchedBridge;
@autoreleasepool {
bridge = [[RCTBridge alloc] initWithBundleURL:nil moduleProvider:nil launchOptions:nil];
batchedBridge = bridge.batchedBridge;
XCTAssertTrue([batchedBridge isValid], @"RCTBatchedBridge should be valid");
[bridge reload];
}
// Use RUN_RUNLOOP_WHILE because `batchedBridge` deallocates on the main thread.
RUN_RUNLOOP_WHILE(batchedBridge != nil, DEFAULT_TIMEOUT)
XCTAssertNotNil(bridge, @"RCTBridge should not have been deallocated");
XCTAssertNil(batchedBridge, @"RCTBatchedBridge should have been deallocated");
}
@end

View File

@ -0,0 +1,187 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>
#import "RCTBridge.h"
#import "RCTBridgeModule.h"
#import "RCTJavaScriptExecutor.h"
#import "RCTUtils.h"
@interface RCTBridge (Testing)
@property (nonatomic, strong, readonly) RCTBridge *batchedBridge;
- (void)_handleBuffer:(id)buffer context:(NSNumber *)context;
- (void)setUp;
@end
@interface TestExecutor : NSObject <RCTJavaScriptExecutor>
@property (nonatomic, readonly, copy) NSMutableDictionary *injectedStuff;
@end
@implementation TestExecutor
RCT_EXPORT_MODULE()
- (void)setUp {}
- (instancetype)init
{
if (self = [super init]) {
_injectedStuff = [NSMutableDictionary dictionary];
}
return self;
}
- (BOOL)isValid
{
return YES;
}
- (void)executeJSCall:(NSString *)name
method:(NSString *)method
arguments:(NSArray *)arguments
context:(NSNumber *)executorID
callback:(RCTJavaScriptCallback)onComplete
{
onComplete(nil, nil);
}
- (void)executeApplicationScript:(NSString *)script
sourceURL:(NSURL *)url
onComplete:(RCTJavaScriptCompleteBlock)onComplete
{
onComplete(nil);
}
- (void)executeBlockOnJavaScriptQueue:(dispatch_block_t)block
{
block();
}
- (void)injectJSONText:(NSString *)script
asGlobalObjectNamed:(NSString *)objectName
callback:(RCTJavaScriptCompleteBlock)onComplete
{
_injectedStuff[objectName] = script;
onComplete(nil);
}
- (void)invalidate {}
@end
@interface RCTBridgeTests : XCTestCase <RCTBridgeModule>
{
RCTBridge *_bridge;
BOOL _testMethodCalled;
dispatch_queue_t _queue;
}
@end
@implementation RCTBridgeTests
RCT_EXPORT_MODULE(TestModule)
- (dispatch_queue_t)methodQueue
{
return _queue;
}
- (void)setUp
{
[super setUp];
_queue = dispatch_queue_create("com.facebook.React.TestQueue", DISPATCH_QUEUE_SERIAL);
_bridge = [[RCTBridge alloc] initWithBundleURL:nil
moduleProvider:^{ return @[self]; }
launchOptions:nil];
_bridge.executorClass = [TestExecutor class];
// Force to recreate the executor with the new class
// - reload: doesn't work here since bridge hasn't loaded yet.
[_bridge invalidate];
[_bridge setUp];
}
- (void)tearDown
{
[super tearDown];
[_bridge invalidate];
}
- (void)testHookRegistration
{
TestExecutor *executor = [_bridge.batchedBridge valueForKey:@"_javaScriptExecutor"];
NSString *injectedStuff = executor.injectedStuff[@"__fbBatchedBridgeConfig"];
NSDictionary *moduleConfig = RCTJSONParse(injectedStuff, NULL);
NSDictionary *remoteModuleConfig = moduleConfig[@"remoteModuleConfig"];
NSDictionary *testModuleConfig = remoteModuleConfig[@"TestModule"];
NSDictionary *constants = testModuleConfig[@"constants"];
NSDictionary *methods = testModuleConfig[@"methods"];
XCTAssertNotNil(moduleConfig);
XCTAssertNotNil(remoteModuleConfig);
XCTAssertNotNil(testModuleConfig);
XCTAssertNotNil(constants);
XCTAssertEqualObjects(constants[@"eleventyMillion"], @42);
XCTAssertNotNil(methods);
XCTAssertNotNil(methods[@"testMethod"]);
}
- (void)testCallNativeMethod
{
TestExecutor *executor = [_bridge.batchedBridge valueForKey:@"_javaScriptExecutor"];
NSString *injectedStuff = executor.injectedStuff[@"__fbBatchedBridgeConfig"];
NSDictionary *moduleConfig = RCTJSONParse(injectedStuff, NULL);
NSDictionary *remoteModuleConfig = moduleConfig[@"remoteModuleConfig"];
NSDictionary *testModuleConfig = remoteModuleConfig[@"TestModule"];
NSNumber *testModuleID = testModuleConfig[@"moduleID"];
NSDictionary *methods = testModuleConfig[@"methods"];
NSDictionary *testMethod = methods[@"testMethod"];
NSNumber *testMethodID = testMethod[@"methodID"];
NSArray *args = @[@1234, @5678, @"stringy", @{@"a": @1}, @42];
NSArray *buffer = @[@[testModuleID], @[testMethodID], @[args], @[], @1234567];
[_bridge.batchedBridge _handleBuffer:buffer context:RCTGetExecutorID(executor)];
dispatch_sync(_queue, ^{
// clear the queue
XCTAssertTrue(_testMethodCalled);
});
}
- (void)DISABLED_testBadArgumentsCount
{
//NSArray *bufferWithMissingArgument = @[@[@1], @[@0], @[@[@1234, @5678, @"stringy", @{@"a": @1}/*, @42*/]], @[], @1234567];
//[_bridge _handleBuffer:bufferWithMissingArgument];
NSLog(@"WARNING: testBadArgumentsCount is temporarily disabled until we have a better way to test cases that we expect to trigger redbox errors");
}
RCT_EXPORT_METHOD(testMethod:(NSInteger)integer
number:(NSNumber *)number
string:(NSString *)string
dictionary:(NSDictionary *)dict
callback:(RCTResponseSenderBlock)callback)
{
_testMethodCalled = YES;
XCTAssertTrue(integer == 1234);
XCTAssertEqualObjects(number, @5678);
XCTAssertEqualObjects(string, @"stringy");
XCTAssertEqualObjects(dict, @{@"a": @1});
XCTAssertNotNil(callback);
}
- (NSDictionary *)constantsToExport
{
return @{@"eleventyMillion": @42};
}
@end

View File

@ -0,0 +1,193 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <mach/mach_time.h>
#import <XCTest/XCTest.h>
#import "RCTContextExecutor.h"
#import "RCTUtils.h"
@interface RCTContextExecutorTests : XCTestCase
@end
@implementation RCTContextExecutorTests
{
RCTContextExecutor *_executor;
}
- (void)setUp
{
[super setUp];
_executor = [[RCTContextExecutor alloc] init];
RCTSetExecutorID(_executor);
[_executor setUp];
}
- (void)testNativeLoggingHookExceptionBehavior
{
dispatch_semaphore_t doneSem = dispatch_semaphore_create(0);
[_executor executeApplicationScript:@"var x = {toString: function() { throw 1; }}; nativeLoggingHook(x);"
sourceURL:[NSURL URLWithString:@"file://"]
onComplete:^(id error){
dispatch_semaphore_signal(doneSem);
}];
dispatch_semaphore_wait(doneSem, DISPATCH_TIME_FOREVER);
[_executor invalidate];
}
static uint64_t _get_time_nanoseconds(void)
{
static struct mach_timebase_info tb_info = {0};
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
int ret = mach_timebase_info(&tb_info);
assert(0 == ret);
});
return (mach_absolute_time() * tb_info.numer) / tb_info.denom;
}
- (void)testDeserializationPerf
{
// This test case checks the assumption that deserializing objects from JavaScript
// values one-by-one via ObjC JSC API is slower than using JSON string
// You might want to switch your tests schema to "Release" build configuration
JSContextGroupRef group = JSContextGroupCreate();
JSGlobalContextRef context = JSGlobalContextCreateInGroup(group, NULL);
id message = @[@[@1, @2, @3, @4], @[@{@"a": @1}, @{@"b": @2}], [NSNull null]];
NSString *code = RCTJSONStringify(message, NULL);
JSStringRef script = JSStringCreateWithCFString((__bridge CFStringRef)code);
JSValueRef error = NULL;
JSValueRef value = JSEvaluateScript(context, script, NULL, NULL, 0, &error);
XCTAssertTrue(error == NULL);
id obj;
uint64_t start = _get_time_nanoseconds();
for (int i = 0; i < 10000; i++) {
JSStringRef jsonJSString = JSValueCreateJSONString(context, value, 0, nil);
NSString *jsonString = (__bridge NSString *)JSStringCopyCFString(kCFAllocatorDefault, jsonJSString);
JSStringRelease(jsonJSString);
obj = RCTJSONParse(jsonString, NULL);
}
NSLog(@"JSON Parse time: %.2fms", (_get_time_nanoseconds() - start) / 1000000.0);
JSStringRelease(script);
JSGlobalContextRelease(context);
JSContextGroupRelease(group);
}
- (void)MANUALLY_testJavaScriptCallSpeed
{
/**
* Since we almost don't change the RCTContextExecutor logic, and this test is
* very likely to become flaky (specially accross different devices) leave it
* to be run manually
*
* Previous Values: If you change the executor code, you should update this values
*/
int const runs = 4e5;
int const frequency = 10;
double const threshold = 0.1;
static double const expectedTimes[] = {
0x1.6199943826cf1p+13,
0x1.a3bc0a81551c3p+13,
0x1.d49fbb8602fe3p+13,
0x1.d1f64085ecb7bp+13,
};
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSString *script = @" \
var modules = { \
module: { \
method: function () { \
return true; \
} \
} \
}; \
function require(module) { \
return modules[module]; \
} \
";
[_executor executeApplicationScript:script sourceURL:[NSURL URLWithString:@"http://localhost:8081/"] onComplete:^(NSError *error) {
NSMutableArray *params = [[NSMutableArray alloc] init];
id data = @1;
for (int i = 0; i < 4; i++) {
double samples[runs / frequency];
int size = runs / frequency;
double total = 0;
for (int j = 0; j < runs; j++) {
@autoreleasepool {
double start = _get_time_nanoseconds();
[_executor executeJSCall:@"module"
method:@"method"
arguments:params
context:RCTGetExecutorID(_executor)
callback:^(id json, NSError *__error) {
RCTAssert([json isEqual:@YES], @"Invalid return");
}];
double run = _get_time_nanoseconds() - start;
if ((j % frequency) == frequency - 1) { // Warmup
total += run;
samples[j/frequency] = run;
}
}
}
double mean = total / size;
double variance = 0;
for (int j = 0; j < size; j++) {
variance += pow(samples[j] - mean, 2);
}
variance /= size;
double standardDeviation = sqrt(variance);
double marginOfError = standardDeviation * 1.645;
double lower = mean - marginOfError;
double upper = mean + marginOfError;
int s = 0;
total = 0;
for (int j = 0; j < size; j++) {
double v = samples[j];
if (v >= lower && v <= upper) {
samples[s++] = v;
total += v;
}
}
mean = total / s;
lower = mean * (1.0 - threshold);
upper = mean * (1.0 + threshold);
double expected = expectedTimes[i];
NSLog(@"Previous: %lf, New: %f -> %a", expected, mean, mean);
if (upper < expected) {
NSLog(@"You made JS calls with %d argument(s) %.2lf%% faster :) - Remember to update the tests with the new value: %a",
i, (1 - (double)mean / expected) * 100, mean);
}
XCTAssertTrue(lower < expected, @"You made JS calls with %d argument(s) %.2lf%% slower :( - If that's *really* necessary, update the tests with the new value: %a",
i, ((double)mean / expected - 1) * 100, mean);
[params addObject:data];
}
dispatch_semaphore_signal(semaphore);
}];
while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}
}
@end

View File

@ -0,0 +1,48 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <XCTest/XCTest.h>
#import "RCTConvert.h"
@interface RCTConvert_NSURLTests : XCTestCase
@end
@implementation RCTConvert_NSURLTests
#define TEST_URL(name, _input, _expectedURL) \
- (void)test_##name { \
NSURL *result = [RCTConvert NSURL:_input]; \
NSURL *expected = [NSURL URLWithString:_expectedURL]; \
XCTAssertEqualObjects(result.absoluteURL, expected); \
} \
#define TEST_PATH(name, _input, _expectedPath) \
- (void)test_##name { \
NSURL *result = [RCTConvert NSURL:_input]; \
XCTAssertEqualObjects(result.path, _expectedPath); \
} \
#define TEST_BUNDLE_PATH(name, _input, _expectedPath) \
TEST_PATH(name, _input, [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:_expectedPath])
// Basic tests
TEST_URL(basic, @"http://example.com", @"http://example.com")
TEST_URL(null, [NSNull null], nil)
// Local files
TEST_PATH(fileURL, @"file:///blah/hello.jsbundle", @"/blah/hello.jsbundle")
TEST_BUNDLE_PATH(filePath, @"blah/hello.jsbundle", @"blah/hello.jsbundle")
TEST_BUNDLE_PATH(filePathWithSpaces, @"blah blah/hello.jsbundle", @"blah blah/hello.jsbundle")
TEST_BUNDLE_PATH(filePathWithEncodedSpaces, @"blah%20blah/hello.jsbundle", @"blah blah/hello.jsbundle")
TEST_BUNDLE_PATH(imageAt2XPath, @"images/foo@2x.jpg", @"images/foo@2x.jpg")
TEST_BUNDLE_PATH(imageFile, @"foo.jpg", @"foo.jpg")
// Remote files
TEST_URL(fullURL, @"http://example.com/blah/hello.jsbundle", @"http://example.com/blah/hello.jsbundle")
TEST_URL(urlWithSpaces, @"http://example.com/blah blah/foo", @"http://example.com/blah%20blah/foo")
TEST_URL(urlWithEncodedSpaces, @"http://example.com/blah%20blah/foo", @"http://example.com/blah%20blah/foo")
TEST_URL(imageURL, @"http://example.com/foo@2x.jpg", @"http://example.com/foo@2x.jpg")
TEST_URL(imageURLWithSpaces, @"http://example.com/blah foo@2x.jpg", @"http://example.com/blah%20foo@2x.jpg")
@end

View File

@ -0,0 +1,159 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <XCTest/XCTest.h>
#import "RCTConvert.h"
@interface RCTConvert_UIFontTests : XCTestCase
@end
@implementation RCTConvert_UIFontTests
#define RCTAssertEqualFonts(font1, font2) { \
XCTAssertEqualObjects(font1, font2); \
}
- (void)DISABLED_testWeight // task #7118691
{
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Bold" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontWeight": @"bold"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Medium" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontWeight": @"500"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-UltraLight" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontWeight": @"100"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontWeight": @"normal"}];
RCTAssertEqualFonts(expected, result);
}
}
- (void)testSize
{
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:18.5];
UIFont *result = [RCTConvert UIFont:@{@"fontSize": @18.5}];
RCTAssertEqualFonts(expected, result);
}
}
- (void)testFamily
{
{
UIFont *expected = [UIFont fontWithName:@"Cochin" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Cochin"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Helvetica Neue"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Italic" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"HelveticaNeue-Italic"}];
RCTAssertEqualFonts(expected, result);
}
}
- (void)testStyle
{
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Italic" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontStyle": @"italic"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontStyle": @"normal"}];
RCTAssertEqualFonts(expected, result);
}
}
- (void)DISABLED_testStyleAndWeight // task #7118691
{
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-UltraLightItalic" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontStyle": @"italic", @"fontWeight": @"100"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-BoldItalic" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontStyle": @"italic", @"fontWeight": @"bold"}];
RCTAssertEqualFonts(expected, result);
}
}
- (void)DISABLED_testFamilyAndWeight // task #7118691
{
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Bold" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Helvetica Neue", @"fontWeight": @"bold"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"HelveticaNeue-Bold", @"fontWeight": @"normal"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"Cochin-Bold" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Cochin", @"fontWeight": @"700"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"Cochin" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Cochin", @"fontWeight": @"500"}]; // regular Cochin is actually medium bold
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"Cochin" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Cochin", @"fontWeight": @"100"}];
RCTAssertEqualFonts(expected, result);
}
}
- (void)testFamilyAndStyle
{
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Italic" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Helvetica Neue", @"fontStyle": @"italic"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"HelveticaNeue-Italic", @"fontStyle": @"normal"}];
RCTAssertEqualFonts(expected, result);
}
}
- (void)DISABLED_testFamilyStyleAndWeight // task #7118691
{
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-UltraLightItalic" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"Helvetica Neue", @"fontStyle": @"italic", @"fontWeight": @"100"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue-Bold" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"HelveticaNeue-Italic", @"fontStyle": @"normal", @"fontWeight": @"bold"}];
RCTAssertEqualFonts(expected, result);
}
{
UIFont *expected = [UIFont fontWithName:@"HelveticaNeue" size:14];
UIFont *result = [RCTConvert UIFont:@{@"fontFamily": @"HelveticaNeue-Italic", @"fontStyle": @"normal", @"fontWeight": @"normal"}];
RCTAssertEqualFonts(expected, result);
}
}
@end

View File

@ -0,0 +1,144 @@
// Copyright 2004-present Facebook. All Rights Reserved.
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import "RCTEventDispatcher.h"
@interface RCTTestEvent : RCTBaseEvent
@property (nonatomic, assign) BOOL canCoalesce;
@end
@implementation RCTTestEvent
- (instancetype)initWithViewTag:(NSNumber *)viewTag eventName:(NSString *)eventName body:(NSDictionary *)body
{
if (self = [super initWithViewTag:viewTag eventName:eventName body:body]) {
self.canCoalesce = YES;
}
return self;
}
+ (NSString *)moduleDotMethod
{
return @"RCTDeviceEventEmitter.emit";
}
@end
@interface RCTEventDispatcherTests : XCTestCase
@end
@implementation RCTEventDispatcherTests
{
id _bridge;
RCTEventDispatcher *_eventDispatcher;
NSString *_eventName;
NSDictionary *_body;
RCTTestEvent *_testEvent;
NSString *_JSMethod;
}
- (void)setUp
{
[super setUp];
_bridge = [OCMockObject mockForClass:[RCTBridge class]];
_eventDispatcher = [[RCTEventDispatcher alloc] init];
((id<RCTBridgeModule>)_eventDispatcher).bridge = _bridge;
_eventName = @"sampleEvent";
_body = @{ @"foo": @"bar" };
_testEvent = [[RCTTestEvent alloc] initWithViewTag:nil
eventName:_eventName
body:_body];
_JSMethod = [[_testEvent class] moduleDotMethod];
}
- (void)testLegacyEventsAreImmediatelyDispatched
{
[[_bridge expect] enqueueJSCall:_JSMethod
args:@[_eventName, _body]];
[_eventDispatcher sendDeviceEventWithName:_eventName body:_body];
[_bridge verify];
}
- (void)testNonCoalescingEventsAreImmediatelyDispatched
{
_testEvent.canCoalesce = NO;
[[_bridge expect] enqueueJSCall:_JSMethod
args:@[_eventName, _body]];
[_eventDispatcher sendEvent:_testEvent];
[_bridge verify];
}
- (void)testCoalescedEventShouldBeDispatchedOnFrameUpdate
{
[_eventDispatcher sendEvent:_testEvent];
[[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
args:@[_eventName, _body]];
[(id<RCTFrameUpdateObserver>)_eventDispatcher didUpdateFrame:nil];
[_bridge verify];
}
- (void)testBasicCoalescingReturnsLastEvent
{
RCTTestEvent *ignoredEvent = [[RCTTestEvent alloc] initWithViewTag:nil
eventName:_eventName
body:@{ @"other": @"body" }];
[_eventDispatcher sendEvent:ignoredEvent];
[_eventDispatcher sendEvent:_testEvent];
[[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
args:@[_eventName, _body]];
[(id<RCTFrameUpdateObserver>)_eventDispatcher didUpdateFrame:nil];
[_bridge verify];
}
- (void)testDifferentEventTypesDontCoalesce
{
NSString *firstEventName = @"firstEvent";
RCTTestEvent *firstEvent = [[RCTTestEvent alloc] initWithViewTag:nil
eventName:firstEventName
body:_body];
[_eventDispatcher sendEvent:firstEvent];
[_eventDispatcher sendEvent:_testEvent];
[[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
args:@[firstEventName, _body]];
[[_bridge expect] enqueueJSCall:@"RCTDeviceEventEmitter.emit"
args:@[_eventName, _body]];
[(id<RCTFrameUpdateObserver>)_eventDispatcher didUpdateFrame:nil];
[_bridge verify];
}
@end

View File

@ -0,0 +1,43 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <XCTest/XCTest.h>
#import "RCTSparseArray.h"
#import "UIView+React.h"
@interface RCTSparseArrayTests : XCTestCase
@end
@implementation RCTSparseArrayTests
- (void)testDictionary
{
NSObject<RCTViewNodeProtocol> *myView = [[UIView alloc] init];
myView.reactTag = @4;
NSObject<RCTViewNodeProtocol> *myOtherView = [[UIView alloc] init];
myOtherView.reactTag = @5;
RCTSparseArray *registry = [[RCTSparseArray alloc] init];
XCTAssertNil(registry[@4], @"how did you have a view when none are registered?");
XCTAssertNil(registry[@5], @"how did you have a view when none are registered?");
registry[myView.reactTag] = myView;
XCTAssertEqual(registry[@4], myView);
XCTAssertNil(registry[@5], @"didn't register other view yet");
registry[myOtherView.reactTag] = myOtherView;
XCTAssertEqual(registry[@4], myView);
XCTAssertEqual(registry[@5], myOtherView);
registry[myView.reactTag] = nil;
XCTAssertNil(registry[@4]);
XCTAssertEqual(registry[@5], myOtherView);
registry[myOtherView.reactTag] = nil;
XCTAssertNil(registry[@4], @"how did you have a view when none are registered?");
XCTAssertNil(registry[@5], @"how did you have a view when none are registered?");
}
@end

View File

@ -0,0 +1,179 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#import <XCTest/XCTest.h>
#import "RCTSparseArray.h"
#import "RCTUIManager.h"
#import "UIView+React.h"
@interface RCTUIManager (Testing)
- (void)_manageChildren:(NSNumber *)containerReactTag
moveFromIndices:(NSArray *)moveFromIndices
moveToIndices:(NSArray *)moveToIndices
addChildReactTags:(NSArray *)addChildReactTags
addAtIndices:(NSArray *)addAtIndices
removeAtIndices:(NSArray *)removeAtIndices
registry:(RCTSparseArray *)registry;
@property (nonatomic, readonly) RCTSparseArray *viewRegistry;
@end
@interface RCTUIManagerTests : XCTestCase
@property (nonatomic, readwrite, strong) RCTUIManager *uiManager;
@end
@implementation RCTUIManagerTests
- (void)setUp
{
[super setUp];
_uiManager = [[RCTUIManager alloc] init];
// Register 20 views to use in the tests
for (NSInteger i = 1; i <= 20; i++) {
UIView *registeredView = [[UIView alloc] init];
[registeredView setReactTag:@(i)];
_uiManager.viewRegistry[i] = registeredView;
}
}
- (void)testManagingChildrenToAddViews
{
UIView *containerView = _uiManager.viewRegistry[20];
NSMutableArray *addedViews = [NSMutableArray array];
NSArray *tagsToAdd = @[@1, @2, @3, @4, @5];
NSArray *addAtIndices = @[@0, @1, @2, @3, @4];
for (NSNumber *tag in tagsToAdd) {
[addedViews addObject:_uiManager.viewRegistry[tag]];
}
// Add views 1-5 to view 20
[_uiManager _manageChildren:@20
moveFromIndices:nil
moveToIndices:nil
addChildReactTags:tagsToAdd
addAtIndices:addAtIndices
removeAtIndices:nil
registry:_uiManager.viewRegistry];
XCTAssertTrue([[containerView reactSubviews] count] == 5,
@"Expect to have 5 react subviews after calling manage children \
with 5 tags to add, instead have %lu", (unsigned long)[[containerView reactSubviews] count]);
for (UIView *view in addedViews) {
XCTAssertTrue([view superview] == containerView,
@"Expected to have manage children successfully add children");
[view removeFromSuperview];
}
}
- (void)testManagingChildrenToRemoveViews
{
UIView *containerView = _uiManager.viewRegistry[20];
NSMutableArray *removedViews = [NSMutableArray array];
NSArray *removeAtIndices = @[@0, @4, @8, @12, @16];
for (NSNumber *index in removeAtIndices) {
NSNumber *reactTag = @([index integerValue] + 2);
[removedViews addObject:_uiManager.viewRegistry[reactTag]];
}
for (NSInteger i = 2; i < 20; i++) {
UIView *view = _uiManager.viewRegistry[i];
[containerView addSubview:view];
}
// Remove views 1-5 from view 20
[_uiManager _manageChildren:@20
moveFromIndices:nil
moveToIndices:nil
addChildReactTags:nil
addAtIndices:nil
removeAtIndices:removeAtIndices
registry:_uiManager.viewRegistry];
XCTAssertEqual(containerView.reactSubviews.count, (NSUInteger)13,
@"Expect to have 13 react subviews after calling manage children\
with 5 tags to remove and 18 prior children, instead have %zd",
containerView.reactSubviews.count);
for (UIView *view in removedViews) {
XCTAssertTrue([view superview] == nil,
@"Expected to have manage children successfully remove children");
// After removing views are unregistered - we need to reregister
_uiManager.viewRegistry[view.reactTag] = view;
}
for (NSInteger i = 2; i < 20; i++) {
UIView *view = _uiManager.viewRegistry[i];
if (![removedViews containsObject:view]) {
XCTAssertTrue([view superview] == containerView,
@"Should not have removed view with react tag %ld during delete but did", (long)i);
[view removeFromSuperview];
}
}
}
// We want to start with views 1-10 added at indices 0-9
// Then we'll remove indices 2, 3, 5 and 8
// Add views 11 and 12 to indices 0 and 6
// And move indices 4 and 9 to 1 and 7
// So in total it goes from:
// [1,2,3,4,5,6,7,8,9,10]
// to
// [11,5,1,2,7,8,12,10]
- (void)testManagingChildrenToAddRemoveAndMove
{
UIView *containerView = _uiManager.viewRegistry[20];
NSArray *removeAtIndices = @[@2, @3, @5, @8];
NSArray *addAtIndices = @[@0, @6];
NSArray *tagsToAdd = @[@11, @12];
NSArray *moveFromIndices = @[@4, @9];
NSArray *moveToIndices = @[@1, @7];
// We need to keep these in array to keep them around
NSMutableArray *viewsToRemove = [NSMutableArray array];
for (NSInteger i = 0; i < removeAtIndices.count; i++) {
NSNumber *reactTagToRemove = @([removeAtIndices[i] integerValue] + 1);
UIView *viewToRemove = _uiManager.viewRegistry[reactTagToRemove];
[viewsToRemove addObject:viewToRemove];
}
for (NSInteger i = 1; i < 11; i++) {
UIView *view = _uiManager.viewRegistry[i];
[containerView addSubview:view];
}
[_uiManager _manageChildren:@20
moveFromIndices:moveFromIndices
moveToIndices:moveToIndices
addChildReactTags:tagsToAdd
addAtIndices:addAtIndices
removeAtIndices:removeAtIndices
registry:_uiManager.viewRegistry];
XCTAssertTrue([[containerView reactSubviews] count] == 8,
@"Expect to have 8 react subviews after calling manage children,\
instead have the following subviews %@", [containerView reactSubviews]);
NSArray *expectedReactTags = @[@11, @5, @1, @2, @7, @8, @12, @10];
for (NSInteger i = 0; i < [[containerView subviews] count]; i++) {
XCTAssertEqualObjects([[containerView reactSubviews][i] reactTag], expectedReactTags[i],
@"Expected subview at index %ld to have react tag #%@ but has tag #%@",
(long)i, expectedReactTags[i], [[containerView reactSubviews][i] reactTag]);
}
// Clean up after ourselves
for (NSInteger i = 1; i < 13; i++) {
UIView *view = _uiManager.viewRegistry[i];
[view removeFromSuperview];
}
for (UIView *view in viewsToRemove) {
_uiManager.viewRegistry[view.reactTag] = view;
}
}
@end

Binary file not shown.

View File

@ -0,0 +1,131 @@
/**
* The examples provided by Facebook are for non-commercial testing and
* evaluation purposes only.
*
* Facebook reserves all rights not expressly granted.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @flow
*/
'use strict';
var React = require('react-native');
var {
ProgressViewIOS,
StyleSheet,
View,
Text,
TouchableHighlight,
} = React;
class Downloader extends React.Component {
xhr: XMLHttpRequest;
cancelled: boolean;
constructor(props) {
super(props);
this.cancelled = false;
this.state = {
downloading: false,
contentSize: 1,
downloaded: 0,
};
}
download() {
this.xhr && this.xhr.abort();
var xhr = this.xhr || new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === xhr.HEADERS_RECEIVED) {
var contentSize = parseInt(xhr.getResponseHeader('Content-Length'), 10);
this.setState({
contentSize: contentSize,
downloaded: 0,
});
} else if (xhr.readyState === xhr.LOADING) {
this.setState({
downloaded: xhr.responseText.length,
});
} else if (xhr.readyState === xhr.DONE) {
this.setState({
downloading: false,
});
if (this.cancelled) {
this.cancelled = false;
return;
}
if (xhr.status === 200) {
alert('Download complete!');
} else if (xhr.status !== 0) {
alert('Error: Server returned HTTP status of ' + xhr.status + ' ' + xhr.responseText);
} else {
alert('Error: ' + xhr.responseText);
}
}
};
xhr.open('GET', 'http://www.gutenberg.org/cache/epub/100/pg100.txt');
xhr.send();
this.xhr = xhr;
this.setState({downloading: true});
}
componentWillUnmount() {
this.cancelled = true;
this.xhr && this.xhr.abort();
}
render() {
var button = this.state.downloading ? (
<View style={styles.wrapper}>
<View style={styles.button}>
<Text>Downloading...</Text>
</View>
</View>
) : (
<TouchableHighlight
style={styles.wrapper}
onPress={this.download.bind(this)}>
<View style={styles.button}>
<Text>Download 5MB Text File</Text>
</View>
</TouchableHighlight>
);
return (
<View>
{button}
<ProgressViewIOS progress={(this.state.downloaded / this.state.contentSize)}/>
</View>
);
}
}
exports.framework = 'React';
exports.title = 'XMLHttpRequest';
exports.description = 'XMLHttpRequest';
exports.examples = [{
title: 'File Download',
render() {
return <Downloader/>;
}
}];
var styles = StyleSheet.create({
wrapper: {
borderRadius: 5,
marginBottom: 5,
},
button: {
backgroundColor: '#eeeeee',
padding: 10,
},
});

View File

@ -1,51 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AppDelegate.h"
#import "RCTRootView.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
// Loading JavaScript code - uncomment the one you want.
// OPTION 1
// Load from development server. Start the server from the repository root:
//
// $ npm start
//
// To run on device, change `localhost` to the IP address of your computer, and make sure your computer and
// iOS device are on the same Wi-Fi network.
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/IntegrationTests/IntegrationTestsApp.includeRequire.runModule.bundle?dev=true"];
// OPTION 2
// Load from pre-bundled file on disk. To re-generate the static bundle, run
//
// $ curl http://localhost:8081/IntegrationTests/IntegrationTestsApp.includeRequire.runModule.bundle -o main.jsbundle
//
// and uncomment the next following line
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"IntegrationTestsApp"
launchOptions:launchOptions];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [[UIViewController alloc] init];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end

View File

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="13F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Facebook. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="IntegrationTests" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

View File

@ -1,44 +0,0 @@
{
"images" : [
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "uie_icon@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "uie_icon@2x-1.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "uie_icon@2x-2.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "uie_icon@2x-3.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "uie_icon@2x-5.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "uie_icon@2x-4.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.facebook.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSLocationWhenInUseUsageDescription</key>
<string>You need to add NSLocationWhenInUseUsageDescription key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@ -1,664 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
004D28A31AAF61C70097A701 /* IntegrationTestsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 004D28A21AAF61C70097A701 /* IntegrationTestsTests.m */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
1405E9C21AC3E65600F5BC37 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1405E9C11AC3E63C00F5BC37 /* libReact.a */; };
580C37611AB0F61E0015E709 /* libRCTAdSupport.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 580C374B1AB0F54A0015E709 /* libRCTAdSupport.a */; };
580C37621AB0F6260015E709 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 580C37501AB0F55C0015E709 /* libRCTGeolocation.a */; };
580C37631AB0F62C0015E709 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 580C37551AB0F56E0015E709 /* libRCTImage.a */; };
580C37641AB0F6350015E709 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 580C375A1AB0F5970015E709 /* libRCTNetwork.a */; };
580C37651AB0F63E0015E709 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 580C375F1AB0F5D10015E709 /* libRCTText.a */; };
58B80D5F1ABA4147004008FB /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 580C378F1AB104B00015E709 /* libRCTTest.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
1405E9C01AC3E63C00F5BC37 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 1405E9BC1AC3E63C00F5BC37 /* React.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
remoteInfo = React;
};
58005BCB1ABA44F10062E044 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = IntegrationTests;
};
580C374A1AB0F54A0015E709 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
remoteInfo = RCTAdSupport;
};
580C374F1AB0F55C0015E709 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTGeolocation;
};
580C37541AB0F56E0015E709 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13417FE31AA91428003F314A /* RCTImage.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
remoteInfo = RCTImage;
};
580C37591AB0F5970015E709 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 134180261AA91779003F314A /* RCTNetwork.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 58B511DB1A9E6C8500147676;
remoteInfo = RCTNetwork;
};
580C375E1AB0F5D10015E709 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13417FEA1AA914B8003F314A /* RCTText.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 58B5119B1A9E6C1200147676;
remoteInfo = RCTText;
};
580C378E1AB104B00015E709 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 580C37891AB104AF0015E709 /* RCTTest.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 580C376F1AB104AF0015E709;
remoteInfo = RCTTest;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
004D289E1AAF61C70097A701 /* IntegrationTestsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IntegrationTestsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
004D28A11AAF61C70097A701 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
004D28A21AAF61C70097A701 /* IntegrationTestsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IntegrationTestsTests.m; sourceTree = "<group>"; };
13417FE31AA91428003F314A /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
134180261AA91779003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../Libraries/GeoLocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* IntegrationTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IntegrationTests.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
1405E9BC1AC3E63C00F5BC37 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../React/React.xcodeproj; sourceTree = "<group>"; };
580C37891AB104AF0015E709 /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = ../Libraries/RCTTest/RCTTest.xcodeproj; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
004D289B1AAF61C70097A701 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
1405E9C21AC3E65600F5BC37 /* libReact.a in Frameworks */,
580C37611AB0F61E0015E709 /* libRCTAdSupport.a in Frameworks */,
580C37621AB0F6260015E709 /* libRCTGeolocation.a in Frameworks */,
580C37631AB0F62C0015E709 /* libRCTImage.a in Frameworks */,
580C37641AB0F6350015E709 /* libRCTNetwork.a in Frameworks */,
58B80D5F1ABA4147004008FB /* libRCTTest.a in Frameworks */,
580C37651AB0F63E0015E709 /* libRCTText.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
004D289F1AAF61C70097A701 /* IntegrationTestsTests */ = {
isa = PBXGroup;
children = (
004D28A21AAF61C70097A701 /* IntegrationTestsTests.m */,
004D28A01AAF61C70097A701 /* Supporting Files */,
);
path = IntegrationTestsTests;
sourceTree = "<group>";
};
004D28A01AAF61C70097A701 /* Supporting Files */ = {
isa = PBXGroup;
children = (
004D28A11AAF61C70097A701 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
1316A21D1AA397F400C0188E /* Libraries */ = {
isa = PBXGroup;
children = (
1405E9BC1AC3E63C00F5BC37 /* React.xcodeproj */,
134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */,
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */,
13417FE31AA91428003F314A /* RCTImage.xcodeproj */,
134180261AA91779003F314A /* RCTNetwork.xcodeproj */,
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */,
580C37891AB104AF0015E709 /* RCTTest.xcodeproj */,
);
name = Libraries;
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* IntegrationTests */ = {
isa = PBXGroup;
children = (
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
13B07FB71A68108700A75B9A /* main.m */,
);
name = IntegrationTests;
sourceTree = "<group>";
};
1405E9BD1AC3E63C00F5BC37 /* Products */ = {
isa = PBXGroup;
children = (
1405E9C11AC3E63C00F5BC37 /* libReact.a */,
);
name = Products;
sourceTree = "<group>";
};
580C37471AB0F54A0015E709 /* Products */ = {
isa = PBXGroup;
children = (
580C374B1AB0F54A0015E709 /* libRCTAdSupport.a */,
);
name = Products;
sourceTree = "<group>";
};
580C374C1AB0F55C0015E709 /* Products */ = {
isa = PBXGroup;
children = (
580C37501AB0F55C0015E709 /* libRCTGeolocation.a */,
);
name = Products;
sourceTree = "<group>";
};
580C37511AB0F56E0015E709 /* Products */ = {
isa = PBXGroup;
children = (
580C37551AB0F56E0015E709 /* libRCTImage.a */,
);
name = Products;
sourceTree = "<group>";
};
580C37561AB0F5970015E709 /* Products */ = {
isa = PBXGroup;
children = (
580C375A1AB0F5970015E709 /* libRCTNetwork.a */,
);
name = Products;
sourceTree = "<group>";
};
580C375B1AB0F5D10015E709 /* Products */ = {
isa = PBXGroup;
children = (
580C375F1AB0F5D10015E709 /* libRCTText.a */,
);
name = Products;
sourceTree = "<group>";
};
580C378A1AB104AF0015E709 /* Products */ = {
isa = PBXGroup;
children = (
580C378F1AB104B00015E709 /* libRCTTest.a */,
);
name = Products;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
13B07FAE1A68108700A75B9A /* IntegrationTests */,
1316A21D1AA397F400C0188E /* Libraries */,
004D289F1AAF61C70097A701 /* IntegrationTestsTests */,
83CBBA001A601CBA00E9B192 /* Products */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
};
83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* IntegrationTests.app */,
004D289E1AAF61C70097A701 /* IntegrationTestsTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
004D289D1AAF61C70097A701 /* IntegrationTestsTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 004D28AD1AAF61C70097A701 /* Build configuration list for PBXNativeTarget "IntegrationTestsTests" */;
buildPhases = (
004D289A1AAF61C70097A701 /* Sources */,
004D289B1AAF61C70097A701 /* Frameworks */,
004D289C1AAF61C70097A701 /* Resources */,
);
buildRules = (
);
dependencies = (
58005BCC1ABA44F10062E044 /* PBXTargetDependency */,
);
name = IntegrationTestsTests;
productName = IntegrationTestsTests;
productReference = 004D289E1AAF61C70097A701 /* IntegrationTestsTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
13B07F861A680F5B00A75B9A /* IntegrationTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "IntegrationTests" */;
buildPhases = (
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = IntegrationTests;
productName = "Hello World";
productReference = 13B07F961A680F5B00A75B9A /* IntegrationTests.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
004D289D1AAF61C70097A701 = {
CreatedOnToolsVersion = 6.1.1;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "IntegrationTests" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 580C37471AB0F54A0015E709 /* Products */;
ProjectRef = 134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */;
},
{
ProductGroup = 580C374C1AB0F55C0015E709 /* Products */;
ProjectRef = 134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */;
},
{
ProductGroup = 580C37511AB0F56E0015E709 /* Products */;
ProjectRef = 13417FE31AA91428003F314A /* RCTImage.xcodeproj */;
},
{
ProductGroup = 580C37561AB0F5970015E709 /* Products */;
ProjectRef = 134180261AA91779003F314A /* RCTNetwork.xcodeproj */;
},
{
ProductGroup = 580C378A1AB104AF0015E709 /* Products */;
ProjectRef = 580C37891AB104AF0015E709 /* RCTTest.xcodeproj */;
},
{
ProductGroup = 580C375B1AB0F5D10015E709 /* Products */;
ProjectRef = 13417FEA1AA914B8003F314A /* RCTText.xcodeproj */;
},
{
ProductGroup = 1405E9BD1AC3E63C00F5BC37 /* Products */;
ProjectRef = 1405E9BC1AC3E63C00F5BC37 /* React.xcodeproj */;
},
);
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* IntegrationTests */,
004D289D1AAF61C70097A701 /* IntegrationTestsTests */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
1405E9C11AC3E63C00F5BC37 /* libReact.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libReact.a;
remoteRef = 1405E9C01AC3E63C00F5BC37 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
580C374B1AB0F54A0015E709 /* libRCTAdSupport.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTAdSupport.a;
remoteRef = 580C374A1AB0F54A0015E709 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
580C37501AB0F55C0015E709 /* libRCTGeolocation.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTGeolocation.a;
remoteRef = 580C374F1AB0F55C0015E709 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
580C37551AB0F56E0015E709 /* libRCTImage.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTImage.a;
remoteRef = 580C37541AB0F56E0015E709 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
580C375A1AB0F5970015E709 /* libRCTNetwork.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTNetwork.a;
remoteRef = 580C37591AB0F5970015E709 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
580C375F1AB0F5D10015E709 /* libRCTText.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTText.a;
remoteRef = 580C375E1AB0F5D10015E709 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
580C378F1AB104B00015E709 /* libRCTTest.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTTest.a;
remoteRef = 580C378E1AB104B00015E709 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
004D289C1AAF61C70097A701 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8E1A680F5B00A75B9A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
004D289A1AAF61C70097A701 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
004D28A31AAF61C70097A701 /* IntegrationTestsTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F871A680F5B00A75B9A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
58005BCC1ABA44F10062E044 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 13B07F861A680F5B00A75B9A /* IntegrationTests */;
targetProxy = 58005BCB1ABA44F10062E044 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
13B07FB21A68108700A75B9A /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
004D28A61AAF61C70097A701 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SDKROOT)/Developer/Library/Frameworks",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"FB_REFERENCE_IMAGE_DIR=\"\\\"$(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages\\\"\"",
"$(inherited)",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../React/**",
);
INFOPLIST_FILE = IntegrationTestsTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/IntegrationTests.app/IntegrationTests";
};
name = Debug;
};
004D28A71AAF61C70097A701 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SDKROOT)/Developer/Library/Frameworks",
"$(DEVELOPER_FRAMEWORKS_DIR)",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../React/**",
);
INFOPLIST_FILE = IntegrationTestsTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/IntegrationTests.app/IntegrationTests";
};
name = Release;
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../React/**",
);
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = IntegrationTests;
};
name = Debug;
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../React/**",
);
INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = IntegrationTests;
};
name = Release;
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../React/**",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
83CBBA211A601CBA00E9B192 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../React/**",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
004D28AD1AAF61C70097A701 /* Build configuration list for PBXNativeTarget "IntegrationTestsTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
004D28A61AAF61C70097A701 /* Debug */,
004D28A71AAF61C70097A701 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "IntegrationTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */,
13B07F951A680F5B00A75B9A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "IntegrationTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */,
83CBBA211A601CBA00E9B192 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
}

View File

@ -19,9 +19,17 @@ var slice = Array.prototype.slice;
var MethodTypes = keyMirror({
remote: null,
remoteAsync: null,
local: null,
});
type ErrorData = {
message: string;
domain: string;
code: number;
nativeStackIOS?: string;
};
/**
* Creates remotely invokable modules.
*/
@ -36,21 +44,37 @@ var BatchedBridgeFactory = {
*/
_createBridgedModule: function(messageQueue, moduleConfig, moduleName) {
var remoteModule = mapObject(moduleConfig.methods, function(methodConfig, memberName) {
return methodConfig.type === MethodTypes.local ? null : function() {
var lastArg = arguments.length > 0 ? arguments[arguments.length - 1] : null;
var secondLastArg = arguments.length > 1 ? arguments[arguments.length - 2] : null;
var hasSuccCB = typeof lastArg === 'function';
var hasErrorCB = typeof secondLastArg === 'function';
hasErrorCB && invariant(
hasSuccCB,
'Cannot have a non-function arg after a function arg.'
);
var numCBs = (hasSuccCB ? 1 : 0) + (hasErrorCB ? 1 : 0);
var args = slice.call(arguments, 0, arguments.length - numCBs);
var onSucc = hasSuccCB ? lastArg : null;
var onFail = hasErrorCB ? secondLastArg : null;
return messageQueue.call(moduleName, memberName, args, onFail, onSucc);
};
switch (methodConfig.type) {
case MethodTypes.remoteAsync:
return function(...args) {
return new Promise((resolve, reject) => {
messageQueue.call(moduleName, memberName, args, resolve, (errorData) => {
var error = _createErrorFromErrorData(errorData);
reject(error);
});
});
};
case MethodTypes.local:
return null;
default:
return function() {
var lastArg = arguments.length > 0 ? arguments[arguments.length - 1] : null;
var secondLastArg = arguments.length > 1 ? arguments[arguments.length - 2] : null;
var hasSuccCB = typeof lastArg === 'function';
var hasErrorCB = typeof secondLastArg === 'function';
hasErrorCB && invariant(
hasSuccCB,
'Cannot have a non-function arg after a function arg.'
);
var numCBs = (hasSuccCB ? 1 : 0) + (hasErrorCB ? 1 : 0);
var args = slice.call(arguments, 0, arguments.length - numCBs);
var onSucc = hasSuccCB ? lastArg : null;
var onFail = hasErrorCB ? secondLastArg : null;
return messageQueue.call(moduleName, memberName, args, onFail, onSucc);
};
}
});
for (var constName in moduleConfig.constants) {
warning(!remoteModule[constName], 'saw constant and method named %s', constName);
@ -59,7 +83,6 @@ var BatchedBridgeFactory = {
return remoteModule;
},
create: function(MessageQueue, modulesConfig, localModulesConfig) {
var messageQueue = new MessageQueue(modulesConfig, localModulesConfig);
return {
@ -80,4 +103,14 @@ var BatchedBridgeFactory = {
}
};
function _createErrorFromErrorData(errorData: ErrorData): Error {
var {
message,
...extraErrorInfo,
} = errorData;
var error = new Error(message);
error.framesToPop = 1;
return Object.assign(error, extraErrorInfo);
}
module.exports = BatchedBridgeFactory;

View File

@ -19,7 +19,6 @@ var Platform = require('Platform');
var PropTypes = require('ReactPropTypes');
var React = require('React');
var ReactChildren = require('ReactChildren');
var ReactNativeViewAttributes = require('ReactNativeViewAttributes');
var StyleSheet = require('StyleSheet');
var Text = require('Text');
var TextInputState = require('TextInputState');
@ -29,36 +28,7 @@ var TouchableWithoutFeedback = require('TouchableWithoutFeedback');
var createReactNativeComponentClass = require('createReactNativeComponentClass');
var emptyFunction = require('emptyFunction');
var invariant = require('invariant');
var merge = require('merge');
var RCTTextViewAttributes = merge(ReactNativeViewAttributes.UIView, {
autoCorrect: true,
autoCapitalize: true,
clearTextOnFocus: true,
color: true,
editable: true,
fontFamily: true,
fontSize: true,
fontStyle: true,
fontWeight: true,
keyboardType: true,
returnKeyType: true,
enablesReturnKeyAutomatically: true,
secureTextEntry: true,
selectTextOnFocus: true,
mostRecentEventCounter: true,
placeholder: true,
placeholderTextColor: true,
text: true,
});
var RCTTextFieldAttributes = merge(RCTTextViewAttributes, {
caretHidden: true,
enabled: true,
clearButtonMode: true,
clearTextOnFocus: true,
selectTextOnFocus: true,
});
var requireNativeComponent = require('requireNativeComponent');
var onlyMultiline = {
onSelectionChange: true,
@ -82,16 +52,14 @@ var AndroidTextInputAttributes = {
testID: true,
};
var viewConfigIOS = {
uiViewClassName: 'RCTTextField',
validAttributes: RCTTextFieldAttributes,
};
var viewConfigAndroid = {
uiViewClassName: 'AndroidTextInput',
validAttributes: AndroidTextInputAttributes,
};
var RCTTextView = requireNativeComponent('RCTTextView', null);
var RCTTextField = requireNativeComponent('RCTTextField', null);
type DefaultProps = {
bufferDelay: number;
};
@ -164,7 +132,7 @@ var TextInput = React.createClass({
*/
keyboardType: PropTypes.oneOf([
// Cross-platform
'default',
'default',
'numeric',
'email-address',
// iOS-only
@ -296,7 +264,7 @@ var TextInput = React.createClass({
*/
mixins: [NativeMethodsMixin, TimerMixin],
viewConfig: ((Platform.OS === 'ios' ? viewConfigIOS :
viewConfig: ((Platform.OS === 'ios' ? RCTTextField.viewConfig :
(Platform.OS === 'android' ? viewConfigAndroid : {})) : Object),
isFocused: function(): boolean {
@ -510,6 +478,7 @@ var TextInput = React.createClass({
onFocus={this._onFocus}
onBlur={this._onBlur}
onChange={this._onChange}
onTextInput={this._onTextInput}
onEndEditing={this.props.onEndEditing}
onSubmitEditing={this.props.onSubmitEditing}
onLayout={this.props.onLayout}
@ -576,16 +545,6 @@ var styles = StyleSheet.create({
},
});
var RCTTextView = createReactNativeComponentClass({
validAttributes: RCTTextViewAttributes,
uiViewClassName: 'RCTTextView',
});
var RCTTextField = createReactNativeComponentClass({
validAttributes: RCTTextFieldAttributes,
uiViewClassName: 'RCTTextField',
});
var AndroidTextInput = createReactNativeComponentClass({
validAttributes: AndroidTextInputAttributes,
uiViewClassName: 'AndroidTextInput',

View File

@ -1290,7 +1290,7 @@ var Navigator = React.createClass({
key={this.state.idStack[i]}
ref={'scene_' + i}
onStartShouldSetResponderCapture={() => {
return !!this.state.transitionFromIndex || !!this.state.activeGesture;
return (this.state.transitionFromIndex != null) || (this.state.transitionFromIndex != null);
}}
style={[styles.baseScene, this.props.sceneStyle, disabledSceneStyle]}>
{React.cloneElement(child, {

View File

@ -164,7 +164,6 @@ var NavigatorBreadcrumbNavigationBar = React.createClass({
renderToHardwareTextureAndroid: renderToHardwareTexture,
};
this.refs['crumb_' + index].setNativeProps(props);
this.refs['icon_' + index].setNativeProps(props);
this.refs['separator_' + index].setNativeProps(props);
this.refs['title_' + index].setNativeProps(props);

View File

@ -10,6 +10,7 @@
1304D5AB1AA8C4A30002E2BE /* RCTStaticImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5A81AA8C4A30002E2BE /* RCTStaticImage.m */; };
1304D5AC1AA8C4A30002E2BE /* RCTStaticImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5AA1AA8C4A30002E2BE /* RCTStaticImageManager.m */; };
1304D5B21AA8C50D0002E2BE /* RCTGIFImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */; };
1345A8391B26592900583190 /* RCTImageRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1345A8381B26592900583190 /* RCTImageRequestHandler.m */; };
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879341AAD238D00F088A5 /* RCTCameraRollManager.m */; };
143879381AAD32A300F088A5 /* RCTImageLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 143879371AAD32A300F088A5 /* RCTImageLoader.m */; };
58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */; };
@ -36,6 +37,8 @@
1304D5AA1AA8C4A30002E2BE /* RCTStaticImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStaticImageManager.m; sourceTree = "<group>"; };
1304D5B01AA8C50D0002E2BE /* RCTGIFImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTGIFImage.h; sourceTree = "<group>"; };
1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTGIFImage.m; sourceTree = "<group>"; };
1345A8371B26592900583190 /* RCTImageRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageRequestHandler.h; sourceTree = "<group>"; };
1345A8381B26592900583190 /* RCTImageRequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageRequestHandler.m; sourceTree = "<group>"; };
143879331AAD238D00F088A5 /* RCTCameraRollManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCameraRollManager.h; sourceTree = "<group>"; };
143879341AAD238D00F088A5 /* RCTCameraRollManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCameraRollManager.m; sourceTree = "<group>"; };
143879361AAD32A300F088A5 /* RCTImageLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageLoader.h; sourceTree = "<group>"; };
@ -71,6 +74,8 @@
1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */,
58B511891A9E6BD600147676 /* RCTImageDownloader.h */,
58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */,
1345A8371B26592900583190 /* RCTImageRequestHandler.h */,
1345A8381B26592900583190 /* RCTImageRequestHandler.m */,
58B5118B1A9E6BD600147676 /* RCTNetworkImageView.h */,
58B5118C1A9E6BD600147676 /* RCTNetworkImageView.m */,
58B5118D1A9E6BD600147676 /* RCTNetworkImageViewManager.h */,
@ -152,6 +157,7 @@
58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */,
58B511911A9E6BD600147676 /* RCTNetworkImageViewManager.m in Sources */,
1304D5AC1AA8C4A30002E2BE /* RCTStaticImageManager.m in Sources */,
1345A8391B26592900583190 /* RCTImageRequestHandler.m in Sources */,
58B511901A9E6BD600147676 /* RCTNetworkImageView.m in Sources */,
1304D5B21AA8C50D0002E2BE /* RCTGIFImage.m in Sources */,
143879351AAD238D00F088A5 /* RCTCameraRollManager.m in Sources */,

View File

@ -82,8 +82,8 @@ static NSString *RCTCacheKeyForURL(NSURL *url)
RCTImageDownloader *strongSelf = weakSelf;
NSArray *blocks = strongSelf->_pendingBlocks[cacheKey];
[strongSelf->_pendingBlocks removeObjectForKey:cacheKey];
for (RCTCachedDataDownloadBlock cacheDownloadBlock in blocks) {
cacheDownloadBlock(cached, data, error);
for (RCTCachedDataDownloadBlock downloadBlock in blocks) {
downloadBlock(cached, data, error);
}
});
};

View File

@ -16,9 +16,22 @@
#import <UIKit/UIKit.h>
#import "RCTConvert.h"
#import "RCTDefines.h"
#import "RCTGIFImage.h"
#import "RCTImageDownloader.h"
#import "RCTLog.h"
#import "RCTUtils.h"
static void RCTDispatchCallbackOnMainQueue(void (^ __nonnull callback)(NSError *, id), NSError *error, UIImage *image)
{
if ([NSThread isMainThread]) {
callback(error, image);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
callback(error, image);
});
}
}
static dispatch_queue_t RCTImageLoaderQueue(void)
{
@ -31,24 +44,6 @@ static dispatch_queue_t RCTImageLoaderQueue(void)
return queue;
}
static NSError *RCTErrorWithMessage(NSString *message)
{
NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: message};
NSError *error = [[NSError alloc] initWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
return error;
}
static void RCTDispatchCallbackOnMainQueue(void (^callback)(NSError *, id), NSError *error, UIImage *image)
{
if ([NSThread isMainThread]) {
callback(error, image);
} else {
dispatch_async(dispatch_get_main_queue(), ^{
callback(error, image);
});
}
}
@implementation RCTImageLoader
+ (ALAssetsLibrary *)assetsLibrary

View File

@ -7,11 +7,8 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h>
#import "RCTURLRequestHandler.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@interface RCTImageRequestHandler : NSObject <RCTURLRequestHandler>
@end

View File

@ -0,0 +1,62 @@
//
// RCTImageRequestHandler.m
// RCTImage
//
// Created by Nick Lockwood on 09/06/2015.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import "RCTImageRequestHandler.h"
#import <UIKit/UIKit.h>
#import "RCTImageLoader.h"
#import "RCTUtils.h"
@implementation RCTImageRequestHandler
{
NSInteger _currentToken;
}
RCT_EXPORT_MODULE()
- (BOOL)canHandleRequest:(NSURLRequest *)request
{
return [@[@"assets-library", @"ph"] containsObject:[request.URL.scheme lowercaseString]];
}
- (id)sendRequest:(NSURLRequest *)request
withDelegate:(id<RCTURLRequestDelegate>)delegate
{
NSNumber *requestToken = @(++_currentToken);
NSString *URLString = [request.URL absoluteString];
[RCTImageLoader loadImageWithTag:URLString callback:^(NSError *error, UIImage *image) {
if (error) {
[delegate URLRequest:requestToken didCompleteWithError:error];
return;
}
NSString *mimeType = nil;
NSData *imageData = nil;
if (RCTImageHasAlpha(image.CGImage)) {
mimeType = @"image/png";
imageData = UIImagePNGRepresentation(image);
} else {
mimeType = @"image/jpeg";
imageData = UIImageJPEGRepresentation(image, 1.0);
}
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL
MIMEType:mimeType
expectedContentLength:imageData.length
textEncodingName:nil];
[delegate URLRequest:requestToken didReceiveResponse:response];
[delegate URLRequest:requestToken didReceiveData:imageData];
[delegate URLRequest:requestToken didCompleteWithError:nil];
}];
return requestToken;
}
@end

View File

@ -85,7 +85,7 @@ function setUpAlert() {
var alertOpts = {
title: 'Alert',
message: '' + text,
buttons: [{'cancel': 'Okay'}],
buttons: [{'cancel': 'OK'}],
};
RCTAlertManager.alertWithArgs(alertOpts, null);
};
@ -102,6 +102,7 @@ function setUpXHR() {
// The native XMLHttpRequest in Chrome dev tools is CORS aware and won't
// let you fetch anything from the internet
GLOBAL.XMLHttpRequest = require('XMLHttpRequest');
GLOBAL.FormData = require('FormData');
var fetchPolyfill = require('fetch');
GLOBAL.fetch = fetchPolyfill.fetch;

View File

@ -13,9 +13,10 @@
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var RCTLinkingManager = require('NativeModules').LinkingManager;
var Map = require('Map');
var invariant = require('invariant');
var _notifHandlers = {};
var _notifHandlers = new Map();
var _initialURL = RCTLinkingManager &&
RCTLinkingManager.initialURL;
@ -80,10 +81,6 @@ var DEVICE_NOTIF_EVENT = 'openURL';
* }
* });
* ```
*
* _The iOS simulator does not support the `mailto:` and `tel:` schemas
* because the Mail and Phone apps are not installed - you will need to test
* them on a device._
*/
class LinkingIOS {
/**
@ -95,10 +92,11 @@ class LinkingIOS {
type === 'url',
'LinkingIOS only supports `url` events'
);
_notifHandlers[handler] = RCTDeviceEventEmitter.addListener(
var listener = RCTDeviceEventEmitter.addListener(
DEVICE_NOTIF_EVENT,
handler
);
_notifHandlers.set(handler, listener);
}
/**
@ -109,11 +107,12 @@ class LinkingIOS {
type === 'url',
'LinkingIOS only supports `url` events'
);
if (!_notifHandlers[handler]) {
var listener = _notifHandlers.get(handler);
if (!listener) {
return;
}
_notifHandlers[handler].remove();
_notifHandlers[handler] = null;
listener.remove();
_notifHandlers.delete(handler);
}
/**

View File

@ -0,0 +1,67 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule FormData
* @flow
*/
'use strict';
type FormDataValue = any;
type FormDataPart = [string, FormDataValue];
/**
* Polyfill for XMLHttpRequest2 FormData API, allowing multipart POST requests
* with mixed data (string, native files) to be submitted via XMLHttpRequest.
*/
class FormData {
_parts: Array<FormDataPart>;
_partsByKey: {[key: string]: FormDataPart};
constructor() {
this._parts = [];
this._partsByKey = {};
}
append(key: string, value: FormDataValue) {
var parts = this._partsByKey[key];
if (parts) {
// It's a bit unclear what the behaviour should be in this case.
// The XMLHttpRequest spec doesn't specify it, while MDN says that
// the any new values should appended to existing values. We're not
// doing that for now -- it's tedious and doesn't seem worth the effort.
parts[1] = value;
return;
}
parts = [key, value];
this._parts.push(parts);
this._partsByKey[key] = parts;
}
getParts(): Array<FormDataValue> {
return this._parts.map(([name, value]) => {
if (typeof value === 'string') {
return {
string: value,
headers: {
'content-disposition': 'form-data; name="' + name + '"',
},
};
}
var contentDisposition = 'form-data; name="' + name + '"';
if (typeof value.name === 'string') {
contentDisposition += '; filename="' + value.name + '"';
}
return {
...value,
headers: {'content-disposition': contentDisposition},
};
});
}
}
module.exports = FormData;

View File

@ -11,70 +11,451 @@
#import "RCTAssert.h"
#import "RCTConvert.h"
#import "RCTURLRequestHandler.h"
#import "RCTEventDispatcher.h"
#import "RCTHTTPRequestHandler.h"
#import "RCTLog.h"
#import "RCTUtils.h"
@implementation RCTDataManager
typedef void (^RCTHTTPQueryResult)(NSError *error, NSDictionary *result);
RCT_EXPORT_MODULE()
@interface RCTDataManager ()<RCTURLRequestDelegate>
- (void)processDataForHTTPQuery:(NSDictionary *)data callback:(void (^)(NSError *error, NSDictionary *result))callback;
@end
/**
* Executes a network request.
* The responseSender block won't be called on same thread as called.
* Helper to convert FormData payloads into multipart/formdata requests.
*/
RCT_EXPORT_METHOD(queryData:(NSString *)queryType
withQuery:(NSDictionary *)query
responseSender:(RCTResponseSenderBlock)responseSender)
@interface RCTHTTPFormDataHelper : NSObject
@property (nonatomic, weak) RCTDataManager *dataManager;
@end
@implementation RCTHTTPFormDataHelper
{
if ([queryType isEqualToString:@"http"]) {
NSMutableArray *parts;
NSMutableData *multipartBody;
RCTHTTPQueryResult _callback;
NSString *boundary;
}
// Build request
NSURL *URL = [RCTConvert NSURL:query[@"url"]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
request.HTTPMethod = [RCTConvert NSString:query[@"method"]] ?: @"GET";
request.allHTTPHeaderFields = [RCTConvert NSDictionary:query[@"headers"]];
request.HTTPBody = [RCTConvert NSData:query[@"data"]];
- (void)process:(NSArray *)formData callback:(nonnull void (^)(NSError *error, NSDictionary *result))callback
{
if (![formData count]) {
callback(nil, nil);
return;
}
parts = [formData mutableCopy];
_callback = callback;
multipartBody = [[NSMutableData alloc] init];
boundary = [self generateBoundary];
// Build data task
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError) {
NSDictionary *currentPart = [parts objectAtIndex: 0];
[_dataManager processDataForHTTPQuery:currentPart callback:^(NSError *e, NSDictionary *r) {
[self handleResult:r error:e];
}];
}
NSHTTPURLResponse *httpResponse = nil;
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
// Might be a local file request
httpResponse = (NSHTTPURLResponse *)response;
}
- (NSString *)generateBoundary
{
NSString *const boundaryChars = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_./";
const NSUInteger boundaryLength = 70;
// Build response
NSArray *responseJSON;
if (connectionError == nil) {
NSStringEncoding encoding = NSUTF8StringEncoding;
if (response.textEncodingName) {
CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
}
responseJSON = @[
@(httpResponse.statusCode ?: 200),
httpResponse.allHeaderFields ?: @{},
[[NSString alloc] initWithData:data encoding:encoding] ?: @"",
];
} else {
responseJSON = @[
@(httpResponse.statusCode),
httpResponse.allHeaderFields ?: @{},
connectionError.localizedDescription ?: [NSNull null],
];
}
NSMutableString *output = [NSMutableString stringWithCapacity:boundaryLength];
NSUInteger numchars = [boundaryChars length];
for (NSUInteger i = 0; i < boundaryLength; i++) {
[output appendFormat:@"%C", [boundaryChars characterAtIndex:arc4random_uniform((u_int32_t)numchars)]];
}
return output;
}
// Send response (won't be sent on same thread as caller)
responseSender(responseJSON);
- (void)handleResult:(NSDictionary *)result error:(NSError *)error
{
if (error) {
_callback(error, nil);
return;
}
NSDictionary *currentPart = parts[0];
[parts removeObjectAtIndex:0];
// Start with boundary.
[multipartBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
// Print headers.
NSMutableDictionary *headers = [(NSDictionary*)currentPart[@"headers"] mutableCopy];
NSString *partContentType = result[@"contentType"];
if (partContentType != nil) {
[headers setObject:partContentType forKey:@"content-type"];
}
[headers enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) {
[multipartBody appendData:[[NSString stringWithFormat:@"%@: %@\r\n", parameterKey, parameterValue]
dataUsingEncoding:NSUTF8StringEncoding]];
}];
// Add the body.
[multipartBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[multipartBody appendData:result[@"body"]];
[multipartBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
if ([parts count]) {
NSDictionary *nextPart = [parts objectAtIndex: 0];
[_dataManager processDataForHTTPQuery:nextPart callback:^(NSError *e, NSDictionary *r) {
[self handleResult:r error:e];
}];
return;
}
[task resume];
// We've processed the last item. Finish and return.
[multipartBody appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary]
dataUsingEncoding:NSUTF8StringEncoding]];
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=\"%@\"", boundary];
_callback(nil, @{@"body": multipartBody, @"contentType": contentType});
}
} else {
@end
RCTLogError(@"unsupported query type %@", queryType);
/**
* Helper to package in-flight requests together with their response data.
*/
@interface RCTActiveURLRequest : NSObject
@property (nonatomic, strong) NSNumber *requestID;
@property (nonatomic, strong) NSURLRequest *request;
@property (nonatomic, strong) id<RCTURLRequestHandler> handler;
@property (nonatomic, assign) BOOL incrementalUpdates;
@property (nonatomic, strong) NSURLResponse *response;
@property (nonatomic, strong) NSMutableData *data;
@end
@implementation RCTActiveURLRequest
- (void)setResponse:(NSURLResponse *)response;
{
_response = response;
if (!_incrementalUpdates) {
_data = [[NSMutableData alloc] initWithCapacity:(NSUInteger)MAX(0, response.expectedContentLength)];
}
}
@end
/**
* Helper to load request body data using a handler.
*/
@interface RCTDataLoader : NSObject <RCTURLRequestDelegate>
@end
typedef void (^RCTDataLoaderCallback)(NSData *data, NSString *MIMEType, NSError *error);
@implementation RCTDataLoader
{
RCTDataLoaderCallback _callback;
RCTActiveURLRequest *_request;
id _requestToken;
}
- (instancetype)initWithRequest:(NSURLRequest *)request
handler:(id<RCTURLRequestHandler>)handler
callback:(RCTDataLoaderCallback)callback
{
if ((self = [super init])) {
_callback = callback;
_request = [[RCTActiveURLRequest alloc] init];
_request.request = request;
_request.handler = handler;
_request.incrementalUpdates = NO;
_requestToken = [handler sendRequest:request withDelegate:self];
}
return self;
}
- (void)URLRequest:(id)requestToken didReceiveResponse:(NSURLResponse *)response
{
RCTAssert([requestToken isEqual:_requestToken], @"Shouldn't ever happen");
_request.response = response;
}
- (void)URLRequest:(id)requestToken didReceiveData:(NSData *)data
{
RCTAssert([requestToken isEqual:_requestToken], @"Shouldn't ever happen");
[_request.data appendData:data];
}
- (void)URLRequest:(id)requestToken didCompleteWithError:(NSError *)error
{
RCTAssert(_callback != nil, @"The callback property must be set");
_callback(_request.data, _request.response.MIMEType, error);
}
@end
/**
* Bridge module that provides the JS interface to the network stack.
*/
@implementation RCTDataManager
{
NSInteger _currentRequestID;
NSMapTable *_activeRequests;
}
@synthesize bridge = _bridge;
RCT_EXPORT_MODULE()
- (instancetype)init
{
if ((self = [super init])) {
_currentRequestID = 0;
_activeRequests = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
valueOptions:NSPointerFunctionsStrongMemory
capacity:0];
}
return self;
}
- (void)buildRequest:(NSDictionary *)query
responseSender:(RCTResponseSenderBlock)responseSender
{
NSURL *URL = [RCTConvert NSURL:query[@"url"]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
request.HTTPMethod = [[RCTConvert NSString:query[@"method"]] uppercaseString] ?: @"GET";
request.allHTTPHeaderFields = [RCTConvert NSDictionary:query[@"headers"]];
BOOL incrementalUpdates = [RCTConvert BOOL:query[@"incrementalUpdates"]];
NSDictionary *data = [RCTConvert NSDictionary:query[@"data"]];
[self processDataForHTTPQuery:data callback:^(NSError *error, NSDictionary *result) {
if (error) {
RCTLogError(@"Error processing request body: %@", error);
// Ideally we'd circle back to JS here and notify an error/abort on the request.
return;
}
request.HTTPBody = result[@"body"];
NSString *contentType = result[@"contentType"];
if (contentType) {
[request setValue:contentType forHTTPHeaderField:@"content-type"];
}
[self sendRequest:request
incrementalUpdates:incrementalUpdates
responseSender:responseSender];
}];
}
- (id<RCTURLRequestHandler>)handlerForRequest:(NSURLRequest *)request
{
NSMutableArray *handlers = [NSMutableArray array];
for (id<RCTBridgeModule> module in _bridge.modules.allValues) {
if ([module conformsToProtocol:@protocol(RCTURLRequestHandler)]) {
if ([(id<RCTURLRequestHandler>)module canHandleRequest:request]) {
[handlers addObject:module];
}
}
}
[handlers sortUsingComparator:^NSComparisonResult(id<RCTURLRequestHandler> a, id<RCTURLRequestHandler> b) {
float priorityA = [a respondsToSelector:@selector(handlerPriority)] ? [a handlerPriority] : 0;
float priorityB = [b respondsToSelector:@selector(handlerPriority)] ? [b handlerPriority] : 0;
if (priorityA < priorityB) {
return NSOrderedAscending;
} else if (priorityA > priorityB) {
return NSOrderedDescending;
} else {
RCTLogError(@"The RCTURLRequestHandlers %@ and %@ both reported that"
" they can handle the request %@, and have equal priority"
" (%g). This could result in non-deterministic behavior.",
a, b, request, priorityA);
return NSOrderedSame;
}
}];
id<RCTURLRequestHandler> handler = [handlers lastObject];
if (!handler) {
RCTLogError(@"No suitable request handler found for %@", request);
}
return handler;
}
/**
* Process the 'data' part of an HTTP query.
*
* 'data' can be a JSON value of the following forms:
*
* - {"string": "..."}: a simple JS string that will be UTF-8 encoded and sent as the body
*
* - {"uri": "some-uri://..."}: reference to a system resource, e.g. an image in the asset library
*
* - {"formData": [...]}: list of data payloads that will be combined into a multipart/form-data request
*
* If successful, the callback be called with a result dictionary containing the following (optional) keys:
*
* - @"body" (NSData): the body of the request
*
* - @"contentType" (NSString): the content type header of the request
*
*/
- (void)processDataForHTTPQuery:(NSDictionary *)query callback:(nonnull void (^)(NSError *error, NSDictionary *result))callback
{
if (!query) {
callback(nil, nil);
return;
}
NSData *body = [RCTConvert NSData:query[@"string"]];
if (body) {
callback(nil, @{@"body": body});
return;
}
NSURLRequest *request = [RCTConvert NSURLRequest:query[@"uri"]];
if (request) {
id<RCTURLRequestHandler> handler = [self handlerForRequest:request];
(void)[[RCTDataLoader alloc] initWithRequest:request handler:handler callback:^(NSData *data, NSString *MIMEType, NSError *error) {
if (data) {
callback(nil, @{@"body": data, @"contentType": MIMEType});
} else {
callback(error, nil);
}
}];
return;
}
NSDictionaryArray *formData = [RCTConvert NSDictionaryArray:query[@"formData"]];
if (formData != nil) {
RCTHTTPFormDataHelper *formDataHelper = [[RCTHTTPFormDataHelper alloc] init];
formDataHelper.dataManager = self;
[formDataHelper process:formData callback:callback];
return;
}
// Nothing in the data payload, at least nothing we could understand anyway.
// Ignore and treat it as if it were null.
callback(nil, nil);
}
- (void)sendRequest:(NSURLRequest *)request
incrementalUpdates:(BOOL)incrementalUpdates
responseSender:(RCTResponseSenderBlock)responseSender
{
id<RCTURLRequestHandler> handler = [self handlerForRequest:request];
id token = [handler sendRequest:request withDelegate:self];
if (token) {
RCTActiveURLRequest *activeRequest = [[RCTActiveURLRequest alloc] init];
activeRequest.requestID = @(++_currentRequestID);
activeRequest.request = request;
activeRequest.handler = handler;
activeRequest.incrementalUpdates = incrementalUpdates;
[_activeRequests setObject:activeRequest forKey:token];
responseSender(@[activeRequest.requestID]);
}
}
- (void)sendData:(NSData *)data forRequestToken:(id)requestToken
{
if (data.length == 0) {
return;
}
RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken];
// Get text encoding
NSURLResponse *response = request.response;
NSStringEncoding encoding = NSUTF8StringEncoding;
if (response.textEncodingName) {
CFStringEncoding cfEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
encoding = CFStringConvertEncodingToNSStringEncoding(cfEncoding);
}
NSString *responseText = [[NSString alloc] initWithData:data encoding:encoding];
if (!responseText && data.length) {
RCTLogError(@"Received data was invalid.");
return;
}
NSArray *responseJSON = @[request.requestID, responseText ?: @""];
[_bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkData"
body:responseJSON];
}
#pragma mark - RCTURLRequestDelegate
- (void)URLRequest:(id)requestToken didReceiveResponse:(NSURLResponse *)response
{
RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken];
RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken);
request.response = response;
NSHTTPURLResponse *httpResponse = nil;
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
// Might be a local file request
httpResponse = (NSHTTPURLResponse *)response;
}
NSArray *responseJSON = @[request.requestID,
@(httpResponse.statusCode ?: 200),
httpResponse.allHeaderFields ?: @{},
];
[_bridge.eventDispatcher sendDeviceEventWithName:@"didReceiveNetworkResponse"
body:responseJSON];
}
- (void)URLRequest:(id)requestToken didReceiveData:(NSData *)data
{
RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken];
RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken);
if (request.incrementalUpdates) {
[self sendData:data forRequestToken:requestToken];
} else {
[request.data appendData:data];
}
}
- (void)URLRequest:(id)requestToken didCompleteWithError:(NSError *)error
{
RCTActiveURLRequest *request = [_activeRequests objectForKey:requestToken];
RCTAssert(request != nil, @"Unrecognized request token: %@", requestToken);
if (!request.incrementalUpdates) {
[self sendData:request.data forRequestToken:requestToken];
}
NSArray *responseJSON = @[request.requestID,
error.localizedDescription ?: [NSNull null]
];
[_bridge.eventDispatcher sendDeviceEventWithName:@"didCompleteNetworkResponse"
body:responseJSON];
[_activeRequests removeObjectForKey:requestToken];
}
#pragma mark - JS API
RCT_EXPORT_METHOD(sendRequest:(NSDictionary *)query
responseSender:(RCTResponseSenderBlock)responseSender)
{
[self buildRequest:query responseSender:responseSender];
}
RCT_EXPORT_METHOD(cancelRequest:(NSNumber *)requestID)
{
id requestToken = nil;
RCTActiveURLRequest *activeRequest = nil;
for (id token in _activeRequests) {
RCTActiveURLRequest *request = [_activeRequests objectForKey:token];
if ([request.requestID isEqualToNumber:requestID]) {
activeRequest = request;
requestToken = token;
break;
}
}
id<RCTURLRequestHandler> handler = activeRequest.handler;
if ([handler respondsToSelector:@selector(cancelRequest:)]) {
[activeRequest.handler cancelRequest:requestToken];
}
}

View File

@ -7,11 +7,9 @@
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "RCTURLRequestHandler.h"
#import "RCTInvalidating.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
@interface RCTHTTPRequestHandler : NSObject <RCTURLRequestHandler, RCTInvalidating>
@end

View File

@ -0,0 +1,107 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTHTTPRequestHandler.h"
#import "RCTAssert.h"
#import "RCTConvert.h"
#import "RCTEventDispatcher.h"
#import "RCTImageLoader.h"
#import "RCTLog.h"
#import "RCTUtils.h"
@interface RCTHTTPRequestHandler () <NSURLSessionDataDelegate>
@end
@implementation RCTHTTPRequestHandler
{
NSMapTable *_delegates;
NSURLSession *_session;
}
RCT_EXPORT_MODULE()
- (instancetype)init
{
if ((self = [super init])) {
_delegates = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory
valueOptions:NSPointerFunctionsStrongMemory
capacity:0];
}
return self;
}
- (void)invalidate
{
[_session invalidateAndCancel];
_session = nil;
_delegates = nil;
}
- (BOOL)isValid
{
return _delegates != nil;
}
#pragma mark - NSURLRequestHandler
- (BOOL)canHandleRequest:(NSURLRequest *)request
{
return [@[@"http", @"https", @"file"] containsObject:[request.URL.scheme lowercaseString]];
}
- (id)sendRequest:(NSURLRequest *)request
withDelegate:(id<RCTURLRequestDelegate>)delegate
{
// Lazy setup
if (!_session && [self isValid]) {
NSOperationQueue *callbackQueue = [[NSOperationQueue alloc] init];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:configuration
delegate:self
delegateQueue:callbackQueue];
}
NSURLSessionDataTask *task = [_session dataTaskWithRequest:request];
[_delegates setObject:delegate forKey:task];
[task resume];
return task;
}
- (void)cancelRequest:(NSURLSessionDataTask *)requestToken
{
[requestToken cancel];
}
#pragma mark - NSURLSession delegate
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)task
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
[[_delegates objectForKey:task] URLRequest:task didReceiveResponse:response];
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)task
didReceiveData:(NSData *)data
{
[[_delegates objectForKey:task] URLRequest:task didReceiveData:data];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
[[_delegates objectForKey:task] URLRequest:task didCompleteWithError:error];
[_delegates removeObjectForKey:task];
}
@end

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
1372B7371AB03E7B00659ED6 /* RCTReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 1372B7361AB03E7B00659ED6 /* RCTReachability.m */; };
352DA0BA1B17855800AA15A8 /* RCTHTTPRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 352DA0B81B17855800AA15A8 /* RCTHTTPRequestHandler.m */; };
58B512081A9E6CE300147676 /* RCTDataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B512071A9E6CE300147676 /* RCTDataManager.m */; };
/* End PBXBuildFile section */
@ -26,6 +27,8 @@
/* Begin PBXFileReference section */
1372B7351AB03E7B00659ED6 /* RCTReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTReachability.h; sourceTree = "<group>"; };
1372B7361AB03E7B00659ED6 /* RCTReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTReachability.m; sourceTree = "<group>"; };
352DA0B71B17855800AA15A8 /* RCTHTTPRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTHTTPRequestHandler.h; sourceTree = "<group>"; };
352DA0B81B17855800AA15A8 /* RCTHTTPRequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTHTTPRequestHandler.m; sourceTree = "<group>"; };
58B511DB1A9E6C8500147676 /* libRCTNetwork.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTNetwork.a; sourceTree = BUILT_PRODUCTS_DIR; };
58B512061A9E6CE300147676 /* RCTDataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDataManager.h; sourceTree = "<group>"; };
58B512071A9E6CE300147676 /* RCTDataManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDataManager.m; sourceTree = "<group>"; };
@ -47,6 +50,8 @@
children = (
58B512061A9E6CE300147676 /* RCTDataManager.h */,
58B512071A9E6CE300147676 /* RCTDataManager.m */,
352DA0B71B17855800AA15A8 /* RCTHTTPRequestHandler.h */,
352DA0B81B17855800AA15A8 /* RCTHTTPRequestHandler.m */,
1372B7351AB03E7B00659ED6 /* RCTReachability.h */,
1372B7361AB03E7B00659ED6 /* RCTReachability.m */,
58B511DC1A9E6C8500147676 /* Products */,
@ -121,6 +126,7 @@
files = (
1372B7371AB03E7B00659ED6 /* RCTReachability.m in Sources */,
58B512081A9E6CE300147676 /* RCTDataManager.m in Sources */,
352DA0BA1B17855800AA15A8 /* RCTHTTPRequestHandler.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -209,6 +215,7 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../Image/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
@ -226,6 +233,7 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../Image/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";

View File

@ -11,30 +11,102 @@
*/
'use strict';
var FormData = require('FormData');
var RCTDataManager = require('NativeModules').DataManager;
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var XMLHttpRequestBase = require('XMLHttpRequestBase');
class XMLHttpRequest extends XMLHttpRequestBase {
_requestId: ?number;
_subscriptions: [any];
constructor() {
super();
this._requestId = null;
this._subscriptions = [];
}
_didCreateRequest(requestId: number): void {
this._requestId = requestId;
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
'didReceiveNetworkResponse',
(args) => this._didReceiveResponse.call(this, args[0], args[1], args[2])
));
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
'didReceiveNetworkData',
(args) => this._didReceiveData.call(this, args[0], args[1])
));
this._subscriptions.push(RCTDeviceEventEmitter.addListener(
'didCompleteNetworkResponse',
(args) => this._didCompleteResponse.call(this, args[0], args[1])
));
}
_didReceiveResponse(requestId: number, status: number, responseHeaders: ?Object): void {
if (requestId === this._requestId) {
this.status = status;
this.setResponseHeaders(responseHeaders);
this.setReadyState(this.HEADERS_RECEIVED);
}
}
_didReceiveData(requestId: number, responseText: string): void {
if (requestId === this._requestId) {
if (!this.responseText) {
this.responseText = responseText;
} else {
this.responseText += responseText;
}
this.setReadyState(this.LOADING);
}
}
_didCompleteResponse(requestId: number, error: string): void {
if (requestId === this._requestId) {
if (error) {
this.responseText = error;
}
this._clearSubscriptions();
this._requestId = null;
this.setReadyState(this.DONE);
}
}
_clearSubscriptions(): void {
for (var i = 0; i < this._subscriptions.length; i++) {
var sub = this._subscriptions[i];
sub.remove();
}
this._subscriptions = [];
}
sendImpl(method: ?string, url: ?string, headers: Object, data: any): void {
RCTDataManager.queryData(
'http',
if (typeof data === 'string') {
data = {string: data};
}
if (data instanceof FormData) {
data = {formData: data.getParts()};
}
RCTDataManager.sendRequest(
{
method: method,
url: url,
data: data,
headers: headers,
method,
url,
data,
headers,
incrementalUpdates: this.onreadystatechange ? true : false,
},
this.callback.bind(this)
this._didCreateRequest.bind(this)
);
}
abortImpl(): void {
console.warn(
'XMLHttpRequest: abort() cancels JS callbacks ' +
'but not native HTTP request.'
);
if (this._requestId) {
RCTDataManager.cancelRequest(this._requestId);
this._clearSubscriptions();
this._requestId = null;
}
}
}

View File

@ -1,8 +1,13 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @flow
* @providesModule XMLHttpRequestBase
* @flow
*/
'use strict';
@ -30,6 +35,7 @@ class XMLHttpRequestBase {
_headers: Object;
_sent: boolean;
_aborted: boolean;
_lowerCaseResponseHeaders: Object;
constructor() {
this.UNSENT = 0;
@ -38,46 +44,52 @@ class XMLHttpRequestBase {
this.LOADING = 3;
this.DONE = 4;
this.onreadystatechange = undefined;
this.upload = undefined; /* Upload not supported */
this.readyState = this.UNSENT;
this.responseHeaders = undefined;
this.responseText = undefined;
this.status = 0;
this.onreadystatechange = null;
this.onload = null;
this.upload = undefined; /* Upload not supported yet */
this._reset();
this._method = null;
this._url = null;
this._headers = {};
this._sent = false;
this._aborted = false;
}
_reset() {
this.readyState = this.UNSENT;
this.responseHeaders = undefined;
this.responseText = '';
this.status = 0;
this._headers = {};
this._sent = false;
this._lowerCaseResponseHeaders = {};
}
getAllResponseHeaders(): ?string {
if (this.responseHeaders) {
var headers = [];
for (var headerName in this.responseHeaders) {
headers.push(headerName + ': ' + this.responseHeaders[headerName]);
}
return headers.join('\n');
if (!this.responseHeaders) {
// according to the spec, return null if no response has been received
return null;
}
// according to the spec, return null <==> no response has been received
return null;
var headers = this.responseHeaders || {};
return Object.keys(headers).map((headerName) => {
return headerName + ': ' + headers[headerName];
}).join('\n');
}
getResponseHeader(header: string): ?string {
if (this.responseHeaders) {
var value = this.responseHeaders[header.toLowerCase()];
return value !== undefined ? value : null;
}
return null;
var value = this._lowerCaseResponseHeaders[header.toLowerCase()];
return value !== undefined ? value : null;
}
setRequestHeader(header: string, value: any): void {
if (this.readyState !== this.OPENED) {
throw new Error('Request has not been opened');
}
this._headers[header.toLowerCase()] = value;
}
open(method: string, url: string, async: ?boolean): void {
/* Other optional arguments are not supported */
/* Other optional arguments are not supported yet */
if (this.readyState !== this.UNSENT) {
throw new Error('Cannot open, already sending');
}
@ -85,10 +97,11 @@ class XMLHttpRequestBase {
// async is default
throw new Error('Synchronous http requests are not supported');
}
this._reset();
this._method = method;
this._url = url;
this._aborted = false;
this._setReadyState(this.OPENED);
this.setReadyState(this.OPENED);
}
sendImpl(method: ?string, url: ?string, headers: Object, data: any): void {
@ -111,20 +124,18 @@ class XMLHttpRequestBase {
}
abort(): void {
this._aborted = true;
this.abortImpl();
// only call onreadystatechange if there is something to abort,
// below logic is per spec
if (!(this.readyState === this.UNSENT ||
(this.readyState === this.OPENED && !this._sent) ||
this.readyState === this.DONE)) {
this._sent = false;
this._setReadyState(this.DONE);
this._reset();
this.setReadyState(this.DONE);
}
if (this.readyState === this.DONE) {
this._sendLoad();
}
this.readyState = this.UNSENT;
this._aborted = true;
// Reset again after, in case modified in handler
this._reset();
}
callback(status: number, responseHeaders: ?Object, responseText: string): void {
@ -132,18 +143,22 @@ class XMLHttpRequestBase {
return;
}
this.status = status;
// Headers should be case-insensitive
var lcResponseHeaders = {};
for (var header in responseHeaders) {
lcResponseHeaders[header.toLowerCase()] = responseHeaders[header];
}
this.responseHeaders = lcResponseHeaders;
this.setResponseHeaders(responseHeaders);
this.responseText = responseText;
this._setReadyState(this.DONE);
this._sendLoad();
this.setReadyState(this.DONE);
}
_setReadyState(newState: number): void {
setResponseHeaders(responseHeaders: ?Object): void {
this.responseHeaders = responseHeaders || null;
var headers = responseHeaders || {};
this._lowerCaseResponseHeaders =
Object.keys(headers).reduce((lcaseHeaders, headerName) => {
lcaseHeaders[headerName.toLowerCase()] = headers[headerName];
return headers;
}, {});
}
setReadyState(newState: number): void {
this.readyState = newState;
// TODO: workaround flow bug with nullable function checks
var onreadystatechange = this.onreadystatechange;
@ -152,6 +167,9 @@ class XMLHttpRequestBase {
// event anywhere, let's leave it empty
onreadystatechange(null);
}
if (newState === this.DONE && !this._aborted) {
this._sendLoad();
}
}
_sendLoad(): void {

View File

@ -121,7 +121,7 @@ RCT_EXPORT_METHOD(getApplicationIconBadgeNumber:(RCTResponseSenderBlock)callback
RCT_EXPORT_METHOD(requestPermissions:(NSDictionary *)permissions)
{
UIUserNotificationType types = UIRemoteNotificationTypeNone;
UIUserNotificationType types = UIUserNotificationTypeNone;
if (permissions) {
if ([permissions[@"alert"] boolValue]) {
types |= UIUserNotificationTypeAlert;

View File

@ -69,4 +69,21 @@ RCT_EXPORT_METHOD(sendAppEvent:(NSString *)name body:(id)body)
[_bridge.eventDispatcher sendAppEventWithName:name body:body];
}
RCT_REMAP_METHOD(shouldResolve, shouldResolve_resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
{
resolve(@1);
}
RCT_REMAP_METHOD(shouldReject, shouldReject_resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
{
reject(nil);
}
RCT_EXPORT_METHOD(finish:(BOOL)success)
{
RCTAssert(success, @"RCTTestModule finished without success");
[self markTestCompleted];
}
@end

View File

@ -35,6 +35,7 @@ var createReactNativeComponentClass = function(
this.previousFlattenedStyle = null;
};
Constructor.displayName = viewConfig.uiViewClassName;
Constructor.viewConfig = viewConfig;
Constructor.prototype = new ReactNativeBaseComponent(viewConfig);
Constructor.prototype.constructor = Constructor;

View File

@ -13,7 +13,6 @@
var StyleSheetRegistry = require('StyleSheetRegistry');
var invariant = require('invariant');
var mergeIntoFast = require('mergeIntoFast');
type Atom = number | bool | Object | Array<?Atom>
type StyleObj = Atom | Array<?StyleObj>
@ -25,10 +24,7 @@ function getStyle(style) {
return style;
}
// TODO: Flow 0.7.0 doesn't refine bools properly so we have to use `any` to
// tell it that this can't be a bool anymore. Should be fixed in 0.8.0,
// after which this can take a ?StyleObj.
function flattenStyle(style: any): ?Object {
function flattenStyle(style: ?StyleObj): ?Object {
if (!style) {
return undefined;
}
@ -42,7 +38,13 @@ function flattenStyle(style: any): ?Object {
for (var i = 0; i < style.length; ++i) {
var computedStyle = flattenStyle(style[i]);
if (computedStyle) {
mergeIntoFast(result, computedStyle);
for (var key in computedStyle) {
result[key] = computedStyle[key];
if (__DEV__) {
var value = computedStyle[key];
}
}
}
}
return result;

View File

@ -127,7 +127,7 @@ function _convertToRadians(value: string): number {
function _validateTransform(key, value, transformation) {
invariant(
!value.getValue,
'You passed an animated value or spring to a normal component. ' +
'You passed an Animated.Value to a normal component. ' +
'You need to wrap that component in an Animated. For example, ' +
'replace <View /> by <Animated.View />.'
);

View File

@ -514,10 +514,10 @@ var MessageQueueMixin = {
);
// Store callback _before_ sending the request, just in case the MailBox
// returns the response in a blocking manner.
if (onSucc) {
if (onFail || onSucc) {
this._storeCallbacksInCurrentThread(onFail, onSucc, scope, this._POOLED_CBIDS);
onFail && params.push(this._POOLED_CBIDS.errorCallbackID);
params.push(this._POOLED_CBIDS.successCallbackID);
onSucc && params.push(this._POOLED_CBIDS.successCallbackID);
}
var moduleID = this._remoteModuleNameToModuleID[moduleName];
if (moduleID === undefined || moduleID === null) {

View File

@ -31,8 +31,11 @@ typedef void (^RCTWSMessageCallback)(NSError *error, NSDictionary *reply);
RCTSparseArray *_callbacks;
dispatch_semaphore_t _socketOpenSemaphore;
NSMutableDictionary *_injectedObjects;
NSURL *_url;
}
RCT_EXPORT_MODULE()
- (instancetype)init
{
return [self initWithURL:[NSURL URLWithString:@"http://localhost:8081/debugger-proxy"]];
@ -41,41 +44,45 @@ typedef void (^RCTWSMessageCallback)(NSError *error, NSDictionary *reply);
- (instancetype)initWithURL:(NSURL *)URL
{
if (self = [super init]) {
_jsQueue = dispatch_queue_create("com.facebook.React.WebSocketExecutor", DISPATCH_QUEUE_SERIAL);
_socket = [[RCTSRWebSocket alloc] initWithURL:URL];
_socket.delegate = self;
_callbacks = [[RCTSparseArray alloc] init];
_injectedObjects = [[NSMutableDictionary alloc] init];
[_socket setDelegateDispatchQueue:_jsQueue];
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-chrome-devtools" relativeToURL:URL];
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil];
if (![self connectToProxy]) {
RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If \
you are running on the device, check if you have the right IP \
address in `RCTWebSocketExecutor.m`.", URL);
[self invalidate];
return nil;
}
NSInteger retries = 3;
BOOL runtimeIsReady = [self prepareJSRuntime];
while (!runtimeIsReady && retries > 0) {
runtimeIsReady = [self prepareJSRuntime];
retries--;
}
if (!runtimeIsReady) {
RCTLogError(@"Runtime is not ready. Make sure Chrome is running and not "
"paused on a breakpoint or exception and try reloading again.");
[self invalidate];
return nil;
}
_url = URL;
}
return self;
}
- (void)setUp
{
_jsQueue = dispatch_queue_create("com.facebook.React.WebSocketExecutor", DISPATCH_QUEUE_SERIAL);
_socket = [[RCTSRWebSocket alloc] initWithURL:_url];
_socket.delegate = self;
_callbacks = [[RCTSparseArray alloc] init];
_injectedObjects = [[NSMutableDictionary alloc] init];
[_socket setDelegateDispatchQueue:_jsQueue];
NSURL *startDevToolsURL = [NSURL URLWithString:@"/launch-chrome-devtools" relativeToURL:_url];
[NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:startDevToolsURL] delegate:nil];
if (![self connectToProxy]) {
RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If \
you are running on the device, check if you have the right IP \
address in `RCTWebSocketExecutor.m`.", _url);
[self invalidate];
return;
}
NSInteger retries = 3;
BOOL runtimeIsReady = [self prepareJSRuntime];
while (!runtimeIsReady && retries > 0) {
runtimeIsReady = [self prepareJSRuntime];
retries--;
}
if (!runtimeIsReady) {
RCTLogError(@"Runtime is not ready. Make sure Chrome is running and not "
"paused on a breakpoint or exception and try reloading again.");
[self invalidate];
return;
}
}
- (BOOL)connectToProxy
{
_socketOpenSemaphore = dispatch_semaphore_create(0);

View File

@ -62,6 +62,7 @@ var ReactNative = Object.assign(Object.create(require('React')), {
DeviceEventEmitter: require('RCTDeviceEventEmitter'),
NativeAppEventEmitter: require('RCTNativeAppEventEmitter'),
NativeModules: require('NativeModules'),
Platform: require('Platform'),
requireNativeComponent: require('requireNativeComponent'),
addons: {

View File

@ -47,12 +47,17 @@ typedef NS_ENUM(NSUInteger, RCTBridgeFields) {
RCTBridgeFieldFlushDateMillis
};
typedef NS_ENUM(NSUInteger, RCTJavaScriptFunctionKind) {
RCTJavaScriptFunctionKindNormal,
RCTJavaScriptFunctionKindAsync,
};
#ifdef __LP64__
typedef uint64_t RCTHeaderValue;
typedef struct mach_header_64 *RCTHeaderValue;
typedef struct section_64 RCTHeaderSection;
#define RCTGetSectByNameFromHeader getsectbynamefromheader_64
#else
typedef uint32_t RCTHeaderValue;
typedef struct mach_header *RCTHeaderValue;
typedef struct section RCTHeaderSection;
#define RCTGetSectByNameFromHeader getsectbynamefromheader
#endif
@ -98,15 +103,15 @@ static NSArray *RCTJSMethods(void)
dladdr(&RCTJSMethods, &info);
const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase;
const RCTHeaderSection *section = RCTGetSectByNameFromHeader((void *)mach_header, "__DATA", "RCTImport");
if (section) {
for (RCTHeaderValue addr = section->offset;
addr < section->offset + section->size;
unsigned long size = 0;
const uint8_t *sectionData = getsectiondata(mach_header, "__DATA", "RCTImport", &size);
if (sectionData) {
for (const uint8_t *addr = sectionData;
addr < sectionData + size;
addr += sizeof(const char **)) {
// Get data entry
NSString *entry = @(*(const char **)(mach_header + addr));
NSString *entry = @(*(const char **)addr);
[uniqueMethods addObject:entry];
}
}
@ -139,15 +144,15 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void)
dladdr(&RCTBridgeModuleClassesByModuleID, &info);
const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase;
const RCTHeaderSection *section = RCTGetSectByNameFromHeader((void *)mach_header, "__DATA", "RCTExportModule");
if (section) {
for (RCTHeaderValue addr = section->offset;
addr < section->offset + section->size;
unsigned long size;
const uint8_t *sectionData = getsectiondata(mach_header, "__DATA", "RCTExportModule", &size);
if (sectionData) {
for (const uint8_t *addr = sectionData;
addr < sectionData + size;
addr += sizeof(const char **)) {
// Get data entry
NSString *entry = @(*(const char **)(mach_header + addr));
NSString *entry = @(*(const char **)addr);
NSArray *parts = [[entry substringWithRange:(NSRange){2, entry.length - 3}]
componentsSeparatedByString:@" "];
@ -204,6 +209,27 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void)
return RCTModuleClassesByID;
}
// TODO: Can we just replace RCTMakeError with this function instead?
static NSDictionary *RCTJSErrorFromNSError(NSError *error)
{
NSString *errorMessage;
NSArray *stackTrace = [NSThread callStackSymbols];
NSMutableDictionary *errorInfo =
[NSMutableDictionary dictionaryWithObject:stackTrace forKey:@"nativeStackIOS"];
if (error) {
errorMessage = error.localizedDescription ?: @"Unknown error from a native module";
errorInfo[@"domain"] = error.domain ?: RCTErrorDomain;
errorInfo[@"code"] = @(error.code);
} else {
errorMessage = @"Unknown error from a native module";
errorInfo[@"domain"] = RCTErrorDomain;
errorInfo[@"code"] = @-1;
}
return RCTMakeError(errorMessage, nil, errorInfo);
}
@class RCTBatchedBridge;
@interface RCTBridge ()
@ -239,6 +265,7 @@ static NSArray *RCTBridgeModuleClassesByModuleID(void)
@property (nonatomic, copy, readonly) NSString *moduleClassName;
@property (nonatomic, copy, readonly) NSString *JSMethodName;
@property (nonatomic, assign, readonly) SEL selector;
@property (nonatomic, assign, readonly) RCTJavaScriptFunctionKind functionKind;
@end
@ -390,22 +417,64 @@ case _value: { \
[invocation setArgument:returnValue atIndex:index];
free(returnValue);
}];
break;
free(returnValue);
}];
break;
}
default:
defaultCase(argumentType);
}
} else if ([argumentName isEqualToString:@"RCTResponseSenderBlock"]) {
addBlockArgument();
} else if ([argumentName isEqualToString:@"RCTPromiseResolveBlock"]) {
RCTAssert(i == numberOfArguments - 2,
@"The RCTPromiseResolveBlock must be the second to last parameter in -[%@ %@]",
_moduleClassName, objCMethodName);
RCT_ARG_BLOCK(
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
RCTLogError(@"Argument %tu (%@) of %@.%@ must be a promise resolver ID", index,
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
return;
}
default:
defaultCase(argumentType);
}
} else if ([argumentName isEqualToString:@"RCTResponseSenderBlock"]) {
addBlockArgument();
} else {
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
__autoreleasing RCTPromiseResolveBlock value = (^(id result) {
NSArray *arguments = result ? @[result] : @[];
[bridge _invokeAndProcessModule:@"BatchedBridge"
method:@"invokeCallbackAndReturnFlushedQueue"
arguments:@[json, arguments]
context:context];
});
)
_functionKind = RCTJavaScriptFunctionKindAsync;
} else if ([argumentName isEqualToString:@"RCTPromiseRejectBlock"]) {
RCTAssert(i == numberOfArguments - 1,
@"The RCTPromiseRejectBlock must be the last parameter in -[%@ %@]",
_moduleClassName, objCMethodName);
RCT_ARG_BLOCK(
if (RCT_DEBUG && ![json isKindOfClass:[NSNumber class]]) {
RCTLogError(@"Argument %tu (%@) of %@.%@ must be a promise rejecter ID", index,
json, RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName);
return;
}
// Unknown argument type
RCTLogError(@"Unknown argument type '%@' in method %@. Extend RCTConvert"
" to support this type.", argumentName, [self methodName]);
}
// Marked as autoreleasing, because NSInvocation doesn't retain arguments
__autoreleasing RCTPromiseRejectBlock value = (^(NSError *error) {
NSDictionary *errorJSON = RCTJSErrorFromNSError(error);
[bridge _invokeAndProcessModule:@"BatchedBridge"
method:@"invokeCallbackAndReturnFlushedQueue"
arguments:@[json, @[errorJSON]]
context:context];
});
)
_functionKind = RCTJavaScriptFunctionKindAsync;
} else {
// Unknown argument type
RCTLogError(@"Unknown argument type '%@' in method %@. Extend RCTConvert"
" to support this type.", argumentName, [self methodName]);
}
}
_argumentBlocks = [argumentBlocks copy];
@ -427,9 +496,18 @@ case _value: { \
// Safety check
if (arguments.count != _argumentBlocks.count) {
NSInteger actualCount = arguments.count;
NSInteger expectedCount = _argumentBlocks.count;
// Subtract the implicit Promise resolver and rejecter functions for implementations of async functions
if (_functionKind == RCTJavaScriptFunctionKindAsync) {
actualCount -= 2;
expectedCount -= 2;
}
RCTLogError(@"%@.%@ was called with %zd arguments, but expects %zd",
RCTBridgeModuleNameForClass(_moduleClass), _JSMethodName,
arguments.count, _argumentBlocks.count);
actualCount, expectedCount);
return;
}
}
@ -481,21 +559,23 @@ static RCTSparseArray *RCTExportedMethodsByModuleID(void)
dladdr(&RCTExportedMethodsByModuleID, &info);
const RCTHeaderValue mach_header = (RCTHeaderValue)info.dli_fbase;
const RCTHeaderSection *section = RCTGetSectByNameFromHeader((void *)mach_header, "__DATA", "RCTExport");
if (section == NULL) {
unsigned long size;
const uint8_t *sectionData = getsectiondata(mach_header, "__DATA", "RCTExport", &size);
if (sectionData == NULL) {
return;
}
NSArray *classes = RCTBridgeModuleClassesByModuleID();
NSMutableDictionary *methodsByModuleClassName = [NSMutableDictionary dictionaryWithCapacity:[classes count]];
for (RCTHeaderValue addr = section->offset;
addr < section->offset + section->size;
for (const uint8_t *addr = sectionData;
addr < sectionData + size;
addr += sizeof(const char **) * 3) {
// Get data entry
const char **entries = (const char **)(mach_header + addr);
const char **entries = (const char **) addr;
// Create method
RCTModuleMethod *moduleMethod =
@ -533,7 +613,7 @@ static RCTSparseArray *RCTExportedMethodsByModuleID(void)
* },
* "methodName2": {
* "methodID": 1,
* "type": "remote"
* "type": "remoteAsync"
* },
* etc...
* },
@ -557,7 +637,7 @@ static NSDictionary *RCTRemoteModulesConfig(NSDictionary *modulesByName)
[methods enumerateObjectsUsingBlock:^(RCTModuleMethod *method, NSUInteger methodID, BOOL *_stop) {
methodsByName[method.JSMethodName] = @{
@"methodID": @(methodID),
@"type": @"remote",
@"type": method.functionKind == RCTJavaScriptFunctionKindAsync ? @"remoteAsync" : @"remote",
};
}];
@ -819,7 +899,7 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
@implementation RCTBatchedBridge
{
BOOL _loading;
id<RCTJavaScriptExecutor> _javaScriptExecutor;
__weak id<RCTJavaScriptExecutor> _javaScriptExecutor;
RCTSparseArray *_modulesByID;
RCTSparseArray *_queuesByID;
dispatch_queue_t _methodQueue;
@ -856,13 +936,6 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
[_mainDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
/**
* Initialize executor to allow enqueueing calls
*/
Class executorClass = self.executorClass ?: [RCTContextExecutor class];
_javaScriptExecutor = RCTCreateExecutor(executorClass);
_latestJSExecutor = _javaScriptExecutor;
/**
* Initialize and register bridge modules *before* adding the display link
* so we don't have threading issues
@ -900,7 +973,7 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
- (Class)executorClass
{
return _parentBridge.executorClass;
return _parentBridge.executorClass ?: [RCTContextExecutor class];
}
- (void)setExecutorClass:(Class)executorClass
@ -965,6 +1038,16 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
// Store modules
_modulesByName = [modulesByName copy];
/**
* The executor is a bridge module, wait for it to be created and set it before
* any other module has access to the bridge
*/
_javaScriptExecutor = _modulesByName[RCTBridgeModuleNameForClass(self.executorClass)];
_latestJSExecutor = _javaScriptExecutor;
RCTSetExecutorID(_javaScriptExecutor);
[_javaScriptExecutor setUp];
// Set bridge
for (id<RCTBridgeModule> module in _modulesByName.allValues) {
if ([module respondsToSelector:@selector(setBridge:)]) {
@ -1081,6 +1164,10 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
- (NSDictionary *)modules
{
if (!self.isValid) {
return nil;
}
RCTAssert(_modulesByName != nil, @"Bridge modules have not yet been initialized. "
"You may be trying to access a module too early in the startup procedure.");
@ -1111,7 +1198,9 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
// Invalidate modules
for (id target in _modulesByID.allObjects) {
if ([target respondsToSelector:@selector(invalidate)]) {
[(id<RCTInvalidating>)target invalidate];
[self dispatchBlock:^{
[(id<RCTInvalidating>)target invalidate];
} forModule:target];
}
}
@ -1373,15 +1462,42 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
return;
}
// TODO: if we sort the requests by module, we could dispatch once per
// module instead of per request, which would reduce the call overhead.
NSMapTable *buckets = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:_queuesByID.count];
for (NSUInteger i = 0; i < numRequests; i++) {
@autoreleasepool {
[self _handleRequestNumber:i
moduleID:[moduleIDs[i] integerValue]
methodID:[methodIDs[i] integerValue]
params:paramsArrays[i]
context:context];
id queue = RCTNullIfNil(_queuesByID[moduleIDs[i]]);
NSMutableOrderedSet *set = [buckets objectForKey:queue];
if (!set) {
set = [[NSMutableOrderedSet alloc] init];
[buckets setObject:set forKey:queue];
}
[set addObject:@(i)];
}
for (id queue in buckets) {
RCTProfileBeginFlowEvent();
dispatch_block_t block = ^{
RCTProfileEndFlowEvent();
RCTProfileBeginEvent();
NSOrderedSet *calls = [buckets objectForKey:queue];
@autoreleasepool {
for (NSNumber *indexObj in calls) {
NSUInteger index = indexObj.unsignedIntegerValue;
[self _handleRequestNumber:index
moduleID:[moduleIDs[index] integerValue]
methodID:[methodIDs[index] integerValue]
params:paramsArrays[index]
context:context];
}
}
RCTProfileEndEvent(RCTCurrentThreadName(), @"objc_call,dispatch_async", @{ @"calls": @(calls.count) });
};
if (queue == (id)kCFNull) {
[_javaScriptExecutor executeBlockOnJavaScriptQueue:block];
} else {
dispatch_async(queue, block);
}
}
@ -1401,8 +1517,6 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
params:(NSArray *)params
context:(NSNumber *)context
{
RCTAssertJSThread();
if (!self.isValid) {
return NO;
}
@ -1420,6 +1534,8 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
return NO;
}
RCTProfileBeginEvent();
RCTModuleMethod *method = methods[methodID];
// Look up module
@ -1429,36 +1545,22 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
return NO;
}
RCTProfileBeginFlowEvent();
__weak RCTBatchedBridge *weakSelf = self;
[self dispatchBlock:^{
RCTProfileEndFlowEvent();
RCTProfileBeginEvent();
RCTBatchedBridge *strongSelf = weakSelf;
if (!strongSelf.isValid) {
// strongSelf has been invalidated since the dispatch_async call and this
// invocation should not continue.
return;
@try {
[method invokeWithBridge:self module:module arguments:params context:context];
}
@catch (NSException *exception) {
RCTLogError(@"Exception thrown while invoking %@ on target %@ with params %@: %@", method.JSMethodName, module, params, exception);
if (!RCT_DEBUG && [exception.name rangeOfString:@"Unhandled JS Exception"].location != NSNotFound) {
@throw exception;
}
}
@try {
[method invokeWithBridge:strongSelf module:module arguments:params context:context];
}
@catch (NSException *exception) {
RCTLogError(@"Exception thrown while invoking %@ on target %@ with params %@: %@", method.JSMethodName, module, params, exception);
if (!RCT_DEBUG && [exception.name rangeOfString:@"Unhandled JS Exception"].location != NSNotFound) {
@throw exception;
}
}
RCTProfileEndEvent(@"Invoke callback", @"objc_call", @{
@"module": method.moduleClassName,
@"method": method.JSMethodName,
@"selector": NSStringFromSelector(method.selector),
@"args": RCTJSONStringify(params ?: [NSNull null], NULL),
});
} forModuleID:@(moduleID)];
RCTProfileEndEvent(@"Invoke callback", @"objc_call", @{
@"module": method.moduleClassName,
@"method": method.JSMethodName,
@"selector": NSStringFromSelector(method.selector),
@"args": RCTJSONStringify(params ?: [NSNull null], NULL),
});
return YES;
}

View File

@ -17,6 +17,20 @@
*/
typedef void (^RCTResponseSenderBlock)(NSArray *response);
/**
* Block that bridge modules use to resolve the JS promise waiting for a result.
* Nil results are supported and are converted to JS's undefined value.
*/
typedef void (^RCTPromiseResolveBlock)(id result);
/**
* Block that bridge modules use to reject the JS promise waiting for a result.
* The error may be nil but it is preferable to pass an NSError object for more
* precise error messages.
*/
typedef void (^RCTPromiseRejectBlock)(NSError *error);
/**
* This constant can be returned from +methodQueue to force module
* methods to be called on the JavaScript thread. This can have serious
@ -37,7 +51,7 @@ extern const dispatch_queue_t RCTJSThread;
* A reference to the RCTBridge. Useful for modules that require access
* to bridge features, such as sending events or making JS calls. This
* will be set automatically by the bridge when it initializes the module.
* To implement this in your module, just add @synthesize bridge = _bridge;
* To implement this in your module, just add @synthesize bridge = _bridge;
*/
@property (nonatomic, weak) RCTBridge *bridge;
@ -70,6 +84,26 @@ extern const dispatch_queue_t RCTJSThread;
* { ... }
*
* and is exposed to JavaScript as `NativeModules.ModuleName.doSomething`.
*
* ## Promises
*
* Bridge modules can also define methods that are exported to JavaScript as
* methods that return a Promise, and are compatible with JS async functions.
*
* Declare the last two parameters of your native method to be a resolver block
* and a rejecter block. The resolver block must precede the rejecter block.
*
* For example:
*
* RCT_EXPORT_METHOD(doSomethingAsync:(NSString *)aString
* resolver:(RCTPromiseResolveBlock)resolve
* rejecter:(RCTPromiseRejectBlock)reject
* { ... }
*
* Calling `NativeModules.ModuleName.doSomethingAsync(aString)` from
* JavaScript will return a promise that is resolved or rejected when your
* native method implementation calls the respective block.
*
*/
#define RCT_EXPORT_METHOD(method) \
RCT_REMAP_METHOD(, method)
@ -118,7 +152,7 @@ extern const dispatch_queue_t RCTJSThread;
RCT_EXTERN_REMAP_MODULE(, objc_name, objc_supername)
/**
* Similar to RCT_EXTERN_MODULE but allows setting a custom JavaScript name
* Like RCT_EXTERN_MODULE, but allows setting a custom JavaScript name.
*/
#define RCT_EXTERN_REMAP_MODULE(js_name, objc_name, objc_supername) \
objc_name : objc_supername \
@ -136,7 +170,7 @@ extern const dispatch_queue_t RCTJSThread;
RCT_EXTERN_REMAP_METHOD(, method)
/**
* Similar to RCT_EXTERN_REMAP_METHOD but allows setting a custom JavaScript name
* Like RCT_EXTERN_REMAP_METHOD, but allows setting a custom JavaScript name.
*/
#define RCT_EXTERN_REMAP_METHOD(js_name, method) \
- (void)__rct_export__##method { \

View File

@ -118,7 +118,8 @@ RCT_CONVERTER(NSString *, NSString, description)
+ (NSURLRequest *)NSURLRequest:(id)json
{
return [NSURLRequest requestWithURL:[self NSURL:json]];
NSURL *URL = [self NSURL:json];
return URL ? [NSURLRequest requestWithURL:URL] : nil;
}
+ (NSDate *)NSDate:(id)json

View File

@ -18,6 +18,21 @@
#define RCT_EXTERN extern __attribute__((visibility("default")))
#endif
/**
* Nullability for Xcode 6.2
*/
#if !__has_feature(nullability)
#define NS_ASSUME_NONNULL_BEGIN
#define NS_ASSUME_NONNULL_END
#define nullable
#define nonnull
#define null_unspecified
#define null_resettable
#define __nullable
#define __nonnull
#define __null_unspecified
#endif
/**
* The RCT_DEBUG macro can be used to exclude error checking and logging code
* from release builds to improve performance and reduce binary size.

View File

@ -72,6 +72,7 @@ static NSNumber *RCTGetEventID(id<RCTEvent> event)
}
@synthesize bridge = _bridge;
@synthesize paused = _paused;
RCT_EXPORT_MODULE()
@ -146,6 +147,7 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveEvent);
}
_eventQueue[eventID] = event;
_paused = NO;
[_eventQueueLock unlock];
}
@ -180,6 +182,7 @@ RCT_IMPORT_METHOD(RCTEventEmitter, receiveEvent);
[_eventQueueLock lock];
eventQueue = _eventQueue;
_eventQueue = [[NSMutableDictionary alloc] init];
_paused = YES;
[_eventQueueLock unlock];
for (id<RCTEvent> event in eventQueue.allValues) {

View File

@ -11,6 +11,7 @@
#import <JavaScriptCore/JavaScriptCore.h>
#import "RCTBridgeModule.h"
#import "RCTInvalidating.h"
typedef void (^RCTJavaScriptCompleteBlock)(NSError *error);
@ -20,7 +21,13 @@ typedef void (^RCTJavaScriptCallback)(id json, NSError *error);
* Abstracts away a JavaScript execution context - we may be running code in a
* web view (for debugging purposes), or may be running code in a `JSContext`.
*/
@protocol RCTJavaScriptExecutor <RCTInvalidating>
@protocol RCTJavaScriptExecutor <RCTInvalidating, RCTBridgeModule>
/**
* Used to set up the executor after the bridge has been fully initialized.
* Do any expensive setup in this method instead of `-init`.
*/
- (void)setUp;
/**
* Executes given method with arguments on JS thread and calls the given callback
@ -61,14 +68,12 @@ typedef void (^RCTJavaScriptCallback)(id json, NSError *error);
@end
static const char *RCTJavaScriptExecutorID = "RCTJavaScriptExecutorID";
__used static id<RCTJavaScriptExecutor> RCTCreateExecutor(Class executorClass)
__used static void RCTSetExecutorID(id<RCTJavaScriptExecutor> executor)
{
static NSUInteger executorID = 0;
id<RCTJavaScriptExecutor> executor = [[executorClass alloc] init];
if (executor) {
objc_setAssociatedObject(executor, RCTJavaScriptExecutorID, @(++executorID), OBJC_ASSOCIATION_RETAIN);
}
return executor;
}
__used static NSNumber *RCTGetExecutorID(id<RCTJavaScriptExecutor> executor)

View File

@ -171,6 +171,9 @@ void _RCTLogFormat(
// Log to red box
if (level >= RCTLOG_REDBOX_LEVEL) {
if (level < RCTLOG_FATAL_LEVEL) {
[[RCTRedBox sharedInstance] setNextBackgroundColor:[UIColor colorWithRed:0.9 green:0.4 blue:0.2 alpha:1]];
}
[[RCTRedBox sharedInstance] showErrorMessage:message];
}

View File

@ -18,6 +18,8 @@
- (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack;
- (void)updateErrorMessage:(NSString *)message withStack:(NSArray *)stack;
- (void)setNextBackgroundColor:(UIColor *)color;
- (NSString *)currentErrorMessage;
- (void)dismiss;

View File

@ -29,14 +29,15 @@
NSArray *_lastStackTrace;
UITableViewCell *_cachedMessageCell;
UIColor *_redColor;
}
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
_redColor = [UIColor colorWithRed:0.8 green:0 blue:0 alpha:1];
self.windowLevel = UIWindowLevelStatusBar + 5;
self.backgroundColor = [UIColor colorWithRed:0.8 green:0 blue:0 alpha:1];
self.backgroundColor = _redColor;
self.hidden = YES;
UIViewController *rootController = [[UIViewController alloc] init];
@ -132,6 +133,7 @@
- (void)dismiss
{
self.hidden = YES;
self.backgroundColor = _redColor;
[self resignFirstResponder];
[[[[UIApplication sharedApplication] delegate] window] makeKeyWindow];
}
@ -261,6 +263,7 @@
@implementation RCTRedBox
{
RCTRedBoxWindow *_window;
UIColor *_nextBackgroundColor;
}
+ (instancetype)sharedInstance
@ -273,6 +276,11 @@
return _sharedInstance;
}
- (void)setNextBackgroundColor:(UIColor *)color
{
_nextBackgroundColor = color;
}
- (void)showErrorMessage:(NSString *)message
{
[self showErrorMessage:message withStack:nil showIfHidden:YES];
@ -304,6 +312,10 @@
_window = [[RCTRedBoxWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
}
[_window showErrorMessage:message withStack:stack showIfHidden:shouldShow];
if (_nextBackgroundColor) {
_window.backgroundColor = _nextBackgroundColor;
_nextBackgroundColor = nil;
}
});
}
@ -334,6 +346,7 @@
- (void)updateErrorMessage:(NSString *)message withStack:(NSArray *)stack {}
- (void)showErrorMessage:(NSString *)message withStack:(NSArray *)stack showIfHidden:(BOOL)shouldShow {}
- (NSString *)currentErrorMessage { return nil; }
- (void)setNextBackgroundColor:(UIColor *)color {}
- (void)dismiss {}
@end

View File

@ -0,0 +1,36 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/Foundation.h>
/**
* An abstract interface used by request handler modules to send
* data back over the bridge back to JS.
*/
@protocol RCTURLRequestDelegate <NSObject>
/**
* Call this when you first receives a response from the server. This should
* include response headers, etc.
*/
- (void)URLRequest:(id)requestToken didReceiveResponse:(NSURLResponse *)response;
/**
* Call this when you receive data from the server. This can be called multiple
* times with partial data chunks, or just once with the full data packet.
*/
- (void)URLRequest:(id)requestToken didReceiveData:(NSData *)data;
/**
* Call this when the request is complete and/or if an error is encountered.
* For a successful request, the error parameter should be nil.
*/
- (void)URLRequest:(id)requestToken didCompleteWithError:(NSError *)error;
@end

View File

@ -0,0 +1,54 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTBridgeModule.h"
#import "RCTURLRequestDelegate.h"
/**
* Provides the interface needed to register a request handler. Request handlers
* are also bridge modules, so should be registered using RCT_EXPORT_MODULE().
*/
@protocol RCTURLRequestHandler <RCTBridgeModule>
/**
* Indicates whether this handler is capable of processing the specified
* request. Typically the handler would examine the scheme/protocol of the
* request URL (and possibly the HTTP method and/or headers) to determine this.
*/
- (BOOL)canHandleRequest:(NSURLRequest *)request;
/**
* Send a network request and call the delegate with the response data. The
* method should return a token, which can be anything, including the request
* itself. This will be used later to refer to the request in callbacks. The
* `sendRequest:withDelegate:` method *must* return before calling any of the
* delegate methods, or the delegate won't recognize the token.
*/
- (id)sendRequest:(NSURLRequest *)request
withDelegate:(id<RCTURLRequestDelegate>)delegate;
@optional
/**
* Not all request types can be cancelled, but this method can be implemented
* for ones that can. It should be used to free up any resources on ongoing
* processes associated with the request.
*/
- (void)cancelRequest:(id)requestToken;
/**
* If more than one RCTURLRequestHandler responds YES to `canHandleRequest:`
* then `handlerPriority` is used to determine which one to use. The handler
* with the highest priority will be selected. Default priority is zero. If
* two or more valid handlers have the same priority, the selection order is
* undefined.
*/
- (float)handlerPriority;
@end

View File

@ -57,3 +57,10 @@ RCT_EXTERN BOOL RCTRunningInTestEnvironment(void);
// Return YES if image has an alpha component
RCT_EXTERN BOOL RCTImageHasAlpha(CGImageRef image);
// Create an NSError in the NCTErrorDomain
RCT_EXTERN NSError *RCTErrorWithMessage(NSString *message);
// Convert nil values to NSNull, and vice-versa
RCT_EXTERN id RCTNullIfNil(id value);
RCT_EXTERN id RCTNilIfNull(id value);

View File

@ -281,3 +281,20 @@ BOOL RCTImageHasAlpha(CGImageRef image)
return YES;
}
}
NSError *RCTErrorWithMessage(NSString *message)
{
NSDictionary *errorInfo = @{NSLocalizedDescriptionKey: message};
NSError *error = [[NSError alloc] initWithDomain:RCTErrorDomain code:0 userInfo:errorInfo];
return error;
}
id RCTNullIfNil(id value)
{
return value ?: (id)kCFNull;
}
id RCTNilIfNull(id value)
{
return value == (id)kCFNull ? nil : value;
}

View File

@ -68,6 +68,8 @@
NSThread *_javaScriptThread;
}
RCT_EXPORT_MODULE()
/**
* The one tiny pure native hook that we implement is a native logging hook.
* You could even argue that this is not necessary - we could plumb logging
@ -233,37 +235,43 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
JSGlobalContextRef ctx;
if (context) {
ctx = JSGlobalContextRetain(context);
} else {
JSContextGroupRef group = JSContextGroupCreate();
ctx = JSGlobalContextCreateInGroup(group, NULL);
#if FB_JSC_HACK
JSContextGroupBindToCurrentThread(group);
#endif
JSContextGroupRelease(group);
strongSelf->_context = [[RCTJavaScriptContext alloc] initWithJSContext:ctx];
}
strongSelf->_context = [[RCTJavaScriptContext alloc] initWithJSContext:ctx];
[strongSelf _addNativeHook:RCTNativeLoggingHook withName:"nativeLoggingHook"];
[strongSelf _addNativeHook:RCTNoop withName:"noop"];
#if RCT_DEV
[strongSelf _addNativeHook:RCTConsoleProfile withName:"consoleProfile"];
[strongSelf _addNativeHook:RCTConsoleProfileEnd withName:"consoleProfileEnd"];
for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(toggleProfilingFlag:)
name:event
object:nil];
}
#endif
}];
}
return self;
}
- (void)setUp
{
__weak RCTContextExecutor *weakSelf = self;
[self executeBlockOnJavaScriptQueue:^{
RCTContextExecutor *strongSelf = weakSelf;
if (!strongSelf) {
return;
}
if (!strongSelf->_context) {
JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);
JSGlobalContextRetain(ctx);
strongSelf->_context = [[RCTJavaScriptContext alloc] initWithJSContext:ctx];
}
[strongSelf _addNativeHook:RCTNativeLoggingHook withName:"nativeLoggingHook"];
[strongSelf _addNativeHook:RCTNoop withName:"noop"];
#if RCT_DEV
[strongSelf _addNativeHook:RCTConsoleProfile withName:"consoleProfile"];
[strongSelf _addNativeHook:RCTConsoleProfileEnd withName:"consoleProfileEnd"];
for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(toggleProfilingFlag:)
name:event
object:nil];
}
#endif
}];
}
- (void)toggleProfilingFlag:(NSNotification *)notification
{
JSObjectRef globalObject = JSContextGetGlobalObject(_context.ctx);

View File

@ -46,16 +46,14 @@ static void RCTReportError(RCTJavaScriptCallback callback, NSString *fmt, ...)
NSRegularExpression *_scriptTagsRegex;
}
RCT_EXPORT_MODULE()
@synthesize valid = _valid;
- (instancetype)initWithWebView:(UIWebView *)webView
{
if ((self = [super init])) {
_objectsToInject = [[NSMutableDictionary alloc] init];
_webView = webView ?: [[UIWebView alloc] init];
_commentsRegex = [NSRegularExpression regularExpressionWithPattern:@"(^ *?\\/\\/.*?$|\\/\\*\\*[\\s\\S]*?\\*\\/)" options:NSRegularExpressionAnchorsMatchLines error:NULL],
_scriptTagsRegex = [NSRegularExpression regularExpressionWithPattern:@"<(\\/?script[^>]*?)>" options:0 error:NULL],
_webView.delegate = self;
_webView = webView;
}
return self;
}
@ -65,6 +63,18 @@ static void RCTReportError(RCTJavaScriptCallback callback, NSString *fmt, ...)
return [self initWithWebView:nil];
}
- (void)setUp
{
if (!_webView) {
_webView = [[UIWebView alloc] init];
}
_objectsToInject = [[NSMutableDictionary alloc] init];
_commentsRegex = [NSRegularExpression regularExpressionWithPattern:@"(^ *?\\/\\/.*?$|\\/\\*\\*[\\s\\S]*?\\*\\/)" options:NSRegularExpressionAnchorsMatchLines error:NULL],
_scriptTagsRegex = [NSRegularExpression regularExpressionWithPattern:@"<(\\/?script[^>]*?)>" options:0 error:NULL],
_webView.delegate = self;
}
- (void)invalidate
{
_valid = NO;

View File

@ -44,7 +44,9 @@ RCT_EXPORT_METHOD(reportSoftException:(NSString *)message
[_delegate handleSoftJSExceptionWithMessage:message stack:stack];
return;
}
// JS already logs the error via console.
RCTRedBox *box = [RCTRedBox sharedInstance];
[box setNextBackgroundColor:[UIColor colorWithRed:0.9 green:0.4 blue:0.2 alpha:1]];
[box showErrorMessage:message withStack:stack];
}
RCT_EXPORT_METHOD(reportFatalException:(NSString *)message

Some files were not shown because too many files have changed in this diff Show More