返回介绍

React Native 文件上传的客户端

发布于 2025-04-26 18:09:29 字数 10016 浏览 0 评论 0 收藏

创建一个项目:

react-native init TestSample

编辑生成的 index.ios.js 文件,代码如下:

index.ios.js



'use strict';
var React = require('react-native'); var{
  AppRegistry,
  TouchableHighlight,
  StyleSheet,
  Text,
View,
  NativeModules
} = React;
var TestSample = React.createClass({
  getInitialState: function(){
    return {
      status: ""
    }
  },
  onPress: function(){
    var obj = {
      uri: "data:http://example.com/banner.jpg",
      uploadUrl: "http://192.168.100.7:3000/api/photo",
      fileName: "banner.jpg",
      mimeType: "application/jpeg"
    };
    NativeModules.FileTransfer.upload(obj, (err, res) => {
      if (err ! = null){
        this.setState({status: err});
      }
      else {
        this.setState({status: "OK"});
      }
    })
  },
  render: function() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.ios.js
        </Text>
        <Text style={styles.instructions}>
          Press Cmd+R to reload, {'\n'} Cmd+D or shake for dev menu
        </Text>
        <TouchableHighlight onPress={this.onPress}>
          <Text style={styles.button}>Upload</Text>
        </TouchableHighlight>
        <Text>{this.state.status}</Text>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
  button: {
    color: '#123456',
    marginBottom: 5
  }
});

和原来的文件不一样的地方就是,添加了上传文件部分的代码:

onPress: function(){
  var obj = {
    uri: "data:http://example.com/banner.jpg",
    uploadUrl: "http://192.168.100.7:3000/api/photo",
    fileName: "banner.jpg",
    mimeType: "application/jpeg"
  };
  NativeModules.FileTransfer.upload(obj, (err, res) => {
    if (err ! = null){
      this.setState({status: err});
    } else {
      this.setState({status: "OK"});
    }
  })
}

如果需要上传一个远程文件,那就提供一个带有 uri 前缀的数据。阅读 RTCFileTransfer.m 文件,了解所有支持的上传文件前缀。

我们来创建 FileTransfer 的模块。它暴露出一个名为 upload 的方法。在 Xcode 中添加 RTCFile-Transfer.m 文件,步骤为:Your Project>Libraries>React>Base。

RTCFileTransfer.m



#import "RCTBridgeModule.h"
#import "RCTUtils.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <UIKit/UIKit.h>
@interface FileTransfer : NSObject <RCTBridgeModule>
- (NSMutableURLRequest *)getMultiPartRequest:(NSData *)data
    serverUrl:(NSString *)server requestData:(NSDictionary *)
    requestData mimeType:(NSString *)mimeType fileName:(NSString *)
    fileName;
- (void)uploadAssetsLibrary:(NSDictionary *)input callback:(
    RCTResponseSenderBlock)callback;
- (void)uploadUri:(NSDictionary *)input callback:(
    RCTResponseSenderBlock)callback;
- (void)uploadFile:(NSDictionary *)input callback:(
    RCTResponseSenderBlock)callback;
- (void)sendData:(NSData *)data withOptions:(NSDictionary *)input
    callback:(RCTResponseSenderBlock)callback;
@end

@implementation FileTransfer RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(upload:(NSDictionary *)input callback:(
    RCTResponseSenderBlock)callback)
{
NSString *uri = input[@"uri"]; if([uri hasPrefix:@"assets-library
    "]){
    [self uploadAssetsLibrary:input callback:callback];
  }
else if([uri hasPrefix:@"data:"]){
[self uploadUri:input callback:callback];
}
else if([uri hasPrefix:@"file:"]){
    [self uploadUri:input callback:callback];
  }
else if ([uri isAbsolutePath]) {
[self uploadFile:input callback:callback];
} else{
    callback(@[RCTMakeError(@"Unknown protocol for key: 'file'",
        nil, nil)]);
  }
}

- (void)uploadAssetsLibrary:(NSDictionary *)input callback:(
    RCTResponseSenderBlock)callback
{
  NSURL *assetUrl = [[NSURL alloc] initWithString:input[@"uri"]];
  ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
  [library assetForURL:assetUrl resultBlock:^(ALAsset *asset) {
    ALAssetRepresentation *rep = [asset defaultRepresentation];
    CGImageRef fullScreenImageRef = [rep fullScreenImage];
    UIImage *image = [UIImage imageWithCGImage:fullScreenImageRef];
    NSData *fileData = UIImagePNGRepresentation(image);
    [self sendData:fileData withOptions:input callback:callback];

    // Byte *buffer = (Byte*)malloc(rep.size);

    //     NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0
        length:rep.size error:nil];
    //
    //     NSData *fileData = [NSData dataWithBytesNoCopy:buffer
        length:buffered freeWhenDone:YES];
    // NSDictionary* requestData = [input objectForKey:@"data"];
    // NSMutableURLRequest* req = [self getMultiPartRequest:
        fileData serverUrl:uploadUrl requestData:requestData
        mimeType:mimeType fileName:fileName];
    //
    // NSHTTPURLResponse *response = nil;
    // NSData *returnData = [NSURLConnection sendSynchronousRequest
        :req returningResponse:&response error:nil];
    // NSInteger statusCode = [response statusCode];
    // NSString *returnString = [[NSString alloc] initWithData:
        returnData encoding:NSUTF8StringEncoding];
    //
    // NSDictionary *res=[[NSDictionary alloc]
        initWithObjectsAndKeys:[NSNumber numberWithInteger:
        statusCode], @"status", returnString, @"data", nil];
    //
    // callback(@[res]);
  } failureBlock:^(NSError *error) {
    callback(@[RCTMakeError(@"Error loading library asset", nil,
        nil)]);
}]; }

