package com.vinzscam.reactnativefileviewer; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import androidx.core.content.FileProvider; import android.webkit.MimeTypeMap; import com.facebook.react.bridge.ActivityEventListener; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.BaseActivityEventListener; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.WritableMap; import com.facebook.react.modules.core.DeviceEventManagerModule; import java.io.File; public class RNFileViewerModule extends ReactContextBaseJavaModule { private final ReactApplicationContext reactContext; private static final String SHOW_OPEN_WITH_DIALOG = "showOpenWithDialog" ; private static final String SHOW_STORE_SUGGESTIONS ="showAppsSuggestions"; private static final String OPEN_EVENT = "RNFileViewerDidOpen"; private static final String DISMISS_EVENT = "RNFileViewerDidDismiss"; private static final Integer RN_FILE_VIEWER_REQUEST = 33341; private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() { @Override public void onActivityResult(final Activity activity, final int requestCode, final int resultCode, final Intent intent) { sendEvent(DISMISS_EVENT, requestCode - RN_FILE_VIEWER_REQUEST, null); } }; public RNFileViewerModule(ReactApplicationContext reactContext) { super(reactContext); this.reactContext = reactContext; reactContext.addActivityEventListener(mActivityEventListener); } @ReactMethod public void open(String path, Integer currentId, ReadableMap options) { Uri contentUri = null; Boolean showOpenWithDialog = options.hasKey(SHOW_OPEN_WITH_DIALOG) ? options.getBoolean(SHOW_OPEN_WITH_DIALOG) : false; Boolean showStoreSuggestions = options.hasKey(SHOW_STORE_SUGGESTIONS) ? options.getBoolean(SHOW_STORE_SUGGESTIONS) : false; if(path.startsWith("content://")) { contentUri = Uri.parse(path); } else { File newFile = new File(path); try { final String packageName = getCurrentActivity().getPackageName(); final String authority = new StringBuilder(packageName).append(".provider").toString(); contentUri = FileProvider.getUriForFile(getCurrentActivity(), authority, newFile); } catch(IllegalArgumentException e) { sendEvent(OPEN_EVENT, currentId, e.getMessage()); return; } } if(contentUri == null) { sendEvent(OPEN_EVENT, currentId, "Invalid file"); return; } String extension = MimeTypeMap.getFileExtensionFromUrl(path).toLowerCase(); String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_VIEW); shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); shareIntent.setDataAndType(contentUri, mimeType); shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri); Intent intentActivity; if (showOpenWithDialog) { intentActivity = Intent.createChooser(shareIntent, "Open with"); } else { intentActivity = shareIntent; } PackageManager pm = getCurrentActivity().getPackageManager(); if (shareIntent.resolveActivity(pm) != null) { try { getCurrentActivity().startActivityForResult(intentActivity, currentId + RN_FILE_VIEWER_REQUEST); sendEvent(OPEN_EVENT, currentId, null); } catch(Exception e) { sendEvent(OPEN_EVENT, currentId, e.getMessage()); } } else { try { if (showStoreSuggestions) { if(mimeType == null) { throw new Exception("It wasn't possible to detect the type of the file"); } Intent storeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=" + mimeType + "&c=apps")); getCurrentActivity().startActivity(storeIntent); } throw new Exception("No app associated with this mime type"); } catch(Exception e) { sendEvent(OPEN_EVENT, currentId, e.getMessage()); } } } @Override public String getName() { return "RNFileViewer"; } private void sendEvent(String eventName, Integer currentId, String errorMessage) { WritableMap params = Arguments.createMap(); params.putInt("id", currentId); if(errorMessage != null) { params.putString("error", errorMessage); } reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params); } }