├── LICENSE ├── RCTFileTransfer.m ├── README.md └── package.json /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Kamil Pękala 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /RCTFileTransfer.m: -------------------------------------------------------------------------------- 1 | // 2 | // RCTFileTransfer.m 3 | // react-native-file-transfer 4 | // 5 | // Created by Kamil Pękala on 30.04.2015 6 | // Copyright (c) 2015 Kamil Pękala. All rights reserved. 7 | // 8 | 9 | #import "RCTBridgeModule.h" 10 | #import "RCTUtils.h" 11 | #import 12 | #import 13 | 14 | @interface FileTransfer : NSObject 15 | - (NSMutableURLRequest *)getMultiPartRequest:(NSData *)data serverUrl:(NSString *)server requestData:(NSDictionary *)requestData requestHeaders:(NSDictionary *)requestHeaders mimeType:(NSString *)mimeType fileName:(NSString *)fileName fileKey:(NSString *)fileKey; 16 | - (void)uploadAssetsLibrary:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; 17 | - (void)uploadUri:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; 18 | - (void)uploadFile:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; 19 | - (void)sendData:(NSData *)data withOptions:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; 20 | @end 21 | 22 | @implementation FileTransfer 23 | 24 | RCT_EXPORT_MODULE(); 25 | 26 | RCT_EXPORT_METHOD(upload:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) 27 | { 28 | NSString *uri = input[@"uri"]; 29 | if([uri hasPrefix:@"assets-library"]){ 30 | [self uploadAssetsLibrary:input callback:callback]; 31 | } 32 | else if([uri hasPrefix:@"data:"]){ 33 | [self uploadUri:input callback:callback]; 34 | } 35 | else if([uri hasPrefix:@"file:"]){ 36 | [self uploadUri:input callback:callback]; 37 | } 38 | else if ([uri isAbsolutePath]) { 39 | [self uploadFile:input callback:callback]; 40 | } 41 | else{ 42 | callback(@[RCTMakeError(@"Unknown protocol for key: 'file'", nil, nil)]); 43 | } 44 | } 45 | 46 | - (void)uploadAssetsLibrary:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback 47 | { 48 | 49 | NSURL *assetUrl = [[NSURL alloc] initWithString:input[@"uri"]]; 50 | ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 51 | [library assetForURL:assetUrl resultBlock:^(ALAsset *asset) { 52 | 53 | ALAssetRepresentation *rep = [asset defaultRepresentation]; 54 | 55 | CGImageRef fullScreenImageRef = [rep fullScreenImage]; 56 | UIImage *image = [UIImage imageWithCGImage:fullScreenImageRef]; 57 | NSData *fileData = UIImagePNGRepresentation(image); 58 | 59 | [self sendData:fileData withOptions:input callback:callback]; 60 | 61 | // Byte *buffer = (Byte*)malloc(rep.size); 62 | // NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil]; 63 | // 64 | // NSData *fileData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES]; 65 | // NSDictionary* requestData = [input objectForKey:@"data"]; 66 | // NSMutableURLRequest* req = [self getMultiPartRequest:fileData serverUrl:uploadUrl requestData:requestData mimeType:mimeType fileName:fileName]; 67 | // 68 | // NSHTTPURLResponse *response = nil; 69 | // NSData *returnData = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:nil]; 70 | // NSInteger statusCode = [response statusCode]; 71 | // NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; 72 | // 73 | // NSDictionary *res=[[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInteger:statusCode],@"status",returnString,@"data",nil]; 74 | // 75 | // callback(@[res]); 76 | } failureBlock:^(NSError *error) { 77 | callback(@[RCTMakeError(@"Error loading library asset", nil, nil)]); 78 | }]; 79 | } 80 | 81 | - (void)uploadFile:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback 82 | { 83 | NSString *filePath = input[@"uri"]; 84 | NSData *fileData = [NSData dataWithContentsOfFile:filePath]; 85 | 86 | [self sendData:fileData withOptions:input callback:callback]; 87 | } 88 | 89 | - (void)uploadUri:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback 90 | { 91 | NSString *dataUrlString = input[@"uri"]; 92 | NSURL *dataUrl = [[NSURL alloc] initWithString:dataUrlString]; 93 | NSData *fileData = [NSData dataWithContentsOfURL: dataUrl]; 94 | 95 | [self sendData:fileData withOptions:input callback:callback]; 96 | } 97 | 98 | - (void)sendData:(NSData *)data withOptions:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback 99 | { 100 | NSString *fileName = input[@"fileName"]; 101 | NSString *mimeType = input[@"mimeType"]; 102 | NSString *uploadUrl = input[@"uploadUrl"]; 103 | NSString *fileKey = input[@"fileKey"]; 104 | 105 | if (!fileKey) fileKey = @"file"; 106 | 107 | NSDictionary* requestData = [input objectForKey:@"data"]; 108 | NSDictionary* requestHeaders = [input objectForKey:@"headers"]; 109 | NSMutableURLRequest* req = [self getMultiPartRequest:data serverUrl:uploadUrl requestData:requestData requestHeaders:requestHeaders mimeType:mimeType fileName:fileName fileKey:fileKey]; 110 | 111 | NSHTTPURLResponse *response = nil; 112 | NSData *returnData = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:nil]; 113 | NSInteger statusCode = [response statusCode]; 114 | NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding]; 115 | 116 | NSDictionary *res=[[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInteger:statusCode],@"status",returnString,@"data",nil]; 117 | 118 | callback(@[[NSNull null], res]); 119 | } 120 | 121 | - (NSMutableURLRequest *)getMultiPartRequest:(NSData *)data serverUrl:(NSString *)server requestData:(NSDictionary *)requestData requestHeaders:(NSDictionary *)requestHeaders mimeType:(NSString *)mimeType fileName:(NSString *)fileName fileKey:(NSString *)fileKey 122 | { 123 | NSURL* url = [NSURL URLWithString:server]; 124 | NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; 125 | 126 | [req setHTTPMethod:@"POST"]; 127 | 128 | NSString* formBoundaryString = @"----react.file.transfer.form.boundary"; 129 | 130 | NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", formBoundaryString]; 131 | [req setValue:contentType forHTTPHeaderField:@"Content-Type"]; 132 | 133 | NSData* formBoundaryData = [[NSString stringWithFormat:@"--%@\r\n", formBoundaryString] dataUsingEncoding:NSUTF8StringEncoding]; 134 | NSMutableData* requestBody = [NSMutableData data]; 135 | 136 | for (NSString* key in requestHeaders) { 137 | id val = [requestHeaders objectForKey:key]; 138 | if ([val respondsToSelector:@selector(stringValue)]) { 139 | val = [val stringValue]; 140 | } 141 | if (![val isKindOfClass:[NSString class]]) { 142 | continue; 143 | } 144 | 145 | [req setValue:val forHTTPHeaderField:key]; 146 | } 147 | 148 | for (NSString* key in requestData) { 149 | id val = [requestData objectForKey:key]; 150 | if ([val respondsToSelector:@selector(stringValue)]) { 151 | val = [val stringValue]; 152 | } 153 | 154 | if (![val isKindOfClass:[NSString class]]) { 155 | NSError *error; 156 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:val 157 | options:(NSJSONWritingOptions)0 158 | error:&error]; 159 | val = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; 160 | } 161 | 162 | [requestBody appendData:formBoundaryData]; 163 | [requestBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; 164 | [requestBody appendData:[val dataUsingEncoding:NSUTF8StringEncoding]]; 165 | [requestBody appendData:[@"\r\n" dataUsingEncoding : NSUTF8StringEncoding]]; 166 | } 167 | 168 | [requestBody appendData:formBoundaryData]; 169 | [requestBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fileKey, fileName] dataUsingEncoding:NSUTF8StringEncoding]]; 170 | if (mimeType != nil) { 171 | [requestBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n", mimeType] dataUsingEncoding:NSUTF8StringEncoding]]; 172 | } 173 | [requestBody appendData:[[NSString stringWithFormat:@"Content-Length: %ld\r\n\r\n", (long)[data length]] dataUsingEncoding:NSUTF8StringEncoding]]; 174 | 175 | NSData* afterFile = [[NSString stringWithFormat:@"\r\n--%@--\r\n", formBoundaryString] dataUsingEncoding:NSUTF8StringEncoding]; 176 | 177 | long long totalPayloadLength = [requestBody length] + [data length] + [afterFile length]; 178 | [req setValue:[[NSNumber numberWithLongLong:totalPayloadLength] stringValue] forHTTPHeaderField:@"Content-Length"]; 179 | 180 | [requestBody appendData:data]; 181 | [requestBody appendData:afterFile]; 182 | [req setHTTPBody:requestBody]; 183 | return req; 184 | } 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-file-transfer [![npm version](https://badge.fury.io/js/react-native-file-transfer.svg)](http://badge.fury.io/js/react-native-file-transfer) 2 | This little plugin lets you easily upload files from your photo library to a web server using a standard `multipart/form-data` POST request. It **does not** incorporate the tranfer of photo library images data from Objective-C to JavaScript (which is slow). The request are being made directly from Objective-C. 3 | # installation 4 | 1. `npm install react-native-file-transfer`; 5 | 2. In xcode: Add `RTCFileTransfer.m` in `Your Project > Libraries > React > Base`. 6 | 7 | # how to use it 8 | When you properly add the `RCTFileTransfer.m` file to your xcode project you may now use it in the js files. Example usage: 9 | ```javascript 10 | var { NativeModules } = require('react-native'); 11 | var obj = { 12 | uri, // either an 'assets-library' url (for files from photo library) or an image dataURL 13 | uploadUrl, 14 | fileName, 15 | fileKey, // (default="file") the name of the field in the POST form data under which to store the file 16 | mimeType, 17 | headers, 18 | data: { 19 | // whatever properties you wish to send in the request 20 | // along with the uploaded file 21 | } 22 | }; 23 | NativeModules.FileTransfer.upload(obj, (err, res) => { 24 | // handle response 25 | // it is an object with 'status' and 'data' properties 26 | // if the file path protocol is not supported the status will be 0 27 | // and the request won't be made at all 28 | }); 29 | ``` 30 | **pull-requests welcome** 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-file-transfer", 3 | "version": "0.0.3", 4 | "description": "react-native plugin for uploading files with multipart/form-data requests", 5 | "homepage": "https://github.com/kamilkp/react-native-file-transfer", 6 | "author": { 7 | "name": "Kamil Pekala", 8 | "email": "kamilkp@gmail.com", 9 | "url": "http://github.com/kamilkp" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/kamilkp/react-native-file-transfer.git" 14 | }, 15 | "devDependencies": {}, 16 | "scripts": {}, 17 | "dependencies": {} 18 | } 19 | --------------------------------------------------------------------------------