- (void)uploadFile:(NSDictionary *)input callback:(
    RCTResponseSenderBlock)callback
{
  NSString *filePath = input[@"uri"];
  NSData *fileData = [NSData dataWithContentsOfFile:filePath];

  [self sendData:fileData withOptions:input callback:callback];
}

- (void)uploadUri:(NSDictionary *)input callback:(
    RCTResponseSenderBlock)callback
{
  NSString *dataUrlString = input[@"uri"];
  NSURL *dataUrl = [[NSURL alloc] initWithString:dataUrlString];
  NSData *fileData = [NSData dataWithContentsOfURL: dataUrl];

  [self sendData:fileData withOptions:input callback:callback];
}

- (void)sendData:(NSData *)data withOptions:(NSDictionary *)input
    callback:(RCTResponseSenderBlock)callback
{
  NSString *fileName = input[@"fileName"];
  NSString *mimeType = input[@"mimeType"];
  NSString *uploadUrl = input[@"uploadUrl"];

  NSDictionary* requestData = [input objectForKey:@"data"];
  NSMutableURLRequest* req = [self getMultiPartRequest:data
      serverUrl:uploadUrl requestData:requestData mimeType:mimeType
      fileName:fileName];

  NSHTTPURLResponse *response = nil;
  NSData *returnData = [NSURLConnection sendSynchronousRequest:req
      returningResponse:&response error:nil];
  NSInteger statusCode = [response statusCode];
  NSString *returnString = [[NSString alloc] initWithData:
      returnData encoding:NSUTF8StringEncoding];

  NSDictionary *res=[[NSDictionary alloc] initWithObjectsAndKeys:[
      NSNumber numberWithInteger:statusCode], @"status", returnString,
      @"data", nil];

  callback(@[[NSNull null], res]);
}

- (NSMutableURLRequest *)getMultiPartRequest:(NSData *)data
    serverUrl:(NSString *)server requestData:(NSDictionary *)
    requestData mimeType:(NSString *)mimeType fileName:(NSString *)
    fileName
{
  NSString* fileKey = @"file";
  NSURL* url = [NSURL URLWithString:server];
  NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:
      url];
  [req setHTTPMethod:@"POST"];

  NSString* formBoundaryString = @"----react.file.transfer.form.
      boundary";

  NSString* contentType = [NSString stringWithFormat:@"multipart/
      form-data; boundary=%@", formBoundaryString];
  [req setValue:contentType forHTTPHeaderField:@"Content-Type"];

  NSData* formBoundaryData = [[NSString stringWithFormat:@"--%@\r\n
      ", formBoundaryString] dataUsingEncoding:NSUTF8StringEncoding
      ];
  NSMutableData* requestBody = [NSMutableData data];
  for (NSString* key in requestData) {
    id val = [requestData objectForKey:key];
    if ([val respondsToSelector:@selector(stringValue)]) {
      val = [val stringValue];
    }
    if (! [val isKindOfClass:[NSString class]]) {
      continue;
    }
    [requestBody appendData:formBoundaryData];
    [requestBody appendData:[[NSString stringWithFormat:@"Content-
        Disposition: form-data; name=\"%@\"\r\n\r\n", key]
        dataUsingEncoding:NSUTF8StringEncoding]];
    [requestBody appendData:[val dataUsingEncoding:
        NSUTF8StringEncoding]];
    [requestBody appendData:[@"\r\n" dataUsingEncoding :
        NSUTF8StringEncoding]];
  }
  [requestBody appendData:formBoundaryData];
  [requestBody appendData:[[NSString stringWithFormat:@"Content-
      Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",
      fileKey, fileName] dataUsingEncoding:NSUTF8StringEncoding]];
  if (mimeType ! = nil) {
    [requestBody appendData:[[NSString stringWithFormat:@"Content-
        Type: %@\r\n", mimeType] dataUsingEncoding:
        NSUTF8StringEncoding]];
  }
  [requestBody appendData:[[NSString stringWithFormat:@"Content-
      Length: %ld\r\n\r\n", (long)[data length]] dataUsingEncoding:
      NSUTF8StringEncoding]];

  NSData* afterFile = [[NSString stringWithFormat:@"\r\n--%@--\r\n
      ", formBoundaryString] dataUsingEncoding:NSUTF8StringEncoding
      ];

  long long totalPayloadLength = [requestBody length] + [data
      length] + [afterFile length];
  [req setValue:[[NSNumber numberWithLongLong:totalPayloadLength]
      stringValue] forHTTPHeaderField:@"Content-Length"];

  [requestBody appendData:data];
  [requestBody appendData:afterFile];
  [req setHTTPBody:requestBody];
  return req;
}

@end

程序运行后,当点击上传按钮上传图片后,可以在 Node.js 服务器的 uploads 文件夹下找到上传的 banner.jpg 文件。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。