2015-10-19 14:40:05 +01:00
|
|
|
package com.rnfs;
|
|
|
|
|
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
|
|
import android.os.Environment;
|
2015-10-26 00:26:03 +00:00
|
|
|
import android.os.AsyncTask;
|
2015-10-19 14:40:05 +01:00
|
|
|
import android.util.Base64;
|
|
|
|
|
import android.content.Context;
|
2015-11-20 00:16:13 +00:00
|
|
|
import android.support.annotation.Nullable;
|
2015-10-19 14:40:05 +01:00
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
import java.io.FileInputStream;
|
2015-10-21 00:17:03 +01:00
|
|
|
import java.io.BufferedInputStream;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.OutputStream;
|
2015-10-26 00:26:03 +00:00
|
|
|
import java.io.IOException;
|
2015-10-21 00:17:03 +01:00
|
|
|
import java.net.URL;
|
|
|
|
|
import java.net.URLConnection;
|
2015-11-20 00:16:13 +00:00
|
|
|
import java.net.HttpURLConnection;
|
2015-10-19 14:40:05 +01:00
|
|
|
|
|
|
|
|
import com.facebook.react.bridge.NativeModule;
|
|
|
|
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
|
|
|
import com.facebook.react.bridge.ReactContext;
|
|
|
|
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
|
|
|
import com.facebook.react.bridge.ReactMethod;
|
|
|
|
|
import com.facebook.react.bridge.Callback;
|
|
|
|
|
import com.facebook.react.bridge.ReadableMap;
|
|
|
|
|
import com.facebook.react.bridge.WritableMap;
|
|
|
|
|
import com.facebook.react.bridge.Arguments;
|
|
|
|
|
import com.facebook.react.bridge.WritableArray;
|
|
|
|
|
|
2015-11-20 00:16:13 +00:00
|
|
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
|
|
|
|
2015-10-19 14:40:05 +01:00
|
|
|
public class RNFSManager extends ReactContextBaseJavaModule {
|
|
|
|
|
|
|
|
|
|
private static final String NSDocumentDirectoryPath = "NSDocumentDirectoryPath";
|
|
|
|
|
private static final String NSDocumentDirectory = "NSDocumentDirectory";
|
|
|
|
|
|
|
|
|
|
private static final String NSFileTypeRegular = "NSFileTypeRegular";
|
|
|
|
|
private static final String NSFileTypeDirectory = "NSFileTypeDirectory";
|
|
|
|
|
|
|
|
|
|
public RNFSManager(ReactApplicationContext reactContext) {
|
|
|
|
|
super(reactContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String getName() {
|
|
|
|
|
return "RNFSManager";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ReactMethod
|
|
|
|
|
public void writeFile(String filepath, String base64Content, ReadableMap options, Callback callback) {
|
|
|
|
|
try {
|
|
|
|
|
byte[] bytes = Base64.decode(base64Content, Base64.DEFAULT);
|
|
|
|
|
|
|
|
|
|
FileOutputStream outputStream = new FileOutputStream(filepath);
|
|
|
|
|
outputStream.write(bytes);
|
|
|
|
|
outputStream.close();
|
|
|
|
|
|
2015-10-22 01:25:52 +01:00
|
|
|
callback.invoke(null, true, filepath);
|
2015-10-19 14:40:05 +01:00
|
|
|
} catch (Exception ex) {
|
|
|
|
|
ex.printStackTrace();
|
|
|
|
|
callback.invoke(makeErrorPayload(ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ReactMethod
|
|
|
|
|
public void readFile(String filepath, Callback callback) {
|
|
|
|
|
try {
|
|
|
|
|
File file = new File(filepath);
|
|
|
|
|
|
|
|
|
|
if (!file.exists()) throw new Exception("File does not exist");
|
|
|
|
|
|
|
|
|
|
FileInputStream inputStream = new FileInputStream(filepath);
|
|
|
|
|
byte[] buffer = new byte[(int)file.length()];
|
|
|
|
|
inputStream.read(buffer);
|
|
|
|
|
|
2015-10-22 01:25:52 +01:00
|
|
|
String base64Content = Base64.encodeToString(buffer, Base64.NO_WRAP);
|
2015-10-19 14:40:05 +01:00
|
|
|
|
|
|
|
|
callback.invoke(null, base64Content);
|
|
|
|
|
} catch (Exception ex) {
|
|
|
|
|
ex.printStackTrace();
|
|
|
|
|
callback.invoke(makeErrorPayload(ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ReactMethod
|
2015-10-22 01:25:52 +01:00
|
|
|
public void readDir(String directory, Callback callback) {
|
2015-10-19 14:40:05 +01:00
|
|
|
try {
|
2015-10-22 01:25:52 +01:00
|
|
|
File file = new File(directory);
|
2015-10-19 14:40:05 +01:00
|
|
|
|
2015-10-22 01:25:52 +01:00
|
|
|
if (!file.exists()) throw new Exception("Folder does not exist");
|
2015-10-20 23:31:29 +01:00
|
|
|
|
2015-10-19 14:40:05 +01:00
|
|
|
File[] files = file.listFiles();
|
|
|
|
|
|
|
|
|
|
WritableArray fileMaps = Arguments.createArray();
|
|
|
|
|
|
|
|
|
|
for (File childFile : files) {
|
|
|
|
|
WritableMap fileMap = Arguments.createMap();
|
|
|
|
|
|
|
|
|
|
fileMap.putString("name", childFile.getName());
|
|
|
|
|
fileMap.putString("path", childFile.getAbsolutePath());
|
2015-10-20 23:31:29 +01:00
|
|
|
fileMap.putInt("size", (int)childFile.length());
|
|
|
|
|
fileMap.putInt("type", childFile.isDirectory() ? 1 : 0);
|
2015-10-19 14:40:05 +01:00
|
|
|
|
|
|
|
|
fileMaps.pushMap(fileMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callback.invoke(null, fileMaps);
|
|
|
|
|
|
|
|
|
|
} catch (Exception ex) {
|
|
|
|
|
ex.printStackTrace();
|
|
|
|
|
callback.invoke(makeErrorPayload(ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ReactMethod
|
|
|
|
|
public void stat(String filepath, Callback callback) {
|
|
|
|
|
try {
|
|
|
|
|
File file = new File(filepath);
|
|
|
|
|
|
|
|
|
|
if (!file.exists()) throw new Exception("File does not exist");
|
|
|
|
|
|
|
|
|
|
WritableMap statMap = Arguments.createMap();
|
|
|
|
|
|
|
|
|
|
statMap.putInt("ctime", (int)(file.lastModified() / 1000));
|
|
|
|
|
statMap.putInt("mtime", (int)(file.lastModified() / 1000));
|
|
|
|
|
statMap.putInt("size", (int)file.length());
|
|
|
|
|
statMap.putInt("type", file.isDirectory() ? 1 : 0);
|
|
|
|
|
|
|
|
|
|
callback.invoke(null, statMap);
|
|
|
|
|
} catch (Exception ex) {
|
|
|
|
|
ex.printStackTrace();
|
|
|
|
|
callback.invoke(makeErrorPayload(ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ReactMethod
|
|
|
|
|
public void unlink(String filepath, Callback callback) {
|
|
|
|
|
try {
|
|
|
|
|
File file = new File(filepath);
|
|
|
|
|
|
|
|
|
|
if (!file.exists()) throw new Exception("File does not exist");
|
|
|
|
|
|
2015-10-20 23:31:29 +01:00
|
|
|
boolean success = DeleteRecursive(file);
|
|
|
|
|
|
|
|
|
|
callback.invoke(null, success, filepath);
|
|
|
|
|
} catch (Exception ex) {
|
|
|
|
|
ex.printStackTrace();
|
|
|
|
|
callback.invoke(makeErrorPayload(ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean DeleteRecursive(File fileOrDirectory) {
|
|
|
|
|
if (fileOrDirectory.isDirectory()) {
|
|
|
|
|
for (File child : fileOrDirectory.listFiles()) {
|
|
|
|
|
DeleteRecursive(child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fileOrDirectory.delete();
|
2015-11-20 00:16:13 +00:00
|
|
|
}
|
2015-10-20 23:31:29 +01:00
|
|
|
|
|
|
|
|
@ReactMethod
|
2015-10-22 01:25:52 +01:00
|
|
|
public void mkdir(String filepath, Boolean excludeFromBackup, Callback callback) {
|
2015-10-20 23:31:29 +01:00
|
|
|
try {
|
|
|
|
|
File file = new File(filepath);
|
|
|
|
|
|
|
|
|
|
file.mkdirs();
|
|
|
|
|
|
|
|
|
|
boolean success = file.exists();
|
2015-10-19 14:40:05 +01:00
|
|
|
|
|
|
|
|
callback.invoke(null, success, filepath);
|
|
|
|
|
} catch (Exception ex) {
|
|
|
|
|
ex.printStackTrace();
|
|
|
|
|
callback.invoke(makeErrorPayload(ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-20 00:16:13 +00:00
|
|
|
private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
|
|
|
|
|
reactContext
|
|
|
|
|
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
|
|
|
|
|
.emit(eventName, params);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-21 00:17:03 +01:00
|
|
|
@ReactMethod
|
2015-11-20 00:16:13 +00:00
|
|
|
public void downloadFile(String urlStr, final String filepath, final int jobId, final Callback callback) {
|
2015-10-21 00:17:03 +01:00
|
|
|
try {
|
|
|
|
|
File file = new File(filepath);
|
|
|
|
|
URL url = new URL(urlStr);
|
|
|
|
|
|
2015-10-26 00:26:03 +00:00
|
|
|
DownloadParams params = new DownloadParams();
|
|
|
|
|
params.src = url;
|
|
|
|
|
params.dest = file;
|
|
|
|
|
params.onTaskCompleted = new OnTaskCompleted() {
|
|
|
|
|
public void onTaskCompleted(Exception ex) {
|
|
|
|
|
if (ex == null) {
|
|
|
|
|
boolean success = true;
|
|
|
|
|
callback.invoke(null, success, filepath);
|
|
|
|
|
} else {
|
|
|
|
|
callback.invoke(makeErrorPayload(ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-11-20 00:16:13 +00:00
|
|
|
params.onDownloadProgress = new OnDownloadProgress() {
|
|
|
|
|
public void onDownloadProgress(int statusCode, int contentLength, int bytesWritten) {
|
|
|
|
|
WritableMap data = Arguments.createMap();
|
|
|
|
|
data.putInt("statusCode", statusCode);
|
|
|
|
|
data.putInt("contentLength", contentLength);
|
|
|
|
|
data.putInt("bytesWritten", bytesWritten);
|
|
|
|
|
|
|
|
|
|
sendEvent(getReactApplicationContext(), "DownloadProgress-" + jobId, data);
|
|
|
|
|
}
|
|
|
|
|
};
|
2015-10-21 00:17:03 +01:00
|
|
|
|
2015-10-26 00:26:03 +00:00
|
|
|
DownloadTask downloadTask = new DownloadTask();
|
|
|
|
|
downloadTask.execute(params);
|
2015-10-21 00:17:03 +01:00
|
|
|
} catch (Exception ex) {
|
|
|
|
|
ex.printStackTrace();
|
|
|
|
|
callback.invoke(makeErrorPayload(ex));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-26 00:26:03 +00:00
|
|
|
private class DownloadParams {
|
|
|
|
|
public URL src;
|
|
|
|
|
public File dest;
|
|
|
|
|
public OnTaskCompleted onTaskCompleted;
|
2015-11-20 00:16:13 +00:00
|
|
|
public OnDownloadProgress onDownloadProgress;
|
2015-10-26 00:26:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public interface OnTaskCompleted {
|
|
|
|
|
void onTaskCompleted(Exception ex);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-20 00:16:13 +00:00
|
|
|
public interface OnDownloadProgress {
|
|
|
|
|
void onDownloadProgress(int statusCode, int contentLength, int bytesWritten);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class DownloadTask extends AsyncTask<DownloadParams, int[], Exception> {
|
|
|
|
|
private DownloadParams mParam;
|
|
|
|
|
|
2015-10-26 00:26:03 +00:00
|
|
|
protected Exception doInBackground(DownloadParams... params) {
|
2015-11-20 00:16:13 +00:00
|
|
|
mParam = params[0];
|
|
|
|
|
|
2015-10-26 00:26:03 +00:00
|
|
|
try {
|
2015-11-20 00:16:13 +00:00
|
|
|
this.download(mParam);
|
|
|
|
|
mParam.onTaskCompleted.onTaskCompleted(null);
|
2015-10-26 00:26:03 +00:00
|
|
|
} catch (Exception ex) {
|
2015-11-20 00:16:13 +00:00
|
|
|
mParam.onTaskCompleted.onTaskCompleted(ex);
|
2015-10-26 00:26:03 +00:00
|
|
|
return ex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void download(DownloadParams param) throws IOException {
|
|
|
|
|
InputStream input = null;
|
|
|
|
|
OutputStream output = null;
|
|
|
|
|
|
|
|
|
|
try {
|
2015-11-20 00:16:13 +00:00
|
|
|
HttpURLConnection connection = (HttpURLConnection)param.src.openConnection();
|
2015-10-26 00:26:03 +00:00
|
|
|
|
|
|
|
|
connection.setConnectTimeout(5000);
|
|
|
|
|
connection.connect();
|
|
|
|
|
|
2015-11-20 00:16:13 +00:00
|
|
|
int statusCode = connection.getResponseCode();
|
2015-10-26 00:26:03 +00:00
|
|
|
int lengthOfFile = connection.getContentLength();
|
|
|
|
|
|
2015-11-20 00:16:13 +00:00
|
|
|
input = new BufferedInputStream(param.src.openStream(), 8 * 1024);
|
2015-10-26 00:26:03 +00:00
|
|
|
output = new FileOutputStream(param.dest);
|
|
|
|
|
|
2015-11-20 00:16:13 +00:00
|
|
|
byte data[] = new byte[8 * 1024];
|
|
|
|
|
int total = 0;
|
2015-10-26 00:26:03 +00:00
|
|
|
int count;
|
|
|
|
|
|
|
|
|
|
while ((count = input.read(data)) != -1) {
|
|
|
|
|
total += count;
|
2015-11-20 00:16:13 +00:00
|
|
|
publishProgress(new int[] { statusCode, lengthOfFile, total });
|
2015-10-26 00:26:03 +00:00
|
|
|
output.write(data, 0, count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
output.flush();
|
|
|
|
|
} finally {
|
|
|
|
|
if (output != null) output.close();
|
|
|
|
|
if (input != null) input.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-20 00:16:13 +00:00
|
|
|
@Override
|
|
|
|
|
protected void onProgressUpdate(int[]... values) {
|
|
|
|
|
super.onProgressUpdate(values);
|
|
|
|
|
mParam.onDownloadProgress.onDownloadProgress(values[0][0], values[0][1], values[0][2]);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-26 00:26:03 +00:00
|
|
|
protected void onPostExecute(Exception ex) {
|
|
|
|
|
|
|
|
|
|
}
|
2015-11-20 00:16:13 +00:00
|
|
|
}
|
2015-10-26 00:26:03 +00:00
|
|
|
|
2015-10-19 14:40:05 +01:00
|
|
|
@ReactMethod
|
|
|
|
|
public void pathForBundle(String bundleNamed, Callback callback) {
|
|
|
|
|
// TODO: Not sure what equilivent would be?
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private WritableMap makeErrorPayload(Exception ex) {
|
|
|
|
|
WritableMap error = Arguments.createMap();
|
|
|
|
|
error.putString("message", ex.getMessage());
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Map<String, Object> getConstants() {
|
|
|
|
|
final Map<String, Object> constants = new HashMap<>();
|
|
|
|
|
constants.put(NSDocumentDirectory, 0);
|
|
|
|
|
constants.put(NSDocumentDirectoryPath, this.getReactApplicationContext().getFilesDir().getAbsolutePath());
|
|
|
|
|
constants.put(NSFileTypeRegular, 0);
|
|
|
|
|
constants.put(NSFileTypeDirectory, 1);
|
|
|
|
|
return constants;
|
|
|
|
|
}
|
|
|
|
|
}
|