Skip to content

Instantly share code, notes, and snippets.

@progmonster
Created August 29, 2017 15:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save progmonster/ff8ea9bc40f55ca1cd97c84419117605 to your computer and use it in GitHub Desktop.
Save progmonster/ff8ea9bc40f55ca1cd97c84419117605 to your computer and use it in GitHub Desktop.
react native document picker
package com.smsapprn;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.RequiresPermission;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.util.Base64;
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.BaseActivityEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class ExpModule extends ReactContextBaseJavaModule {
private static final int READ_REQUEST_CODE = 42;
public ExpModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "ExpModule";
}
@ReactMethod
public void getSimList(final Promise promise) {
try {
SubscriptionManager subscriptionManager = (SubscriptionManager) getReactApplicationContext()
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
WritableArray result = Arguments.createArray();
for (SubscriptionInfo subscriptionInfo : subscriptionManager.getActiveSubscriptionInfoList()) {
WritableMap simInfo = Arguments.createMap();
simInfo.putInt("slotIndex", subscriptionInfo.getSimSlotIndex());
simInfo.putInt("subscriptionId", subscriptionInfo.getSubscriptionId());
simInfo.putString("carrierName", subscriptionInfo.getCarrierName().toString());
simInfo.putString("displayName", subscriptionInfo.getDisplayName().toString());
result.pushMap(simInfo);
}
promise.resolve(result);
} catch (Exception e) {
promise.reject(e);
}
}
@ReactMethod
public void sayHello(ReadableArray mimeTypes, final Promise promise) {
String[] mimeTypesArr = new String[mimeTypes.size()];
for (int mimeTypeIdx = 0; mimeTypeIdx < mimeTypes.size(); mimeTypeIdx++) {
mimeTypesArr[mimeTypeIdx] = mimeTypes.getString(mimeTypeIdx);
}
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
// Filter to only show results that can be "opened", such as a
// file (as opposed to a list of contacts or timezones)
intent.addCategory(Intent.CATEGORY_OPENABLE);
// Filter to show only images, using the image MIME data type.
// If one wanted to search for ogg vorbis files, the type would be "audio/ogg".
// To search for all documents available via installed storage providers,
// it would be "*/*".
intent.setType("*/*");
intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypesArr);
Activity currentActivity = getCurrentActivity();
if (currentActivity == null) {
promise.reject(new RuntimeException("Can't obtain current activity."));
return;
}
if (intent.resolveActivity(getReactApplicationContext().getPackageManager()) == null) {
promise.reject(new RuntimeException("Can't resolve activity."));
return;
}
ActivityEventListener openDocumentActivityEventListener = new BaseActivityEventListener() {
@Override
public void onActivityResult(final Activity activity, int requestCode, int resultCode, Intent data) {
if (requestCode != READ_REQUEST_CODE) {
return;
}
getReactApplicationContext().removeActivityEventListener(this);
if (resultCode != Activity.RESULT_OK) {
promise.resolve(null);
return;
}
AsyncTask<Uri, Integer, AsyncTaskResult<byte[]>> downloadTask = new AsyncTask<Uri, Integer, AsyncTaskResult<byte[]>>() {
protected AsyncTaskResult<byte[]> doInBackground(Uri... uris) {
try {
InputStream inputStream = activity.getContentResolver().openInputStream(uris[0]);
try (BufferedInputStream bis = new BufferedInputStream(inputStream)) {
return new AsyncTaskResult<>(readBytes(bis, isCancelled()));
} catch (IOException e) {
return new AsyncTaskResult<>(e);
}
} catch (FileNotFoundException e) {
return new AsyncTaskResult<>(e);
}
}
@Override
protected void onPostExecute(AsyncTaskResult<byte[]> asyncTaskResult) {
if (asyncTaskResult.getError() == null) {
try {
promise.resolve(Base64.encodeToString(asyncTaskResult.getResult(), Base64.NO_WRAP));
} catch (Exception e) {
promise.reject(e);
}
} else {
asyncTaskResult.getError().printStackTrace();
promise.reject(asyncTaskResult.getError());
}
}
};
downloadTask.execute(data.getData());
}
};
getReactApplicationContext().addActivityEventListener(openDocumentActivityEventListener);
currentActivity.startActivityForResult(intent, READ_REQUEST_CODE);
}
private byte[] readBytes(InputStream inputStream, boolean cancelled) throws IOException {
// this dynamically extends to take the bytes you read
ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
// this is storage overwritten on each iteration with bytes
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
// we need to know how may bytes were read to write them to the byteBuffer
int len;
while ((len = inputStream.read(buffer)) != -1) {
if (cancelled) {
return null;
}
byteBuffer.write(buffer, 0, len);
}
// and then we can return your byte array.
return byteBuffer.toByteArray();
}
private static class AsyncTaskResult<T> {
private T result;
private Exception error;
public T getResult() {
return result;
}
public Exception getError() {
return error;
}
public AsyncTaskResult(T result) {
super();
this.result = result;
}
public AsyncTaskResult(Exception error) {
super();
this.error = error;
}
}
}
import {NativeModules} from "react-native"
module.exports = NativeModules.ExpModule;
package com.smsapprn;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ExpReactPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new ExpModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
@progmonster
Copy link
Author

progmonster commented Aug 29, 2017

"Exp" because of "experimental" not because of Expo. Works only for Android with API Level 19 or higher (https://developer.android.com/guide/topics/providers/document-provider.html)

Method to call is "sayHello", rename it as you want :)

Example of usage:

import ExpModule from "ExpModule";

ExpModule.sayHello([
  "application/vnd.ms-excel",
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
]).then(result => {
       // result - contains file data in base64 encoding
}).catch(error => {})

@flieks
Copy link

flieks commented Aug 29, 2017

thanks @progmonster. I think this requires APPI 22 and higher
subscriptionManager.getActiveSubscriptionInfoList
this needs 22 or higher
note: ok i suppose i can delete this function :)
Don't i have to connect ExpReactPackage in MainActivity (get packages or sth) ?

@flieks
Copy link

flieks commented Aug 29, 2017

@progmonster It opens the file picker but after i pick a file it closes and doesn't fire the then() or catch() callback..
update: it doesn't go in the onActivityResult of BaseActivityEventListener
I get this error in logcat:
https://gist.github.com/flieks/f34c30a83b5995025ccba499c1bfe9fb
I'm runnnig on android 7.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment