Merge branch 'master' of github.com:itinance/react-native-fs

* 'master' of github.com:itinance/react-native-fs: (25 commits)
  fix touch() error on android
  Fixed Mtime
  Add missing flow annotations
  v2.5.2 (cocoapods related only)
  removed osx-version from Podspec
  added a note for cocoapods that we can't support it yet
  added a note for cocoapods that we can't support it yet
  Changes to the Podspec
  Changelog for README
  Version 2.5.0 - compat with RN 0.47.0
  Added back for Backward-Compat but without @override
  Version bump 2.4.0
  removed createJSModules method (RN 0.47 breaking change)
  Add `createJSModules()` to be compatible with latest React.
  Update SDK compile and build tools to version 26.
  update README
  add read method with lenght and position params
  add `touch` method for changing file timestamps
  Remove createJSModules from package
  pod file path error
  ...
This commit is contained in:
Hagen Hübel 2017-09-26 05:55:05 +02:00
commit bcf81df6f8
10 changed files with 231 additions and 25 deletions

53
FS.common.js Normal file → Executable file
View File

@ -13,6 +13,7 @@ var NativeAppEventEmitter = require('react-native').NativeAppEventEmitter; // i
var DeviceEventEmitter = require('react-native').DeviceEventEmitter; // Android
var base64 = require('base-64');
var utf8 = require('utf8');
var isIOS = require('react-native').Platform.OS === 'ios';
var RNFSFileTypeRegular = RNFSManager.RNFSFileTypeRegular;
var RNFSFileTypeDirectory = RNFSManager.RNFSFileTypeDirectory;
@ -60,6 +61,8 @@ type DownloadFileOptions = {
headers?: Headers; // An object of headers to be passed to the server
background?: boolean; // iOS only
progressDivider?: number;
readTimeout?: number;
connectionTimeout?: number;
begin?: (res: DownloadBeginCallbackResult) => void;
progress?: (res: DownloadProgressCallbackResult) => void;
};
@ -265,6 +268,36 @@ var RNFS = {
return readFileGeneric(filepath, encodingOrOptions, RNFSManager.readFile);
},
read(filepath: string, length: number = 0, position: number = 0, encodingOrOptions?: any): Promise<string> {
var options = {
encoding: 'utf8'
};
if (encodingOrOptions) {
if (typeof encodingOrOptions === 'string') {
options.encoding = encodingOrOptions;
} else if (typeof encodingOrOptions === 'object') {
options = encodingOrOptions;
}
}
return RNFSManager.read(normalizeFilePath(filepath), length, position).then((b64) => {
var contents;
if (options.encoding === 'utf8') {
contents = utf8.decode(base64.decode(b64));
} else if (options.encoding === 'ascii') {
contents = base64.decode(b64);
} else if (options.encoding === 'base64') {
contents = b64;
} else {
throw new Error('Invalid encoding type "' + String(options.encoding) + '"');
}
return contents;
});
},
// Android only
readFileAssets(filepath: string, encodingOrOptions?: any): Promise<string> {
if (!RNFSManager.readFileAssets) {
@ -397,6 +430,8 @@ var RNFS = {
if (options.headers && typeof options.headers !== 'object') throw new Error('downloadFile: Invalid value for property `headers`');
if (options.background && typeof options.background !== 'boolean') throw new Error('downloadFile: Invalid value for property `background`');
if (options.progressDivider && typeof options.progressDivider !== 'number') throw new Error('downloadFile: Invalid value for property `progressDivider`');
if (options.readTimeout && typeof options.readTimeout !== 'number') throw new Error('downloadFile: Invalid value for property `readTimeout`');
if (options.connectionTimeout && typeof options.connectionTimeout !== 'number') throw new Error('downloadFile: Invalid value for property `connectionTimeout`');
var jobId = getJobId();
var subscriptions = [];
@ -415,7 +450,9 @@ var RNFS = {
toFile: normalizeFilePath(options.toFile),
headers: options.headers || {},
background: !!options.background,
progressDivider: options.progressDivider || 0
progressDivider: options.progressDivider || 0,
readTimeout: options.readTimeout || 15000,
connectionTimeout: options.connectionTimeout || 5000
};
return {
@ -479,6 +516,20 @@ var RNFS = {
};
},
touch(filepath: string, mtime?: Date, ctime?: Date): Promise<void> {
if (ctime && !(ctime instanceof Date)) throw new Error('touch: Invalid value for argument `ctime`');
if (mtime && !(mtime instanceof Date)) throw new Error('touch: Invalid value for argument `mtime`');
var ctimeTime = 0;
if (isIOS) {
ctimeTime = ctime && ctime.getTime();
}
return RNFSManager.touch(
normalizeFilePath(filepath),
mtime && mtime.getTime(),
ctimeTime
);
},
MainBundlePath: RNFSManager.RNFSMainBundlePath,
CachesDirectoryPath: RNFSManager.RNFSCachesDirectoryPath,
DocumentDirectoryPath: RNFSManager.RNFSDocumentDirectoryPath,

View File

@ -2,11 +2,23 @@
Native filesystem access for react-native
## Changes for v2.5
- breaking change for RN 0.47 at android (https://github.com/facebook/react-native/releases/tag/v0.47.0)
## Changes for v2.4
- Made new thread for other native processes [ANDROID] (https://github.com/itinance/react-native-fs/commit/ad36b078db9728489155a55c1b7daa42ed191945) thx to [codesinghanoop](https://github.com/codesinghanoop)
- Upgrade gradle build tools to 25 (https://github.com/itinance/react-native-fs/commit/239bccb9d56fe9308daafb86920ed29eb9e5cfe4) thx to [markusguenther](https://github.com/markusguenther)
- Fixed Podfile Path-Error (https://github.com/itinance/react-native-fs/commit/9fd51e7e977400f3194c100af88b4c25e7510530) thx to [colorfulberry](https://github.com/colorfulberry)
- Add read-method with length and position params (https://github.com/itinance/react-native-fs/commit/a39c22be81f0c1f2263dbe60f3cd6cfcc902d2ac) thx to [simitti](https://github.com/simitii)
## Changes for v2.3
- React-Native 0.40 is minimum required for compiling on iOS (otherwise install an older release, see below)
- Access to iOS-based "assets-library" is now supported with `copyAssetsFileIOS`
- `readDir` will return now creation- and modification-time of files as with `stat()` (thanks @Ignigena)
- optional connectionTimeout and readTimeout-Settings on `downloadFile` for Android (thanks @drunksaint)
## Breaking change in v2.0
@ -43,18 +55,23 @@ At the command line, in your project folder, type:
Done! No need to worry about manually adding the library to your project.
### Adding with CocoaPods
### ~~Adding with CocoaPods~~
Add the RNFS pod to your list of application pods in your Podfile, using the path from the Podfile to the installed module:
Currently we don't support Cocoapods. If you are familiar with it, please feel free to submit PRs.
More Info [here](https://github.com/itinance/react-native-fs/issues/308#issuecomment-319803126).
~~Add the RNFS pod to your list of application pods in your Podfile, using the path from the Podfile to the installed module:~~
~~
```
pod 'RNFS', :path => './node_modules/react-native-fs'
pod 'RNFS', :path => '../node_modules/react-native-fs'
```
Install pods as usual:
```
pod install
```
~~
### Adding Manually in XCode
@ -362,6 +379,12 @@ Reads the file at `path` and return contents. `encoding` can be one of `utf8` (d
Note: you will take quite a performance hit if you are reading big files
### `read(filepath: string, length = 0, position = 0, encodingOrOptions?: any): Promise<string>`
Reads `length` bytes from the given `position` of the file at `path` and returns contents. `encoding` can be one of `utf8` (default), `ascii`, `base64`. Use `base64` for reading binary files.
Note: reading big files piece by piece using this method may be useful in terms of performance.
### `readFileAssets(filepath:string, encoding?: string): Promise<string>`
Reads the file at `path` in the Android app's assets folder and return contents. `encoding` can be one of `utf8` (default), `ascii`, `base64`. Use `base64` for reading binary files.
@ -440,6 +463,10 @@ Check in the Android assets folder if the item exists. `filepath` is the relativ
Reads the file at `path` and returns its checksum as determined by `algorithm`, which can be one of `md5`, `sha1`, `sha224`, `sha256`, `sha384`, `sha512`.
### `touch(filepath: string, mtime?: Date, ctime?: Date): Promise<string>`
Sets the modification timestamp `mtime` and creation timestamp `ctime` of the file at `filepath`. Setting `ctime` is only supported on iOS, android always sets both timestamps to `mtime`.
### `mkdir(filepath: string, options?: MkdirOptions): Promise<void>`
```
@ -463,6 +490,8 @@ type DownloadFileOptions = {
progressDivider?: number;
begin?: (res: DownloadBeginCallbackResult) => void;
progress?: (res: DownloadProgressCallbackResult) => void;
connectionTimeout?: number // only supported on Android yet
readTimeout?: number // only supported on Android yet
};
```
```

View File

@ -9,12 +9,13 @@ Pod::Spec.new do |s|
s.summary = pjson["description"]
s.license = pjson["license"]
s.author = { "Johannes Lumpe" => "johannes@lum.pe" }
s.ios.deployment_target = '8.0'
s.tvos.deployment_target = '9.0'
s.ios.deployment_target = '9.0'
s.source = { :git => "https://github.com/itinance/react-native-fs", :tag => "v#{s.version}" }
s.source_files = '*.{h,m}'
s.preserve_paths = "**/*.js"
s.dependency 'React/Core'
s.dependency 'React'
end

76
RNFSManager.m Normal file → Executable file
View File

@ -261,6 +261,51 @@ RCT_EXPORT_METHOD(readFile:(NSString *)filepath
resolve(base64Content);
}
RCT_EXPORT_METHOD(read:(NSString *)filepath
length: (NSInteger *)length
position: (NSInteger *)position
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filepath];
if (!fileExists) {
return reject(@"ENOENT", [NSString stringWithFormat:@"ENOENT: no such file or directory, open '%@'", filepath], nil);
}
NSError *error = nil;
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filepath error:&error];
if (error) {
return [self reject:reject withError:error];
}
if ([attributes objectForKey:NSFileType] == NSFileTypeDirectory) {
return reject(@"EISDIR", @"EISDIR: illegal operation on a directory, read", nil);
}
// Open the file handler.
NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:filepath];
if (file == nil) {
return reject(@"EISDIR", @"EISDIR: Could not open file for reading", nil);
}
// Seek to the position if there is one.
[file seekToFileOffset: (int)position];
NSData *content;
if ((int)length > 0) {
content = [file readDataOfLength: (int)length];
} else {
content = [file readDataToEndOfFile];
}
NSString *base64Content = [content base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
resolve(base64Content);
}
RCT_EXPORT_METHOD(hash:(NSString *)filepath
algorithm:(NSString *)algorithm
resolver:(RCTPromiseResolveBlock)resolve
@ -685,6 +730,37 @@ RCT_EXPORT_METHOD(copyAssetsVideoIOS: (NSString *) imageUri
resolve(destination);
}
RCT_EXPORT_METHOD(touch:(NSString*)filepath
mtime:(NSDate *)mtime
ctime:(NSDate *)ctime
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSFileManager *manager = [NSFileManager defaultManager];
BOOL exists = [manager fileExistsAtPath:filepath isDirectory:false];
if (!exists) {
return reject(@"ENOENT", [NSString stringWithFormat:@"ENOENT: no such file, open '%@'", filepath], nil);
}
NSMutableDictionary *attr = [NSMutableDictionary dictionary];
if (mtime) {
[attr setValue:mtime forKey:NSFileModificationDate];
}
if (ctime) {
[attr setValue:ctime forKey:NSFileCreationDate];
}
NSError *error = nil;
BOOL success = [manager setAttributes:attr ofItemAtPath:filepath error:&error];
if (!success) {
return [self reject:reject withError:error];
}
resolve(nil);
}
- (NSNumber *)dateToTimeIntervalNumber:(NSDate *)date

View File

@ -11,8 +11,8 @@ buildscript {
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
minSdkVersion 16

View File

@ -23,6 +23,8 @@ public class DownloadParams {
public File dest;
public ReadableMap headers;
public float progressDivider;
public int readTimeout;
public int connectionTimeout;
public OnTaskCompleted onTaskCompleted;
public OnDownloadBegin onDownloadBegin;
public OnDownloadProgress onDownloadProgress;

View File

@ -22,20 +22,23 @@ import com.facebook.react.bridge.ReadableMapKeySetIterator;
public class Downloader extends AsyncTask<DownloadParams, int[], DownloadResult> {
private DownloadParams mParam;
private AtomicBoolean mAbort = new AtomicBoolean(false);
DownloadResult res;
protected DownloadResult doInBackground(DownloadParams... params) {
mParam = params[0];
res = new DownloadResult();
DownloadResult res = new DownloadResult();
try {
this.download(mParam, res);
mParam.onTaskCompleted.onTaskCompleted(res);
} catch (Exception ex) {
res.exception = ex;
mParam.onTaskCompleted.onTaskCompleted(res);
return res;
}
new Thread(new Runnable() {
public void run() {
try {
download(mParam, res);
mParam.onTaskCompleted.onTaskCompleted(res);
} catch (Exception ex) {
res.exception = ex;
mParam.onTaskCompleted.onTaskCompleted(res);
}
}
}).start();
return res;
}
@ -56,8 +59,8 @@ public class Downloader extends AsyncTask<DownloadParams, int[], DownloadResult>
connection.setRequestProperty(key, value);
}
connection.setConnectTimeout(5000);
connection.setReadTimeout(15000);
connection.setConnectTimeout(param.connectionTimeout);
connection.setReadTimeout(param.readTimeout);
connection.connect();
int statusCode = connection.getResponseCode();

42
android/src/main/java/com/rnfs/RNFSManager.java Normal file → Executable file
View File

@ -150,6 +150,35 @@ public class RNFSManager extends ReactContextBaseJavaModule {
}
}
@ReactMethod
public void read(String filepath, int length, int position, Promise promise){
try {
File file = new File(filepath);
if (file.isDirectory()) {
rejectFileIsDirectory(promise);
return;
}
if (!file.exists()) {
rejectFileNotFound(promise, filepath);
return;
}
FileInputStream inputStream = new FileInputStream(filepath);
byte[] buffer = new byte[length];
inputStream.skip(position);
inputStream.read(buffer,0,length);
String base64Content = Base64.encodeToString(buffer, Base64.NO_WRAP);
promise.resolve(base64Content);
} catch (Exception ex) {
ex.printStackTrace();
reject(promise, filepath, ex);
}
}
@ReactMethod
public void readFileAssets(String filepath, Promise promise) {
InputStream stream = null;
@ -283,7 +312,7 @@ public class RNFSManager extends ReactContextBaseJavaModule {
for (File childFile : files) {
WritableMap fileMap = Arguments.createMap();
fileMap.putInt("mtime", (int)childFile.lastModified());
fileMap.putDouble("mtime", (double)childFile.lastModified()/1000);
fileMap.putString("name", childFile.getName());
fileMap.putString("path", childFile.getAbsolutePath());
fileMap.putInt("size", (int)childFile.length());
@ -631,6 +660,17 @@ public class RNFSManager extends ReactContextBaseJavaModule {
promise.resolve(info);
}
@ReactMethod
public void touch(String filepath, double mtime, double ctime, Promise promise) {
try {
File file = new File(filepath);
promise.resolve(file.setLastModified((long) mtime));
} catch (Exception ex) {
ex.printStackTrace();
reject(promise, filepath, ex);
}
}
private void reject(Promise promise, String filepath, Exception ex) {
if (ex instanceof FileNotFoundException) {
rejectFileNotFound(promise, filepath);

View File

@ -17,13 +17,14 @@ public class RNFSPackage implements ReactPackage {
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
// deprecated >= RN 0.47.0
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Arrays.<ViewManager>asList();
}
}

View File

@ -32,5 +32,8 @@
"flow-bin": "0.28.0",
"react": "^15.4.2",
"react-native": "^0.40.0"
},
"peerDependencies": {
"react-native": ">=0.40.0"
}
}