Skip to content

Commit e8e092c

Browse files
authored
Merge branch 'master' into dev
2 parents a378a71 + e3456ef commit e8e092c

File tree

9 files changed

+117
-37
lines changed

9 files changed

+117
-37
lines changed

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## Changes for v2.17
4+
5+
- #938 Manually flush & invalidate session upon completion
6+
- #954 Switch to using channels for byte copying.
7+
- #962 Size limit with copyAssetsVideoIOS
8+
- #963 Add basic support for Android content URIs in stat
9+
- #972 Manually flush & invalidate completed session
10+
- #974 Add content for copyAssetsFileIOS method
11+
- #975 Fix copyAssetsFileIOS's image resizing option to resize to exact width and height
12+
- #985 README.md: clarify usage of readFileRes
13+
- #986 macOS support
14+
315
## Changes for v2.16
416
- #797 Added path to the Android download folder
517
- #842 Fixes #811 Concurrent downloads send progress updates to all progress callbacks

Downloader.m

+12-1
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,22 @@ - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTas
128128
NSLog(@"RNFS download: unable to move tempfile to destination. %@, %@", error, error.userInfo);
129129
}
130130

131+
// When numerous downloads are called the sessions are not always invalidated and cleared by iOS14.
132+
// This leads to error 28 – no space left on device so we manually flush and invalidate to free up space
133+
if(session != nil){
134+
[session flushWithCompletionHandler:^{
135+
[session finishTasksAndInvalidate];
136+
}];
137+
}
138+
131139
return _params.completeCallback(_statusCode, _bytesWritten);
132140
}
133141

