diff --git a/.gitignore b/.gitignore
index d07b789..48bf865 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,4 @@ xcuserdata
*.xccheckout
*.moved-aside
*.xcuserstate
+*.vscode
\ No newline at end of file
diff --git a/README.md b/README.md
index 15b1653..6824cb4 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,16 @@
# react-native-uploader
A React Native module for uploading files and camera roll assets. Supports progress notification.
+# Do you absolutely need this?
+You can use file upload with `fetch` and if you want progress bar, you can use xhr. Read my post [How to upload photo/file in react-native](https://github.com/g6ling/React-Native-Tips/tree/master/How_to_upload_photo%2Cfile_in%20react-native). Even after read my post, but you are not enough, read the following.
+
## Install
+### Use rnpm
+1. `npm install react-native-uploader --save`
+2. `rnpm link react-native-uploader`
+
+If you don't want use rnpm, do this
### iOS
1. `npm install react-native-uploader --save`
2. In XCode, in the project navigator, right click `Libraries` ➜ `Add Files to [your project's name]`
@@ -10,6 +18,33 @@ A React Native module for uploading files and camera roll assets. Supports progr
4. In XCode, in the project navigator, select your project. Add `libRNUploader.a` to your project's `Build Phases` ➜ `Link Binary With Libraries`
5. Run your project (`Cmd+R`)
+### Android
+1. Add to your settings.gradle:
+```
+include ':RNFileTransfer', ':app'
+project(':RNFileTransfer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-file-transfer-android/android')
+```
+
+2. Add to your android/build.gradle:
+```
+dependencies {
+ ...
+ compile project(':RNFileTransfer')
+}
+```
+
+3. Add to MainActivity.java
+```
+import com.burlap.filetransfer.FileTransferPackage;
+...
+mReactInstanceManager = ReactInstanceManager.builder()
+ .setApplication(getApplication())
+ .setBundleAssetName("index.android.bundle")
+ .setJSMainModuleName("index.android")
+ .addPackage(new MainReactPackage())
+ .addPackage(new FileTransferPackage())
+```
+
## Example
See ./examples/UploadFromCameraRoll
@@ -18,10 +53,10 @@ See ./examples/UploadFromCameraRoll
## Usage
```javascript
-var RNUploader = require('NativeModules').RNUploader;
+var RNUploader = require('react-native-uploader');
var {
- StyleSheet,
+ StyleSheet,
Component,
View,
DeviceEventEmitter,
@@ -35,7 +70,7 @@ componentDidMount(){
let bytesWritten = data.totalBytesWritten;
let bytesTotal = data.totalBytesExpectedToWrite;
let progress = data.progress;
-
+
console.log( "upload progress: " + progress + "%");
});
}
@@ -53,17 +88,17 @@ doUpload(){
{
name: 'file[]',
filename: 'image2.gif',
- filepath: "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7",
+ filepath: "data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7", // base64 only support ios
filetype: 'image/gif',
},
];
let opts = {
url: 'http://my.server/api/upload',
- files: files,
- method: 'POST', // optional: POST or PUT
- headers: { 'Accept': 'application/json' }, // optional
- params: { 'user_id': 1 }, // optional
+ files: files,
+ method: 'POST', // optional: POST or PUT, only support ios, android always have POST
+ headers: { 'Accept': 'application/json' }, // optional, only support ios, android always have { 'Accept': 'application/json' }
+ params: { 'user_id': 1 }, // optional, Android support this only string. If you want this in Android use params: { 'user_id': '1' }
};
RNUploader.upload( opts, (err, response) => {
@@ -71,12 +106,14 @@ doUpload(){
console.log(err);
return;
}
-
+
let status = response.status;
let responseString = response.data;
let json = JSON.parse( responseString );
console.log('upload complete with status ' + status);
+
+ // android's response is response.body.string.
});
}
@@ -90,9 +127,10 @@ doUpload(){
||type|required|description|example|
|---|---|---|---|---|
|`url`|string|required|URL to upload to|`http://my.server/api/upload`|
-|`method`|string|optional|HTTP method, values: [PUT,POST], default: POST|`POST`|
-|`headers`|object|optional|HTTP headers|`{ 'Accept': 'application/json' }`|
-|`params`|object|optional|Query parameters|`{ 'user_id': 1 }`|
+|`method(only iOS)`|string|optional|HTTP method, values: [PUT,POST], default: POST|`POST`|
+|`headers(only iOS)`|object|optional|HTTP headers|`{ 'Accept': 'application/json' }`|
+|`params(iOS)`|object|optional|Query parameters|`{ 'user_id': 1 }`|
+|`params(Android)`|object|optional|Query parameters|`{ 'user_id': '1' }`
only support string value. You can't use int, boolean, etc..|
|`files`|array|required|Array of file objects to upload. See below.| `[{ name: 'file', filename: 'image1.png', filepath: 'assets-library://...', filetype: 'image/png' } ]` |
`callback` is a method with two parameters:
@@ -100,7 +138,8 @@ doUpload(){
||type|description|example|
|---|---|---|---|
|error|string|String detailing the error|`A server with the specified hostname could not be found.`|
-|response|object{status:Number, data:String}|Object returned with a status code and data.|`{ status: 200, data: '{ success: true }' }`|
+|response(iOS)|object{status:Number, data:String}|Object returned with a status code and data.|`{ status: 200, data: '{ success: true }' }`|
+|response(Android)|String|String returned with responseBody.|`success: true`|
#### `files`
@@ -110,10 +149,10 @@ doUpload(){
|---|---|---|---|---|
|name|string|optional|Form parameter key for the specified file. If missing, will use `filename`.|`file[]`|
|filename|string|required|filename|`image1.png`|
-|filepath|string|required|File URI
Supports `assets-library:`, `data:` and `file:` URIs and file paths.|`assets-library://...`
`data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOV...`
`file:/tmp/image1.png`
`/tmp/image1.png`|
+|filepath|string|required|File URI
Supports `assets-library:`, `data:` and `file:` URIs and file paths.|`assets-library://...(iOS)`
`content://...(Android)`
`data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOV...(only iOS)`
`file:/tmp/image1.png`
`/tmp/image1.png`|
|filetype|string|optional|MIME type of file. If missing, will infer based on the extension in `filepath`.|`image/png`|
-### Progress
+### Progress (only support iOS)
To monitor upload progress simply subscribe to the `RNUploaderProgress` event using DeviceEventEmitter.
```
@@ -121,12 +160,12 @@ DeviceEventEmitter.addListener('RNUploaderProgress', (data)=>{
let bytesWritten = data.totalBytesWritten;
let bytesTotal = data.totalBytesExpectedToWrite;
let progress = data.progress;
-
+
console.log( "upload progress: " + progress + "%");
});
```
-### Cancel
+### Cancel (only support iOS)
To cancel an upload in progress:
```
RNUploader.cancel()
@@ -143,8 +182,9 @@ Inspired by similiar projects:
* progress reporting
* packaged as a static library
* support for multiple files at a time
-* support for files from the assets library, base64 `data:` or `file:` paths
+* support for files from the assets library, base64 `data:` or `file:` paths
* no external dependencies (ie: AFNetworking)
+* support Android
## License
diff --git a/RNUploader/RNUploader.ios.js b/RNUploader/RNUploader.ios.js
deleted file mode 100644
index 50c8be0..0000000
--- a/RNUploader/RNUploader.ios.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * @providesModule RNUploader
- * @flow
- */
-'use strict';
-
-var NativeRNUploader = require('NativeModules').RNUploader;
-
-/**
- * High-level docs for the RNUploader iOS API can be written here.
- */
-
-var RNUploader = {
- test: function() {
- NativeRNUploader.test();
- }
-};
-
-module.exports = RNUploader;
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..76f22b0
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,36 @@
+buildscript {
+ repositories {
+ jcenter()
+ maven { url "https://jitpack.io" }
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.1.3'
+ }
+}
+
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.1"
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 23
+ versionCode 1
+ versionName "1.0"
+ }
+}
+
+repositories {
+ maven { url "https://jitpack.io" }
+}
+
+dependencies {
+ compile 'com.android.support:appcompat-v7:23.+'
+ compile 'com.facebook.react:react-native:0.16.+'
+ compile 'com.squareup.okhttp3:okhttp:3.3.1'
+ compile 'com.zhy:okhttputils:2.6.2'
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+}
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4add1ea
--- /dev/null
+++ b/android/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/android/src/main/java/com/burlap/filetransfer/FileTransferModule.java b/android/src/main/java/com/burlap/filetransfer/FileTransferModule.java
new file mode 100644
index 0000000..e0eb5d4
--- /dev/null
+++ b/android/src/main/java/com/burlap/filetransfer/FileTransferModule.java
@@ -0,0 +1,171 @@
+package com.burlap.filetransfer;
+
+import android.app.DownloadManager;
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.net.Uri;
+
+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.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReadableMapKeySetIterator;
+import com.facebook.react.bridge.ReadableType;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.modules.core.DeviceEventManagerModule;
+
+import org.json.*;
+
+import java.util.Map;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+
+import okhttp3.MediaType;
+import okhttp3.MultipartBody;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+import com.zhy.http.okhttp.request.CountingRequestBody;
+
+public class FileTransferModule extends ReactContextBaseJavaModule {
+
+ private final OkHttpClient client = new OkHttpClient();
+ private String TAG = "ImageUploadAndroid";
+ ReactApplicationContext reactContext = null;
+
+ public FileTransferModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ this.reactContext = reactContext;
+ }
+
+ @Override
+ public String getName() {
+ // match up with the IOS name
+ return "FileTransfer";
+ }
+
+ @ReactMethod
+ public void upload(ReadableMap options, Callback complete) {
+
+ final Callback completeCallback = complete;
+
+ try {
+ MultipartBody.Builder mRequestBody = new MultipartBody.Builder()
+ .setType(MultipartBody.FORM);
+
+ ReadableArray files = options.getArray("files");
+ String url = options.getString("url");
+
+ if(options.hasKey("params")){
+ ReadableMap data = options.getMap("params");
+ ReadableMapKeySetIterator iterator = data.keySetIterator();
+
+ while(iterator.hasNextKey()){
+ String key = iterator.nextKey();
+ if(ReadableType.String.equals(data.getType(key))) {
+ mRequestBody.addFormDataPart(key, data.getString(key));
+ }
+ }
+ }
+
+
+
+
+ if(files.size() != 0){
+ for(int fileIndex=0 ; fileIndex createNativeModules(ReactApplicationContext reactContext) {
+ return Arrays.asList(
+ new FileTransferModule(reactContext)
+ );
+ }
+
+
+ @Override
+ public List> createJSModules() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ return Arrays.asList();
+ }
+}
diff --git a/index.android.js b/index.android.js
new file mode 100644
index 0000000..a279f82
--- /dev/null
+++ b/index.android.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var { NativeModules } = require('react-native');
+var FileTransfer = NativeModules.FileTransfer
+
+class RNUploader {
+ constructor() {
+ }
+
+ static upload(opts, callback) {
+ FileTransfer.upload(opts, callback);
+ }
+}
+
+module.exports = RNUploader;
\ No newline at end of file
diff --git a/index.ios.js b/index.ios.js
new file mode 100644
index 0000000..1a33044
--- /dev/null
+++ b/index.ios.js
@@ -0,0 +1,28 @@
+/**
+ * @providesModule RNUploader
+ * @flow
+ */
+'use strict';
+var { NativeModules } = require('react-native');
+var NativeRNUploader = NativeModules.RNUploader;
+
+/**
+ * High-level docs for the RNUploader iOS API can be written here.
+ */
+
+class RNUploader {
+ constructor() {
+ }
+
+ static upload(opts, callback) {
+ NativeRNUploader.upload(opts, callback);
+ }
+ static cancel(){
+ NativeRNUploader.cancel()
+ }
+ static test() {
+ NativeRNUploader.test()
+ }
+}
+
+module.exports = RNUploader;
\ No newline at end of file
diff --git a/RNUploader/RNUploader.m b/ios/RNUploader.m
similarity index 100%
rename from RNUploader/RNUploader.m
rename to ios/RNUploader.m
diff --git a/RNUploader/RNUploader.xcodeproj/project.pbxproj b/ios/RNUploader.xcodeproj/project.pbxproj
similarity index 100%
rename from RNUploader/RNUploader.xcodeproj/project.pbxproj
rename to ios/RNUploader.xcodeproj/project.pbxproj
diff --git a/RNUploader/RNUploader.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/RNUploader.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from RNUploader/RNUploader.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to ios/RNUploader.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/package.json b/package.json
index 7bf5627..b654ff7 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"type": "git",
"url": "git+https://github.com/aroth/react-native-uploader.git"
},
- "version": "0.0.9",
+ "version": "0.0.10",
"description": "A React Native module to upload files and camera roll assets. Supports progress notification.",
"author": {
"name": "Adam Roth",
@@ -31,5 +31,6 @@
"name": "aroth",
"email": "adamjroth@gmail.com"
}
- ]
+ ],
+ "main": "index"
}