Skip to content

Commit 7f5651d

Browse files
skysky
authored andcommitted
first commit
0 parents  commit 7f5651d

File tree

14 files changed

+931
-0
lines changed

14 files changed

+931
-0
lines changed

android/build.gradle

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
buildscript {
2+
repositories {
3+
mavenCentral()
4+
}
5+
dependencies {
6+
classpath 'com.android.tools.build:gradle:2.1.2'
7+
}
8+
}
9+
10+
apply plugin: 'com.android.library'
11+
12+
android {
13+
compileSdkVersion 'android-25'
14+
buildToolsVersion '25.0.1'
15+
16+
defaultConfig {
17+
minSdkVersion 19
18+
targetSdkVersion 22
19+
}
20+
21+
buildTypes {
22+
release {
23+
minifyEnabled false
24+
proguardFile getDefaultProguardFile('proguard-android.txt')
25+
}
26+
}
27+
}
28+
29+
allprojects {
30+
repositories {
31+
mavenLocal()
32+
jcenter()
33+
maven {
34+
url "http://files.couchbase.com/maven2/"
35+
}
36+
}
37+
}
38+
39+
dependencies {
40+
compile 'com.facebook.react:react-native:+'
41+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.reactnativedocumentpicker"
4+
android:versionCode="1"
5+
android:versionName="1.0">
6+
</manifest>
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
package com.reactnativedocumentpicker;
2+
3+
import android.app.Activity;
4+
import android.content.ContentResolver;
5+
import android.content.Intent;
6+
import android.database.Cursor;
7+
import android.net.Uri;
8+
import android.os.Bundle;
9+
import android.provider.MediaStore;
10+
import android.provider.OpenableColumns;
11+
import android.util.Log;
12+
import android.webkit.MimeTypeMap;
13+
14+
import com.facebook.react.bridge.ActivityEventListener;
15+
import com.facebook.react.bridge.Arguments;
16+
import com.facebook.react.bridge.Callback;
17+
import com.facebook.react.bridge.ReactApplicationContext;
18+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
19+
import com.facebook.react.bridge.ReactMethod;
20+
import com.facebook.react.bridge.ReadableArray;
21+
import com.facebook.react.bridge.ReadableMap;
22+
import com.facebook.react.bridge.WritableMap;
23+
24+
import java.io.File;
25+
import java.io.FileOutputStream;
26+
import java.io.IOException;
27+
import java.net.URL;
28+
import java.nio.channels.Channels;
29+
import java.nio.channels.ReadableByteChannel;
30+
31+
/**
32+
* @see <a href="https://developer.android.com/guide/topics/providers/document-provider.html">android documentation</a>
33+
*/
34+
public class DocumentPicker extends ReactContextBaseJavaModule implements ActivityEventListener {
35+
private static final String NAME = "RNDocumentPicker";
36+
private static final int READ_REQUEST_CODE = 41;
37+
38+
private static class Fields {
39+
//private static final String FILE_PATH = "filepath";
40+
private static final String FILE_SIZE = "fileSize";
41+
private static final String FILE_NAME = "fileName";
42+
private static final String TYPE = "type";
43+
}
44+
45+
private Callback callback;
46+
47+
public DocumentPicker(ReactApplicationContext reactContext) {
48+
super(reactContext);
49+
reactContext.addActivityEventListener(this);
50+
}
51+
52+
@Override
53+
public String getName() {
54+
return NAME;
55+
}
56+
57+
@ReactMethod
58+
public void show(ReadableMap args, Callback callback) {
59+
Intent intent;
60+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
61+
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
62+
} else {
63+
intent = new Intent(Intent.ACTION_PICK);
64+
}
65+
intent.addCategory(Intent.CATEGORY_OPENABLE);
66+
67+
if (!args.isNull("filetype")) {
68+
ReadableArray filetypes = args.getArray("filetype");
69+
if (filetypes.size() > 0) {
70+
intent.setType(filetypes.getString(0));
71+
}
72+
}
73+
74+
this.callback = callback;
75+
76+
getReactApplicationContext().startActivityForResult(intent, READ_REQUEST_CODE, Bundle.EMPTY);
77+
}
78+
79+
// removed @Override temporarily just to get it working on RN0.33 and RN0.32 - will remove
80+
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
81+
onActivityResult(requestCode, resultCode, data);
82+
}
83+
84+
// removed @Override temporarily just to get it working on RN0.33 and RN0.32
85+
public void onActivityResult(int requestCode, int resultCode, Intent data) {
86+
if (requestCode != READ_REQUEST_CODE)
87+
return;
88+
89+
if (resultCode != Activity.RESULT_OK) {
90+
callback.invoke("Bad result code: " + resultCode, null);
91+
return;
92+
}
93+
94+
if (data == null) {
95+
callback.invoke("No data", null);
96+
return;
97+
}
98+
99+
try {
100+
Uri uri = data.getData();
101+
callback.invoke(null, toMapWithMetadata(uri));
102+
} catch (Exception e) {
103+
Log.e(NAME, "Failed to read", e);
104+
callback.invoke(e.getMessage(), null);
105+
}
106+
}
107+
108+
private WritableMap toMapWithMetadata(Uri uri) {
109+
WritableMap map;
110+
if(uri.toString().startsWith("/")) {
111+
map = metaDataFromFile(new File(uri.toString()));
112+
} else if (uri.toString().startsWith("http")) {
113+
map = metaDataFromUri(uri);
114+
} else {
115+
map = metaDataFromContentResolver(uri);
116+
}
117+
118+
map.putString("uri", uri.toString());
119+
120+
return map;
121+
}
122+
123+
private WritableMap metaDataFromUri(Uri uri) {
124+
WritableMap map = Arguments.createMap();
125+
126+
File outputDir = getReactApplicationContext().getCacheDir();
127+
try {
128+
File downloaded = download(uri, outputDir);
129+
//map.putString(Fields.FILE_PATH, downloaded.getAbsolutePath());
130+
map.putInt(Fields.FILE_SIZE, (int) downloaded.length());
131+
map.putString(Fields.FILE_NAME, downloaded.getName());
132+
map.putString(Fields.TYPE, mimeTypeFromName(uri.toString()));
133+
} catch (IOException e) {
134+
Log.e("DocumentPicker", "Failed to download file", e);
135+
}
136+
137+
return map;
138+
}
139+
140+
private WritableMap metaDataFromFile(File file) {
141+
WritableMap map = Arguments.createMap();
142+
143+
if(!file.exists())
144+
return map;
145+
//map.putString(Fields.FILE_PATH, file.getAbsolutePath());
146+
map.putInt(Fields.FILE_SIZE, (int) file.length());
147+
map.putString(Fields.FILE_NAME, file.getName());
148+
map.putString(Fields.TYPE, mimeTypeFromName(file.getAbsolutePath()));
149+
150+
return map;
151+
}
152+
153+
154+
private WritableMap metaDataFromContentResolver(Uri uri) {
155+
WritableMap map = Arguments.createMap();
156+
157+
ContentResolver contentResolver = getReactApplicationContext().getContentResolver();
158+
159+
map.putString(Fields.TYPE, contentResolver.getType(uri));
160+
161+
Cursor cursor = contentResolver.query(uri, null, null, null, null, null);
162+
163+
try {
164+
if (cursor != null && cursor.moveToFirst()) {
165+
166+
//map.putString(Fields.FILE_PATH, cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)));
167+
//map.putString(Fields.FILE_PATH, "");
168+
map.putString(Fields.FILE_NAME, cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)));
169+
170+
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
171+
if (!cursor.isNull(sizeIndex)) {
172+
String size = cursor.getString(sizeIndex);
173+
if (size != null)
174+
map.putInt(Fields.FILE_SIZE, Integer.valueOf(size));
175+
}
176+
}
177+
} finally {
178+
if (cursor != null) {
179+
cursor.close();
180+
}
181+
}
182+
183+
return map;
184+
}
185+
186+
private static File download(Uri uri, File outputDir) throws IOException {
187+
File file = File.createTempFile("prefix", "extension", outputDir);
188+
189+
URL url = new URL(uri.toString());
190+
191+
ReadableByteChannel channel = Channels.newChannel(url.openStream());
192+
try{
193+
FileOutputStream stream = new FileOutputStream(file);
194+
195+
try {
196+
stream.getChannel().transferFrom(channel, 0, Long.MAX_VALUE);
197+
return file;
198+
} finally {
199+
stream.close();
200+
}
201+
} finally {
202+
channel.close();
203+
}
204+
}
205+
206+
private static String mimeTypeFromName(String absolutePath) {
207+
String extension = MimeTypeMap.getFileExtensionFromUrl(absolutePath);
208+
if (extension != null) {
209+
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
210+
} else {
211+
return null;
212+
}
213+
}
214+
215+
// Required for RN 0.30+ modules than implement ActivityEventListener
216+
public void onNewIntent(Intent intent) {
217+
}
218+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.reactnativedocumentpicker;
2+
3+
import com.facebook.react.ReactPackage;
4+
import com.facebook.react.bridge.JavaScriptModule;
5+
import com.facebook.react.bridge.NativeModule;
6+
import com.facebook.react.bridge.ReactApplicationContext;
7+
import com.facebook.react.uimanager.ViewManager;
8+
import com.reactnativedocumentpicker.DocumentPicker;
9+
10+
import java.util.ArrayList;
11+
import java.util.Collections;
12+
import java.util.List;
13+
14+
public class ReactNativeDocumentPicker implements ReactPackage {
15+
16+
// Deprecated RN 0.47
17+
public List<Class<? extends JavaScriptModule>> createJSModules() {
18+
return Collections.emptyList();
19+
}
20+
21+
@Override
22+
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
23+
return Collections.emptyList();
24+
}
25+
26+
@Override
27+
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
28+
List<NativeModule> modules = new ArrayList<>();
29+
modules.add(new DocumentPicker(reactContext));
30+
return modules;
31+
}
32+
}

index.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
import {Platform, NativeModules} from "react-native";
4+
const DocumentPicker = NativeModules.RNDocumentPicker;
5+
6+
/**
7+
* Android requires mime types, iOS is a bit more complicated:
8+
*
9+
* @see https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html
10+
*/
11+
class DocumentPickerUtil {
12+
static allFiles() {
13+
return (Platform.OS === 'android') ? "*/*" : "public.content";
14+
}
15+
16+
static images() {
17+
return (Platform.OS === 'android') ? "image/*" : "public.image";
18+
}
19+
20+
static videos() {
21+
return (Platform.OS === 'android') ? "video/*" : "public.movie";
22+
}
23+
24+
static plainText() {
25+
return (Platform.OS === 'android') ? "text/plain" : "public.plain-text";
26+
}
27+
28+
static audio() {
29+
return (Platform.OS === 'android') ? "audio/*" : "public.audio";
30+
}
31+
32+
static pdf() {
33+
return (Platform.OS === 'android') ? "application/pdf" : "com.adobe.pdf";
34+
}
35+
}
36+
37+
module.exports = {DocumentPickerUtil, DocumentPicker};

0 commit comments

Comments
 (0)