From 642d4519a1f2ac0d8cb33feffc41d43c4b351fc4 Mon Sep 17 00:00:00 2001 From: Philipp von Weitershausen Date: Fri, 25 Nov 2016 14:47:45 +0530 Subject: [PATCH 01/66] Add blob implementation with WebSocket integration Fix import paths after rebasing Modify build targets --- Examples/2048/2048.xcodeproj/project.pbxproj | 684 ++++++++++++++++ .../Movies/Movies.xcodeproj/project.pbxproj | 730 ++++++++++++++++++ .../TicTacToe.xcodeproj/project.pbxproj | 728 +++++++++++++++++ Libraries/Blob/Blob.js | 152 ++++ Libraries/Blob/BlobTypes.js | 22 + .../Blob/RCTBlob.xcodeproj/project.pbxproj | 323 ++++++++ Libraries/Blob/RCTBlobManager.h | 31 + Libraries/Blob/RCTBlobManager.m | 158 ++++ Libraries/Blob/URL.js | 66 ++ Libraries/Core/InitializeCore.js | 2 + .../RCTWebSocket.xcodeproj/project.pbxproj | 24 +- Libraries/WebSocket/RCTWebSocketModule.m | 51 +- Libraries/WebSocket/WebSocket.js | 61 +- RNTester/RNTester.xcodeproj/project.pbxproj | 50 +- .../RNTesterLegacy.xcodeproj/project.pbxproj | 119 ++- React.podspec | 27 +- .../java/com/facebook/react/modules/blob/BUCK | 23 + .../react/modules/blob/BlobModule.java | 133 ++++ .../react/modules/blob/BlobProvider.java | 87 +++ .../com/facebook/react/modules/websocket/BUCK | 36 +- .../modules/websocket/WebSocketModule.java | 116 ++- .../main/java/com/facebook/react/shell/BUCK | 122 +-- .../react/shell/MainReactPackage.java | 7 + .../ios/HelloWorld.xcodeproj/project.pbxproj | 135 +--- package.json | 1 + 25 files changed, 3656 insertions(+), 232 deletions(-) create mode 100644 Examples/2048/2048.xcodeproj/project.pbxproj create mode 100644 Examples/Movies/Movies.xcodeproj/project.pbxproj create mode 100644 Examples/TicTacToe/TicTacToe.xcodeproj/project.pbxproj create mode 100644 Libraries/Blob/Blob.js create mode 100644 Libraries/Blob/BlobTypes.js create mode 100755 Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj create mode 100755 Libraries/Blob/RCTBlobManager.h create mode 100755 Libraries/Blob/RCTBlobManager.m create mode 100644 Libraries/Blob/URL.js create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java diff --git a/Examples/2048/2048.xcodeproj/project.pbxproj b/Examples/2048/2048.xcodeproj/project.pbxproj new file mode 100644 index 00000000000000..0e8372ebb51a54 --- /dev/null +++ b/Examples/2048/2048.xcodeproj/project.pbxproj @@ -0,0 +1,684 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 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 */; }; + 1461632D1AC3E23900C2F5AD /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1461632C1AC3E22900C2F5AD /* libReact.a */; }; + 5F82F1781B85785200FAE87E /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F82F1771B85784500FAE87E /* libRCTWebSocket.a */; }; + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; + ADBDB96A1DFEC03D00ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9431DFEC01900ED6528 /* libRCTBlob.a */; }; + E730D7501D4EE4E2000B7DA8 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E730D74C1D4EE4D0000B7DA8 /* libRCTNetwork.a */; }; + E730D7571D4EE538000B7DA8 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E730D7561D4EE534000B7DA8 /* libRCTImage.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1461632B1AC3E22900C2F5AD /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; + remoteInfo = React; + }; + 5F82F1761B85784500FAE87E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3C86DF461ADF2C930047B81A; + remoteInfo = RCTWebSocket; + }; + 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5119B1A9E6C1200147676; + remoteInfo = RCTText; + }; + ADBDB9421DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB93E1DFEC01800ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 358F4ED71D1E81A9004DF814; + remoteInfo = RCTBlob; + }; + ADBDB9461DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; + remoteInfo = "RCTImage-tvOS"; + }; + ADBDB94A1DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28541D9B044C00D4039D; + remoteInfo = "RCTNetwork-tvOS"; + }; + ADBDB94E1DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A287B1D9B048500D4039D; + remoteInfo = "RCTText-tvOS"; + }; + ADBDB9521DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28881D9B049200D4039D; + remoteInfo = "RCTWebSocket-tvOS"; + }; + ADBDB95C1DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28131D9B038B00D4039D; + remoteInfo = "React-tvOS"; + }; + ADBDB95E1DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C059A1DE3340900C268FA; + remoteInfo = yoga; + }; + ADBDB9601DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C06751DE3340C00C268FA; + remoteInfo = "yoga-tvOS"; + }; + ADBDB9621DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; + remoteInfo = cxxreact; + }; + ADBDB9641DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; + remoteInfo = "cxxreact-tvOS"; + }; + ADBDB9661DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; + remoteInfo = jschelpers; + }; + ADBDB9681DFEC01900ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; + remoteInfo = "jschelpers-tvOS"; + }; + E730D74B1D4EE4D0000B7DA8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B511DB1A9E6C8500147676; + remoteInfo = RCTNetwork; + }; + E730D7551D4EE534000B7DA8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5115D1A9E6B3D00147676; + remoteInfo = RCTImage; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 13B07F961A680F5B00A75B9A /* 2048.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 2048.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = 2048/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = 2048/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = 2048/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = 2048/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = 2048/main.m; sourceTree = ""; }; + 146163271AC3E22900C2F5AD /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = ""; }; + 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; + ADBDB93E1DFEC01800ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; + E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; + E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ADBDB96A1DFEC03D00ED6528 /* libRCTBlob.a in Frameworks */, + E730D7571D4EE538000B7DA8 /* libRCTImage.a in Frameworks */, + E730D7501D4EE4E2000B7DA8 /* libRCTNetwork.a in Frameworks */, + 5F82F1781B85785200FAE87E /* libRCTWebSocket.a in Frameworks */, + 1461632D1AC3E23900C2F5AD /* libReact.a in Frameworks */, + 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 13B07FAE1A68108700A75B9A /* 2048 */ = { + isa = PBXGroup; + children = ( + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = 2048; + sourceTree = ""; + }; + 146163281AC3E22900C2F5AD /* Products */ = { + isa = PBXGroup; + children = ( + 1461632C1AC3E22900C2F5AD /* libReact.a */, + ADBDB95D1DFEC01900ED6528 /* libReact.a */, + ADBDB95F1DFEC01900ED6528 /* libyoga.a */, + ADBDB9611DFEC01900ED6528 /* libyoga.a */, + ADBDB9631DFEC01900ED6528 /* libcxxreact.a */, + ADBDB9651DFEC01900ED6528 /* libcxxreact.a */, + ADBDB9671DFEC01900ED6528 /* libjschelpers.a */, + ADBDB9691DFEC01900ED6528 /* libjschelpers.a */, + ); + name = Products; + sourceTree = ""; + }; + 5F82F1731B85784500FAE87E /* Products */ = { + isa = PBXGroup; + children = ( + 5F82F1771B85784500FAE87E /* libRCTWebSocket.a */, + ADBDB9531DFEC01900ED6528 /* libRCTWebSocket-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ADBDB93E1DFEC01800ED6528 /* RCTBlob.xcodeproj */, + E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */, + E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */, + 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */, + 146163271AC3E22900C2F5AD /* React.xcodeproj */, + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, + ); + name = Libraries; + sourceTree = ""; + }; + 832341B11AAA6A8300B99B32 /* Products */ = { + isa = PBXGroup; + children = ( + 832341B51AAA6A8300B99B32 /* libRCTText.a */, + ADBDB94F1DFEC01900ED6528 /* libRCTText-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* 2048 */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 83CBBA001A601CBA00E9B192 /* Products */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* 2048.app */, + ); + name = Products; + sourceTree = ""; + }; + ADBDB93F1DFEC01800ED6528 /* Products */ = { + isa = PBXGroup; + children = ( + ADBDB9431DFEC01900ED6528 /* libRCTBlob.a */, + ); + name = Products; + sourceTree = ""; + }; + E730D7481D4EE4D0000B7DA8 /* Products */ = { + isa = PBXGroup; + children = ( + E730D74C1D4EE4D0000B7DA8 /* libRCTNetwork.a */, + ADBDB94B1DFEC01900ED6528 /* libRCTNetwork-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + E730D7521D4EE534000B7DA8 /* Products */ = { + isa = PBXGroup; + children = ( + E730D7561D4EE534000B7DA8 /* libRCTImage.a */, + ADBDB9471DFEC01900ED6528 /* libRCTImage-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* 2048 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "2048" */; + buildPhases = ( + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 68ACCCD51D2BE2D2008E368A /* Run Script */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 2048; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* 2048.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = Facebook; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "2048" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = ADBDB93F1DFEC01800ED6528 /* Products */; + ProjectRef = ADBDB93E1DFEC01800ED6528 /* RCTBlob.xcodeproj */; + }, + { + ProductGroup = E730D7521D4EE534000B7DA8 /* Products */; + ProjectRef = E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */; + }, + { + ProductGroup = E730D7481D4EE4D0000B7DA8 /* Products */; + ProjectRef = E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */; + }, + { + ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; + ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; + }, + { + ProductGroup = 5F82F1731B85784500FAE87E /* Products */; + ProjectRef = 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */; + }, + { + ProductGroup = 146163281AC3E22900C2F5AD /* Products */; + ProjectRef = 146163271AC3E22900C2F5AD /* React.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* 2048 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 1461632C1AC3E22900C2F5AD /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = 1461632B1AC3E22900C2F5AD /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 5F82F1771B85784500FAE87E /* libRCTWebSocket.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTWebSocket.a; + remoteRef = 5F82F1761B85784500FAE87E /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTText.a; + remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9431DFEC01900ED6528 /* libRCTBlob.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTBlob.a; + remoteRef = ADBDB9421DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9471DFEC01900ED6528 /* libRCTImage-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTImage-tvOS.a"; + remoteRef = ADBDB9461DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB94B1DFEC01900ED6528 /* libRCTNetwork-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTNetwork-tvOS.a"; + remoteRef = ADBDB94A1DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB94F1DFEC01900ED6528 /* libRCTText-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTText-tvOS.a"; + remoteRef = ADBDB94E1DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9531DFEC01900ED6528 /* libRCTWebSocket-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTWebSocket-tvOS.a"; + remoteRef = ADBDB9521DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB95D1DFEC01900ED6528 /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = ADBDB95C1DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB95F1DFEC01900ED6528 /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = ADBDB95E1DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9611DFEC01900ED6528 /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = ADBDB9601DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9631DFEC01900ED6528 /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = ADBDB9621DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9651DFEC01900ED6528 /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = ADBDB9641DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9671DFEC01900ED6528 /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = ADBDB9661DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9691DFEC01900ED6528 /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = ADBDB9681DFEC01900ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E730D74C1D4EE4D0000B7DA8 /* libRCTNetwork.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTNetwork.a; + remoteRef = E730D74B1D4EE4D0000B7DA8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E730D7561D4EE534000B7DA8 /* libRCTImage.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTImage.a; + remoteRef = E730D7551D4EE534000B7DA8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 68ACCCD51D2BE2D2008E368A /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export NODE_BINARY=node\n$SRCROOT/../../packager/react-native-xcode.sh Examples/2048/Game2048.js\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = 2048; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 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)/2048/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = 2048; + }; + 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)/2048/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = 2048; + }; + 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; + ENABLE_TESTABILITY = 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 = 8.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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "2048" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "2048" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/Examples/Movies/Movies.xcodeproj/project.pbxproj b/Examples/Movies/Movies.xcodeproj/project.pbxproj new file mode 100644 index 00000000000000..0ba1653c35ce48 --- /dev/null +++ b/Examples/Movies/Movies.xcodeproj/project.pbxproj @@ -0,0 +1,730 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1341801E1AA91750003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341801B1AA91740003F314A /* libRCTNetwork.a */; }; + 13442C061AA90EA00037E5B0 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13442C051AA90E7D0037E5B0 /* libRCTImage.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 */; }; + 140D9B661AC36C42004F25EE /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14312D241AC3654D00CDC950 /* libRCTLinking.a */; }; + 14A2D4421AC3E43800CC738A /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A2D4411AC3E41A00CC738A /* libReact.a */; }; + 58C5726B1AA6239E00CDF9C8 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C5725B1AA6236500CDF9C8 /* libRCTText.a */; }; + 67C95F201B0E64A30040BCE2 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */; }; + ADBDB9A11DFEC1CA00ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9761DFEC1C200ED6528 /* libRCTBlob.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1341801A1AA91740003F314A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 134180151AA91740003F314A /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B511DB1A9E6C8500147676; + remoteInfo = RCTNetwork; + }; + 13442C041AA90E7D0037E5B0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5115D1A9E6B3D00147676; + remoteInfo = RCTImage; + }; + 14312D231AC3654D00CDC950 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTLinking; + }; + 14A2D4401AC3E41A00CC738A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; + remoteInfo = React; + }; + 58C5725A1AA6236500CDF9C8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5119B1A9E6C1200147676; + remoteInfo = RCTText; + }; + 67C95F1D1B0E647A0040BCE2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3C86DF461ADF2C930047B81A; + remoteInfo = RCTWebSocket; + }; + ADBDB9751DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB9711DFEC1C200ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 358F4ED71D1E81A9004DF814; + remoteInfo = RCTBlob; + }; + ADBDB9791DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; + remoteInfo = "RCTImage-tvOS"; + }; + ADBDB97D1DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28471D9B043800D4039D; + remoteInfo = "RCTLinking-tvOS"; + }; + ADBDB9811DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 134180151AA91740003F314A /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28541D9B044C00D4039D; + remoteInfo = "RCTNetwork-tvOS"; + }; + ADBDB9851DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A287B1D9B048500D4039D; + remoteInfo = "RCTText-tvOS"; + }; + ADBDB9891DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28881D9B049200D4039D; + remoteInfo = "RCTWebSocket-tvOS"; + }; + ADBDB9931DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28131D9B038B00D4039D; + remoteInfo = "React-tvOS"; + }; + ADBDB9951DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C059A1DE3340900C268FA; + remoteInfo = yoga; + }; + ADBDB9971DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C06751DE3340C00C268FA; + remoteInfo = "yoga-tvOS"; + }; + ADBDB9991DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; + remoteInfo = cxxreact; + }; + ADBDB99B1DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; + remoteInfo = "cxxreact-tvOS"; + }; + ADBDB99D1DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; + remoteInfo = jschelpers; + }; + ADBDB99F1DFEC1C200ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; + remoteInfo = "jschelpers-tvOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 134180151AA91740003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; + 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* Movies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Movies.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Movies/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Movies/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Movies/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Movies/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Movies/main.m; sourceTree = ""; }; + 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../../Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = ""; }; + 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = ""; }; + 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = SOURCE_ROOT; }; + 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; + ADBDB9711DFEC1C200ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ADBDB9A11DFEC1CA00ED6528 /* libRCTBlob.a in Frameworks */, + 67C95F201B0E64A30040BCE2 /* libRCTWebSocket.a in Frameworks */, + 14A2D4421AC3E43800CC738A /* libReact.a in Frameworks */, + 140D9B661AC36C42004F25EE /* libRCTLinking.a in Frameworks */, + 1341801E1AA91750003F314A /* libRCTNetwork.a in Frameworks */, + 13442C061AA90EA00037E5B0 /* libRCTImage.a in Frameworks */, + 58C5726B1AA6239E00CDF9C8 /* libRCTText.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 134180161AA91740003F314A /* Products */ = { + isa = PBXGroup; + children = ( + 1341801B1AA91740003F314A /* libRCTNetwork.a */, + ADBDB9821DFEC1C200ED6528 /* libRCTNetwork-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 13442C011AA90E7D0037E5B0 /* Products */ = { + isa = PBXGroup; + children = ( + 13442C051AA90E7D0037E5B0 /* libRCTImage.a */, + ADBDB97A1DFEC1C200ED6528 /* libRCTImage-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* Movies */ = { + isa = PBXGroup; + children = ( + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = Movies; + sourceTree = ""; + }; + 14312D1F1AC3654D00CDC950 /* Products */ = { + isa = PBXGroup; + children = ( + 14312D241AC3654D00CDC950 /* libRCTLinking.a */, + ADBDB97E1DFEC1C200ED6528 /* libRCTLinking-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 14A2D43D1AC3E41A00CC738A /* Products */ = { + isa = PBXGroup; + children = ( + 14A2D4411AC3E41A00CC738A /* libReact.a */, + ADBDB9941DFEC1C200ED6528 /* libReact.a */, + ADBDB9961DFEC1C200ED6528 /* libyoga.a */, + ADBDB9981DFEC1C200ED6528 /* libyoga.a */, + ADBDB99A1DFEC1C200ED6528 /* libcxxreact.a */, + ADBDB99C1DFEC1C200ED6528 /* libcxxreact.a */, + ADBDB99E1DFEC1C200ED6528 /* libjschelpers.a */, + ADBDB9A01DFEC1C200ED6528 /* libjschelpers.a */, + ); + name = Products; + sourceTree = ""; + }; + 58C571FC1AA6124500CDF9C8 /* Libraries */ = { + isa = PBXGroup; + children = ( + ADBDB9711DFEC1C200ED6528 /* RCTBlob.xcodeproj */, + 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */, + 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */, + 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */, + 134180151AA91740003F314A /* RCTNetwork.xcodeproj */, + 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */, + 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */, + ); + name = Libraries; + sourceTree = ""; + }; + 58C572571AA6236500CDF9C8 /* Products */ = { + isa = PBXGroup; + children = ( + 58C5725B1AA6236500CDF9C8 /* libRCTText.a */, + ADBDB9861DFEC1C200ED6528 /* libRCTText-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 67C95F161B0E647A0040BCE2 /* Products */ = { + isa = PBXGroup; + children = ( + 67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */, + ADBDB98A1DFEC1C200ED6528 /* libRCTWebSocket-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* Movies */, + 58C571FC1AA6124500CDF9C8 /* Libraries */, + 83CBBA001A601CBA00E9B192 /* Products */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* Movies.app */, + ); + name = Products; + sourceTree = ""; + }; + ADBDB9721DFEC1C200ED6528 /* Products */ = { + isa = PBXGroup; + children = ( + ADBDB9761DFEC1C200ED6528 /* libRCTBlob.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* Movies */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Movies" */; + buildPhases = ( + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 68ACCCEE1D2BE57F008E368A /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Movies; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* Movies.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = Facebook; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Movies" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = ADBDB9721DFEC1C200ED6528 /* Products */; + ProjectRef = ADBDB9711DFEC1C200ED6528 /* RCTBlob.xcodeproj */; + }, + { + ProductGroup = 13442C011AA90E7D0037E5B0 /* Products */; + ProjectRef = 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */; + }, + { + ProductGroup = 14312D1F1AC3654D00CDC950 /* Products */; + ProjectRef = 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */; + }, + { + ProductGroup = 134180161AA91740003F314A /* Products */; + ProjectRef = 134180151AA91740003F314A /* RCTNetwork.xcodeproj */; + }, + { + ProductGroup = 58C572571AA6236500CDF9C8 /* Products */; + ProjectRef = 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */; + }, + { + ProductGroup = 67C95F161B0E647A0040BCE2 /* Products */; + ProjectRef = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */; + }, + { + ProductGroup = 14A2D43D1AC3E41A00CC738A /* Products */; + ProjectRef = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* Movies */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 1341801B1AA91740003F314A /* libRCTNetwork.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTNetwork.a; + remoteRef = 1341801A1AA91740003F314A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 13442C051AA90E7D0037E5B0 /* libRCTImage.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTImage.a; + remoteRef = 13442C041AA90E7D0037E5B0 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 14312D241AC3654D00CDC950 /* libRCTLinking.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTLinking.a; + remoteRef = 14312D231AC3654D00CDC950 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 14A2D4411AC3E41A00CC738A /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = 14A2D4401AC3E41A00CC738A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 58C5725B1AA6236500CDF9C8 /* libRCTText.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTText.a; + remoteRef = 58C5725A1AA6236500CDF9C8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTWebSocket.a; + remoteRef = 67C95F1D1B0E647A0040BCE2 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9761DFEC1C200ED6528 /* libRCTBlob.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTBlob.a; + remoteRef = ADBDB9751DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB97A1DFEC1C200ED6528 /* libRCTImage-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTImage-tvOS.a"; + remoteRef = ADBDB9791DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB97E1DFEC1C200ED6528 /* libRCTLinking-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTLinking-tvOS.a"; + remoteRef = ADBDB97D1DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9821DFEC1C200ED6528 /* libRCTNetwork-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTNetwork-tvOS.a"; + remoteRef = ADBDB9811DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9861DFEC1C200ED6528 /* libRCTText-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTText-tvOS.a"; + remoteRef = ADBDB9851DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB98A1DFEC1C200ED6528 /* libRCTWebSocket-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTWebSocket-tvOS.a"; + remoteRef = ADBDB9891DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9941DFEC1C200ED6528 /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = ADBDB9931DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9961DFEC1C200ED6528 /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = ADBDB9951DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9981DFEC1C200ED6528 /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = ADBDB9971DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB99A1DFEC1C200ED6528 /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = ADBDB9991DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB99C1DFEC1C200ED6528 /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = ADBDB99B1DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB99E1DFEC1C200ED6528 /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = ADBDB99D1DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9A01DFEC1C200ED6528 /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = ADBDB99F1DFEC1C200ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 68ACCCEE1D2BE57F008E368A /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export NODE_BINARY=node\n$SRCROOT/../../packager/react-native-xcode.sh Examples/Movies/MoviesApp.ios.js\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = Movies; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 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)/Movies/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = Movies; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Libraries/**"; + }; + 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)/Movies/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = Movies; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Libraries/**"; + }; + 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; + ENABLE_TESTABILITY = 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 = 8.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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Movies" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Movies" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/Examples/TicTacToe/TicTacToe.xcodeproj/project.pbxproj b/Examples/TicTacToe/TicTacToe.xcodeproj/project.pbxproj new file mode 100644 index 00000000000000..ae65abdfb07e49 --- /dev/null +++ b/Examples/TicTacToe/TicTacToe.xcodeproj/project.pbxproj @@ -0,0 +1,728 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1341803E1AA91802003F314A /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341803D1AA917ED003F314A /* libRCTImage.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 */; }; + 144C5F691AC3E5E300B004E7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 144C5F681AC3E5D800B004E7 /* libReact.a */; }; + 58C572511AA6229D00CDF9C8 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C5724D1AA6224400CDF9C8 /* libRCTText.a */; }; + 5FF8942E1B85571A007731BE /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5FF8942D1B8556F8007731BE /* libRCTWebSocket.a */; }; + 832044981B492C2500E297FC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832044951B492C1E00E297FC /* libRCTSettings.a */; }; + ADBDB9D81DFEC21200ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9AD1DFEC20D00ED6528 /* libRCTBlob.a */; }; + E730D7731D4EE604000B7DA8 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E730D76E1D4EE5FC000B7DA8 /* libRCTNetwork.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 1341803C1AA917ED003F314A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 134180381AA917ED003F314A /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5115D1A9E6B3D00147676; + remoteInfo = RCTImage; + }; + 144C5F671AC3E5D800B004E7 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; + remoteInfo = React; + }; + 58C5724C1AA6224400CDF9C8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B5119B1A9E6C1200147676; + remoteInfo = RCTText; + }; + 5FF8942C1B8556F8007731BE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3C86DF461ADF2C930047B81A; + remoteInfo = RCTWebSocket; + }; + 832044941B492C1E00E297FC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 134814201AA4EA6300B7C361; + remoteInfo = RCTSettings; + }; + ADBDB9AC1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB9A81DFEC20D00ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 358F4ED71D1E81A9004DF814; + remoteInfo = RCTBlob; + }; + ADBDB9B01DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 134180381AA917ED003F314A /* RCTImage.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; + remoteInfo = "RCTImage-tvOS"; + }; + ADBDB9B41DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28541D9B044C00D4039D; + remoteInfo = "RCTNetwork-tvOS"; + }; + ADBDB9B81DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28611D9B046600D4039D; + remoteInfo = "RCTSettings-tvOS"; + }; + ADBDB9BC1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A287B1D9B048500D4039D; + remoteInfo = "RCTText-tvOS"; + }; + ADBDB9C01DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28881D9B049200D4039D; + remoteInfo = "RCTWebSocket-tvOS"; + }; + ADBDB9CA1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 2D2A28131D9B038B00D4039D; + remoteInfo = "React-tvOS"; + }; + ADBDB9CC1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C059A1DE3340900C268FA; + remoteInfo = yoga; + }; + ADBDB9CE1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C06751DE3340C00C268FA; + remoteInfo = "yoga-tvOS"; + }; + ADBDB9D01DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; + remoteInfo = cxxreact; + }; + ADBDB9D21DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; + remoteInfo = "cxxreact-tvOS"; + }; + ADBDB9D41DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; + remoteInfo = jschelpers; + }; + ADBDB9D61DFEC20D00ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; + remoteInfo = "jschelpers-tvOS"; + }; + E730D76D1D4EE5FC000B7DA8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 58B511DB1A9E6C8500147676; + remoteInfo = RCTNetwork; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 134180381AA917ED003F314A /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* TicTacToe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TicTacToe.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = TicTacToe/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = TicTacToe/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = TicTacToe/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = TicTacToe/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = TicTacToe/main.m; sourceTree = ""; }; + 144C5F631AC3E5D800B004E7 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = ""; }; + 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; + 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; + 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../../Libraries/Settings/RCTSettings.xcodeproj; sourceTree = ""; }; + ADBDB9A81DFEC20D00ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; + E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ADBDB9D81DFEC21200ED6528 /* libRCTBlob.a in Frameworks */, + E730D7731D4EE604000B7DA8 /* libRCTNetwork.a in Frameworks */, + 5FF8942E1B85571A007731BE /* libRCTWebSocket.a in Frameworks */, + 144C5F691AC3E5E300B004E7 /* libReact.a in Frameworks */, + 1341803E1AA91802003F314A /* libRCTImage.a in Frameworks */, + 58C572511AA6229D00CDF9C8 /* libRCTText.a in Frameworks */, + 832044981B492C2500E297FC /* libRCTSettings.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 134180391AA917ED003F314A /* Products */ = { + isa = PBXGroup; + children = ( + 1341803D1AA917ED003F314A /* libRCTImage.a */, + ADBDB9B11DFEC20D00ED6528 /* libRCTImage-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 13B07FAE1A68108700A75B9A /* TicTacToe */ = { + isa = PBXGroup; + children = ( + 13B07FAF1A68108700A75B9A /* AppDelegate.h */, + 13B07FB01A68108700A75B9A /* AppDelegate.m */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, + 13B07FB71A68108700A75B9A /* main.m */, + ); + name = TicTacToe; + sourceTree = ""; + }; + 144C5F641AC3E5D800B004E7 /* Products */ = { + isa = PBXGroup; + children = ( + 144C5F681AC3E5D800B004E7 /* libReact.a */, + ADBDB9CB1DFEC20D00ED6528 /* libReact.a */, + ADBDB9CD1DFEC20D00ED6528 /* libyoga.a */, + ADBDB9CF1DFEC20D00ED6528 /* libyoga.a */, + ADBDB9D11DFEC20D00ED6528 /* libcxxreact.a */, + ADBDB9D31DFEC20D00ED6528 /* libcxxreact.a */, + ADBDB9D51DFEC20D00ED6528 /* libjschelpers.a */, + ADBDB9D71DFEC20D00ED6528 /* libjschelpers.a */, + ); + name = Products; + sourceTree = ""; + }; + 58C572071AA6126D00CDF9C8 /* Libraries */ = { + isa = PBXGroup; + children = ( + ADBDB9A81DFEC20D00ED6528 /* RCTBlob.xcodeproj */, + E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */, + 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */, + 144C5F631AC3E5D800B004E7 /* React.xcodeproj */, + 134180381AA917ED003F314A /* RCTImage.xcodeproj */, + 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */, + 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */, + ); + name = Libraries; + sourceTree = ""; + }; + 58C572481AA6224300CDF9C8 /* Products */ = { + isa = PBXGroup; + children = ( + 58C5724D1AA6224400CDF9C8 /* libRCTText.a */, + ADBDB9BD1DFEC20D00ED6528 /* libRCTText-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 5FF894291B8556F8007731BE /* Products */ = { + isa = PBXGroup; + children = ( + 5FF8942D1B8556F8007731BE /* libRCTWebSocket.a */, + ADBDB9C11DFEC20D00ED6528 /* libRCTWebSocket-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 832044901B492C1E00E297FC /* Products */ = { + isa = PBXGroup; + children = ( + 832044951B492C1E00E297FC /* libRCTSettings.a */, + ADBDB9B91DFEC20D00ED6528 /* libRCTSettings-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* TicTacToe */, + 58C572071AA6126D00CDF9C8 /* Libraries */, + 83CBBA001A601CBA00E9B192 /* Products */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* TicTacToe.app */, + ); + name = Products; + sourceTree = ""; + }; + ADBDB9A91DFEC20D00ED6528 /* Products */ = { + isa = PBXGroup; + children = ( + ADBDB9AD1DFEC20D00ED6528 /* libRCTBlob.a */, + ); + name = Products; + sourceTree = ""; + }; + E730D7691D4EE5FC000B7DA8 /* Products */ = { + isa = PBXGroup; + children = ( + E730D76E1D4EE5FC000B7DA8 /* libRCTNetwork.a */, + ADBDB9B51DFEC20D00ED6528 /* libRCTNetwork-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* TicTacToe */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "TicTacToe" */; + buildPhases = ( + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 681C70ED1D2BE73C00E71791 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = TicTacToe; + productName = "Hello World"; + productReference = 13B07F961A680F5B00A75B9A /* TicTacToe.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = Facebook; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "TicTacToe" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = ADBDB9A91DFEC20D00ED6528 /* Products */; + ProjectRef = ADBDB9A81DFEC20D00ED6528 /* RCTBlob.xcodeproj */; + }, + { + ProductGroup = 134180391AA917ED003F314A /* Products */; + ProjectRef = 134180381AA917ED003F314A /* RCTImage.xcodeproj */; + }, + { + ProductGroup = E730D7691D4EE5FC000B7DA8 /* Products */; + ProjectRef = E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */; + }, + { + ProductGroup = 832044901B492C1E00E297FC /* Products */; + ProjectRef = 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */; + }, + { + ProductGroup = 58C572481AA6224300CDF9C8 /* Products */; + ProjectRef = 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */; + }, + { + ProductGroup = 5FF894291B8556F8007731BE /* Products */; + ProjectRef = 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */; + }, + { + ProductGroup = 144C5F641AC3E5D800B004E7 /* Products */; + ProjectRef = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* TicTacToe */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 1341803D1AA917ED003F314A /* libRCTImage.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTImage.a; + remoteRef = 1341803C1AA917ED003F314A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 144C5F681AC3E5D800B004E7 /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = 144C5F671AC3E5D800B004E7 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 58C5724D1AA6224400CDF9C8 /* libRCTText.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTText.a; + remoteRef = 58C5724C1AA6224400CDF9C8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 5FF8942D1B8556F8007731BE /* libRCTWebSocket.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTWebSocket.a; + remoteRef = 5FF8942C1B8556F8007731BE /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 832044951B492C1E00E297FC /* libRCTSettings.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTSettings.a; + remoteRef = 832044941B492C1E00E297FC /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9AD1DFEC20D00ED6528 /* libRCTBlob.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTBlob.a; + remoteRef = ADBDB9AC1DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9B11DFEC20D00ED6528 /* libRCTImage-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTImage-tvOS.a"; + remoteRef = ADBDB9B01DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9B51DFEC20D00ED6528 /* libRCTNetwork-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTNetwork-tvOS.a"; + remoteRef = ADBDB9B41DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9B91DFEC20D00ED6528 /* libRCTSettings-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTSettings-tvOS.a"; + remoteRef = ADBDB9B81DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9BD1DFEC20D00ED6528 /* libRCTText-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTText-tvOS.a"; + remoteRef = ADBDB9BC1DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9C11DFEC20D00ED6528 /* libRCTWebSocket-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTWebSocket-tvOS.a"; + remoteRef = ADBDB9C01DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9CB1DFEC20D00ED6528 /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = ADBDB9CA1DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9CD1DFEC20D00ED6528 /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = ADBDB9CC1DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9CF1DFEC20D00ED6528 /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = ADBDB9CE1DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9D11DFEC20D00ED6528 /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = ADBDB9D01DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9D31DFEC20D00ED6528 /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = ADBDB9D21DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9D51DFEC20D00ED6528 /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = ADBDB9D41DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADBDB9D71DFEC20D00ED6528 /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = ADBDB9D61DFEC20D00ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + E730D76E1D4EE5FC000B7DA8 /* libRCTNetwork.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTNetwork.a; + remoteRef = E730D76D1D4EE5FC000B7DA8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 681C70ED1D2BE73C00E71791 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "export NODE_BINARY=node\n$SRCROOT/../../packager/react-native-xcode.sh Examples/TicTacToe/TicTacToeApp.js\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, + 13B07FC11A68108700A75B9A /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 13B07FB21A68108700A75B9A /* Base */, + ); + name = LaunchScreen.xib; + path = TicTacToe; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 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)/TicTacToe/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = TicTacToe; + }; + 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)/TicTacToe/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = ( + "-ObjC", + "-lc++", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = TicTacToe; + }; + 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; + ENABLE_TESTABILITY = 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 = 8.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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "TicTacToe" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "TicTacToe" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js new file mode 100644 index 00000000000000..6e57269ce85419 --- /dev/null +++ b/Libraries/Blob/Blob.js @@ -0,0 +1,152 @@ +/** + * Copyright (c) 2013-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 Blob + * @flow + */ + +'use strict'; + +const uuid = require('uuid'); +const invariant = require('fbjs/lib/invariant'); +const { BlobModule } = require('NativeModules'); + +import type { BlobProps } from './BlobTypes'; + +/** + * Opaque JS representation of some binary data in native. + * + * The API is modeled after the W3C Blob API, with one caveat + * regarding explicit deallocation. Refer to the `close()` + * method for further details. + * + * Example usage in a React component: + * + * class WebSocketImage extends React.Component { + * state = {blob: null}; + * componentDidMount() { + * let ws = this.ws = new WebSocket(...); + * ws.binaryType = 'blob'; + * ws.onmessage = (event) => { + * if (this.state.blob) { + * this.state.blob.close(); + * } + * this.setState({blob: event.data}); + * }; + * } + * componentUnmount() { + * if (this.state.blob) { + * this.state.blob.close(); + * } + * this.ws.close(); + * } + * render() { + * if (!this.state.blob) { + * return ; + * } + * return ; + * } + * } + * + * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob + */ +class Blob { + /** + * Size of the data contained in the Blob object, in bytes. + */ + size: number; + /* + * String indicating the MIME type of the data contained in the Blob. + * If the type is unknown, this string is empty. + */ + type: string; + + /* + * Unique id to identify the blob on native side (non-standard) + */ + blobId: string; + /* + * Offset to indicate part of blob, used when sliced (non-standard) + */ + offset: number; + + /** + * Construct blob instance from blob data from native. + * Used internally by modules like XHR, WebSocket, etc. + */ + static create(props: BlobProps): Blob { + return Object.assign(Object.create(Blob.prototype), props); + } + + /** + * Constructor for JS consumers. + * Currently we only support creating Blobs from other Blobs. + * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob + */ + constructor(parts: Array, options: any) { + let blobId = uuid.v4(); + let size = 0; + parts.forEach((part) => { + invariant(part instanceof Blob, 'Can currently only create a Blob from other Blobs'); + size += part.size; + }); + BlobModule.createFromParts(parts, blobId); + return Blob.create({ + blobId, + offset: 0, + size, + }); + } + + /* + * This method is used to create a new Blob object containing + * the data in the specified range of bytes of the source Blob. + * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice + */ + slice(start?: number, end?: number): Blob { + let offset = this.offset; + let size = this.size; + if (typeof start === 'number') { + if (start > size) { + start = size; + } + offset += start; + size -= start; + + if (typeof end === 'number') { + if (end < 0) { + end = this.size + end; + } + size = end - start; + } + } + return Blob.create({ + blobId: this.blobId, + offset, + size, + }); + } + + /** + * This method is in the standard, but not actually implemented by + * any browsers at this point. It's important for how Blobs work in + * React Native, however, since we cannot de-allocate resources automatically, + * so consumers need to explicitly de-allocate them. + * + * Note that the semantics around Blobs created via `blob.slice()` + * and `new Blob([blob])` are different. `blob.slice()` creates a + * new *view* onto the same binary data, so calling `close()` on any + * of those views is enough to deallocate the data, whereas + * `new Blob([blob, ...])` actually copies the data in memory. + */ + close() { + BlobModule.release(this.blobId); + } +} + +module.exports = Blob; diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js new file mode 100644 index 00000000000000..1e3e8ad34a372a --- /dev/null +++ b/Libraries/Blob/BlobTypes.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2013-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 + */ + +export type BlobProps = { + blobId: string; + offset: number; + size: number; + type?: string; +}; + +export type FileProps = BlobProps & { + name: string; + lastModified: number; +}; diff --git a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj new file mode 100755 index 00000000000000..9acbdb5d61316e --- /dev/null +++ b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj @@ -0,0 +1,323 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; + ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 358F4ED51D1E81A9004DF814 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBlob.a; sourceTree = BUILT_PRODUCTS_DIR; }; + AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBlobManager.h; sourceTree = ""; }; + AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBlobManager.m; sourceTree = ""; }; + ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTBlob-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 358F4ED41D1E81A9004DF814 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 358F4ECE1D1E81A9004DF814 = { + isa = PBXGroup; + children = ( + AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */, + AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */, + 358F4ED81D1E81A9004DF814 /* Products */, + ); + sourceTree = ""; + }; + 358F4ED81D1E81A9004DF814 /* Products */ = { + isa = PBXGroup; + children = ( + 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */, + ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 358F4ED61D1E81A9004DF814 /* RCTBlob */ = { + isa = PBXNativeTarget; + buildConfigurationList = 358F4EE01D1E81A9004DF814 /* Build configuration list for PBXNativeTarget "RCTBlob" */; + buildPhases = ( + 358F4ED31D1E81A9004DF814 /* Sources */, + 358F4ED41D1E81A9004DF814 /* Frameworks */, + 358F4ED51D1E81A9004DF814 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RCTBlob; + productName = SLKBlobs; + productReference = 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */; + productType = "com.apple.product-type.library.static"; + }; + ADD01A671E09402E00F6D226 /* RCTBlob-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = ADD01A6E1E09402E00F6D226 /* Build configuration list for PBXNativeTarget "RCTBlob-tvOS" */; + buildPhases = ( + ADD01A641E09402E00F6D226 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "RCTBlob-tvOS"; + productName = "RCTBlob-tvOS"; + productReference = ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 358F4ECF1D1E81A9004DF814 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0730; + ORGANIZATIONNAME = "Silk Labs"; + TargetAttributes = { + 358F4ED61D1E81A9004DF814 = { + CreatedOnToolsVersion = 7.3; + }; + ADD01A671E09402E00F6D226 = { + CreatedOnToolsVersion = 8.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 358F4ED21D1E81A9004DF814 /* Build configuration list for PBXProject "RCTBlob" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 358F4ECE1D1E81A9004DF814; + productRefGroup = 358F4ED81D1E81A9004DF814 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 358F4ED61D1E81A9004DF814 /* RCTBlob */, + ADD01A671E09402E00F6D226 /* RCTBlob-tvOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 358F4ED31D1E81A9004DF814 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + ADD01A641E09402E00F6D226 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 358F4EDE1D1E81A9004DF814 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + 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; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + 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; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 358F4EDF1D1E81A9004DF814 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + 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; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 358F4EE11D1E81A9004DF814 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../../React/**", + "$(SRCROOT)/../../ReactCommon/**", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 358F4EE21D1E81A9004DF814 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "$(SRCROOT)/../../React/**", + "$(SRCROOT)/../../ReactCommon/**", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + ADD01A6F1E09402E00F6D226 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TVOS_DEPLOYMENT_TARGET = 10.1; + }; + name = Debug; + }; + ADD01A701E09402E00F6D226 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + TVOS_DEPLOYMENT_TARGET = 10.1; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 358F4ED21D1E81A9004DF814 /* Build configuration list for PBXProject "RCTBlob" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 358F4EDE1D1E81A9004DF814 /* Debug */, + 358F4EDF1D1E81A9004DF814 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 358F4EE01D1E81A9004DF814 /* Build configuration list for PBXNativeTarget "RCTBlob" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 358F4EE11D1E81A9004DF814 /* Debug */, + 358F4EE21D1E81A9004DF814 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + ADD01A6E1E09402E00F6D226 /* Build configuration list for PBXNativeTarget "RCTBlob-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + ADD01A6F1E09402E00F6D226 /* Debug */, + ADD01A701E09402E00F6D226 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 358F4ECF1D1E81A9004DF814 /* Project object */; +} diff --git a/Libraries/Blob/RCTBlobManager.h b/Libraries/Blob/RCTBlobManager.h new file mode 100755 index 00000000000000..ff434034aae583 --- /dev/null +++ b/Libraries/Blob/RCTBlobManager.h @@ -0,0 +1,31 @@ +/** + * 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 +#import +#import + +@interface RCTBlobManager : NSObject + +- (NSString *)store:(NSData *)data; + +- (NSData *)resolve:(NSDictionary *)blob; + +- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size; + +- (void)release:(NSString *)blobId; + +@end + + +@interface RCTBridge (RCTBlobManager) + +@property (nonatomic, readonly) RCTBlobManager *blobs; + +@end diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.m new file mode 100755 index 00000000000000..67d211b4d48010 --- /dev/null +++ b/Libraries/Blob/RCTBlobManager.m @@ -0,0 +1,158 @@ +/** + * 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 "RCTBlobManager.h" + +#import + +static NSString *const kBlobUriScheme = @"blob"; + +@implementation RCTBlobManager +{ + NSMutableDictionary *_blobs; + NSOperationQueue *_queue; +} + +RCT_EXPORT_MODULE(BlobModule) + +- (NSDictionary *)constantsToExport +{ + return @{ + @"BLOB_URI_SCHEME": kBlobUriScheme, + @"BLOB_URI_HOST": [NSNull null], + }; +} + +- (NSString *)store:(NSData *)data +{ + NSString *blobId = [NSUUID UUID].UUIDString; + [self store:data withId:blobId]; + return blobId; +} + +- (void)store:(NSData *)data withId:(NSString *)blobId +{ + if (!_blobs) { + _blobs = [NSMutableDictionary new]; + } + _blobs[blobId] = data; +} + +- (NSData *)resolve:(NSDictionary *)blob +{ + NSString *blobId = [RCTConvert NSString:blob[@"blobId"]]; + NSNumber *offset = [RCTConvert NSNumber:blob[@"offset"]]; + NSNumber *size = [RCTConvert NSNumber:blob[@"size"]]; + return [self resolve:blobId + offset:offset ? [offset integerValue] : 0 + size:size ? [size integerValue] : -1]; +} + +- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size +{ + NSData *data = _blobs[blobId]; + if (!data) { + return nil; + } + if (offset != 0 || (size != -1 && size != data.length)) { + data = [data subdataWithRange:NSMakeRange(offset, size)]; + } + return data; +} + +RCT_EXPORT_METHOD(createFromParts:(NSArray *> *)parts withId:(NSString *)blobId) +{ + NSMutableData *data = [NSMutableData new]; + for (NSDictionary *part in parts) { + NSData *partData = [self resolve:part]; + [data appendData:partData]; + } + [self store:data withId:blobId]; +} + +RCT_EXPORT_METHOD(release:(NSString *)blobId) +{ + [_blobs removeObjectForKey:blobId]; +} + +#pragma mark - RCTURLRequestHandler methods + +- (BOOL)canHandleRequest:(NSURLRequest *)request +{ + return [request.URL.scheme caseInsensitiveCompare:kBlobUriScheme] == NSOrderedSame; +} + +- (id)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate +{ + // Lazy setup + if (!_queue) { + _queue = [NSOperationQueue new]; + _queue.maxConcurrentOperationCount = 2; + } + + __weak __block NSBlockOperation *weakOp; + __block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ + NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL + MIMEType:nil + expectedContentLength:-1 + textEncodingName:nil]; + + [delegate URLRequest:weakOp didReceiveResponse:response]; + + NSURLComponents *components = [[NSURLComponents alloc] initWithURL:request.URL resolvingAgainstBaseURL:NO]; + + NSString *blobId = components.path; + NSInteger offset = 0; + NSInteger size = -1; + + if (components.queryItems) { + for (NSURLQueryItem *queryItem in components.queryItems) { + if ([queryItem.name isEqualToString:@"offset"]) { + offset = [queryItem.value integerValue]; + } + if ([queryItem.name isEqualToString:@"size"]) { + size = [queryItem.value integerValue]; + } + } + } + + NSData *data; + if (blobId) { + data = [self resolve:blobId offset:offset size:size]; + } + NSError *error; + if (data) { + [delegate URLRequest:weakOp didReceiveData:data]; + } else { + error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil]; + } + [delegate URLRequest:weakOp didCompleteWithError:error]; + }]; + + weakOp = op; + [_queue addOperation:op]; + return op; +} + +- (void)cancelRequest:(NSOperation *)op +{ + [op cancel]; +} + +@end + + +@implementation RCTBridge (RCTBlobManager) + +- (RCTBlobManager *)blobs +{ + return [self moduleForClass:[RCTBlobManager class]]; +} + +@end diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js new file mode 100644 index 00000000000000..026af2fce0b968 --- /dev/null +++ b/Libraries/Blob/URL.js @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2013-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 URL + * @flow + */ +'use strict'; + +const Blob = require('Blob'); +const { BlobModule } = require('react-native').NativeModules; + +let BLOB_URL_PREFIX = null; + +if (typeof BlobModule.BLOB_URI_SCHEME === 'string') { + BLOB_URL_PREFIX = BlobModule.BLOB_URI_SCHEME + ':'; + if (typeof BlobModule.BLOB_URI_HOST === 'string') { + BLOB_URL_PREFIX += `//${BlobModule.BLOB_URI_HOST}/`; + } +} + +/** + * To allow Blobs be accessed via `content://` URIs, + * you need to register `BlobProvider` as a ContentProvider in your app's `AndroidManifest.xml`: + * + * ```xml + * + * + * + * + * + * ``` + * And then define the `blob_provider_authority` string in `res/values/strings.xml`. Use a dotted name that's entirely unique to your app: + * + * ```xml + * + * your.app.package.blobs + * + * ``` + */ +class URL { + constructor() { + throw new Error('Creating URL objects is not supported yet.'); + } + + static createObjectURL(blob: Blob) { + if (BLOB_URL_PREFIX === null) { + throw new Error('Cannot create URL for blob!'); + } + return `${BLOB_URL_PREFIX}${blob.blobId}?offset=${blob.offset}&size=${blob.size}`; + } + + static revokeObjectURL(url: string) { + // Do nothing. + } +} + +module.exports = URL; diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 4b6cac529fe424..968634131ec75d 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -189,6 +189,8 @@ defineProperty(global, 'Headers', () => require('fetch').Headers); defineProperty(global, 'Request', () => require('fetch').Request); defineProperty(global, 'Response', () => require('fetch').Response); defineProperty(global, 'WebSocket', () => require('WebSocket')); +defineProperty(global, 'Blob', () => require('Blob')); +defineProperty(global, 'URL', () => require('URL')); // Set up Geolocation let navigator = global.navigator; diff --git a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj index 8008c37898b786..c5de5f0e8879a0 100644 --- a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj +++ b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ 3C86DF7A1ADF695F0047B81A /* RCTWebSocketModule.h */, 3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */, 3C86DF471ADF2C930047B81A /* Products */, + AD0871001E2158CB007D136D /* Frameworks */, ); indentWidth = 2; sourceTree = ""; @@ -63,6 +64,13 @@ name = Products; sourceTree = ""; }; + AD0871001E2158CB007D136D /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -172,6 +180,7 @@ OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + SKIP_INSTALL = YES; TVOS_DEPLOYMENT_TARGET = 9.2; }; name = Debug; @@ -186,6 +195,7 @@ OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; + SKIP_INSTALL = YES; TVOS_DEPLOYMENT_TARGET = 9.2; }; name = Release; @@ -232,7 +242,7 @@ MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; - SKIP_INSTALL = YES; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../Blob"; WARNING_CFLAGS = ( "-Werror", "-Wall", @@ -275,7 +285,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - SKIP_INSTALL = YES; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../Blob"; VALIDATE_PRODUCT = YES; WARNING_CFLAGS = ( "-Werror", @@ -289,8 +299,13 @@ buildSettings = { EXECUTABLE_PREFIX = lib; GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../React/**", + "$(SRCROOT)/../../ReactCommon/**", + ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; }; name = Debug; }; @@ -299,8 +314,13 @@ buildSettings = { EXECUTABLE_PREFIX = lib; GCC_TREAT_WARNINGS_AS_ERRORS = NO; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/../../React/**", + "$(SRCROOT)/../../ReactCommon/**", + ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; }; name = Release; }; diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m index 5a420b70e6f6f1..802bba1d37c1e5 100644 --- a/Libraries/WebSocket/RCTWebSocketModule.m +++ b/Libraries/WebSocket/RCTWebSocketModule.m @@ -8,13 +8,17 @@ */ #import "RCTWebSocketModule.h" +#import "RCTSRWebSocket.h" #import #import #import - -#import "RCTSRWebSocket.h" +<<<<<<< HEAD +#import +======= +#import "RCTBlobManager.h" +>>>>>>> Add blob implementation with WebSocket integration @implementation RCTSRWebSocket (React) @@ -37,6 +41,7 @@ @interface RCTWebSocketModule () @implementation RCTWebSocketModule { NSMutableDictionary *_sockets; + NSMutableSet *_blobsEnabled; } RCT_EXPORT_MODULE() @@ -99,6 +104,27 @@ - (void)dealloc [_sockets[socketID] send:message]; } +RCT_EXPORT_METHOD(sendBlob:(NSDictionary *)blob socketID:(nonnull NSNumber *)socketID) +{ + RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + NSData *data = [blobManager resolve:blob]; + // Unfortunately we don't have access to the WebSocket object, so we have to + // convert it to base64 and send it through the existing method :( + [self sendBinary:[data base64EncodedStringWithOptions:0] socketID:socketID]; +} + +RCT_EXPORT_METHOD(setBinaryType:(NSString *)binaryType socketID:(nonnull NSNumber *)socketID) +{ + if (!_blobsEnabled) { + _blobsEnabled = [NSMutableSet new]; + } + if ([binaryType isEqualToString:@"blob"]) { + [_blobsEnabled addObject:socketID]; + } else { + [_blobsEnabled removeObject:socketID]; + } +} + RCT_EXPORT_METHOD(ping:(nonnull NSNumber *)socketID) { [_sockets[socketID] sendPing:NULL]; @@ -114,10 +140,25 @@ - (void)dealloc - (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message { - BOOL binary = [message isKindOfClass:[NSData class]]; + NSString *type = @"text"; + if ([message isKindOfClass:[NSData class]]) { + if (_blobsEnabled && [_blobsEnabled containsObject:webSocket.reactTag]) { + RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + message = @{ + @"blobId": [blobManager store:message], + @"offset": @0, + @"size": @(((NSData *)message).length), + }; + type = @"blob"; + } else { + message = [message base64EncodedStringWithOptions:0]; + type = @"binary"; + } + } + [self sendEventWithName:@"websocketMessage" body:@{ - @"data": binary ? [message base64EncodedStringWithOptions:0] : message, - @"type": binary ? @"binary" : @"text", + @"data": message, + @"type": type, @"id": webSocket.reactTag }]; } diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 40b086de24e289..079aa6ecae20e6 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -12,16 +12,18 @@ 'use strict'; const NativeEventEmitter = require('NativeEventEmitter'); +const Blob = require('Blob'); const Platform = require('Platform'); const RCTWebSocketModule = require('NativeModules').WebSocketModule; const WebSocketEvent = require('WebSocketEvent'); -const binaryToBase64 = require('binaryToBase64'); const EventTarget = require('event-target-shim'); const base64 = require('base64-js'); import type EventSubscription from 'EventSubscription'; +type BinaryType = 'blob' | 'arraybuffer' + const CONNECTING = 0; const OPEN = 1; const CLOSING = 2; @@ -58,13 +60,13 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { _socketId: number; _eventEmitter: NativeEventEmitter; _subscriptions: Array; + _binaryType: ?BinaryType; onclose: ?Function; onerror: ?Function; onmessage: ?Function; onopen: ?Function; - binaryType: ?string; bufferedAmount: number; extension: ?string; protocol: ?string; @@ -96,6 +98,30 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { RCTWebSocketModule.connect(url, protocols, options, this._socketId); } + get binaryType(): ?BinaryType { + return this._binaryType; + } + + set binaryType(binaryType: BinaryType): void { + if (binaryType !== 'blob' && binaryType !== 'arraybuffer') { + throw new Error('binaryType must be either \'blob\' or \'arraybuffer\''); + } + this._binaryType = binaryType; + RCTWebSocketModule.setBinaryType(binaryType, this._socketId); + } + + get binaryType(): ?BinaryType { + return this._binaryType; + } + + set binaryType(binaryType: BinaryType): void { + if (binaryType !== 'blob' && binaryType !== 'arraybuffer') { + throw new Error('binaryType must be either \'blob\' or \'arraybuffer\''); + } + this._binaryType = binaryType; + RCTWebSocketModule.setBinaryType(binaryType, this._socketId); + } + close(code?: number, reason?: string): void { if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { @@ -106,18 +132,30 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { this._close(code, reason); } - send(data: string | ArrayBuffer | $ArrayBufferView): void { + send(data: string | ArrayBuffer | $ArrayBufferView | Blob): void { if (this.readyState === this.CONNECTING) { throw new Error('INVALID_STATE_ERR'); } + if (data instanceof Blob) { + RCTWebSocketModule.sendBlob(data, this._socketId); + return; + } + if (typeof data === 'string') { RCTWebSocketModule.send(data, this._socketId); return; } - if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) { - RCTWebSocketModule.sendBinary(binaryToBase64(data), this._socketId); + + if (ArrayBuffer.isView(data)) { + // $FlowFixMe: no way to assert that 'data' is indeed an ArrayBufferView now + data = data.buffer; + } + + if (data instanceof ArrayBuffer) { + data = base64.fromByteArray(new Uint8Array(data)); + RCTWebSocketModule.sendBinary(data, this._socketId); return; } @@ -154,9 +192,16 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { if (ev.id !== this._socketId) { return; } - this.dispatchEvent(new WebSocketEvent('message', { - data: (ev.type === 'binary') ? base64.toByteArray(ev.data).buffer : ev.data - })); + let data = ev.data; + switch (ev.type) { + case 'binary': + data = base64.toByteArray(ev.data).buffer; + break; + case 'blob': + data = Blob.create(ev.data); + break; + } + this.dispatchEvent(new WebSocketEvent('message', { data })); }), this._eventEmitter.addListener('websocketOpen', ev => { if (ev.id !== this._socketId) { diff --git a/RNTester/RNTester.xcodeproj/project.pbxproj b/RNTester/RNTester.xcodeproj/project.pbxproj index 6a291b5ebbaf09..2e783da6edbadc 100644 --- a/RNTester/RNTester.xcodeproj/project.pbxproj +++ b/RNTester/RNTester.xcodeproj/project.pbxproj @@ -119,6 +119,9 @@ 83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; }; 8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */; }; 8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */; }; + ADAC7A091E093BB900D77272 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */; }; + ADBDBA0D1DFEC24D00ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */; }; + ADD01A631E093FA900F6D226 /* libRCTBlob-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */; }; BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */; }; C654F0B31EB34A73000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F0B21EB34A73000B7A9A /* RNTesterTestModule.m */; }; C654F17E1EB34D24000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F0B21EB34A73000B7A9A /* RNTesterTestModule.m */; }; @@ -406,6 +409,20 @@ remoteGlobalIDString = 134814201AA4EA6300B7C361; remoteInfo = RCTSettings; }; + ADBDB9F01DFEC24500ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 358F4ED71D1E81A9004DF814; + remoteInfo = RCTBlob; + }; + ADD01A461E093FA100F6D226 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = ADAC7A2E1E093EF800D77272; + remoteInfo = "RCTBlob-tvOS"; + }; D85B829B1AB6D5CE003F4FE2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */; @@ -495,6 +512,7 @@ 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderTests.m; sourceTree = ""; }; 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderHelpers.m; sourceTree = ""; }; 8385CF051B8747A000C6273E /* RCTImageLoaderHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTImageLoaderHelpers.h; sourceTree = ""; }; + ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenuTests.m; sourceTree = ""; }; C654F0B21EB34A73000B7A9A /* RNTesterTestModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNTesterTestModule.m; sourceTree = ""; }; D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = ""; }; @@ -506,6 +524,7 @@ buildActionMask = 2147483647; files = ( 192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */, + ADAC7A091E093BB900D77272 /* libRCTBlob.a in Frameworks */, 14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */, 14D6D71F1B2222EF001FB087 /* libRCTAdSupport.a in Frameworks */, 14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */, @@ -527,7 +546,7 @@ buildActionMask = 2147483647; files = ( 2D66FF8F1ECA406D00F0A767 /* libART.a in Frameworks */, - 14AADF051AC3DBB1002390C9 /* libReact.a in Frameworks */, + ADBDBA0D1DFEC24D00ED6528 /* libRCTBlob.a in Frameworks */, 147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */, 134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */, 13E501F11D07A84A005F35D8 /* libRCTAnimation.a in Frameworks */, @@ -572,6 +591,7 @@ 2DD323E61DA2DE3F000FE1B8 /* libRCTNetwork-tvOS.a in Frameworks */, 3D05746D1DE6008900184BB4 /* libRCTPushNotification-tvOS.a in Frameworks */, 2DD323E71DA2DE3F000FE1B8 /* libRCTSettings-tvOS.a in Frameworks */, + ADD01A631E093FA900F6D226 /* libRCTBlob-tvOS.a in Frameworks */, 2DD323E81DA2DE3F000FE1B8 /* libRCTText-tvOS.a in Frameworks */, 2DD323E91DA2DE3F000FE1B8 /* libRCTWebSocket-tvOS.a in Frameworks */, ); @@ -599,6 +619,7 @@ isa = PBXGroup; children = ( 2D66FF5F1ECA405900F0A767 /* ART.xcodeproj */, + ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */, 14AADEFF1AC3DB95002390C9 /* React.xcodeproj */, 14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */, 134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */, @@ -923,6 +944,15 @@ name = Products; sourceTree = ""; }; + ADBDB9E91DFEC24500ED6528 /* Products */ = { + isa = PBXGroup; + children = ( + ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */, + ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; D85B82921AB6D5CE003F4FE2 /* Products */ = { isa = PBXGroup; children = ( @@ -1117,6 +1147,10 @@ ProductGroup = 13E5019D1D07A502005F35D8 /* Products */; ProjectRef = 13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */; }, + { + ProductGroup = ADBDB9E91DFEC24500ED6528 /* Products */; + ProjectRef = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; + }, { ProductGroup = 138DEE031B9EDDDB007F4EA5 /* Products */; ProjectRef = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */; @@ -1432,6 +1466,20 @@ remoteRef = 834C36D11AF8DA610019C93C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTBlob.a; + remoteRef = ADBDB9F01DFEC24500ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTBlob-tvOS.a"; + remoteRef = ADD01A461E093FA100F6D226 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; diff --git a/RNTester/RNTesterLegacy.xcodeproj/project.pbxproj b/RNTester/RNTesterLegacy.xcodeproj/project.pbxproj index fa2fa7c34a9c62..46cf6768aedba5 100644 --- a/RNTester/RNTesterLegacy.xcodeproj/project.pbxproj +++ b/RNTester/RNTesterLegacy.xcodeproj/project.pbxproj @@ -99,6 +99,7 @@ 2DD323E71DA2DE3F000FE1B8 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323C81DA2DD8B000FE1B8 /* libRCTSettings-tvOS.a */; }; 2DD323E81DA2DE3F000FE1B8 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D01DA2DD8B000FE1B8 /* libRCTText-tvOS.a */; }; 2DD323E91DA2DE3F000FE1B8 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D51DA2DD8B000FE1B8 /* libRCTWebSocket-tvOS.a */; }; + 2DD323EA1DA2DE3F000FE1B8 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D91DA2DD8B000FE1B8 /* libReact.a */; }; 3578590A1B28D2CF00341EDB /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 357859011B28D2C500341EDB /* libRCTLinking.a */; }; 39AA31A41DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 39AA31A31DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m */; }; 3D05746D1DE6008900184BB4 /* libRCTPushNotification-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D05746C1DE6008900184BB4 /* libRCTPushNotification-tvOS.a */; }; @@ -115,6 +116,9 @@ 83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; }; 8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */; }; 8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */; }; + ADAC7A091E093BB900D77272 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */; }; + ADBDBA0D1DFEC24D00ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */; }; + ADD01A631E093FA900F6D226 /* libRCTBlob-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */; }; BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */; }; C654F14C1EB34D0C000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F14B1EB34D0C000B7A9A /* RNTesterTestModule.m */; }; C654F16E1EB34D14000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F14B1EB34D0C000B7A9A /* RNTesterTestModule.m */; }; @@ -374,6 +378,20 @@ remoteGlobalIDString = 134814201AA4EA6300B7C361; remoteInfo = RCTSettings; }; + ADBDB9F01DFEC24500ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 358F4ED71D1E81A9004DF814; + remoteInfo = RCTBlob; + }; + ADD01A461E093FA100F6D226 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = ADAC7A2E1E093EF800D77272; + remoteInfo = "RCTBlob-tvOS"; + }; D85B829B1AB6D5CE003F4FE2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */; @@ -461,6 +479,7 @@ 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderTests.m; sourceTree = ""; }; 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderHelpers.m; sourceTree = ""; }; 8385CF051B8747A000C6273E /* RCTImageLoaderHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTImageLoaderHelpers.h; sourceTree = ""; }; + ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenuTests.m; sourceTree = ""; }; C654F14B1EB34D0C000B7A9A /* RNTesterTestModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNTesterTestModule.m; sourceTree = ""; }; D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = ""; }; @@ -471,6 +490,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + ADAC7A091E093BB900D77272 /* libRCTBlob.a in Frameworks */, 14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */, 14D6D71F1B2222EF001FB087 /* libRCTAdSupport.a in Frameworks */, 14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */, @@ -490,7 +510,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1380DCD41E70C44800E7C47D /* libReact.a in Frameworks */, + ADBDBA0D1DFEC24D00ED6528 /* libRCTBlob.a in Frameworks */, + 14AADF051AC3DBB1002390C9 /* libReact.a in Frameworks */, 147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */, 134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */, 13E501F11D07A84A005F35D8 /* libRCTAnimation.a in Frameworks */, @@ -527,12 +548,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2DD323EA1DA2DE3F000FE1B8 /* libReact.a in Frameworks */, 2DD323E31DA2DE3F000FE1B8 /* libRCTAnimation-tvOS.a in Frameworks */, 3D302F221DF8285100D6DDAE /* libRCTImage-tvOS.a in Frameworks */, 2DD323E51DA2DE3F000FE1B8 /* libRCTLinking-tvOS.a in Frameworks */, 2DD323E61DA2DE3F000FE1B8 /* libRCTNetwork-tvOS.a in Frameworks */, 3D05746D1DE6008900184BB4 /* libRCTPushNotification-tvOS.a in Frameworks */, 2DD323E71DA2DE3F000FE1B8 /* libRCTSettings-tvOS.a in Frameworks */, + ADD01A631E093FA900F6D226 /* libRCTBlob-tvOS.a in Frameworks */, 2DD323E81DA2DE3F000FE1B8 /* libRCTText-tvOS.a in Frameworks */, 2DD323E91DA2DE3F000FE1B8 /* libRCTWebSocket-tvOS.a in Frameworks */, ); @@ -559,7 +582,8 @@ 1316A21D1AA397F400C0188E /* Libraries */ = { isa = PBXGroup; children = ( - 1380DC8B1E70C0DC00E7C47D /* ReactLegacy.xcodeproj */, + ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */, + 14AADEFF1AC3DB95002390C9 /* React.xcodeproj */, 14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */, 134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */, 13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */, @@ -752,6 +776,21 @@ name = Products; sourceTree = ""; }; + 14AADF001AC3DB95002390C9 /* Products */ = { + isa = PBXGroup; + children = ( + 14AADF041AC3DB95002390C9 /* libReact.a */, + 2DD323D91DA2DD8B000FE1B8 /* libReact.a */, + 3D3C08811DE3424E00C268FA /* libyoga.a */, + 3D3C08831DE3424E00C268FA /* libyoga.a */, + 3D05748C1DE6008900184BB4 /* libcxxreact.a */, + 3D05748E1DE6008900184BB4 /* libcxxreact.a */, + 3D0574901DE6008900184BB4 /* libjschelpers.a */, + 3D0574921DE6008900184BB4 /* libjschelpers.a */, + ); + name = Products; + sourceTree = ""; + }; 14D6D6EA1B2205C0001FB087 /* OCMock */ = { isa = PBXGroup; children = ( @@ -871,6 +910,15 @@ name = Products; sourceTree = ""; }; + ADBDB9E91DFEC24500ED6528 /* Products */ = { + isa = PBXGroup; + children = ( + ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */, + ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; D85B82921AB6D5CE003F4FE2 /* Products */ = { isa = PBXGroup; children = ( @@ -1061,6 +1109,10 @@ ProductGroup = 13E5019D1D07A502005F35D8 /* Products */; ProjectRef = 13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */; }, + { + ProductGroup = ADBDB9E91DFEC24500ED6528 /* Products */; + ProjectRef = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; + }, { ProductGroup = 138DEE031B9EDDDB007F4EA5 /* Products */; ProjectRef = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */; @@ -1320,6 +1372,13 @@ remoteRef = 2DD323D41DA2DD8B000FE1B8 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 2DD323D91DA2DD8B000FE1B8 /* libReact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libReact.a; + remoteRef = 2DD323D81DA2DD8B000FE1B8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 357859011B28D2C500341EDB /* libRCTLinking.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1334,6 +1393,48 @@ remoteRef = 3D05746B1DE6008900184BB4 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 3D05748C1DE6008900184BB4 /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = 3D05748B1DE6008900184BB4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3D05748E1DE6008900184BB4 /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = 3D05748D1DE6008900184BB4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3D0574901DE6008900184BB4 /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = 3D05748F1DE6008900184BB4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3D0574921DE6008900184BB4 /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = 3D0574911DE6008900184BB4 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3D3C08811DE3424E00C268FA /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = 3D3C08801DE3424E00C268FA /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3D3C08831DE3424E00C268FA /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = 3D3C08821DE3424E00C268FA /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 58005BEE1ABA80530062E044 /* libRCTTest.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -1348,6 +1449,20 @@ remoteRef = 834C36D11AF8DA610019C93C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTBlob.a; + remoteRef = ADBDB9F01DFEC24500ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = "libRCTBlob-tvOS.a"; + remoteRef = ADD01A461E093FA100F6D226 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; diff --git a/React.podspec b/React.podspec index b493b13a296ec9..7be163417b58b3 100644 --- a/React.podspec +++ b/React.podspec @@ -131,10 +131,22 @@ Pod::Spec.new do |s| ss.header_dir = "RCTAnimation" end - s.subspec "RCTCameraRoll" do |ss| - ss.dependency "React/Core" - ss.dependency "React/RCTImage" - ss.source_files = "Libraries/CameraRoll/*.{h,m}" + s.subspec 'RCTBlob' do |ss| + ss.dependency 'React/Core' + ss.source_files = "Libraries/Blob/*.{h,m}" + ss.preserve_paths = "Libraries/Blob/*.js" + end + + s.subspec 'RCTBlob' do |ss| + ss.dependency 'React/Core' + ss.source_files = "Libraries/Blob/*.{h,m}" + ss.preserve_paths = "Libraries/Blob/*.js" + end + + s.subspec 'RCTCameraRoll' do |ss| + ss.dependency 'React/Core' + ss.dependency 'React/RCTImage' + ss.source_files = "Libraries/CameraRoll/*.{h,m}" end s.subspec "RCTGeolocation" do |ss| @@ -173,9 +185,10 @@ Pod::Spec.new do |s| ss.source_files = "Libraries/Vibration/*.{h,m}" end - s.subspec "RCTWebSocket" do |ss| - ss.dependency "React/Core" - ss.source_files = "Libraries/WebSocket/*.{h,m}" + s.subspec 'RCTWebSocket' do |ss| + ss.dependency 'React/Core' + ss.dependency 'React/RCTBlob' + ss.source_files = "Libraries/WebSocket/*.{h,m}" end s.subspec "RCTLinkingIOS" do |ss| diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK new file mode 100644 index 00000000000000..e699eebcd78070 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -0,0 +1,23 @@ +include_defs('//ReactAndroid/DEFS') + +android_library( + name = 'blob', + srcs = glob(['**/*.java']), + deps = [ + react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'), + react_native_dep('third-party/android/support-annotations:android-support-annotations'), + react_native_dep('third-party/android/support/v4:lib-support-v4'), + react_native_dep('third-party/java/infer-annotations:infer-annotations'), + react_native_dep('third-party/java/jsr-305:jsr-305'), + react_native_target('java/com/facebook/react/bridge:bridge'), + react_native_target('java/com/facebook/react/common:common'), + react_native_target('java/com/facebook/react/module/annotations:annotations'), + ], + visibility = [ + 'PUBLIC', + ], +) + +project_config( + src_target = ':blob', +) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java new file mode 100644 index 00000000000000..779117268d9dba --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -0,0 +1,133 @@ +/** + * 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. + */ + +package com.facebook.react.modules.blob; + +import android.content.res.Resources; +import android.net.Uri; +import android.support.annotation.Nullable; + +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.common.MapBuilder; +import com.facebook.react.module.annotations.ReactModule; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@ReactModule(name = "BlobModule") +public class BlobModule extends ReactContextBaseJavaModule { + + public BlobModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public String getName() { + return "BlobModule"; + } + + @Override + @Nullable + public Map getConstants() { + // The application can register BlobProvider as a ContentProvider so that blobs are resolvable. + // If it does, it needs to tell us what authority was used via this string resource. + Resources resources = getReactApplicationContext().getResources(); + String packageName = getReactApplicationContext().getPackageName(); + int resourceId = resources.getIdentifier("blob_provider_authority", "string", packageName); + if (resourceId == 0) { + return null; + } + + return MapBuilder.of( + "BLOB_URI_SCHEME", "content", + "BLOB_URI_HOST", resources.getString(resourceId)); + } + + private static Map sBlobs = new HashMap<>(); + + public static String store(byte[] data) { + String blobId = UUID.randomUUID().toString(); + store(data, blobId); + return blobId; + } + + public static void store(byte[] data, String blobId) { + sBlobs.put(blobId, data); + } + + public static void remove(String blobId) { + sBlobs.remove(blobId); + } + + @Nullable + public static byte[] resolve(Uri uri) { + String blobId = uri.getLastPathSegment(); + int offset = 0; + int size = -1; + String offsetParam = uri.getQueryParameter("offset"); + if (offsetParam != null) { + offset = Integer.parseInt(offsetParam, 10); + } + String sizeParam = uri.getQueryParameter("size"); + if (sizeParam != null) { + size = Integer.parseInt(sizeParam, 10); + } + return resolve(blobId, offset, size); + } + + @Nullable + public static byte[] resolve(String blobId, int offset, int size) { + byte[] data = sBlobs.get(blobId); + if (data == null){ + return null; + } + if (size == -1) { + size = data.length - offset; + } + if (offset > 0) { + data = Arrays.copyOfRange(data, offset, offset + size); + } + return data; + } + + @Nullable + public static byte[] resolve(ReadableMap blob) { + return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); + } + + + @ReactMethod + public void createFromParts(ReadableArray parts, String blobId) { + int totalBlobSize = 0; + ArrayList partList = new ArrayList<>(parts.size()); + for (int i = 0; i < parts.size(); i++) { + ReadableMap part = parts.getMap(i); + totalBlobSize += part.getInt("size"); + partList.add(i, part); + } + ByteBuffer buffer = ByteBuffer.allocate(totalBlobSize); + for (ReadableMap part : partList) { + buffer.put(resolve(part)); + } + store(buffer.array(), blobId); + } + + @ReactMethod + public void release(String blobId) { + remove(blobId); + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java new file mode 100644 index 00000000000000..fea21798d70a4d --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java @@ -0,0 +1,87 @@ +/** + * 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. + */ + +package com.facebook.react.modules.blob; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.os.ParcelFileDescriptor; +import android.support.annotation.Nullable; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; + +public final class BlobProvider extends ContentProvider { + + @Override + public boolean onCreate() { + return false; + } + + @Nullable + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + return null; + } + + @Nullable + @Override + public String getType(Uri uri) { + return null; + } + + @Nullable + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { + if (!mode.equals("r")) { + throw new FileNotFoundException("Cannot open " + uri.toString() + " in mode '" + mode + "'"); + } + byte[] data = BlobModule.resolve(uri); + if (data == null) { + throw new FileNotFoundException("Cannot open " + uri.toString() + ", blob not found."); + } + + ParcelFileDescriptor[] pipe; + try { + pipe = ParcelFileDescriptor.createPipe(); + } catch (IOException exception) { + return null; + } + ParcelFileDescriptor readSide = pipe[0]; + ParcelFileDescriptor writeSide = pipe[1]; + + OutputStream outputStream = new ParcelFileDescriptor.AutoCloseOutputStream(writeSide); + try { + outputStream.write(data); + outputStream.close(); + } catch (IOException exception) { + return null; + } + + return readSide; + } +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK index 6ea83d2e5c85ec..091cf8cb15eea2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK @@ -1,21 +1,23 @@ include_defs("//ReactAndroid/DEFS") android_library( - name = "websocket", - srcs = glob(["**/*.java"]), - visibility = [ - "PUBLIC", - ], - deps = [ - react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), - react_native_dep("third-party/java/infer-annotations:infer-annotations"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_dep("third-party/java/okhttp:okhttp3"), - react_native_dep("third-party/java/okio:okio"), - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/module/annotations:annotations"), - react_native_target("java/com/facebook/react/modules/core:core"), - react_native_target("java/com/facebook/react/modules/network:network"), - ], + name = 'websocket', + srcs = glob(['**/*.java']), + deps = [ + react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'), + react_native_dep('third-party/java/infer-annotations:infer-annotations'), + react_native_dep('third-party/java/jsr-305:jsr-305'), + react_native_dep('third-party/java/okhttp:okhttp3'), + react_native_dep('third-party/java/okhttp:okhttp3-ws'), + react_native_dep('third-party/java/okio:okio'), + react_native_target('java/com/facebook/react/bridge:bridge'), + react_native_target('java/com/facebook/react/common:common'), + react_native_target('java/com/facebook/react/module/annotations:annotations'), + react_native_target('java/com/facebook/react/modules/core:core'), + react_native_target('java/com/facebook/react/modules/network:network'), + react_native_target('java/com/facebook/react/modules/blob:blob'), + ], + visibility = [ + 'PUBLIC', + ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java index 7213bb730e661f..c7a1bced98a328 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java @@ -9,16 +9,6 @@ package com.facebook.react.modules.websocket; -import javax.annotation.Nullable; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactApplicationContext; @@ -32,9 +22,20 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.ReactConstants; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.blob.BlobModule; import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.network.ForwardingCookieHandler; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -46,6 +47,7 @@ public class WebSocketModule extends ReactContextBaseJavaModule { private final Map mWebSocketConnections = new HashMap<>(); + private final Map mBlobsEnabled = new HashMap<>(); private ReactContext mReactContext; private ForwardingCookieHandler mCookieHandler; @@ -58,8 +60,8 @@ public WebSocketModule(ReactApplicationContext context) { private void sendEvent(String eventName, WritableMap params) { mReactContext - .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(eventName, params); + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); } @Override @@ -69,19 +71,19 @@ public String getName() { @ReactMethod public void connect( - final String url, - @Nullable final ReadableArray protocols, - @Nullable final ReadableMap headers, - final int id) { + final String url, + @Nullable final ReadableArray protocols, + @Nullable final ReadableMap headers, + final int id) { OkHttpClient client = new OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read - .build(); + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read + .build(); Request.Builder builder = new Request.Builder() - .tag(id) - .url(url); + .tag(id) + .url(url); String cookie = getCookie(url); if (cookie != null) { @@ -101,8 +103,8 @@ public void connect( builder.addHeader(key, headers.getString(key)); } else { FLog.w( - ReactConstants.TAG, - "Ignoring: requested " + key + ", value not a string"); + ReactConstants.TAG, + "Ignoring: requested " + key + ", value not a string"); } } } else { @@ -159,11 +161,28 @@ public void onMessage(WebSocket webSocket, String text) { @Override public void onMessage(WebSocket webSocket, ByteString bytes) { - String text = bytes.utf8(); WritableMap params = Arguments.createMap(); + params.putInt("id", id); - params.putString("data", text); - params.putString("type", "binary"); + + if (mBlobsEnabled.containsKey(id) && mBlobsEnabled.get(id)) { + byte[] data = bytes.toByteArray(); + + WritableMap blob = Arguments.createMap(); + + blob.putString("blobId", BlobModule.store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + + params.putMap("data", blob); + params.putString("type", "blob"); + } else { + String text = bytes.utf8(); + + params.putString("data", text); + params.putString("type", "binary"); + } + sendEvent("websocketMessage", params); } }); @@ -183,11 +202,12 @@ public void close(int code, String reason, int id) { try { client.close(code, reason); mWebSocketConnections.remove(id); + mBlobsEnabled.remove(id); } catch (Exception e) { FLog.e( - ReactConstants.TAG, - "Could not close WebSocket connection for id " + id, - e); + ReactConstants.TAG, + "Could not close WebSocket connection for id " + id, + e); } } @@ -219,6 +239,25 @@ public void sendBinary(String base64String, int id) { } } + @ReactMethod + public void sendBlob(ReadableMap blob, int id) { + WebSocket client = mWebSocketConnections.get(id); + if (client == null) { + // This is a programmer error + throw new RuntimeException("Cannot send a message. Unknown WebSocket id " + id); + } + byte[] data = BlobModule.resolve( + blob.getString("blobId"), + blob.getInt("offset"), + blob.getInt("size")); + + if (data != null) { + client.send(ByteString.of(data)); + } else { + notifyWebSocketFailed(id, "Blob data not found for id " + id); + } + } + @ReactMethod public void ping(int id) { WebSocket client = mWebSocketConnections.get(id); @@ -243,7 +282,7 @@ private void notifyWebSocketFailed(int id, String message) { /** * Get the default HTTP(S) origin for a specific WebSocket URI * - * @param String uri + * @param uri * @return A string of the endpoint converted to HTTP protocol (http[s]://host[:port]) */ @@ -263,10 +302,10 @@ private static String getDefaultOrigin(String uri) { if (requestURI.getPort() != -1) { defaultOrigin = String.format( - "%s://%s:%s", - scheme, - requestURI.getHost(), - requestURI.getPort()); + "%s://%s:%s", + scheme, + requestURI.getHost(), + requestURI.getPort()); } else { defaultOrigin = String.format("%s://%s/", scheme, requestURI.getHost()); } @@ -277,10 +316,15 @@ private static String getDefaultOrigin(String uri) { } } + @ReactMethod + public void setBinaryType(String binaryType, int id) { + mBlobsEnabled.put(id, binaryType.equals("blob")); + } + /** * Get the cookie for a specific domain * - * @param String uri + * @param uri * @return The cookie header or null if none is set */ private String getCookie(String uri) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index a928e6688d1bba..1fcc65c31a772f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -1,65 +1,65 @@ include_defs("//ReactAndroid/DEFS") android_library( - name = "shell", - srcs = glob(["**/*.java"]), - visibility = [ - "PUBLIC", - ], - deps = [ - react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"), - react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), - react_native_dep("third-party/android/support/v4:lib-support-v4"), - react_native_dep("third-party/java/infer-annotations:infer-annotations"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_target("java/com/facebook/react:react"), - react_native_target("java/com/facebook/react/animated:animated"), - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/devsupport:devsupport"), - react_native_target("java/com/facebook/react/flat:flat"), - react_native_target("java/com/facebook/react/module/model:model"), - react_native_target("java/com/facebook/react/modules/accessibilityinfo:accessibilityinfo"), - react_native_target("java/com/facebook/react/modules/appstate:appstate"), - react_native_target("java/com/facebook/react/modules/camera:camera"), - react_native_target("java/com/facebook/react/modules/clipboard:clipboard"), - react_native_target("java/com/facebook/react/modules/core:core"), - react_native_target("java/com/facebook/react/modules/datepicker:datepicker"), - react_native_target("java/com/facebook/react/modules/debug:debug"), - react_native_target("java/com/facebook/react/modules/dialog:dialog"), - react_native_target("java/com/facebook/react/modules/fresco:fresco"), - react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), - react_native_target("java/com/facebook/react/modules/image:image"), - react_native_target("java/com/facebook/react/modules/intent:intent"), - react_native_target("java/com/facebook/react/modules/location:location"), - react_native_target("java/com/facebook/react/modules/netinfo:netinfo"), - react_native_target("java/com/facebook/react/modules/network:network"), - react_native_target("java/com/facebook/react/modules/permissions:permissions"), - react_native_target("java/com/facebook/react/modules/share:share"), - react_native_target("java/com/facebook/react/modules/statusbar:statusbar"), - react_native_target("java/com/facebook/react/modules/storage:storage"), - react_native_target("java/com/facebook/react/modules/timepicker:timepicker"), - react_native_target("java/com/facebook/react/modules/toast:toast"), - react_native_target("java/com/facebook/react/modules/vibration:vibration"), - react_native_target("java/com/facebook/react/modules/websocket:websocket"), - react_native_target("java/com/facebook/react/uimanager:uimanager"), - react_native_target("java/com/facebook/react/views/art:art"), - react_native_target("java/com/facebook/react/views/drawer:drawer"), - react_native_target("java/com/facebook/react/views/image:image"), - react_native_target("java/com/facebook/react/views/modal:modal"), - react_native_target("java/com/facebook/react/views/picker:picker"), - react_native_target("java/com/facebook/react/views/progressbar:progressbar"), - react_native_target("java/com/facebook/react/views/scroll:scroll"), - react_native_target("java/com/facebook/react/views/slider:slider"), - react_native_target("java/com/facebook/react/views/swiperefresh:swiperefresh"), - react_native_target("java/com/facebook/react/views/switchview:switchview"), - react_native_target("java/com/facebook/react/views/text:text"), - react_native_target("java/com/facebook/react/views/text/frescosupport:frescosupport"), - react_native_target("java/com/facebook/react/views/textinput:textinput"), - react_native_target("java/com/facebook/react/views/toolbar:toolbar"), - react_native_target("java/com/facebook/react/views/view:view"), - react_native_target("java/com/facebook/react/views/viewpager:viewpager"), - react_native_target("java/com/facebook/react/views/webview:webview"), - react_native_target("res:shell"), - ], + name = 'shell', + srcs = glob(['**/*.java']), + deps = [ + react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'), + react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'), + react_native_dep('third-party/android/support/v4:lib-support-v4'), + react_native_dep('third-party/java/infer-annotations:infer-annotations'), + react_native_dep('third-party/java/jsr-305:jsr-305'), + react_native_target('java/com/facebook/react:react'), + react_native_target('java/com/facebook/react/animated:animated'), + react_native_target('java/com/facebook/react/bridge:bridge'), + react_native_target('java/com/facebook/react/common:common'), + react_native_target('java/com/facebook/react/devsupport:devsupport'), + react_native_target('java/com/facebook/react/module/model:model'), + react_native_target('java/com/facebook/react/modules/appstate:appstate'), + react_native_target('java/com/facebook/react/modules/blob:blob'), + react_native_target('java/com/facebook/react/modules/camera:camera'), + react_native_target('java/com/facebook/react/modules/clipboard:clipboard'), + react_native_target('java/com/facebook/react/modules/core:core'), + react_native_target('java/com/facebook/react/modules/datepicker:datepicker'), + react_native_target('java/com/facebook/react/modules/debug:debug'), + react_native_target('java/com/facebook/react/modules/dialog:dialog'), + react_native_target('java/com/facebook/react/modules/fresco:fresco'), + react_native_target('java/com/facebook/react/modules/i18nmanager:i18nmanager'), + react_native_target('java/com/facebook/react/modules/image:image'), + react_native_target('java/com/facebook/react/modules/intent:intent'), + react_native_target('java/com/facebook/react/modules/location:location'), + react_native_target('java/com/facebook/react/modules/netinfo:netinfo'), + react_native_target('java/com/facebook/react/modules/network:network'), + react_native_target('java/com/facebook/react/modules/permissions:permissions'), + react_native_target('java/com/facebook/react/modules/share:share'), + react_native_target('java/com/facebook/react/modules/statusbar:statusbar'), + react_native_target('java/com/facebook/react/modules/storage:storage'), + react_native_target('java/com/facebook/react/modules/timepicker:timepicker'), + react_native_target('java/com/facebook/react/modules/toast:toast'), + react_native_target('java/com/facebook/react/modules/vibration:vibration'), + react_native_target('java/com/facebook/react/modules/websocket:websocket'), + react_native_target('java/com/facebook/react/uimanager:uimanager'), + react_native_target('java/com/facebook/react/views/art:art'), + react_native_target('java/com/facebook/react/views/drawer:drawer'), + react_native_target('java/com/facebook/react/views/image:image'), + react_native_target('java/com/facebook/react/views/modal:modal'), + react_native_target('java/com/facebook/react/views/picker:picker'), + react_native_target('java/com/facebook/react/views/progressbar:progressbar'), + react_native_target('java/com/facebook/react/views/recyclerview:recyclerview'), + react_native_target('java/com/facebook/react/views/scroll:scroll'), + react_native_target('java/com/facebook/react/views/slider:slider'), + react_native_target('java/com/facebook/react/views/swiperefresh:swiperefresh'), + react_native_target('java/com/facebook/react/views/switchview:switchview'), + react_native_target('java/com/facebook/react/views/text:text'), + react_native_target('java/com/facebook/react/views/text/frescosupport:frescosupport'), + react_native_target('java/com/facebook/react/views/textinput:textinput'), + react_native_target('java/com/facebook/react/views/toolbar:toolbar'), + react_native_target('java/com/facebook/react/views/view:view'), + react_native_target('java/com/facebook/react/views/viewpager:viewpager'), + react_native_target('java/com/facebook/react/views/webview:webview'), + react_native_target('res:shell'), + ], + visibility = [ + 'PUBLIC', + ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java index cb35735d745494..54c901ef2be5f4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java @@ -30,6 +30,7 @@ import com.facebook.react.module.model.ReactModuleInfoProvider; import com.facebook.react.modules.accessibilityinfo.AccessibilityInfoModule; import com.facebook.react.modules.appstate.AppStateModule; +import com.facebook.react.modules.blob.BlobModule; import com.facebook.react.modules.camera.CameraRollManager; import com.facebook.react.modules.camera.ImageEditingManager; import com.facebook.react.modules.camera.ImageStoreManager; @@ -113,6 +114,12 @@ public NativeModule get() { return new AppStateModule(context); } }), + new ModuleSpec(BlobModule.class, new Provider() { + @Override + public NativeModule get() { + return new BlobModule(context); + } + }), new ModuleSpec(AsyncStorageModule.class, new Provider() { @Override public NativeModule get() { diff --git a/local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj b/local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj index e4471789dbd729..795d2ebfb6b925 100644 --- a/local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj +++ b/local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 2DCD954D1E0B4F2C00145EB5 /* HelloWorldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* HelloWorldTests.m */; }; 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; + ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -158,48 +159,6 @@ remoteGlobalIDString = 2D2A28131D9B038B00D4039D; remoteInfo = "React-tvOS"; }; - 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C059A1DE3340900C268FA; - remoteInfo = yoga; - }; - 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C06751DE3340C00C268FA; - remoteInfo = "yoga-tvOS"; - }; - 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; - remoteInfo = cxxreact; - }; - 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; - remoteInfo = "cxxreact-tvOS"; - }; - 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; - remoteInfo = jschelpers; - }; - 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; - remoteInfo = "jschelpers-tvOS"; - }; 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; @@ -228,6 +187,13 @@ remoteGlobalIDString = 58B5119B1A9E6C1200147676; remoteInfo = RCTText; }; + ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 358F4ED71D1E81A9004DF814; + remoteInfo = RCTBlob; + }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ @@ -255,6 +221,7 @@ 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = "../node_modules/react-native/Libraries/NativeAnimation/RCTAnimation.xcodeproj"; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = ""; }; + ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = "../node_modules/react-native/Libraries/Blob/RCTBlob.xcodeproj"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -270,6 +237,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + ADBDB9381DFEBF1600ED6528 /* libRCTBlob.a in Frameworks */, + 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, 5E9157361DD0AC6A00FF2AA8 /* libRCTAnimation.a in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, @@ -404,13 +373,7 @@ isa = PBXGroup; children = ( 146834041AC3E56700842450 /* libReact.a */, - 3DAD3EA31DF850E9000B6D8A /* libReact.a */, - 3DAD3EA51DF850E9000B6D8A /* libyoga.a */, - 3DAD3EA71DF850E9000B6D8A /* libyoga.a */, - 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */, - 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */, - 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */, - 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */, + 3DAD3EA31DF850E9000B6D8A /* libReact-tvOS.a */, ); name = Products; sourceTree = ""; @@ -439,6 +402,7 @@ 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */, 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, + ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */, 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */, 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */, @@ -483,6 +447,22 @@ name = Products; sourceTree = ""; }; + ADBDB9201DFEBF0600ED6528 /* Products */ = { + isa = PBXGroup; + children = ( + ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */, + ); + name = Products; + sourceTree = ""; + }; + ADBDB9201DFEBF0600ED6528 /* Products */ = { + isa = PBXGroup; + children = ( + ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */, + ); + name = Products; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -602,6 +582,10 @@ ProductGroup = 5E91572E1DD0AC6500FF2AA8 /* Products */; ProjectRef = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; }, + { + ProductGroup = ADBDB9201DFEBF0600ED6528 /* Products */; + ProjectRef = ADBDB91F1DFEBF0600ED6528 /* RCTBlob.xcodeproj */; + }, { ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */; @@ -748,55 +732,13 @@ remoteRef = 3DAD3E981DF850E9000B6D8A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 3DAD3EA31DF850E9000B6D8A /* libReact.a */ = { + 3DAD3EA31DF850E9000B6D8A /* libReact-tvOS.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = libReact.a; + path = "libReact-tvOS.a"; remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; @@ -825,6 +767,13 @@ remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + ADBDB9271DFEBF0700ED6528 /* libRCTBlob.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libRCTBlob.a; + remoteRef = ADBDB9261DFEBF0700ED6528 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ diff --git a/package.json b/package.json index d6502fce51e370..9db8b9437891b7 100644 --- a/package.json +++ b/package.json @@ -210,6 +210,7 @@ "stacktrace-parser": "^0.1.3", "temp": "0.8.3", "throat": "^3.0.0", + "uuid": "^3.0.1", "whatwg-fetch": "^1.0.0", "wordwrap": "^1.0.0", "write-file-atomic": "^1.2.0", From be07fa92657b4648a666582583f6ba18041b559e Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 25 Nov 2016 14:47:45 +0530 Subject: [PATCH 02/66] Add a 'fromURI' method to blob --- Libraries/Blob/Blob.js | 11 +++ .../react/modules/blob/BlobModule.java | 68 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 6e57269ce85419..1f2caacc8d7aca 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -83,6 +83,17 @@ class Blob { return Object.assign(Object.create(Blob.prototype), props); } + /** + * Create blob from a local content URI + */ + static async fromURI(uri: string, options?: { type: string }): Promise { + const blob = await BlobModule.createFromURI(uri); + return Blob.create({ + ...blob, + type: options && options.type ? options.type : blob.type, + }); + } + /** * Constructor for JS consumers. * Currently we only support creating Blobs from other Blobs. diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 779117268d9dba..4e69056f490563 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -109,6 +109,41 @@ public static byte[] resolve(ReadableMap blob) { return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); } + private static byte[] getBytes(InputStream inputStream) throws IOException { + ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); + int bufferSize = 1024; + byte[] buffer = new byte[bufferSize]; + int len = 0; + while ((len = inputStream.read(buffer)) != -1) { + byteBuffer.write(buffer, 0, len); + } + return byteBuffer.toByteArray(); + } + + private String getNameFromUri(Uri contentUri) { + if (contentUri.getScheme().equals("file")) { + return contentUri.getLastPathSegment(); + } + String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME}; + Cursor metaCursor = getReactApplicationContext().getContentResolver().query(contentUri, projection, null, null, null); + if (metaCursor != null) { + try { + if (metaCursor.moveToFirst()) { + return metaCursor.getString(0); + } + } finally { + metaCursor.close(); + } + } + return contentUri.getLastPathSegment(); + } + + private long getLastModifiedFromUri(Uri contentUri) { + if (contentUri.getScheme().equals("file")) { + return new File(contentUri.toString()).lastModified(); + } + return 0; + } @ReactMethod public void createFromParts(ReadableArray parts, String blobId) { @@ -126,6 +161,39 @@ public void createFromParts(ReadableArray parts, String blobId) { store(buffer.array(), blobId); } + @ReactMethod + public void createFromURI(String path, Promise promise) { + try { + Uri uri = Uri.parse(path); + ContentResolver resolver = getReactApplicationContext().getContentResolver(); + + String type = resolver.getType(uri); + if (type != null) { + String ext = MimeTypeMap.getFileExtensionFromUrl(path); + if (ext != null) { + type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext); + } + } + + InputStream is = resolver.openInputStream(uri); + byte[] data = getBytes(is); + + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + blob.putString("type", type); + + // Needed for files + blob.putString("name", getNameFromUri(uri)); + blob.putDouble("lastModified", getLastModifiedFromUri(uri)); + + promise.resolve(blob); + } catch (Exception e) { + promise.reject(e); + } + } + @ReactMethod public void release(String blobId) { remove(blobId); From e8ea3888e217e2f79d266ec0fab59f2382a23260 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 25 Nov 2016 14:48:45 +0530 Subject: [PATCH 03/66] Fix blob not sliced when offset is 0 --- .../main/java/com/facebook/react/modules/blob/BlobModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 4e69056f490563..f65a95cb2517f2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -98,7 +98,7 @@ public static byte[] resolve(String blobId, int offset, int size) { if (size == -1) { size = data.length - offset; } - if (offset > 0) { + if (offset >= 0) { data = Arrays.copyOfRange(data, offset, offset + size); } return data; From 553f20e8b93909cdffc17e71fda99eb3783cf570 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 25 Nov 2016 14:51:20 +0530 Subject: [PATCH 04/66] Add blob support to XMLHttpRequest --- Libraries/Blob/File.js | 57 +++++++++++++++++ Libraries/Core/InitializeCore.js | 1 + Libraries/Network/XMLHttpRequest.js | 12 ++-- .../modules/network/NetworkingModule.java | 61 ++++++++++++++----- .../react/modules/network/ResponseUtil.java | 16 ++++- 5 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 Libraries/Blob/File.js diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js new file mode 100644 index 00000000000000..9d6f3b32a44b9e --- /dev/null +++ b/Libraries/Blob/File.js @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2013-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 File + * @flow + */ +'use strict'; + +const Blob = require('Blob'); +const { BlobModule } = require('react-native').NativeModules; + +import type { FileProps } from './BlobTypes'; + +/** + * The File interface provides information about files. + */ +class File extends Blob { + /** + * Construct file instance from blob data from native. + */ + static create(props: FileProps): File { + const file = Blob.create(props); + // Object.setPrototypeOf is not available + file.__proto__ = File.prototype; // eslint-disable-line no-proto + Object.defineProperties(file, { + name: { + enumerable: true, + configurable: false, + writable: false, + value: props.name, + }, + lastModified: { + enumerable: true, + configurable: false, + writable: false, + value: props.lastModified, + }, + }); + + return file; + } + + /** + * Create file from a local content URI + */ + static async fromURI(uri: string): Promise { + const options = await BlobModule.createFromURI(uri); + return File.create(options); + } +} + +module.exports = File; diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 968634131ec75d..cb09ae4e7e0c09 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -190,6 +190,7 @@ defineProperty(global, 'Request', () => require('fetch').Request); defineProperty(global, 'Response', () => require('fetch').Response); defineProperty(global, 'WebSocket', () => require('WebSocket')); defineProperty(global, 'Blob', () => require('Blob')); +defineProperty(global, 'File', () => require('File')); defineProperty(global, 'URL', () => require('URL')); // Set up Geolocation diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index 3e7f3953b3b865..becdecdfb62b74 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -13,10 +13,10 @@ const EventTarget = require('event-target-shim'); const RCTNetworking = require('RCTNetworking'); - const base64 = require('base64-js'); const invariant = require('fbjs/lib/invariant'); const warning = require('fbjs/lib/warning'); +const Blob = require('Blob'); type ResponseType = '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text'; type Response = ?Object | string; @@ -236,10 +236,7 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { break; case 'blob': - this._cachedResponse = new global.Blob( - [base64.toByteArray(this._response).buffer], - {type: this.getResponseHeader('content-type') || ''} - ); + this._cachedResponse = Blob.create(this._response); break; case 'json': @@ -486,9 +483,12 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { )); let nativeResponseType = 'text'; - if (this._responseType === 'arraybuffer' || this._responseType === 'blob') { + if (this._responseType === 'arraybuffer') { nativeResponseType = 'base64'; } + if (this._responseType === 'blob') { + nativeResponseType = 'blob'; + } invariant(this._method, 'Request method needs to be defined.'); invariant(this._url, 'Request URL needs to be defined.'); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index d4b047994d3938..aebaed42d1486f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -9,16 +9,6 @@ package com.facebook.react.modules.network; -import javax.annotation.Nullable; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - import android.util.Base64; import com.facebook.react.bridge.Arguments; @@ -31,8 +21,19 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.network.OkHttpCallUtil; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.blob.BlobModule; import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + import okhttp3.Call; import okhttp3.Callback; import okhttp3.CookieJar; @@ -62,6 +63,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule { private static final String REQUEST_BODY_KEY_URI = "uri"; private static final String REQUEST_BODY_KEY_FORMDATA = "formData"; private static final String REQUEST_BODY_KEY_BASE64 = "base64"; + private static final String REQUEST_BODY_KEY_BLOB_ID = "blobId"; private static final String USER_AGENT_HEADER_NAME = "user-agent"; private static final int CHUNK_TIMEOUT_NS = 100 * 1000000; // 100ms private static final int MAX_CHUNK_SIZE_BETWEEN_FLUSHES = 8 * 1024; // 8K @@ -295,6 +297,24 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { requestBuilder.method( method, RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); + } else if (data.hasKey(REQUEST_BODY_KEY_BLOB_ID)) { + if (data.hasKey("type")) { + String type = data.getString("type"); + if (!type.isEmpty()) { + contentType = type; + } + } + if (contentType == null) { + contentType = "application/octet-stream"; + } + String blobId = data.getString(REQUEST_BODY_KEY_BLOB_ID); + byte[] bytes = BlobModule.resolve( + blobId, + data.getInt("offset"), + data.getInt("size"));; + requestBuilder.method( + method, + RequestBody.create(MediaType.parse(contentType), bytes)); } else if (data.hasKey(REQUEST_BODY_KEY_FORMDATA)) { if (contentType == null) { contentType = "multipart/form-data"; @@ -367,13 +387,22 @@ public void onResponse(Call call, Response response) throws IOException { } // Otherwise send the data in one big chunk, in the format that JS requested. - String responseString = ""; - if (responseType.equals("text")) { - responseString = responseBody.string(); - } else if (responseType.equals("base64")) { - responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); + if (responseType.equals("blob")) { + byte[] data = responseBody.bytes(); + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", BlobModule.store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + ResponseUtil.onDataReceived(eventEmitter, requestId, blob); + } else { + String responseString = ""; + if (responseType.equals("text")) { + responseString = responseBody.string(); + } else if (responseType.equals("base64")) { + responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); + } + ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); } - ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); ResponseUtil.onRequestSuccess(eventEmitter, requestId); } catch (IOException e) { ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java index 5b589e195b0ccc..20bed2a23b3913 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java @@ -9,14 +9,14 @@ package com.facebook.react.modules.network; -import java.io.IOException; -import java.net.SocketTimeoutException; - import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; +import java.io.IOException; +import java.net.SocketTimeoutException; + /** * Util methods to send network responses to JS. */ @@ -71,6 +71,16 @@ public static void onDataReceived( eventEmitter.emit("didReceiveNetworkData", args); } + public static void onDataReceived( + RCTDeviceEventEmitter eventEmitter, + int requestId, + WritableMap data) { + WritableArray args = Arguments.createArray(); + args.pushInt(requestId); + args.pushMap(data); + + eventEmitter.emit("didReceiveNetworkData", args); + } public static void onRequestError( RCTDeviceEventEmitter eventEmitter, From aaba705dd317265620c242e6e7d19bbe8d40901a Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Tue, 13 Dec 2016 20:58:42 +0530 Subject: [PATCH 05/66] Make blob properties read-only following the spec --- Libraries/Blob/Blob.js | 86 ++++++------------- Libraries/Blob/BlobManager.js | 70 +++++++++++++++ Libraries/Blob/BlobTypes.js | 16 ++-- Libraries/Blob/File.js | 38 ++------ Libraries/Blob/URL.js | 2 +- Libraries/Network/RCTNetworking.ios.js | 2 + Libraries/Network/XMLHttpRequest.js | 17 +++- Libraries/WebSocket/WebSocket.js | 5 +- .../react-native-implementation.js | 1 + 9 files changed, 134 insertions(+), 103 deletions(-) create mode 100644 Libraries/Blob/BlobManager.js diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 1f2caacc8d7aca..f8ef28a451932d 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -12,11 +12,7 @@ 'use strict'; -const uuid = require('uuid'); -const invariant = require('fbjs/lib/invariant'); -const { BlobModule } = require('NativeModules'); - -import type { BlobProps } from './BlobTypes'; +import type { BlobData } from './BlobTypes'; /** * Opaque JS representation of some binary data in native. @@ -56,62 +52,16 @@ import type { BlobProps } from './BlobTypes'; * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob */ class Blob { - /** - * Size of the data contained in the Blob object, in bytes. - */ - size: number; - /* - * String indicating the MIME type of the data contained in the Blob. - * If the type is unknown, this string is empty. - */ - type: string; - - /* - * Unique id to identify the blob on native side (non-standard) - */ - blobId: string; - /* - * Offset to indicate part of blob, used when sliced (non-standard) - */ - offset: number; - - /** - * Construct blob instance from blob data from native. - * Used internally by modules like XHR, WebSocket, etc. - */ - static create(props: BlobProps): Blob { - return Object.assign(Object.create(Blob.prototype), props); - } - - /** - * Create blob from a local content URI - */ - static async fromURI(uri: string, options?: { type: string }): Promise { - const blob = await BlobModule.createFromURI(uri); - return Blob.create({ - ...blob, - type: options && options.type ? options.type : blob.type, - }); - } + data: BlobData; /** * Constructor for JS consumers. * Currently we only support creating Blobs from other Blobs. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob */ - constructor(parts: Array, options: any) { - let blobId = uuid.v4(); - let size = 0; - parts.forEach((part) => { - invariant(part instanceof Blob, 'Can currently only create a Blob from other Blobs'); - size += part.size; - }); - BlobModule.createFromParts(parts, blobId); - return Blob.create({ - blobId, - offset: 0, - size, - }); + constructor(parts: Array = []) { + const BlobManager = require('BlobManager'); + return BlobManager.createFromParts(parts); } /* @@ -120,8 +70,8 @@ class Blob { * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice */ slice(start?: number, end?: number): Blob { - let offset = this.offset; - let size = this.size; + const BlobManager = require('BlobManager'); + let { size, offset } = this.data; if (typeof start === 'number') { if (start > size) { start = size; @@ -136,8 +86,8 @@ class Blob { size = end - start; } } - return Blob.create({ - blobId: this.blobId, + return BlobManager.createFromOptions({ + blobId: this.data.blobId, offset, size, }); @@ -156,7 +106,23 @@ class Blob { * `new Blob([blob, ...])` actually copies the data in memory. */ close() { - BlobModule.release(this.blobId); + const BlobManager = require('BlobManager'); + BlobManager.release(this.data.blobId); + } + + /** + * Size of the data contained in the Blob object, in bytes. + */ + get size(): number { + return this.data.size; + } + + /* + * String indicating the MIME type of the data contained in the Blob. + * If the type is unknown, this string is empty. + */ + get type(): string { + return this.data.type || ''; } } diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js new file mode 100644 index 00000000000000..1ff66ec599c84c --- /dev/null +++ b/Libraries/Blob/BlobManager.js @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2013-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 BlobManager + * @flow + */ + +'use strict'; + +const uuid = require('uuid'); +const invariant = require('fbjs/lib/invariant'); +const Blob = require('Blob'); +const File = require('File'); +const { BlobModule } = require('react-native').NativeModules; + +import type { BlobData } from './BlobTypes'; + +/** + * Module to manage blobs + */ +class BlobManager { + + /** + * Create blob from existing array of blobs. + */ + static createFromParts(parts: Array): Blob { + let blobId = uuid.v4(); + let size = 0; + parts.forEach((part) => { + invariant(part instanceof Blob, 'Can currently only create a Blob from other Blobs'); + size += part.size; + }); + BlobModule.createFromParts(parts, blobId); + return BlobManager.createFromOptions({ + blobId, + offset: 0, + size, + }); + } + + /** + * Create blob instance from blob data from native. + * Used internally by modules like XHR, WebSocket, etc. + */ + static createFromOptions(options: BlobData): Blob { + return Object.assign(Object.create(Blob.prototype), { data: options }); + } + + /** + * Create file instance from a local content URI + */ + static async createFromURI(uri: string, options?: { type: string }): Promise { + const blob = await BlobModule.createFromURI(uri); + return Object.assign(Object.create(File.prototype), { data: blob }); + } + + /** + * Deallocate resources for a blob. + */ + static release(blobId: string) { + return BlobModule.release(blobId); + } +} + +module.exports = BlobManager; diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js index 1e3e8ad34a372a..4c5c9965fa2e9b 100644 --- a/Libraries/Blob/BlobTypes.js +++ b/Libraries/Blob/BlobTypes.js @@ -9,14 +9,18 @@ * @flow */ -export type BlobProps = { +export type BlobData = { + /* + * Unique id to identify the blob on native side + */ blobId: string; + /* + * Offset to indicate part of blob, used when sliced + */ offset: number; + size: number; type?: string; -}; - -export type FileProps = BlobProps & { - name: string; - lastModified: number; + name?: string; + lastModified?: number; }; diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js index 9d6f3b32a44b9e..df8d612ee5df46 100644 --- a/Libraries/Blob/File.js +++ b/Libraries/Blob/File.js @@ -12,45 +12,23 @@ 'use strict'; const Blob = require('Blob'); -const { BlobModule } = require('react-native').NativeModules; - -import type { FileProps } from './BlobTypes'; /** * The File interface provides information about files. */ class File extends Blob { - /** - * Construct file instance from blob data from native. + /** + * Name of the file. */ - static create(props: FileProps): File { - const file = Blob.create(props); - // Object.setPrototypeOf is not available - file.__proto__ = File.prototype; // eslint-disable-line no-proto - Object.defineProperties(file, { - name: { - enumerable: true, - configurable: false, - writable: false, - value: props.name, - }, - lastModified: { - enumerable: true, - configurable: false, - writable: false, - value: props.lastModified, - }, - }); - - return file; + get name(): string { + return this.data.name || ''; } - /** - * Create file from a local content URI + /* + * Last modified time of the file. */ - static async fromURI(uri: string): Promise { - const options = await BlobModule.createFromURI(uri); - return File.create(options); + get lastModified(): number { + return this.data.lastModified || 0; } } diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index 026af2fce0b968..7768a2d80a008c 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -55,7 +55,7 @@ class URL { if (BLOB_URL_PREFIX === null) { throw new Error('Cannot create URL for blob!'); } - return `${BLOB_URL_PREFIX}${blob.blobId}?offset=${blob.offset}&size=${blob.size}`; + return `${BLOB_URL_PREFIX}${blob.data.blobId}?offset=${blob.data.offset}&size=${blob.size}`; } static revokeObjectURL(url: string) { diff --git a/Libraries/Network/RCTNetworking.ios.js b/Libraries/Network/RCTNetworking.ios.js index 15f3d6da7ac08c..f2c8bb95b12500 100644 --- a/Libraries/Network/RCTNetworking.ios.js +++ b/Libraries/Network/RCTNetworking.ios.js @@ -18,6 +18,8 @@ const convertRequestBody = require('convertRequestBody'); import type {RequestBody} from 'convertRequestBody'; +import type { NativeResponseType } from './XMLHttpRequest'; + class RCTNetworking extends NativeEventEmitter { isAvailable: boolean = true; diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index becdecdfb62b74..315e2a51e55986 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -17,9 +17,11 @@ const base64 = require('base64-js'); const invariant = require('fbjs/lib/invariant'); const warning = require('fbjs/lib/warning'); const Blob = require('Blob'); +const BlobManager = require('BlobManager'); -type ResponseType = '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text'; -type Response = ?Object | string; +export type NativeResponseType = 'base64' | 'blob' | 'text'; +export type ResponseType = '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text'; +export type Response = ?Object | string; type XHRInterceptor = { requestSent( @@ -236,7 +238,11 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { break; case 'blob': - this._cachedResponse = Blob.create(this._response); + if (typeof this._response === 'object' && this._response) { + this._cachedResponse = BlobManager.createFromOptions(this._response); + } else { + throw new Error('Invalid response for blob'); + } break; case 'json': @@ -482,13 +488,16 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { (args) => this.__didCompleteResponse(...args) )); - let nativeResponseType = 'text'; + let nativeResponseType: NativeResponseType = 'text'; if (this._responseType === 'arraybuffer') { nativeResponseType = 'base64'; } if (this._responseType === 'blob') { nativeResponseType = 'blob'; } + if (data instanceof Blob) { + data = data.data; + } invariant(this._method, 'Request method needs to be defined.'); invariant(this._url, 'Request URL needs to be defined.'); diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 079aa6ecae20e6..e6bcb04d844540 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -13,6 +13,7 @@ const NativeEventEmitter = require('NativeEventEmitter'); const Blob = require('Blob'); +const BlobManager = require('BlobManager'); const Platform = require('Platform'); const RCTWebSocketModule = require('NativeModules').WebSocketModule; const WebSocketEvent = require('WebSocketEvent'); @@ -138,7 +139,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { } if (data instanceof Blob) { - RCTWebSocketModule.sendBlob(data, this._socketId); + RCTWebSocketModule.sendBlob(data.data, this._socketId); return; } @@ -198,7 +199,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { data = base64.toByteArray(ev.data).buffer; break; case 'blob': - data = Blob.create(ev.data); + data = BlobManager.createFromOptions(ev.data); break; } this.dispatchEvent(new WebSocketEvent('message', { data })); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index bb8820234ef9ab..ce7cb53f42265f 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -70,6 +70,7 @@ const ReactNative = { get AsyncStorage() { return require('AsyncStorage'); }, get BackAndroid() { return require('BackAndroid'); }, // deprecated: use BackHandler instead get BackHandler() { return require('BackHandler'); }, + get BlobManager() { return require('BlobManager'); }, get CameraRoll() { return require('CameraRoll'); }, get Clipboard() { return require('Clipboard'); }, get DatePickerAndroid() { return require('DatePickerAndroid'); }, From 22ebafbcb13b2ee9e46fe57a0f55d6820972bbfa Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 16 Dec 2016 19:30:57 +0530 Subject: [PATCH 06/66] Add a basic implementation for FileReader on Android --- Libraries/Blob/BlobManager.js | 3 + Libraries/Blob/FileReader.js | 159 ++++++++++++++++++ Libraries/Core/InitializeCore.js | 1 + .../react/modules/blob/BlobModule.java | 2 +- .../react/modules/blob/FileReaderModule.java | 82 +++++++++ .../react/shell/MainReactPackage.java | 7 + 6 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 Libraries/Blob/FileReader.js create mode 100644 ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 1ff66ec599c84c..637f24233db0ac 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -56,6 +56,9 @@ class BlobManager { */ static async createFromURI(uri: string, options?: { type: string }): Promise { const blob = await BlobModule.createFromURI(uri); + if (options && typeof options.type === 'string') { + blob.type = options.type; + } return Object.assign(Object.create(File.prototype), { data: blob }); } diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js new file mode 100644 index 00000000000000..3f11426df7f503 --- /dev/null +++ b/Libraries/Blob/FileReader.js @@ -0,0 +1,159 @@ +/** + * 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 FileReader + * @flow + */ + +'use strict'; + +const EventTarget = require('event-target-shim'); +const Platform = require('Platform'); +const Blob = require('Blob'); +const { FileReaderModule } = require('react-native').NativeModules; + +type ReadyState = + | 0 // EMPTY + | 1 // LOADING + | 2 // DONE + +type ReaderResult = string | ArrayBuffer; + +const READER_EVENTS = [ + 'abort', + 'error', + 'load', + 'loadstart', + 'loadend', + 'progress', +]; + +const EMPTY = 0; +const LOADING = 1; +const DONE = 2; + +class FileReader extends EventTarget(...READER_EVENTS) { + + static EMPTY = EMPTY; + static LOADING = LOADING; + static DONE = DONE; + + EMPTY = EMPTY; + LOADING = LOADING; + DONE = DONE; + + _readyState: ReadyState; + _error: ?Error; + _result: ?ReaderResult; + _aborted: boolean = false; + _subscriptions: Array<*> = []; + + constructor() { + super(); + this._reset(); + } + + _reset(): void { + this._readyState = EMPTY; + this._error = null; + this._result = null; + } + + _clearSubscriptions(): void { + this._subscriptions.forEach(sub => sub.remove()); + this._subscriptions = []; + } + + _setReadyState(newState: ReadyState) { + this._readyState = newState; + this.dispatchEvent({ type: 'readystatechange' }); + if (newState === DONE) { + if (this._aborted) { + this.dispatchEvent({ type: 'abort' }); + } else if (this._error) { + this.dispatchEvent({ type: 'error' }); + } else { + this.dispatchEvent({ type: 'load' }); + } + this.dispatchEvent({ type: 'loadend' }); + } + } + + readAsArrayBuffer() { + throw new Error('FileReader.readAsArrayBuffer is not implemented'); + } + + readAsDataURL(blob: Blob) { + if (Platform.OS === 'ios') { + throw new Error('FileReader.readAsDataURL is not implemented on iOS'); + } + + this._aborted = false; + + FileReaderModule.readAsDataURL(blob.data).then((text: string) => { + if (this._aborted) { + return; + } + this._result = text; + this._setReadyState(DONE); + }, error => { + if (this._aborted) { + return; + } + this._error = error; + this._setReadyState(DONE); + }); + } + + readAsText(blob: Blob, encoding: string = 'UTF-8') { + if (Platform.OS === 'ios') { + throw new Error('FileReader.readAsText is not implemented on iOS'); + } + + this._aborted = false; + + FileReaderModule.readAsText(blob.data, encoding).then((text: string) => { + if (this._aborted) { + return; + } + this._result = text; + this._setReadyState(DONE); + }, error => { + if (this._aborted) { + return; + } + this._error = error; + this._setReadyState(DONE); + }); + } + + abort() { + this._aborted = true; + // only call onreadystatechange if there is something to abort, as per spec + if (this._readyState !== EMPTY && this._readyState !== DONE) { + this._reset(); + this._setReadyState(DONE); + } + // Reset again after, in case modified in handler + this._reset(); + } + + get readyState(): ReadyState { + return this._readyState; + } + + get error(): ?Error { + return this._error; + } + + get result(): ?ReaderResult { + return this._result; + } +} + +module.exports = FileReader; diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index cb09ae4e7e0c09..281e083d39a6b1 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -191,6 +191,7 @@ defineProperty(global, 'Response', () => require('fetch').Response); defineProperty(global, 'WebSocket', () => require('WebSocket')); defineProperty(global, 'Blob', () => require('Blob')); defineProperty(global, 'File', () => require('File')); +defineProperty(global, 'FileReader', () => require('FileReader')); defineProperty(global, 'URL', () => require('URL')); // Set up Geolocation diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index f65a95cb2517f2..f29505ed96dce9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -166,8 +166,8 @@ public void createFromURI(String path, Promise promise) { try { Uri uri = Uri.parse(path); ContentResolver resolver = getReactApplicationContext().getContentResolver(); - String type = resolver.getType(uri); + if (type != null) { String ext = MimeTypeMap.getFileExtensionFromUrl(path); if (ext != null) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java new file mode 100644 index 00000000000000..23d433ff6dd72c --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java @@ -0,0 +1,82 @@ +package com.facebook.react.modules.blob; + +/** + * 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 android.util.Base64; +import com.facebook.react.bridge.*; +import com.facebook.react.module.annotations.ReactModule; + + +@ReactModule(name = "FileReaderModule") +public class FileReaderModule extends ReactContextBaseJavaModule { + + private static final String ERROR_INVALID_BLOB = "ERROR_INVALID_BLOB"; + + public FileReaderModule(ReactApplicationContext reactContext) { + super(reactContext); + } + + @Override + public String getName() { + return "FileReaderModule"; + } + + @ReactMethod + public void readAsText(ReadableMap blob, String encoding, Promise promise) { + byte[] bytes = BlobModule.resolve( + blob.getString("blobId"), + blob.getInt("offset"), + blob.getInt("size")); + + if (bytes == null) { + promise.reject(ERROR_INVALID_BLOB, "The specified blob is invalid"); + return; + } + + try { + promise.resolve(new String(bytes, encoding)); + } catch (Exception e) { + promise.reject(e); + } + } + + @ReactMethod + public void readAsDataURL(ReadableMap blob, Promise promise) { + byte[] bytes = BlobModule.resolve( + blob.getString("blobId"), + blob.getInt("offset"), + blob.getInt("size")); + + if (bytes == null) { + promise.reject(ERROR_INVALID_BLOB, "The specified blob is invalid"); + return; + } + + try { + StringBuilder sb = new StringBuilder(); + sb.append("data:"); + + if (blob.hasKey("type") && !blob.getString("type").isEmpty()) { + sb.append(blob.getString("type")); + } else { + sb.append("application/octet-stream"); + } + + sb.append(";bas64,"); + sb.append(Base64.encodeToString(bytes, Base64.NO_WRAP)); + + promise.resolve(sb.toString()); + } catch (Exception e) { + promise.reject(e); + } + } +} + diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java index 54c901ef2be5f4..f7fb6a8213a99f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java @@ -31,6 +31,7 @@ import com.facebook.react.modules.accessibilityinfo.AccessibilityInfoModule; import com.facebook.react.modules.appstate.AppStateModule; import com.facebook.react.modules.blob.BlobModule; +import com.facebook.react.modules.blob.FileReaderModule; import com.facebook.react.modules.camera.CameraRollManager; import com.facebook.react.modules.camera.ImageEditingManager; import com.facebook.react.modules.camera.ImageStoreManager; @@ -120,6 +121,12 @@ public NativeModule get() { return new BlobModule(context); } }), + new ModuleSpec(FileReaderModule.class, new Provider() { + @Override + public NativeModule get() { + return new FileReaderModule(context); + } + }), new ModuleSpec(AsyncStorageModule.class, new Provider() { @Override public NativeModule get() { From 781e9e6a1d8ea0b263ad34e909078af8d76d257f Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Mon, 19 Dec 2016 14:21:00 +0530 Subject: [PATCH 07/66] Fix getting mime type --- .../java/com/facebook/react/modules/blob/BlobModule.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index f29505ed96dce9..53256267066d2a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -168,13 +168,17 @@ public void createFromURI(String path, Promise promise) { ContentResolver resolver = getReactApplicationContext().getContentResolver(); String type = resolver.getType(uri); - if (type != null) { + if (type == null) { String ext = MimeTypeMap.getFileExtensionFromUrl(path); if (ext != null) { type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext); } } + if (type == null) { + type = ""; + } + InputStream is = resolver.openInputStream(uri); byte[] data = getBytes(is); From 109a465e8d25699f553a7f23de45e45bc64b8135 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Tue, 20 Dec 2016 19:38:36 +0530 Subject: [PATCH 08/66] Add unit tests for Blob and File --- Libraries/Blob/Blob.js | 6 +- Libraries/Blob/BlobManager.js | 7 ++- Libraries/Blob/BlobTypes.js | 6 ++ Libraries/Blob/FileReader.js | 2 +- Libraries/Blob/__mocks__/BlobModule.js | 18 ++++++ Libraries/Blob/__mocks__/FileReaderModule.js | 12 ++++ Libraries/Blob/__tests__/Blob-test.js | 58 ++++++++++++++++++++ Libraries/Blob/__tests__/BlobManager-test.js | 33 +++++++++++ Libraries/Blob/__tests__/File-test.js | 35 ++++++++++++ Libraries/Blob/__tests__/FileReader-test.js | 42 ++++++++++++++ 10 files changed, 212 insertions(+), 7 deletions(-) create mode 100644 Libraries/Blob/__mocks__/BlobModule.js create mode 100644 Libraries/Blob/__mocks__/FileReaderModule.js create mode 100644 Libraries/Blob/__tests__/Blob-test.js create mode 100644 Libraries/Blob/__tests__/BlobManager-test.js create mode 100644 Libraries/Blob/__tests__/File-test.js create mode 100644 Libraries/Blob/__tests__/FileReader-test.js diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index f8ef28a451932d..38fc57e4767171 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -12,7 +12,7 @@ 'use strict'; -import type { BlobData } from './BlobTypes'; +import type { BlobData, BlobOptions } from './BlobTypes'; /** * Opaque JS representation of some binary data in native. @@ -59,9 +59,9 @@ class Blob { * Currently we only support creating Blobs from other Blobs. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob */ - constructor(parts: Array = []) { + constructor(parts: Array = [], options: BlobOptions) { const BlobManager = require('BlobManager'); - return BlobManager.createFromParts(parts); + this.data = BlobManager.createFromParts(parts, options).data; } /* diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 637f24233db0ac..2ac961d4b8172e 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -16,9 +16,9 @@ const uuid = require('uuid'); const invariant = require('fbjs/lib/invariant'); const Blob = require('Blob'); const File = require('File'); -const { BlobModule } = require('react-native').NativeModules; +const { BlobModule } = require('NativeModules'); -import type { BlobData } from './BlobTypes'; +import type { BlobData, BlobOptions } from './BlobTypes'; /** * Module to manage blobs @@ -28,7 +28,7 @@ class BlobManager { /** * Create blob from existing array of blobs. */ - static createFromParts(parts: Array): Blob { + static createFromParts(parts: Array, options: BlobOptions): Blob { let blobId = uuid.v4(); let size = 0; parts.forEach((part) => { @@ -40,6 +40,7 @@ class BlobManager { blobId, offset: 0, size, + type: options ? options.type : '', }); } diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js index 4c5c9965fa2e9b..98a1a60b9e6aed 100644 --- a/Libraries/Blob/BlobTypes.js +++ b/Libraries/Blob/BlobTypes.js @@ -24,3 +24,9 @@ export type BlobData = { name?: string; lastModified?: number; }; + + +export type BlobOptions = { + type: string; + endings: "transparent" | "native"; +} diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js index 3f11426df7f503..ac7ba5f9fed925 100644 --- a/Libraries/Blob/FileReader.js +++ b/Libraries/Blob/FileReader.js @@ -15,7 +15,7 @@ const EventTarget = require('event-target-shim'); const Platform = require('Platform'); const Blob = require('Blob'); -const { FileReaderModule } = require('react-native').NativeModules; +const { FileReaderModule } = require('NativeModules'); type ReadyState = | 0 // EMPTY diff --git a/Libraries/Blob/__mocks__/BlobModule.js b/Libraries/Blob/__mocks__/BlobModule.js new file mode 100644 index 00000000000000..4416caec11dbdc --- /dev/null +++ b/Libraries/Blob/__mocks__/BlobModule.js @@ -0,0 +1,18 @@ +/* @flow */ + +const BlobModule = { + createFromParts() {}, + async createFromURI() { + return { + blobId: 'c6cec908-c69e-11e6-9d9d-cec0c932ce01', + offset: 0, + size: 34254, + type: 'image/png', + name: 'image.png', + lastModified: 1482229709578, + }; + }, + release() {} +}; + +module.exports = BlobModule; diff --git a/Libraries/Blob/__mocks__/FileReaderModule.js b/Libraries/Blob/__mocks__/FileReaderModule.js new file mode 100644 index 00000000000000..a97b84a21bbed5 --- /dev/null +++ b/Libraries/Blob/__mocks__/FileReaderModule.js @@ -0,0 +1,12 @@ +/* @flow */ + +const FileReaderModule = { + async readAsText() { + return ''; + }, + async readAsDataURL() { + return 'data:text/plain;base64,NDI='; + }, +}; + +module.exports = FileReaderModule; diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js new file mode 100644 index 00000000000000..0b57e3303585bc --- /dev/null +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -0,0 +1,58 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + */ +'use strict'; + +jest + .unmock('Blob') + .unmock('BlobManager') + .unmock('../__mocks__/BlobModule') + .setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), + }); + +var Blob = require('Blob'); + +describe('Blob', function() { + + it('should create empty blob', () => { + const blob = new Blob(); + expect(blob).toBeInstanceOf(Blob); + expect(blob.data.offset).toBe(0); + expect(blob.data.size).toBe(0); + expect(blob.size).toBe(0); + expect(blob.type).toBe(''); + }); + + it('should create blob from other blobs', () => { + const blobA = new Blob(); + const blobB = new Blob(); + + blobA.data.size = 34546; + blobB.data.size = 65453; + + const blob = new Blob([ blobA, blobB ]); + + expect(blob.size).toBe(99999); + expect(blob.type).toBe(''); + }); + + it('should slice a blob', () => { + const blob = new Blob(); + + blob.data.size = 34546; + + const sliceA = blob.slice(0, 2354); + + expect(sliceA.data.offset).toBe(0); + expect(sliceA.size).toBe(2354); + expect(sliceA.type).toBe(''); + + const sliceB = blob.slice(2384, 7621); + + expect(sliceB.data.offset).toBe(2384); + expect(sliceB.size).toBe(7621 - 2384); + expect(sliceB.type).toBe(''); + }); + +}); diff --git a/Libraries/Blob/__tests__/BlobManager-test.js b/Libraries/Blob/__tests__/BlobManager-test.js new file mode 100644 index 00000000000000..6ffdd0f111b8dc --- /dev/null +++ b/Libraries/Blob/__tests__/BlobManager-test.js @@ -0,0 +1,33 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + */ +'use strict'; + +jest + .unmock('File') + .unmock('Blob') + .unmock('BlobManager') + .unmock('../__mocks__/BlobModule') + .setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), + }); + +var Blob = require('Blob'); +var File = require('File'); +var BlobManager = require('BlobManager'); + +describe('BlobManager', function() { + + it('should create blob from parts', () => { + const blob = BlobManager.createFromParts([], { type: 'text/html' }); + expect(blob).toBeInstanceOf(Blob); + expect(blob.type).toBe('text/html'); + }); + + it('should create file from uri', async () => { + const file = await BlobManager.createFromURI('file://path/to/a/file', { type: 'text/css' }); + expect(file).toBeInstanceOf(File); + expect(file.type).toBe('text/css'); + }); + +}); diff --git a/Libraries/Blob/__tests__/File-test.js b/Libraries/Blob/__tests__/File-test.js new file mode 100644 index 00000000000000..8695d73cd9f0c9 --- /dev/null +++ b/Libraries/Blob/__tests__/File-test.js @@ -0,0 +1,35 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + */ +'use strict'; + +jest + .unmock('File') + .unmock('Blob') + .unmock('BlobManager') + .unmock('../__mocks__/BlobModule') + .setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), + }); + +var File = require('File'); + +describe('File', function() { + + it('should create empty file', () => { + const file = new File(); + expect(file).toBeInstanceOf(File); + expect(file.data.offset).toBe(0); + expect(file.data.size).toBe(0); + expect(file.size).toBe(0); + expect(file.type).toBe(''); + expect(file.name).toBe(''); + expect(file.lastModified).toBe(0); + }); + + it('should create empty file with type', () => { + const file = new File([], { type: 'image/jpeg' }); + expect(file.type).toBe('image/jpeg'); + }); + +}); diff --git a/Libraries/Blob/__tests__/FileReader-test.js b/Libraries/Blob/__tests__/FileReader-test.js new file mode 100644 index 00000000000000..f032242da95172 --- /dev/null +++ b/Libraries/Blob/__tests__/FileReader-test.js @@ -0,0 +1,42 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + */ +'use strict'; + +jest + .disableAutomock() + .unmock('event-target-shim') + .setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), + FileReaderModule: require('../__mocks__/FileReaderModule'), + }) + .setMock('Platform', { + OS: 'android' // remove when iOS is implemented + }); + +var Blob = require('Blob'); +var FileReader = require('FileReader'); + +describe('FileReader', function() { + + it('should read blob as text', async () => { + const e = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = resolve; + reader.onerror = reject; + reader.readAsText(new Blob()); + }); + expect(e.target.result).toBe(''); + }); + + it('should read blob as data URL', async () => { + const e = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = resolve; + reader.onerror = reject; + reader.readAsDataURL(new Blob()); + }); + expect(e.target.result).toBe('data:text/plain;base64,NDI='); + }); + +}); From 274662874447cb57efbfa5d727b93e9572ca9a9f Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 21 Dec 2016 07:00:52 +0530 Subject: [PATCH 09/66] Implement creating blob from string --- Libraries/Blob/BlobManager.js | 30 +++++- Libraries/Blob/__tests__/Blob-test.js | 8 +- .../react/modules/blob/BlobModule.java | 96 +++++++++++-------- 3 files changed, 85 insertions(+), 49 deletions(-) diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 2ac961d4b8172e..879d3260c7a65d 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -13,13 +13,18 @@ 'use strict'; const uuid = require('uuid'); -const invariant = require('fbjs/lib/invariant'); const Blob = require('Blob'); const File = require('File'); const { BlobModule } = require('NativeModules'); import type { BlobData, BlobOptions } from './BlobTypes'; +function countUTF8Bytes(s: string){ + let b = 0; + for (let i = 0, c; c = s.charCodeAt(i++); b += c >> 11 ? 3 : c >> 7 ? 2 : 1) {} + return b; +} + /** * Module to manage blobs */ @@ -28,14 +33,29 @@ class BlobManager { /** * Create blob from existing array of blobs. */ - static createFromParts(parts: Array, options: BlobOptions): Blob { + static createFromParts(parts: Array, options: BlobOptions): Blob { let blobId = uuid.v4(); let size = 0; parts.forEach((part) => { - invariant(part instanceof Blob, 'Can currently only create a Blob from other Blobs'); - size += part.size; + if (typeof part === 'string') { + size += countUTF8Bytes(part); + } else if (part instanceof Blob) { + size += part.size; + } else { + throw new Error('Can currently only create a Blob from other Blobs or strings'); + } }); - BlobModule.createFromParts(parts, blobId); + BlobModule.createFromParts(parts.map(part => { + let type, data; + if (part instanceof Blob) { + type = 'blob'; + data = part.data; + } else { + type = typeof part; + data = part; + } + return { type, data }; + }), blobId); return BlobManager.createFromOptions({ blobId, offset: 0, diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 0b57e3303585bc..5014fcacd55b79 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -24,14 +24,14 @@ describe('Blob', function() { expect(blob.type).toBe(''); }); - it('should create blob from other blobs', () => { + it('should create blob from other blobs and strings', () => { const blobA = new Blob(); const blobB = new Blob(); - blobA.data.size = 34546; - blobB.data.size = 65453; + blobA.data.size = 34540; + blobB.data.size = 65452; - const blob = new Blob([ blobA, blobB ]); + const blob = new Blob([ blobA, blobB, 'i ♥ u' ]); expect(blob.size).toBe(99999); expect(blob.type).toBe(''); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 53256267066d2a..b6dd7edb013514 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -12,21 +12,15 @@ import android.content.res.Resources; import android.net.Uri; import android.support.annotation.Nullable; - -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContextBaseJavaModule; -import com.facebook.react.bridge.ReactMethod; -import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.bridge.ReadableMap; +import android.webkit.MimeTypeMap; +import com.facebook.react.bridge.*; import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; +import java.io.*; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.nio.charset.Charset; +import java.util.*; @ReactModule(name = "BlobModule") public class BlobModule extends ReactContextBaseJavaModule { @@ -59,16 +53,16 @@ public Map getConstants() { private static Map sBlobs = new HashMap<>(); + private static void store(byte[] data, String blobId) { + sBlobs.put(blobId, data); + } + public static String store(byte[] data) { String blobId = UUID.randomUUID().toString(); store(data, blobId); return blobId; } - public static void store(byte[] data, String blobId) { - sBlobs.put(blobId, data); - } - public static void remove(String blobId) { sBlobs.remove(blobId); } @@ -109,12 +103,19 @@ public static byte[] resolve(ReadableMap blob) { return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); } - private static byte[] getBytes(InputStream inputStream) throws IOException { + private byte[] getBytesFromUri(Uri contentUri) throws IOException { + ContentResolver resolver = getReactApplicationContext().getContentResolver(); + InputStream is = resolver.openInputStream(contentUri); + + if (is == null) { + throw new FileNotFoundException("File not found for " + contentUri); + } + ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); int bufferSize = 1024; byte[] buffer = new byte[bufferSize]; - int len = 0; - while ((len = inputStream.read(buffer)) != -1) { + int len; + while ((len = is.read(buffer)) != -1) { byteBuffer.write(buffer, 0, len); } return byteBuffer.toByteArray(); @@ -145,18 +146,48 @@ private long getLastModifiedFromUri(Uri contentUri) { return 0; } + private String getMimeTypeFromUri(Uri contentUri) { + ContentResolver resolver = getReactApplicationContext().getContentResolver(); + String type = resolver.getType(contentUri); + + if (type == null) { + String ext = MimeTypeMap.getFileExtensionFromUrl(contentUri.getPath()); + if (ext != null) { + type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext); + } + } + + if (type == null) { + type = ""; + } + + return type; + } + @ReactMethod public void createFromParts(ReadableArray parts, String blobId) { int totalBlobSize = 0; - ArrayList partList = new ArrayList<>(parts.size()); + ArrayList partList = new ArrayList<>(parts.size()); for (int i = 0; i < parts.size(); i++) { ReadableMap part = parts.getMap(i); - totalBlobSize += part.getInt("size"); - partList.add(i, part); + switch (part.getString("type")) { + case "blob": + ReadableMap blob = part.getMap("data"); + totalBlobSize += blob.getInt("size"); + partList.add(i, resolve(blob)); + break; + case "string": + byte[] bytes = part.getString("data").getBytes(Charset.forName("UTF-8")); + totalBlobSize += bytes.length; + partList.add(i, bytes); + break; + default: + throw new IllegalArgumentException("Invalid type for blob: " + part.getString("type")); + } } ByteBuffer buffer = ByteBuffer.allocate(totalBlobSize); - for (ReadableMap part : partList) { - buffer.put(resolve(part)); + for (byte[] bytes : partList) { + buffer.put(bytes); } store(buffer.array(), blobId); } @@ -165,28 +196,13 @@ public void createFromParts(ReadableArray parts, String blobId) { public void createFromURI(String path, Promise promise) { try { Uri uri = Uri.parse(path); - ContentResolver resolver = getReactApplicationContext().getContentResolver(); - String type = resolver.getType(uri); - - if (type == null) { - String ext = MimeTypeMap.getFileExtensionFromUrl(path); - if (ext != null) { - type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext); - } - } - - if (type == null) { - type = ""; - } - - InputStream is = resolver.openInputStream(uri); - byte[] data = getBytes(is); + byte[] data = getBytesFromUri(uri); WritableMap blob = Arguments.createMap(); blob.putString("blobId", store(data)); blob.putInt("offset", 0); blob.putInt("size", data.length); - blob.putString("type", type); + blob.putString("type", getMimeTypeFromUri(uri)); // Needed for files blob.putString("name", getNameFromUri(uri)); From a60605d60515d06aad2fe0f8e4644a81a10e4ac6 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 21 Dec 2016 07:02:17 +0530 Subject: [PATCH 10/66] Add tests for blob module --- .../test/java/com/facebook/react/modules/BUCK | 75 ++++---- .../react/modules/blob/BlobModuleTest.java | 180 ++++++++++++++++++ 2 files changed, 218 insertions(+), 37 deletions(-) create mode 100644 ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK index 50603b90a9cbf3..59153daa97bf38 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK @@ -1,41 +1,42 @@ include_defs("//ReactAndroid/DEFS") rn_robolectric_test( - name = "modules", - srcs = glob(["**/*.java"]), - # Please change the contact to the oncall of your team - contacts = ["oncall+fbandroid_sheriff@xmail.facebook.com"], - visibility = [ - "PUBLIC", - ], - deps = [ - YOGA_TARGET, - react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"), - react_native_dep("third-party/java/fest:fest"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_dep("third-party/java/junit:junit"), - react_native_dep("third-party/java/mockito:mockito"), - react_native_dep("third-party/java/okhttp:okhttp3"), - react_native_dep("third-party/java/okio:okio"), - react_native_dep("third-party/java/robolectric3/robolectric:robolectric"), - react_native_target("java/com/facebook/react:react"), - react_native_target("java/com/facebook/react/animation:animation"), - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/common/network:network"), - react_native_target("java/com/facebook/react/devsupport:interfaces"), - react_native_target("java/com/facebook/react/jstasks:jstasks"), - react_native_target("java/com/facebook/react/modules/clipboard:clipboard"), - react_native_target("java/com/facebook/react/modules/common:common"), - react_native_target("java/com/facebook/react/modules/core:core"), - react_native_target("java/com/facebook/react/modules/debug:debug"), - react_native_target("java/com/facebook/react/modules/dialog:dialog"), - react_native_target("java/com/facebook/react/modules/network:network"), - react_native_target("java/com/facebook/react/modules/share:share"), - react_native_target("java/com/facebook/react/modules/storage:storage"), - react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo"), - react_native_target("java/com/facebook/react/touch:touch"), - react_native_target("java/com/facebook/react/uimanager:uimanager"), - react_native_tests_target("java/com/facebook/react/bridge:testhelpers"), - ], + # Please change the contact to the oncall of your team + contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'], + name = 'modules', + srcs = glob(['**/*.java']), + deps = [ + YOGA_TARGET, + react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'), + react_native_dep('third-party/java/fest:fest'), + react_native_dep('third-party/java/jsr-305:jsr-305'), + react_native_dep('third-party/java/junit:junit'), + react_native_dep('third-party/java/mockito:mockito'), + react_native_dep('third-party/java/okhttp:okhttp3'), + react_native_dep('third-party/java/okio:okio'), + react_native_dep('third-party/java/robolectric3/robolectric:robolectric'), + react_native_target('java/com/facebook/react/animation:animation'), + react_native_target('java/com/facebook/react/bridge:bridge'), + react_native_target('java/com/facebook/react/common/network:network'), + react_native_target('java/com/facebook/react/common:common'), + react_native_target('java/com/facebook/react/devsupport:devsupport'), + react_native_target('java/com/facebook/react/jstasks:jstasks'), + react_native_target('java/com/facebook/react/modules/blob:blob'), + react_native_target('java/com/facebook/react/modules/clipboard:clipboard'), + react_native_target('java/com/facebook/react/modules/common:common'), + react_native_target('java/com/facebook/react/modules/core:core'), + react_native_target('java/com/facebook/react/modules/debug:debug'), + react_native_target('java/com/facebook/react/modules/dialog:dialog'), + react_native_target('java/com/facebook/react/modules/network:network'), + react_native_target('java/com/facebook/react/modules/share:share'), + react_native_target('java/com/facebook/react/modules/storage:storage'), + react_native_target('java/com/facebook/react/modules/systeminfo:systeminfo'), + react_native_target('java/com/facebook/react/touch:touch'), + react_native_target('java/com/facebook/react/uimanager:uimanager'), + react_native_target('java/com/facebook/react:react'), + react_native_tests_target('java/com/facebook/react/bridge:testhelpers'), + ], + visibility = [ + 'PUBLIC' + ], ) diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java new file mode 100644 index 00000000000000..cb6e4e4e87ce87 --- /dev/null +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java @@ -0,0 +1,180 @@ +/** + * 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. + */ + +package com.facebook.react.modules.blob; + +import android.net.Uri; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactTestHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.rule.PowerMockRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import javax.annotation.Nullable; +import java.util.Random; + +import static org.junit.Assert.*; + +@PrepareForTest({Arguments.class}) +@RunWith(RobolectricTestRunner.class) +@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) +@Config(manifest = Config.NONE) +public class BlobModuleTest { + + private byte[] bytes; + private String blobId; + private BlobModule blobModule; + + @Rule + public PowerMockRule rule = new PowerMockRule(); + + @Before + public void prepareModules() throws Exception { + PowerMockito.mockStatic(Arguments.class); + Mockito.when(Arguments.createMap()).thenAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + return new JavaOnlyMap(); + } + }); + + bytes = new byte[120]; + new Random().nextBytes(bytes); + blobId = BlobModule.store(bytes); + blobModule = new BlobModule(ReactTestHelper.createCatalystContextForTest()); + + BlobModule spy = PowerMockito.spy(blobModule); + + PowerMockito.when(spy, "getBytesFromUri", Uri.class).thenReturn(bytes); + PowerMockito.when(spy, "getNameFromUri", Uri.class).thenReturn("test.png"); + PowerMockito.when(spy, "getLastModifiedFromUri", Uri.class).thenReturn(1482276506); + PowerMockito.when(spy, "getMimeTypeFromUri", Uri.class).thenReturn("image/png"); + } + + @After + public void cleanUp() { + BlobModule.remove(blobId); + } + + @Test + public void testResolve() { + assertArrayEquals(bytes, BlobModule.resolve(blobId, 0, bytes.length)); + assertArrayEquals(bytes, BlobModule.resolve(blobId, 30, bytes.length - 30)); + } + + @Test + public void testResolveUri() { + Uri uri = new Uri.Builder() + .appendPath(blobId) + .appendQueryParameter("offset", "0") + .appendQueryParameter("size", String.valueOf(bytes.length)) + .build(); + + assertArrayEquals(bytes, BlobModule.resolve(uri)); + } + + @Test + public void testResolveMap() { + JavaOnlyMap blob = new JavaOnlyMap(); + blob.putString("blobId", blobId); + blob.putInt("offset", 0); + blob.putInt("size", bytes.length); + + assertArrayEquals(bytes, BlobModule.resolve(blob)); + } + + @Test + public void testRemove() { + assertNotNull(BlobModule.resolve(blobId, 0, bytes.length)); + + BlobModule.remove(blobId); + + assertNull(BlobModule.resolve(blobId, 0, bytes.length)); + } + + @Test + public void testCreateFromParts() { + JavaOnlyMap blob = new JavaOnlyMap(); + blob.putString("blobId", blobId); + blob.putInt("offset", 0); + blob.putInt("size", bytes.length); + + assertArrayEquals(bytes, BlobModule.resolve(blob)); + } + + @Test + public void testCreateFromURI() { + final SimplePromise promise = new SimplePromise(); + + blobModule.createFromURI("content://photos/holiday-season", promise); + + JavaOnlyMap map = (JavaOnlyMap) promise.getValue(); + + assertNotNull(map.getString("blobId")); + assertEquals(map.getInt("offset"), 0); + assertEquals(map.getInt("size"), bytes.length); + assertEquals(map.getString("type"), "image/png"); + assertEquals(map.getString("name"), "test"); + assertEquals(map.getInt("lastModified"), 1482276506); + } + + @Test + public void testRelease() { + assertNotNull(BlobModule.resolve(blobId, 0, bytes.length)); + + blobModule.release(blobId); + + assertNull(BlobModule.resolve(blobId, 0, bytes.length)); + } + + final static class SimplePromise implements Promise { + private Object mValue; + + public Object getValue() { + return mValue; + } + + @Override + public void resolve(Object value) { + mValue = value; + } + + @Override + public void reject(String code, String message) { + reject(code, message, /*Throwable*/null); + } + + @Override + @Deprecated + public void reject(String message) {} + + @Override + public void reject(String code, Throwable e) {} + + @Override + public void reject(Throwable e) {} + + @Override + public void reject(String code, String message, @Nullable Throwable e) {} + } + +} From d4b62b9616a5ad493980b2dd4861e5d19b3e076e Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 21 Dec 2016 15:44:17 +0530 Subject: [PATCH 11/66] Cast blob parts to string --- Libraries/Blob/Blob.js | 2 +- Libraries/Blob/BlobManager.js | 59 ++++++++++++++++++++++------------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 38fc57e4767171..37a4c65a386b01 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -59,7 +59,7 @@ class Blob { * Currently we only support creating Blobs from other Blobs. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob */ - constructor(parts: Array = [], options: BlobOptions) { + constructor(parts: Array = [], options: BlobOptions) { const BlobManager = require('BlobManager'); this.data = BlobManager.createFromParts(parts, options).data; } diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 879d3260c7a65d..57ecbaa08e785c 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -18,11 +18,21 @@ const File = require('File'); const { BlobModule } = require('NativeModules'); import type { BlobData, BlobOptions } from './BlobTypes'; +import {map} from 'async'; -function countUTF8Bytes(s: string){ - let b = 0; - for (let i = 0, c; c = s.charCodeAt(i++); b += c >> 11 ? 3 : c >> 7 ? 2 : 1) {} - return b; +function countUTF8Bytes(text: string) { + let length = 0; + for (let i = 0; i < text.length; i++) { + const c = text.charCodeAt(i); + if (c < 128) { + length++; + } else if ((c > 127) && (c < 2048)) { + length += 2; + } else { + length += 3; + } + } + return length; } /** @@ -34,28 +44,33 @@ class BlobManager { * Create blob from existing array of blobs. */ static createFromParts(parts: Array, options: BlobOptions): Blob { - let blobId = uuid.v4(); - let size = 0; - parts.forEach((part) => { - if (typeof part === 'string') { - size += countUTF8Bytes(part); - } else if (part instanceof Blob) { - size += part.size; + const blobId = uuid.v4(); + const items = parts.map(part => { + if (part instanceof ArrayBuffer || global.ArrayBufferView && part instanceof global.ArrayBufferView) { + throw new Error('Creating blobs from \'ArrayBuffer\' and \'ArrayBufferView\' are not supported'); + } + if (part instanceof Blob) { + return { + data: part.data, + type: 'blob', + }; } else { - throw new Error('Can currently only create a Blob from other Blobs or strings'); + return { + data: String(part), + type: 'string', + }; } }); - BlobModule.createFromParts(parts.map(part => { - let type, data; - if (part instanceof Blob) { - type = 'blob'; - data = part.data; + const size = items.reduce((acc, curr) => { + if (curr.type === 'string') { + return acc + countUTF8Bytes(curr.data); } else { - type = typeof part; - data = part; + return acc + curr.data.size; } - return { type, data }; - }), blobId); + }, 0); + + BlobModule.createFromParts(items, blobId); + return BlobManager.createFromOptions({ blobId, offset: 0, @@ -77,9 +92,11 @@ class BlobManager { */ static async createFromURI(uri: string, options?: { type: string }): Promise { const blob = await BlobModule.createFromURI(uri); + if (options && typeof options.type === 'string') { blob.type = options.type; } + return Object.assign(Object.create(File.prototype), { data: blob }); } From 600217a57f04c939e2627cb39a62737b9e7332c2 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 21 Dec 2016 16:29:07 +0530 Subject: [PATCH 12/66] Fix counting bytes --- Libraries/Blob/BlobManager.js | 17 +---------------- Libraries/Blob/__tests__/Blob-test.js | 13 +++++++++++-- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 57ecbaa08e785c..f1aff7c2ab8531 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -20,21 +20,6 @@ const { BlobModule } = require('NativeModules'); import type { BlobData, BlobOptions } from './BlobTypes'; import {map} from 'async'; -function countUTF8Bytes(text: string) { - let length = 0; - for (let i = 0; i < text.length; i++) { - const c = text.charCodeAt(i); - if (c < 128) { - length++; - } else if ((c > 127) && (c < 2048)) { - length += 2; - } else { - length += 3; - } - } - return length; -} - /** * Module to manage blobs */ @@ -63,7 +48,7 @@ class BlobManager { }); const size = items.reduce((acc, curr) => { if (curr.type === 'string') { - return acc + countUTF8Bytes(curr.data); + return acc + global.unescape(encodeURI(curr.data)).length; } else { return acc + curr.data.size; } diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 5014fcacd55b79..dfc92b21c9cb43 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -27,13 +27,22 @@ describe('Blob', function() { it('should create blob from other blobs and strings', () => { const blobA = new Blob(); const blobB = new Blob(); + const textA = 'i ♥ dogs'; + const textB = '𐀀'; + const textC = 'Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘!͖̬̰̙̗̿̋ͥͥ̂ͣ̐́́͜͞'; blobA.data.size = 34540; blobB.data.size = 65452; - const blob = new Blob([ blobA, blobB, 'i ♥ u' ]); + const blob = new Blob([ blobA, blobB, textA, textB, textC ]); - expect(blob.size).toBe(99999); + expect(blob.size).toBe( + blobA.size + + blobB.size + + global.Buffer.byteLength(textA, 'UTF-8') + + global.Buffer.byteLength(textB, 'UTF-8') + + global.Buffer.byteLength(textC, 'UTF-8') + ); expect(blob.type).toBe(''); }); From b1614c10dbddbd6f776d396e86b0e87654228196 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Thu, 22 Dec 2016 13:35:46 +0530 Subject: [PATCH 13/66] Fix test for createFromParts --- .../react/modules/blob/BlobModuleTest.java | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java index cb6e4e4e87ce87..bef9cdb645d36b 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java @@ -10,10 +10,7 @@ package com.facebook.react.modules.blob; import android.net.Uri; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.JavaOnlyMap; -import com.facebook.react.bridge.Promise; -import com.facebook.react.bridge.ReactTestHelper; +import com.facebook.react.bridge.*; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -30,7 +27,10 @@ import org.robolectric.annotation.Config; import javax.annotation.Nullable; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.Random; +import java.util.UUID; import static org.junit.Assert.*; @@ -113,12 +113,42 @@ public void testRemove() { @Test public void testCreateFromParts() { + String id = UUID.randomUUID().toString(); + + JavaOnlyMap blobData = new JavaOnlyMap(); + blobData.putString("blobId", blobId); + blobData.putInt("offset", 0); + blobData.putInt("size", bytes.length); JavaOnlyMap blob = new JavaOnlyMap(); - blob.putString("blobId", blobId); + blob.putMap("data", blobData); + blob.putString("type", "blob"); + + String stringData = "i ♥ dogs"; + byte[] stringBytes = stringData.getBytes(Charset.forName("UTF-8")); + JavaOnlyMap string = new JavaOnlyMap(); + string.putString("data", stringData); + string.putString("type", "blob"); + + JavaOnlyArray parts = new JavaOnlyArray(); + parts.pushMap(blob); + parts.pushMap(string); + + blobModule.createFromParts(parts, id); + + JavaOnlyMap resultBlob = new JavaOnlyMap(); + resultBlob.putString("blobId", id); blob.putInt("offset", 0); blob.putInt("size", bytes.length); - assertArrayEquals(bytes, BlobModule.resolve(blob)); + int resultSize = bytes.length + stringBytes.length; + + byte[] result = BlobModule.resolve(id, 0, resultSize); + + ByteBuffer buffer = ByteBuffer.allocate(resultSize); + buffer.put(bytes); + buffer.put(stringBytes); + + assertArrayEquals(result, buffer.array()); } @Test From 8ad63693779405f15b819ebd1ebf6c1de29f6cb2 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Sun, 25 Dec 2016 19:55:57 +0530 Subject: [PATCH 14/66] Don't allow accessing data after blob is closed --- Libraries/Blob/Blob.js | 14 +++++++++++++- Libraries/Blob/__tests__/Blob-test.js | 8 ++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 37a4c65a386b01..3ba462c0ed4931 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -52,7 +52,7 @@ import type { BlobData, BlobOptions } from './BlobTypes'; * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob */ class Blob { - data: BlobData; + _data: ?BlobData; /** * Constructor for JS consumers. @@ -69,6 +69,17 @@ class Blob { * the data in the specified range of bytes of the source Blob. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice */ + set data(data: ?BlobData) { + this._data = data; + } + + get data(): BlobData { + if (this._data) { + return this._data; + } + throw new Error('Blob has been closed and is no longer available'); + } + slice(start?: number, end?: number): Blob { const BlobManager = require('BlobManager'); let { size, offset } = this.data; @@ -108,6 +119,7 @@ class Blob { close() { const BlobManager = require('BlobManager'); BlobManager.release(this.data.blobId); + this.data = null; } /** diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index dfc92b21c9cb43..d86b3c553b5483 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -64,4 +64,12 @@ describe('Blob', function() { expect(sliceB.type).toBe(''); }); + it('should close a blob', () => { + const blob = new Blob(); + + blob.close(); + + expect(() => blob.size).toThrow(); + }); + }); From 968a7b831bd45964bdbbb0578d6d2b2860677fe6 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Sun, 25 Dec 2016 21:04:27 +0530 Subject: [PATCH 15/66] Keep track of blobs and release when blobs are released --- Libraries/Blob/BlobManager.js | 17 ++++++++++++++- Libraries/Blob/BlobRegistry.js | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 Libraries/Blob/BlobRegistry.js diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index f1aff7c2ab8531..b22985afcd19a7 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -15,6 +15,7 @@ const uuid = require('uuid'); const Blob = require('Blob'); const File = require('File'); +const BlobRegistry = require('BlobRegistry'); const { BlobModule } = require('NativeModules'); import type { BlobData, BlobOptions } from './BlobTypes'; @@ -69,6 +70,7 @@ class BlobManager { * Used internally by modules like XHR, WebSocket, etc. */ static createFromOptions(options: BlobData): Blob { + BlobRegistry.register(options.blobId); return Object.assign(Object.create(Blob.prototype), { data: options }); } @@ -78,6 +80,8 @@ class BlobManager { static async createFromURI(uri: string, options?: { type: string }): Promise { const blob = await BlobModule.createFromURI(uri); + BlobRegistry.register(blob.data.blobId); + if (options && typeof options.type === 'string') { blob.type = options.type; } @@ -89,7 +93,18 @@ class BlobManager { * Deallocate resources for a blob. */ static release(blobId: string) { - return BlobModule.release(blobId); + BlobRegistry.unregister(blobId); + if (BlobRegistry.has(blobId)) { + return; + } + BlobModule.release(blobId); + } + + /** + * Deallocate resources for a all related blobs, including sliced ones. + */ + static releaseAll(blobId: string) { + BlobModule.release(blobId); } } diff --git a/Libraries/Blob/BlobRegistry.js b/Libraries/Blob/BlobRegistry.js new file mode 100644 index 00000000000000..fcebd769e45244 --- /dev/null +++ b/Libraries/Blob/BlobRegistry.js @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2013-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 BlobRegistry + * @flow + */ + +const registry: { [key: string]: number } = {}; + +const register = (id: string) => { + if (registry[id]) { + registry[id]++; + } else { + registry[id] = 1; + } +}; + +const unregister = (id: string) => { + if (registry[id]) { + registry[id]--; + if (registry[id] <= 0) { + delete registry[id]; + } + } +}; + +const has = (id: string) => { + return registry[id] && registry[id] > 0; +}; + +module.exports = { + register, + unregister, + has, +}; From 60f8ebbddb19b3750cf64c243a20d76a4e1d1a52 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Thu, 1 Jun 2017 21:01:26 +0530 Subject: [PATCH 16/66] Fix typo in BlobManager --- Libraries/Blob/BlobManager.js | 2 +- .../react/modules/blob/BlobModule.java | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index b22985afcd19a7..9b24ce2776a9ff 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -80,7 +80,7 @@ class BlobManager { static async createFromURI(uri: string, options?: { type: string }): Promise { const blob = await BlobModule.createFromURI(uri); - BlobRegistry.register(blob.data.blobId); + BlobRegistry.register(blob.blobId); if (options && typeof options.type === 'string') { blob.type = options.type; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index b6dd7edb013514..1aabae3015599f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -9,18 +9,37 @@ package com.facebook.react.modules.blob; +import android.content.ContentResolver; import android.content.res.Resources; +import android.database.Cursor; import android.net.Uri; +import android.provider.MediaStore; import android.support.annotation.Nullable; import android.webkit.MimeTypeMap; -import com.facebook.react.bridge.*; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableArray; +import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; @ReactModule(name = "BlobModule") public class BlobModule extends ReactContextBaseJavaModule { From f56c66be5f9cf8cb9689868d22effe9ab4cde85b Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 7 Jun 2017 05:28:31 +0530 Subject: [PATCH 17/66] Use fetch to retrive blob from URI --- Libraries/Blob/BlobManager.js | 24 --------- Libraries/Blob/__tests__/BlobManager-test.js | 7 --- .../react-native-implementation.js | 1 - .../react/modules/blob/BlobModule.java | 54 +++++++++---------- .../modules/network/NetworkingModule.java | 21 +++++++- 5 files changed, 44 insertions(+), 63 deletions(-) diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 9b24ce2776a9ff..071df713ac3eb2 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -14,12 +14,10 @@ const uuid = require('uuid'); const Blob = require('Blob'); -const File = require('File'); const BlobRegistry = require('BlobRegistry'); const { BlobModule } = require('NativeModules'); import type { BlobData, BlobOptions } from './BlobTypes'; -import {map} from 'async'; /** * Module to manage blobs @@ -74,21 +72,6 @@ class BlobManager { return Object.assign(Object.create(Blob.prototype), { data: options }); } - /** - * Create file instance from a local content URI - */ - static async createFromURI(uri: string, options?: { type: string }): Promise { - const blob = await BlobModule.createFromURI(uri); - - BlobRegistry.register(blob.blobId); - - if (options && typeof options.type === 'string') { - blob.type = options.type; - } - - return Object.assign(Object.create(File.prototype), { data: blob }); - } - /** * Deallocate resources for a blob. */ @@ -99,13 +82,6 @@ class BlobManager { } BlobModule.release(blobId); } - - /** - * Deallocate resources for a all related blobs, including sliced ones. - */ - static releaseAll(blobId: string) { - BlobModule.release(blobId); - } } module.exports = BlobManager; diff --git a/Libraries/Blob/__tests__/BlobManager-test.js b/Libraries/Blob/__tests__/BlobManager-test.js index 6ffdd0f111b8dc..e21ad2b1f6106a 100644 --- a/Libraries/Blob/__tests__/BlobManager-test.js +++ b/Libraries/Blob/__tests__/BlobManager-test.js @@ -13,7 +13,6 @@ jest }); var Blob = require('Blob'); -var File = require('File'); var BlobManager = require('BlobManager'); describe('BlobManager', function() { @@ -24,10 +23,4 @@ describe('BlobManager', function() { expect(blob.type).toBe('text/html'); }); - it('should create file from uri', async () => { - const file = await BlobManager.createFromURI('file://path/to/a/file', { type: 'text/css' }); - expect(file).toBeInstanceOf(File); - expect(file.type).toBe('text/css'); - }); - }); diff --git a/Libraries/react-native/react-native-implementation.js b/Libraries/react-native/react-native-implementation.js index ce7cb53f42265f..bb8820234ef9ab 100644 --- a/Libraries/react-native/react-native-implementation.js +++ b/Libraries/react-native/react-native-implementation.js @@ -70,7 +70,6 @@ const ReactNative = { get AsyncStorage() { return require('AsyncStorage'); }, get BackAndroid() { return require('BackAndroid'); }, // deprecated: use BackHandler instead get BackHandler() { return require('BackHandler'); }, - get BlobManager() { return require('BlobManager'); }, get CameraRoll() { return require('CameraRoll'); }, get Clipboard() { return require('Clipboard'); }, get DatePickerAndroid() { return require('DatePickerAndroid'); }, diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 1aabae3015599f..caa8f0a8ee93a4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -10,6 +10,7 @@ package com.facebook.react.modules.blob; import android.content.ContentResolver; +import android.content.Context; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; @@ -18,7 +19,6 @@ import android.webkit.MimeTypeMap; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; @@ -122,8 +122,25 @@ public static byte[] resolve(ReadableMap blob) { return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); } - private byte[] getBytesFromUri(Uri contentUri) throws IOException { - ContentResolver resolver = getReactApplicationContext().getContentResolver(); + public static WritableMap fetch(Uri uri, Context context) throws IOException { + ContentResolver resolver = context.getContentResolver(); + + byte[] data = getBytesFromUri(uri, resolver); + + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + blob.putString("type", getMimeTypeFromUri(uri, resolver)); + + // Needed for files + blob.putString("name", getNameFromUri(uri, resolver)); + blob.putDouble("lastModified", getLastModifiedFromUri(uri)); + + return blob; + } + + private static byte[] getBytesFromUri(Uri contentUri, ContentResolver resolver) throws IOException { InputStream is = resolver.openInputStream(contentUri); if (is == null) { @@ -140,12 +157,12 @@ private byte[] getBytesFromUri(Uri contentUri) throws IOException { return byteBuffer.toByteArray(); } - private String getNameFromUri(Uri contentUri) { + private static String getNameFromUri(Uri contentUri, ContentResolver resolver) { if (contentUri.getScheme().equals("file")) { return contentUri.getLastPathSegment(); } String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME}; - Cursor metaCursor = getReactApplicationContext().getContentResolver().query(contentUri, projection, null, null, null); + Cursor metaCursor = resolver.query(contentUri, projection, null, null, null); if (metaCursor != null) { try { if (metaCursor.moveToFirst()) { @@ -158,15 +175,14 @@ private String getNameFromUri(Uri contentUri) { return contentUri.getLastPathSegment(); } - private long getLastModifiedFromUri(Uri contentUri) { + private static long getLastModifiedFromUri(Uri contentUri) { if (contentUri.getScheme().equals("file")) { return new File(contentUri.toString()).lastModified(); } return 0; } - private String getMimeTypeFromUri(Uri contentUri) { - ContentResolver resolver = getReactApplicationContext().getContentResolver(); + private static String getMimeTypeFromUri(Uri contentUri, ContentResolver resolver) { String type = resolver.getType(contentUri); if (type == null) { @@ -211,28 +227,6 @@ public void createFromParts(ReadableArray parts, String blobId) { store(buffer.array(), blobId); } - @ReactMethod - public void createFromURI(String path, Promise promise) { - try { - Uri uri = Uri.parse(path); - byte[] data = getBytesFromUri(uri); - - WritableMap blob = Arguments.createMap(); - blob.putString("blobId", store(data)); - blob.putInt("offset", 0); - blob.putInt("size", data.length); - blob.putString("type", getMimeTypeFromUri(uri)); - - // Needed for files - blob.putString("name", getNameFromUri(uri)); - blob.putDouble("lastModified", getLastModifiedFromUri(uri)); - - promise.resolve(blob); - } catch (Exception e) { - promise.reject(e); - } - } - @ReactMethod public void release(String blobId) { remove(blobId); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index aebaed42d1486f..8bdcd6b0a40634 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -9,6 +9,7 @@ package com.facebook.react.modules.network; +import android.net.Uri; import android.util.Base64; import com.facebook.react.bridge.Arguments; @@ -170,13 +171,31 @@ public void sendRequest( final boolean useIncrementalUpdates, int timeout, boolean withCredentials) { + + final RCTDeviceEventEmitter eventEmitter = getEventEmitter(); + + try { + Uri uri = Uri.parse(url); + String scheme = uri.getScheme(); + boolean isRemote = scheme.equals("http") || scheme.equals("https"); + + if (!isRemote && responseType.equals("blob")) { + WritableMap blob = BlobModule.fetch(uri, getReactApplicationContext()); + ResponseUtil.onDataReceived(eventEmitter, requestId, blob); + ResponseUtil.onRequestSuccess(eventEmitter, requestId); + return; + } + } catch (IOException e) { + ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); + return; + } + Request.Builder requestBuilder = new Request.Builder().url(url); if (requestId != 0) { requestBuilder.tag(requestId); } - final RCTDeviceEventEmitter eventEmitter = getEventEmitter(); OkHttpClient.Builder clientBuilder = mClient.newBuilder(); if (!withCredentials) { From 7c0d8b29221c55beff306483161a3449e82fd40e Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 7 Jun 2017 13:57:10 +0530 Subject: [PATCH 18/66] Add support for downloading blobs on iOS --- .../RCTNetwork.xcodeproj/project.pbxproj | 2 ++ Libraries/Network/RCTNetworking.mm | 31 +++++++++++++++---- Libraries/WebSocket/RCTWebSocketModule.m | 6 +--- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj b/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj index d7875a8a137b16..6677ec77507d24 100644 --- a/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj +++ b/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj @@ -247,6 +247,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SKIP_INSTALL = YES; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../Blob"; WARNING_CFLAGS = ( "-Werror", "-Wall", @@ -291,6 +292,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SKIP_INSTALL = YES; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../Blob"; VALIDATE_PRODUCT = YES; WARNING_CFLAGS = ( "-Werror", diff --git a/Libraries/Network/RCTNetworking.mm b/Libraries/Network/RCTNetworking.mm index 248dfce227c3d1..81bca891b4ee37 100644 --- a/Libraries/Network/RCTNetworking.mm +++ b/Libraries/Network/RCTNetworking.mm @@ -19,6 +19,7 @@ #import #import +#import "RCTBlobManager.h" #import "RCTHTTPRequestHandler.h" typedef RCTURLRequestCancellationBlock (^RCTHTTPQueryResult)(NSError *error, NSDictionary *result); @@ -411,7 +412,9 @@ + (NSString *)decodeTextData:(NSData *)data fromResponse:(NSURLResponse *)respon - (void)sendData:(NSData *)data responseType:(NSString *)responseType - forTask:(RCTNetworkTask *)task + mimeType:(NSString *)mimeType + fileName:(NSString *)fileName + forTask:(RCTNetworkTask *)task { RCTAssertThread(_methodQueue, @"sendData: must be called on method queue"); @@ -419,22 +422,34 @@ - (void)sendData:(NSData *)data return; } - NSString *responseString; + NSArray *responseJSON; + if ([responseType isEqualToString:@"text"]) { // No carry storage is required here because the entire data has been loaded. - responseString = [RCTNetworking decodeTextData:data fromResponse:task.response withCarryData:nil]; + NSString *responseString = [RCTNetworking decodeTextData:data fromResponse:task.response withCarryData:nil]; if (!responseString) { RCTLogWarn(@"Received data was not a string, or was not a recognised encoding."); return; } + responseJSON = @[task.requestID, responseString]; + } else if ([responseType isEqualToString:@"blob"]) { + RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + NSDictionary *responseData = @{ + @"blobId": [blobManager store:data], + @"offset": @0, + @"size": @(data.length), + @"name": fileName, + @"type": mimeType, + }; + responseJSON = @[task.requestID, responseData]; } else if ([responseType isEqualToString:@"base64"]) { - responseString = [data base64EncodedStringWithOptions:0]; + NSString *responseString = [data base64EncodedStringWithOptions:0]; + responseJSON = @[task.requestID, responseString]; } else { RCTLogWarn(@"Invalid responseType: %@", responseType); return; } - NSArray *responseJSON = @[task.requestID, responseString]; [self sendEventWithName:@"didReceiveNetworkData" body:responseJSON]; } @@ -517,7 +532,11 @@ - (void)sendRequest:(NSURLRequest *)request // Unless we were sending incremental (text) chunks to JS, all along, now // is the time to send the request body to JS. if (!(incrementalUpdates && [responseType isEqualToString:@"text"])) { - [strongSelf sendData:data responseType:responseType forTask:task]; + [strongSelf sendData:data + responseType:responseType + mimeType:[response MIMEType] + fileName:[response suggestedFilename] + forTask:task]; } NSArray *responseJSON = @[task.requestID, RCTNullIfNil(error.localizedDescription), diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m index 802bba1d37c1e5..3494be6da19b04 100644 --- a/Libraries/WebSocket/RCTWebSocketModule.m +++ b/Libraries/WebSocket/RCTWebSocketModule.m @@ -9,16 +9,12 @@ #import "RCTWebSocketModule.h" #import "RCTSRWebSocket.h" +#import "RCTBlobManager.h" #import #import #import -<<<<<<< HEAD -#import -======= -#import "RCTBlobManager.h" ->>>>>>> Add blob implementation with WebSocket integration @implementation RCTSRWebSocket (React) From d62da305ed17cffd36234412e2dbfa447ae6183c Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 7 Jun 2017 17:58:53 +0530 Subject: [PATCH 19/66] Fix typo in base64 conversion --- .../java/com/facebook/react/modules/blob/FileReaderModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java index 23d433ff6dd72c..3c9bf34d04e9d4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java @@ -70,7 +70,7 @@ public void readAsDataURL(ReadableMap blob, Promise promise) { sb.append("application/octet-stream"); } - sb.append(";bas64,"); + sb.append(";base64,"); sb.append(Base64.encodeToString(bytes, Base64.NO_WRAP)); promise.resolve(sb.toString()); From 39feed9d92ad73efbc43dfd58462f70a35b78c16 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Wed, 7 Jun 2017 21:22:29 +0530 Subject: [PATCH 20/66] Fix uploading blob via XHR --- Libraries/Network/RCTNetworking.ios.js | 2 +- Libraries/Network/RCTNetworking.mm | 12 +++++++++++- Libraries/Network/XMLHttpRequest.js | 3 --- Libraries/Network/convertRequestBody.js | 7 ++++++- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Libraries/Network/RCTNetworking.ios.js b/Libraries/Network/RCTNetworking.ios.js index f2c8bb95b12500..184637b081e5d2 100644 --- a/Libraries/Network/RCTNetworking.ios.js +++ b/Libraries/Network/RCTNetworking.ios.js @@ -34,7 +34,7 @@ class RCTNetworking extends NativeEventEmitter { url: string, headers: Object, data: RequestBody, - responseType: 'text' | 'base64', + responseType: NativeResponseType, incrementalUpdates: boolean, timeout: number, callback: (requestId: number) => any, diff --git a/Libraries/Network/RCTNetworking.mm b/Libraries/Network/RCTNetworking.mm index 81bca891b4ee37..da4d9c16406d54 100644 --- a/Libraries/Network/RCTNetworking.mm +++ b/Libraries/Network/RCTNetworking.mm @@ -298,6 +298,8 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request * * - {"formData": [...]}: list of data payloads that will be combined into a multipart/form-data request * + * - {"blob": {...}}: an object representing a blob + * * If successful, the callback be called with a result dictionary containing the following (optional) keys: * * - @"body" (NSData): the body of the request @@ -317,6 +319,14 @@ - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary if (body) { return callback(nil, @{@"body": body}); } + NSDictionary *blob = [RCTConvert NSDictionary:query[@"blob"]]; + if (blob) { + RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + NSData *data = [blobManager resolve:blob]; + if (data) { + return callback(nil, @{@"body": data}); + } + } NSString *base64String = [RCTConvert NSString:query[@"base64"]]; if (base64String) { NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:0]; @@ -436,7 +446,7 @@ - (void)sendData:(NSData *)data RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; NSDictionary *responseData = @{ @"blobId": [blobManager store:data], - @"offset": @0, + @"offset": 0, @"size": @(data.length), @"name": fileName, @"type": mimeType, diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index 315e2a51e55986..f45984c95b16b0 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -495,9 +495,6 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { if (this._responseType === 'blob') { nativeResponseType = 'blob'; } - if (data instanceof Blob) { - data = data.data; - } invariant(this._method, 'Request method needs to be defined.'); invariant(this._url, 'Request URL needs to be defined.'); diff --git a/Libraries/Network/convertRequestBody.js b/Libraries/Network/convertRequestBody.js index e82689692bf1ef..6dd9803fcdab94 100644 --- a/Libraries/Network/convertRequestBody.js +++ b/Libraries/Network/convertRequestBody.js @@ -13,10 +13,12 @@ const binaryToBase64 = require('binaryToBase64'); +const Blob = require('Blob'); const FormData = require('FormData'); export type RequestBody = - string + | string + | Blob | FormData | {uri: string} | ArrayBuffer @@ -27,6 +29,9 @@ function convertRequestBody(body: RequestBody): Object { if (typeof body === 'string') { return {string: body}; } + if (body instanceof Blob) { + return {blob: body.data}; + } if (body instanceof FormData) { return {formData: body.getParts()}; } From 1a6060ad1b2304395d18def237699eec25c42bd3 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Thu, 8 Jun 2017 20:09:05 +0530 Subject: [PATCH 21/66] Basic implementation of file reader --- Libraries/Blob/FileReader.js | 9 --- .../Blob/RCTBlob.xcodeproj/project.pbxproj | 31 +++++----- Libraries/Blob/RCTBlobManager.m | 20 +++++-- Libraries/Blob/RCTFileReaderModule.h | 16 +++++ Libraries/Blob/RCTFileReaderModule.m | 60 +++++++++++++++++++ Libraries/Network/RCTNetworking.mm | 2 +- 6 files changed, 109 insertions(+), 29 deletions(-) create mode 100644 Libraries/Blob/RCTFileReaderModule.h create mode 100644 Libraries/Blob/RCTFileReaderModule.m diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js index ac7ba5f9fed925..d0bff7449f2e1c 100644 --- a/Libraries/Blob/FileReader.js +++ b/Libraries/Blob/FileReader.js @@ -13,7 +13,6 @@ 'use strict'; const EventTarget = require('event-target-shim'); -const Platform = require('Platform'); const Blob = require('Blob'); const { FileReaderModule } = require('NativeModules'); @@ -89,10 +88,6 @@ class FileReader extends EventTarget(...READER_EVENTS) { } readAsDataURL(blob: Blob) { - if (Platform.OS === 'ios') { - throw new Error('FileReader.readAsDataURL is not implemented on iOS'); - } - this._aborted = false; FileReaderModule.readAsDataURL(blob.data).then((text: string) => { @@ -111,10 +106,6 @@ class FileReader extends EventTarget(...READER_EVENTS) { } readAsText(blob: Blob, encoding: string = 'UTF-8') { - if (Platform.OS === 'ios') { - throw new Error('FileReader.readAsText is not implemented on iOS'); - } - this._aborted = false; FileReaderModule.readAsText(blob.data, encoding).then((text: string) => { diff --git a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj index 9acbdb5d61316e..d81666e585d3ad 100755 --- a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj +++ b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 5241ACAD1EE8595100F67468 /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 5241ACAC1EE8595100F67468 /* RCTFileReaderModule.m */; }; + 5241ACAE1EE8595100F67468 /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 5241ACAC1EE8595100F67468 /* RCTFileReaderModule.m */; }; AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; /* End PBXBuildFile section */ @@ -24,10 +26,12 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBlob.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 5241ACAB1EE769AD00F67468 /* libRCTBlob-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTBlob-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5241ACAC1EE8595100F67468 /* RCTFileReaderModule.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = RCTFileReaderModule.m; sourceTree = ""; tabWidth = 2; }; + 5241ACAF1EE8598200F67468 /* RCTFileReaderModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTFileReaderModule.h; sourceTree = ""; }; + 52F260D91EE7167300F0B7B4 /* libRCTBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBlob.a; sourceTree = BUILT_PRODUCTS_DIR; }; AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBlobManager.h; sourceTree = ""; }; AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBlobManager.m; sourceTree = ""; }; - ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTBlob-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -44,21 +48,15 @@ 358F4ECE1D1E81A9004DF814 = { isa = PBXGroup; children = ( + 5241ACAC1EE8595100F67468 /* RCTFileReaderModule.m */, + 5241ACAF1EE8598200F67468 /* RCTFileReaderModule.h */, AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */, AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */, - 358F4ED81D1E81A9004DF814 /* Products */, + 52F260D91EE7167300F0B7B4 /* libRCTBlob.a */, + 5241ACAB1EE769AD00F67468 /* libRCTBlob-tvOS.a */, ); sourceTree = ""; }; - 358F4ED81D1E81A9004DF814 /* Products */ = { - isa = PBXGroup; - children = ( - 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */, - ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -76,7 +74,7 @@ ); name = RCTBlob; productName = SLKBlobs; - productReference = 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */; + productReference = 52F260D91EE7167300F0B7B4 /* libRCTBlob.a */; productType = "com.apple.product-type.library.static"; }; ADD01A671E09402E00F6D226 /* RCTBlob-tvOS */ = { @@ -91,7 +89,7 @@ ); name = "RCTBlob-tvOS"; productName = "RCTBlob-tvOS"; - productReference = ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */; + productReference = 5241ACAB1EE769AD00F67468 /* libRCTBlob-tvOS.a */; productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ @@ -120,7 +118,7 @@ en, ); mainGroup = 358F4ECE1D1E81A9004DF814; - productRefGroup = 358F4ED81D1E81A9004DF814 /* Products */; + productRefGroup = 358F4ECE1D1E81A9004DF814; projectDirPath = ""; projectRoot = ""; targets = ( @@ -135,6 +133,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5241ACAD1EE8595100F67468 /* RCTFileReaderModule.m in Sources */, AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -143,6 +142,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5241ACAE1EE8595100F67468 /* RCTFileReaderModule.m in Sources */, ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -316,6 +316,7 @@ ADD01A701E09402E00F6D226 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.m index 67d211b4d48010..c9f2db786ee80d 100755 --- a/Libraries/Blob/RCTBlobManager.m +++ b/Libraries/Blob/RCTBlobManager.m @@ -68,12 +68,24 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) RCT_EXPORT_METHOD(createFromParts:(NSArray *> *)parts withId:(NSString *)blobId) { - NSMutableData *data = [NSMutableData new]; + NSMutableData *blob = [NSMutableData new]; + for (NSDictionary *part in parts) { - NSData *partData = [self resolve:part]; - [data appendData:partData]; + NSString *type = [RCTConvert NSString:part[@"type"]]; + + if ([type isEqualToString:@"blob"]) { + NSDictionary *data = [RCTConvert NSDictionary:part[@"data"]]; + NSData *partData = [self resolve:data]; + [blob appendData:partData]; + } else if ([type isEqualToString:@"string"]) { + NSData *data = [[RCTConvert NSString:part[@"data"]] dataUsingEncoding:NSUTF8StringEncoding]; + [blob appendData:data]; + } else { + [NSException raise:@"Invalid type for blob" format:@"%@ is invalid", type]; + } } - [self store:data withId:blobId]; + + [self store:blob withId:blobId]; } RCT_EXPORT_METHOD(release:(NSString *)blobId) diff --git a/Libraries/Blob/RCTFileReaderModule.h b/Libraries/Blob/RCTFileReaderModule.h new file mode 100644 index 00000000000000..ae04933b8e69f5 --- /dev/null +++ b/Libraries/Blob/RCTFileReaderModule.h @@ -0,0 +1,16 @@ +/** + * 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 + +@interface RCTFileReaderModule : NSObject + +@property (nonatomic, weak) RCTBridge *bridge; + +@end diff --git a/Libraries/Blob/RCTFileReaderModule.m b/Libraries/Blob/RCTFileReaderModule.m new file mode 100644 index 00000000000000..d78e3931b488a6 --- /dev/null +++ b/Libraries/Blob/RCTFileReaderModule.m @@ -0,0 +1,60 @@ +/** + * 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 "RCTFileReaderModule.h" +#import "RCTBlobManager.h" + +#import +#import + + +@implementation RCTFileReaderModule + +RCT_EXPORT_MODULE(FileReaderModule) + +RCT_EXPORT_METHOD(readAsText:(NSDictionary *)blob + encoding:(NSString *)encoding + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) +{ + RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + NSData *data = [blobManager resolve:blob]; + + if (data == nil) { + reject(RCTErrorUnspecified, + [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil); + } else { + NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + + resolve(text); + } +} + +RCT_EXPORT_METHOD(readAsDataURL:(NSDictionary *)blob + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) +{ + RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + NSData *data = [blobManager resolve:blob]; + + if (data == nil) { + reject(RCTErrorUnspecified, + [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil); + } else { + NSString *type = [RCTConvert NSString:blob[@"type"]]; + NSString *text = [NSString stringWithFormat:@"data:%@;base64,%@", + type != nil && [type length] > 0 ? type : @"application/octet-stream", + [data base64EncodedStringWithOptions:0]]; + + resolve(text); + } +} + +@end diff --git a/Libraries/Network/RCTNetworking.mm b/Libraries/Network/RCTNetworking.mm index da4d9c16406d54..9cc060905ab26c 100644 --- a/Libraries/Network/RCTNetworking.mm +++ b/Libraries/Network/RCTNetworking.mm @@ -446,7 +446,7 @@ - (void)sendData:(NSData *)data RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; NSDictionary *responseData = @{ @"blobId": [blobManager store:data], - @"offset": 0, + @"offset": @0, @"size": @(data.length), @"name": fileName, @"type": mimeType, From 8880eb9da466cdbe36251d03dd9a20a7f6d32862 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Thu, 8 Jun 2017 21:24:47 +0530 Subject: [PATCH 22/66] Revert unwanted changes --- Examples/2048/2048.xcodeproj/project.pbxproj | 684 ---------------- .../Movies/Movies.xcodeproj/project.pbxproj | 730 ------------------ .../TicTacToe.xcodeproj/project.pbxproj | 728 ----------------- .../java/com/facebook/react/modules/blob/BUCK | 26 +- .../com/facebook/react/modules/websocket/BUCK | 38 +- .../main/java/com/facebook/react/shell/BUCK | 122 +-- .../test/java/com/facebook/react/modules/BUCK | 76 +- 7 files changed, 131 insertions(+), 2273 deletions(-) delete mode 100644 Examples/2048/2048.xcodeproj/project.pbxproj delete mode 100644 Examples/Movies/Movies.xcodeproj/project.pbxproj delete mode 100644 Examples/TicTacToe/TicTacToe.xcodeproj/project.pbxproj diff --git a/Examples/2048/2048.xcodeproj/project.pbxproj b/Examples/2048/2048.xcodeproj/project.pbxproj deleted file mode 100644 index 0e8372ebb51a54..00000000000000 --- a/Examples/2048/2048.xcodeproj/project.pbxproj +++ /dev/null @@ -1,684 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 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 */; }; - 1461632D1AC3E23900C2F5AD /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1461632C1AC3E22900C2F5AD /* libReact.a */; }; - 5F82F1781B85785200FAE87E /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F82F1771B85784500FAE87E /* libRCTWebSocket.a */; }; - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; - ADBDB96A1DFEC03D00ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9431DFEC01900ED6528 /* libRCTBlob.a */; }; - E730D7501D4EE4E2000B7DA8 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E730D74C1D4EE4D0000B7DA8 /* libRCTNetwork.a */; }; - E730D7571D4EE538000B7DA8 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E730D7561D4EE534000B7DA8 /* libRCTImage.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 1461632B1AC3E22900C2F5AD /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; - remoteInfo = React; - }; - 5F82F1761B85784500FAE87E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3C86DF461ADF2C930047B81A; - remoteInfo = RCTWebSocket; - }; - 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5119B1A9E6C1200147676; - remoteInfo = RCTText; - }; - ADBDB9421DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = ADBDB93E1DFEC01800ED6528 /* RCTBlob.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 358F4ED71D1E81A9004DF814; - remoteInfo = RCTBlob; - }; - ADBDB9461DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; - remoteInfo = "RCTImage-tvOS"; - }; - ADBDB94A1DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28541D9B044C00D4039D; - remoteInfo = "RCTNetwork-tvOS"; - }; - ADBDB94E1DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A287B1D9B048500D4039D; - remoteInfo = "RCTText-tvOS"; - }; - ADBDB9521DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28881D9B049200D4039D; - remoteInfo = "RCTWebSocket-tvOS"; - }; - ADBDB95C1DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28131D9B038B00D4039D; - remoteInfo = "React-tvOS"; - }; - ADBDB95E1DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C059A1DE3340900C268FA; - remoteInfo = yoga; - }; - ADBDB9601DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C06751DE3340C00C268FA; - remoteInfo = "yoga-tvOS"; - }; - ADBDB9621DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; - remoteInfo = cxxreact; - }; - ADBDB9641DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; - remoteInfo = "cxxreact-tvOS"; - }; - ADBDB9661DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; - remoteInfo = jschelpers; - }; - ADBDB9681DFEC01900ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; - remoteInfo = "jschelpers-tvOS"; - }; - E730D74B1D4EE4D0000B7DA8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B511DB1A9E6C8500147676; - remoteInfo = RCTNetwork; - }; - E730D7551D4EE534000B7DA8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5115D1A9E6B3D00147676; - remoteInfo = RCTImage; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 13B07F961A680F5B00A75B9A /* 2048.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 2048.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = 2048/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = 2048/AppDelegate.m; sourceTree = ""; }; - 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = 2048/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = 2048/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = 2048/main.m; sourceTree = ""; }; - 146163271AC3E22900C2F5AD /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = ""; }; - 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; - ADBDB93E1DFEC01800ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; - E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; - E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ADBDB96A1DFEC03D00ED6528 /* libRCTBlob.a in Frameworks */, - E730D7571D4EE538000B7DA8 /* libRCTImage.a in Frameworks */, - E730D7501D4EE4E2000B7DA8 /* libRCTNetwork.a in Frameworks */, - 5F82F1781B85785200FAE87E /* libRCTWebSocket.a in Frameworks */, - 1461632D1AC3E23900C2F5AD /* libReact.a in Frameworks */, - 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 13B07FAE1A68108700A75B9A /* 2048 */ = { - isa = PBXGroup; - children = ( - 13B07FAF1A68108700A75B9A /* AppDelegate.h */, - 13B07FB01A68108700A75B9A /* AppDelegate.m */, - 13B07FB51A68108700A75B9A /* Images.xcassets */, - 13B07FB61A68108700A75B9A /* Info.plist */, - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, - 13B07FB71A68108700A75B9A /* main.m */, - ); - name = 2048; - sourceTree = ""; - }; - 146163281AC3E22900C2F5AD /* Products */ = { - isa = PBXGroup; - children = ( - 1461632C1AC3E22900C2F5AD /* libReact.a */, - ADBDB95D1DFEC01900ED6528 /* libReact.a */, - ADBDB95F1DFEC01900ED6528 /* libyoga.a */, - ADBDB9611DFEC01900ED6528 /* libyoga.a */, - ADBDB9631DFEC01900ED6528 /* libcxxreact.a */, - ADBDB9651DFEC01900ED6528 /* libcxxreact.a */, - ADBDB9671DFEC01900ED6528 /* libjschelpers.a */, - ADBDB9691DFEC01900ED6528 /* libjschelpers.a */, - ); - name = Products; - sourceTree = ""; - }; - 5F82F1731B85784500FAE87E /* Products */ = { - isa = PBXGroup; - children = ( - 5F82F1771B85784500FAE87E /* libRCTWebSocket.a */, - ADBDB9531DFEC01900ED6528 /* libRCTWebSocket-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 832341AE1AAA6A7D00B99B32 /* Libraries */ = { - isa = PBXGroup; - children = ( - ADBDB93E1DFEC01800ED6528 /* RCTBlob.xcodeproj */, - E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */, - E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */, - 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */, - 146163271AC3E22900C2F5AD /* React.xcodeproj */, - 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, - ); - name = Libraries; - sourceTree = ""; - }; - 832341B11AAA6A8300B99B32 /* Products */ = { - isa = PBXGroup; - children = ( - 832341B51AAA6A8300B99B32 /* libRCTText.a */, - ADBDB94F1DFEC01900ED6528 /* libRCTText-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 13B07FAE1A68108700A75B9A /* 2048 */, - 832341AE1AAA6A7D00B99B32 /* Libraries */, - 83CBBA001A601CBA00E9B192 /* Products */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* 2048.app */, - ); - name = Products; - sourceTree = ""; - }; - ADBDB93F1DFEC01800ED6528 /* Products */ = { - isa = PBXGroup; - children = ( - ADBDB9431DFEC01900ED6528 /* libRCTBlob.a */, - ); - name = Products; - sourceTree = ""; - }; - E730D7481D4EE4D0000B7DA8 /* Products */ = { - isa = PBXGroup; - children = ( - E730D74C1D4EE4D0000B7DA8 /* libRCTNetwork.a */, - ADBDB94B1DFEC01900ED6528 /* libRCTNetwork-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - E730D7521D4EE534000B7DA8 /* Products */ = { - isa = PBXGroup; - children = ( - E730D7561D4EE534000B7DA8 /* libRCTImage.a */, - ADBDB9471DFEC01900ED6528 /* libRCTImage-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 13B07F861A680F5B00A75B9A /* 2048 */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "2048" */; - buildPhases = ( - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - 68ACCCD51D2BE2D2008E368A /* Run Script */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = 2048; - productName = "Hello World"; - productReference = 13B07F961A680F5B00A75B9A /* 2048.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 83CBB9F71A601CBA00E9B192 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0700; - ORGANIZATIONNAME = Facebook; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "2048" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = ADBDB93F1DFEC01800ED6528 /* Products */; - ProjectRef = ADBDB93E1DFEC01800ED6528 /* RCTBlob.xcodeproj */; - }, - { - ProductGroup = E730D7521D4EE534000B7DA8 /* Products */; - ProjectRef = E730D7511D4EE534000B7DA8 /* RCTImage.xcodeproj */; - }, - { - ProductGroup = E730D7481D4EE4D0000B7DA8 /* Products */; - ProjectRef = E730D7471D4EE4D0000B7DA8 /* RCTNetwork.xcodeproj */; - }, - { - ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; - ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; - }, - { - ProductGroup = 5F82F1731B85784500FAE87E /* Products */; - ProjectRef = 5F82F1721B85784500FAE87E /* RCTWebSocket.xcodeproj */; - }, - { - ProductGroup = 146163281AC3E22900C2F5AD /* Products */; - ProjectRef = 146163271AC3E22900C2F5AD /* React.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* 2048 */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - 1461632C1AC3E22900C2F5AD /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 1461632B1AC3E22900C2F5AD /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 5F82F1771B85784500FAE87E /* libRCTWebSocket.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTWebSocket.a; - remoteRef = 5F82F1761B85784500FAE87E /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 832341B51AAA6A8300B99B32 /* libRCTText.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTText.a; - remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9431DFEC01900ED6528 /* libRCTBlob.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTBlob.a; - remoteRef = ADBDB9421DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9471DFEC01900ED6528 /* libRCTImage-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTImage-tvOS.a"; - remoteRef = ADBDB9461DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB94B1DFEC01900ED6528 /* libRCTNetwork-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTNetwork-tvOS.a"; - remoteRef = ADBDB94A1DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB94F1DFEC01900ED6528 /* libRCTText-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTText-tvOS.a"; - remoteRef = ADBDB94E1DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9531DFEC01900ED6528 /* libRCTWebSocket-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTWebSocket-tvOS.a"; - remoteRef = ADBDB9521DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB95D1DFEC01900ED6528 /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = ADBDB95C1DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB95F1DFEC01900ED6528 /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = ADBDB95E1DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9611DFEC01900ED6528 /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = ADBDB9601DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9631DFEC01900ED6528 /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = ADBDB9621DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9651DFEC01900ED6528 /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = ADBDB9641DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9671DFEC01900ED6528 /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = ADBDB9661DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9691DFEC01900ED6528 /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = ADBDB9681DFEC01900ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E730D74C1D4EE4D0000B7DA8 /* libRCTNetwork.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTNetwork.a; - remoteRef = E730D74B1D4EE4D0000B7DA8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E730D7561D4EE534000B7DA8 /* libRCTImage.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTImage.a; - remoteRef = E730D7551D4EE534000B7DA8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - 13B07F8E1A680F5B00A75B9A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 68ACCCD51D2BE2D2008E368A /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export NODE_BINARY=node\n$SRCROOT/../../packager/react-native-xcode.sh Examples/2048/Game2048.js\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 13B07F871A680F5B00A75B9A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, - 13B07FC11A68108700A75B9A /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 13B07FB21A68108700A75B9A /* Base */, - ); - name = LaunchScreen.xib; - path = 2048; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 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)/2048/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = 2048; - }; - 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)/2048/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = 2048; - }; - 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; - ENABLE_TESTABILITY = 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 = 8.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 = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "2048" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "2048" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/Examples/Movies/Movies.xcodeproj/project.pbxproj b/Examples/Movies/Movies.xcodeproj/project.pbxproj deleted file mode 100644 index 0ba1653c35ce48..00000000000000 --- a/Examples/Movies/Movies.xcodeproj/project.pbxproj +++ /dev/null @@ -1,730 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1341801E1AA91750003F314A /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341801B1AA91740003F314A /* libRCTNetwork.a */; }; - 13442C061AA90EA00037E5B0 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13442C051AA90E7D0037E5B0 /* libRCTImage.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 */; }; - 140D9B661AC36C42004F25EE /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14312D241AC3654D00CDC950 /* libRCTLinking.a */; }; - 14A2D4421AC3E43800CC738A /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14A2D4411AC3E41A00CC738A /* libReact.a */; }; - 58C5726B1AA6239E00CDF9C8 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C5725B1AA6236500CDF9C8 /* libRCTText.a */; }; - 67C95F201B0E64A30040BCE2 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */; }; - ADBDB9A11DFEC1CA00ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9761DFEC1C200ED6528 /* libRCTBlob.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 1341801A1AA91740003F314A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 134180151AA91740003F314A /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B511DB1A9E6C8500147676; - remoteInfo = RCTNetwork; - }; - 13442C041AA90E7D0037E5B0 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5115D1A9E6B3D00147676; - remoteInfo = RCTImage; - }; - 14312D231AC3654D00CDC950 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTLinking; - }; - 14A2D4401AC3E41A00CC738A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; - remoteInfo = React; - }; - 58C5725A1AA6236500CDF9C8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5119B1A9E6C1200147676; - remoteInfo = RCTText; - }; - 67C95F1D1B0E647A0040BCE2 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3C86DF461ADF2C930047B81A; - remoteInfo = RCTWebSocket; - }; - ADBDB9751DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = ADBDB9711DFEC1C200ED6528 /* RCTBlob.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 358F4ED71D1E81A9004DF814; - remoteInfo = RCTBlob; - }; - ADBDB9791DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; - remoteInfo = "RCTImage-tvOS"; - }; - ADBDB97D1DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28471D9B043800D4039D; - remoteInfo = "RCTLinking-tvOS"; - }; - ADBDB9811DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 134180151AA91740003F314A /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28541D9B044C00D4039D; - remoteInfo = "RCTNetwork-tvOS"; - }; - ADBDB9851DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A287B1D9B048500D4039D; - remoteInfo = "RCTText-tvOS"; - }; - ADBDB9891DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28881D9B049200D4039D; - remoteInfo = "RCTWebSocket-tvOS"; - }; - ADBDB9931DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28131D9B038B00D4039D; - remoteInfo = "React-tvOS"; - }; - ADBDB9951DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C059A1DE3340900C268FA; - remoteInfo = yoga; - }; - ADBDB9971DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C06751DE3340C00C268FA; - remoteInfo = "yoga-tvOS"; - }; - ADBDB9991DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; - remoteInfo = cxxreact; - }; - ADBDB99B1DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; - remoteInfo = "cxxreact-tvOS"; - }; - ADBDB99D1DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; - remoteInfo = jschelpers; - }; - ADBDB99F1DFEC1C200ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; - remoteInfo = "jschelpers-tvOS"; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 134180151AA91740003F314A /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; - 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; - 13B07F961A680F5B00A75B9A /* Movies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Movies.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = Movies/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = Movies/AppDelegate.m; sourceTree = ""; }; - 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Movies/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Movies/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = Movies/main.m; sourceTree = ""; }; - 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../../Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = ""; }; - 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = ""; }; - 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = SOURCE_ROOT; }; - 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; - ADBDB9711DFEC1C200ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ADBDB9A11DFEC1CA00ED6528 /* libRCTBlob.a in Frameworks */, - 67C95F201B0E64A30040BCE2 /* libRCTWebSocket.a in Frameworks */, - 14A2D4421AC3E43800CC738A /* libReact.a in Frameworks */, - 140D9B661AC36C42004F25EE /* libRCTLinking.a in Frameworks */, - 1341801E1AA91750003F314A /* libRCTNetwork.a in Frameworks */, - 13442C061AA90EA00037E5B0 /* libRCTImage.a in Frameworks */, - 58C5726B1AA6239E00CDF9C8 /* libRCTText.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 134180161AA91740003F314A /* Products */ = { - isa = PBXGroup; - children = ( - 1341801B1AA91740003F314A /* libRCTNetwork.a */, - ADBDB9821DFEC1C200ED6528 /* libRCTNetwork-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 13442C011AA90E7D0037E5B0 /* Products */ = { - isa = PBXGroup; - children = ( - 13442C051AA90E7D0037E5B0 /* libRCTImage.a */, - ADBDB97A1DFEC1C200ED6528 /* libRCTImage-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 13B07FAE1A68108700A75B9A /* Movies */ = { - isa = PBXGroup; - children = ( - 13B07FAF1A68108700A75B9A /* AppDelegate.h */, - 13B07FB01A68108700A75B9A /* AppDelegate.m */, - 13B07FB51A68108700A75B9A /* Images.xcassets */, - 13B07FB61A68108700A75B9A /* Info.plist */, - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, - 13B07FB71A68108700A75B9A /* main.m */, - ); - name = Movies; - sourceTree = ""; - }; - 14312D1F1AC3654D00CDC950 /* Products */ = { - isa = PBXGroup; - children = ( - 14312D241AC3654D00CDC950 /* libRCTLinking.a */, - ADBDB97E1DFEC1C200ED6528 /* libRCTLinking-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 14A2D43D1AC3E41A00CC738A /* Products */ = { - isa = PBXGroup; - children = ( - 14A2D4411AC3E41A00CC738A /* libReact.a */, - ADBDB9941DFEC1C200ED6528 /* libReact.a */, - ADBDB9961DFEC1C200ED6528 /* libyoga.a */, - ADBDB9981DFEC1C200ED6528 /* libyoga.a */, - ADBDB99A1DFEC1C200ED6528 /* libcxxreact.a */, - ADBDB99C1DFEC1C200ED6528 /* libcxxreact.a */, - ADBDB99E1DFEC1C200ED6528 /* libjschelpers.a */, - ADBDB9A01DFEC1C200ED6528 /* libjschelpers.a */, - ); - name = Products; - sourceTree = ""; - }; - 58C571FC1AA6124500CDF9C8 /* Libraries */ = { - isa = PBXGroup; - children = ( - ADBDB9711DFEC1C200ED6528 /* RCTBlob.xcodeproj */, - 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */, - 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */, - 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */, - 134180151AA91740003F314A /* RCTNetwork.xcodeproj */, - 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */, - 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */, - ); - name = Libraries; - sourceTree = ""; - }; - 58C572571AA6236500CDF9C8 /* Products */ = { - isa = PBXGroup; - children = ( - 58C5725B1AA6236500CDF9C8 /* libRCTText.a */, - ADBDB9861DFEC1C200ED6528 /* libRCTText-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 67C95F161B0E647A0040BCE2 /* Products */ = { - isa = PBXGroup; - children = ( - 67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */, - ADBDB98A1DFEC1C200ED6528 /* libRCTWebSocket-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 13B07FAE1A68108700A75B9A /* Movies */, - 58C571FC1AA6124500CDF9C8 /* Libraries */, - 83CBBA001A601CBA00E9B192 /* Products */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* Movies.app */, - ); - name = Products; - sourceTree = ""; - }; - ADBDB9721DFEC1C200ED6528 /* Products */ = { - isa = PBXGroup; - children = ( - ADBDB9761DFEC1C200ED6528 /* libRCTBlob.a */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 13B07F861A680F5B00A75B9A /* Movies */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Movies" */; - buildPhases = ( - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - 68ACCCEE1D2BE57F008E368A /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Movies; - productName = "Hello World"; - productReference = 13B07F961A680F5B00A75B9A /* Movies.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 83CBB9F71A601CBA00E9B192 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0700; - ORGANIZATIONNAME = Facebook; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Movies" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = ADBDB9721DFEC1C200ED6528 /* Products */; - ProjectRef = ADBDB9711DFEC1C200ED6528 /* RCTBlob.xcodeproj */; - }, - { - ProductGroup = 13442C011AA90E7D0037E5B0 /* Products */; - ProjectRef = 13442C001AA90E7D0037E5B0 /* RCTImage.xcodeproj */; - }, - { - ProductGroup = 14312D1F1AC3654D00CDC950 /* Products */; - ProjectRef = 14312D1E1AC3654D00CDC950 /* RCTLinking.xcodeproj */; - }, - { - ProductGroup = 134180161AA91740003F314A /* Products */; - ProjectRef = 134180151AA91740003F314A /* RCTNetwork.xcodeproj */; - }, - { - ProductGroup = 58C572571AA6236500CDF9C8 /* Products */; - ProjectRef = 587650F61A9EB120008B8F17 /* RCTText.xcodeproj */; - }, - { - ProductGroup = 67C95F161B0E647A0040BCE2 /* Products */; - ProjectRef = 67C95F151B0E647A0040BCE2 /* RCTWebSocket.xcodeproj */; - }, - { - ProductGroup = 14A2D43D1AC3E41A00CC738A /* Products */; - ProjectRef = 14A2D43C1AC3E41A00CC738A /* React.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* Movies */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - 1341801B1AA91740003F314A /* libRCTNetwork.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTNetwork.a; - remoteRef = 1341801A1AA91740003F314A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 13442C051AA90E7D0037E5B0 /* libRCTImage.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTImage.a; - remoteRef = 13442C041AA90E7D0037E5B0 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 14312D241AC3654D00CDC950 /* libRCTLinking.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTLinking.a; - remoteRef = 14312D231AC3654D00CDC950 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 14A2D4411AC3E41A00CC738A /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 14A2D4401AC3E41A00CC738A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 58C5725B1AA6236500CDF9C8 /* libRCTText.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTText.a; - remoteRef = 58C5725A1AA6236500CDF9C8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 67C95F1E1B0E647A0040BCE2 /* libRCTWebSocket.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTWebSocket.a; - remoteRef = 67C95F1D1B0E647A0040BCE2 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9761DFEC1C200ED6528 /* libRCTBlob.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTBlob.a; - remoteRef = ADBDB9751DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB97A1DFEC1C200ED6528 /* libRCTImage-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTImage-tvOS.a"; - remoteRef = ADBDB9791DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB97E1DFEC1C200ED6528 /* libRCTLinking-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTLinking-tvOS.a"; - remoteRef = ADBDB97D1DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9821DFEC1C200ED6528 /* libRCTNetwork-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTNetwork-tvOS.a"; - remoteRef = ADBDB9811DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9861DFEC1C200ED6528 /* libRCTText-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTText-tvOS.a"; - remoteRef = ADBDB9851DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB98A1DFEC1C200ED6528 /* libRCTWebSocket-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTWebSocket-tvOS.a"; - remoteRef = ADBDB9891DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9941DFEC1C200ED6528 /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = ADBDB9931DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9961DFEC1C200ED6528 /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = ADBDB9951DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9981DFEC1C200ED6528 /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = ADBDB9971DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB99A1DFEC1C200ED6528 /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = ADBDB9991DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB99C1DFEC1C200ED6528 /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = ADBDB99B1DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB99E1DFEC1C200ED6528 /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = ADBDB99D1DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9A01DFEC1C200ED6528 /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = ADBDB99F1DFEC1C200ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - 13B07F8E1A680F5B00A75B9A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 68ACCCEE1D2BE57F008E368A /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export NODE_BINARY=node\n$SRCROOT/../../packager/react-native-xcode.sh Examples/Movies/MoviesApp.ios.js\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 13B07F871A680F5B00A75B9A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, - 13B07FC11A68108700A75B9A /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 13B07FB21A68108700A75B9A /* Base */, - ); - name = LaunchScreen.xib; - path = Movies; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 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)/Movies/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = Movies; - USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Libraries/**"; - }; - 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)/Movies/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = Movies; - USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../../Libraries/**"; - }; - 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; - ENABLE_TESTABILITY = 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 = 8.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 = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Movies" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Movies" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/Examples/TicTacToe/TicTacToe.xcodeproj/project.pbxproj b/Examples/TicTacToe/TicTacToe.xcodeproj/project.pbxproj deleted file mode 100644 index ae65abdfb07e49..00000000000000 --- a/Examples/TicTacToe/TicTacToe.xcodeproj/project.pbxproj +++ /dev/null @@ -1,728 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 1341803E1AA91802003F314A /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1341803D1AA917ED003F314A /* libRCTImage.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 */; }; - 144C5F691AC3E5E300B004E7 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 144C5F681AC3E5D800B004E7 /* libReact.a */; }; - 58C572511AA6229D00CDF9C8 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C5724D1AA6224400CDF9C8 /* libRCTText.a */; }; - 5FF8942E1B85571A007731BE /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5FF8942D1B8556F8007731BE /* libRCTWebSocket.a */; }; - 832044981B492C2500E297FC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832044951B492C1E00E297FC /* libRCTSettings.a */; }; - ADBDB9D81DFEC21200ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9AD1DFEC20D00ED6528 /* libRCTBlob.a */; }; - E730D7731D4EE604000B7DA8 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E730D76E1D4EE5FC000B7DA8 /* libRCTNetwork.a */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 1341803C1AA917ED003F314A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 134180381AA917ED003F314A /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5115D1A9E6B3D00147676; - remoteInfo = RCTImage; - }; - 144C5F671AC3E5D800B004E7 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; - remoteInfo = React; - }; - 58C5724C1AA6224400CDF9C8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B5119B1A9E6C1200147676; - remoteInfo = RCTText; - }; - 5FF8942C1B8556F8007731BE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3C86DF461ADF2C930047B81A; - remoteInfo = RCTWebSocket; - }; - 832044941B492C1E00E297FC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 134814201AA4EA6300B7C361; - remoteInfo = RCTSettings; - }; - ADBDB9AC1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = ADBDB9A81DFEC20D00ED6528 /* RCTBlob.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 358F4ED71D1E81A9004DF814; - remoteInfo = RCTBlob; - }; - ADBDB9B01DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 134180381AA917ED003F314A /* RCTImage.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A283A1D9B042B00D4039D; - remoteInfo = "RCTImage-tvOS"; - }; - ADBDB9B41DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28541D9B044C00D4039D; - remoteInfo = "RCTNetwork-tvOS"; - }; - ADBDB9B81DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28611D9B046600D4039D; - remoteInfo = "RCTSettings-tvOS"; - }; - ADBDB9BC1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A287B1D9B048500D4039D; - remoteInfo = "RCTText-tvOS"; - }; - ADBDB9C01DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28881D9B049200D4039D; - remoteInfo = "RCTWebSocket-tvOS"; - }; - ADBDB9CA1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 2D2A28131D9B038B00D4039D; - remoteInfo = "React-tvOS"; - }; - ADBDB9CC1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C059A1DE3340900C268FA; - remoteInfo = yoga; - }; - ADBDB9CE1DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3C06751DE3340C00C268FA; - remoteInfo = "yoga-tvOS"; - }; - ADBDB9D01DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; - remoteInfo = cxxreact; - }; - ADBDB9D21DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; - remoteInfo = "cxxreact-tvOS"; - }; - ADBDB9D41DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; - remoteInfo = jschelpers; - }; - ADBDB9D61DFEC20D00ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; - remoteInfo = "jschelpers-tvOS"; - }; - E730D76D1D4EE5FC000B7DA8 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 58B511DB1A9E6C8500147676; - remoteInfo = RCTNetwork; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 134180381AA917ED003F314A /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; - 13B07F961A680F5B00A75B9A /* TicTacToe.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TicTacToe.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = TicTacToe/AppDelegate.h; sourceTree = ""; }; - 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = TicTacToe/AppDelegate.m; sourceTree = ""; }; - 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = TicTacToe/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = TicTacToe/Info.plist; sourceTree = ""; }; - 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = TicTacToe/main.m; sourceTree = ""; }; - 144C5F631AC3E5D800B004E7 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = ""; }; - 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../../Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; - 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../../Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; - 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../../Libraries/Settings/RCTSettings.xcodeproj; sourceTree = ""; }; - ADBDB9A81DFEC20D00ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; - E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../../Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ADBDB9D81DFEC21200ED6528 /* libRCTBlob.a in Frameworks */, - E730D7731D4EE604000B7DA8 /* libRCTNetwork.a in Frameworks */, - 5FF8942E1B85571A007731BE /* libRCTWebSocket.a in Frameworks */, - 144C5F691AC3E5E300B004E7 /* libReact.a in Frameworks */, - 1341803E1AA91802003F314A /* libRCTImage.a in Frameworks */, - 58C572511AA6229D00CDF9C8 /* libRCTText.a in Frameworks */, - 832044981B492C2500E297FC /* libRCTSettings.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 134180391AA917ED003F314A /* Products */ = { - isa = PBXGroup; - children = ( - 1341803D1AA917ED003F314A /* libRCTImage.a */, - ADBDB9B11DFEC20D00ED6528 /* libRCTImage-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 13B07FAE1A68108700A75B9A /* TicTacToe */ = { - isa = PBXGroup; - children = ( - 13B07FAF1A68108700A75B9A /* AppDelegate.h */, - 13B07FB01A68108700A75B9A /* AppDelegate.m */, - 13B07FB51A68108700A75B9A /* Images.xcassets */, - 13B07FB61A68108700A75B9A /* Info.plist */, - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, - 13B07FB71A68108700A75B9A /* main.m */, - ); - name = TicTacToe; - sourceTree = ""; - }; - 144C5F641AC3E5D800B004E7 /* Products */ = { - isa = PBXGroup; - children = ( - 144C5F681AC3E5D800B004E7 /* libReact.a */, - ADBDB9CB1DFEC20D00ED6528 /* libReact.a */, - ADBDB9CD1DFEC20D00ED6528 /* libyoga.a */, - ADBDB9CF1DFEC20D00ED6528 /* libyoga.a */, - ADBDB9D11DFEC20D00ED6528 /* libcxxreact.a */, - ADBDB9D31DFEC20D00ED6528 /* libcxxreact.a */, - ADBDB9D51DFEC20D00ED6528 /* libjschelpers.a */, - ADBDB9D71DFEC20D00ED6528 /* libjschelpers.a */, - ); - name = Products; - sourceTree = ""; - }; - 58C572071AA6126D00CDF9C8 /* Libraries */ = { - isa = PBXGroup; - children = ( - ADBDB9A81DFEC20D00ED6528 /* RCTBlob.xcodeproj */, - E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */, - 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */, - 144C5F631AC3E5D800B004E7 /* React.xcodeproj */, - 134180381AA917ED003F314A /* RCTImage.xcodeproj */, - 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */, - 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */, - ); - name = Libraries; - sourceTree = ""; - }; - 58C572481AA6224300CDF9C8 /* Products */ = { - isa = PBXGroup; - children = ( - 58C5724D1AA6224400CDF9C8 /* libRCTText.a */, - ADBDB9BD1DFEC20D00ED6528 /* libRCTText-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 5FF894291B8556F8007731BE /* Products */ = { - isa = PBXGroup; - children = ( - 5FF8942D1B8556F8007731BE /* libRCTWebSocket.a */, - ADBDB9C11DFEC20D00ED6528 /* libRCTWebSocket-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 832044901B492C1E00E297FC /* Products */ = { - isa = PBXGroup; - children = ( - 832044951B492C1E00E297FC /* libRCTSettings.a */, - ADBDB9B91DFEC20D00ED6528 /* libRCTSettings-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 13B07FAE1A68108700A75B9A /* TicTacToe */, - 58C572071AA6126D00CDF9C8 /* Libraries */, - 83CBBA001A601CBA00E9B192 /* Products */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* TicTacToe.app */, - ); - name = Products; - sourceTree = ""; - }; - ADBDB9A91DFEC20D00ED6528 /* Products */ = { - isa = PBXGroup; - children = ( - ADBDB9AD1DFEC20D00ED6528 /* libRCTBlob.a */, - ); - name = Products; - sourceTree = ""; - }; - E730D7691D4EE5FC000B7DA8 /* Products */ = { - isa = PBXGroup; - children = ( - E730D76E1D4EE5FC000B7DA8 /* libRCTNetwork.a */, - ADBDB9B51DFEC20D00ED6528 /* libRCTNetwork-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 13B07F861A680F5B00A75B9A /* TicTacToe */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "TicTacToe" */; - buildPhases = ( - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - 681C70ED1D2BE73C00E71791 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = TicTacToe; - productName = "Hello World"; - productReference = 13B07F961A680F5B00A75B9A /* TicTacToe.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 83CBB9F71A601CBA00E9B192 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0700; - ORGANIZATIONNAME = Facebook; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "TicTacToe" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectReferences = ( - { - ProductGroup = ADBDB9A91DFEC20D00ED6528 /* Products */; - ProjectRef = ADBDB9A81DFEC20D00ED6528 /* RCTBlob.xcodeproj */; - }, - { - ProductGroup = 134180391AA917ED003F314A /* Products */; - ProjectRef = 134180381AA917ED003F314A /* RCTImage.xcodeproj */; - }, - { - ProductGroup = E730D7691D4EE5FC000B7DA8 /* Products */; - ProjectRef = E730D7681D4EE5FC000B7DA8 /* RCTNetwork.xcodeproj */; - }, - { - ProductGroup = 832044901B492C1E00E297FC /* Products */; - ProjectRef = 8320448F1B492C1E00E297FC /* RCTSettings.xcodeproj */; - }, - { - ProductGroup = 58C572481AA6224300CDF9C8 /* Products */; - ProjectRef = 587650DA1A9EB0DB008B8F17 /* RCTText.xcodeproj */; - }, - { - ProductGroup = 5FF894291B8556F8007731BE /* Products */; - ProjectRef = 5FF894281B8556F8007731BE /* RCTWebSocket.xcodeproj */; - }, - { - ProductGroup = 144C5F641AC3E5D800B004E7 /* Products */; - ProjectRef = 144C5F631AC3E5D800B004E7 /* React.xcodeproj */; - }, - ); - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* TicTacToe */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXReferenceProxy section */ - 1341803D1AA917ED003F314A /* libRCTImage.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTImage.a; - remoteRef = 1341803C1AA917ED003F314A /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 144C5F681AC3E5D800B004E7 /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = 144C5F671AC3E5D800B004E7 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 58C5724D1AA6224400CDF9C8 /* libRCTText.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTText.a; - remoteRef = 58C5724C1AA6224400CDF9C8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 5FF8942D1B8556F8007731BE /* libRCTWebSocket.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTWebSocket.a; - remoteRef = 5FF8942C1B8556F8007731BE /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - 832044951B492C1E00E297FC /* libRCTSettings.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTSettings.a; - remoteRef = 832044941B492C1E00E297FC /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9AD1DFEC20D00ED6528 /* libRCTBlob.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTBlob.a; - remoteRef = ADBDB9AC1DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9B11DFEC20D00ED6528 /* libRCTImage-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTImage-tvOS.a"; - remoteRef = ADBDB9B01DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9B51DFEC20D00ED6528 /* libRCTNetwork-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTNetwork-tvOS.a"; - remoteRef = ADBDB9B41DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9B91DFEC20D00ED6528 /* libRCTSettings-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTSettings-tvOS.a"; - remoteRef = ADBDB9B81DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9BD1DFEC20D00ED6528 /* libRCTText-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTText-tvOS.a"; - remoteRef = ADBDB9BC1DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9C11DFEC20D00ED6528 /* libRCTWebSocket-tvOS.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = "libRCTWebSocket-tvOS.a"; - remoteRef = ADBDB9C01DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9CB1DFEC20D00ED6528 /* libReact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libReact.a; - remoteRef = ADBDB9CA1DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9CD1DFEC20D00ED6528 /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = ADBDB9CC1DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9CF1DFEC20D00ED6528 /* libyoga.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libyoga.a; - remoteRef = ADBDB9CE1DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9D11DFEC20D00ED6528 /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = ADBDB9D01DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9D31DFEC20D00ED6528 /* libcxxreact.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libcxxreact.a; - remoteRef = ADBDB9D21DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9D51DFEC20D00ED6528 /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = ADBDB9D41DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - ADBDB9D71DFEC20D00ED6528 /* libjschelpers.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libjschelpers.a; - remoteRef = ADBDB9D61DFEC20D00ED6528 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; - E730D76E1D4EE5FC000B7DA8 /* libRCTNetwork.a */ = { - isa = PBXReferenceProxy; - fileType = archive.ar; - path = libRCTNetwork.a; - remoteRef = E730D76D1D4EE5FC000B7DA8 /* PBXContainerItemProxy */; - sourceTree = BUILT_PRODUCTS_DIR; - }; -/* End PBXReferenceProxy section */ - -/* Begin PBXResourcesBuildPhase section */ - 13B07F8E1A680F5B00A75B9A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 681C70ED1D2BE73C00E71791 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "export NODE_BINARY=node\n$SRCROOT/../../packager/react-native-xcode.sh Examples/TicTacToe/TicTacToeApp.js\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 13B07F871A680F5B00A75B9A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, - 13B07FC11A68108700A75B9A /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 13B07FB21A68108700A75B9A /* Base */, - ); - name = LaunchScreen.xib; - path = TicTacToe; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 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)/TicTacToe/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = TicTacToe; - }; - 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)/TicTacToe/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - LIBRARY_SEARCH_PATHS = "$(inherited)"; - OTHER_LDFLAGS = ( - "-ObjC", - "-lc++", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = TicTacToe; - }; - 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; - ENABLE_TESTABILITY = 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 = 8.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 = 8.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "TicTacToe" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "TicTacToe" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK index e699eebcd78070..340846cdc5a325 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -1,23 +1,23 @@ -include_defs('//ReactAndroid/DEFS') +include_defs("//ReactAndroid/DEFS") android_library( - name = 'blob', - srcs = glob(['**/*.java']), + name = "blob", + srcs = glob(["**/*.java"]), deps = [ - react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'), - react_native_dep('third-party/android/support-annotations:android-support-annotations'), - react_native_dep('third-party/android/support/v4:lib-support-v4'), - react_native_dep('third-party/java/infer-annotations:infer-annotations'), - react_native_dep('third-party/java/jsr-305:jsr-305'), - react_native_target('java/com/facebook/react/bridge:bridge'), - react_native_target('java/com/facebook/react/common:common'), - react_native_target('java/com/facebook/react/module/annotations:annotations'), + react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), + react_native_dep("third-party/android/support-annotations:android-support-annotations"), + react_native_dep("third-party/android/support/v4:lib-support-v4"), + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/module/annotations:annotations"), ], visibility = [ - 'PUBLIC', + "PUBLIC", ], ) project_config( - src_target = ':blob', + src_target = ":blob", ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK index 091cf8cb15eea2..956c75620b8d48 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK @@ -1,23 +1,23 @@ include_defs("//ReactAndroid/DEFS") android_library( - name = 'websocket', - srcs = glob(['**/*.java']), - deps = [ - react_native_dep('libraries/fbcore/src/main/java/com/facebook/common/logging:logging'), - react_native_dep('third-party/java/infer-annotations:infer-annotations'), - react_native_dep('third-party/java/jsr-305:jsr-305'), - react_native_dep('third-party/java/okhttp:okhttp3'), - react_native_dep('third-party/java/okhttp:okhttp3-ws'), - react_native_dep('third-party/java/okio:okio'), - react_native_target('java/com/facebook/react/bridge:bridge'), - react_native_target('java/com/facebook/react/common:common'), - react_native_target('java/com/facebook/react/module/annotations:annotations'), - react_native_target('java/com/facebook/react/modules/core:core'), - react_native_target('java/com/facebook/react/modules/network:network'), - react_native_target('java/com/facebook/react/modules/blob:blob'), - ], - visibility = [ - 'PUBLIC', - ], + name = "websocket", + srcs = glob(["**/*.java"]), + deps = [ + react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_dep("third-party/java/okhttp:okhttp3"), + react_native_dep("third-party/java/okhttp:okhttp3-ws"), + react_native_dep("third-party/java/okio:okio"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/modules/network:network"), + react_native_target("java/com/facebook/react/modules/blob:blob"), + ], + visibility = [ + "PUBLIC", + ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index 1fcc65c31a772f..2af34e8f364777 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -1,65 +1,65 @@ include_defs("//ReactAndroid/DEFS") android_library( - name = 'shell', - srcs = glob(['**/*.java']), - deps = [ - react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'), - react_native_dep('libraries/soloader/java/com/facebook/soloader:soloader'), - react_native_dep('third-party/android/support/v4:lib-support-v4'), - react_native_dep('third-party/java/infer-annotations:infer-annotations'), - react_native_dep('third-party/java/jsr-305:jsr-305'), - react_native_target('java/com/facebook/react:react'), - react_native_target('java/com/facebook/react/animated:animated'), - react_native_target('java/com/facebook/react/bridge:bridge'), - react_native_target('java/com/facebook/react/common:common'), - react_native_target('java/com/facebook/react/devsupport:devsupport'), - react_native_target('java/com/facebook/react/module/model:model'), - react_native_target('java/com/facebook/react/modules/appstate:appstate'), - react_native_target('java/com/facebook/react/modules/blob:blob'), - react_native_target('java/com/facebook/react/modules/camera:camera'), - react_native_target('java/com/facebook/react/modules/clipboard:clipboard'), - react_native_target('java/com/facebook/react/modules/core:core'), - react_native_target('java/com/facebook/react/modules/datepicker:datepicker'), - react_native_target('java/com/facebook/react/modules/debug:debug'), - react_native_target('java/com/facebook/react/modules/dialog:dialog'), - react_native_target('java/com/facebook/react/modules/fresco:fresco'), - react_native_target('java/com/facebook/react/modules/i18nmanager:i18nmanager'), - react_native_target('java/com/facebook/react/modules/image:image'), - react_native_target('java/com/facebook/react/modules/intent:intent'), - react_native_target('java/com/facebook/react/modules/location:location'), - react_native_target('java/com/facebook/react/modules/netinfo:netinfo'), - react_native_target('java/com/facebook/react/modules/network:network'), - react_native_target('java/com/facebook/react/modules/permissions:permissions'), - react_native_target('java/com/facebook/react/modules/share:share'), - react_native_target('java/com/facebook/react/modules/statusbar:statusbar'), - react_native_target('java/com/facebook/react/modules/storage:storage'), - react_native_target('java/com/facebook/react/modules/timepicker:timepicker'), - react_native_target('java/com/facebook/react/modules/toast:toast'), - react_native_target('java/com/facebook/react/modules/vibration:vibration'), - react_native_target('java/com/facebook/react/modules/websocket:websocket'), - react_native_target('java/com/facebook/react/uimanager:uimanager'), - react_native_target('java/com/facebook/react/views/art:art'), - react_native_target('java/com/facebook/react/views/drawer:drawer'), - react_native_target('java/com/facebook/react/views/image:image'), - react_native_target('java/com/facebook/react/views/modal:modal'), - react_native_target('java/com/facebook/react/views/picker:picker'), - react_native_target('java/com/facebook/react/views/progressbar:progressbar'), - react_native_target('java/com/facebook/react/views/recyclerview:recyclerview'), - react_native_target('java/com/facebook/react/views/scroll:scroll'), - react_native_target('java/com/facebook/react/views/slider:slider'), - react_native_target('java/com/facebook/react/views/swiperefresh:swiperefresh'), - react_native_target('java/com/facebook/react/views/switchview:switchview'), - react_native_target('java/com/facebook/react/views/text:text'), - react_native_target('java/com/facebook/react/views/text/frescosupport:frescosupport'), - react_native_target('java/com/facebook/react/views/textinput:textinput'), - react_native_target('java/com/facebook/react/views/toolbar:toolbar'), - react_native_target('java/com/facebook/react/views/view:view'), - react_native_target('java/com/facebook/react/views/viewpager:viewpager'), - react_native_target('java/com/facebook/react/views/webview:webview'), - react_native_target('res:shell'), - ], - visibility = [ - 'PUBLIC', - ], + name = "shell", + srcs = glob(["**/*.java"]), + deps = [ + react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"), + react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), + react_native_dep("third-party/android/support/v4:lib-support-v4"), + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_target("java/com/facebook/react:react"), + react_native_target("java/com/facebook/react/animated:animated"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/devsupport:devsupport"), + react_native_target("java/com/facebook/react/module/model:model"), + react_native_target("java/com/facebook/react/modules/appstate:appstate"), + react_native_target("java/com/facebook/react/modules/blob:blob"), + react_native_target("java/com/facebook/react/modules/camera:camera"), + react_native_target("java/com/facebook/react/modules/clipboard:clipboard"), + react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/modules/datepicker:datepicker"), + react_native_target("java/com/facebook/react/modules/debug:debug"), + react_native_target("java/com/facebook/react/modules/dialog:dialog"), + react_native_target("java/com/facebook/react/modules/fresco:fresco"), + react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"), + react_native_target("java/com/facebook/react/modules/image:image"), + react_native_target("java/com/facebook/react/modules/intent:intent"), + react_native_target("java/com/facebook/react/modules/location:location"), + react_native_target("java/com/facebook/react/modules/netinfo:netinfo"), + react_native_target("java/com/facebook/react/modules/network:network"), + react_native_target("java/com/facebook/react/modules/permissions:permissions"), + react_native_target("java/com/facebook/react/modules/share:share"), + react_native_target("java/com/facebook/react/modules/statusbar:statusbar"), + react_native_target("java/com/facebook/react/modules/storage:storage"), + react_native_target("java/com/facebook/react/modules/timepicker:timepicker"), + react_native_target("java/com/facebook/react/modules/toast:toast"), + react_native_target("java/com/facebook/react/modules/vibration:vibration"), + react_native_target("java/com/facebook/react/modules/websocket:websocket"), + react_native_target("java/com/facebook/react/uimanager:uimanager"), + react_native_target("java/com/facebook/react/views/art:art"), + react_native_target("java/com/facebook/react/views/drawer:drawer"), + react_native_target("java/com/facebook/react/views/image:image"), + react_native_target("java/com/facebook/react/views/modal:modal"), + react_native_target("java/com/facebook/react/views/picker:picker"), + react_native_target("java/com/facebook/react/views/progressbar:progressbar"), + react_native_target("java/com/facebook/react/views/recyclerview:recyclerview"), + react_native_target("java/com/facebook/react/views/scroll:scroll"), + react_native_target("java/com/facebook/react/views/slider:slider"), + react_native_target("java/com/facebook/react/views/swiperefresh:swiperefresh"), + react_native_target("java/com/facebook/react/views/switchview:switchview"), + react_native_target("java/com/facebook/react/views/text:text"), + react_native_target("java/com/facebook/react/views/text/frescosupport:frescosupport"), + react_native_target("java/com/facebook/react/views/textinput:textinput"), + react_native_target("java/com/facebook/react/views/toolbar:toolbar"), + react_native_target("java/com/facebook/react/views/view:view"), + react_native_target("java/com/facebook/react/views/viewpager:viewpager"), + react_native_target("java/com/facebook/react/views/webview:webview"), + react_native_target("res:shell"), + ], + visibility = [ + "PUBLIC", + ], ) diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK index 59153daa97bf38..77d073b5b41f7e 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK @@ -1,42 +1,42 @@ include_defs("//ReactAndroid/DEFS") rn_robolectric_test( - # Please change the contact to the oncall of your team - contacts = ['oncall+fbandroid_sheriff@xmail.facebook.com'], - name = 'modules', - srcs = glob(['**/*.java']), - deps = [ - YOGA_TARGET, - react_native_dep('libraries/fbcore/src/test/java/com/facebook/powermock:powermock'), - react_native_dep('third-party/java/fest:fest'), - react_native_dep('third-party/java/jsr-305:jsr-305'), - react_native_dep('third-party/java/junit:junit'), - react_native_dep('third-party/java/mockito:mockito'), - react_native_dep('third-party/java/okhttp:okhttp3'), - react_native_dep('third-party/java/okio:okio'), - react_native_dep('third-party/java/robolectric3/robolectric:robolectric'), - react_native_target('java/com/facebook/react/animation:animation'), - react_native_target('java/com/facebook/react/bridge:bridge'), - react_native_target('java/com/facebook/react/common/network:network'), - react_native_target('java/com/facebook/react/common:common'), - react_native_target('java/com/facebook/react/devsupport:devsupport'), - react_native_target('java/com/facebook/react/jstasks:jstasks'), - react_native_target('java/com/facebook/react/modules/blob:blob'), - react_native_target('java/com/facebook/react/modules/clipboard:clipboard'), - react_native_target('java/com/facebook/react/modules/common:common'), - react_native_target('java/com/facebook/react/modules/core:core'), - react_native_target('java/com/facebook/react/modules/debug:debug'), - react_native_target('java/com/facebook/react/modules/dialog:dialog'), - react_native_target('java/com/facebook/react/modules/network:network'), - react_native_target('java/com/facebook/react/modules/share:share'), - react_native_target('java/com/facebook/react/modules/storage:storage'), - react_native_target('java/com/facebook/react/modules/systeminfo:systeminfo'), - react_native_target('java/com/facebook/react/touch:touch'), - react_native_target('java/com/facebook/react/uimanager:uimanager'), - react_native_target('java/com/facebook/react:react'), - react_native_tests_target('java/com/facebook/react/bridge:testhelpers'), - ], - visibility = [ - 'PUBLIC' - ], + # Please change the contact to the oncall of your team + contacts = ["oncall+fbandroid_sheriff@xmail.facebook.com"], + name = "modules", + srcs = glob(["**/*.java"]), + deps = [ + YOGA_TARGET, + react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"), + react_native_dep("third-party/java/fest:fest"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_dep("third-party/java/junit:junit"), + react_native_dep("third-party/java/mockito:mockito"), + react_native_dep("third-party/java/okhttp:okhttp3"), + react_native_dep("third-party/java/okio:okio"), + react_native_dep("third-party/java/robolectric3/robolectric:robolectric"), + react_native_target("java/com/facebook/react/animation:animation"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/common/network:network"), + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/devsupport:devsupport"), + react_native_target("java/com/facebook/react/jstasks:jstasks"), + react_native_target("java/com/facebook/react/modules/blob:blob"), + react_native_target("java/com/facebook/react/modules/clipboard:clipboard"), + react_native_target("java/com/facebook/react/modules/common:common"), + react_native_target("java/com/facebook/react/modules/core:core"), + react_native_target("java/com/facebook/react/modules/debug:debug"), + react_native_target("java/com/facebook/react/modules/dialog:dialog"), + react_native_target("java/com/facebook/react/modules/network:network"), + react_native_target("java/com/facebook/react/modules/share:share"), + react_native_target("java/com/facebook/react/modules/storage:storage"), + react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo"), + react_native_target("java/com/facebook/react/touch:touch"), + react_native_target("java/com/facebook/react/uimanager:uimanager"), + react_native_target("java/com/facebook/react:react"), + react_native_tests_target("java/com/facebook/react/bridge:testhelpers"), + ], + visibility = [ + "PUBLIC" + ], ) From 9930649ef6ca9286a25b1827e0c89945d14a3f75 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 9 Jun 2017 17:06:13 +0530 Subject: [PATCH 23/66] Fix RNTester app --- RNTester/RNTester.xcodeproj/project.pbxproj | 85 ++++++++++----------- 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/RNTester/RNTester.xcodeproj/project.pbxproj b/RNTester/RNTester.xcodeproj/project.pbxproj index 2e783da6edbadc..4272f713c3bb84 100644 --- a/RNTester/RNTester.xcodeproj/project.pbxproj +++ b/RNTester/RNTester.xcodeproj/project.pbxproj @@ -37,7 +37,6 @@ 1497CFB01B21F5E400C1F8F2 /* RCTFontTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA81B21F5E400C1F8F2 /* RCTFontTests.m */; }; 1497CFB11B21F5E400C1F8F2 /* RCTEventDispatcherTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFA91B21F5E400C1F8F2 /* RCTEventDispatcherTests.m */; }; 1497CFB31B21F5E400C1F8F2 /* RCTUIManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */; }; - 14AADF051AC3DBB1002390C9 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14AADF041AC3DB95002390C9 /* libReact.a */; }; 14B6DA821B276C5900BF4DD1 /* libRCTTest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58005BEE1ABA80530062E044 /* libRCTTest.a */; }; 14D6D7111B220EB3001FB087 /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14D6D7101B220EB3001FB087 /* libOCMock.a */; }; 14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 147CED4B1AB34F8C00DA3E4C /* libRCTActionSheet.a */; }; @@ -119,9 +118,6 @@ 83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; }; 8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */; }; 8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */; }; - ADAC7A091E093BB900D77272 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */; }; - ADBDBA0D1DFEC24D00ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */; }; - ADD01A631E093FA900F6D226 /* libRCTBlob-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */; }; BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */; }; C654F0B31EB34A73000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F0B21EB34A73000B7A9A /* RNTesterTestModule.m */; }; C654F17E1EB34D24000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F0B21EB34A73000B7A9A /* RNTesterTestModule.m */; }; @@ -395,6 +391,20 @@ remoteGlobalIDString = 139D7E881E25C6D100323FB7; remoteInfo = "double-conversion"; }; + 527C9AD71EEABE7C007AF55D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 527C9ACC1EEABE7B007AF55D /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 52F260D91EE7167300F0B7B4; + remoteInfo = RCTBlob; + }; + 527C9AD91EEABE7C007AF55D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 527C9ACC1EEABE7B007AF55D /* RCTBlob.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 5241ACAB1EE769AD00F67468; + remoteInfo = "RCTBlob-tvOS"; + }; 58005BED1ABA80530062E044 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 58005BE41ABA80530062E044 /* RCTTest.xcodeproj */; @@ -409,20 +419,6 @@ remoteGlobalIDString = 134814201AA4EA6300B7C361; remoteInfo = RCTSettings; }; - ADBDB9F01DFEC24500ED6528 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 358F4ED71D1E81A9004DF814; - remoteInfo = RCTBlob; - }; - ADD01A461E093FA100F6D226 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = ADAC7A2E1E093EF800D77272; - remoteInfo = "RCTBlob-tvOS"; - }; D85B829B1AB6D5CE003F4FE2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */; @@ -506,13 +502,13 @@ 3D2AFAF41D646CF80089D1A3 /* legacy_image@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "legacy_image@2x.png"; path = "RNTester/legacy_image@2x.png"; sourceTree = ""; }; 3DB99D0B1BA0340600302749 /* RNTesterIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNTesterIntegrationTests.m; sourceTree = ""; }; 3DD981D51D33C6FB007DC7BE /* RNTesterUnitTestsBundle.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = RNTesterUnitTestsBundle.js; sourceTree = ""; }; + 527C9ACC1EEABE7B007AF55D /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; 58005BE41ABA80530062E044 /* RCTTest.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTTest.xcodeproj; path = ../Libraries/RCTTest/RCTTest.xcodeproj; sourceTree = ""; }; 68FF44371CF6111500720EFD /* RCTBundleURLProviderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBundleURLProviderTests.m; sourceTree = ""; }; 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTUIManagerScenarioTests.m; sourceTree = ""; }; 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderTests.m; sourceTree = ""; }; 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderHelpers.m; sourceTree = ""; }; 8385CF051B8747A000C6273E /* RCTImageLoaderHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTImageLoaderHelpers.h; sourceTree = ""; }; - ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = ""; }; BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenuTests.m; sourceTree = ""; }; C654F0B21EB34A73000B7A9A /* RNTesterTestModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNTesterTestModule.m; sourceTree = ""; }; D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = ""; }; @@ -524,7 +520,6 @@ buildActionMask = 2147483647; files = ( 192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */, - ADAC7A091E093BB900D77272 /* libRCTBlob.a in Frameworks */, 14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */, 14D6D71F1B2222EF001FB087 /* libRCTAdSupport.a in Frameworks */, 14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */, @@ -546,7 +541,6 @@ buildActionMask = 2147483647; files = ( 2D66FF8F1ECA406D00F0A767 /* libART.a in Frameworks */, - ADBDBA0D1DFEC24D00ED6528 /* libRCTBlob.a in Frameworks */, 147CED4C1AB3532B00DA3E4C /* libRCTActionSheet.a in Frameworks */, 134454601AAFCABD003F0779 /* libRCTAdSupport.a in Frameworks */, 13E501F11D07A84A005F35D8 /* libRCTAnimation.a in Frameworks */, @@ -591,7 +585,6 @@ 2DD323E61DA2DE3F000FE1B8 /* libRCTNetwork-tvOS.a in Frameworks */, 3D05746D1DE6008900184BB4 /* libRCTPushNotification-tvOS.a in Frameworks */, 2DD323E71DA2DE3F000FE1B8 /* libRCTSettings-tvOS.a in Frameworks */, - ADD01A631E093FA900F6D226 /* libRCTBlob-tvOS.a in Frameworks */, 2DD323E81DA2DE3F000FE1B8 /* libRCTText-tvOS.a in Frameworks */, 2DD323E91DA2DE3F000FE1B8 /* libRCTWebSocket-tvOS.a in Frameworks */, ); @@ -618,8 +611,8 @@ 1316A21D1AA397F400C0188E /* Libraries */ = { isa = PBXGroup; children = ( + 527C9ACC1EEABE7B007AF55D /* RCTBlob.xcodeproj */, 2D66FF5F1ECA405900F0A767 /* ART.xcodeproj */, - ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */, 14AADEFF1AC3DB95002390C9 /* React.xcodeproj */, 14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */, 134454551AAFCAAE003F0779 /* RCTAdSupport.xcodeproj */, @@ -896,6 +889,15 @@ path = RNTester/RNTesterBundle; sourceTree = ""; }; + 527C9ACD1EEABE7B007AF55D /* Products */ = { + isa = PBXGroup; + children = ( + 527C9AD81EEABE7C007AF55D /* libRCTBlob.a */, + 527C9ADA1EEABE7C007AF55D /* libRCTBlob-tvOS.a */, + ); + name = Products; + sourceTree = ""; + }; 58005BE51ABA80530062E044 /* Products */ = { isa = PBXGroup; children = ( @@ -944,15 +946,6 @@ name = Products; sourceTree = ""; }; - ADBDB9E91DFEC24500ED6528 /* Products */ = { - isa = PBXGroup; - children = ( - ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */, - ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */, - ); - name = Products; - sourceTree = ""; - }; D85B82921AB6D5CE003F4FE2 /* Products */ = { isa = PBXGroup; children = ( @@ -1148,8 +1141,8 @@ ProjectRef = 13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */; }, { - ProductGroup = ADBDB9E91DFEC24500ED6528 /* Products */; - ProjectRef = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */; + ProductGroup = 527C9ACD1EEABE7B007AF55D /* Products */; + ProjectRef = 527C9ACC1EEABE7B007AF55D /* RCTBlob.xcodeproj */; }, { ProductGroup = 138DEE031B9EDDDB007F4EA5 /* Products */; @@ -1452,32 +1445,32 @@ remoteRef = 3D507F431EBC88B700B56834 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 58005BEE1ABA80530062E044 /* libRCTTest.a */ = { + 527C9AD81EEABE7C007AF55D /* libRCTBlob.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = libRCTTest.a; - remoteRef = 58005BED1ABA80530062E044 /* PBXContainerItemProxy */; + path = libRCTBlob.a; + remoteRef = 527C9AD71EEABE7C007AF55D /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 834C36D21AF8DA610019C93C /* libRCTSettings.a */ = { + 527C9ADA1EEABE7C007AF55D /* libRCTBlob-tvOS.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = libRCTSettings.a; - remoteRef = 834C36D11AF8DA610019C93C /* PBXContainerItemProxy */; + path = "libRCTBlob-tvOS.a"; + remoteRef = 527C9AD91EEABE7C007AF55D /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */ = { + 58005BEE1ABA80530062E044 /* libRCTTest.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = libRCTBlob.a; - remoteRef = ADBDB9F01DFEC24500ED6528 /* PBXContainerItemProxy */; + path = libRCTTest.a; + remoteRef = 58005BED1ABA80530062E044 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */ = { + 834C36D21AF8DA610019C93C /* libRCTSettings.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = "libRCTBlob-tvOS.a"; - remoteRef = ADD01A461E093FA100F6D226 /* PBXContainerItemProxy */; + path = libRCTSettings.a; + remoteRef = 834C36D11AF8DA610019C93C /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */ = { From 8b6fd3f7e3cb37de1c4793d08553f96dbbb59923 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 9 Jun 2017 17:10:55 +0530 Subject: [PATCH 24/66] Fix BUCK --- .../java/com/facebook/react/modules/blob/BUCK | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK index 340846cdc5a325..c1985c06d9ef6c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -1,23 +1,19 @@ include_defs("//ReactAndroid/DEFS") android_library( - name = "blob", - srcs = glob(["**/*.java"]), - deps = [ - react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), - react_native_dep("third-party/android/support-annotations:android-support-annotations"), - react_native_dep("third-party/android/support/v4:lib-support-v4"), - react_native_dep("third-party/java/infer-annotations:infer-annotations"), - react_native_dep("third-party/java/jsr-305:jsr-305"), - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/module/annotations:annotations"), - ], - visibility = [ - "PUBLIC", - ], -) - -project_config( - src_target = ":blob", + name = "blob", + srcs = glob(["**/*.java"]), + visibility = [ + "PUBLIC", + ], + deps = [ + react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), + react_native_dep("third-party/android/support-annotations:android-support-annotations"), + react_native_dep("third-party/android/support/v4:lib-support-v4"), + react_native_dep("third-party/java/infer-annotations:infer-annotations"), + react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_target("java/com/facebook/react/bridge:bridge"), + react_native_target("java/com/facebook/react/common:common"), + react_native_target("java/com/facebook/react/module/annotations:annotations"), + ], ) From d0efa54fe30f44bed447d66fd78fe4ac7f99c815 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Mon, 12 Jun 2017 06:08:54 +0530 Subject: [PATCH 25/66] Respect specified encoding for readAsText --- Libraries/Blob/RCTFileReaderModule.m | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Libraries/Blob/RCTFileReaderModule.m b/Libraries/Blob/RCTFileReaderModule.m index d78e3931b488a6..2a9837d3b7f151 100644 --- a/Libraries/Blob/RCTFileReaderModule.m +++ b/Libraries/Blob/RCTFileReaderModule.m @@ -31,7 +31,15 @@ @implementation RCTFileReaderModule reject(RCTErrorUnspecified, [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil); } else { - NSString *text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSStringEncoding stringEncoding; + + if (encoding == nil) { + stringEncoding = NSUTF8StringEncoding; + } else { + stringEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encoding)); + } + + NSString *text = [[NSString alloc] initWithData:data encoding:stringEncoding]; resolve(text); } From 5c2dd2c9386b43d8c67a1c82f48b84209733d6c8 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 3 Aug 2017 13:50:37 +0200 Subject: [PATCH 26/66] Attempt to merge #23102931 --- Libraries/Blob/Blob.js | 73 +---------- Libraries/Blob/BlobTypes.js | 9 +- .../Blob/RCTBlob.xcodeproj/project.pbxproj | 115 ++---------------- Libraries/Blob/RCTBlobManager.h | 18 --- Libraries/Blob/RCTBlobManager.m | 70 ++--------- Libraries/Blob/RCTFileReaderModule.h | 2 - Libraries/Blob/RCTFileReaderModule.m | 2 + Libraries/Blob/URL.js | 19 --- .../java/com/facebook/react/modules/blob/BUCK | 6 - .../react/modules/blob/BlobModule.java | 96 +-------------- .../react/modules/blob/BlobProvider.java | 43 ------- 11 files changed, 33 insertions(+), 420 deletions(-) diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 3bec9311ebf5d3..74fd897ec849ce 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -12,16 +12,12 @@ 'use strict'; -<<<<<<< HEAD -import type { BlobData, BlobOptions } from './BlobTypes'; -======= const invariant = require('fbjs/lib/invariant'); const uuid = require('uuid'); const { BlobModule } = require('NativeModules'); -import type { BlobProps } from 'BlobTypes'; ->>>>>>> master +import type { BlobProps, BlobData, BlobOptions } from 'BlobTypes'; /** * Opaque JS representation of some binary data in native. @@ -61,61 +57,16 @@ import type { BlobProps } from 'BlobTypes'; * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob */ class Blob { -<<<<<<< HEAD _data: ?BlobData; -======= - /** - * Size of the data contained in the Blob object, in bytes. - */ - size: number; - /* - * String indicating the MIME type of the data contained in the Blob. - * If the type is unknown, this string is empty. - */ - type: string; - - /* - * Unique id to identify the blob on native side (non-standard) - */ - blobId: string; - /* - * Offset to indicate part of blob, used when sliced (non-standard) - */ - offset: number; - - /** - * Construct blob instance from blob data from native. - * Used internally by modules like XHR, WebSocket, etc. - */ - static create(props: BlobProps): Blob { - return Object.assign(Object.create(Blob.prototype), props); - } ->>>>>>> master /** * Constructor for JS consumers. * Currently we only support creating Blobs from other Blobs. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob */ -<<<<<<< HEAD - constructor(parts: Array = [], options: BlobOptions) { - const BlobManager = require('BlobManager'); - this.data = BlobManager.createFromParts(parts, options).data; -======= constructor(parts: Array, options: any) { - const blobId = uuid(); - let size = 0; - parts.forEach((part) => { - invariant(part instanceof Blob, 'Can currently only create a Blob from other Blobs'); - size += part.size; - }); - BlobModule.createFromParts(parts, blobId); - return Blob.create({ - blobId, - offset: 0, - size, - }); ->>>>>>> master + const BlobManager = require('BlobManager'); + this.data = BlobManager.createFromParts(parts).data; } /* @@ -123,7 +74,6 @@ class Blob { * the data in the specified range of bytes of the source Blob. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice */ -<<<<<<< HEAD set data(data: ?BlobData) { this._data = data; } @@ -137,12 +87,8 @@ class Blob { slice(start?: number, end?: number): Blob { const BlobManager = require('BlobManager'); - let { size, offset } = this.data; -======= - slice(start?: number, end?: number): Blob { - let offset = this.offset; - let size = this.size; ->>>>>>> master + let { offset, size } = this.data; + if (typeof start === 'number') { if (start > size) { start = size; @@ -157,13 +103,8 @@ class Blob { size = end - start; } } -<<<<<<< HEAD return BlobManager.createFromOptions({ blobId: this.data.blobId, -======= - return Blob.create({ - blobId: this.blobId, ->>>>>>> master offset, size, }); @@ -182,7 +123,6 @@ class Blob { * `new Blob([blob, ...])` actually copies the data in memory. */ close() { -<<<<<<< HEAD const BlobManager = require('BlobManager'); BlobManager.release(this.data.blobId); this.data = null; @@ -201,9 +141,6 @@ class Blob { */ get type(): string { return this.data.type || ''; -======= - BlobModule.release(this.blobId); ->>>>>>> master } } diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js index 8201df47bc306f..684ca9e135c55a 100644 --- a/Libraries/Blob/BlobTypes.js +++ b/Libraries/Blob/BlobTypes.js @@ -12,14 +12,15 @@ 'use strict'; -export type BlobProps = { +export type BlobData = { blobId: string, offset: number, size: number, type?: string, + lastModified?: number, }; -export type FileProps = BlobProps & { - name: string, - lastModified: number, +export type BlobOptions = { + type: string, + endings: "transparent" | "native", }; diff --git a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj index 1b896338d1c73f..09d9e76c89b3f7 100755 --- a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj +++ b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj @@ -7,29 +7,17 @@ objects = { /* Begin PBXBuildFile section */ -<<<<<<< HEAD - 5241ACAD1EE8595100F67468 /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 5241ACAC1EE8595100F67468 /* RCTFileReaderModule.m */; }; - 5241ACAE1EE8595100F67468 /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 5241ACAC1EE8595100F67468 /* RCTFileReaderModule.m */; }; -======= AD0871131E215B28007D136D /* RCTBlobManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; AD0871161E215EC9007D136D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; AD0871181E215ED1007D136D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; AD08711A1E2162C8007D136D /* RCTBlobManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; ->>>>>>> master AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; + ADDFBA6C1F33455F0064C998 /* RCTFileReaderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; }; + ADDFBA6D1F33455F0064C998 /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ -<<<<<<< HEAD - 358F4ED51D1E81A9004DF814 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "include/$(PRODUCT_NAME)"; - dstSubfolderSpec = 16; - files = ( - ); -======= 358F4ED51D1E81A9004DF814 /* Copy Headers */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -50,52 +38,25 @@ AD0871131E215B28007D136D /* RCTBlobManager.h in Copy Headers */, ); name = "Copy Headers"; ->>>>>>> master runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ -<<<<<<< HEAD - 5241ACAB1EE769AD00F67468 /* libRCTBlob-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTBlob-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 5241ACAC1EE8595100F67468 /* RCTFileReaderModule.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = RCTFileReaderModule.m; sourceTree = ""; tabWidth = 2; }; - 5241ACAF1EE8598200F67468 /* RCTFileReaderModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTFileReaderModule.h; sourceTree = ""; }; - 52F260D91EE7167300F0B7B4 /* libRCTBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBlob.a; sourceTree = BUILT_PRODUCTS_DIR; }; - AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBlobManager.h; sourceTree = ""; }; - AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBlobManager.m; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 358F4ED41D1E81A9004DF814 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -======= 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBlob.a; sourceTree = BUILT_PRODUCTS_DIR; }; AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBlobManager.h; sourceTree = ""; }; AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBlobManager.m; sourceTree = ""; }; ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTBlob-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFileReaderModule.h; sourceTree = ""; }; + ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFileReaderModule.m; sourceTree = ""; }; /* End PBXFileReference section */ ->>>>>>> master /* Begin PBXGroup section */ 358F4ECE1D1E81A9004DF814 = { isa = PBXGroup; children = ( -<<<<<<< HEAD - 5241ACAC1EE8595100F67468 /* RCTFileReaderModule.m */, - 5241ACAF1EE8598200F67468 /* RCTFileReaderModule.h */, - AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */, - AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */, - 52F260D91EE7167300F0B7B4 /* libRCTBlob.a */, - 5241ACAB1EE769AD00F67468 /* libRCTBlob-tvOS.a */, - ); -======= + ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */, + ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */, AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */, AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */, 358F4ED81D1E81A9004DF814 /* Products */, @@ -112,19 +73,17 @@ ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */, ); name = Products; ->>>>>>> master sourceTree = ""; }; /* End PBXGroup section */ -<<<<<<< HEAD -======= /* Begin PBXHeadersBuildPhase section */ AD0871151E215EB7007D136D /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( AD0871161E215EC9007D136D /* RCTBlobManager.h in Headers */, + ADDFBA6C1F33455F0064C998 /* RCTFileReaderModule.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -138,21 +97,14 @@ }; /* End PBXHeadersBuildPhase section */ ->>>>>>> master /* Begin PBXNativeTarget section */ 358F4ED61D1E81A9004DF814 /* RCTBlob */ = { isa = PBXNativeTarget; buildConfigurationList = 358F4EE01D1E81A9004DF814 /* Build configuration list for PBXNativeTarget "RCTBlob" */; buildPhases = ( -<<<<<<< HEAD - 358F4ED31D1E81A9004DF814 /* Sources */, - 358F4ED41D1E81A9004DF814 /* Frameworks */, - 358F4ED51D1E81A9004DF814 /* CopyFiles */, -======= AD0871151E215EB7007D136D /* Headers */, 358F4ED51D1E81A9004DF814 /* Copy Headers */, 358F4ED31D1E81A9004DF814 /* Sources */, ->>>>>>> master ); buildRules = ( ); @@ -160,22 +112,15 @@ ); name = RCTBlob; productName = SLKBlobs; -<<<<<<< HEAD - productReference = 52F260D91EE7167300F0B7B4 /* libRCTBlob.a */; -======= productReference = 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */; ->>>>>>> master productType = "com.apple.product-type.library.static"; }; ADD01A671E09402E00F6D226 /* RCTBlob-tvOS */ = { isa = PBXNativeTarget; buildConfigurationList = ADD01A6E1E09402E00F6D226 /* Build configuration list for PBXNativeTarget "RCTBlob-tvOS" */; buildPhases = ( -<<<<<<< HEAD -======= AD0871171E215ECC007D136D /* Headers */, AD0871121E215B16007D136D /* Copy Headers */, ->>>>>>> master ADD01A641E09402E00F6D226 /* Sources */, ); buildRules = ( @@ -184,11 +129,7 @@ ); name = "RCTBlob-tvOS"; productName = "RCTBlob-tvOS"; -<<<<<<< HEAD - productReference = 5241ACAB1EE769AD00F67468 /* libRCTBlob-tvOS.a */; -======= productReference = ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */; ->>>>>>> master productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ @@ -217,11 +158,7 @@ en, ); mainGroup = 358F4ECE1D1E81A9004DF814; -<<<<<<< HEAD - productRefGroup = 358F4ECE1D1E81A9004DF814; -======= productRefGroup = 358F4ED81D1E81A9004DF814 /* Products */; ->>>>>>> master projectDirPath = ""; projectRoot = ""; targets = ( @@ -236,10 +173,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( -<<<<<<< HEAD - 5241ACAD1EE8595100F67468 /* RCTFileReaderModule.m in Sources */, -======= ->>>>>>> master + ADDFBA6D1F33455F0064C998 /* RCTFileReaderModule.m in Sources */, AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -248,10 +182,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( -<<<<<<< HEAD - 5241ACAE1EE8595100F67468 /* RCTFileReaderModule.m in Sources */, -======= ->>>>>>> master ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -296,18 +226,11 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; -<<<<<<< HEAD - IPHONEOS_DEPLOYMENT_TARGET = 9.3; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; -======= IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SKIP_INSTALL = YES; ->>>>>>> master }; name = Debug; }; @@ -342,16 +265,10 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; -<<<<<<< HEAD - IPHONEOS_DEPLOYMENT_TARGET = 9.3; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; -======= IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SKIP_INSTALL = YES; ->>>>>>> master VALIDATE_PRODUCT = YES; }; name = Release; @@ -359,14 +276,6 @@ 358F4EE11D1E81A9004DF814 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { -<<<<<<< HEAD - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/../../React/**", - "$(SRCROOT)/../../ReactCommon/**", - ); -======= ->>>>>>> master OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -376,14 +285,6 @@ 358F4EE21D1E81A9004DF814 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { -<<<<<<< HEAD - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "$(SRCROOT)/../../React/**", - "$(SRCROOT)/../../ReactCommon/**", - ); -======= ->>>>>>> master OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/Libraries/Blob/RCTBlobManager.h b/Libraries/Blob/RCTBlobManager.h index d791b9407de17f..03b3ffc60a6fb4 100755 --- a/Libraries/Blob/RCTBlobManager.h +++ b/Libraries/Blob/RCTBlobManager.h @@ -13,22 +13,4 @@ @interface RCTBlobManager : NSObject -<<<<<<< HEAD -- (NSString *)store:(NSData *)data; - -- (NSData *)resolve:(NSDictionary *)blob; - -- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size; - -- (void)release:(NSString *)blobId; - -@end - - -@interface RCTBridge (RCTBlobManager) - -@property (nonatomic, readonly) RCTBlobManager *blobs; - -======= ->>>>>>> master @end diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.m index 6ee980b9de1edf..38d9c2a1ecca1c 100755 --- a/Libraries/Blob/RCTBlobManager.m +++ b/Libraries/Blob/RCTBlobManager.m @@ -10,14 +10,6 @@ #import "RCTBlobManager.h" #import -<<<<<<< HEAD - -static NSString *const kBlobUriScheme = @"blob"; - -@implementation RCTBlobManager -{ - NSMutableDictionary *_blobs; -======= #import static NSString *const kBlobUriScheme = @"blob"; @@ -28,22 +20,17 @@ - (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager; @end - @implementation RCTBlobManager { NSMutableDictionary *_blobs; _RCTBlobContentHandler *_contentHandler; ->>>>>>> master NSOperationQueue *_queue; } RCT_EXPORT_MODULE(BlobModule) -<<<<<<< HEAD -======= @synthesize bridge = _bridge; ->>>>>>> master - (NSDictionary *)constantsToExport { return @{ @@ -52,14 +39,11 @@ @implementation RCTBlobManager }; } -<<<<<<< HEAD -======= - (dispatch_queue_t)methodQueue { return [[_bridge webSocketModule] methodQueue]; } ->>>>>>> master - (NSString *)store:(NSData *)data { NSString *blobId = [NSUUID UUID].UUIDString; @@ -72,10 +56,6 @@ - (void)store:(NSData *)data withId:(NSString *)blobId if (!_blobs) { _blobs = [NSMutableDictionary new]; } -<<<<<<< HEAD -======= - ->>>>>>> master _blobs[blobId] = data; } @@ -84,10 +64,6 @@ - (NSData *)resolve:(NSDictionary *)blob NSString *blobId = [RCTConvert NSString:blob[@"blobId"]]; NSNumber *offset = [RCTConvert NSNumber:blob[@"offset"]]; NSNumber *size = [RCTConvert NSNumber:blob[@"size"]]; -<<<<<<< HEAD -======= - ->>>>>>> master return [self resolve:blobId offset:offset ? [offset integerValue] : 0 size:size ? [size integerValue] : -1]; @@ -105,28 +81,6 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) return data; } -<<<<<<< HEAD -RCT_EXPORT_METHOD(createFromParts:(NSArray *> *)parts withId:(NSString *)blobId) -{ - NSMutableData *blob = [NSMutableData new]; - - for (NSDictionary *part in parts) { - NSString *type = [RCTConvert NSString:part[@"type"]]; - - if ([type isEqualToString:@"blob"]) { - NSDictionary *data = [RCTConvert NSDictionary:part[@"data"]]; - NSData *partData = [self resolve:data]; - [blob appendData:partData]; - } else if ([type isEqualToString:@"string"]) { - NSData *data = [[RCTConvert NSString:part[@"data"]] dataUsingEncoding:NSUTF8StringEncoding]; - [blob appendData:data]; - } else { - [NSException raise:@"Invalid type for blob" format:@"%@ is invalid", type]; - } - } - - [self store:blob withId:blobId]; -======= RCT_EXPORT_METHOD(enableBlobSupport:(nonnull NSNumber *)socketID) { if (!_contentHandler) { @@ -149,11 +103,20 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) { NSMutableData *data = [NSMutableData new]; for (NSDictionary *part in parts) { - NSData *partData = [self resolve:part]; - [data appendData:partData]; + NSString *type = [RCTConvert NSString:part[@"type"]]; + + if ([type isEqualToString:@"blob"]) { + NSDictionary *data = [RCTConvert NSDictionary:part[@"data"]]; + NSData *partData = [self resolve:data]; + [blob appendData:partData]; + } else if ([type isEqualToString:@"string"]) { + NSData *data = [[RCTConvert NSString:part[@"data"]] dataUsingEncoding:NSUTF8StringEncoding]; + [blob appendData:data]; + } else { + [NSException raise:@"Invalid type for blob" format:@"%@ is invalid", type]; + } } [self store:data withId:blobId]; ->>>>>>> master } RCT_EXPORT_METHOD(release:(NSString *)blobId) @@ -227,14 +190,6 @@ - (void)cancelRequest:(NSOperation *)op @end -<<<<<<< HEAD - -@implementation RCTBridge (RCTBlobManager) - -- (RCTBlobManager *)blobs -{ - return [self moduleForClass:[RCTBlobManager class]]; -======= @implementation _RCTBlobContentHandler { __weak RCTBlobManager *_blobManager; } @@ -260,7 +215,6 @@ - (id)processMessage:(id)message forSocketID:(NSNumber *)socketID withType:(NSSt @"offset": @0, @"size": @(((NSData *)message).length), }; ->>>>>>> master } @end diff --git a/Libraries/Blob/RCTFileReaderModule.h b/Libraries/Blob/RCTFileReaderModule.h index ae04933b8e69f5..8728c7c3dc0b67 100644 --- a/Libraries/Blob/RCTFileReaderModule.h +++ b/Libraries/Blob/RCTFileReaderModule.h @@ -11,6 +11,4 @@ @interface RCTFileReaderModule : NSObject -@property (nonatomic, weak) RCTBridge *bridge; - @end diff --git a/Libraries/Blob/RCTFileReaderModule.m b/Libraries/Blob/RCTFileReaderModule.m index 2a9837d3b7f151..b18cd2f2a685be 100644 --- a/Libraries/Blob/RCTFileReaderModule.m +++ b/Libraries/Blob/RCTFileReaderModule.m @@ -19,6 +19,8 @@ @implementation RCTFileReaderModule RCT_EXPORT_MODULE(FileReaderModule) +@synthesize bridge = _bridge; + RCT_EXPORT_METHOD(readAsText:(NSDictionary *)blob encoding:(NSString *)encoding resolve:(RCTPromiseResolveBlock)resolve diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index e013544cecc5d5..6db176b0250928 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -9,19 +9,12 @@ * @providesModule URL * @flow */ -<<<<<<< HEAD -'use strict'; - -const Blob = require('Blob'); -const { BlobModule } = require('react-native').NativeModules; -======= 'use strict'; const Blob = require('Blob'); const { BlobModule } = require('NativeModules'); ->>>>>>> master let BLOB_URL_PREFIX = null; @@ -47,12 +40,8 @@ if (typeof BlobModule.BLOB_URI_SCHEME === 'string') { * * * ``` -<<<<<<< HEAD - * And then define the `blob_provider_authority` string in `res/values/strings.xml`. Use a dotted name that's entirely unique to your app: -======= * And then define the `blob_provider_authority` string in `res/values/strings.xml`. * Use a dotted name that's entirely unique to your app: ->>>>>>> master * * ```xml * @@ -62,22 +51,14 @@ if (typeof BlobModule.BLOB_URI_SCHEME === 'string') { */ class URL { constructor() { -<<<<<<< HEAD throw new Error('Creating URL objects is not supported yet.'); -======= - throw new Error('Creating BlobURL objects is not supported yet.'); ->>>>>>> master } static createObjectURL(blob: Blob) { if (BLOB_URL_PREFIX === null) { throw new Error('Cannot create URL for blob!'); } -<<<<<<< HEAD - return `${BLOB_URL_PREFIX}${blob.data.blobId}?offset=${blob.data.offset}&size=${blob.size}`; -======= return `${BLOB_URL_PREFIX}${blob.blobId}?offset=${blob.offset}&size=${blob.size}`; ->>>>>>> master } static revokeObjectURL(url: string) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK index 1409adff22f9d1..936f5e5719dc73 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -12,17 +12,11 @@ android_library( react_native_dep("third-party/android/support/v4:lib-support-v4"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), -<<<<<<< HEAD - react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/module/annotations:annotations"), -======= react_native_dep("third-party/java/okio:okio"), react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("java/com/facebook/react/modules/websocket:websocket"), ->>>>>>> master ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 42be984de9a2c2..bdac246ba99092 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -1,25 +1,4 @@ /** -<<<<<<< HEAD - * 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. - */ - -package com.facebook.react.modules.blob; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.database.Cursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.support.annotation.Nullable; -import android.webkit.MimeTypeMap; - -======= * 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 @@ -31,7 +10,6 @@ import android.content.res.Resources; import android.net.Uri; import android.support.annotation.Nullable; ->>>>>>> master import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -41,30 +19,13 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; -<<<<<<< HEAD - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -======= import com.facebook.react.modules.websocket.WebSocketModule; import java.nio.ByteBuffer; ->>>>>>> master import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.UUID; -<<<<<<< HEAD - -@ReactModule(name = "BlobModule") -public class BlobModule extends ReactContextBaseJavaModule { - -======= import okio.ByteString; @ReactModule(name = BlobModule.NAME) @@ -96,18 +57,13 @@ public void onMessage(ByteString bytes, WritableMap params) { } }; ->>>>>>> master public BlobModule(ReactApplicationContext reactContext) { super(reactContext); } @Override public String getName() { -<<<<<<< HEAD - return "BlobModule"; -======= return NAME; ->>>>>>> master } @Override @@ -123,37 +79,15 @@ public Map getConstants() { } return MapBuilder.of( -<<<<<<< HEAD - "BLOB_URI_SCHEME", "content", - "BLOB_URI_HOST", resources.getString(resourceId)); - } - - private static Map sBlobs = new HashMap<>(); - - private static void store(byte[] data, String blobId) { - sBlobs.put(blobId, data); - } - - public static String store(byte[] data) { -======= "BLOB_URI_SCHEME", "content", "BLOB_URI_HOST", resources.getString(resourceId)); } public String store(byte[] data) { ->>>>>>> master String blobId = UUID.randomUUID().toString(); store(data, blobId); return blobId; } -<<<<<<< HEAD - public static void remove(String blobId) { - sBlobs.remove(blobId); - } - - @Nullable - public static byte[] resolve(Uri uri) { -======= public void store(byte[] data, String blobId) { mBlobs.put(blobId, data); } @@ -164,7 +98,6 @@ public void remove(String blobId) { @Nullable public byte[] resolve(Uri uri) { ->>>>>>> master String blobId = uri.getLastPathSegment(); int offset = 0; int size = -1; @@ -180,32 +113,21 @@ public byte[] resolve(Uri uri) { } @Nullable -<<<<<<< HEAD - public static byte[] resolve(String blobId, int offset, int size) { - byte[] data = sBlobs.get(blobId); - if (data == null){ -======= public byte[] resolve(String blobId, int offset, int size) { byte[] data = mBlobs.get(blobId); if (data == null) { ->>>>>>> master return null; } if (size == -1) { size = data.length - offset; } -<<<<<<< HEAD if (offset >= 0) { -======= - if (offset > 0) { ->>>>>>> master data = Arrays.copyOfRange(data, offset, offset + size); } return data; } @Nullable -<<<<<<< HEAD public static byte[] resolve(ReadableMap blob) { return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); } @@ -285,11 +207,8 @@ private static String getMimeTypeFromUri(Uri contentUri, ContentResolver resolve } return type; -======= - public byte[] resolve(ReadableMap blob) { - return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); } - + private WebSocketModule getWebSocketModule() { return getReactApplicationContext().getNativeModule(WebSocketModule.class); } @@ -313,13 +232,11 @@ public void sendBlob(ReadableMap blob, int id) { } else { getWebSocketModule().sendBinary((ByteString) null, id); } ->>>>>>> master } @ReactMethod public void createFromParts(ReadableArray parts, String blobId) { int totalBlobSize = 0; -<<<<<<< HEAD ArrayList partList = new ArrayList<>(parts.size()); for (int i = 0; i < parts.size(); i++) { ReadableMap part = parts.getMap(i); @@ -341,17 +258,6 @@ public void createFromParts(ReadableArray parts, String blobId) { ByteBuffer buffer = ByteBuffer.allocate(totalBlobSize); for (byte[] bytes : partList) { buffer.put(bytes); -======= - ArrayList partList = new ArrayList<>(parts.size()); - for (int i = 0; i < parts.size(); i++) { - ReadableMap part = parts.getMap(i); - totalBlobSize += part.getInt("size"); - partList.add(i, part); - } - ByteBuffer buffer = ByteBuffer.allocate(totalBlobSize); - for (ReadableMap part : partList) { - buffer.put(resolve(part)); ->>>>>>> master } store(buffer.array(), blobId); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java index 83d2805455b2e3..2404f2dbab1393 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobProvider.java @@ -1,40 +1,22 @@ /** -<<<<<<< HEAD - * 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. - */ - -======= * 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. */ ->>>>>>> master package com.facebook.react.modules.blob; import android.content.ContentProvider; import android.content.ContentValues; -<<<<<<< HEAD -======= import android.content.Context; ->>>>>>> master import android.database.Cursor; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.support.annotation.Nullable; -<<<<<<< HEAD - -======= import com.facebook.react.ReactApplication; import com.facebook.react.ReactNativeHost; import com.facebook.react.bridge.ReactContext; ->>>>>>> master import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; @@ -43,26 +25,6 @@ public final class BlobProvider extends ContentProvider { @Override public boolean onCreate() { -<<<<<<< HEAD - return false; - } - - @Nullable - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - return null; - } - - @Nullable - @Override - public String getType(Uri uri) { - return null; - } - - @Nullable - @Override - public Uri insert(Uri uri, ContentValues values) { -======= return true; } @@ -79,7 +41,6 @@ public Uri insert(Uri uri, ContentValues values) { @Override public @Nullable Uri insert(Uri uri, ContentValues values) { ->>>>>>> master return null; } @@ -98,9 +59,6 @@ public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundEx if (!mode.equals("r")) { throw new FileNotFoundException("Cannot open " + uri.toString() + " in mode '" + mode + "'"); } -<<<<<<< HEAD - byte[] data = BlobModule.resolve(uri); -======= BlobModule blobModule = null; Context context = getContext().getApplicationContext(); @@ -115,7 +73,6 @@ public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundEx } byte[] data = blobModule.resolve(uri); ->>>>>>> master if (data == null) { throw new FileNotFoundException("Cannot open " + uri.toString() + ", blob not found."); } From 5fc2acbdab8c7d8e33c09764bf5051beceeff5f6 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Thu, 3 Aug 2017 15:18:38 +0200 Subject: [PATCH 27/66] Some fixes --- Libraries/WebSocket/WebSocket.js | 1 - .../react/modules/blob/BlobModule.java | 30 +++- .../modules/websocket/WebSocketModule.java | 163 ++++++++---------- 3 files changed, 91 insertions(+), 103 deletions(-) diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 4a66f129b325eb..04c0405f234461 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -14,7 +14,6 @@ const Blob = require('Blob'); const EventTarget = require('event-target-shim'); const NativeEventEmitter = require('NativeEventEmitter'); -const Blob = require('Blob'); const BlobManager = require('BlobManager'); const NativeModules = require('NativeModules'); const Platform = require('Platform'); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index bdac246ba99092..12ef20d4835705 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -7,9 +7,15 @@ */ package com.facebook.react.modules.blob; +import android.content.ContentResolver; +import android.content.Context; import android.content.res.Resources; +import android.database.Cursor; import android.net.Uri; +import android.provider.MediaStore; import android.support.annotation.Nullable; +import android.webkit.MimeTypeMap; + import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -20,12 +26,20 @@ import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; import com.facebook.react.modules.websocket.WebSocketModule; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.UUID; + import okio.ByteString; @ReactModule(name = BlobModule.NAME) @@ -33,9 +47,9 @@ public class BlobModule extends ReactContextBaseJavaModule { protected static final String NAME = "BlobModule"; - private final Map mBlobs = new HashMap<>(); + private static final Map mBlobs = new HashMap<>(); - protected final WebSocketModule.ContentHandler mContentHandler = + protected static final WebSocketModule.ContentHandler BlobHandler = new WebSocketModule.ContentHandler() { @Override public void onMessage(String text, WritableMap params) { @@ -82,22 +96,22 @@ public Map getConstants() { "BLOB_URI_SCHEME", "content", "BLOB_URI_HOST", resources.getString(resourceId)); } - public String store(byte[] data) { + public static String store(byte[] data) { String blobId = UUID.randomUUID().toString(); store(data, blobId); return blobId; } - public void store(byte[] data, String blobId) { + public static void store(byte[] data, String blobId) { mBlobs.put(blobId, data); } - public void remove(String blobId) { + public static void remove(String blobId) { mBlobs.remove(blobId); } @Nullable - public byte[] resolve(Uri uri) { + public static byte[] resolve(Uri uri) { String blobId = uri.getLastPathSegment(); int offset = 0; int size = -1; @@ -113,7 +127,7 @@ public byte[] resolve(Uri uri) { } @Nullable - public byte[] resolve(String blobId, int offset, int size) { + public static byte[] resolve(String blobId, int offset, int size) { byte[] data = mBlobs.get(blobId); if (data == null) { return null; @@ -215,7 +229,7 @@ private WebSocketModule getWebSocketModule() { @ReactMethod public void enableBlobSupport(final int id) { - getWebSocketModule().setContentHandler(id, mContentHandler); + getWebSocketModule().setContentHandler(id, BlobHandler); } @ReactMethod diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java index c5362b8330724a..8acd6c5458f76e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java @@ -22,7 +22,6 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.ReactConstants; import com.facebook.react.module.annotations.ReactModule; -import com.facebook.react.modules.blob.BlobModule; import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.network.ForwardingCookieHandler; import java.io.IOException; @@ -63,8 +62,8 @@ public WebSocketModule(ReactApplicationContext context) { private void sendEvent(String eventName, WritableMap params) { mReactContext - .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit(eventName, params); + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); } @Override @@ -82,15 +81,15 @@ public void setContentHandler(final int id, final ContentHandler contentHandler) @ReactMethod public void connect( - final String url, - @Nullable final ReadableArray protocols, - @Nullable final ReadableMap headers, - final int id) { + final String url, + @Nullable final ReadableArray protocols, + @Nullable final ReadableMap headers, + final int id) { OkHttpClient client = new OkHttpClient.Builder() - .connectTimeout(10, TimeUnit.SECONDS) - .writeTimeout(10, TimeUnit.SECONDS) - .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read - .build(); + .connectTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read + .build(); Request.Builder builder = new Request.Builder().tag(id).url(url); @@ -112,8 +111,8 @@ public void connect( builder.addHeader(key, headers.getString(key)); } else { FLog.w( - ReactConstants.TAG, - "Ignoring: requested " + key + ", value not a string"); + ReactConstants.TAG, + "Ignoring: requested " + key + ", value not a string"); } } } else { @@ -136,64 +135,64 @@ public void connect( } client.newWebSocket( - builder.build(), - new WebSocketListener() { - - @Override - public void onOpen(WebSocket webSocket, Response response) { - mWebSocketConnections.put(id, webSocket); - WritableMap params = Arguments.createMap(); - params.putInt("id", id); - sendEvent("websocketOpen", params); - } + builder.build(), + new WebSocketListener() { + + @Override + public void onOpen(WebSocket webSocket, Response response) { + mWebSocketConnections.put(id, webSocket); + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + sendEvent("websocketOpen", params); + } - @Override - public void onClosed(WebSocket webSocket, int code, String reason) { - WritableMap params = Arguments.createMap(); - params.putInt("id", id); - params.putInt("code", code); - params.putString("reason", reason); - sendEvent("websocketClosed", params); - } + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putInt("code", code); + params.putString("reason", reason); + sendEvent("websocketClosed", params); + } - @Override - public void onFailure(WebSocket webSocket, Throwable t, Response response) { - notifyWebSocketFailed(id, t.getMessage()); - } + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + notifyWebSocketFailed(id, t.getMessage()); + } - @Override - public void onMessage(WebSocket webSocket, String text) { - WritableMap params = Arguments.createMap(); - params.putInt("id", id); - params.putString("type", "text"); - - ContentHandler contentHandler = mContentHandlers.get(id); - if (contentHandler != null) { - contentHandler.onMessage(text, params); - } else { - params.putString("data", text); - } - sendEvent("websocketMessage", params); + @Override + public void onMessage(WebSocket webSocket, String text) { + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putString("type", "text"); + + ContentHandler contentHandler = mContentHandlers.get(id); + if (contentHandler != null) { + contentHandler.onMessage(text, params); + } else { + params.putString("data", text); } + sendEvent("websocketMessage", params); + } - @Override - public void onMessage(WebSocket webSocket, ByteString bytes) { - WritableMap params = Arguments.createMap(); - params.putInt("id", id); - params.putString("type", "binary"); - - ContentHandler contentHandler = mContentHandlers.get(id); - if (contentHandler != null) { - contentHandler.onMessage(bytes, params); - } else { - String text = bytes.base64(); + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putString("type", "binary"); - params.putString("data", text); - } + ContentHandler contentHandler = mContentHandlers.get(id); + if (contentHandler != null) { + contentHandler.onMessage(bytes, params); + } else { + String text = bytes.base64(); - sendEvent("websocketMessage", params); + params.putString("data", text); } - }); + + sendEvent("websocketMessage", params); + } + }); // Trigger shutdown of the dispatcher's executor so this process can exit cleanly client.dispatcher().executorService().shutdown(); @@ -213,9 +212,9 @@ public void close(int code, String reason, int id) { mContentHandlers.remove(id); } catch (Exception e) { FLog.e( - ReactConstants.TAG, - "Could not close WebSocket connection for id " + id, - e); + ReactConstants.TAG, + "Could not close WebSocket connection for id " + id, + e); } } @@ -260,25 +259,6 @@ public void sendBinary(ByteString byteString, int id) { } } - @ReactMethod - public void sendBlob(ReadableMap blob, int id) { - WebSocket client = mWebSocketConnections.get(id); - if (client == null) { - // This is a programmer error - throw new RuntimeException("Cannot send a message. Unknown WebSocket id " + id); - } - byte[] data = BlobModule.resolve( - blob.getString("blobId"), - blob.getInt("offset"), - blob.getInt("size")); - - if (data != null) { - client.send(ByteString.of(data)); - } else { - notifyWebSocketFailed(id, "Blob data not found for id " + id); - } - } - @ReactMethod public void ping(int id) { WebSocket client = mWebSocketConnections.get(id); @@ -322,10 +302,10 @@ private static String getDefaultOrigin(String uri) { if (requestURI.getPort() != -1) { defaultOrigin = String.format( - "%s://%s:%s", - scheme, - requestURI.getHost(), - requestURI.getPort()); + "%s://%s:%s", + scheme, + requestURI.getHost(), + requestURI.getPort()); } else { defaultOrigin = String.format("%s://%s/", scheme, requestURI.getHost()); } @@ -336,11 +316,6 @@ private static String getDefaultOrigin(String uri) { } } - @ReactMethod - public void setBinaryType(String binaryType, int id) { - mBlobsEnabled.put(id, binaryType.equals("blob")); - } - /** * Get the cookie for a specific domain * From e644c216d2f73b8aad411070210bf941b22533f6 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 11 Aug 2017 16:28:04 +0200 Subject: [PATCH 28/66] Make blob work on Android --- Libraries/Blob/Blob.js | 2 +- Libraries/WebSocket/WebSocket.js | 22 +--------- .../modules/network/NetworkingModule.java | 43 +++++++++++-------- 3 files changed, 26 insertions(+), 41 deletions(-) diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 74fd897ec849ce..197039e66911b9 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -64,7 +64,7 @@ class Blob { * Currently we only support creating Blobs from other Blobs. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob */ - constructor(parts: Array, options: any) { + constructor(parts: Array = [], options: any) { const BlobManager = require('BlobManager'); this.data = BlobManager.createFromParts(parts).data; } diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 04c0405f234461..36078e1ff139c8 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -141,26 +141,6 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { return this._binaryType; } - set binaryType(binaryType: BinaryType): void { - if (binaryType !== 'blob' && binaryType !== 'arraybuffer') { - throw new Error('binaryType must be either \'blob\' or \'arraybuffer\''); - } - this._binaryType = binaryType; - RCTWebSocketModule.setBinaryType(binaryType, this._socketId); - } - - get binaryType(): ?BinaryType { - return this._binaryType; - } - - set binaryType(binaryType: BinaryType): void { - if (binaryType !== 'blob' && binaryType !== 'arraybuffer') { - throw new Error('binaryType must be either \'blob\' or \'arraybuffer\''); - } - this._binaryType = binaryType; - RCTWebSocketModule.setBinaryType(binaryType, this._socketId); - } - close(code?: number, reason?: string): void { if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) { @@ -179,7 +159,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { if (data instanceof Blob) { const BlobModule = NativeModules.BlobModule; invariant(BlobModule, 'Native module BlobModule is required for blob support'); - BlobModule.sendBlob(data, this._socketId); + BlobModule.sendBlob(data.data, this._socketId); return; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 99809244e84b76..5419ce05d52254 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -64,6 +64,7 @@ public final class NetworkingModule extends ReactContextBaseJavaModule { private static final String REQUEST_BODY_KEY_URI = "uri"; private static final String REQUEST_BODY_KEY_FORMDATA = "formData"; private static final String REQUEST_BODY_KEY_BASE64 = "base64"; + private static final String REQUEST_BODY_KEY_BLOB = "blob"; private static final String REQUEST_BODY_KEY_BLOB_ID = "blobId"; private static final String USER_AGENT_HEADER_NAME = "user-agent"; private static final int CHUNK_TIMEOUT_NS = 100 * 1000000; // 100ms @@ -316,7 +317,7 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { requestBuilder.method( method, RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); - } else if (data.hasKey(REQUEST_BODY_KEY_BLOB_ID)) { + } else if (data.hasKey(REQUEST_BODY_KEY_BLOB)) { if (data.hasKey("type")) { String type = data.getString("type"); if (!type.isEmpty()) { @@ -326,11 +327,12 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { if (contentType == null) { contentType = "application/octet-stream"; } - String blobId = data.getString(REQUEST_BODY_KEY_BLOB_ID); + ReadableMap blob = data.getMap(REQUEST_BODY_KEY_BLOB); + String blobId = blob.getString(REQUEST_BODY_KEY_BLOB_ID); byte[] bytes = BlobModule.resolve( blobId, - data.getInt("offset"), - data.getInt("size"));; + blob.getInt("offset"), + blob.getInt("size"));; requestBuilder.method( method, RequestBody.create(MediaType.parse(contentType), bytes)); @@ -406,7 +408,6 @@ public void onResponse(Call call, Response response) throws IOException { } // Otherwise send the data in one big chunk, in the format that JS requested. - String responseString = ""; if (responseType.equals("blob")) { byte[] data = responseBody.bytes(); WritableMap blob = Arguments.createMap(); @@ -414,22 +415,26 @@ public void onResponse(Call call, Response response) throws IOException { blob.putInt("offset", 0); blob.putInt("size", data.length); ResponseUtil.onDataReceived(eventEmitter, requestId, blob); - } else if (responseType.equals("text")) { - try { - responseString = responseBody.string(); - } catch (IOException e) { - if (response.request().method().equalsIgnoreCase("HEAD")) { - // The request is an `HEAD` and the body is empty, - // the OkHttp will produce an exception. - // Ignore the exception to not invalidate the request in the - // Javascript layer. - // Introduced to fix issue #7463. - } else { - ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); + } else { + String responseString = ""; + if (responseType.equals("text")) { + try { + responseString = responseBody.string(); + } catch (IOException e) { + if (response.request().method().equalsIgnoreCase("HEAD")) { + // The request is an `HEAD` and the body is empty, + // the OkHttp will produce an exception. + // Ignore the exception to not invalidate the request in the + // Javascript layer. + // Introduced to fix issue #7463. + } else { + ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); + } } + } else if (responseType.equals("base64")) { + responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); } - } else if (responseType.equals("base64")) { - responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); + ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); } ResponseUtil.onRequestSuccess(eventEmitter, requestId); } catch (IOException e) { From 9798801b192fd2b0b7aac45e6f844dcc343feec0 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Sun, 27 Aug 2017 19:42:15 +0200 Subject: [PATCH 29/66] Fix the file constructor and remove leftover file --- Libraries/Blob/Blob.js | 11 +++-------- Libraries/Blob/BlobManager.js | 5 +++-- Libraries/Blob/BlobTypes.js | 3 ++- Libraries/Blob/BlobTypes.js~HEAD | 32 -------------------------------- Libraries/Blob/File.js | 11 +++++++++++ 5 files changed, 19 insertions(+), 43 deletions(-) delete mode 100644 Libraries/Blob/BlobTypes.js~HEAD diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 197039e66911b9..bfc062c9882fa7 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -12,12 +12,7 @@ 'use strict'; -const invariant = require('fbjs/lib/invariant'); -const uuid = require('uuid'); - -const { BlobModule } = require('NativeModules'); - -import type { BlobProps, BlobData, BlobOptions } from 'BlobTypes'; +import type { BlobData, BlobOptions } from 'BlobTypes'; /** * Opaque JS representation of some binary data in native. @@ -64,9 +59,9 @@ class Blob { * Currently we only support creating Blobs from other Blobs. * Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob */ - constructor(parts: Array = [], options: any) { + constructor(parts: Array = [], options?: BlobOptions) { const BlobManager = require('BlobManager'); - this.data = BlobManager.createFromParts(parts).data; + this.data = BlobManager.createFromParts(parts, options).data; } /* diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 071df713ac3eb2..5b65e8ccb86b30 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -17,7 +17,7 @@ const Blob = require('Blob'); const BlobRegistry = require('BlobRegistry'); const { BlobModule } = require('NativeModules'); -import type { BlobData, BlobOptions } from './BlobTypes'; +import type { BlobData, BlobOptions } from 'BlobTypes'; /** * Module to manage blobs @@ -27,7 +27,7 @@ class BlobManager { /** * Create blob from existing array of blobs. */ - static createFromParts(parts: Array, options: BlobOptions): Blob { + static createFromParts(parts: Array, options?: BlobOptions): Blob { const blobId = uuid.v4(); const items = parts.map(part => { if (part instanceof ArrayBuffer || global.ArrayBufferView && part instanceof global.ArrayBufferView) { @@ -60,6 +60,7 @@ class BlobManager { offset: 0, size, type: options ? options.type : '', + lastModified: options ? options.lastModified : Date.now(), }); } diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js index 684ca9e135c55a..4eaca2649868c0 100644 --- a/Libraries/Blob/BlobTypes.js +++ b/Libraries/Blob/BlobTypes.js @@ -16,11 +16,12 @@ export type BlobData = { blobId: string, offset: number, size: number, + name?: string, type?: string, lastModified?: number, }; export type BlobOptions = { type: string, - endings: "transparent" | "native", + lastModified: number, }; diff --git a/Libraries/Blob/BlobTypes.js~HEAD b/Libraries/Blob/BlobTypes.js~HEAD deleted file mode 100644 index 98a1a60b9e6aed..00000000000000 --- a/Libraries/Blob/BlobTypes.js~HEAD +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) 2013-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 - */ - -export type BlobData = { - /* - * Unique id to identify the blob on native side - */ - blobId: string; - /* - * Offset to indicate part of blob, used when sliced - */ - offset: number; - - size: number; - type?: string; - name?: string; - lastModified?: number; -}; - - -export type BlobOptions = { - type: string; - endings: "transparent" | "native"; -} diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js index df8d612ee5df46..67d4cdb20ae400 100644 --- a/Libraries/Blob/File.js +++ b/Libraries/Blob/File.js @@ -13,10 +13,21 @@ const Blob = require('Blob'); +import type { BlobOptions } from 'BlobTypes'; + /** * The File interface provides information about files. */ class File extends Blob { + + /** + * Constructor for JS consumers. + */ + constructor(parts: Array = [], name?: string, options?: BlobOptions) { + super(parts, options); + this.data.name = name; + } + /** * Name of the file. */ From 8564ec812e140fca4b7fa2dfa176c4442a5f49b0 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 15 Sep 2017 17:23:41 +0200 Subject: [PATCH 30/66] Make blob module optional on Android --- Libraries/WebSocket/WebSocket.js | 6 +- .../react/modules/blob/BlobModule.java | 108 +++++-- .../modules/network/NetworkingModule.java | 301 ++++++++++-------- 3 files changed, 257 insertions(+), 158 deletions(-) diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 36078e1ff139c8..d59e98526ac08a 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -128,9 +128,9 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { invariant(BlobModule, 'Native module BlobModule is required for blob support'); if (BlobModule) { if (binaryType === 'blob') { - BlobModule.enableBlobSupport(this._socketId); + BlobModule.addWebSocketHandler(this._socketId); } else { - BlobModule.disableBlobSupport(this._socketId); + BlobModule.removeWebSocketHandler(this._socketId); } } } @@ -159,7 +159,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { if (data instanceof Blob) { const BlobModule = NativeModules.BlobModule; invariant(BlobModule, 'Native module BlobModule is required for blob support'); - BlobModule.sendBlob(data.data, this._socketId); + BlobModule.sendOverSocket(data.data, this._socketId); return; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 12ef20d4835705..f7f243e8d52e66 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -25,6 +25,7 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.MapBuilder; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.network.NetworkingModule; import com.facebook.react.modules.websocket.WebSocketModule; import java.io.ByteArrayOutputStream; @@ -40,6 +41,9 @@ import java.util.Map; import java.util.UUID; +import okhttp3.MediaType; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; import okio.ByteString; @ReactModule(name = BlobModule.NAME) @@ -71,8 +75,88 @@ public void onMessage(ByteString bytes, WritableMap params) { } }; + private static final NetworkingModule.UriHandler NetworkingUriHandler = + new NetworkingModule.UriHandler() { + @Override + public boolean supports(Uri uri, String responseType) { + String scheme = uri.getScheme(); + boolean isRemote = scheme.equals("http") || scheme.equals("https"); + + return (!isRemote && responseType.equals("blob")); + } + + @Override + public WritableMap fetch(Uri uri, Context context) throws IOException { + ContentResolver resolver = context.getContentResolver(); + + byte[] data = getBytesFromUri(uri, resolver); + + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + blob.putString("type", getMimeTypeFromUri(uri, resolver)); + + // Needed for files + blob.putString("name", getNameFromUri(uri, resolver)); + blob.putDouble("lastModified", getLastModifiedFromUri(uri)); + + return blob; + } + }; + + private static final NetworkingModule.RequestBodyHandler NetworkingRequestBodyHandler = + new NetworkingModule.RequestBodyHandler() { + @Override + public boolean supports(ReadableMap data) { + return data.hasKey("blob"); + } + + @Override + public RequestBody toRequestBody(ReadableMap data, String contentType) { + String type = contentType; + if (data.hasKey("type") && !data.getString("type").isEmpty()) { + type = data.getString("type"); + } + if (type == null) { + type = "application/octet-stream"; + } + ReadableMap blob = data.getMap("blob"); + String blobId = blob.getString("blobId"); + byte[] bytes = resolve( + blobId, + blob.getInt("offset"), + blob.getInt("size"));; + + return RequestBody.create(MediaType.parse(type), bytes); + } + }; + + private static final NetworkingModule.ResponseHandler NetworkingResponseHandler = + new NetworkingModule.ResponseHandler() { + @Override + public boolean supports(String responseType) { + return responseType.equals("blob"); + } + + @Override + public WritableMap toResponseData(ResponseBody body) throws IOException { + byte[] data = body.bytes(); + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + return blob; + } + }; + public BlobModule(ReactApplicationContext reactContext) { super(reactContext); + + // Enable Blob support for networking modules + NetworkingModule.addUriHandler(NetworkingUriHandler); + NetworkingModule.addRequestBodyHandler(NetworkingRequestBodyHandler); + NetworkingModule.addResponseHandler(NetworkingResponseHandler); } @Override @@ -146,24 +230,6 @@ public static byte[] resolve(ReadableMap blob) { return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); } - public static WritableMap fetch(Uri uri, Context context) throws IOException { - ContentResolver resolver = context.getContentResolver(); - - byte[] data = getBytesFromUri(uri, resolver); - - WritableMap blob = Arguments.createMap(); - blob.putString("blobId", store(data)); - blob.putInt("offset", 0); - blob.putInt("size", data.length); - blob.putString("type", getMimeTypeFromUri(uri, resolver)); - - // Needed for files - blob.putString("name", getNameFromUri(uri, resolver)); - blob.putDouble("lastModified", getLastModifiedFromUri(uri)); - - return blob; - } - private static byte[] getBytesFromUri(Uri contentUri, ContentResolver resolver) throws IOException { InputStream is = resolver.openInputStream(contentUri); @@ -228,17 +294,17 @@ private WebSocketModule getWebSocketModule() { } @ReactMethod - public void enableBlobSupport(final int id) { + public void addWebSocketHandler(final int id) { getWebSocketModule().setContentHandler(id, BlobHandler); } @ReactMethod - public void disableBlobSupport(final int id) { + public void removeWebSocketHandler(final int id) { getWebSocketModule().setContentHandler(id, null); } @ReactMethod - public void sendBlob(ReadableMap blob, int id) { + public void sendOverSocket(ReadableMap blob, int id) { byte[] data = resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); if (data != null) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 5419ce05d52254..8b4f726f3ddc4f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -5,10 +5,9 @@ * 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. - */ - -package com.facebook.react.modules.network; + */package com.facebook.react.modules.network; +import android.content.Context; import android.net.Uri; import android.util.Base64; @@ -22,14 +21,16 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.network.OkHttpCallUtil; import com.facebook.react.module.annotations.ReactModule; -import com.facebook.react.modules.blob.BlobModule; import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -56,6 +57,24 @@ @ReactModule(name = NetworkingModule.NAME) public final class NetworkingModule extends ReactContextBaseJavaModule { + public interface UriHandler { + boolean supports(Uri uri, String responseType); + + WritableMap fetch(Uri uri, Context context) throws IOException; + } + + public interface RequestBodyHandler { + boolean supports(ReadableMap map); + + RequestBody toRequestBody(ReadableMap map, String contentType); + } + + public interface ResponseHandler { + boolean supports(String responseType); + + WritableMap toResponseData(ResponseBody body) throws IOException; + } + protected static final String NAME = "Networking"; private static final String CONTENT_ENCODING_HEADER_NAME = "content-encoding"; @@ -64,12 +83,14 @@ public final class NetworkingModule extends ReactContextBaseJavaModule { private static final String REQUEST_BODY_KEY_URI = "uri"; private static final String REQUEST_BODY_KEY_FORMDATA = "formData"; private static final String REQUEST_BODY_KEY_BASE64 = "base64"; - private static final String REQUEST_BODY_KEY_BLOB = "blob"; - private static final String REQUEST_BODY_KEY_BLOB_ID = "blobId"; private static final String USER_AGENT_HEADER_NAME = "user-agent"; private static final int CHUNK_TIMEOUT_NS = 100 * 1000000; // 100ms private static final int MAX_CHUNK_SIZE_BETWEEN_FLUSHES = 8 * 1024; // 8K + private static final List mRequestBodyHandlers = new ArrayList<>(); + private static final List mUriHandlers = new ArrayList<>(); + private static final List mResponseHandlers = new ArrayList<>(); + private final OkHttpClient mClient; private final ForwardingCookieHandler mCookieHandler; private final @Nullable String mDefaultUserAgent; @@ -78,10 +99,10 @@ public final class NetworkingModule extends ReactContextBaseJavaModule { private boolean mShuttingDown; /* package */ NetworkingModule( - ReactApplicationContext reactContext, - @Nullable String defaultUserAgent, - OkHttpClient client, - @Nullable List networkInterceptorCreators) { + ReactApplicationContext reactContext, + @Nullable String defaultUserAgent, + OkHttpClient client, + @Nullable List networkInterceptorCreators) { super(reactContext); if (networkInterceptorCreators != null) { @@ -106,9 +127,9 @@ public final class NetworkingModule extends ReactContextBaseJavaModule { * @param client the {@link OkHttpClient} to be used for networking */ /* package */ NetworkingModule( - ReactApplicationContext context, - @Nullable String defaultUserAgent, - OkHttpClient client) { + ReactApplicationContext context, + @Nullable String defaultUserAgent, + OkHttpClient client) { this(context, defaultUserAgent, client, null); } @@ -125,8 +146,8 @@ public NetworkingModule(final ReactApplicationContext context) { * methods would be called to attach the interceptors to the client. */ public NetworkingModule( - ReactApplicationContext context, - List networkInterceptorCreators) { + ReactApplicationContext context, + List networkInterceptorCreators) { this(context, null, OkHttpClientProvider.createClient(), networkInterceptorCreators); } @@ -158,33 +179,47 @@ public void onCatalystInstanceDestroy() { mCookieJarContainer.removeCookieJar(); } + public static void addUriHandler(UriHandler handler) { + mUriHandlers.add(handler); + } + + public static void addRequestBodyHandler(RequestBodyHandler handler) { + mRequestBodyHandlers.add(handler); + } + + public static void addResponseHandler(ResponseHandler handler) { + mResponseHandlers.add(handler); + } + @ReactMethod /** * @param timeout value of 0 results in no timeout */ public void sendRequest( - String method, - String url, - final int requestId, - ReadableArray headers, - ReadableMap data, - final String responseType, - final boolean useIncrementalUpdates, - int timeout, - boolean withCredentials) { + String method, + String url, + final int requestId, + ReadableArray headers, + ReadableMap data, + final String responseType, + final boolean useIncrementalUpdates, + int timeout, + boolean withCredentials) { final RCTDeviceEventEmitter eventEmitter = getEventEmitter(); try { Uri uri = Uri.parse(url); - String scheme = uri.getScheme(); - boolean isRemote = scheme.equals("http") || scheme.equals("https"); - if (!isRemote && responseType.equals("blob")) { - WritableMap blob = BlobModule.fetch(uri, getReactApplicationContext()); - ResponseUtil.onDataReceived(eventEmitter, requestId, blob); - ResponseUtil.onRequestSuccess(eventEmitter, requestId); - return; + // Check if a handler is registered + for (int i = 0; i < mUriHandlers.size(); i++) { + if (mUriHandlers.get(i).supports(uri, responseType)) { + UriHandler handler = mUriHandlers.get(i); + WritableMap res = handler.fetch(uri, getReactApplicationContext()); + ResponseUtil.onDataReceived(eventEmitter, requestId, res); + ResponseUtil.onRequestSuccess(eventEmitter, requestId); + return; + } } } catch (IOException e) { ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); @@ -211,29 +246,29 @@ public void sendRequest( public Response intercept(Interceptor.Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); ProgressResponseBody responseBody = new ProgressResponseBody( - originalResponse.body(), - new ProgressListener() { - long last = System.nanoTime(); - - @Override - public void onProgress(long bytesWritten, long contentLength, boolean done) { - long now = System.nanoTime(); - if (!done && !shouldDispatch(now, last)) { - return; - } - if (responseType.equals("text")) { - // For 'text' responses we continuously send response data with progress info to - // JS below, so no need to do anything here. - return; - } - ResponseUtil.onDataReceivedProgress( - eventEmitter, - requestId, - bytesWritten, - contentLength); - last = now; - } - }); + originalResponse.body(), + new ProgressListener() { + long last = System.nanoTime(); + + @Override + public void onProgress(long bytesWritten, long contentLength, boolean done) { + long now = System.nanoTime(); + if (!done && !shouldDispatch(now, last)) { + return; + } + if (responseType.equals("text")) { + // For 'text' responses we continuously send response data with progress info to + // JS below, so no need to do anything here. + return; + } + ResponseUtil.onDataReceivedProgress( + eventEmitter, + requestId, + bytesWritten, + contentLength); + last = now; + } + }); return originalResponse.newBuilder().body(responseBody).build(); } }); @@ -257,15 +292,30 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { String contentEncoding = requestHeaders.get(CONTENT_ENCODING_HEADER_NAME); requestBuilder.headers(requestHeaders); + // Check if a handler is registered + RequestBodyHandler handler = null; + + if (data != null) { + for (int i = 0; i < mRequestBodyHandlers.size(); i++) { + if (mRequestBodyHandlers.get(i).supports(data)) { + handler = mRequestBodyHandlers.get(i); + break; + } + } + } + if (data == null) { requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); + } else if (handler != null) { + RequestBody requestBody = handler.toRequestBody(data, contentType); + requestBuilder.method(method, requestBody); } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String body = data.getString(REQUEST_BODY_KEY_STRING); @@ -283,86 +333,67 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } else if (data.hasKey(REQUEST_BODY_KEY_BASE64)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String base64String = data.getString(REQUEST_BODY_KEY_BASE64); MediaType contentMediaType = MediaType.parse(contentType); requestBuilder.method( - method, - RequestBody.create(contentMediaType, ByteString.decodeBase64(base64String))); + method, + RequestBody.create(contentMediaType, ByteString.decodeBase64(base64String))); } else if (data.hasKey(REQUEST_BODY_KEY_URI)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String uri = data.getString(REQUEST_BODY_KEY_URI); InputStream fileInputStream = - RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri); + RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri); if (fileInputStream == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Could not retrieve file for uri " + uri, - null); + eventEmitter, + requestId, + "Could not retrieve file for uri " + uri, + null); return; } - requestBuilder.method( - method, - RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); - } else if (data.hasKey(REQUEST_BODY_KEY_BLOB)) { - if (data.hasKey("type")) { - String type = data.getString("type"); - if (!type.isEmpty()) { - contentType = type; - } - } - if (contentType == null) { - contentType = "application/octet-stream"; - } - ReadableMap blob = data.getMap(REQUEST_BODY_KEY_BLOB); - String blobId = blob.getString(REQUEST_BODY_KEY_BLOB_ID); - byte[] bytes = BlobModule.resolve( - blobId, - blob.getInt("offset"), - blob.getInt("size"));; requestBuilder.method( method, - RequestBody.create(MediaType.parse(contentType), bytes)); + RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); } else if (data.hasKey(REQUEST_BODY_KEY_FORMDATA)) { if (contentType == null) { contentType = "multipart/form-data"; } ReadableArray parts = data.getArray(REQUEST_BODY_KEY_FORMDATA); MultipartBody.Builder multipartBuilder = - constructMultipartBody(parts, contentType, requestId); + constructMultipartBody(parts, contentType, requestId); if (multipartBuilder == null) { return; } requestBuilder.method( - method, - RequestBodyUtil.createProgressRequest( - multipartBuilder.build(), - new ProgressListener() { - long last = System.nanoTime(); - - @Override - public void onProgress(long bytesWritten, long contentLength, boolean done) { - long now = System.nanoTime(); - if (done || shouldDispatch(now, last)) { - ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); - last = now; - } - } - })); + method, + RequestBodyUtil.createProgressRequest( + multipartBuilder.build(), + new ProgressListener() { + long last = System.nanoTime(); + + @Override + public void onProgress(long bytesWritten, long contentLength, boolean done) { + long now = System.nanoTime(); + if (done || shouldDispatch(now, last)) { + ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); + last = now; + } + } + })); } else { // Nothing in data payload, at least nothing we could understand anyway. requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); @@ -399,6 +430,17 @@ public void onResponse(Call call, Response response) throws IOException { ResponseBody responseBody = response.body(); try { + // Check if a handler is registered + for (int i = 0; i < mResponseHandlers.size(); i++) { + if (mResponseHandlers.get(i).supports(responseType)) { + ResponseHandler handler = mResponseHandlers.get(i); + WritableMap res = handler.toResponseData(responseBody); + ResponseUtil.onDataReceived(eventEmitter, requestId, res); + ResponseUtil.onRequestSuccess(eventEmitter, requestId); + return; + } + } + // If JS wants progress updates during the download, and it requested a text response, // periodically send response data updates to JS. if (useIncrementalUpdates && responseType.equals("text")) { @@ -408,34 +450,25 @@ public void onResponse(Call call, Response response) throws IOException { } // Otherwise send the data in one big chunk, in the format that JS requested. - if (responseType.equals("blob")) { - byte[] data = responseBody.bytes(); - WritableMap blob = Arguments.createMap(); - blob.putString("blobId", BlobModule.store(data)); - blob.putInt("offset", 0); - blob.putInt("size", data.length); - ResponseUtil.onDataReceived(eventEmitter, requestId, blob); - } else { - String responseString = ""; - if (responseType.equals("text")) { - try { - responseString = responseBody.string(); - } catch (IOException e) { - if (response.request().method().equalsIgnoreCase("HEAD")) { - // The request is an `HEAD` and the body is empty, - // the OkHttp will produce an exception. - // Ignore the exception to not invalidate the request in the - // Javascript layer. - // Introduced to fix issue #7463. - } else { - ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); - } + String responseString = ""; + if (responseType.equals("text")) { + try { + responseString = responseBody.string(); + } catch (IOException e) { + if (response.request().method().equalsIgnoreCase("HEAD")) { + // The request is an `HEAD` and the body is empty, + // the OkHttp will produce an exception. + // Ignore the exception to not invalidate the request in the + // Javascript layer. + // Introduced to fix issue #7463. + } else { + ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); } - } else if (responseType.equals("base64")) { - responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); } - ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); + } else if (responseType.equals("base64")) { + responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); } + ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); ResponseUtil.onRequestSuccess(eventEmitter, requestId); } catch (IOException e) { ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); From 1479086ad35269ab2f7b15fcc6e5229e2de04696 Mon Sep 17 00:00:00 2001 From: Satyajit Sahoo Date: Fri, 15 Sep 2017 18:09:08 +0200 Subject: [PATCH 31/66] Fix compilation error on iOS --- Libraries/Blob/RCTBlobManager.h | 8 ++++++++ Libraries/Blob/RCTBlobManager.m | 15 +++++++-------- Libraries/WebSocket/RCTWebSocketModule.m | 21 --------------------- 3 files changed, 15 insertions(+), 29 deletions(-) diff --git a/Libraries/Blob/RCTBlobManager.h b/Libraries/Blob/RCTBlobManager.h index 03b3ffc60a6fb4..1d5427aa3f9e88 100755 --- a/Libraries/Blob/RCTBlobManager.h +++ b/Libraries/Blob/RCTBlobManager.h @@ -13,4 +13,12 @@ @interface RCTBlobManager : NSObject +- (NSString *)store:(NSData *)data; + +- (void)store:(NSData *)data withId:(NSString *)blobId; + +- (NSData *)resolve:(NSDictionary *)blob; + +- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size; + @end diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.m index c37781cd43611d..ca3065e5710237 100755 --- a/Libraries/Blob/RCTBlobManager.m +++ b/Libraries/Blob/RCTBlobManager.m @@ -86,7 +86,7 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) return data; } -RCT_EXPORT_METHOD(enableBlobSupport:(nonnull NSNumber *)socketID) +RCT_EXPORT_METHOD(addWebSocketHandler:(nonnull NSNumber *)socketID) { if (!_contentHandler) { _contentHandler = [[_RCTBlobContentHandler alloc] initWithBlobManager:self]; @@ -94,12 +94,12 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) [[_bridge webSocketModule] setContentHandler:_contentHandler forSocketID:socketID]; } -RCT_EXPORT_METHOD(disableBlobSupport:(nonnull NSNumber *)socketID) +RCT_EXPORT_METHOD(removeWebSocketHandler:(nonnull NSNumber *)socketID) { [[_bridge webSocketModule] setContentHandler:nil forSocketID:socketID]; } -RCT_EXPORT_METHOD(sendBlob:(NSDictionary *)blob socketID:(nonnull NSNumber *)socketID) +RCT_EXPORT_METHOD(sendOverSocket:(NSDictionary *)blob socketID:(nonnull NSNumber *)socketID) { [[_bridge webSocketModule] sendData:[self resolve:blob] forSocketID:socketID]; } @@ -111,12 +111,11 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) NSString *type = [RCTConvert NSString:part[@"type"]]; if ([type isEqualToString:@"blob"]) { - NSDictionary *data = [RCTConvert NSDictionary:part[@"data"]]; - NSData *partData = [self resolve:data]; - [blob appendData:partData]; + NSData *partData = [self resolve:part]; + [data appendData:partData]; } else if ([type isEqualToString:@"string"]) { - NSData *data = [[RCTConvert NSString:part[@"data"]] dataUsingEncoding:NSUTF8StringEncoding]; - [blob appendData:data]; + NSData *partData = [[RCTConvert NSString:part[@"data"]] dataUsingEncoding:NSUTF8StringEncoding]; + [data appendData:partData]; } else { [NSException raise:@"Invalid type for blob" format:@"%@ is invalid", type]; } diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m index 8dc7b094f6c46d..c04a0adcb2d721 100644 --- a/Libraries/WebSocket/RCTWebSocketModule.m +++ b/Libraries/WebSocket/RCTWebSocketModule.m @@ -107,27 +107,6 @@ - (void)sendData:(NSData *)data forSocketID:(nonnull NSNumber *)socketID [_sockets[socketID] send:data]; } -RCT_EXPORT_METHOD(sendBlob:(NSDictionary *)blob socketID:(nonnull NSNumber *)socketID) -{ - RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; - NSData *data = [blobManager resolve:blob]; - // Unfortunately we don't have access to the WebSocket object, so we have to - // convert it to base64 and send it through the existing method :( - [self sendBinary:[data base64EncodedStringWithOptions:0] socketID:socketID]; -} - -RCT_EXPORT_METHOD(setBinaryType:(NSString *)binaryType socketID:(nonnull NSNumber *)socketID) -{ - if (!_blobsEnabled) { - _blobsEnabled = [NSMutableSet new]; - } - if ([binaryType isEqualToString:@"blob"]) { - [_blobsEnabled addObject:socketID]; - } else { - [_blobsEnabled removeObject:socketID]; - } -} - RCT_EXPORT_METHOD(ping:(nonnull NSNumber *)socketID) { [_sockets[socketID] sendPing:NULL]; From d9d32954cb9d46faebd0814a1c3e89a5482cd4ed Mon Sep 17 00:00:00 2001 From: Craig Cronin Date: Fri, 29 Sep 2017 10:54:59 -0400 Subject: [PATCH 32/66] Remove dependency --- Libraries/Blob/RCTBlobManager.m | 55 +++++++++++++++++++++++++---- Libraries/Network/RCTNetworking.h | 9 +++++ Libraries/Network/RCTNetworking.mm | 41 +++++++++++++-------- Libraries/Network/XMLHttpRequest.js | 13 +++++++ 4 files changed, 98 insertions(+), 20 deletions(-) diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.m index ca3065e5710237..2cabdf935e5498 100755 --- a/Libraries/Blob/RCTBlobManager.m +++ b/Libraries/Blob/RCTBlobManager.m @@ -11,10 +11,17 @@ #import #import +#import static NSString *const kBlobUriScheme = @"blob"; -@interface _RCTBlobContentHandler : NSObject +@interface _RCTBlobWebSocketContentHandler : NSObject + +- (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager; + +@end + +@interface _RCTBlobXMLHttpRequestContentHandler : NSObject - (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager; @@ -23,7 +30,8 @@ - (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager; @implementation RCTBlobManager { NSMutableDictionary *_blobs; - _RCTBlobContentHandler *_contentHandler; + _RCTBlobWebSocketContentHandler *_webSocketContentHandler; + _RCTBlobXMLHttpRequestContentHandler *_xmlHttpRequestContentHandler; NSOperationQueue *_queue; } @@ -86,12 +94,25 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) return data; } +RCT_EXPORT_METHOD(addXMLHttpRequestHandler) +{ + if (!_xmlHttpRequestContentHandler) { + _xmlHttpRequestContentHandler = [[_RCTBlobXMLHttpRequestContentHandler alloc] initWithBlobManager:self]; + } + [[_bridge networking] setContentHandler:_xmlHttpRequestContentHandler]; +} + +RCT_EXPORT_METHOD(removeXMLHttpRequestHandler) +{ + [[_bridge networking] setContentHandler:nil]; +} + RCT_EXPORT_METHOD(addWebSocketHandler:(nonnull NSNumber *)socketID) { - if (!_contentHandler) { - _contentHandler = [[_RCTBlobContentHandler alloc] initWithBlobManager:self]; + if (!_webSocketContentHandler) { + _webSocketContentHandler = [[_RCTBlobWebSocketContentHandler alloc] initWithBlobManager:self]; } - [[_bridge webSocketModule] setContentHandler:_contentHandler forSocketID:socketID]; + [[_bridge webSocketModule] setContentHandler:_webSocketContentHandler forSocketID:socketID]; } RCT_EXPORT_METHOD(removeWebSocketHandler:(nonnull NSNumber *)socketID) @@ -194,7 +215,7 @@ - (void)cancelRequest:(NSOperation *)op @end -@implementation _RCTBlobContentHandler { +@implementation _RCTBlobWebSocketContentHandler { __weak RCTBlobManager *_blobManager; } @@ -222,3 +243,25 @@ - (id)processMessage:(id)message forSocketID:(NSNumber *)socketID withType:(NSSt } @end + +@implementation _RCTBlobXMLHttpRequestContentHandler { + __weak RCTBlobManager *_blobManager; +} + +-(instancetype)initWithBlobManager:(RCTBlobManager *)blobManager +{ + if (self = [super init]) { + _blobManager = blobManager; + } + return self; +} + +- (NSData *)processBlob:(NSDictionary *)blob { + return [_blobManager resolve:blob]; +} + +- (NSString *)storeBlob:(NSData *)data { + return [_blobManager store:data]; +} + +@end diff --git a/Libraries/Network/RCTNetworking.h b/Libraries/Network/RCTNetworking.h index eabc411617d4b4..23cdf69205e11c 100644 --- a/Libraries/Network/RCTNetworking.h +++ b/Libraries/Network/RCTNetworking.h @@ -10,6 +10,13 @@ #import #import +@protocol RCTXMLHttpRequestContentHandler + +- (NSData *)processBlob:(NSDictionary *)blob; +- (NSString *)storeBlob:(NSData *)data; + +@end + @interface RCTNetworking : RCTEventEmitter /** @@ -24,6 +31,8 @@ - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request completionBlock:(RCTURLRequestCompletionBlock)completionBlock; +- (void)setContentHandler:(id)handler; + @end @interface RCTBridge (RCTNetworking) diff --git a/Libraries/Network/RCTNetworking.mm b/Libraries/Network/RCTNetworking.mm index 9cc060905ab26c..6664cd4d47cb8c 100644 --- a/Libraries/Network/RCTNetworking.mm +++ b/Libraries/Network/RCTNetworking.mm @@ -19,7 +19,6 @@ #import #import -#import "RCTBlobManager.h" #import "RCTHTTPRequestHandler.h" typedef RCTURLRequestCancellationBlock (^RCTHTTPQueryResult)(NSError *error, NSDictionary *result); @@ -132,6 +131,7 @@ @implementation RCTNetworking NSMutableDictionary *_tasksByRequestID; std::mutex _handlersLock; NSArray> *_handlers; + id _contentHandler; } @synthesize methodQueue = _methodQueue; @@ -321,11 +321,18 @@ - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary } NSDictionary *blob = [RCTConvert NSDictionary:query[@"blob"]]; if (blob) { - RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; - NSData *data = [blobManager resolve:blob]; - if (data) { - return callback(nil, @{@"body": data}); + if (_contentHandler) { + NSData *data = [_contentHandler processBlob:blob]; + if (data) { + return callback(nil, @{@"body": data}); + } } + + // RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; + // NSData *data = [blobManager resolve:blob]; + // if (data) { + // return callback(nil, @{@"body": data}); + // } } NSString *base64String = [RCTConvert NSString:query[@"base64"]]; if (base64String) { @@ -443,15 +450,16 @@ - (void)sendData:(NSData *)data } responseJSON = @[task.requestID, responseString]; } else if ([responseType isEqualToString:@"blob"]) { - RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; - NSDictionary *responseData = @{ - @"blobId": [blobManager store:data], - @"offset": @0, - @"size": @(data.length), - @"name": fileName, - @"type": mimeType, - }; - responseJSON = @[task.requestID, responseData]; + if (_contentHandler) { + NSDictionary *responseData = @{ + @"blobId": [_contentHandler storeBlob:data], + @"offset": @0, + @"size": @(data.length), + @"name": fileName, + @"type": mimeType, + }; + responseJSON = @[task.requestID, responseData]; + } } else if ([responseType isEqualToString:@"base64"]) { NSString *responseString = [data base64EncodedStringWithOptions:0]; responseJSON = @[task.requestID, responseString]; @@ -574,6 +582,11 @@ - (void)sendRequest:(NSURLRequest *)request [task start]; } +- (void)setContentHandler:(id)handler +{ + _contentHandler = handler; +} + #pragma mark - Public API - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request completionBlock:(RCTURLRequestCompletionBlock)completionBlock diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index f5d14a387ecce0..76c90c393e2417 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -25,6 +25,7 @@ const invariant = require('fbjs/lib/invariant'); const warning = require('fbjs/lib/warning'); const Blob = require('Blob'); const BlobManager = require('BlobManager'); +const NativeModules = require('NativeModules'); export type NativeResponseType = 'base64' | 'blob' | 'text'; export type ResponseType = '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text'; @@ -203,6 +204,18 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { SUPPORTED_RESPONSE_TYPES[responseType] || responseType === 'document', `The provided value '${responseType}' is unsupported in this environment.` ); + + if (this._responseType === 'blob' || responseType === 'blob') { + const BlobModule = NativeModules.BlobModule; + invariant(BlobModule, 'Native module BlobModule is required for blob support'); + if (BlobModule) { + if (responseType === 'blob') { + BlobModule.addXMLHttpRequestHandler(); + } else { + BlobModule.removeXMLHttpRequestHandler(); + } + } + } this._responseType = responseType; } From ccf580eda032ef7d012b8385c828c72b54423eb1 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Mon, 2 Oct 2017 19:49:55 -0400 Subject: [PATCH 33/66] Fixes, cleanup and @format --- Libraries/Blob/Blob.js | 20 ++--- Libraries/Blob/BlobManager.js | 22 +++-- Libraries/Blob/BlobRegistry.js | 3 +- Libraries/Blob/BlobTypes.js | 1 + Libraries/Blob/File.js | 17 +++- Libraries/Blob/FileReader.js | 74 ++++++++-------- Libraries/Blob/RCTBlobManager.m | 16 ++-- Libraries/Blob/URL.js | 3 +- Libraries/Blob/__mocks__/BlobModule.js | 15 +++- Libraries/Blob/__mocks__/FileReaderModule.js | 13 ++- Libraries/Blob/__tests__/Blob-test.js | 34 ++++---- Libraries/Blob/__tests__/BlobManager-test.js | 24 +++--- Libraries/Blob/__tests__/File-test.js | 40 +++++---- Libraries/Blob/__tests__/FileReader-test.js | 25 +++--- .../RCTNetwork.xcodeproj/project.pbxproj | 2 - Libraries/Network/RCTNetworking.mm | 18 ++-- .../react/modules/blob/BlobModule.java | 21 +++-- .../modules/network/NetworkingModule.java | 12 +++ .../InitializeJavaScriptAppEngine.js | 0 {Libraries/lib => lib}/RCTEventEmitter.js | 0 {Libraries/lib => lib}/README | 0 {Libraries/lib => lib}/TextInputState.js | 0 {Libraries/lib => lib}/UIManager.js | 0 .../lib => lib}/UIManagerStatTracker.js | 0 {Libraries/lib => lib}/View.js | 0 {Libraries/lib => lib}/deepDiffer.js | 0 .../deepFreezeAndThrowOnMutationInDev.js | 0 {Libraries/lib => lib}/flattenStyle.js | 0 .../ios/HelloWorld.xcodeproj/project.pbxproj | 84 +++++++++++++++++++ 29 files changed, 298 insertions(+), 146 deletions(-) rename {Libraries/lib => lib}/InitializeJavaScriptAppEngine.js (100%) rename {Libraries/lib => lib}/RCTEventEmitter.js (100%) rename {Libraries/lib => lib}/README (100%) rename {Libraries/lib => lib}/TextInputState.js (100%) rename {Libraries/lib => lib}/UIManager.js (100%) rename {Libraries/lib => lib}/UIManagerStatTracker.js (100%) rename {Libraries/lib => lib}/View.js (100%) rename {Libraries/lib => lib}/deepDiffer.js (100%) rename {Libraries/lib => lib}/deepFreezeAndThrowOnMutationInDev.js (100%) rename {Libraries/lib => lib}/flattenStyle.js (100%) diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index fac2013c37135d..3f077a05d71fc1 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -8,19 +8,12 @@ * * @providesModule Blob * @flow + * @format */ 'use strict'; -const invariant = require('fbjs/lib/invariant'); -/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error - * found when Flow v0.54 was deployed. To see the error delete this comment and - * run Flow. */ -const uuid = require('uuid'); - -const { BlobModule } = require('NativeModules'); - -import type { BlobProps } from 'BlobTypes'; +import type {BlobData, BlobOptions} from 'BlobTypes'; /** * Opaque JS representation of some binary data in native. @@ -82,15 +75,16 @@ class Blob { } get data(): BlobData { - if (this._data) { - return this._data; + if (!this._data) { + throw new Error('Blob has been closed and is no longer available'); } - throw new Error('Blob has been closed and is no longer available'); + + return this._data; } slice(start?: number, end?: number): Blob { const BlobManager = require('BlobManager'); - let { offset, size } = this.data; + let {offset, size} = this.data; if (typeof start === 'number') { if (start > size) { diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 5b65e8ccb86b30..451a632839c3c7 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -8,6 +8,7 @@ * * @providesModule BlobManager * @flow + * @format */ 'use strict'; @@ -15,23 +16,30 @@ const uuid = require('uuid'); const Blob = require('Blob'); const BlobRegistry = require('BlobRegistry'); -const { BlobModule } = require('NativeModules'); +const {BlobModule} = require('NativeModules'); -import type { BlobData, BlobOptions } from 'BlobTypes'; +import type {BlobData, BlobOptions} from 'BlobTypes'; /** * Module to manage blobs */ class BlobManager { - /** * Create blob from existing array of blobs. */ - static createFromParts(parts: Array, options?: BlobOptions): Blob { + static createFromParts( + parts: Array, + options?: BlobOptions, + ): Blob { const blobId = uuid.v4(); const items = parts.map(part => { - if (part instanceof ArrayBuffer || global.ArrayBufferView && part instanceof global.ArrayBufferView) { - throw new Error('Creating blobs from \'ArrayBuffer\' and \'ArrayBufferView\' are not supported'); + if ( + part instanceof ArrayBuffer || + (global.ArrayBufferView && part instanceof global.ArrayBufferView) + ) { + throw new Error( + "Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported", + ); } if (part instanceof Blob) { return { @@ -70,7 +78,7 @@ class BlobManager { */ static createFromOptions(options: BlobData): Blob { BlobRegistry.register(options.blobId); - return Object.assign(Object.create(Blob.prototype), { data: options }); + return Object.assign(Object.create(Blob.prototype), {data: options}); } /** diff --git a/Libraries/Blob/BlobRegistry.js b/Libraries/Blob/BlobRegistry.js index fcebd769e45244..925e78f3a78453 100644 --- a/Libraries/Blob/BlobRegistry.js +++ b/Libraries/Blob/BlobRegistry.js @@ -8,9 +8,10 @@ * * @providesModule BlobRegistry * @flow + * @format */ -const registry: { [key: string]: number } = {}; +const registry: {[key: string]: number} = {}; const register = (id: string) => { if (registry[id]) { diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js index 4eaca2649868c0..c053c08cfc8deb 100644 --- a/Libraries/Blob/BlobTypes.js +++ b/Libraries/Blob/BlobTypes.js @@ -8,6 +8,7 @@ * * @providesModule BlobTypes * @flow + * @format */ 'use strict'; diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js index 67d4cdb20ae400..076d9946bf5d4d 100644 --- a/Libraries/Blob/File.js +++ b/Libraries/Blob/File.js @@ -8,22 +8,33 @@ * * @providesModule File * @flow + * @format */ 'use strict'; const Blob = require('Blob'); -import type { BlobOptions } from 'BlobTypes'; +const invariant = require('invariant'); + +import type {BlobOptions} from 'BlobTypes'; /** * The File interface provides information about files. */ class File extends Blob { - /** * Constructor for JS consumers. */ - constructor(parts: Array = [], name?: string, options?: BlobOptions) { + constructor( + parts: Array, + name: string, + options?: BlobOptions, + ) { + invariant( + parts != null && name != null, + 'Failed to construct `File`: Must pass both `parts` and `name` arguments.', + ); + super(parts, options); this.data.name = name; } diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js index d0bff7449f2e1c..121f7ef76caa21 100644 --- a/Libraries/Blob/FileReader.js +++ b/Libraries/Blob/FileReader.js @@ -8,18 +8,19 @@ * * @providesModule FileReader * @flow + * @format */ 'use strict'; const EventTarget = require('event-target-shim'); const Blob = require('Blob'); -const { FileReaderModule } = require('NativeModules'); +const {FileReaderModule} = require('NativeModules'); type ReadyState = | 0 // EMPTY | 1 // LOADING - | 2 // DONE + | 2; // DONE type ReaderResult = string | ArrayBuffer; @@ -37,7 +38,6 @@ const LOADING = 1; const DONE = 2; class FileReader extends EventTarget(...READER_EVENTS) { - static EMPTY = EMPTY; static LOADING = LOADING; static DONE = DONE; @@ -70,16 +70,16 @@ class FileReader extends EventTarget(...READER_EVENTS) { _setReadyState(newState: ReadyState) { this._readyState = newState; - this.dispatchEvent({ type: 'readystatechange' }); + this.dispatchEvent({type: 'readystatechange'}); if (newState === DONE) { if (this._aborted) { - this.dispatchEvent({ type: 'abort' }); + this.dispatchEvent({type: 'abort'}); } else if (this._error) { - this.dispatchEvent({ type: 'error' }); + this.dispatchEvent({type: 'error'}); } else { - this.dispatchEvent({ type: 'load' }); + this.dispatchEvent({type: 'load'}); } - this.dispatchEvent({ type: 'loadend' }); + this.dispatchEvent({type: 'loadend'}); } } @@ -90,37 +90,43 @@ class FileReader extends EventTarget(...READER_EVENTS) { readAsDataURL(blob: Blob) { this._aborted = false; - FileReaderModule.readAsDataURL(blob.data).then((text: string) => { - if (this._aborted) { - return; - } - this._result = text; - this._setReadyState(DONE); - }, error => { - if (this._aborted) { - return; - } - this._error = error; - this._setReadyState(DONE); - }); + FileReaderModule.readAsDataURL(blob.data).then( + (text: string) => { + if (this._aborted) { + return; + } + this._result = text; + this._setReadyState(DONE); + }, + error => { + if (this._aborted) { + return; + } + this._error = error; + this._setReadyState(DONE); + }, + ); } readAsText(blob: Blob, encoding: string = 'UTF-8') { this._aborted = false; - FileReaderModule.readAsText(blob.data, encoding).then((text: string) => { - if (this._aborted) { - return; - } - this._result = text; - this._setReadyState(DONE); - }, error => { - if (this._aborted) { - return; - } - this._error = error; - this._setReadyState(DONE); - }); + FileReaderModule.readAsText(blob.data, encoding).then( + (text: string) => { + if (this._aborted) { + return; + } + this._result = text; + this._setReadyState(DONE); + }, + error => { + if (this._aborted) { + return; + } + this._error = error; + this._setReadyState(DONE); + }, + ); } abort() { diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.m index 2cabdf935e5498..184525ae06c565 100755 --- a/Libraries/Blob/RCTBlobManager.m +++ b/Libraries/Blob/RCTBlobManager.m @@ -132,7 +132,7 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) NSString *type = [RCTConvert NSString:part[@"type"]]; if ([type isEqualToString:@"blob"]) { - NSData *partData = [self resolve:part]; + NSData *partData = [self resolve:part[@"data"]]; [data appendData:partData]; } else if ([type isEqualToString:@"string"]) { NSData *partData = [[RCTConvert NSString:part[@"data"]] dataUsingEncoding:NSUTF8StringEncoding]; @@ -215,7 +215,8 @@ - (void)cancelRequest:(NSOperation *)op @end -@implementation _RCTBlobWebSocketContentHandler { +@implementation _RCTBlobWebSocketContentHandler +{ __weak RCTBlobManager *_blobManager; } @@ -244,11 +245,12 @@ - (id)processMessage:(id)message forSocketID:(NSNumber *)socketID withType:(NSSt @end -@implementation _RCTBlobXMLHttpRequestContentHandler { +@implementation _RCTBlobXMLHttpRequestContentHandler +{ __weak RCTBlobManager *_blobManager; } --(instancetype)initWithBlobManager:(RCTBlobManager *)blobManager +- (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager { if (self = [super init]) { _blobManager = blobManager; @@ -256,11 +258,13 @@ -(instancetype)initWithBlobManager:(RCTBlobManager *)blobManager return self; } -- (NSData *)processBlob:(NSDictionary *)blob { +- (NSData *)processBlob:(NSDictionary *)blob +{ return [_blobManager resolve:blob]; } -- (NSString *)storeBlob:(NSData *)data { +- (NSString *)storeBlob:(NSData *)data +{ return [_blobManager store:data]; } diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index e683cbcc20c5fb..848c99768e8951 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -59,7 +59,8 @@ class URL { if (BLOB_URL_PREFIX === null) { throw new Error('Cannot create URL for blob!'); } - return `${BLOB_URL_PREFIX}${blob.blobId}?offset=${blob.offset}&size=${blob.size}`; + return `${BLOB_URL_PREFIX}${blob.data.blobId}?offset=${blob.data + .offset}&size=${blob.size}`; } static revokeObjectURL(url: string) { diff --git a/Libraries/Blob/__mocks__/BlobModule.js b/Libraries/Blob/__mocks__/BlobModule.js index 4416caec11dbdc..386e5f28622a2b 100644 --- a/Libraries/Blob/__mocks__/BlobModule.js +++ b/Libraries/Blob/__mocks__/BlobModule.js @@ -1,5 +1,14 @@ -/* @flow */ - +/** + * 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 + * @format + */ const BlobModule = { createFromParts() {}, async createFromURI() { @@ -12,7 +21,7 @@ const BlobModule = { lastModified: 1482229709578, }; }, - release() {} + release() {}, }; module.exports = BlobModule; diff --git a/Libraries/Blob/__mocks__/FileReaderModule.js b/Libraries/Blob/__mocks__/FileReaderModule.js index a97b84a21bbed5..d4b35e00c24cc2 100644 --- a/Libraries/Blob/__mocks__/FileReaderModule.js +++ b/Libraries/Blob/__mocks__/FileReaderModule.js @@ -1,5 +1,14 @@ -/* @flow */ - +/** + * 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 + * @format + */ const FileReaderModule = { async readAsText() { return ''; diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index d86b3c553b5483..4aa058669678d0 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -1,20 +1,22 @@ /** - * 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. + * + * @format */ 'use strict'; -jest - .unmock('Blob') - .unmock('BlobManager') - .unmock('../__mocks__/BlobModule') - .setMock('NativeModules', { - BlobModule: require('../__mocks__/BlobModule'), - }); +jest.setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), +}); var Blob = require('Blob'); describe('Blob', function() { - it('should create empty blob', () => { const blob = new Blob(); expect(blob).toBeInstanceOf(Blob); @@ -29,19 +31,20 @@ describe('Blob', function() { const blobB = new Blob(); const textA = 'i ♥ dogs'; const textB = '𐀀'; - const textC = 'Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘!͖̬̰̙̗̿̋ͥͥ̂ͣ̐́́͜͞'; + const textC = + 'Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘!͖̬̰̙̗̿̋ͥͥ̂ͣ̐́́͜͞'; blobA.data.size = 34540; blobB.data.size = 65452; - const blob = new Blob([ blobA, blobB, textA, textB, textC ]); + const blob = new Blob([blobA, blobB, textA, textB, textC]); expect(blob.size).toBe( blobA.size + - blobB.size + - global.Buffer.byteLength(textA, 'UTF-8') + - global.Buffer.byteLength(textB, 'UTF-8') + - global.Buffer.byteLength(textC, 'UTF-8') + blobB.size + + global.Buffer.byteLength(textA, 'UTF-8') + + global.Buffer.byteLength(textB, 'UTF-8') + + global.Buffer.byteLength(textC, 'UTF-8'), ); expect(blob.type).toBe(''); }); @@ -71,5 +74,4 @@ describe('Blob', function() { expect(() => blob.size).toThrow(); }); - }); diff --git a/Libraries/Blob/__tests__/BlobManager-test.js b/Libraries/Blob/__tests__/BlobManager-test.js index e21ad2b1f6106a..f6b5fbf253da56 100644 --- a/Libraries/Blob/__tests__/BlobManager-test.js +++ b/Libraries/Blob/__tests__/BlobManager-test.js @@ -1,26 +1,26 @@ /** - * 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. + * + * @format */ 'use strict'; -jest - .unmock('File') - .unmock('Blob') - .unmock('BlobManager') - .unmock('../__mocks__/BlobModule') - .setMock('NativeModules', { - BlobModule: require('../__mocks__/BlobModule'), - }); +jest.setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), +}); var Blob = require('Blob'); var BlobManager = require('BlobManager'); describe('BlobManager', function() { - it('should create blob from parts', () => { - const blob = BlobManager.createFromParts([], { type: 'text/html' }); + const blob = BlobManager.createFromParts([], {type: 'text/html'}); expect(blob).toBeInstanceOf(Blob); expect(blob.type).toBe('text/html'); }); - }); diff --git a/Libraries/Blob/__tests__/File-test.js b/Libraries/Blob/__tests__/File-test.js index 8695d73cd9f0c9..5e686d4ba13846 100644 --- a/Libraries/Blob/__tests__/File-test.js +++ b/Libraries/Blob/__tests__/File-test.js @@ -1,35 +1,45 @@ /** - * 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. + * + * @format */ 'use strict'; -jest - .unmock('File') - .unmock('Blob') - .unmock('BlobManager') - .unmock('../__mocks__/BlobModule') - .setMock('NativeModules', { - BlobModule: require('../__mocks__/BlobModule'), - }); +jest.setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), +}); -var File = require('File'); +const File = require('File'); describe('File', function() { - it('should create empty file', () => { - const file = new File(); + const file = new File([], 'test.jpg'); expect(file).toBeInstanceOf(File); expect(file.data.offset).toBe(0); expect(file.data.size).toBe(0); expect(file.size).toBe(0); expect(file.type).toBe(''); - expect(file.name).toBe(''); - expect(file.lastModified).toBe(0); + expect(file.name).toBe('test.jpg'); + expect(file.lastModified).toEqual(expect.any(Number)); }); it('should create empty file with type', () => { - const file = new File([], { type: 'image/jpeg' }); + const file = new File([], 'test.jpg', {type: 'image/jpeg'}); expect(file.type).toBe('image/jpeg'); }); + it('should create empty file with lastModified', () => { + const file = new File([], 'test.jpg', {lastModified: 1337}); + expect(file.lastModified).toBe(1337); + }); + + it('should throw on invalid arguments', () => { + expect(() => new File()).toThrow(); + expect(() => new File([])).toThrow(); + }); }); diff --git a/Libraries/Blob/__tests__/FileReader-test.js b/Libraries/Blob/__tests__/FileReader-test.js index f032242da95172..3d56e8f324e0f6 100644 --- a/Libraries/Blob/__tests__/FileReader-test.js +++ b/Libraries/Blob/__tests__/FileReader-test.js @@ -1,24 +1,24 @@ /** - * 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. + * + * @format */ 'use strict'; -jest - .disableAutomock() - .unmock('event-target-shim') - .setMock('NativeModules', { - BlobModule: require('../__mocks__/BlobModule'), - FileReaderModule: require('../__mocks__/FileReaderModule'), - }) - .setMock('Platform', { - OS: 'android' // remove when iOS is implemented - }); +jest.unmock('event-target-shim').setMock('NativeModules', { + BlobModule: require('../__mocks__/BlobModule'), + FileReaderModule: require('../__mocks__/FileReaderModule'), +}); var Blob = require('Blob'); var FileReader = require('FileReader'); describe('FileReader', function() { - it('should read blob as text', async () => { const e = await new Promise((resolve, reject) => { const reader = new FileReader(); @@ -38,5 +38,4 @@ describe('FileReader', function() { }); expect(e.target.result).toBe('data:text/plain;base64,NDI='); }); - }); diff --git a/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj b/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj index 4300e84bdcdda0..2ca45336dd64d4 100644 --- a/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj +++ b/Libraries/Network/RCTNetwork.xcodeproj/project.pbxproj @@ -248,7 +248,6 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../Blob"; WARNING_CFLAGS = ( "-Werror", "-Wall", @@ -293,7 +292,6 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../Blob"; VALIDATE_PRODUCT = YES; WARNING_CFLAGS = ( "-Werror", diff --git a/Libraries/Network/RCTNetworking.mm b/Libraries/Network/RCTNetworking.mm index 6664cd4d47cb8c..c69b18b9428518 100644 --- a/Libraries/Network/RCTNetworking.mm +++ b/Libraries/Network/RCTNetworking.mm @@ -327,12 +327,6 @@ - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary return callback(nil, @{@"body": data}); } } - - // RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]]; - // NSData *data = [blobManager resolve:blob]; - // if (data) { - // return callback(nil, @{@"body": data}); - // } } NSString *base64String = [RCTConvert NSString:query[@"base64"]]; if (base64String) { @@ -429,9 +423,9 @@ + (NSString *)decodeTextData:(NSData *)data fromResponse:(NSURLResponse *)respon - (void)sendData:(NSData *)data responseType:(NSString *)responseType - mimeType:(NSString *)mimeType - fileName:(NSString *)fileName - forTask:(RCTNetworkTask *)task + mimeType:(NSString *)mimeType + fileName:(NSString *)fileName + forTask:(RCTNetworkTask *)task { RCTAssertThread(_methodQueue, @"sendData: must be called on method queue"); @@ -552,9 +546,9 @@ - (void)sendRequest:(NSURLRequest *)request if (!(incrementalUpdates && [responseType isEqualToString:@"text"])) { [strongSelf sendData:data responseType:responseType - mimeType:[response MIMEType] - fileName:[response suggestedFilename] - forTask:task]; + mimeType:[response MIMEType] + fileName:[response suggestedFilename] + forTask:task]; } NSArray *responseJSON = @[task.requestID, RCTNullIfNil(error.localizedDescription), diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index f7f243e8d52e66..f55adf2c2b2f40 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -152,11 +152,6 @@ public WritableMap toResponseData(ResponseBody body) throws IOException { public BlobModule(ReactApplicationContext reactContext) { super(reactContext); - - // Enable Blob support for networking modules - NetworkingModule.addUriHandler(NetworkingUriHandler); - NetworkingModule.addRequestBodyHandler(NetworkingRequestBodyHandler); - NetworkingModule.addResponseHandler(NetworkingResponseHandler); } @Override @@ -288,7 +283,21 @@ private static String getMimeTypeFromUri(Uri contentUri, ContentResolver resolve return type; } - + + @ReactMethod + public void addXMLHttpRequestHandler() { + NetworkingModule.addUriHandler(NetworkingUriHandler); + NetworkingModule.addRequestBodyHandler(NetworkingRequestBodyHandler); + NetworkingModule.addResponseHandler(NetworkingResponseHandler); + } + + @ReactMethod + public void removeXMLHttpRequestHandler() { + NetworkingModule.removeUriHandler(NetworkingUriHandler); + NetworkingModule.removeRequestBodyHandler(NetworkingRequestBodyHandler); + NetworkingModule.removeResponseHandler(NetworkingResponseHandler); + } + private WebSocketModule getWebSocketModule() { return getReactApplicationContext().getNativeModule(WebSocketModule.class); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 8b4f726f3ddc4f..889399db8a45ec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -191,6 +191,18 @@ public static void addResponseHandler(ResponseHandler handler) { mResponseHandlers.add(handler); } + public static void removeUriHandler(UriHandler handler) { + mUriHandlers.remove(handler); + } + + public static void removeRequestBodyHandler(RequestBodyHandler handler) { + mRequestBodyHandlers.remove(handler); + } + + public static void removeResponseHandler(ResponseHandler handler) { + mResponseHandlers.remove(handler); + } + @ReactMethod /** * @param timeout value of 0 results in no timeout diff --git a/Libraries/lib/InitializeJavaScriptAppEngine.js b/lib/InitializeJavaScriptAppEngine.js similarity index 100% rename from Libraries/lib/InitializeJavaScriptAppEngine.js rename to lib/InitializeJavaScriptAppEngine.js diff --git a/Libraries/lib/RCTEventEmitter.js b/lib/RCTEventEmitter.js similarity index 100% rename from Libraries/lib/RCTEventEmitter.js rename to lib/RCTEventEmitter.js diff --git a/Libraries/lib/README b/lib/README similarity index 100% rename from Libraries/lib/README rename to lib/README diff --git a/Libraries/lib/TextInputState.js b/lib/TextInputState.js similarity index 100% rename from Libraries/lib/TextInputState.js rename to lib/TextInputState.js diff --git a/Libraries/lib/UIManager.js b/lib/UIManager.js similarity index 100% rename from Libraries/lib/UIManager.js rename to lib/UIManager.js diff --git a/Libraries/lib/UIManagerStatTracker.js b/lib/UIManagerStatTracker.js similarity index 100% rename from Libraries/lib/UIManagerStatTracker.js rename to lib/UIManagerStatTracker.js diff --git a/Libraries/lib/View.js b/lib/View.js similarity index 100% rename from Libraries/lib/View.js rename to lib/View.js diff --git a/Libraries/lib/deepDiffer.js b/lib/deepDiffer.js similarity index 100% rename from Libraries/lib/deepDiffer.js rename to lib/deepDiffer.js diff --git a/Libraries/lib/deepFreezeAndThrowOnMutationInDev.js b/lib/deepFreezeAndThrowOnMutationInDev.js similarity index 100% rename from Libraries/lib/deepFreezeAndThrowOnMutationInDev.js rename to lib/deepFreezeAndThrowOnMutationInDev.js diff --git a/Libraries/lib/flattenStyle.js b/lib/flattenStyle.js similarity index 100% rename from Libraries/lib/flattenStyle.js rename to lib/flattenStyle.js diff --git a/local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj b/local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj index 5b87cf351f5086..606ef9c915635c 100644 --- a/local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj +++ b/local-cli/templates/HelloWorld/ios/HelloWorld.xcodeproj/project.pbxproj @@ -159,6 +159,48 @@ remoteGlobalIDString = 2D2A28131D9B038B00D4039D; remoteInfo = "React-tvOS"; }; + 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C059A1DE3340900C268FA; + remoteInfo = yoga; + }; + 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3C06751DE3340C00C268FA; + remoteInfo = "yoga-tvOS"; + }; + 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9251DE5FBEC00167DC4; + remoteInfo = cxxreact; + }; + 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9321DE5FBEE00167DC4; + remoteInfo = "cxxreact-tvOS"; + }; + 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD90B1DE5FBD600167DC4; + remoteInfo = jschelpers; + }; + 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 3D3CD9181DE5FBD800167DC4; + remoteInfo = "jschelpers-tvOS"; + }; 5E9157321DD0AC6500FF2AA8 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5E91572D1DD0AC6500FF2AA8 /* RCTAnimation.xcodeproj */; @@ -739,6 +781,48 @@ remoteRef = 3DAD3EA21DF850E9000B6D8A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 3DAD3EA51DF850E9000B6D8A /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = 3DAD3EA41DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EA71DF850E9000B6D8A /* libyoga.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libyoga.a; + remoteRef = 3DAD3EA61DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EA91DF850E9000B6D8A /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = 3DAD3EA81DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EAB1DF850E9000B6D8A /* libcxxreact.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libcxxreact.a; + remoteRef = 3DAD3EAA1DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EAD1DF850E9000B6D8A /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = 3DAD3EAC1DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 3DAD3EAF1DF850E9000B6D8A /* libjschelpers.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libjschelpers.a; + remoteRef = 3DAD3EAE1DF850E9000B6D8A /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 5E9157331DD0AC6500FF2AA8 /* libRCTAnimation.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; From 6159d5b104b91b963cd2185850c783b6fafd2a35 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Tue, 3 Oct 2017 18:59:10 -0400 Subject: [PATCH 34/66] Xcodeproj fixes, add ios tests --- .../Blob/RCTBlob.xcodeproj/project.pbxproj | 8 ++ Libraries/Blob/RCTBlobManager.h | 4 + Libraries/Blob/RCTBlobManager.m | 7 +- RNTester/RNTester.xcodeproj/project.pbxproj | 14 +++ .../RNTesterUnitTests/RCTBlobManagerTests.m | 96 +++++++++++++++++++ .../react/modules/blob/BlobModuleTest.java | 5 - 6 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 RNTester/RNTesterUnitTests/RCTBlobManagerTests.m diff --git a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj index 09d9e76c89b3f7..8586d1ad41d3ea 100755 --- a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj +++ b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj @@ -7,6 +7,10 @@ objects = { /* Begin PBXBuildFile section */ + 19BA88FE1F84391700741C5A /* RCTFileReaderModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; }; + 19BA88FF1F84392900741C5A /* RCTFileReaderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; }; + 19BA89001F84392F00741C5A /* RCTFileReaderModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; }; + 19BA89011F84393D00741C5A /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */; }; AD0871131E215B28007D136D /* RCTBlobManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; AD0871161E215EC9007D136D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; AD0871181E215ED1007D136D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; @@ -24,6 +28,7 @@ dstPath = include/RCTBlob; dstSubfolderSpec = 16; files = ( + 19BA88FE1F84391700741C5A /* RCTFileReaderModule.h in Copy Headers */, AD08711A1E2162C8007D136D /* RCTBlobManager.h in Copy Headers */, ); name = "Copy Headers"; @@ -35,6 +40,7 @@ dstPath = include/RCTBlob; dstSubfolderSpec = 16; files = ( + 19BA89001F84392F00741C5A /* RCTFileReaderModule.h in Copy Headers */, AD0871131E215B28007D136D /* RCTBlobManager.h in Copy Headers */, ); name = "Copy Headers"; @@ -91,6 +97,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 19BA88FF1F84392900741C5A /* RCTFileReaderModule.h in Headers */, AD0871181E215ED1007D136D /* RCTBlobManager.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -182,6 +189,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 19BA89011F84393D00741C5A /* RCTFileReaderModule.m in Sources */, ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Libraries/Blob/RCTBlobManager.h b/Libraries/Blob/RCTBlobManager.h index 1d5427aa3f9e88..4667340874187b 100755 --- a/Libraries/Blob/RCTBlobManager.h +++ b/Libraries/Blob/RCTBlobManager.h @@ -21,4 +21,8 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size; +- (void)remove:(NSString *)blobId; + +- (void)createFromParts:(NSArray *> *)parts withId:(NSString *)blobId; + @end diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.m index 184525ae06c565..e6b1c005d6b140 100755 --- a/Libraries/Blob/RCTBlobManager.m +++ b/Libraries/Blob/RCTBlobManager.m @@ -94,6 +94,11 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) return data; } +- (void)remove:(NSString *)blobId +{ + [_blobs removeObjectForKey:blobId]; +} + RCT_EXPORT_METHOD(addXMLHttpRequestHandler) { if (!_xmlHttpRequestContentHandler) { @@ -146,7 +151,7 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) RCT_EXPORT_METHOD(release:(NSString *)blobId) { - [_blobs removeObjectForKey:blobId]; + [self remove:blobId]; } #pragma mark - RCTURLRequestHandler methods diff --git a/RNTester/RNTester.xcodeproj/project.pbxproj b/RNTester/RNTester.xcodeproj/project.pbxproj index 039f9c656f2436..fee5f3b3fed081 100644 --- a/RNTester/RNTester.xcodeproj/project.pbxproj +++ b/RNTester/RNTester.xcodeproj/project.pbxproj @@ -54,6 +54,8 @@ 192F69B91E82409A008692C7 /* RCTConvert_YGValueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */; }; 192F69BA1E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */; }; 192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13E501A31D07A502005F35D8 /* libRCTAnimation.a */; }; + 19BA88D51F84344F00741C5A /* RCTBlobManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 19BA88D41F84344F00741C5A /* RCTBlobManagerTests.m */; }; + 19BA89031F8439A700741C5A /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5281CA511EEAC9A700AC40CD /* libRCTBlob.a */; }; 272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; }; 27B885561BED29AF00008352 /* RCTRootViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */; }; 27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; }; @@ -489,6 +491,7 @@ 192F69B51E82409A008692C7 /* RCTAnimationUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationUtilsTests.m; sourceTree = ""; }; 192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert_YGValueTests.m; sourceTree = ""; }; 192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNativeAnimatedNodesManagerTests.m; sourceTree = ""; }; + 19BA88D41F84344F00741C5A /* RCTBlobManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTBlobManagerTests.m; sourceTree = ""; }; 272E6B3B1BEA849E001FCF37 /* UpdatePropertiesExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdatePropertiesExampleView.h; path = RNTester/NativeExampleViews/UpdatePropertiesExampleView.h; sourceTree = ""; }; 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UpdatePropertiesExampleView.m; path = RNTester/NativeExampleViews/UpdatePropertiesExampleView.m; sourceTree = ""; }; 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootViewIntegrationTests.m; sourceTree = ""; }; @@ -526,6 +529,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 19BA89031F8439A700741C5A /* libRCTBlob.a in Frameworks */, 192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */, 14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */, 14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */, @@ -729,6 +733,7 @@ isa = PBXGroup; children = ( 192F69B51E82409A008692C7 /* RCTAnimationUtilsTests.m */, + 19BA88D41F84344F00741C5A /* RCTBlobManagerTests.m */, 192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */, 192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */, 13B6C1A21C34225900D3FAF5 /* RCTURLUtilsTests.m */, @@ -842,6 +847,13 @@ name = Products; sourceTree = ""; }; + 19BA89021F8439A700741C5A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; 272E6B3A1BEA846C001FCF37 /* NativeExampleViews */ = { isa = PBXGroup; children = ( @@ -928,6 +940,7 @@ 14D6D6EA1B2205C0001FB087 /* OCMock */, 2DD323911DA2DD8B000FE1B8 /* RNTester-tvOS */, 83CBBA001A601CBA00E9B192 /* Products */, + 19BA89021F8439A700741C5A /* Frameworks */, ); indentWidth = 2; sourceTree = ""; @@ -1607,6 +1620,7 @@ 8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */, 192F69B91E82409A008692C7 /* RCTConvert_YGValueTests.m in Sources */, BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */, + 19BA88D51F84344F00741C5A /* RCTBlobManagerTests.m in Sources */, 68FF44381CF6111500720EFD /* RCTBundleURLProviderTests.m in Sources */, 8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */, ); diff --git a/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m b/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m new file mode 100644 index 00000000000000..a85f36cd434062 --- /dev/null +++ b/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m @@ -0,0 +1,96 @@ +/** + * 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 + +#import + +@interface RCTBlobManagerTests : XCTestCase + +@end + +@implementation RCTBlobManagerTests +{ + RCTBlobManager *_module; + NSMutableData *_data; + NSString *_blobId; +} + +- (void)setUp +{ + [super setUp]; + + _module = [RCTBlobManager new]; + NSInteger size = 120; + _data = [NSMutableData dataWithCapacity:size]; + for (NSInteger i = 0; i < size / 4; i++) { + uint32_t randomBits = arc4random(); + [_data appendBytes:(void *)&randomBits length:4]; + } + _blobId = [NSUUID UUID].UUIDString; + [_module store:_data withId:_blobId]; +} + +- (void)testResolve +{ + XCTAssertTrue([_data isEqualToData:[_module resolve:_blobId offset:0 size:_data.length]]); + NSData *rangeData = [_data subdataWithRange:NSMakeRange(30, _data.length - 30)]; + XCTAssertTrue([rangeData isEqualToData:[_module resolve:_blobId offset:30 size:_data.length - 30]]); +} + +- (void)testResolveMap +{ + NSDictionary *map = @{ + @"blobId": _blobId, + @"size": @(_data.length), + @"offset": @(0), + }; + XCTAssertTrue([_data isEqualToData:[_module resolve:map]]); +} + +- (void)testRemove +{ + XCTAssertNotNil([_module resolve:_blobId offset:0 size:_data.length]); + [_module remove:_blobId]; + XCTAssertNil([_module resolve:_blobId offset:0 size:_data.length]); +} + +- (void)testCreateFromParts +{ + NSDictionary *blobData = @{ + @"blobId": _blobId, + @"offset": @(0), + @"size": @(_data.length), + }; + NSDictionary *blob = @{ + @"data": blobData, + @"type": @"blob", + }; + NSString *stringData = @"i ♥ dogs"; + NSDictionary *string = @{ + @"data": stringData, + @"type": @"string", + }; + NSString *resultId = [NSUUID UUID].UUIDString; + NSArray *parts = @[blob, string]; + + [_module createFromParts:parts withId:resultId]; + + NSMutableData *expectedData = [NSMutableData new]; + [expectedData appendData:_data]; + [expectedData appendData:[stringData dataUsingEncoding:NSUTF8StringEncoding]]; + + NSData *result = [_module resolve:resultId offset:0 size:expectedData.length]; + + XCTAssertTrue([expectedData isEqualToData:result]); +} + +@end + diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java index bef9cdb645d36b..d9c8cdb829e7a1 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java @@ -135,11 +135,6 @@ public void testCreateFromParts() { blobModule.createFromParts(parts, id); - JavaOnlyMap resultBlob = new JavaOnlyMap(); - resultBlob.putString("blobId", id); - blob.putInt("offset", 0); - blob.putInt("size", bytes.length); - int resultSize = bytes.length + stringBytes.length; byte[] result = BlobModule.resolve(id, 0, resultSize); From cc9a4255fda223754705101471fd8f5df218118c Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Wed, 4 Oct 2017 18:45:13 -0400 Subject: [PATCH 35/66] Improve architecture and fix potential thread safety issues on iOS --- Libraries/Blob/BlobManager.js | 40 +++- .../Blob/RCTBlob.xcodeproj/project.pbxproj | 12 +- Libraries/Blob/RCTBlobManager.h | 2 + .../{RCTBlobManager.m => RCTBlobManager.mm} | 193 +++++++++--------- Libraries/Network/RCTNetworking.h | 21 +- Libraries/Network/RCTNetworking.mm | 104 ++++++---- Libraries/Network/XMLHttpRequest.js | 19 +- Libraries/WebSocket/RCTWebSocketModule.h | 5 +- Libraries/WebSocket/RCTWebSocketModule.m | 7 +- Libraries/WebSocket/WebSocket.js | 22 +- .../RNTesterUnitTests/RCTBlobManagerTests.m | 9 + .../react/modules/blob/BlobModule.java | 9 +- 12 files changed, 260 insertions(+), 183 deletions(-) rename Libraries/Blob/{RCTBlobManager.m => RCTBlobManager.mm} (57%) diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 451a632839c3c7..e2cc2e613c7a4f 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -21,9 +21,14 @@ const {BlobModule} = require('NativeModules'); import type {BlobData, BlobOptions} from 'BlobTypes'; /** - * Module to manage blobs + * Module to manage blobs. Wrapper around the native blob module. */ class BlobManager { + /** + * If the native blob module is available. + */ + static isAvailable = !!BlobModule; + /** * Create blob from existing array of blobs. */ @@ -84,13 +89,44 @@ class BlobManager { /** * Deallocate resources for a blob. */ - static release(blobId: string) { + static release(blobId: string): void { BlobRegistry.unregister(blobId); if (BlobRegistry.has(blobId)) { return; } BlobModule.release(blobId); } + + /** + * Inject the blob content handler in the networking module to support blob + * requests and responses. + */ + static addNetworkingHandler(): void { + BlobModule.addNetworkingHandler(); + } + + /** + * Indicate the the websocket should return a blob for incoming binary + * messages. + */ + static addWebSocketHandler(socketId: number): void { + BlobModule.addWebSocketHandler(socketId); + } + + /** + * Indicate the the websocket should no longer return a blob for incoming + * binary messages. + */ + static removeWebSocketHandler(socketId: number): void { + BlobModule.removeWebSocketHandler(socketId); + } + + /** + * Send a blob message to a websocket. + */ + static sendOverSocket(data: Blob, socketId: number): void { + BlobModule.sendOverSocket(data, socketId); + } } module.exports = BlobManager; diff --git a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj index 8586d1ad41d3ea..869ba4bc73b422 100755 --- a/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj +++ b/Libraries/Blob/RCTBlob.xcodeproj/project.pbxproj @@ -15,8 +15,8 @@ AD0871161E215EC9007D136D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; AD0871181E215ED1007D136D /* RCTBlobManager.h in Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; AD08711A1E2162C8007D136D /* RCTBlobManager.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */; }; - AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; - ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */; }; + AD9A43C31DFC7126008DC588 /* RCTBlobManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */; }; + ADD01A711E09404A00F6D226 /* RCTBlobManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */; }; ADDFBA6C1F33455F0064C998 /* RCTFileReaderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */; }; ADDFBA6D1F33455F0064C998 /* RCTFileReaderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */; }; /* End PBXBuildFile section */ @@ -51,7 +51,7 @@ /* Begin PBXFileReference section */ 358F4ED71D1E81A9004DF814 /* libRCTBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTBlob.a; sourceTree = BUILT_PRODUCTS_DIR; }; AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBlobManager.h; sourceTree = ""; }; - AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTBlobManager.m; sourceTree = ""; }; + AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RCTBlobManager.mm; sourceTree = ""; }; ADD01A681E09402E00F6D226 /* libRCTBlob-tvOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libRCTBlob-tvOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTFileReaderModule.h; sourceTree = ""; }; ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTFileReaderModule.m; sourceTree = ""; }; @@ -64,7 +64,7 @@ ADDFBA6A1F33455F0064C998 /* RCTFileReaderModule.h */, ADDFBA6B1F33455F0064C998 /* RCTFileReaderModule.m */, AD9A43C11DFC7126008DC588 /* RCTBlobManager.h */, - AD9A43C21DFC7126008DC588 /* RCTBlobManager.m */, + AD9A43C21DFC7126008DC588 /* RCTBlobManager.mm */, 358F4ED81D1E81A9004DF814 /* Products */, ); indentWidth = 2; @@ -181,7 +181,7 @@ buildActionMask = 2147483647; files = ( ADDFBA6D1F33455F0064C998 /* RCTFileReaderModule.m in Sources */, - AD9A43C31DFC7126008DC588 /* RCTBlobManager.m in Sources */, + AD9A43C31DFC7126008DC588 /* RCTBlobManager.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -190,7 +190,7 @@ buildActionMask = 2147483647; files = ( 19BA89011F84393D00741C5A /* RCTFileReaderModule.m in Sources */, - ADD01A711E09404A00F6D226 /* RCTBlobManager.m in Sources */, + ADD01A711E09404A00F6D226 /* RCTBlobManager.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Libraries/Blob/RCTBlobManager.h b/Libraries/Blob/RCTBlobManager.h index 4667340874187b..8e8d355f60b7ac 100755 --- a/Libraries/Blob/RCTBlobManager.h +++ b/Libraries/Blob/RCTBlobManager.h @@ -21,6 +21,8 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size; +- (NSData *)resolveURL:(NSURL *)url; + - (void)remove:(NSString *)blobId; - (void)createFromParts:(NSArray *> *)parts withId:(NSString *)blobId; diff --git a/Libraries/Blob/RCTBlobManager.m b/Libraries/Blob/RCTBlobManager.mm similarity index 57% rename from Libraries/Blob/RCTBlobManager.m rename to Libraries/Blob/RCTBlobManager.mm index e6b1c005d6b140..8780d6b9e8c189 100755 --- a/Libraries/Blob/RCTBlobManager.m +++ b/Libraries/Blob/RCTBlobManager.mm @@ -15,23 +15,17 @@ static NSString *const kBlobUriScheme = @"blob"; -@interface _RCTBlobWebSocketContentHandler : NSObject - -- (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager; - -@end - -@interface _RCTBlobXMLHttpRequestContentHandler : NSObject - -- (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager; +@interface RCTBlobManager () @end @implementation RCTBlobManager { + // Blobs should be thread safe since they are used from the websocket and networking module, + // make sure to use proper locking when accessing this. NSMutableDictionary *_blobs; - _RCTBlobWebSocketContentHandler *_webSocketContentHandler; - _RCTBlobXMLHttpRequestContentHandler *_xmlHttpRequestContentHandler; + std::mutex _blobsMutex; + NSOperationQueue *_queue; } @@ -39,6 +33,12 @@ @implementation RCTBlobManager @synthesize bridge = _bridge; +- (void)setBridge:(RCTBridge *)bridge +{ + _bridge = bridge; + _blobs = [NSMutableDictionary new]; +} + + (BOOL)requiresMainQueueSetup { return NO; @@ -52,11 +52,6 @@ + (BOOL)requiresMainQueueSetup }; } -- (dispatch_queue_t)methodQueue -{ - return [[_bridge webSocketModule] methodQueue]; -} - - (NSString *)store:(NSData *)data { NSString *blobId = [NSUUID UUID].UUIDString; @@ -66,9 +61,7 @@ - (NSString *)store:(NSData *)data - (void)store:(NSData *)data withId:(NSString *)blobId { - if (!_blobs) { - _blobs = [NSMutableDictionary new]; - } + std::lock_guard lock(_blobsMutex); _blobs[blobId] = data; } @@ -84,7 +77,11 @@ - (NSData *)resolve:(NSDictionary *)blob - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size { - NSData *data = _blobs[blobId]; + NSData *data; + { + std::lock_guard lock(_blobsMutex); + data = _blobs[blobId]; + } if (!data) { return nil; } @@ -94,40 +91,64 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) return data; } -- (void)remove:(NSString *)blobId +- (NSData *)resolveURL:(NSURL *)url { - [_blobs removeObjectForKey:blobId]; + NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO]; + + NSString *blobId = components.path; + NSInteger offset = 0; + NSInteger size = -1; + + if (components.queryItems) { + for (NSURLQueryItem *queryItem in components.queryItems) { + if ([queryItem.name isEqualToString:@"offset"]) { + offset = [queryItem.value integerValue]; + } + if ([queryItem.name isEqualToString:@"size"]) { + size = [queryItem.value integerValue]; + } + } + } + + if (blobId) { + return [self resolve:blobId offset:offset size:size]; + } + return nil; } -RCT_EXPORT_METHOD(addXMLHttpRequestHandler) +- (void)remove:(NSString *)blobId { - if (!_xmlHttpRequestContentHandler) { - _xmlHttpRequestContentHandler = [[_RCTBlobXMLHttpRequestContentHandler alloc] initWithBlobManager:self]; - } - [[_bridge networking] setContentHandler:_xmlHttpRequestContentHandler]; + std::lock_guard lock(_blobsMutex); + [_blobs removeObjectForKey:blobId]; } -RCT_EXPORT_METHOD(removeXMLHttpRequestHandler) +RCT_EXPORT_METHOD(addNetworkingHandler) { - [[_bridge networking] setContentHandler:nil]; + dispatch_async(_bridge.networking.methodQueue, ^{ + [self->_bridge.networking addRequestHandler:self]; + [self->_bridge.networking addResponseHandler:self]; + }); } RCT_EXPORT_METHOD(addWebSocketHandler:(nonnull NSNumber *)socketID) { - if (!_webSocketContentHandler) { - _webSocketContentHandler = [[_RCTBlobWebSocketContentHandler alloc] initWithBlobManager:self]; - } - [[_bridge webSocketModule] setContentHandler:_webSocketContentHandler forSocketID:socketID]; + dispatch_async(_bridge.webSocketModule.methodQueue, ^{ + [self->_bridge.webSocketModule setContentHandler:self forSocketID:socketID]; + }); } RCT_EXPORT_METHOD(removeWebSocketHandler:(nonnull NSNumber *)socketID) { - [[_bridge webSocketModule] setContentHandler:nil forSocketID:socketID]; + dispatch_async(_bridge.webSocketModule.methodQueue, ^{ + [self->_bridge.webSocketModule setContentHandler:nil forSocketID:socketID]; + }); } RCT_EXPORT_METHOD(sendOverSocket:(NSDictionary *)blob socketID:(nonnull NSNumber *)socketID) { - [[_bridge webSocketModule] sendData:[self resolve:blob] forSocketID:socketID]; + dispatch_async(_bridge.webSocketModule.methodQueue, ^{ + [self->_bridge.webSocketModule sendData:[self resolve:blob] forSocketID:socketID]; + }); } RCT_EXPORT_METHOD(createFromParts:(NSArray *> *)parts withId:(NSString *)blobId) @@ -169,8 +190,13 @@ - (id)sendRequest:(NSURLRequest *)request withDelegate:(id 0) { + contentType = blob[@"type"]; } - - *type = @"blob"; - return @{ - @"blobId": [_blobManager store:message], - @"offset": @0, - @"size": @(((NSData *)message).length), - }; + + return @{@"body": [self resolve:blob], @"contentType": contentType}; } -@end - -@implementation _RCTBlobXMLHttpRequestContentHandler +- (BOOL)canHandleNetworkingResponse:(NSString *)responseType { - __weak RCTBlobManager *_blobManager; + return [responseType isEqualToString:@"blob"]; } -- (instancetype)initWithBlobManager:(RCTBlobManager *)blobManager +- (id)handleNetworkingResponse:(NSURLResponse *)response data:(NSData *)data { - if (self = [super init]) { - _blobManager = blobManager; - } - return self; + return @{ + @"blobId": [self store:data], + @"offset": @0, + @"size": @(data.length), + @"name": [response suggestedFilename], + @"type": [response MIMEType], + }; } -- (NSData *)processBlob:(NSDictionary *)blob -{ - return [_blobManager resolve:blob]; -} +#pragma mark - RCTWebSocketContentHandler methods -- (NSString *)storeBlob:(NSData *)data +- (id)processWebsocketMessage:(id)message + forSocketID:(NSNumber *)socketID + withType:(NSString *__autoreleasing _Nonnull *)type { - return [_blobManager store:data]; + if (![message isKindOfClass:[NSData class]]) { + *type = @"text"; + return message; + } + + *type = @"blob"; + return @{ + @"blobId": [self store:message], + @"offset": @0, + @"size": @(((NSData *)message).length), + }; } @end + diff --git a/Libraries/Network/RCTNetworking.h b/Libraries/Network/RCTNetworking.h index 23cdf69205e11c..ac6696b587e52f 100644 --- a/Libraries/Network/RCTNetworking.h +++ b/Libraries/Network/RCTNetworking.h @@ -10,10 +10,17 @@ #import #import -@protocol RCTXMLHttpRequestContentHandler +@protocol RCTNetworkingRequestHandler -- (NSData *)processBlob:(NSDictionary *)blob; -- (NSString *)storeBlob:(NSData *)data; +- (BOOL)canHandleNetworkingRequest:(NSDictionary *)data; +- (NSDictionary *)handleNetworkingRequest:(NSDictionary *)data; + +@end + +@protocol RCTNetworkingResponseHandler + +- (BOOL)canHandleNetworkingResponse:(NSString *)responseType; +- (id)handleNetworkingResponse:(NSURLResponse *)response data:(NSData *)data; @end @@ -31,7 +38,13 @@ - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request completionBlock:(RCTURLRequestCompletionBlock)completionBlock; -- (void)setContentHandler:(id)handler; +- (void)addRequestHandler:(id)handler; + +- (void)addResponseHandler:(id)handler; + +- (void)removeRequestHandler:(id)handler; + +- (void)removeResponseHandler:(id)handler; @end diff --git a/Libraries/Network/RCTNetworking.mm b/Libraries/Network/RCTNetworking.mm index c69b18b9428518..459b6d18a7bb77 100644 --- a/Libraries/Network/RCTNetworking.mm +++ b/Libraries/Network/RCTNetworking.mm @@ -131,13 +131,20 @@ @implementation RCTNetworking NSMutableDictionary *_tasksByRequestID; std::mutex _handlersLock; NSArray> *_handlers; - id _contentHandler; + NSMutableArray> *_requestHandlers; + NSMutableArray> *_responseHandlers; } @synthesize methodQueue = _methodQueue; RCT_EXPORT_MODULE() +- (void)invalidate +{ + _requestHandlers = nil; + _responseHandlers = nil; +} + - (NSArray *)supportedEvents { return @[@"didCompleteNetworkResponse", @@ -315,19 +322,18 @@ - (RCTURLRequestCancellationBlock)processDataForHTTPQuery:(nullable NSDictionary if (!query) { return callback(nil, nil); } + for (id handler in _requestHandlers) { + if ([handler canHandleNetworkingRequest:query]) { + NSDictionary *body = [handler handleNetworkingRequest:query]; + if (body) { + return callback(nil, body); + } + } + } NSData *body = [RCTConvert NSData:query[@"string"]]; if (body) { return callback(nil, @{@"body": body}); } - NSDictionary *blob = [RCTConvert NSDictionary:query[@"blob"]]; - if (blob) { - if (_contentHandler) { - NSData *data = [_contentHandler processBlob:blob]; - if (data) { - return callback(nil, @{@"body": data}); - } - } - } NSString *base64String = [RCTConvert NSString:query[@"base64"]]; if (base64String) { NSData *data = [[NSData alloc] initWithBase64EncodedString:base64String options:0]; @@ -423,8 +429,7 @@ + (NSString *)decodeTextData:(NSData *)data fromResponse:(NSURLResponse *)respon - (void)sendData:(NSData *)data responseType:(NSString *)responseType - mimeType:(NSString *)mimeType - fileName:(NSString *)fileName + response:(NSURLResponse *)response forTask:(RCTNetworkTask *)task { RCTAssertThread(_methodQueue, @"sendData: must be called on method queue"); @@ -433,36 +438,31 @@ - (void)sendData:(NSData *)data return; } - NSArray *responseJSON; + id responseData = nil; + for (id handler in _responseHandlers) { + if ([handler canHandleNetworkingResponse:responseType]) { + responseData = [handler handleNetworkingResponse:response data:data]; + break; + } + } - if ([responseType isEqualToString:@"text"]) { - // No carry storage is required here because the entire data has been loaded. - NSString *responseString = [RCTNetworking decodeTextData:data fromResponse:task.response withCarryData:nil]; - if (!responseString) { - RCTLogWarn(@"Received data was not a string, or was not a recognised encoding."); + if (!responseData) { + if ([responseType isEqualToString:@"text"]) { + // No carry storage is required here because the entire data has been loaded. + responseData = [RCTNetworking decodeTextData:data fromResponse:task.response withCarryData:nil]; + if (!responseData) { + RCTLogWarn(@"Received data was not a string, or was not a recognised encoding."); + return; + } + } else if ([responseType isEqualToString:@"base64"]) { + responseData = [data base64EncodedStringWithOptions:0]; + } else { + RCTLogWarn(@"Invalid responseType: %@", responseType); return; } - responseJSON = @[task.requestID, responseString]; - } else if ([responseType isEqualToString:@"blob"]) { - if (_contentHandler) { - NSDictionary *responseData = @{ - @"blobId": [_contentHandler storeBlob:data], - @"offset": @0, - @"size": @(data.length), - @"name": fileName, - @"type": mimeType, - }; - responseJSON = @[task.requestID, responseData]; - } - } else if ([responseType isEqualToString:@"base64"]) { - NSString *responseString = [data base64EncodedStringWithOptions:0]; - responseJSON = @[task.requestID, responseString]; - } else { - RCTLogWarn(@"Invalid responseType: %@", responseType); - return; } - [self sendEventWithName:@"didReceiveNetworkData" body:responseJSON]; + [self sendEventWithName:@"didReceiveNetworkData" body:@[task.requestID, responseData]]; } - (void)sendRequest:(NSURLRequest *)request @@ -546,8 +546,7 @@ - (void)sendRequest:(NSURLRequest *)request if (!(incrementalUpdates && [responseType isEqualToString:@"text"])) { [strongSelf sendData:data responseType:responseType - mimeType:[response MIMEType] - fileName:[response suggestedFilename] + response:response forTask:task]; } NSArray *responseJSON = @[task.requestID, @@ -576,12 +575,33 @@ - (void)sendRequest:(NSURLRequest *)request [task start]; } -- (void)setContentHandler:(id)handler +#pragma mark - Public API + +- (void)addRequestHandler:(id)handler { - _contentHandler = handler; + if (!_requestHandlers) { + _requestHandlers = [NSMutableArray new]; + } + [_requestHandlers addObject:handler]; } -#pragma mark - Public API +- (void)addResponseHandler:(id)handler +{ + if (!_responseHandlers) { + _responseHandlers = [NSMutableArray new]; + } + [_responseHandlers addObject:handler]; +} + +- (void)removeRequestHandler:(id)handler +{ + [_requestHandlers removeObject:handler]; +} + +- (void)removeResponseHandler:(id)handler +{ + [_responseHandlers removeObject:handler]; +} - (RCTNetworkTask *)networkTaskWithRequest:(NSURLRequest *)request completionBlock:(RCTURLRequestCompletionBlock)completionBlock { diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index 76c90c393e2417..1b086fdf21894a 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -23,9 +23,7 @@ const invariant = require('fbjs/lib/invariant'); * found when Flow v0.54 was deployed. To see the error delete this comment and * run Flow. */ const warning = require('fbjs/lib/warning'); -const Blob = require('Blob'); const BlobManager = require('BlobManager'); -const NativeModules = require('NativeModules'); export type NativeResponseType = 'base64' | 'blob' | 'text'; export type ResponseType = '' | 'arraybuffer' | 'blob' | 'document' | 'json' | 'text'; @@ -58,6 +56,11 @@ type XHRInterceptor = { ): void, }; +// The native blob module is optional so inject it here if available. +if (BlobManager.isAvailable) { + BlobManager.addNetworkingHandler(); +} + const UNSENT = 0; const OPENED = 1; const HEADERS_RECEIVED = 2; @@ -205,16 +208,8 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { `The provided value '${responseType}' is unsupported in this environment.` ); - if (this._responseType === 'blob' || responseType === 'blob') { - const BlobModule = NativeModules.BlobModule; - invariant(BlobModule, 'Native module BlobModule is required for blob support'); - if (BlobModule) { - if (responseType === 'blob') { - BlobModule.addXMLHttpRequestHandler(); - } else { - BlobModule.removeXMLHttpRequestHandler(); - } - } + if (responseType === 'blob') { + invariant(BlobManager.isAvailable, 'Native module BlobModule is required for blob support'); } this._responseType = responseType; } diff --git a/Libraries/WebSocket/RCTWebSocketModule.h b/Libraries/WebSocket/RCTWebSocketModule.h index b2012bc4afbdde..2875d0eb3a9f3d 100644 --- a/Libraries/WebSocket/RCTWebSocketModule.h +++ b/Libraries/WebSocket/RCTWebSocketModule.h @@ -13,8 +13,9 @@ NS_ASSUME_NONNULL_BEGIN @protocol RCTWebSocketContentHandler -- (id)processMessage:(id __nullable)message forSocketID:(NSNumber *)socketID - withType:(NSString *__nonnull __autoreleasing *__nonnull)type; +- (id)processWebsocketMessage:(id __nullable)message + forSocketID:(NSNumber *)socketID + withType:(NSString *__nonnull __autoreleasing *__nonnull)type; @end diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m index c04a0adcb2d721..1af066b506eed3 100644 --- a/Libraries/WebSocket/RCTWebSocketModule.m +++ b/Libraries/WebSocket/RCTWebSocketModule.m @@ -37,7 +37,7 @@ @interface RCTWebSocketModule () @implementation RCTWebSocketModule { NSMutableDictionary *_sockets; - NSMutableDictionary *_contentHandlers; + NSMutableDictionary> *_contentHandlers; } RCT_EXPORT_MODULE() @@ -53,8 +53,9 @@ - (NSArray *)supportedEvents @"websocketClosed"]; } -- (void)dealloc +- (void)invalidate { + _contentHandlers = nil; for (RCTSRWebSocket *socket in _sockets.allValues) { socket.delegate = nil; [socket close]; @@ -135,7 +136,7 @@ - (void)webSocket:(RCTSRWebSocket *)webSocket didReceiveMessage:(id)message NSNumber *socketID = [webSocket reactTag]; id contentHandler = _contentHandlers[socketID]; if (contentHandler) { - message = [contentHandler processMessage:message forSocketID:socketID withType:&type]; + message = [contentHandler processWebsocketMessage:message forSocketID:socketID withType:&type]; } else { if ([message isKindOfClass:[NSData class]]) { type = @"binary"; diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 1095f115e77ad1..4c4dd8e0edcbd8 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -148,14 +148,11 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { throw new Error('binaryType must be either \'blob\' or \'arraybuffer\''); } if (this._binaryType === 'blob' || binaryType === 'blob') { - const BlobModule = NativeModules.BlobModule; - invariant(BlobModule, 'Native module BlobModule is required for blob support'); - if (BlobModule) { - if (binaryType === 'blob') { - BlobModule.addWebSocketHandler(this._socketId); - } else { - BlobModule.removeWebSocketHandler(this._socketId); - } + invariant(BlobManager.isAvailable, 'Native module BlobModule is required for blob support'); + if (binaryType === 'blob') { + BlobManager.addWebSocketHandler(this._socketId); + } else { + BlobManager.removeWebSocketHandler(this._socketId); } } this._binaryType = binaryType; @@ -181,9 +178,8 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { } if (data instanceof Blob) { - const BlobModule = NativeModules.BlobModule; - invariant(BlobModule, 'Native module BlobModule is required for blob support'); - BlobModule.sendOverSocket(data.data, this._socketId); + invariant(BlobManager.isAvailable, 'Native module BlobModule is required for blob support'); + BlobManager.sendOverSocket(data.data, this._socketId); return; } @@ -217,6 +213,10 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { } else { WebSocketModule.close(this._socketId); } + + if (BlobManager.isAvailable && this._binaryType === 'blob') { + BlobManager.removeWebSocketHandler(this._socketId); + } } _unregisterEvents(): void { diff --git a/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m b/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m index a85f36cd434062..0ee4a87e22dc0c 100644 --- a/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m +++ b/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m @@ -28,6 +28,7 @@ - (void)setUp [super setUp]; _module = [RCTBlobManager new]; + [_module setValue:nil forKey:@"bridge"]; NSInteger size = 120; _data = [NSMutableData dataWithCapacity:size]; for (NSInteger i = 0; i < size / 4; i++) { @@ -55,6 +56,14 @@ - (void)testResolveMap XCTAssertTrue([_data isEqualToData:[_module resolve:map]]); } +- (void)testResolveURL +{ + NSURLComponents *components = [NSURLComponents new]; + [components setPath:_blobId]; + [components setQuery:[NSString stringWithFormat:@"offset=0&size=%lu", (unsigned long)_data.length]]; + XCTAssertTrue([_data isEqualToData:[_module resolveURL:[components URL]]]); +} + - (void)testRemove { XCTAssertNotNil([_module resolve:_blobId offset:0 size:_data.length]); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index f55adf2c2b2f40..a930318d5d31fe 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -285,19 +285,12 @@ private static String getMimeTypeFromUri(Uri contentUri, ContentResolver resolve } @ReactMethod - public void addXMLHttpRequestHandler() { + public void addNetworkingHandler() { NetworkingModule.addUriHandler(NetworkingUriHandler); NetworkingModule.addRequestBodyHandler(NetworkingRequestBodyHandler); NetworkingModule.addResponseHandler(NetworkingResponseHandler); } - @ReactMethod - public void removeXMLHttpRequestHandler() { - NetworkingModule.removeUriHandler(NetworkingUriHandler); - NetworkingModule.removeRequestBodyHandler(NetworkingRequestBodyHandler); - NetworkingModule.removeResponseHandler(NetworkingResponseHandler); - } - private WebSocketModule getWebSocketModule() { return getReactApplicationContext().getNativeModule(WebSocketModule.class); } From ed2b25017d4d06cc709eb64f20439ed0c18f41ca Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Wed, 4 Oct 2017 18:57:06 -0400 Subject: [PATCH 36/66] Remove blob include --- Libraries/WebSocket/RCTWebSocketModule.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Libraries/WebSocket/RCTWebSocketModule.m b/Libraries/WebSocket/RCTWebSocketModule.m index 1af066b506eed3..9608c0edb9e807 100644 --- a/Libraries/WebSocket/RCTWebSocketModule.m +++ b/Libraries/WebSocket/RCTWebSocketModule.m @@ -9,7 +9,6 @@ #import "RCTWebSocketModule.h" #import "RCTSRWebSocket.h" -#import "RCTBlobManager.h" #import From f928990e6e116629a9a1a459b528afb4d08e3872 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Wed, 4 Oct 2017 19:00:12 -0400 Subject: [PATCH 37/66] Revert websocket xcodeproj changes --- .../RCTWebSocket.xcodeproj/project.pbxproj | 25 +++---------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj index f46837f108a067..77b584c76c4565 100644 --- a/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj +++ b/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj @@ -131,7 +131,7 @@ 3C86DF7A1ADF695F0047B81A /* RCTWebSocketModule.h */, 3C86DF7B1ADF695F0047B81A /* RCTWebSocketModule.m */, 3C86DF471ADF2C930047B81A /* Products */, - AD0871001E2158CB007D136D /* Frameworks */, + 13526A501F362F7F0008EF00 /* Frameworks */, ); indentWidth = 2; sourceTree = ""; @@ -149,13 +149,6 @@ name = Products; sourceTree = ""; }; - AD0871001E2158CB007D136D /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -332,7 +325,6 @@ OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SKIP_INSTALL = YES; TVOS_DEPLOYMENT_TARGET = 9.2; }; name = Debug; @@ -347,7 +339,6 @@ OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SKIP_INSTALL = YES; TVOS_DEPLOYMENT_TARGET = 9.2; }; name = Release; @@ -394,7 +385,7 @@ MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; - USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../Blob"; + SKIP_INSTALL = YES; WARNING_CFLAGS = ( "-Werror", "-Wall", @@ -437,7 +428,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; - USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/../Blob"; + SKIP_INSTALL = YES; VALIDATE_PRODUCT = YES; WARNING_CFLAGS = ( "-Werror", @@ -451,13 +442,8 @@ buildSettings = { EXECUTABLE_PREFIX = lib; GCC_TREAT_WARNINGS_AS_ERRORS = NO; - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../React/**", - "$(SRCROOT)/../../ReactCommon/**", - ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; }; name = Debug; }; @@ -466,13 +452,8 @@ buildSettings = { EXECUTABLE_PREFIX = lib; GCC_TREAT_WARNINGS_AS_ERRORS = NO; - HEADER_SEARCH_PATHS = ( - "$(SRCROOT)/../../React/**", - "$(SRCROOT)/../../ReactCommon/**", - ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; }; name = Release; }; From 35a37b6c2414fd362c7179526204dafdc4bb2efa Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 5 Oct 2017 16:51:08 -0400 Subject: [PATCH 38/66] Avoid statics for module data to make multiple instances play nicely, cleanup whitespace changes --- .../react/modules/blob/BlobModule.java | 189 ++++++++--------- .../modules/network/NetworkingModule.java | 199 +++++++++--------- 2 files changed, 192 insertions(+), 196 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index a930318d5d31fe..755a6e4212687f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -51,9 +51,9 @@ public class BlobModule extends ReactContextBaseJavaModule { protected static final String NAME = "BlobModule"; - private static final Map mBlobs = new HashMap<>(); + private final Map mBlobs = new HashMap<>(); - protected static final WebSocketModule.ContentHandler BlobHandler = + private final WebSocketModule.ContentHandler mWebSocketContentHandler = new WebSocketModule.ContentHandler() { @Override public void onMessage(String text, WritableMap params) { @@ -75,80 +75,80 @@ public void onMessage(ByteString bytes, WritableMap params) { } }; - private static final NetworkingModule.UriHandler NetworkingUriHandler = - new NetworkingModule.UriHandler() { - @Override - public boolean supports(Uri uri, String responseType) { - String scheme = uri.getScheme(); - boolean isRemote = scheme.equals("http") || scheme.equals("https"); - - return (!isRemote && responseType.equals("blob")); - } - - @Override - public WritableMap fetch(Uri uri, Context context) throws IOException { - ContentResolver resolver = context.getContentResolver(); - - byte[] data = getBytesFromUri(uri, resolver); - - WritableMap blob = Arguments.createMap(); - blob.putString("blobId", store(data)); - blob.putInt("offset", 0); - blob.putInt("size", data.length); - blob.putString("type", getMimeTypeFromUri(uri, resolver)); - - // Needed for files - blob.putString("name", getNameFromUri(uri, resolver)); - blob.putDouble("lastModified", getLastModifiedFromUri(uri)); - - return blob; - } - }; - - private static final NetworkingModule.RequestBodyHandler NetworkingRequestBodyHandler = - new NetworkingModule.RequestBodyHandler() { - @Override - public boolean supports(ReadableMap data) { - return data.hasKey("blob"); - } - - @Override - public RequestBody toRequestBody(ReadableMap data, String contentType) { - String type = contentType; - if (data.hasKey("type") && !data.getString("type").isEmpty()) { - type = data.getString("type"); - } - if (type == null) { - type = "application/octet-stream"; - } - ReadableMap blob = data.getMap("blob"); - String blobId = blob.getString("blobId"); - byte[] bytes = resolve( - blobId, - blob.getInt("offset"), - blob.getInt("size"));; - - return RequestBody.create(MediaType.parse(type), bytes); - } - }; - - private static final NetworkingModule.ResponseHandler NetworkingResponseHandler = - new NetworkingModule.ResponseHandler() { - @Override - public boolean supports(String responseType) { - return responseType.equals("blob"); - } - - @Override - public WritableMap toResponseData(ResponseBody body) throws IOException { - byte[] data = body.bytes(); - WritableMap blob = Arguments.createMap(); - blob.putString("blobId", store(data)); - blob.putInt("offset", 0); - blob.putInt("size", data.length); - return blob; - } - }; + private final NetworkingModule.UriHandler mNetworkingUriHandler = + new NetworkingModule.UriHandler() { + @Override + public boolean supports(Uri uri, String responseType) { + String scheme = uri.getScheme(); + boolean isRemote = scheme.equals("http") || scheme.equals("https"); + + return (!isRemote && responseType.equals("blob")); + } + + @Override + public WritableMap fetch(Uri uri, Context context) throws IOException { + ContentResolver resolver = context.getContentResolver(); + + byte[] data = getBytesFromUri(uri, resolver); + + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + blob.putString("type", getMimeTypeFromUri(uri, resolver)); + + // Needed for files + blob.putString("name", getNameFromUri(uri, resolver)); + blob.putDouble("lastModified", getLastModifiedFromUri(uri)); + + return blob; + } + }; + + private final NetworkingModule.RequestBodyHandler mNetworkingRequestBodyHandler = + new NetworkingModule.RequestBodyHandler() { + @Override + public boolean supports(ReadableMap data) { + return data.hasKey("blob"); + } + + @Override + public RequestBody toRequestBody(ReadableMap data, String contentType) { + String type = contentType; + if (data.hasKey("type") && !data.getString("type").isEmpty()) { + type = data.getString("type"); + } + if (type == null) { + type = "application/octet-stream"; + } + ReadableMap blob = data.getMap("blob"); + String blobId = blob.getString("blobId"); + byte[] bytes = resolve( + blobId, + blob.getInt("offset"), + blob.getInt("size")); + + return RequestBody.create(MediaType.parse(type), bytes); + } + }; + + private final NetworkingModule.ResponseHandler mNetworkingResponseHandler = + new NetworkingModule.ResponseHandler() { + @Override + public boolean supports(String responseType) { + return responseType.equals("blob"); + } + + @Override + public WritableMap toResponseData(ResponseBody body) throws IOException { + byte[] data = body.bytes(); + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + return blob; + } + }; public BlobModule(ReactApplicationContext reactContext) { super(reactContext); @@ -160,8 +160,7 @@ public String getName() { } @Override - @Nullable - public Map getConstants() { + public @Nullable Map getConstants() { // The application can register BlobProvider as a ContentProvider so that blobs are resolvable. // If it does, it needs to tell us what authority was used via this string resource. Resources resources = getReactApplicationContext().getResources(); @@ -171,26 +170,25 @@ public Map getConstants() { return null; } - return MapBuilder.of( + return MapBuilder.of( "BLOB_URI_SCHEME", "content", "BLOB_URI_HOST", resources.getString(resourceId)); } - public static String store(byte[] data) { + public String store(byte[] data) { String blobId = UUID.randomUUID().toString(); store(data, blobId); return blobId; } - public static void store(byte[] data, String blobId) { + public void store(byte[] data, String blobId) { mBlobs.put(blobId, data); } - public static void remove(String blobId) { + public void remove(String blobId) { mBlobs.remove(blobId); } - @Nullable - public static byte[] resolve(Uri uri) { + public @Nullable byte[] resolve(Uri uri) { String blobId = uri.getLastPathSegment(); int offset = 0; int size = -1; @@ -205,8 +203,7 @@ public static byte[] resolve(Uri uri) { return resolve(blobId, offset, size); } - @Nullable - public static byte[] resolve(String blobId, int offset, int size) { + public @Nullable byte[] resolve(String blobId, int offset, int size) { byte[] data = mBlobs.get(blobId); if (data == null) { return null; @@ -220,8 +217,7 @@ public static byte[] resolve(String blobId, int offset, int size) { return data; } - @Nullable - public static byte[] resolve(ReadableMap blob) { + public @Nullable byte[] resolve(ReadableMap blob) { return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); } @@ -284,20 +280,21 @@ private static String getMimeTypeFromUri(Uri contentUri, ContentResolver resolve return type; } - @ReactMethod - public void addNetworkingHandler() { - NetworkingModule.addUriHandler(NetworkingUriHandler); - NetworkingModule.addRequestBodyHandler(NetworkingRequestBodyHandler); - NetworkingModule.addResponseHandler(NetworkingResponseHandler); - } - private WebSocketModule getWebSocketModule() { return getReactApplicationContext().getNativeModule(WebSocketModule.class); } + @ReactMethod + public void addNetworkingHandler() { + NetworkingModule networkingModule = getReactApplicationContext().getNativeModule(NetworkingModule.class); + networkingModule.addUriHandler(mNetworkingUriHandler); + networkingModule.addRequestBodyHandler(mNetworkingRequestBodyHandler); + networkingModule.addResponseHandler(mNetworkingResponseHandler); + } + @ReactMethod public void addWebSocketHandler(final int id) { - getWebSocketModule().setContentHandler(id, BlobHandler); + getWebSocketModule().setContentHandler(id, mWebSocketContentHandler); } @ReactMethod diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 889399db8a45ec..e8cd74c39a6d71 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -87,22 +87,21 @@ public interface ResponseHandler { private static final int CHUNK_TIMEOUT_NS = 100 * 1000000; // 100ms private static final int MAX_CHUNK_SIZE_BETWEEN_FLUSHES = 8 * 1024; // 8K - private static final List mRequestBodyHandlers = new ArrayList<>(); - private static final List mUriHandlers = new ArrayList<>(); - private static final List mResponseHandlers = new ArrayList<>(); - private final OkHttpClient mClient; private final ForwardingCookieHandler mCookieHandler; private final @Nullable String mDefaultUserAgent; private final CookieJarContainer mCookieJarContainer; private final Set mRequestIds; + private final List mRequestBodyHandlers = new ArrayList<>(); + private final List mUriHandlers = new ArrayList<>(); + private final List mResponseHandlers = new ArrayList<>(); private boolean mShuttingDown; /* package */ NetworkingModule( - ReactApplicationContext reactContext, - @Nullable String defaultUserAgent, - OkHttpClient client, - @Nullable List networkInterceptorCreators) { + ReactApplicationContext reactContext, + @Nullable String defaultUserAgent, + OkHttpClient client, + @Nullable List networkInterceptorCreators) { super(reactContext); if (networkInterceptorCreators != null) { @@ -127,9 +126,9 @@ public interface ResponseHandler { * @param client the {@link OkHttpClient} to be used for networking */ /* package */ NetworkingModule( - ReactApplicationContext context, - @Nullable String defaultUserAgent, - OkHttpClient client) { + ReactApplicationContext context, + @Nullable String defaultUserAgent, + OkHttpClient client) { this(context, defaultUserAgent, client, null); } @@ -146,8 +145,8 @@ public NetworkingModule(final ReactApplicationContext context) { * methods would be called to attach the interceptors to the client. */ public NetworkingModule( - ReactApplicationContext context, - List networkInterceptorCreators) { + ReactApplicationContext context, + List networkInterceptorCreators) { this(context, null, OkHttpClientProvider.createClient(), networkInterceptorCreators); } @@ -177,29 +176,33 @@ public void onCatalystInstanceDestroy() { mCookieHandler.destroy(); mCookieJarContainer.removeCookieJar(); + + mRequestBodyHandlers.clear(); + mResponseHandlers.clear(); + mUriHandlers.clear(); } - public static void addUriHandler(UriHandler handler) { + public void addUriHandler(UriHandler handler) { mUriHandlers.add(handler); } - public static void addRequestBodyHandler(RequestBodyHandler handler) { + public void addRequestBodyHandler(RequestBodyHandler handler) { mRequestBodyHandlers.add(handler); } - public static void addResponseHandler(ResponseHandler handler) { + public void addResponseHandler(ResponseHandler handler) { mResponseHandlers.add(handler); } - public static void removeUriHandler(UriHandler handler) { + public void removeUriHandler(UriHandler handler) { mUriHandlers.remove(handler); } - public static void removeRequestBodyHandler(RequestBodyHandler handler) { + public void removeRequestBodyHandler(RequestBodyHandler handler) { mRequestBodyHandlers.remove(handler); } - public static void removeResponseHandler(ResponseHandler handler) { + public void removeResponseHandler(ResponseHandler handler) { mResponseHandlers.remove(handler); } @@ -208,25 +211,23 @@ public static void removeResponseHandler(ResponseHandler handler) { * @param timeout value of 0 results in no timeout */ public void sendRequest( - String method, - String url, - final int requestId, - ReadableArray headers, - ReadableMap data, - final String responseType, - final boolean useIncrementalUpdates, - int timeout, - boolean withCredentials) { - + String method, + String url, + final int requestId, + ReadableArray headers, + ReadableMap data, + final String responseType, + final boolean useIncrementalUpdates, + int timeout, + boolean withCredentials) { final RCTDeviceEventEmitter eventEmitter = getEventEmitter(); try { Uri uri = Uri.parse(url); // Check if a handler is registered - for (int i = 0; i < mUriHandlers.size(); i++) { - if (mUriHandlers.get(i).supports(uri, responseType)) { - UriHandler handler = mUriHandlers.get(i); + for (UriHandler handler : mUriHandlers) { + if (handler.supports(uri, responseType)) { WritableMap res = handler.fetch(uri, getReactApplicationContext()); ResponseUtil.onDataReceived(eventEmitter, requestId, res); ResponseUtil.onRequestSuccess(eventEmitter, requestId); @@ -258,29 +259,29 @@ public void sendRequest( public Response intercept(Interceptor.Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); ProgressResponseBody responseBody = new ProgressResponseBody( - originalResponse.body(), - new ProgressListener() { - long last = System.nanoTime(); - - @Override - public void onProgress(long bytesWritten, long contentLength, boolean done) { - long now = System.nanoTime(); - if (!done && !shouldDispatch(now, last)) { - return; - } - if (responseType.equals("text")) { - // For 'text' responses we continuously send response data with progress info to - // JS below, so no need to do anything here. - return; - } - ResponseUtil.onDataReceivedProgress( - eventEmitter, - requestId, - bytesWritten, - contentLength); - last = now; - } - }); + originalResponse.body(), + new ProgressListener() { + long last = System.nanoTime(); + + @Override + public void onProgress(long bytesWritten, long contentLength, boolean done) { + long now = System.nanoTime(); + if (!done && !shouldDispatch(now, last)) { + return; + } + if (responseType.equals("text")) { + // For 'text' responses we continuously send response data with progress info to + // JS below, so no need to do anything here. + return; + } + ResponseUtil.onDataReceivedProgress( + eventEmitter, + requestId, + bytesWritten, + contentLength); + last = now; + } + }); return originalResponse.newBuilder().body(responseBody).build(); } }); @@ -306,11 +307,10 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { // Check if a handler is registered RequestBodyHandler handler = null; - if (data != null) { - for (int i = 0; i < mRequestBodyHandlers.size(); i++) { - if (mRequestBodyHandlers.get(i).supports(data)) { - handler = mRequestBodyHandlers.get(i); + for (RequestBodyHandler curHandler : mRequestBodyHandlers) { + if (curHandler.supports(data)) { + handler = curHandler; break; } } @@ -324,10 +324,10 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String body = data.getString(REQUEST_BODY_KEY_STRING); @@ -345,24 +345,24 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } else if (data.hasKey(REQUEST_BODY_KEY_BASE64)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String base64String = data.getString(REQUEST_BODY_KEY_BASE64); MediaType contentMediaType = MediaType.parse(contentType); requestBuilder.method( - method, - RequestBody.create(contentMediaType, ByteString.decodeBase64(base64String))); + method, + RequestBody.create(contentMediaType, ByteString.decodeBase64(base64String))); } else if (data.hasKey(REQUEST_BODY_KEY_URI)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String uri = data.getString(REQUEST_BODY_KEY_URI); @@ -370,42 +370,42 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri); if (fileInputStream == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Could not retrieve file for uri " + uri, - null); + eventEmitter, + requestId, + "Could not retrieve file for uri " + uri, + null); return; } requestBuilder.method( - method, - RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); + method, + RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); } else if (data.hasKey(REQUEST_BODY_KEY_FORMDATA)) { if (contentType == null) { contentType = "multipart/form-data"; } ReadableArray parts = data.getArray(REQUEST_BODY_KEY_FORMDATA); MultipartBody.Builder multipartBuilder = - constructMultipartBody(parts, contentType, requestId); + constructMultipartBody(parts, contentType, requestId); if (multipartBuilder == null) { return; } requestBuilder.method( - method, - RequestBodyUtil.createProgressRequest( - multipartBuilder.build(), - new ProgressListener() { - long last = System.nanoTime(); - - @Override - public void onProgress(long bytesWritten, long contentLength, boolean done) { - long now = System.nanoTime(); - if (done || shouldDispatch(now, last)) { - ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); - last = now; - } - } - })); + method, + RequestBodyUtil.createProgressRequest( + multipartBuilder.build(), + new ProgressListener() { + long last = System.nanoTime(); + + @Override + public void onProgress(long bytesWritten, long contentLength, boolean done) { + long now = System.nanoTime(); + if (done || shouldDispatch(now, last)) { + ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); + last = now; + } + } + })); } else { // Nothing in data payload, at least nothing we could understand anyway. requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); @@ -421,8 +421,8 @@ public void onFailure(Call call, IOException e) { } removeRequest(requestId); String errorMessage = e.getMessage() != null - ? e.getMessage() - : "Error while executing request: " + e.getClass().getSimpleName(); + ? e.getMessage() + : "Error while executing request: " + e.getClass().getSimpleName(); ResponseUtil.onRequestError(eventEmitter, requestId, errorMessage, e); } @@ -443,9 +443,8 @@ public void onResponse(Call call, Response response) throws IOException { ResponseBody responseBody = response.body(); try { // Check if a handler is registered - for (int i = 0; i < mResponseHandlers.size(); i++) { - if (mResponseHandlers.get(i).supports(responseType)) { - ResponseHandler handler = mResponseHandlers.get(i); + for (ResponseHandler handler : mResponseHandlers) { + if (handler.supports(responseType)) { WritableMap res = handler.toResponseData(responseBody); ResponseUtil.onDataReceived(eventEmitter, requestId, res); ResponseUtil.onRequestSuccess(eventEmitter, requestId); From adc531895312749f718e8c558bceec56ac87d466 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 5 Oct 2017 16:57:36 -0400 Subject: [PATCH 39/66] Fix whitespace p2 --- .../react/modules/blob/BlobModule.java | 156 ++++----- .../modules/network/NetworkingModule.java | 319 +++++++++--------- 2 files changed, 241 insertions(+), 234 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 755a6e4212687f..ab0f53861d079f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -1,6 +1,6 @@ /** * 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. @@ -54,101 +54,101 @@ public class BlobModule extends ReactContextBaseJavaModule { private final Map mBlobs = new HashMap<>(); private final WebSocketModule.ContentHandler mWebSocketContentHandler = - new WebSocketModule.ContentHandler() { - @Override - public void onMessage(String text, WritableMap params) { - params.putString("data", text); - } + new WebSocketModule.ContentHandler() { + @Override + public void onMessage(String text, WritableMap params) { + params.putString("data", text); + } - @Override - public void onMessage(ByteString bytes, WritableMap params) { - byte[] data = bytes.toByteArray(); + @Override + public void onMessage(ByteString bytes, WritableMap params) { + byte[] data = bytes.toByteArray(); - WritableMap blob = Arguments.createMap(); + WritableMap blob = Arguments.createMap(); - blob.putString("blobId", store(data)); - blob.putInt("offset", 0); - blob.putInt("size", data.length); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); - params.putMap("data", blob); - params.putString("type", "blob"); - } - }; + params.putMap("data", blob); + params.putString("type", "blob"); + } + }; private final NetworkingModule.UriHandler mNetworkingUriHandler = - new NetworkingModule.UriHandler() { - @Override - public boolean supports(Uri uri, String responseType) { - String scheme = uri.getScheme(); - boolean isRemote = scheme.equals("http") || scheme.equals("https"); + new NetworkingModule.UriHandler() { + @Override + public boolean supports(Uri uri, String responseType) { + String scheme = uri.getScheme(); + boolean isRemote = scheme.equals("http") || scheme.equals("https"); - return (!isRemote && responseType.equals("blob")); - } + return (!isRemote && responseType.equals("blob")); + } - @Override - public WritableMap fetch(Uri uri, Context context) throws IOException { - ContentResolver resolver = context.getContentResolver(); + @Override + public WritableMap fetch(Uri uri, Context context) throws IOException { + ContentResolver resolver = context.getContentResolver(); - byte[] data = getBytesFromUri(uri, resolver); + byte[] data = getBytesFromUri(uri, resolver); - WritableMap blob = Arguments.createMap(); - blob.putString("blobId", store(data)); - blob.putInt("offset", 0); - blob.putInt("size", data.length); - blob.putString("type", getMimeTypeFromUri(uri, resolver)); + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + blob.putString("type", getMimeTypeFromUri(uri, resolver)); - // Needed for files - blob.putString("name", getNameFromUri(uri, resolver)); - blob.putDouble("lastModified", getLastModifiedFromUri(uri)); + // Needed for files + blob.putString("name", getNameFromUri(uri, resolver)); + blob.putDouble("lastModified", getLastModifiedFromUri(uri)); - return blob; - } - }; + return blob; + } + }; private final NetworkingModule.RequestBodyHandler mNetworkingRequestBodyHandler = - new NetworkingModule.RequestBodyHandler() { - @Override - public boolean supports(ReadableMap data) { - return data.hasKey("blob"); - } + new NetworkingModule.RequestBodyHandler() { + @Override + public boolean supports(ReadableMap data) { + return data.hasKey("blob"); + } - @Override - public RequestBody toRequestBody(ReadableMap data, String contentType) { - String type = contentType; - if (data.hasKey("type") && !data.getString("type").isEmpty()) { - type = data.getString("type"); - } - if (type == null) { - type = "application/octet-stream"; - } - ReadableMap blob = data.getMap("blob"); - String blobId = blob.getString("blobId"); - byte[] bytes = resolve( - blobId, - blob.getInt("offset"), - blob.getInt("size")); - - return RequestBody.create(MediaType.parse(type), bytes); + @Override + public RequestBody toRequestBody(ReadableMap data, String contentType) { + String type = contentType; + if (data.hasKey("type") && !data.getString("type").isEmpty()) { + type = data.getString("type"); } - }; + if (type == null) { + type = "application/octet-stream"; + } + ReadableMap blob = data.getMap("blob"); + String blobId = blob.getString("blobId"); + byte[] bytes = resolve( + blobId, + blob.getInt("offset"), + blob.getInt("size")); + + return RequestBody.create(MediaType.parse(type), bytes); + } + }; private final NetworkingModule.ResponseHandler mNetworkingResponseHandler = - new NetworkingModule.ResponseHandler() { - @Override - public boolean supports(String responseType) { - return responseType.equals("blob"); - } + new NetworkingModule.ResponseHandler() { + @Override + public boolean supports(String responseType) { + return responseType.equals("blob"); + } - @Override - public WritableMap toResponseData(ResponseBody body) throws IOException { - byte[] data = body.bytes(); - WritableMap blob = Arguments.createMap(); - blob.putString("blobId", store(data)); - blob.putInt("offset", 0); - blob.putInt("size", data.length); - return blob; - } - }; + @Override + public WritableMap toResponseData(ResponseBody body) throws IOException { + byte[] data = body.bytes(); + WritableMap blob = Arguments.createMap(); + blob.putString("blobId", store(data)); + blob.putInt("offset", 0); + blob.putInt("size", data.length); + return blob; + } + }; public BlobModule(ReactApplicationContext reactContext) { super(reactContext); @@ -171,7 +171,7 @@ public String getName() { } return MapBuilder.of( - "BLOB_URI_SCHEME", "content", "BLOB_URI_HOST", resources.getString(resourceId)); + "BLOB_URI_SCHEME", "content", "BLOB_URI_HOST", resources.getString(resourceId)); } public String store(byte[] data) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index e8cd74c39a6d71..888a4172e4390a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -1,11 +1,12 @@ /** * 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. - */package com.facebook.react.modules.network; + */ +package com.facebook.react.modules.network; import android.content.Context; import android.net.Uri; @@ -89,7 +90,9 @@ public interface ResponseHandler { private final OkHttpClient mClient; private final ForwardingCookieHandler mCookieHandler; - private final @Nullable String mDefaultUserAgent; + private final + @Nullable + String mDefaultUserAgent; private final CookieJarContainer mCookieJarContainer; private final Set mRequestIds; private final List mRequestBodyHandlers = new ArrayList<>(); @@ -98,10 +101,10 @@ public interface ResponseHandler { private boolean mShuttingDown; /* package */ NetworkingModule( - ReactApplicationContext reactContext, - @Nullable String defaultUserAgent, - OkHttpClient client, - @Nullable List networkInterceptorCreators) { + ReactApplicationContext reactContext, + @Nullable String defaultUserAgent, + OkHttpClient client, + @Nullable List networkInterceptorCreators) { super(reactContext); if (networkInterceptorCreators != null) { @@ -126,9 +129,9 @@ public interface ResponseHandler { * @param client the {@link OkHttpClient} to be used for networking */ /* package */ NetworkingModule( - ReactApplicationContext context, - @Nullable String defaultUserAgent, - OkHttpClient client) { + ReactApplicationContext context, + @Nullable String defaultUserAgent, + OkHttpClient client) { this(context, defaultUserAgent, client, null); } @@ -145,8 +148,8 @@ public NetworkingModule(final ReactApplicationContext context) { * methods would be called to attach the interceptors to the client. */ public NetworkingModule( - ReactApplicationContext context, - List networkInterceptorCreators) { + ReactApplicationContext context, + List networkInterceptorCreators) { this(context, null, OkHttpClientProvider.createClient(), networkInterceptorCreators); } @@ -211,15 +214,15 @@ public void removeResponseHandler(ResponseHandler handler) { * @param timeout value of 0 results in no timeout */ public void sendRequest( - String method, - String url, - final int requestId, - ReadableArray headers, - ReadableMap data, - final String responseType, - final boolean useIncrementalUpdates, - int timeout, - boolean withCredentials) { + String method, + String url, + final int requestId, + ReadableArray headers, + ReadableMap data, + final String responseType, + final boolean useIncrementalUpdates, + int timeout, + boolean withCredentials) { final RCTDeviceEventEmitter eventEmitter = getEventEmitter(); try { @@ -259,29 +262,29 @@ public void sendRequest( public Response intercept(Interceptor.Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); ProgressResponseBody responseBody = new ProgressResponseBody( - originalResponse.body(), - new ProgressListener() { - long last = System.nanoTime(); - - @Override - public void onProgress(long bytesWritten, long contentLength, boolean done) { - long now = System.nanoTime(); - if (!done && !shouldDispatch(now, last)) { - return; - } - if (responseType.equals("text")) { - // For 'text' responses we continuously send response data with progress info to - // JS below, so no need to do anything here. - return; - } - ResponseUtil.onDataReceivedProgress( - eventEmitter, - requestId, - bytesWritten, - contentLength); - last = now; + originalResponse.body(), + new ProgressListener() { + long last = System.nanoTime(); + + @Override + public void onProgress(long bytesWritten, long contentLength, boolean done) { + long now = System.nanoTime(); + if (!done && !shouldDispatch(now, last)) { + return; + } + if (responseType.equals("text")) { + // For 'text' responses we continuously send response data with progress info to + // JS below, so no need to do anything here. + return; } - }); + ResponseUtil.onDataReceivedProgress( + eventEmitter, + requestId, + bytesWritten, + contentLength); + last = now; + } + }); return originalResponse.newBuilder().body(responseBody).build(); } }); @@ -324,10 +327,10 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String body = data.getString(REQUEST_BODY_KEY_STRING); @@ -345,67 +348,67 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } else if (data.hasKey(REQUEST_BODY_KEY_BASE64)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String base64String = data.getString(REQUEST_BODY_KEY_BASE64); MediaType contentMediaType = MediaType.parse(contentType); requestBuilder.method( - method, - RequestBody.create(contentMediaType, ByteString.decodeBase64(base64String))); + method, + RequestBody.create(contentMediaType, ByteString.decodeBase64(base64String))); } else if (data.hasKey(REQUEST_BODY_KEY_URI)) { if (contentType == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Payload is set but no content-type header specified", - null); + eventEmitter, + requestId, + "Payload is set but no content-type header specified", + null); return; } String uri = data.getString(REQUEST_BODY_KEY_URI); InputStream fileInputStream = - RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri); + RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri); if (fileInputStream == null) { ResponseUtil.onRequestError( - eventEmitter, - requestId, - "Could not retrieve file for uri " + uri, - null); + eventEmitter, + requestId, + "Could not retrieve file for uri " + uri, + null); return; } requestBuilder.method( - method, - RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); + method, + RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); } else if (data.hasKey(REQUEST_BODY_KEY_FORMDATA)) { if (contentType == null) { contentType = "multipart/form-data"; } ReadableArray parts = data.getArray(REQUEST_BODY_KEY_FORMDATA); MultipartBody.Builder multipartBuilder = - constructMultipartBody(parts, contentType, requestId); + constructMultipartBody(parts, contentType, requestId); if (multipartBuilder == null) { return; } requestBuilder.method( - method, - RequestBodyUtil.createProgressRequest( - multipartBuilder.build(), - new ProgressListener() { - long last = System.nanoTime(); - - @Override - public void onProgress(long bytesWritten, long contentLength, boolean done) { - long now = System.nanoTime(); - if (done || shouldDispatch(now, last)) { - ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); - last = now; - } - } - })); + method, + RequestBodyUtil.createProgressRequest( + multipartBuilder.build(), + new ProgressListener() { + long last = System.nanoTime(); + + @Override + public void onProgress(long bytesWritten, long contentLength, boolean done) { + long now = System.nanoTime(); + if (done || shouldDispatch(now, last)) { + ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); + last = now; + } + } + })); } else { // Nothing in data payload, at least nothing we could understand anyway. requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); @@ -413,85 +416,85 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { addRequest(requestId); client.newCall(requestBuilder.build()).enqueue( - new Callback() { - @Override - public void onFailure(Call call, IOException e) { - if (mShuttingDown) { - return; - } - removeRequest(requestId); - String errorMessage = e.getMessage() != null - ? e.getMessage() - : "Error while executing request: " + e.getClass().getSimpleName(); - ResponseUtil.onRequestError(eventEmitter, requestId, errorMessage, e); + new Callback() { + @Override + public void onFailure(Call call, IOException e) { + if (mShuttingDown) { + return; } + removeRequest(requestId); + String errorMessage = e.getMessage() != null + ? e.getMessage() + : "Error while executing request: " + e.getClass().getSimpleName(); + ResponseUtil.onRequestError(eventEmitter, requestId, errorMessage, e); + } - @Override - public void onResponse(Call call, Response response) throws IOException { - if (mShuttingDown) { - return; - } - removeRequest(requestId); - // Before we touch the body send headers to JS - ResponseUtil.onResponseReceived( - eventEmitter, - requestId, - response.code(), - translateHeaders(response.headers()), - response.request().url().toString()); - - ResponseBody responseBody = response.body(); - try { - // Check if a handler is registered - for (ResponseHandler handler : mResponseHandlers) { - if (handler.supports(responseType)) { - WritableMap res = handler.toResponseData(responseBody); - ResponseUtil.onDataReceived(eventEmitter, requestId, res); - ResponseUtil.onRequestSuccess(eventEmitter, requestId); - return; - } - } - - // If JS wants progress updates during the download, and it requested a text response, - // periodically send response data updates to JS. - if (useIncrementalUpdates && responseType.equals("text")) { - readWithProgress(eventEmitter, requestId, responseBody); + @Override + public void onResponse(Call call, Response response) throws IOException { + if (mShuttingDown) { + return; + } + removeRequest(requestId); + // Before we touch the body send headers to JS + ResponseUtil.onResponseReceived( + eventEmitter, + requestId, + response.code(), + translateHeaders(response.headers()), + response.request().url().toString()); + + ResponseBody responseBody = response.body(); + try { + // Check if a handler is registered + for (ResponseHandler handler : mResponseHandlers) { + if (handler.supports(responseType)) { + WritableMap res = handler.toResponseData(responseBody); + ResponseUtil.onDataReceived(eventEmitter, requestId, res); ResponseUtil.onRequestSuccess(eventEmitter, requestId); return; } + } - // Otherwise send the data in one big chunk, in the format that JS requested. - String responseString = ""; - if (responseType.equals("text")) { - try { - responseString = responseBody.string(); - } catch (IOException e) { - if (response.request().method().equalsIgnoreCase("HEAD")) { - // The request is an `HEAD` and the body is empty, - // the OkHttp will produce an exception. - // Ignore the exception to not invalidate the request in the - // Javascript layer. - // Introduced to fix issue #7463. - } else { - ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); - } + // If JS wants progress updates during the download, and it requested a text response, + // periodically send response data updates to JS. + if (useIncrementalUpdates && responseType.equals("text")) { + readWithProgress(eventEmitter, requestId, responseBody); + ResponseUtil.onRequestSuccess(eventEmitter, requestId); + return; + } + + // Otherwise send the data in one big chunk, in the format that JS requested. + String responseString = ""; + if (responseType.equals("text")) { + try { + responseString = responseBody.string(); + } catch (IOException e) { + if (response.request().method().equalsIgnoreCase("HEAD")) { + // The request is an `HEAD` and the body is empty, + // the OkHttp will produce an exception. + // Ignore the exception to not invalidate the request in the + // Javascript layer. + // Introduced to fix issue #7463. + } else { + ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); } - } else if (responseType.equals("base64")) { - responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); } - ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); - ResponseUtil.onRequestSuccess(eventEmitter, requestId); - } catch (IOException e) { - ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); + } else if (responseType.equals("base64")) { + responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); } + ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); + ResponseUtil.onRequestSuccess(eventEmitter, requestId); + } catch (IOException e) { + ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); } - }); + } + }); } private void readWithProgress( - RCTDeviceEventEmitter eventEmitter, - int requestId, - ResponseBody responseBody) throws IOException { + RCTDeviceEventEmitter eventEmitter, + int requestId, + ResponseBody responseBody) throws IOException { long totalBytesRead = -1; long contentLength = -1; try { @@ -545,8 +548,8 @@ private static WritableMap translateHeaders(Headers headers) { // multiple values for the same header if (responseHeaders.hasKey(headerName)) { responseHeaders.putString( - headerName, - responseHeaders.getString(headerName) + ", " + headers.value(i)); + headerName, + responseHeaders.getString(headerName) + ", " + headers.value(i)); } else { responseHeaders.putString(headerName, headers.value(i)); } @@ -576,10 +579,12 @@ public void clearCookies(com.facebook.react.bridge.Callback callback) { mCookieHandler.clearCookies(callback); } - private @Nullable MultipartBody.Builder constructMultipartBody( - ReadableArray body, - String contentType, - int requestId) { + private + @Nullable + MultipartBody.Builder constructMultipartBody( + ReadableArray body, + String contentType, + int requestId) { RCTDeviceEventEmitter eventEmitter = getEventEmitter(); MultipartBody.Builder multipartBuilder = new MultipartBody.Builder(); multipartBuilder.setType(MediaType.parse(contentType)); @@ -621,7 +626,7 @@ public void clearCookies(com.facebook.react.bridge.Callback callback) { } String fileContentUriStr = bodyPart.getString(REQUEST_BODY_KEY_URI); InputStream fileInputStream = - RequestBodyUtil.getFileInputStream(getReactApplicationContext(), fileContentUriStr); + RequestBodyUtil.getFileInputStream(getReactApplicationContext(), fileContentUriStr); if (fileInputStream == null) { ResponseUtil.onRequestError( eventEmitter, @@ -641,9 +646,11 @@ public void clearCookies(com.facebook.react.bridge.Callback callback) { /** * Extracts the headers from the Array. If the format is invalid, this method will return null. */ - private @Nullable Headers extractHeaders( - @Nullable ReadableArray headersArray, - @Nullable ReadableMap requestData) { + private + @Nullable + Headers extractHeaders( + @Nullable ReadableArray headersArray, + @Nullable ReadableMap requestData) { if (headersArray == null) { return null; } From e70fb7e370814e93b8eccbf62d2538bff298bbc0 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 5 Oct 2017 17:32:11 -0400 Subject: [PATCH 40/66] Fix whitespace p3 --- .../modules/network/NetworkingModule.java | 216 +++++++++--------- 1 file changed, 105 insertions(+), 111 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 888a4172e4390a..d03ffd419759a7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -1,7 +1,7 @@ /** * 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. @@ -90,9 +90,7 @@ public interface ResponseHandler { private final OkHttpClient mClient; private final ForwardingCookieHandler mCookieHandler; - private final - @Nullable - String mDefaultUserAgent; + private final @Nullable String mDefaultUserAgent; private final CookieJarContainer mCookieJarContainer; private final Set mRequestIds; private final List mRequestBodyHandlers = new ArrayList<>(); @@ -101,10 +99,10 @@ public interface ResponseHandler { private boolean mShuttingDown; /* package */ NetworkingModule( - ReactApplicationContext reactContext, - @Nullable String defaultUserAgent, - OkHttpClient client, - @Nullable List networkInterceptorCreators) { + ReactApplicationContext reactContext, + @Nullable String defaultUserAgent, + OkHttpClient client, + @Nullable List networkInterceptorCreators) { super(reactContext); if (networkInterceptorCreators != null) { @@ -214,15 +212,15 @@ public void removeResponseHandler(ResponseHandler handler) { * @param timeout value of 0 results in no timeout */ public void sendRequest( - String method, - String url, - final int requestId, - ReadableArray headers, - ReadableMap data, - final String responseType, - final boolean useIncrementalUpdates, - int timeout, - boolean withCredentials) { + String method, + String url, + final int requestId, + ReadableArray headers, + ReadableMap data, + final String responseType, + final boolean useIncrementalUpdates, + int timeout, + boolean withCredentials) { final RCTDeviceEventEmitter eventEmitter = getEventEmitter(); try { @@ -370,7 +368,7 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } String uri = data.getString(REQUEST_BODY_KEY_URI); InputStream fileInputStream = - RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri); + RequestBodyUtil.getFileInputStream(getReactApplicationContext(), uri); if (fileInputStream == null) { ResponseUtil.onRequestError( eventEmitter, @@ -380,15 +378,15 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { return; } requestBuilder.method( - method, - RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); + method, + RequestBodyUtil.create(MediaType.parse(contentType), fileInputStream)); } else if (data.hasKey(REQUEST_BODY_KEY_FORMDATA)) { if (contentType == null) { contentType = "multipart/form-data"; } ReadableArray parts = data.getArray(REQUEST_BODY_KEY_FORMDATA); MultipartBody.Builder multipartBuilder = - constructMultipartBody(parts, contentType, requestId); + constructMultipartBody(parts, contentType, requestId); if (multipartBuilder == null) { return; } @@ -398,17 +396,17 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { RequestBodyUtil.createProgressRequest( multipartBuilder.build(), new ProgressListener() { - long last = System.nanoTime(); + long last = System.nanoTime(); - @Override - public void onProgress(long bytesWritten, long contentLength, boolean done) { - long now = System.nanoTime(); - if (done || shouldDispatch(now, last)) { - ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); - last = now; - } - } - })); + @Override + public void onProgress(long bytesWritten, long contentLength, boolean done) { + long now = System.nanoTime(); + if (done || shouldDispatch(now, last)) { + ResponseUtil.onDataSend(eventEmitter, requestId, bytesWritten, contentLength); + last = now; + } + } + })); } else { // Nothing in data payload, at least nothing we could understand anyway. requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); @@ -416,85 +414,85 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { addRequest(requestId); client.newCall(requestBuilder.build()).enqueue( - new Callback() { - @Override - public void onFailure(Call call, IOException e) { - if (mShuttingDown) { - return; + new Callback() { + @Override + public void onFailure(Call call, IOException e) { + if (mShuttingDown) { + return; + } + removeRequest(requestId); + String errorMessage = e.getMessage() != null + ? e.getMessage() + : "Error while executing request: " + e.getClass().getSimpleName(); + ResponseUtil.onRequestError(eventEmitter, requestId, errorMessage, e); } - removeRequest(requestId); - String errorMessage = e.getMessage() != null - ? e.getMessage() - : "Error while executing request: " + e.getClass().getSimpleName(); - ResponseUtil.onRequestError(eventEmitter, requestId, errorMessage, e); - } - @Override - public void onResponse(Call call, Response response) throws IOException { - if (mShuttingDown) { - return; - } - removeRequest(requestId); - // Before we touch the body send headers to JS - ResponseUtil.onResponseReceived( - eventEmitter, - requestId, - response.code(), - translateHeaders(response.headers()), - response.request().url().toString()); - - ResponseBody responseBody = response.body(); - try { - // Check if a handler is registered - for (ResponseHandler handler : mResponseHandlers) { - if (handler.supports(responseType)) { - WritableMap res = handler.toResponseData(responseBody); - ResponseUtil.onDataReceived(eventEmitter, requestId, res); + @Override + public void onResponse(Call call, Response response) throws IOException { + if (mShuttingDown) { + return; + } + removeRequest(requestId); + // Before we touch the body send headers to JS + ResponseUtil.onResponseReceived( + eventEmitter, + requestId, + response.code(), + translateHeaders(response.headers()), + response.request().url().toString()); + + ResponseBody responseBody = response.body(); + try { + // Check if a handler is registered + for (ResponseHandler handler : mResponseHandlers) { + if (handler.supports(responseType)) { + WritableMap res = handler.toResponseData(responseBody); + ResponseUtil.onDataReceived(eventEmitter, requestId, res); + ResponseUtil.onRequestSuccess(eventEmitter, requestId); + return; + } + } + + // If JS wants progress updates during the download, and it requested a text response, + // periodically send response data updates to JS. + if (useIncrementalUpdates && responseType.equals("text")) { + readWithProgress(eventEmitter, requestId, responseBody); ResponseUtil.onRequestSuccess(eventEmitter, requestId); return; } - } - // If JS wants progress updates during the download, and it requested a text response, - // periodically send response data updates to JS. - if (useIncrementalUpdates && responseType.equals("text")) { - readWithProgress(eventEmitter, requestId, responseBody); - ResponseUtil.onRequestSuccess(eventEmitter, requestId); - return; - } - - // Otherwise send the data in one big chunk, in the format that JS requested. - String responseString = ""; - if (responseType.equals("text")) { - try { - responseString = responseBody.string(); - } catch (IOException e) { - if (response.request().method().equalsIgnoreCase("HEAD")) { - // The request is an `HEAD` and the body is empty, - // the OkHttp will produce an exception. - // Ignore the exception to not invalidate the request in the - // Javascript layer. - // Introduced to fix issue #7463. - } else { - ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); + // Otherwise send the data in one big chunk, in the format that JS requested. + String responseString = ""; + if (responseType.equals("text")) { + try { + responseString = responseBody.string(); + } catch (IOException e) { + if (response.request().method().equalsIgnoreCase("HEAD")) { + // The request is an `HEAD` and the body is empty, + // the OkHttp will produce an exception. + // Ignore the exception to not invalidate the request in the + // Javascript layer. + // Introduced to fix issue #7463. + } else { + ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); + } } + } else if (responseType.equals("base64")) { + responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); } - } else if (responseType.equals("base64")) { - responseString = Base64.encodeToString(responseBody.bytes(), Base64.NO_WRAP); + ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); + ResponseUtil.onRequestSuccess(eventEmitter, requestId); + } catch (IOException e) { + ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); } - ResponseUtil.onDataReceived(eventEmitter, requestId, responseString); - ResponseUtil.onRequestSuccess(eventEmitter, requestId); - } catch (IOException e) { - ResponseUtil.onRequestError(eventEmitter, requestId, e.getMessage(), e); } - } - }); + }); } private void readWithProgress( - RCTDeviceEventEmitter eventEmitter, - int requestId, - ResponseBody responseBody) throws IOException { + RCTDeviceEventEmitter eventEmitter, + int requestId, + ResponseBody responseBody) throws IOException { long totalBytesRead = -1; long contentLength = -1; try { @@ -548,8 +546,8 @@ private static WritableMap translateHeaders(Headers headers) { // multiple values for the same header if (responseHeaders.hasKey(headerName)) { responseHeaders.putString( - headerName, - responseHeaders.getString(headerName) + ", " + headers.value(i)); + headerName, + responseHeaders.getString(headerName) + ", " + headers.value(i)); } else { responseHeaders.putString(headerName, headers.value(i)); } @@ -579,12 +577,10 @@ public void clearCookies(com.facebook.react.bridge.Callback callback) { mCookieHandler.clearCookies(callback); } - private - @Nullable - MultipartBody.Builder constructMultipartBody( - ReadableArray body, - String contentType, - int requestId) { + private @Nullable MultipartBody.Builder constructMultipartBody( + ReadableArray body, + String contentType, + int requestId) { RCTDeviceEventEmitter eventEmitter = getEventEmitter(); MultipartBody.Builder multipartBuilder = new MultipartBody.Builder(); multipartBuilder.setType(MediaType.parse(contentType)); @@ -626,7 +622,7 @@ MultipartBody.Builder constructMultipartBody( } String fileContentUriStr = bodyPart.getString(REQUEST_BODY_KEY_URI); InputStream fileInputStream = - RequestBodyUtil.getFileInputStream(getReactApplicationContext(), fileContentUriStr); + RequestBodyUtil.getFileInputStream(getReactApplicationContext(), fileContentUriStr); if (fileInputStream == null) { ResponseUtil.onRequestError( eventEmitter, @@ -646,11 +642,9 @@ MultipartBody.Builder constructMultipartBody( /** * Extracts the headers from the Array. If the format is invalid, this method will return null. */ - private - @Nullable - Headers extractHeaders( - @Nullable ReadableArray headersArray, - @Nullable ReadableMap requestData) { + private @Nullable Headers extractHeaders( + @Nullable ReadableArray headersArray, + @Nullable ReadableMap requestData) { if (headersArray == null) { return null; } From 37a0269f4351a8ada5e8820102580fa74d6a7068 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 5 Oct 2017 17:44:22 -0400 Subject: [PATCH 41/66] Improve buffer resize condition to match ios --- .../main/java/com/facebook/react/modules/blob/BlobModule.java | 2 +- .../com/facebook/react/modules/network/NetworkingModule.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index ab0f53861d079f..7e40f5863b08cd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -211,7 +211,7 @@ public void remove(String blobId) { if (size == -1) { size = data.length - offset; } - if (offset >= 0) { + if (offset > 0 || size != data.length) { data = Arrays.copyOfRange(data, offset, offset + size); } return data; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index d03ffd419759a7..5b60a039ffa798 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -422,8 +422,8 @@ public void onFailure(Call call, IOException e) { } removeRequest(requestId); String errorMessage = e.getMessage() != null - ? e.getMessage() - : "Error while executing request: " + e.getClass().getSimpleName(); + ? e.getMessage() + : "Error while executing request: " + e.getClass().getSimpleName(); ResponseUtil.onRequestError(eventEmitter, requestId, errorMessage, e); } From 1aa1f843e564869a211b8f6af12614528e35e5f8 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 5 Oct 2017 17:55:45 -0400 Subject: [PATCH 42/66] More cleanup --- .../react/modules/blob/BlobModule.java | 2 +- .../react/modules/blob/FileReaderModule.java | 16 ++- .../react/modules/network/ResponseUtil.java | 1 + .../modules/websocket/WebSocketModule.java | 100 +++++++++--------- 4 files changed, 65 insertions(+), 54 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 7e40f5863b08cd..2adf3792b8402a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -1,6 +1,6 @@ /** * 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. diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java index 3c9bf34d04e9d4..5625a04583e151 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java @@ -11,7 +11,12 @@ import android.util.Base64; -import com.facebook.react.bridge.*; + +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.module.annotations.ReactModule; @@ -29,9 +34,14 @@ public String getName() { return "FileReaderModule"; } + private BlobModule getBlobModule() { + return getReactApplicationContext().getNativeModule(BlobModule.class); + } + @ReactMethod public void readAsText(ReadableMap blob, String encoding, Promise promise) { - byte[] bytes = BlobModule.resolve( + + byte[] bytes = getBlobModule().resolve( blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); @@ -50,7 +60,7 @@ public void readAsText(ReadableMap blob, String encoding, Promise promise) { @ReactMethod public void readAsDataURL(ReadableMap blob, Promise promise) { - byte[] bytes = BlobModule.resolve( + byte[] bytes = getBlobModule().resolve( blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java index 20bed2a23b3913..cd5aabff0fdceb 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/ResponseUtil.java @@ -71,6 +71,7 @@ public static void onDataReceived( eventEmitter.emit("didReceiveNetworkData", args); } + public static void onDataReceived( RCTDeviceEventEmitter eventEmitter, int requestId, diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java index 7fbbca33881b9e..2bfae94e7a9428 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java @@ -137,64 +137,64 @@ public void connect( } client.newWebSocket( - builder.build(), - new WebSocketListener() { - - @Override - public void onOpen(WebSocket webSocket, Response response) { - mWebSocketConnections.put(id, webSocket); - WritableMap params = Arguments.createMap(); - params.putInt("id", id); - sendEvent("websocketOpen", params); - } + builder.build(), + new WebSocketListener() { + + @Override + public void onOpen(WebSocket webSocket, Response response) { + mWebSocketConnections.put(id, webSocket); + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + sendEvent("websocketOpen", params); + } - @Override - public void onClosed(WebSocket webSocket, int code, String reason) { - WritableMap params = Arguments.createMap(); - params.putInt("id", id); - params.putInt("code", code); - params.putString("reason", reason); - sendEvent("websocketClosed", params); - } + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putInt("code", code); + params.putString("reason", reason); + sendEvent("websocketClosed", params); + } - @Override - public void onFailure(WebSocket webSocket, Throwable t, Response response) { - notifyWebSocketFailed(id, t.getMessage()); - } + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + notifyWebSocketFailed(id, t.getMessage()); + } - @Override - public void onMessage(WebSocket webSocket, String text) { - WritableMap params = Arguments.createMap(); - params.putInt("id", id); - params.putString("type", "text"); - - ContentHandler contentHandler = mContentHandlers.get(id); - if (contentHandler != null) { - contentHandler.onMessage(text, params); - } else { - params.putString("data", text); + @Override + public void onMessage(WebSocket webSocket, String text) { + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putString("type", "text"); + + ContentHandler contentHandler = mContentHandlers.get(id); + if (contentHandler != null) { + contentHandler.onMessage(text, params); + } else { + params.putString("data", text); + } + sendEvent("websocketMessage", params); } - sendEvent("websocketMessage", params); - } - @Override - public void onMessage(WebSocket webSocket, ByteString bytes) { - WritableMap params = Arguments.createMap(); - params.putInt("id", id); - params.putString("type", "binary"); + @Override + public void onMessage(WebSocket webSocket, ByteString bytes) { + WritableMap params = Arguments.createMap(); + params.putInt("id", id); + params.putString("type", "binary"); - ContentHandler contentHandler = mContentHandlers.get(id); - if (contentHandler != null) { - contentHandler.onMessage(bytes, params); - } else { - String text = bytes.base64(); + ContentHandler contentHandler = mContentHandlers.get(id); + if (contentHandler != null) { + contentHandler.onMessage(bytes, params); + } else { + String text = bytes.base64(); - params.putString("data", text); - } + params.putString("data", text); + } - sendEvent("websocketMessage", params); - } - }); + sendEvent("websocketMessage", params); + } + }); // Trigger shutdown of the dispatcher's executor so this process can exit cleanly client.dispatcher().executorService().shutdown(); From 8e98f95cfbd0954360d1d77138bec21f1749298a Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 5 Oct 2017 18:08:25 -0400 Subject: [PATCH 43/66] Fix buck files --- .../com/facebook/react/modules/websocket/BUCK | 8 +++----- .../src/main/java/com/facebook/react/shell/BUCK | 6 ++---- .../test/java/com/facebook/react/modules/BUCK | 16 ++++++++-------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK index 956c75620b8d48..6ea83d2e5c85ec 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/BUCK @@ -3,21 +3,19 @@ include_defs("//ReactAndroid/DEFS") android_library( name = "websocket", srcs = glob(["**/*.java"]), + visibility = [ + "PUBLIC", + ], deps = [ react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/java/okhttp:okhttp3"), - react_native_dep("third-party/java/okhttp:okhttp3-ws"), react_native_dep("third-party/java/okio:okio"), react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), react_native_target("java/com/facebook/react/modules/core:core"), react_native_target("java/com/facebook/react/modules/network:network"), - react_native_target("java/com/facebook/react/modules/blob:blob"), - ], - visibility = [ - "PUBLIC", ], ) diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index 63ede8ce3a9de9..2b2a5ba1c214ba 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -19,7 +19,9 @@ android_library( react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/devsupport:devsupport"), + react_native_target("java/com/facebook/react/flat:flat"), react_native_target("java/com/facebook/react/module/model:model"), + react_native_target("java/com/facebook/react/modules/accessibilityinfo:accessibilityinfo"), react_native_target("java/com/facebook/react/modules/appstate:appstate"), react_native_target("java/com/facebook/react/modules/blob:blob"), react_native_target("java/com/facebook/react/modules/camera:camera"), @@ -51,7 +53,6 @@ android_library( react_native_target("java/com/facebook/react/views/modal:modal"), react_native_target("java/com/facebook/react/views/picker:picker"), react_native_target("java/com/facebook/react/views/progressbar:progressbar"), - react_native_target("java/com/facebook/react/views/recyclerview:recyclerview"), react_native_target("java/com/facebook/react/views/scroll:scroll"), react_native_target("java/com/facebook/react/views/slider:slider"), react_native_target("java/com/facebook/react/views/swiperefresh:swiperefresh"), @@ -65,7 +66,4 @@ android_library( react_native_target("java/com/facebook/react/views/webview:webview"), react_native_target("res:shell"), ], - visibility = [ - "PUBLIC", - ], ) diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK index be2230a0a9503c..b6675cb7eefdbe 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/BUCK @@ -1,10 +1,13 @@ include_defs("//ReactAndroid/DEFS") rn_robolectric_test( - # Please change the contact to the oncall of your team - contacts = ["oncall+fbandroid_sheriff@xmail.facebook.com"], name = "modules", srcs = glob(["**/*.java"]), + # Please change the contact to the oncall of your team + contacts = ["oncall+fbandroid_sheriff@xmail.facebook.com"], + visibility = [ + "PUBLIC", + ], deps = [ YOGA_TARGET, react_native_dep("libraries/fbcore/src/test/java/com/facebook/powermock:powermock"), @@ -16,11 +19,12 @@ rn_robolectric_test( react_native_dep("third-party/java/okhttp:okhttp3"), react_native_dep("third-party/java/okio:okio"), react_native_dep("third-party/java/robolectric3/robolectric:robolectric"), + react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/animation:animation"), react_native_target("java/com/facebook/react/bridge:bridge"), - react_native_target("java/com/facebook/react/common/network:network"), react_native_target("java/com/facebook/react/common:common"), - react_native_target("java/com/facebook/react/devsupport:devsupport"), + react_native_target("java/com/facebook/react/common/network:network"), + react_native_target("java/com/facebook/react/devsupport:interfaces"), react_native_target("java/com/facebook/react/jstasks:jstasks"), react_native_target("java/com/facebook/react/modules/blob:blob"), react_native_target("java/com/facebook/react/modules/clipboard:clipboard"), @@ -34,10 +38,6 @@ rn_robolectric_test( react_native_target("java/com/facebook/react/modules/systeminfo:systeminfo"), react_native_target("java/com/facebook/react/touch:touch"), react_native_target("java/com/facebook/react/uimanager:uimanager"), - react_native_target("java/com/facebook/react:react"), react_native_tests_target("java/com/facebook/react/bridge:testhelpers"), ], - visibility = [ - "PUBLIC" - ], ) From 45d014ab4bdcad1fc67a0e68dfc40a75df6c3201 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 5 Oct 2017 18:30:37 -0400 Subject: [PATCH 44/66] Document networking interfaces --- .../modules/network/NetworkingModule.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 5b60a039ffa798..172eb79da309a6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -58,21 +58,49 @@ @ReactModule(name = NetworkingModule.NAME) public final class NetworkingModule extends ReactContextBaseJavaModule { + /** + * Allows to implement a custom fetching process for specific URIs. It is the handler's job + * to fetch the URI and return the JS body payload. + */ public interface UriHandler { + /** + * Returns if the handler should be used for an URI. + */ boolean supports(Uri uri, String responseType); + /** + * Fetch the URI and return the JS body payload. + */ WritableMap fetch(Uri uri, Context context) throws IOException; } + /** + * Allows adding custom handling to build the {@link RequestBody} from the JS body payload. + */ public interface RequestBodyHandler { + /** + * Returns if the handler should be used for a JS body payload. + */ boolean supports(ReadableMap map); + /** + * Returns the {@link RequestBody} for the JS body payload. + */ RequestBody toRequestBody(ReadableMap map, String contentType); } + /** + * Allows adding custom handling to build the JS body payload from the {@link ResponseBody}. + */ public interface ResponseHandler { + /** + * Returns if the handler should be used for a response type. + */ boolean supports(String responseType); + /** + * Returns the JS body payload for the {@link ResponseBody}. + */ WritableMap toResponseData(ResponseBody body) throws IOException; } From 21ff09b91c3c28ce868b765fe5d356fa3f65b679 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 5 Oct 2017 18:59:19 -0400 Subject: [PATCH 45/66] Static NAME --- .../com/facebook/react/modules/blob/FileReaderModule.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java index 5625a04583e151..2e550a239f9736 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java @@ -20,9 +20,10 @@ import com.facebook.react.module.annotations.ReactModule; -@ReactModule(name = "FileReaderModule") +@ReactModule(name = FileReaderModule.NAME) public class FileReaderModule extends ReactContextBaseJavaModule { + protected static final String NAME = "FileReaderModule"; private static final String ERROR_INVALID_BLOB = "ERROR_INVALID_BLOB"; public FileReaderModule(ReactApplicationContext reactContext) { @@ -31,7 +32,7 @@ public FileReaderModule(ReactApplicationContext reactContext) { @Override public String getName() { - return "FileReaderModule"; + return NAME; } private BlobModule getBlobModule() { From cd6ede7df4370d4271670121bbcb27b29e13c526 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Fri, 6 Oct 2017 22:25:50 -0400 Subject: [PATCH 46/66] Fix flow --- Libraries/Blob/BlobManager.js | 4 ++-- Libraries/WebSocket/WebSocket.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index e2cc2e613c7a4f..f3d7f832546e99 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -124,8 +124,8 @@ class BlobManager { /** * Send a blob message to a websocket. */ - static sendOverSocket(data: Blob, socketId: number): void { - BlobModule.sendOverSocket(data, socketId); + static sendOverSocket(blob: Blob, socketId: number): void { + BlobModule.sendOverSocket(blob.data, socketId); } } diff --git a/Libraries/WebSocket/WebSocket.js b/Libraries/WebSocket/WebSocket.js index 4c4dd8e0edcbd8..3a70b3792803d5 100644 --- a/Libraries/WebSocket/WebSocket.js +++ b/Libraries/WebSocket/WebSocket.js @@ -179,7 +179,7 @@ class WebSocket extends EventTarget(...WEBSOCKET_EVENTS) { if (data instanceof Blob) { invariant(BlobManager.isAvailable, 'Native module BlobModule is required for blob support'); - BlobManager.sendOverSocket(data.data, this._socketId); + BlobManager.sendOverSocket(data, this._socketId); return; } From b536989cfe1006f676649b8a8128d1b9f508a70c Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Fri, 6 Oct 2017 22:39:15 -0400 Subject: [PATCH 47/66] Fix buck build --- ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK index ff188a87e91081..10a32adc62b81f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BUCK @@ -14,11 +14,13 @@ android_library( react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"), react_native_dep("third-party/java/infer-annotations:infer-annotations"), react_native_dep("third-party/java/jsr-305:jsr-305"), + react_native_dep("third-party/java/okhttp:okhttp3"), react_native_dep("third-party/java/okio:okio"), react_native_target("java/com/facebook/react:react"), react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), + react_native_target("java/com/facebook/react/modules/network:network"), react_native_target("java/com/facebook/react/modules/websocket:websocket"), ], ) From 75b4f1e35d8878d21127fcca76347f63f9d23b99 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sat, 7 Oct 2017 00:07:11 -0400 Subject: [PATCH 48/66] Fix android tests, cleanup createFromURI leftovers --- Libraries/Blob/__mocks__/BlobModule.js | 10 -- .../react/modules/blob/BlobModule.java | 26 ++-- .../modules/network/NetworkingModule.java | 4 +- .../react/modules/blob/BlobModuleTest.java | 126 ++++++------------ 4 files changed, 55 insertions(+), 111 deletions(-) diff --git a/Libraries/Blob/__mocks__/BlobModule.js b/Libraries/Blob/__mocks__/BlobModule.js index 386e5f28622a2b..1cbda950883312 100644 --- a/Libraries/Blob/__mocks__/BlobModule.js +++ b/Libraries/Blob/__mocks__/BlobModule.js @@ -11,16 +11,6 @@ */ const BlobModule = { createFromParts() {}, - async createFromURI() { - return { - blobId: 'c6cec908-c69e-11e6-9d9d-cec0c932ce01', - offset: 0, - size: 34254, - type: 'image/png', - name: 'image.png', - lastModified: 1482229709578, - }; - }, release() {}, }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java index 2adf3792b8402a..7e1c4954af8b7e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/BlobModule.java @@ -86,19 +86,17 @@ public boolean supports(Uri uri, String responseType) { } @Override - public WritableMap fetch(Uri uri, Context context) throws IOException { - ContentResolver resolver = context.getContentResolver(); - - byte[] data = getBytesFromUri(uri, resolver); + public WritableMap fetch(Uri uri) throws IOException { + byte[] data = getBytesFromUri(uri); WritableMap blob = Arguments.createMap(); blob.putString("blobId", store(data)); blob.putInt("offset", 0); blob.putInt("size", data.length); - blob.putString("type", getMimeTypeFromUri(uri, resolver)); + blob.putString("type", getMimeTypeFromUri(uri)); // Needed for files - blob.putString("name", getNameFromUri(uri, resolver)); + blob.putString("name", getNameFromUri(uri)); blob.putDouble("lastModified", getLastModifiedFromUri(uri)); return blob; @@ -221,8 +219,8 @@ public void remove(String blobId) { return resolve(blob.getString("blobId"), blob.getInt("offset"), blob.getInt("size")); } - private static byte[] getBytesFromUri(Uri contentUri, ContentResolver resolver) throws IOException { - InputStream is = resolver.openInputStream(contentUri); + private byte[] getBytesFromUri(Uri contentUri) throws IOException { + InputStream is = getReactApplicationContext().getContentResolver().openInputStream(contentUri); if (is == null) { throw new FileNotFoundException("File not found for " + contentUri); @@ -238,12 +236,14 @@ private static byte[] getBytesFromUri(Uri contentUri, ContentResolver resolver) return byteBuffer.toByteArray(); } - private static String getNameFromUri(Uri contentUri, ContentResolver resolver) { + private String getNameFromUri(Uri contentUri) { if (contentUri.getScheme().equals("file")) { return contentUri.getLastPathSegment(); } String[] projection = {MediaStore.MediaColumns.DISPLAY_NAME}; - Cursor metaCursor = resolver.query(contentUri, projection, null, null, null); + Cursor metaCursor = getReactApplicationContext() + .getContentResolver() + .query(contentUri, projection, null, null, null); if (metaCursor != null) { try { if (metaCursor.moveToFirst()) { @@ -256,15 +256,15 @@ private static String getNameFromUri(Uri contentUri, ContentResolver resolver) { return contentUri.getLastPathSegment(); } - private static long getLastModifiedFromUri(Uri contentUri) { + private long getLastModifiedFromUri(Uri contentUri) { if (contentUri.getScheme().equals("file")) { return new File(contentUri.toString()).lastModified(); } return 0; } - private static String getMimeTypeFromUri(Uri contentUri, ContentResolver resolver) { - String type = resolver.getType(contentUri); + private String getMimeTypeFromUri(Uri contentUri) { + String type = getReactApplicationContext().getContentResolver().getType(contentUri); if (type == null) { String ext = MimeTypeMap.getFileExtensionFromUrl(contentUri.getPath()); diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 172eb79da309a6..f8c66a35c0c14e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -71,7 +71,7 @@ public interface UriHandler { /** * Fetch the URI and return the JS body payload. */ - WritableMap fetch(Uri uri, Context context) throws IOException; + WritableMap fetch(Uri uri) throws IOException; } /** @@ -257,7 +257,7 @@ public void sendRequest( // Check if a handler is registered for (UriHandler handler : mUriHandlers) { if (handler.supports(uri, responseType)) { - WritableMap res = handler.fetch(uri, getReactApplicationContext()); + WritableMap res = handler.fetch(uri); ResponseUtil.onDataReceived(eventEmitter, requestId, res); ResponseUtil.onRequestSuccess(eventEmitter, requestId); return; diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java index d9c8cdb829e7a1..a16a41372cf03d 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java @@ -10,7 +10,12 @@ package com.facebook.react.modules.blob; import android.net.Uri; -import com.facebook.react.bridge.*; + +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.JavaOnlyArray; +import com.facebook.react.bridge.JavaOnlyMap; +import com.facebook.react.bridge.ReactTestHelper; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -26,13 +31,15 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -import javax.annotation.Nullable; import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.util.Arrays; import java.util.Random; import java.util.UUID; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; @PrepareForTest({Arguments.class}) @RunWith(RobolectricTestRunner.class) @@ -40,9 +47,9 @@ @Config(manifest = Config.NONE) public class BlobModuleTest { - private byte[] bytes; - private String blobId; - private BlobModule blobModule; + private byte[] mBytes; + private String mBlobId; + private BlobModule mBlobModule; @Rule public PowerMockRule rule = new PowerMockRule(); @@ -57,58 +64,53 @@ public Object answer(InvocationOnMock invocation) throws Throwable { } }); - bytes = new byte[120]; - new Random().nextBytes(bytes); - blobId = BlobModule.store(bytes); - blobModule = new BlobModule(ReactTestHelper.createCatalystContextForTest()); - - BlobModule spy = PowerMockito.spy(blobModule); + mBytes = new byte[120]; + new Random().nextBytes(mBytes); - PowerMockito.when(spy, "getBytesFromUri", Uri.class).thenReturn(bytes); - PowerMockito.when(spy, "getNameFromUri", Uri.class).thenReturn("test.png"); - PowerMockito.when(spy, "getLastModifiedFromUri", Uri.class).thenReturn(1482276506); - PowerMockito.when(spy, "getMimeTypeFromUri", Uri.class).thenReturn("image/png"); + mBlobModule = new BlobModule(ReactTestHelper.createCatalystContextForTest()); + mBlobId = mBlobModule.store(mBytes); } @After public void cleanUp() { - BlobModule.remove(blobId); + mBlobModule.remove(mBlobId); } @Test public void testResolve() { - assertArrayEquals(bytes, BlobModule.resolve(blobId, 0, bytes.length)); - assertArrayEquals(bytes, BlobModule.resolve(blobId, 30, bytes.length - 30)); + assertArrayEquals(mBytes, mBlobModule.resolve(mBlobId, 0, mBytes.length)); + byte[] expectedRange = Arrays.copyOfRange(mBytes, 30, mBytes.length); + assertArrayEquals(expectedRange, mBlobModule.resolve(mBlobId, 30, mBytes.length - 30)); } @Test public void testResolveUri() { Uri uri = new Uri.Builder() - .appendPath(blobId) + .appendPath(mBlobId) .appendQueryParameter("offset", "0") - .appendQueryParameter("size", String.valueOf(bytes.length)) + .appendQueryParameter("size", String.valueOf(mBytes.length)) .build(); - assertArrayEquals(bytes, BlobModule.resolve(uri)); + assertArrayEquals(mBytes, mBlobModule.resolve(uri)); } @Test public void testResolveMap() { JavaOnlyMap blob = new JavaOnlyMap(); - blob.putString("blobId", blobId); + blob.putString("blobId", mBlobId); blob.putInt("offset", 0); - blob.putInt("size", bytes.length); + blob.putInt("size", mBytes.length); - assertArrayEquals(bytes, BlobModule.resolve(blob)); + assertArrayEquals(mBytes, mBlobModule.resolve(blob)); } @Test public void testRemove() { - assertNotNull(BlobModule.resolve(blobId, 0, bytes.length)); + assertNotNull(mBlobModule.resolve(mBlobId, 0, mBytes.length)); - BlobModule.remove(blobId); + mBlobModule.remove(mBlobId); - assertNull(BlobModule.resolve(blobId, 0, bytes.length)); + assertNull(mBlobModule.resolve(mBlobId, 0, mBytes.length)); } @Test @@ -116,9 +118,9 @@ public void testCreateFromParts() { String id = UUID.randomUUID().toString(); JavaOnlyMap blobData = new JavaOnlyMap(); - blobData.putString("blobId", blobId); + blobData.putString("blobId", mBlobId); blobData.putInt("offset", 0); - blobData.putInt("size", bytes.length); + blobData.putInt("size", mBytes.length); JavaOnlyMap blob = new JavaOnlyMap(); blob.putMap("data", blobData); blob.putString("type", "blob"); @@ -127,79 +129,31 @@ public void testCreateFromParts() { byte[] stringBytes = stringData.getBytes(Charset.forName("UTF-8")); JavaOnlyMap string = new JavaOnlyMap(); string.putString("data", stringData); - string.putString("type", "blob"); + string.putString("type", "string"); JavaOnlyArray parts = new JavaOnlyArray(); parts.pushMap(blob); parts.pushMap(string); - blobModule.createFromParts(parts, id); + mBlobModule.createFromParts(parts, id); - int resultSize = bytes.length + stringBytes.length; + int resultSize = mBytes.length + stringBytes.length; - byte[] result = BlobModule.resolve(id, 0, resultSize); + byte[] result = mBlobModule.resolve(id, 0, resultSize); ByteBuffer buffer = ByteBuffer.allocate(resultSize); - buffer.put(bytes); + buffer.put(mBytes); buffer.put(stringBytes); assertArrayEquals(result, buffer.array()); } - @Test - public void testCreateFromURI() { - final SimplePromise promise = new SimplePromise(); - - blobModule.createFromURI("content://photos/holiday-season", promise); - - JavaOnlyMap map = (JavaOnlyMap) promise.getValue(); - - assertNotNull(map.getString("blobId")); - assertEquals(map.getInt("offset"), 0); - assertEquals(map.getInt("size"), bytes.length); - assertEquals(map.getString("type"), "image/png"); - assertEquals(map.getString("name"), "test"); - assertEquals(map.getInt("lastModified"), 1482276506); - } - @Test public void testRelease() { - assertNotNull(BlobModule.resolve(blobId, 0, bytes.length)); + assertNotNull(mBlobModule.resolve(mBlobId, 0, mBytes.length)); - blobModule.release(blobId); + mBlobModule.release(mBlobId); - assertNull(BlobModule.resolve(blobId, 0, bytes.length)); + assertNull(mBlobModule.resolve(mBlobId, 0, mBytes.length)); } - - final static class SimplePromise implements Promise { - private Object mValue; - - public Object getValue() { - return mValue; - } - - @Override - public void resolve(Object value) { - mValue = value; - } - - @Override - public void reject(String code, String message) { - reject(code, message, /*Throwable*/null); - } - - @Override - @Deprecated - public void reject(String message) {} - - @Override - public void reject(String code, Throwable e) {} - - @Override - public void reject(Throwable e) {} - - @Override - public void reject(String code, String message, @Nullable Throwable e) {} - } - } From fb3496abe256360f7dc37ef6dccda37296ab2b06 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 18 Jan 2018 00:36:47 -0500 Subject: [PATCH 49/66] Fix invariant import, cleanup networking module imports --- Libraries/Blob/File.js | 2 +- Libraries/Blob/URL.js | 5 +++-- .../react/modules/network/NetworkingModule.java | 16 ++-------------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js index 076d9946bf5d4d..a7dfcb374b83c7 100644 --- a/Libraries/Blob/File.js +++ b/Libraries/Blob/File.js @@ -14,7 +14,7 @@ const Blob = require('Blob'); -const invariant = require('invariant'); +const invariant = require('fbjs/lib/invariant'); import type {BlobOptions} from 'BlobTypes'; diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index 848c99768e8951..8b761ca708ce0b 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -59,8 +59,9 @@ class URL { if (BLOB_URL_PREFIX === null) { throw new Error('Cannot create URL for blob!'); } - return `${BLOB_URL_PREFIX}${blob.data.blobId}?offset=${blob.data - .offset}&size=${blob.size}`; + return `${BLOB_URL_PREFIX}${blob.data.blobId}?offset=${ + blob.data.offset + }&size=${blob.size}`; } static revokeObjectURL(url: string) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index 9075c54c5518e3..dcea10fea939c3 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -8,17 +8,7 @@ */ package com.facebook.react.modules.network; -import javax.annotation.Nullable; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.nio.charset.Charset; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - +import android.net.Uri; import android.util.Base64; import com.facebook.react.bridge.Arguments; @@ -36,12 +26,10 @@ import java.io.IOException; import java.io.InputStream; -import java.io.Reader; +import java.nio.charset.Charset; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; From c243471aacb38fa66d3b9398143426c5af992492 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 18 Jan 2018 00:56:54 -0500 Subject: [PATCH 50/66] Address some review feedback --- Libraries/Blob/BlobManager.js | 4 ++-- Libraries/Blob/File.js | 3 ++- Libraries/Blob/RCTBlobManager.mm | 10 +++++++--- Libraries/Network/XMLHttpRequest.js | 2 +- Libraries/Network/convertRequestBody.js | 4 ++-- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index f3d7f832546e99..a2131de9906a93 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -106,7 +106,7 @@ class BlobManager { } /** - * Indicate the the websocket should return a blob for incoming binary + * Indicate the websocket should return a blob for incoming binary * messages. */ static addWebSocketHandler(socketId: number): void { @@ -114,7 +114,7 @@ class BlobManager { } /** - * Indicate the the websocket should no longer return a blob for incoming + * Indicate the websocket should no longer return a blob for incoming * binary messages. */ static removeWebSocketHandler(socketId: number): void { diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js index a7dfcb374b83c7..8e999b20f41dd0 100644 --- a/Libraries/Blob/File.js +++ b/Libraries/Blob/File.js @@ -43,7 +43,8 @@ class File extends Blob { * Name of the file. */ get name(): string { - return this.data.name || ''; + invariant(this.data.name != null, 'Files must have a name set.'); + return this.data.name; } /* diff --git a/Libraries/Blob/RCTBlobManager.mm b/Libraries/Blob/RCTBlobManager.mm index 8780d6b9e8c189..98dcb406926a8e 100755 --- a/Libraries/Blob/RCTBlobManager.mm +++ b/Libraries/Blob/RCTBlobManager.mm @@ -13,7 +13,9 @@ #import #import -static NSString *const kBlobUriScheme = @"blob"; +#import + +static NSString *const kBlobURIScheme = @"blob"; @interface RCTBlobManager () @@ -36,6 +38,8 @@ @implementation RCTBlobManager - (void)setBridge:(RCTBridge *)bridge { _bridge = bridge; + + std::lock_guard lock(_blobsMutex); _blobs = [NSMutableDictionary new]; } @@ -47,7 +51,7 @@ + (BOOL)requiresMainQueueSetup - (NSDictionary *)constantsToExport { return @{ - @"BLOB_URI_SCHEME": kBlobUriScheme, + @"BLOB_URI_SCHEME": kBlobURIScheme, @"BLOB_URI_HOST": [NSNull null], }; } @@ -179,7 +183,7 @@ - (void)remove:(NSString *)blobId - (BOOL)canHandleRequest:(NSURLRequest *)request { - return [request.URL.scheme caseInsensitiveCompare:kBlobUriScheme] == NSOrderedSame; + return [request.URL.scheme caseInsensitiveCompare:kBlobURIScheme] == NSOrderedSame; } - (id)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate diff --git a/Libraries/Network/XMLHttpRequest.js b/Libraries/Network/XMLHttpRequest.js index 1b086fdf21894a..082aaa8932fe23 100644 --- a/Libraries/Network/XMLHttpRequest.js +++ b/Libraries/Network/XMLHttpRequest.js @@ -256,7 +256,7 @@ class XMLHttpRequest extends EventTarget(...XHR_EVENTS) { if (typeof this._response === 'object' && this._response) { this._cachedResponse = BlobManager.createFromOptions(this._response); } else { - throw new Error('Invalid response for blob'); + throw new Error(`Invalid response for blob: ${this._response}`); } break; diff --git a/Libraries/Network/convertRequestBody.js b/Libraries/Network/convertRequestBody.js index 6dd9803fcdab94..9a826d46e2c603 100644 --- a/Libraries/Network/convertRequestBody.js +++ b/Libraries/Network/convertRequestBody.js @@ -8,6 +8,7 @@ * * @providesModule convertRequestBody * @flow + * @format */ 'use strict'; @@ -22,8 +23,7 @@ export type RequestBody = | FormData | {uri: string} | ArrayBuffer - | $ArrayBufferView - ; + | $ArrayBufferView; function convertRequestBody(body: RequestBody): Object { if (typeof body === 'string') { From 368b86ea2a4e8805d98e7010b5dc22ff140fc1bd Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 18 Jan 2018 00:59:31 -0500 Subject: [PATCH 51/66] Fix prettier --- Libraries/Blob/__tests__/Blob-test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 4aa058669678d0..3c63b31d6b3eef 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -31,8 +31,7 @@ describe('Blob', function() { const blobB = new Blob(); const textA = 'i ♥ dogs'; const textB = '𐀀'; - const textC = - 'Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘!͖̬̰̙̗̿̋ͥͥ̂ͣ̐́́͜͞'; + const textC = 'Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘!͖̬̰̙̗̿̋ͥͥ̂ͣ̐́́͜͞'; blobA.data.size = 34540; blobB.data.size = 65452; From 20cdd7ef85c7f04cd620dae7091ca8887a63e7d5 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 18 Jan 2018 16:47:56 -0500 Subject: [PATCH 52/66] Fix android build --- .../com/facebook/react/modules/network/NetworkingModule.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index dcea10fea939c3..f52b5b54c611f2 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -343,7 +343,6 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { } } - RequestBody requestBody; if (data == null) { requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { From 84953bf50a46a7bf3fd96453cb1256afdf12fefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 14:42:17 -0800 Subject: [PATCH 53/66] =?UTF-8?q?Replace=20=E2=99=A5=20with=20\u{2665}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source code should only include printable US-ASCII bytes. Use Unicode escapes like \u to represent non-US-ASCII values. --- .../java/com/facebook/react/modules/blob/BlobModuleTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java index a16a41372cf03d..21690b0063c957 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java @@ -125,7 +125,7 @@ public void testCreateFromParts() { blob.putMap("data", blobData); blob.putString("type", "blob"); - String stringData = "i ♥ dogs"; + String stringData = "i \u{2665} dogs"; byte[] stringBytes = stringData.getBytes(Charset.forName("UTF-8")); JavaOnlyMap string = new JavaOnlyMap(); string.putString("data", stringData); From ddcbc6471a56cd3d7354884585489d592277eb6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 14:43:08 -0800 Subject: [PATCH 54/66] Fix lint issue in BlobModuleTest.java Don't use @RunWith(RobolectricTestRunner.class) Use @RunWith(WithTestDefaultsRunner.class) instead --- .../java/com/facebook/react/modules/blob/BlobModuleTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java index 21690b0063c957..8b1e285369d9b1 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java @@ -42,7 +42,7 @@ import static org.junit.Assert.assertNull; @PrepareForTest({Arguments.class}) -@RunWith(RobolectricTestRunner.class) +@RunWith(WithTestDefaultsRunner.class) @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) @Config(manifest = Config.NONE) public class BlobModuleTest { From 4c7a928c7e85c8f6ddd9f8e151251607144894b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 14:44:21 -0800 Subject: [PATCH 55/66] Use correct unicode escapte --- .../java/com/facebook/react/modules/blob/BlobModuleTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java index 8b1e285369d9b1..a2cf6126203de3 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java @@ -125,7 +125,7 @@ public void testCreateFromParts() { blob.putMap("data", blobData); blob.putString("type", "blob"); - String stringData = "i \u{2665} dogs"; + String stringData = "i \u2665 dogs"; byte[] stringBytes = stringData.getBytes(Charset.forName("UTF-8")); JavaOnlyMap string = new JavaOnlyMap(); string.putString("data", stringData); From da1554047bccfe60a2de74baceacccdcd39d5259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 14:45:48 -0800 Subject: [PATCH 56/66] Use string literal escapes for unicode --- Libraries/Blob/__tests__/Blob-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 3c63b31d6b3eef..9eb76fda4318cd 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -29,9 +29,9 @@ describe('Blob', function() { it('should create blob from other blobs and strings', () => { const blobA = new Blob(); const blobB = new Blob(); - const textA = 'i ♥ dogs'; - const textB = '𐀀'; - const textC = 'Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘!͖̬̰̙̗̿̋ͥͥ̂ͣ̐́́͜͞'; + const textA = 'i \u2665 dogs'; + const textB = '\uD800\uDC00'; + const textC = 'Z\u0351\u036B\u0343\u036A\u0302\u036B\u033D\u034F\u0334\u0319\u0324\u031E\u0349\u035A\u032F\u031E\u0320\u034DA\u036B\u0357\u0334\u0362\u0335\u031C\u0330\u0354L\u0368\u0367\u0369\u0358\u0320G\u0311\u0357\u030E\u0305\u035B\u0341\u0334\u033B\u0348\u034D\u0354\u0339O\u0342\u030C\u030C\u0358\u0328\u0335\u0339\u033B\u031D\u0333!\u033F\u030B\u0365\u0365\u0302\u0363\u0310\u0301\u0301\u035E\u035C\u0356\u032C\u0330\u0319\u0317'; blobA.data.size = 34540; blobB.data.size = 65452; From 28d15003798166cd9c587145a339104ed1fb554b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 14:47:26 -0800 Subject: [PATCH 57/66] Update FileReaderModule.java Copyright header should be at the top --- .../java/com/facebook/react/modules/blob/FileReaderModule.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java index 2e550a239f9736..edab836af6b777 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/blob/FileReaderModule.java @@ -1,5 +1,3 @@ -package com.facebook.react.modules.blob; - /** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. @@ -9,6 +7,7 @@ * of patent rights can be found in the PATENTS file in the same directory. */ +package com.facebook.react.modules.blob; import android.util.Base64; From 00408ab235a8dbdd1c9933ec75894e077897c134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 14:49:30 -0800 Subject: [PATCH 58/66] Update RCTBlobManagerTests.m Source code should only include printable US-ASCII bytes. Use Unicode escapes like \u to represent non-US-ASCII values. --- RNTester/RNTesterUnitTests/RCTBlobManagerTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m b/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m index 0ee4a87e22dc0c..4b7fa64e516a1a 100644 --- a/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m +++ b/RNTester/RNTesterUnitTests/RCTBlobManagerTests.m @@ -82,7 +82,7 @@ - (void)testCreateFromParts @"data": blobData, @"type": @"blob", }; - NSString *stringData = @"i ♥ dogs"; + NSString *stringData = @"i \u2665 dogs"; NSDictionary *string = @{ @"data": stringData, @"type": @"string", From 236ed3faaa15c6084869e1b3c8b3e0d77f4d8dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 14:57:04 -0800 Subject: [PATCH 59/66] Update RCTBlobManager.mm - Imports out of order --- Libraries/Blob/RCTBlobManager.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Blob/RCTBlobManager.mm b/Libraries/Blob/RCTBlobManager.mm index 98dcb406926a8e..17569a4794b08e 100755 --- a/Libraries/Blob/RCTBlobManager.mm +++ b/Libraries/Blob/RCTBlobManager.mm @@ -10,8 +10,8 @@ #import "RCTBlobManager.h" #import -#import #import +#import #import From 35e0c1c4bc1a690258917b5ef758b1fdd05ad97f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 15:18:15 -0800 Subject: [PATCH 60/66] =?UTF-8?q?Insert=20=E2=8F=8E=C2=B7=C2=B7=C2=B7?= =?UTF-8?q?=C2=B7=C2=B7=20(prettier/prettier)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Libraries/Blob/__tests__/Blob-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 9eb76fda4318cd..43798a47a370d3 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -31,7 +31,8 @@ describe('Blob', function() { const blobB = new Blob(); const textA = 'i \u2665 dogs'; const textB = '\uD800\uDC00'; - const textC = 'Z\u0351\u036B\u0343\u036A\u0302\u036B\u033D\u034F\u0334\u0319\u0324\u031E\u0349\u035A\u032F\u031E\u0320\u034DA\u036B\u0357\u0334\u0362\u0335\u031C\u0330\u0354L\u0368\u0367\u0369\u0358\u0320G\u0311\u0357\u030E\u0305\u035B\u0341\u0334\u033B\u0348\u034D\u0354\u0339O\u0342\u030C\u030C\u0358\u0328\u0335\u0339\u033B\u031D\u0333!\u033F\u030B\u0365\u0365\u0302\u0363\u0310\u0301\u0301\u035E\u035C\u0356\u032C\u0330\u0319\u0317'; + const textC = + 'Z\u0351\u036B\u0343\u036A\u0302\u036B\u033D\u034F\u0334\u0319\u0324\u031E\u0349\u035A\u032F\u031E\u0320\u034DA\u036B\u0357\u0334\u0362\u0335\u031C\u0330\u0354L\u0368\u0367\u0369\u0358\u0320G\u0311\u0357\u030E\u0305\u035B\u0341\u0334\u033B\u0348\u034D\u0354\u0339O\u0342\u030C\u030C\u0358\u0328\u0335\u0339\u033B\u031D\u0333!\u033F\u030B\u0365\u0365\u0302\u0363\u0310\u0301\u0301\u035E\u035C\u0356\u032C\u0330\u0319\u0317'; blobA.data.size = 34540; blobB.data.size = 65452; From e2481c45861e284fa88c0cbfdfbdda616a5c1d30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 15:25:56 -0800 Subject: [PATCH 61/66] Update Blob-test.js --- Libraries/Blob/__tests__/Blob-test.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 43798a47a370d3..2c2f889c24e913 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -31,8 +31,14 @@ describe('Blob', function() { const blobB = new Blob(); const textA = 'i \u2665 dogs'; const textB = '\uD800\uDC00'; - const textC = - 'Z\u0351\u036B\u0343\u036A\u0302\u036B\u033D\u034F\u0334\u0319\u0324\u031E\u0349\u035A\u032F\u031E\u0320\u034DA\u036B\u0357\u0334\u0362\u0335\u031C\u0330\u0354L\u0368\u0367\u0369\u0358\u0320G\u0311\u0357\u030E\u0305\u035B\u0341\u0334\u033B\u0348\u034D\u0354\u0339O\u0342\u030C\u030C\u0358\u0328\u0335\u0339\u033B\u031D\u0333!\u033F\u030B\u0365\u0365\u0302\u0363\u0310\u0301\u0301\u035E\u035C\u0356\u032C\u0330\u0319\u0317'; + const textC = + "Z\u0351\u036B\u0343\u036A\u0302\u036B\u033D\u034F\u0334\u0319\u0324" + + "\u031E\u0349\u035A\u032F\u031E\u0320\u034DA\u036B\u0357\u0334\u0362" + + "\u0335\u031C\u0330\u0354L\u0368\u0367\u0369\u0358\u0320G\u0311\u0357" + + "\u030E\u0305\u035B\u0341\u0334\u033B\u0348\u034D\u0354\u0339O\u0342" + + "\u030C\u030C\u0358\u0328\u0335\u0339\u033B\u031D\u0333!\u033F\u030B" + + "\u0365\u0365\u0302\u0363\u0310\u0301\u0301\u035E\u035C\u0356\u032C" + + "\u0330\u0319\u0317"; blobA.data.size = 34540; blobB.data.size = 65452; From 5d215ce018f92f9dd27a7abad43a085da5d3c099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 15:27:05 -0800 Subject: [PATCH 62/66] Update Blob-test.js --- Libraries/Blob/__tests__/Blob-test.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 2c2f889c24e913..12fe0169e41613 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -32,13 +32,13 @@ describe('Blob', function() { const textA = 'i \u2665 dogs'; const textB = '\uD800\uDC00'; const textC = - "Z\u0351\u036B\u0343\u036A\u0302\u036B\u033D\u034F\u0334\u0319\u0324" + - "\u031E\u0349\u035A\u032F\u031E\u0320\u034DA\u036B\u0357\u0334\u0362" + - "\u0335\u031C\u0330\u0354L\u0368\u0367\u0369\u0358\u0320G\u0311\u0357" + - "\u030E\u0305\u035B\u0341\u0334\u033B\u0348\u034D\u0354\u0339O\u0342" + - "\u030C\u030C\u0358\u0328\u0335\u0339\u033B\u031D\u0333!\u033F\u030B" + - "\u0365\u0365\u0302\u0363\u0310\u0301\u0301\u035E\u035C\u0356\u032C" + - "\u0330\u0319\u0317"; + 'Z\u0351\u036B\u0343\u036A\u0302\u036B\u033D\u034F\u0334\u0319\u0324' + + '\u031E\u0349\u035A\u032F\u031E\u0320\u034DA\u036B\u0357\u0334\u0362' + + '\u0335\u031C\u0330\u0354L\u0368\u0367\u0369\u0358\u0320G\u0311\u0357' + + '\u030E\u0305\u035B\u0341\u0334\u033B\u0348\u034D\u0354\u0339O\u0342' + + '\u030C\u030C\u0358\u0328\u0335\u0339\u033B\u031D\u0333!\u033F\u030B' + + '\u0365\u0365\u0302\u0363\u0310\u0301\u0301\u035E\u035C\u0356\u032C' + + '\u0330\u0319\u0317'; blobA.data.size = 34540; blobB.data.size = 65452; From 5494fe99f4818e269e0e38a3b7603ca5cbda1ac2 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Thu, 18 Jan 2018 18:29:30 -0500 Subject: [PATCH 63/66] Add back missing handler code that was lost in merge --- .../com/facebook/react/modules/network/NetworkingModule.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java index f52b5b54c611f2..b94abebc0633c5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java @@ -345,6 +345,9 @@ public void onProgress(long bytesWritten, long contentLength, boolean done) { if (data == null) { requestBuilder.method(method, RequestBodyUtil.getEmptyBody(method)); + } else if (handler != null) { + RequestBody requestBody = handler.toRequestBody(data, contentType); + requestBuilder.method(method, requestBody); } else if (data.hasKey(REQUEST_BODY_KEY_STRING)) { if (contentType == null) { ResponseUtil.onRequestError( From ad568cff5768fb872faa504ea69be96ee0652324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= <165856+hramos@users.noreply.github.com> Date: Thu, 18 Jan 2018 15:37:47 -0800 Subject: [PATCH 64/66] Fix trailing whitespace on RCTBlobManager.mm (TXT6) Trailing Whitespace at line 30 This line contains trailing whitespace. Consider setting up your editor to automatically remove trailing whitespace, you will save time. Autofix (TXT6) Trailing Whitespace at line 101 This line contains trailing whitespace. Consider setting up your editor to automatically remove trailing whitespace, you will save time. Autofix (TXT6) Trailing Whitespace at line 105 This line contains trailing whitespace. Consider setting up your editor to automatically remove trailing whitespace, you will save time. Autofix (TXT6) Trailing Whitespace at line 116 This line contains trailing whitespace. Consider setting up your editor to automatically remove trailing whitespace, you will save time. Autofix (TXT6) Trailing Whitespace at line 241 This line contains trailing whitespace. Consider setting up your editor to automatically remove trailing whitespace, you will save time. Autofix (TXT6) Trailing Whitespace at line 247 This line contains trailing whitespace. Consider setting up your editor to automatically remove trailing whitespace, you will save time. Autofix (TXT6) Trailing Whitespace at line 277 This line contains trailing whitespace. Consider setting up your editor to automatically remove trailing whitespace, you will save time. Autofix (TXT9) Trailing Whitespace at EOF at line 287 --- Libraries/Blob/RCTBlobManager.mm | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Libraries/Blob/RCTBlobManager.mm b/Libraries/Blob/RCTBlobManager.mm index 17569a4794b08e..79c5657fd1c9ea 100755 --- a/Libraries/Blob/RCTBlobManager.mm +++ b/Libraries/Blob/RCTBlobManager.mm @@ -27,7 +27,7 @@ @implementation RCTBlobManager // make sure to use proper locking when accessing this. NSMutableDictionary *_blobs; std::mutex _blobsMutex; - + NSOperationQueue *_queue; } @@ -98,11 +98,11 @@ - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger) - (NSData *)resolveURL:(NSURL *)url { NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO]; - + NSString *blobId = components.path; NSInteger offset = 0; NSInteger size = -1; - + if (components.queryItems) { for (NSURLQueryItem *queryItem in components.queryItems) { if ([queryItem.name isEqualToString:@"offset"]) { @@ -113,7 +113,7 @@ - (NSData *)resolveURL:(NSURL *)url } } } - + if (blobId) { return [self resolve:blobId offset:offset size:size]; } @@ -238,13 +238,13 @@ - (BOOL)canHandleNetworkingRequest:(NSDictionary *)data - (NSDictionary *)handleNetworkingRequest:(NSDictionary *)data { NSDictionary *blob = [RCTConvert NSDictionary:data[@"blob"]]; - + NSString *contentType = @"application/octet-stream"; NSString *blobType = [RCTConvert NSString:blob[@"type"]]; if (blobType != nil && blobType.length > 0) { contentType = blob[@"type"]; } - + return @{@"body": [self resolve:blob], @"contentType": contentType}; } @@ -274,7 +274,7 @@ - (id)processWebsocketMessage:(id)message *type = @"text"; return message; } - + *type = @"blob"; return @{ @"blobId": [self store:message], @@ -284,4 +284,3 @@ - (id)processWebsocketMessage:(id)message } @end - From 2f15886f4dc17d8d3a3626b1d63d4a914d7203ed Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Mon, 22 Jan 2018 20:02:34 -0500 Subject: [PATCH 65/66] Import uuid from uuid/v4 to avoid conflict with internal fb haste module --- Libraries/Blob/BlobManager.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index a2131de9906a93..e30aa1c192c1c6 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -13,7 +13,7 @@ 'use strict'; -const uuid = require('uuid'); +const uuid = require('uuid/v4'); const Blob = require('Blob'); const BlobRegistry = require('BlobRegistry'); const {BlobModule} = require('NativeModules'); @@ -36,7 +36,7 @@ class BlobManager { parts: Array, options?: BlobOptions, ): Blob { - const blobId = uuid.v4(); + const blobId = uuid(); const items = parts.map(part => { if ( part instanceof ArrayBuffer || From d56239b2c937cc60b213c1eb3824fa458824927f Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Mon, 22 Jan 2018 22:03:12 -0500 Subject: [PATCH 66/66] Fix test runner --- .../java/com/facebook/react/modules/blob/BlobModuleTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java index a2cf6126203de3..4339dcd5e4b3db 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/modules/blob/BlobModuleTest.java @@ -42,7 +42,7 @@ import static org.junit.Assert.assertNull; @PrepareForTest({Arguments.class}) -@RunWith(WithTestDefaultsRunner.class) +@RunWith(RobolectricTestRunner.class) @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) @Config(manifest = Config.NONE) public class BlobModuleTest {