134142
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
135143
{
136-
if (error && error.code != NSURLErrorCancelled) {
144+
if (error) {
145+
NSLog(@"RNFS download: didCompleteWithError %@, %@", error, error.userInfo);
146+
if (error.code != NSURLErrorCancelled) {
137147
_resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
138148
if (_resumeData != nil) {
139149
if (_params.resumableCallback) {
@@ -142,6 +152,7 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didComp
142152
} else {
143153
_params.errorCallback(error);
144154
}
155+
}
145156
}
146157
}
147158

README.md

+49-12
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ For RN >= 0.61 please install react-native-fs at version >= @2.16.0!
2525

2626
View the changelog [here](https://github.com/itinance/react-native-fs/blob/master/CHANGELOG.md).
2727

28-
## Usage (iOS)
28+
## Usage (iOS/macOS)
2929

3030
First you need to install react-native-fs:
3131

@@ -408,7 +408,7 @@ Note: Android only.
408408

409409
### `readFileRes(filename:string, encoding?: string): Promise<string>`
410410

411-
Reads the file named `filename` in the Android app's res folder and return contents. `res/drawable` is used as the parent folder for image files, `res/raw` for everything else. `encoding` can be one of `utf8` (default), `ascii`, `base64`. Use `base64` for reading binary files.
411+
Reads the file named `filename` in the Android app's `res` folder and return contents. Only the file name (not folder) needs to be specified. The file type will be detected from the extension and automatically located within `res/drawable` (for image files) or `res/raw` (for everything else). `encoding` can be one of `utf8` (default), `ascii`, `base64`. Use `base64` for reading binary files.
412412

413413
Note: Android only.
414414

@@ -454,16 +454,52 @@ Copies the file named `filename` in the Android app's res folder and copies it t
454454

455455
Note: Android only. Will overwrite destPath if it already exists.
456456

457-
### `copyAssetsFileIOS(imageUri: string, destPath: string, width: number, height: number, scale : number = 1.0, compression : number = 1.0, resizeMode : string = 'contain' ): Promise<string>`
457+
### (iOS only) `copyAssetsFileIOS(imageUri: string, destPath: string, width: number, height: number, scale?: number, compression?: number, resizeMode?: string): Promise<string>`
458458

459-
iOS-only (not available on Mac Catalyst): copies a file from camera-roll, that is prefixed with "assets-library://asset/asset.JPG?..."
460-
to a specific destination. It will download the original from iCloud if necessary.
459+
*Not available on Mac Catalyst.*
461460

462-
If width and height is > 0, the image will be resized to a specific size and a specific compression rate.
463-
If scale is below 1, the image will be scaled according to the scale-factor (between 0.0 and 1.0)
464-
The resizeMode is also considered.
461+
Reads an image file from Camera Roll and writes to `destPath`. This method [assumes the image file to be JPEG file](https://github.com/itinance/react-native-fs/blob/f2f8f4a058cd9acfbcac3b8cf1e08fa1e9b09786/RNFSManager.m#L752-L753). This method will download the original from iCloud if necessary.
465462

466-
*Video-Support:*
463+
#### Parameters
464+
465+
##### `imageUri` string (required)
466+
467+
URI of a file in Camera Roll. Can be [either of the following formats](https://github.com/itinance/react-native-fs/blob/f2f8f4a058cd9acfbcac3b8cf1e08fa1e9b09786/RNFSManager.m#L781-L785):
468+
469+
- `ph://CC95F08C-88C3-4012-9D6D-64A413D254B3/L0/001`
470+
- `assets-library://asset/asset.JPG?id=CC95F08C-88C3-4012-9D6D-64A413D254B3&ext=JPG`
471+
472+
##### `destPath` string (required)
473+
474+
Destination to which the copied file will be saved, e.g. `RNFS.TemporaryDirectoryPath + 'example.jpg'`.
475+
476+
##### `width` number (required)
477+
478+
Copied file's image width will be resized to `width`. [If 0 is provided, width won't be resized.](https://github.com/itinance/react-native-fs/blob/f2f8f4a058cd9acfbcac3b8cf1e08fa1e9b09786/RNFSManager.m#L808)
479+
480+
##### `height` number (required)
481+
482+
Copied file's image height will be resized to `height`. [If 0 is provided, height won't be resized.](https://github.com/itinance/react-native-fs/blob/f2f8f4a058cd9acfbcac3b8cf1e08fa1e9b09786/RNFSManager.m#L808)
483+
484+
##### `scale` number (optional)
485+
486+
Copied file's image will be scaled proportional to `scale` factor from `width` x `height`. If both `width` and `height` are 0, the image won't scale. Range is [0.0, 1.0] and default is 1.0.
487+
488+
##### `compression` number (optional)
489+
490+
Quality of copied file's image. The value 0.0 represents the maximum compression (or lowest quality) while the value 1.0 represents the least compression (or best quality). Range is [0.0, 1.0] and default is 1.0.
491+
492+
##### `resizeMode` string (optional)
493+
494+
If `resizeMode` is 'contain', copied file's image will be scaled so that its larger dimension fits `width` x `height`. If `resizeMode` is other value than 'contain', the image will be scaled so that it completely fills `width` x `height`. Default is 'contain'. Refer to [PHImageContentMode](https://developer.apple.com/documentation/photokit/phimagecontentmode).
495+
496+
#### Return value
497+
498+
##### `Promise<string>`
499+
500+
Copied file's URI.
501+
502+
#### Video-Support
467503

468504
One can use this method also to create a thumbNail from a video in a specific size.
469505
Currently it is impossible to specify a concrete position, the OS will decide wich
@@ -473,10 +509,11 @@ To copy a video from assets-library and save it as a mp4-file, refer to copyAsse
473509
Further information: https://developer.apple.com/reference/photos/phimagemanager/1616964-requestimageforasset
474510
The promise will on success return the final destination of the file, as it was defined in the destPath-parameter.
475511

476-
### copyAssetsVideoIOS(videoUri: string, destPath: string): Promise<string>
512+
### (iOS only) `copyAssetsVideoIOS(videoUri: string, destPath: string): Promise<string>`
513+
514+
*Not available on Mac Catalyst.*
477515

478-
iOS-only (not available on Mac Catalyst): copies a video from assets-library, that is prefixed with 'assets-library://asset/asset.MOV?...'
479-
to a specific destination.
516+
Copies a video from assets-library, that is prefixed with 'assets-library://asset/asset.MOV?...' to a specific destination.
480517

481518
### `unlink(filepath: string): Promise<void>`
482519

RNFS.podspec

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Pod::Spec.new do |s|
1212

1313
s.ios.deployment_target = '8.0'
1414
s.tvos.deployment_target = '9.2'
15+
s.osx.deployment_target = '10.10'
1516

1617
s.source = { :git => "https://github.com/itinance/react-native-fs", :tag => "v#{s.version}" }
1718
s.source_files = '*.{h,m}'

RNFSManager.m

+13-7
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,7 @@ + (BOOL)requiresMainQueueSetup
747747

748748

749749
// [PHAsset fetchAssetsWithALAssetURLs] is deprecated and not supported in Mac Catalyst
750-
#if !TARGET_OS_UIKITFORMAC
750+
#if !TARGET_OS_UIKITFORMAC && !TARGET_OS_OSX
751751
/**
752752
* iOS Only: copy images from the assets-library (camera-roll) to a specific path, asuming
753753
* JPEG-Images.
@@ -812,7 +812,7 @@ + (BOOL)requiresMainQueueSetup
812812
imageOptions.resizeMode = PHImageRequestOptionsResizeModeNone;
813813
} else {
814814
targetSize = CGSizeApplyAffineTransform(size, CGAffineTransformMakeScale(scale, scale));
815-
imageOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
815+
imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
816816
}
817817

818818
PHImageContentMode contentMode = PHImageContentModeAspectFill;
@@ -844,7 +844,7 @@ + (BOOL)requiresMainQueueSetup
844844
#endif
845845

846846
// [PHAsset fetchAssetsWithALAssetURLs] is deprecated and not supported in Mac Catalyst
847-
#if !TARGET_OS_UIKITFORMAC
847+
#if !TARGET_OS_UIKITFORMAC && !TARGET_OS_OSX
848848
/**
849849
* iOS Only: copy videos from the assets-library (camera-roll) to a specific path as mp4-file.
850850
*
@@ -882,10 +882,16 @@ + (BOOL)requiresMainQueueSetup
882882
if ([asset isKindOfClass:[AVURLAsset class]]) {
883883
NSURL *url = [(AVURLAsset *)asset URL];
884884
NSLog(@"Final URL %@",url);
885-
NSData *videoData = [NSData dataWithContentsOfURL:url];
886-
887-
BOOL writeResult = [videoData writeToFile:destination options:NSDataWritingAtomic error:&error];
888-
885+
BOOL writeResult = false;
886+
887+
if (@available(iOS 9.0, *)) {
888+
NSURL *destinationUrl = [NSURL fileURLWithPath:destination relativeToURL:nil];
889+
writeResult = [[NSFileManager defaultManager] copyItemAtURL:url toURL:destinationUrl error:&error];
890+
} else {
891+
NSData *videoData = [NSData dataWithContentsOfURL:url];
892+
writeResult = [videoData writeToFile:destination options:NSDataWritingAtomic error:&error];
893+
}
894+
889895
if(writeResult) {
890896
NSLog(@"video success");
891897
}

Uploader.h

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#import <Foundation/Foundation.h>
2+
3+
#if !TARGET_OS_OSX
24
#import <MobileCoreServices/MobileCoreServices.h>
5+
#endif
36

47
typedef void (^UploadCompleteCallback)(NSString*, NSURLResponse *);
58
typedef void (^UploadErrorCallback)(NSError*);

android/build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ def safeExtGet(prop, fallback) {
44

55
buildscript {
66
repositories {
7-
jcenter()
7+
mavenCentral()
88
}
99

1010
dependencies {

android/src/main/java/com/rnfs/Uploader.java

+23-13
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
import java.io.FileInputStream;
1717
import java.io.InputStreamReader;
1818
import java.net.HttpURLConnection;
19+
import java.nio.channels.Channels;
20+
import java.nio.channels.FileChannel;
21+
import java.nio.channels.WritableByteChannel;
1922
import java.util.List;
2023
import java.util.Map;
2124
import java.util.concurrent.atomic.AtomicBoolean;
@@ -126,39 +129,46 @@ private void upload(UploadParams params, UploadResult result) throws Exception {
126129
connection.connect();
127130

128131
request = new DataOutputStream(connection.getOutputStream());
132+
WritableByteChannel requestChannel = Channels.newChannel(request);
133+
129134
if (!binaryStreamOnly) {
130135
request.writeBytes(metaData);
131136
}
132137

133138
byteSentTotal = 0;
134-
Runtime run = Runtime.getRuntime();
135139

136140
for (ReadableMap map : params.files) {
137141
if (!binaryStreamOnly) {
138142
request.writeBytes(fileHeader[fileCount]);
139143
}
144+
140145
File file = new File(map.getString("filepath"));
141-
int fileLength = (int) file.length();
142-
int bytes_read = 0;
143-
BufferedInputStream bufInput = new BufferedInputStream(new FileInputStream(file));
144-
int buffer_size =(int) Math.ceil(fileLength / 100.f);
145-
if(buffer_size > run.freeMemory() / 10.f) {
146-
buffer_size = (int) Math.ceil(run.freeMemory() / 10.f);
147-
}
148-
byte[] buffer = new byte[buffer_size];
149-
while ((bytes_read = bufInput.read(buffer)) != -1) {
150-
request.write(buffer, 0, bytes_read);
146+
147+
long fileLength = file.length();
148+
long bufferSize = (long) Math.ceil(fileLength / 100.f);
149+
long bytesRead = 0;
150+
151+
FileInputStream fileStream = new FileInputStream(file);
152+
FileChannel fileChannel = fileStream.getChannel();
153+
154+
while (bytesRead < fileLength) {
155+
long transferredBytes = fileChannel.transferTo(bytesRead, bufferSize, requestChannel);
156+
bytesRead += transferredBytes;
157+
151158
if (mParams.onUploadProgress != null) {
152-
byteSentTotal += bytes_read;
159+
byteSentTotal += transferredBytes;
153160
mParams.onUploadProgress.onUploadProgress((int) totalFileLength, byteSentTotal);
154161
}
155162
}
163+
156164
if (!binaryStreamOnly) {
157165
request.writeBytes(crlf);
158166
}
167+
159168
fileCount++;
160-
bufInput.close();
169+
fileStream.close();
161170
}
171+
162172
if (!binaryStreamOnly) {
163173
request.writeBytes(tail);
164174
}

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-fs",
3-
"version": "2.17.0",
3+
"version": "2.18.0",
44
"description": "Native filesystem access for react-native",
55
"main": "FS.common.js",
66
"typings": "index.d.ts",
@@ -35,7 +35,7 @@
3535
"prop-types": "^15.7.2"
3636
},
3737
"peerDependencies": {
38-
"react-native": "^0.59.5",
39-
"react-native-windows": "^0.57.2"
38+
"react-native": "*",
39+
"react-native-windows": "*"
4040
}
4141
}

0 commit comments

Comments
 (0)