Skip to content
This repository was archived by the owner on Mar 16, 2019. It is now read-only.

Commit 17f2ab9

Browse files
committed
Add IOS implementation for #43
1 parent 5137b16 commit 17f2ab9

File tree

3 files changed

+200
-32
lines changed

3 files changed

+200
-32
lines changed

src/ios/RNFetchBlob/RNFetchBlob.m

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -236,16 +236,13 @@ - (NSDictionary *)constantsToExport
236236

237237
}
238238

239-
RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize) {
240-
RNFetchBlobFS *fileStream = [[RNFetchBlobFS alloc] initWithBridgeRef:self.bridge];
241-
if(bufferSize == nil) {
242-
if([[encoding lowercaseString] isEqualToString:@"base64"])
243-
bufferSize = 4095;
244-
else
245-
bufferSize = 4096;
246-
}
247-
[fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
248-
}
239+
RCT_EXPORT_METHOD(writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
240+
[RNFetchBlobFS writeFile:path encoding:encoding data:data append:append resolver:resolve rejecter:reject];
241+
})
242+
243+
RCT_EXPORT_METHOD(writeFileArray:(NSString *)path data:(NSArray *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
244+
[RNFetchBlobFS writeFileArray:path data:data append:append resolver:resolve rejecter:reject];
245+
})
249246

250247
RCT_EXPORT_METHOD(writeStream:(NSString *)path withEncoding:(NSString *)encoding appendData:(BOOL)append callback:(RCTResponseSenderBlock)callback) {
251248
RNFetchBlobFS * fileStream = [[RNFetchBlobFS alloc] initWithBridgeRef:self.bridge];
@@ -412,16 +409,29 @@ - (NSDictionary *)constantsToExport
412409
}
413410

414411
RCT_EXPORT_METHOD(readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
412+
415413
[RNFetchBlobFS readFile:path encoding:encoding resolver:resolve rejecter:reject];
416414
})
417415

418-
RCT_EXPORT_METHOD(writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
419-
[RNFetchBlobFS writeFile:path encoding:encoding data:data append:append resolver:resolve rejecter:reject];
420-
})
421-
422-
RCT_EXPORT_METHOD(writeFileArray:(NSString *)path data:(NSArray *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
423-
[RNFetchBlobFS writeFileArray:path data:data append:append resolver:resolve rejecter:reject];
424-
})
416+
RCT_EXPORT_METHOD(readStream:(NSString *)path withEncoding:(NSString *)encoding bufferSize:(int)bufferSize) {
417+
418+
RNFetchBlobFS *fileStream = [[RNFetchBlobFS alloc] initWithBridgeRef:self.bridge];
419+
if(bufferSize == nil) {
420+
if([[encoding lowercaseString] isEqualToString:@"base64"])
421+
bufferSize = 4095;
422+
else
423+
bufferSize = 4096;
424+
}
425+
// read asset stream
426+
if([path hasPrefix:@"assets-library://"])
427+
{
428+
429+
}
430+
else
431+
{
432+
[fileStream readWithPath:path useEncoding:encoding bufferSize:bufferSize];
433+
}
434+
}
425435

426436
RCT_EXPORT_METHOD(getEnvironmentDirs:(RCTResponseSenderBlock) callback) {
427437

src/ios/RNFetchBlobFS.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
+ (void) writeFileArray:(NSString *)path data:(NSArray *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
5252
+ (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
5353
+ (void) readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject;
54+
+ (void) readAssetFile:(NSData *)assetUrl completionBlock:(void(^)(NSData * content))completionBlock failBlock:(void(^)(NSError * err))failBlock;
55+
+ (NSString *) getPathOfAsset:(NSString *)assetURI;
5456

5557
// constructor
5658
- (id) init;
@@ -61,6 +63,7 @@
6163
- (void) openWithDestination;
6264
- (void) openWithId;
6365
- (NSString *)openWithPath:(NSString *)destPath encode:(nullable NSString *)encode appendData:(BOOL)append;
66+
- (void) startAssetReadStream:(NSData *)assetUrl;
6467

6568
// file stream write data
6669
- (void)write:(NSData *) chunk;

src/ios/RNFetchBlobFS.m

Lines changed: 170 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#import "RCTEventDispatcher.h"
1515
#import "RNFetchBlobFS.h"
1616
#import "RNFetchBlobConst.h"
17+
@import AssetsLibrary;
1718

1819
NSMutableDictionary *fileStreams = nil;
1920

@@ -49,6 +50,18 @@ +(void) setFileStream:(RNFetchBlobFS *) instance withId:(NSString *) uuid {
4950
[fileStreams setValue:instance forKey:uuid];
5051
}
5152

53+
+(NSString *) getPathOfAsset:(NSString *)assetURI
54+
{
55+
// get file path of an app asset
56+
if([assetURI hasPrefix:@"bundle-assets://"])
57+
{
58+
assetURI = [assetURI stringByReplacingOccurrencesOfString:@"bundle-assets://" withString:@""];
59+
assetURI = [[NSBundle mainBundle] pathForResource: [assetURI stringByDeletingPathExtension]
60+
ofType: [assetURI pathExtension]];
61+
}
62+
return assetURI;
63+
}
64+
5265
+ (NSString *) getCacheDir {
5366
return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
5467
}
@@ -84,6 +97,121 @@ + (NSString *) getTempPath:(NSString*)taskId withExtension:(NSString *)ext {
8497
return tempPath;
8598
}
8699

100+
- (void) startAssetReadStream:(NSData *)assetUrl
101+
{
102+
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
103+
{
104+
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
105+
dispatch_async(queue, ^ {
106+
NSString * streamEventCode = [NSString stringWithFormat:@"RNFetchBlobStream+%@", self.path];
107+
ALAssetRepresentation *rep = [myasset defaultRepresentation];
108+
Byte *buffer = (Byte*)malloc(self.bufferSize);
109+
NSUInteger cursor = [rep getBytes:buffer fromOffset:0 length:self.bufferSize error:nil];
110+
while(cursor > 0)
111+
{
112+
cursor += [rep getBytes:buffer fromOffset:cursor length:self.bufferSize error:nil];
113+
NSData * chunkData = [NSData dataWithBytes:buffer length:self.bufferSize];
114+
NSString * encodedChunk = @"";
115+
// emit data
116+
if( [[self.encoding lowercaseString] isEqualToString:@"utf8"] ) {
117+
encodedChunk = [encodedChunk initWithData:chunkData encoding:NSUTF8StringEncoding];
118+
}
119+
// when encoding is ASCII, send byte array data
120+
else if ( [[self.encoding lowercaseString] isEqualToString:@"ascii"] ) {
121+
// RCTBridge only emits string data, so we have to create JSON byte array string
122+
NSMutableArray * asciiArray = [NSMutableArray array];
123+
unsigned char *bytePtr;
124+
if (chunkData.length > 0)
125+
{
126+
bytePtr = (unsigned char *)[chunkData bytes];
127+
NSInteger byteLen = chunkData.length/sizeof(uint8_t);
128+
for (int i = 0; i < byteLen; i++)
129+
{
130+
[asciiArray addObject:[NSNumber numberWithChar:bytePtr[i]]];
131+
}
132+
}
133+
134+
[self.bridge.eventDispatcher
135+
sendDeviceEventWithName:streamEventCode
136+
body: @{
137+
@"event": FS_EVENT_DATA,
138+
@"detail": asciiArray
139+
}
140+
];
141+
return;
142+
}
143+
// convert byte array to base64 data chunks
144+
else if ( [[self.encoding lowercaseString] isEqualToString:@"base64"] ) {
145+
encodedChunk = [chunkData base64EncodedStringWithOptions:0];
146+
}
147+
// unknown encoding, send error event
148+
else {
149+
[self.bridge.eventDispatcher
150+
sendDeviceEventWithName:streamEventCode
151+
body:@{
152+
@"event": FS_EVENT_ERROR,
153+
@"detail": @"unrecognized encoding"
154+
}
155+
];
156+
return;
157+
}
158+
159+
[self.bridge.eventDispatcher
160+
sendDeviceEventWithName:streamEventCode
161+
body:@{
162+
@"event": FS_EVENT_DATA,
163+
@"detail": encodedChunk
164+
}
165+
];
166+
}
167+
free(buffer);
168+
});
169+
170+
};
171+
172+
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *error)
173+
{
174+
175+
};
176+
177+
if(assetUrl && [assetUrl length])
178+
{
179+
NSURL *asseturl = [NSURL URLWithString:assetUrl];
180+
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
181+
[assetslibrary assetForURL:asseturl
182+
resultBlock:resultblock
183+
failureBlock:failureblock];
184+
}
185+
}
186+
187+
// read system asset file
188+
+ (void) readAssetFile:(NSData *)assetUrl completionBlock:(void(^)(NSData * content))completionBlock failBlock:(void(^)(NSError * err))failBlock
189+
{
190+
191+
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
192+
{
193+
ALAssetRepresentation *rep = [myasset defaultRepresentation];
194+
Byte *buffer = (Byte*)malloc(rep.size);
195+
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
196+
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
197+
completionBlock(data);
198+
};
199+
200+
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *error)
201+
{
202+
failBlock(error);
203+
};
204+
205+
if(assetUrl && [assetUrl length])
206+
{
207+
NSURL *asseturl = [NSURL URLWithString:assetUrl];
208+
ALAssetsLibrary* assetslibrary = [[ALAssetsLibrary alloc] init];
209+
[assetslibrary assetForURL:asseturl
210+
resultBlock:resultblock
211+
failureBlock:failureblock];
212+
}
213+
}
214+
87215
+ (void) writeFile:(NSString *)path encoding:(NSString *)encoding data:(NSString *)data append:(BOOL)append resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
88216
@try {
89217
NSFileManager * fm = [NSFileManager defaultManager];
@@ -175,6 +303,37 @@ + (void) writeFileArray:(NSString *)path data:(NSArray *)data append:(BOOL)appen
175303
+ (void) readFile:(NSString *)path encoding:(NSString *)encoding resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
176304
@try
177305
{
306+
// before start reading file, we have to check if the `path` contains any special prefix
307+
// if the `path` begins with the following prefix then it will need special handling.
308+
// "assets-library://" this kind of path usually comes from camera roll, should use it's own readFile implementation
309+
// "bundle-assets://" this means an asset inside app bundle, usually we only have to convert it into normal file path
310+
if([path hasPrefix:@"assets-library://"])
311+
{
312+
[[self class] readAssetFile:path completionBlock:^(NSData * content)
313+
{
314+
if([[encoding lowercaseString] isEqualToString:@"utf8"]) {
315+
resolve([[NSString alloc] initWithData:content encoding:NSUTF8StringEncoding]);
316+
}
317+
else if ([[encoding lowercaseString] isEqualToString:@"base64"]) {
318+
resolve([content base64EncodedStringWithOptions:0]);
319+
}
320+
else if ([[encoding lowercaseString] isEqualToString:@"ascii"]) {
321+
NSMutableArray * resultArray = [NSMutableArray array];
322+
char * bytes = [content bytes];
323+
for(int i=0;i<[content length];i++) {
324+
[resultArray addObject:[NSNumber numberWithChar:bytes[i]]];
325+
}
326+
resolve(resultArray);
327+
}
328+
} failBlock:^(NSError *err) {
329+
@throw @"RNFetchBlobFS readFile error", @"failed to read asset", path;
330+
}];
331+
return ;
332+
}
333+
334+
// normalize the file path
335+
path = [[self class]getPathOfAsset:path];
336+
178337
NSFileManager * fm = [NSFileManager defaultManager];
179338
NSError *err = nil;
180339
BOOL exists = [fm fileExistsAtPath:path];
@@ -325,7 +484,16 @@ - (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding bufferSiz
325484
self.encoding = encoding;
326485
self.path = path;
327486
self.bufferSize = bufferSize;
328-
487+
488+
if([path hasPrefix:@"assets-library://"])
489+
{
490+
491+
return;
492+
}
493+
494+
// normalize file path
495+
path = [[self class] getPathOfAsset:path];
496+
329497
// NSStream needs a runloop so let's create a run loop for it
330498
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
331499
// start NSStream is a runloop
@@ -334,7 +502,7 @@ - (void)readWithPath:(NSString *)path useEncoding:(NSString *)encoding bufferSiz
334502
forMode:NSDefaultRunLoopMode];
335503
[inStream open];
336504
[[NSRunLoop currentRunLoop] run];
337-
505+
338506
});
339507
}
340508

@@ -349,19 +517,6 @@ - (void)closeInStream {
349517

350518
}
351519

352-
void runOnMainQueueWithoutDeadlocking(void (^block)(void))
353-
{
354-
if ([NSThread isMainThread])
355-
{
356-
block();
357-
}
358-
else
359-
{
360-
dispatch_sync(dispatch_get_main_queue(), block);
361-
}
362-
}
363-
364-
365520
#pragma mark RNFetchBlobFS read stream delegate
366521

367522
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {

0 commit comments

Comments
 (0)