From adf060fec241bb42b845d9e477cffe72d19c4185 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Tue, 4 Jul 2017 16:10:55 +0200
Subject: [PATCH 01/21] Add audio, video sharing for android
---
.../alinz/parkerdan/shareextension/ShareModule.java | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java b/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
index e1aea2ce..117c2005 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
@@ -11,9 +11,11 @@
import android.content.Intent;
import android.net.Uri;
+
import android.graphics.Bitmap;
import java.io.InputStream;
-
+import java.util.HashSet;
+import java.util.Set;
public class ShareModule extends ReactContextBaseJavaModule {
@@ -39,10 +41,15 @@ public void data(Promise promise) {
public WritableMap processIntent() {
WritableMap map = Arguments.createMap();
+ Set mediaTypesSupported = new HashSet();
+ mediaTypesSupported.add("video");
+ mediaTypesSupported.add("audio");
+ mediaTypesSupported.add("image");
String value = "";
String type = "";
String action = "";
+ String typePart = "";
Activity currentActivity = getCurrentActivity();
@@ -52,11 +59,13 @@ public WritableMap processIntent() {
type = intent.getType();
if (type == null) {
type = "";
+ } else {
+ typePart = type.substring(0, type.indexOf('/'));
}
if (Intent.ACTION_SEND.equals(action) && "text/plain".equals(type)) {
value = intent.getStringExtra(Intent.EXTRA_TEXT);
}
- else if (Intent.ACTION_SEND.equals(action) && ("image/*".equals(type) || "image/jpeg".equals(type) || "image/png".equals(type) || "image/jpg".equals(type) ) ) {
+ else if (Intent.ACTION_SEND.equals(action) && (mediaTypesSupported.contains(typePart)) ) {
Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
value = "file://" + RealPathUtil.getRealPathFromURI(currentActivity, uri);
From 7a6c3e860c5af290c2a14f0b764bd49eb05e95d6 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Tue, 4 Jul 2017 16:11:16 +0200
Subject: [PATCH 02/21] Update example to make it work
---
.../android/app/src/main/java/com/sample1/MainApplication.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/Sample1/android/app/src/main/java/com/sample1/MainApplication.java b/examples/Sample1/android/app/src/main/java/com/sample1/MainApplication.java
index 19ffaa34..2df8d0e6 100644
--- a/examples/Sample1/android/app/src/main/java/com/sample1/MainApplication.java
+++ b/examples/Sample1/android/app/src/main/java/com/sample1/MainApplication.java
@@ -19,7 +19,7 @@ public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
- protected boolean getUseDeveloperSupport() {
+ public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
From b6ad992730d70152aeb243c81c4a11b893340fe5 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Tue, 4 Jul 2017 16:14:23 +0200
Subject: [PATCH 03/21] Update example and readme
---
README.md | 10 +++++++---
.../Sample1/android/app/src/main/AndroidManifest.xml | 9 ++++++++-
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 131c754e..80077682 100644
--- a/README.md
+++ b/README.md
@@ -254,7 +254,7 @@ public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
- protected boolean getUseDeveloperSupport() {
+ public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@@ -291,8 +291,12 @@ public class MainApplication extends Application implements ReactApplication {
// for sharing links include
- // for sharing photos include
-
+ // for sharing photos include
+
+ // for sharing videos include
+
+ // for sharing audio include
+
```
diff --git a/examples/Sample1/android/app/src/main/AndroidManifest.xml b/examples/Sample1/android/app/src/main/AndroidManifest.xml
index b20054a8..d51e29bd 100644
--- a/examples/Sample1/android/app/src/main/AndroidManifest.xml
+++ b/examples/Sample1/android/app/src/main/AndroidManifest.xml
@@ -35,7 +35,14 @@
-
+ // for sharing links include
+
+ // for sharing photos include
+
+ // for sharing videos include
+
+ // for sharing audio include
+
From bce70040fd73d8c7af51e2cb2b0b0a80a20be3e6 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Wed, 5 Jul 2017 17:02:28 +0200
Subject: [PATCH 04/21] Retrieve path from other apps
---
.../shareextension/RealPathUtil.java | 31 ++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
index c712e18a..57db6e3f 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
@@ -9,6 +9,10 @@
import android.content.ContentUris;
import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import java.io.*;
+import java.nio.channels.FileChannel;
+
public class RealPathUtil {
public static String getRealPathFromURI(final Context context, final Uri uri) {
@@ -66,8 +70,12 @@ else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
+ // try catch if no _data column in contentProvider
+ String path = getDataColumn(context, uri, null, null);
+ if (path != null) return path;
- return getDataColumn(context, uri, null, null);
+ // Try save to tmp file, and return tmp file path
+ return getPathFromSavingTempFile(context, uri);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
@@ -77,6 +85,25 @@ else if ("file".equalsIgnoreCase(uri.getScheme())) {
return null;
}
+ public static String getPathFromSavingTempFile(Context context, final Uri uri) {
+ File tmpFile;
+ try {
+ String fileName = uri.getLastPathSegment();
+ tmpFile = File.createTempFile("tmp", fileName, context.getCacheDir());
+
+ ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
+
+ FileChannel src = new FileInputStream(pfd.getFileDescriptor()).getChannel();
+ FileChannel dst = new FileOutputStream(tmpFile).getChannel();
+ dst.transferFrom(src, 0, src.size());
+ src.close();
+ dst.close();
+ } catch (IOException ex) {
+ return null;
+ }
+ return tmpFile.getAbsolutePath();
+ }
+
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
@@ -103,6 +130,8 @@ public static String getDataColumn(Context context, Uri uri, String selection,
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
+ } catch (Exception e) {
+ return null;
} finally {
if (cursor != null)
cursor.close();
From ce00a3f2b6d7a5b2665643e3b6882aa47e00c101 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Wed, 5 Jul 2017 18:08:47 +0200
Subject: [PATCH 05/21] Add SEND_MULTIPLE and return array for android
---
.../parkerdan/shareextension/ShareModule.java | 45 ++++++++++---------
1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java b/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
index 117c2005..b660a75a 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
@@ -5,17 +5,18 @@
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.Arguments;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
-
-
import android.graphics.Bitmap;
+
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
+import java.util.ArrayList;
public class ShareModule extends ReactContextBaseJavaModule {
@@ -39,14 +40,13 @@ public void data(Promise promise) {
promise.resolve(processIntent());
}
- public WritableMap processIntent() {
- WritableMap map = Arguments.createMap();
+ public WritableArray processIntent() {
+ WritableArray dataArrayMap = Arguments.createArray();
Set mediaTypesSupported = new HashSet();
mediaTypesSupported.add("video");
mediaTypesSupported.add("audio");
mediaTypesSupported.add("image");
- String value = "";
String type = "";
String action = "";
String typePart = "";
@@ -63,23 +63,28 @@ public WritableMap processIntent() {
typePart = type.substring(0, type.indexOf('/'));
}
if (Intent.ACTION_SEND.equals(action) && "text/plain".equals(type)) {
- value = intent.getStringExtra(Intent.EXTRA_TEXT);
+ WritableMap dataMap = Arguments.createMap();
+ dataMap.putString("type", type);
+ dataMap.putString("value", intent.getStringExtra(Intent.EXTRA_TEXT));
+ dataArrayMap.pushMap(dataMap);
}
- else if (Intent.ACTION_SEND.equals(action) && (mediaTypesSupported.contains(typePart)) ) {
+ else if (Intent.ACTION_SEND.equals(action) && (
+ mediaTypesSupported.contains(typePart)) ) {
+ WritableMap dataMap = Arguments.createMap();
+ dataMap.putString("type", type);
Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
- value = "file://" + RealPathUtil.getRealPathFromURI(currentActivity, uri);
-
- } else {
- value = "";
- }
- } else {
- value = "";
- type = "";
+ dataMap.putString("value", "file://" + RealPathUtil.getRealPathFromURI(currentActivity, uri));
+ dataArrayMap.pushMap(dataMap);
+ } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && mediaTypesSupported.contains(typePart)) {
+ ArrayList uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ for (Uri uri : uris) {
+ WritableMap dataMap = Arguments.createMap();
+ dataMap.putString("type", type);
+ dataMap.putString("value", "file://" + RealPathUtil.getRealPathFromURI(currentActivity, uri));
+ dataArrayMap.pushMap(dataMap);
+ }
+ }
}
-
- map.putString("type", type);
- map.putString("value",value);
-
- return map;
+ return dataArrayMap;
}
}
From d595c62ecfd25db729a8df364b281a0d2e22270f Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Wed, 5 Jul 2017 18:08:58 +0200
Subject: [PATCH 06/21] Update android example
---
examples/Sample1/share.android.js | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/examples/Sample1/share.android.js b/examples/Sample1/share.android.js
index 54803f0b..06a8571e 100644
--- a/examples/Sample1/share.android.js
+++ b/examples/Sample1/share.android.js
@@ -5,12 +5,13 @@
import React, { Component } from 'react'
import Modal from 'react-native-modalbox'
-import ShareExtension from 'react-native-share-extension'
+import ShareExtension from './react-native-share-extension'
import {
Text,
TextInput,
View,
+ Image,
TouchableOpacity
} from 'react-native'
@@ -19,17 +20,15 @@ export default class Share extends Component {
super(props, context)
this.state = {
isOpen: true,
- type: '',
- value: ''
+ data: [],
}
}
async componentDidMount() {
try {
- const { type, value } = await ShareExtension.data()
+ const data = await ShareExtension.data();
this.setState({
- type,
- value
+ data,
})
} catch(e) {
console.log('errrr', e)
@@ -45,8 +44,17 @@ export default class Share extends Component {
isOpen: false
})
}
+ renderData(data, index) {
+ return (
+
+ type: { data.type }
+ value: { data.value }
+
+ );
+ }
render() {
+ const dataComponent = this.state.data.map(this.renderData);
return (
@@ -54,8 +62,7 @@ export default class Share extends Component {
Close
- type: { this.state.type }
- value: { this.state.value }
+ {dataComponent}
From f49b63cf257659b5967baf2ed3c6a13bc0ea49dc Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Wed, 5 Jul 2017 18:10:36 +0200
Subject: [PATCH 07/21] Update Readme and example
---
README.md | 1 +
examples/Sample1/android/app/src/main/AndroidManifest.xml | 1 +
2 files changed, 2 insertions(+)
diff --git a/README.md b/README.md
index 80077682..a71d796f 100644
--- a/README.md
+++ b/README.md
@@ -288,6 +288,7 @@ public class MainApplication extends Application implements ReactApplication {
android:theme="@style/Theme.Share.Transparent" >
+
// for sharing links include
diff --git a/examples/Sample1/android/app/src/main/AndroidManifest.xml b/examples/Sample1/android/app/src/main/AndroidManifest.xml
index d51e29bd..2eaa119e 100644
--- a/examples/Sample1/android/app/src/main/AndroidManifest.xml
+++ b/examples/Sample1/android/app/src/main/AndroidManifest.xml
@@ -34,6 +34,7 @@
android:theme="@style/Theme.Share.Transparent" >
+
// for sharing links include
From 27cef78bd1fec385b4108e76f265ccfe4916a63e Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Tue, 11 Jul 2017 15:02:55 +0200
Subject: [PATCH 08/21] Reindent properly two Java files
---
.../shareextension/RealPathUtil.java | 311 +++++++++---------
.../parkerdan/shareextension/ShareModule.java | 105 +++---
2 files changed, 208 insertions(+), 208 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
index 57db6e3f..59a41c2a 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
@@ -10,166 +10,167 @@
import android.os.Environment;
import android.os.ParcelFileDescriptor;
+
import java.io.*;
import java.nio.channels.FileChannel;
public class RealPathUtil {
- public static String getRealPathFromURI(final Context context, final Uri uri) {
-
- final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
-
- // DocumentProvider
- if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
- // ExternalStorageProvider
- if (isExternalStorageDocument(uri)) {
- final String docId = DocumentsContract.getDocumentId(uri);
- final String[] split = docId.split(":");
- final String type = split[0];
-
- if ("primary".equalsIgnoreCase(type)) {
- return Environment.getExternalStorageDirectory() + "/" + split[1];
- }
-
- // TODO handle non-primary volumes
- }
- // DownloadsProvider
- else if (isDownloadsDocument(uri)) {
-
- final String id = DocumentsContract.getDocumentId(uri);
- final Uri contentUri = ContentUris.withAppendedId(
- Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
-
- return getDataColumn(context, contentUri, null, null);
- }
- // MediaProvider
- else if (isMediaDocument(uri)) {
- final String docId = DocumentsContract.getDocumentId(uri);
- final String[] split = docId.split(":");
- final String type = split[0];
-
- Uri contentUri = null;
- if ("image".equals(type)) {
- contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- } else if ("video".equals(type)) {
- contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- } else if ("audio".equals(type)) {
- contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- }
-
- final String selection = "_id=?";
- final String[] selectionArgs = new String[] {
- split[1]
- };
-
- return getDataColumn(context, contentUri, selection, selectionArgs);
- }
- }
- // MediaStore (and general)
- else if ("content".equalsIgnoreCase(uri.getScheme())) {
-
- // Return the remote address
- if (isGooglePhotosUri(uri))
- return uri.getLastPathSegment();
- // try catch if no _data column in contentProvider
- String path = getDataColumn(context, uri, null, null);
- if (path != null) return path;
-
- // Try save to tmp file, and return tmp file path
- return getPathFromSavingTempFile(context, uri);
- }
- // File
- else if ("file".equalsIgnoreCase(uri.getScheme())) {
- return uri.getPath();
- }
-
- return null;
- }
-
- public static String getPathFromSavingTempFile(Context context, final Uri uri) {
- File tmpFile;
- try {
- String fileName = uri.getLastPathSegment();
- tmpFile = File.createTempFile("tmp", fileName, context.getCacheDir());
-
- ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
-
- FileChannel src = new FileInputStream(pfd.getFileDescriptor()).getChannel();
- FileChannel dst = new FileOutputStream(tmpFile).getChannel();
- dst.transferFrom(src, 0, src.size());
- src.close();
- dst.close();
- } catch (IOException ex) {
+ public static String getRealPathFromURI(final Context context, final Uri uri) {
+
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+
+ // DocumentProvider
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ // ExternalStorageProvider
+ if (isExternalStorageDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ if ("primary".equalsIgnoreCase(type)) {
+ return Environment.getExternalStorageDirectory() + "/" + split[1];
+ }
+
+ // TODO handle non-primary volumes
+ }
+ // DownloadsProvider
+ else if (isDownloadsDocument(uri)) {
+
+ final String id = DocumentsContract.getDocumentId(uri);
+ final Uri contentUri = ContentUris.withAppendedId(
+ Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
+
+ return getDataColumn(context, contentUri, null, null);
+ }
+ // MediaProvider
+ else if (isMediaDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ Uri contentUri = null;
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ } else if ("video".equals(type)) {
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ } else if ("audio".equals(type)) {
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ }
+
+ final String selection = "_id=?";
+ final String[] selectionArgs = new String[]{
+ split[1]
+ };
+
+ return getDataColumn(context, contentUri, selection, selectionArgs);
+ }
+ }
+ // MediaStore (and general)
+ else if ("content".equalsIgnoreCase(uri.getScheme())) {
+
+ // Return the remote address
+ if (isGooglePhotosUri(uri))
+ return uri.getLastPathSegment();
+ // try catch if no _data column in contentProvider
+ String path = getDataColumn(context, uri, null, null);
+ if (path != null) return path;
+
+ // Try save to tmp file, and return tmp file path
+ return getPathFromSavingTempFile(context, uri);
+ }
+ // File
+ else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+
+ return null;
+ }
+
+ public static String getPathFromSavingTempFile(Context context, final Uri uri) {
+ File tmpFile;
+ try {
+ String fileName = uri.getLastPathSegment();
+ tmpFile = File.createTempFile("tmp", fileName, context.getCacheDir());
+
+ ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
+
+ FileChannel src = new FileInputStream(pfd.getFileDescriptor()).getChannel();
+ FileChannel dst = new FileOutputStream(tmpFile).getChannel();
+ dst.transferFrom(src, 0, src.size());
+ src.close();
+ dst.close();
+ } catch (IOException ex) {
+ return null;
+ }
+ return tmpFile.getAbsolutePath();
+ }
+
+ /**
+ * Get the value of the data column for this Uri. This is useful for
+ * MediaStore Uris, and other file-based ContentProviders.
+ *
+ * @param context The context.
+ * @param uri The Uri to query.
+ * @param selection (Optional) Filter used in the query.
+ * @param selectionArgs (Optional) Selection arguments used in the query.
+ * @return The value of the _data column, which is typically a file path.
+ */
+ public static String getDataColumn(Context context, Uri uri, String selection,
+ String[] selectionArgs) {
+
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = {
+ column
+ };
+
+ try {
+ cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
+ null);
+ if (cursor != null && cursor.moveToFirst()) {
+ final int index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(index);
+ }
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
return null;
}
- return tmpFile.getAbsolutePath();
- }
-
- /**
- * Get the value of the data column for this Uri. This is useful for
- * MediaStore Uris, and other file-based ContentProviders.
- *
- * @param context The context.
- * @param uri The Uri to query.
- * @param selection (Optional) Filter used in the query.
- * @param selectionArgs (Optional) Selection arguments used in the query.
- * @return The value of the _data column, which is typically a file path.
- */
- public static String getDataColumn(Context context, Uri uri, String selection,
- String[] selectionArgs) {
-
- Cursor cursor = null;
- final String column = "_data";
- final String[] projection = {
- column
- };
-
- try {
- cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
- null);
- if (cursor != null && cursor.moveToFirst()) {
- final int index = cursor.getColumnIndexOrThrow(column);
- return cursor.getString(index);
- }
- } catch (Exception e) {
- return null;
- } finally {
- if (cursor != null)
- cursor.close();
- }
- return null;
- }
-
-
- /**
- * @param uri The Uri to check.
- * @return Whether the Uri authority is ExternalStorageProvider.
- */
- public static boolean isExternalStorageDocument(Uri uri) {
- return "com.android.externalstorage.documents".equals(uri.getAuthority());
- }
-
- /**
- * @param uri The Uri to check.
- * @return Whether the Uri authority is DownloadsProvider.
- */
- public static boolean isDownloadsDocument(Uri uri) {
- return "com.android.providers.downloads.documents".equals(uri.getAuthority());
- }
-
- /**
- * @param uri The Uri to check.
- * @return Whether the Uri authority is MediaProvider.
- */
- public static boolean isMediaDocument(Uri uri) {
- return "com.android.providers.media.documents".equals(uri.getAuthority());
- }
-
- /**
- * @param uri The Uri to check.
- * @return Whether the Uri authority is Google Photos.
- */
- public static boolean isGooglePhotosUri(Uri uri) {
- return "com.google.android.apps.photos.content".equals(uri.getAuthority());
- }
+
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is ExternalStorageProvider.
+ */
+ public static boolean isExternalStorageDocument(Uri uri) {
+ return "com.android.externalstorage.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is DownloadsProvider.
+ */
+ public static boolean isDownloadsDocument(Uri uri) {
+ return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is MediaProvider.
+ */
+ public static boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is Google Photos.
+ */
+ public static boolean isGooglePhotosUri(Uri uri) {
+ return "com.google.android.apps.photos.content".equals(uri.getAuthority());
+ }
}
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java b/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
index b660a75a..a27483a0 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/ShareModule.java
@@ -21,70 +21,69 @@
public class ShareModule extends ReactContextBaseJavaModule {
- public ShareModule(ReactApplicationContext reactContext) {
- super(reactContext);
- }
+ public ShareModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
- @Override
- public String getName() {
- return "ReactNativeShareExtension";
- }
+ @Override
+ public String getName() {
+ return "ReactNativeShareExtension";
+ }
- @ReactMethod
- public void close() {
- getCurrentActivity().finish();
- }
+ @ReactMethod
+ public void close() {
+ getCurrentActivity().finish();
+ }
- @ReactMethod
- public void data(Promise promise) {
- promise.resolve(processIntent());
- }
+ @ReactMethod
+ public void data(Promise promise) {
+ promise.resolve(processIntent());
+ }
- public WritableArray processIntent() {
- WritableArray dataArrayMap = Arguments.createArray();
- Set mediaTypesSupported = new HashSet();
- mediaTypesSupported.add("video");
- mediaTypesSupported.add("audio");
- mediaTypesSupported.add("image");
+ public WritableArray processIntent() {
+ WritableArray dataArrayMap = Arguments.createArray();
+ Set mediaTypesSupported = new HashSet();
+ mediaTypesSupported.add("video");
+ mediaTypesSupported.add("audio");
+ mediaTypesSupported.add("image");
- String type = "";
- String action = "";
- String typePart = "";
+ String type = "";
+ String action = "";
+ String typePart = "";
- Activity currentActivity = getCurrentActivity();
+ Activity currentActivity = getCurrentActivity();
- if (currentActivity != null) {
- Intent intent = currentActivity.getIntent();
- action = intent.getAction();
- type = intent.getType();
- if (type == null) {
- type = "";
- } else {
- typePart = type.substring(0, type.indexOf('/'));
- }
- if (Intent.ACTION_SEND.equals(action) && "text/plain".equals(type)) {
- WritableMap dataMap = Arguments.createMap();
- dataMap.putString("type", type);
- dataMap.putString("value", intent.getStringExtra(Intent.EXTRA_TEXT));
- dataArrayMap.pushMap(dataMap);
- }
- else if (Intent.ACTION_SEND.equals(action) && (
- mediaTypesSupported.contains(typePart)) ) {
- WritableMap dataMap = Arguments.createMap();
- dataMap.putString("type", type);
- Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
- dataMap.putString("value", "file://" + RealPathUtil.getRealPathFromURI(currentActivity, uri));
- dataArrayMap.pushMap(dataMap);
- } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && mediaTypesSupported.contains(typePart)) {
- ArrayList uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
- for (Uri uri : uris) {
+ if (currentActivity != null) {
+ Intent intent = currentActivity.getIntent();
+ action = intent.getAction();
+ type = intent.getType();
+ if (type == null) {
+ type = "";
+ } else {
+ typePart = type.substring(0, type.indexOf('/'));
+ }
+ if (Intent.ACTION_SEND.equals(action) && "text/plain".equals(type)) {
+ WritableMap dataMap = Arguments.createMap();
+ dataMap.putString("type", type);
+ dataMap.putString("value", intent.getStringExtra(Intent.EXTRA_TEXT));
+ dataArrayMap.pushMap(dataMap);
+ } else if (Intent.ACTION_SEND.equals(action) && (
+ mediaTypesSupported.contains(typePart))) {
WritableMap dataMap = Arguments.createMap();
dataMap.putString("type", type);
+ Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
dataMap.putString("value", "file://" + RealPathUtil.getRealPathFromURI(currentActivity, uri));
dataArrayMap.pushMap(dataMap);
+ } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && mediaTypesSupported.contains(typePart)) {
+ ArrayList uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+ for (Uri uri : uris) {
+ WritableMap dataMap = Arguments.createMap();
+ dataMap.putString("type", type);
+ dataMap.putString("value", "file://" + RealPathUtil.getRealPathFromURI(currentActivity, uri));
+ dataArrayMap.pushMap(dataMap);
+ }
}
}
- }
- return dataArrayMap;
- }
+ return dataArrayMap;
+ }
}
From fbd9ceab8ab8d2e9d52225a9aac03507e3ace4a2 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Wed, 16 Aug 2017 10:28:45 +0200
Subject: [PATCH 09/21] Remove non-used createJSModules (RN 0.47)
---
.../java/com/alinz/parkerdan/shareextension/SharePackage.java | 4 ----
.../alinz/reactNativeShareExtension/ShareExPackage.java | 4 ----
2 files changed, 8 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/SharePackage.java b/android/src/main/java/com/alinz/parkerdan/shareextension/SharePackage.java
index 3e168353..b23a6dfa 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/SharePackage.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/SharePackage.java
@@ -16,10 +16,6 @@ public List createNativeModules(ReactApplicationContext reactConte
return Arrays.asList(new ShareModule(reactContext));
}
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
diff --git a/android/src/main/java/com/github/alinz/reactNativeShareExtension/ShareExPackage.java b/android/src/main/java/com/github/alinz/reactNativeShareExtension/ShareExPackage.java
index f21656c3..485c87c5 100644
--- a/android/src/main/java/com/github/alinz/reactNativeShareExtension/ShareExPackage.java
+++ b/android/src/main/java/com/github/alinz/reactNativeShareExtension/ShareExPackage.java
@@ -17,10 +17,6 @@ public List createNativeModules(ReactApplicationContext reactConte
return Arrays.asList(new ShareExModule(reactContext));
}
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
@Override
public List createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
From 25737ada7dffe28cd708257104bef02bed97a5ec Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Fri, 2 Mar 2018 16:11:44 +0100
Subject: [PATCH 10/21] keep image orientation in temp file saved
---
ios/ReactNativeShareExtension.m | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/ios/ReactNativeShareExtension.m b/ios/ReactNativeShareExtension.m
index 53246ca2..0f5983a3 100644
--- a/ios/ReactNativeShareExtension.m
+++ b/ios/ReactNativeShareExtension.m
@@ -60,7 +60,7 @@ - (void)viewDidLoad {
}
- (void)extractDataFromContext:(NSExtensionContext *)context withCallback:(void(^)(NSString *value, NSString* contentType, NSException *exception))callback {
-
+
@try {
NSExtensionItem *item = [context.inputItems firstObject];
NSArray *attachments = item.attachments;
@@ -92,7 +92,7 @@ - (void)extractDataFromContext:(NSExtensionContext *)context withCallback:(void(
}];
} else if (imageProvider) {
[imageProvider loadItemForTypeIdentifier:IMAGE_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
-
+
/**
* Save the image to NSTemporaryDirectory(), which cleans itself tri-daily.
* This is necessary as the iOS 11 screenshot editor gives us a UIImage, while
@@ -100,11 +100,11 @@ - (void)extractDataFromContext:(NSExtensionContext *)context withCallback:(void(
* Therefore the solution is to save a UIImage, either way, and return the local path to that temp UIImage
* This path will be sent to React Native and can be processed and accessed RN side.
**/
-
+
UIImage *sharedImage;
NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"RNSE_TEMP_IMG"];
NSString *fullPath = [filePath stringByAppendingPathExtension:@"png"];
-
+
if ([(NSObject *)item isKindOfClass:[UIImage class]]){
sharedImage = (UIImage *)item;
}else if ([(NSObject *)item isKindOfClass:[NSURL class]]){
@@ -112,9 +112,9 @@ - (void)extractDataFromContext:(NSExtensionContext *)context withCallback:(void(
NSData *data = [NSData dataWithContentsOfURL:url];
sharedImage = [UIImage imageWithData:data];
}
-
- [UIImagePNGRepresentation(sharedImage) writeToFile:fullPath atomically:YES];
-
+
+ [UIImageJPEGRepresentation(sharedImage, 1.0) writeToFile:filePath atomically:YES];
+
if(callback) {
callback(fullPath, [fullPath pathExtension], nil);
}
From f76c216f00cae9c1027f60f47b1ddffa9f4a1d4f Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Fri, 2 Mar 2018 16:12:22 +0100
Subject: [PATCH 11/21] Enable sharing multi content
---
ios/ReactNativeShareExtension.m | 134 +++++++++++++++++---------------
1 file changed, 70 insertions(+), 64 deletions(-)
diff --git a/ios/ReactNativeShareExtension.m b/ios/ReactNativeShareExtension.m
index 0f5983a3..d872ed46 100644
--- a/ios/ReactNativeShareExtension.m
+++ b/ios/ReactNativeShareExtension.m
@@ -47,99 +47,105 @@ - (void)viewDidLoad {
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
- [self extractDataFromContext: extensionContext withCallback:^(NSString* val, NSString* contentType, NSException* err) {
+ [self extractDataFromContext: extensionContext withCallback:^(NSArray* items, NSException* err) {
if(err) {
reject(@"error", err.description, nil);
} else {
- resolve(@{
- @"type": contentType,
- @"value": val
- });
+ resolve(items);
}
}];
}
-- (void)extractDataFromContext:(NSExtensionContext *)context withCallback:(void(^)(NSString *value, NSString* contentType, NSException *exception))callback {
-
+- (void)extractDataFromContext:(NSExtensionContext *)context withCallback:(void(^)(NSArray *items, NSException *exception))callback {
@try {
+ __block NSMutableArray *itemArray = [NSMutableArray new];
NSExtensionItem *item = [context.inputItems firstObject];
+
NSArray *attachments = item.attachments;
__block NSItemProvider *urlProvider = nil;
__block NSItemProvider *imageProvider = nil;
__block NSItemProvider *textProvider = nil;
+ __block NSUInteger index = 0;
[attachments enumerateObjectsUsingBlock:^(NSItemProvider *provider, NSUInteger idx, BOOL *stop) {
if([provider hasItemConformingToTypeIdentifier:URL_IDENTIFIER]) {
urlProvider = provider;
- *stop = YES;
+ index += 1;
+ [urlProvider loadItemForTypeIdentifier:URL_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
+ NSURL *url = (NSURL *)item;
+ [itemArray addObject: @{
+ @"type": @"text/plain",
+ @"value": [url absoluteString]
+ }];
+ if (callback && (index == [attachments count])) {
+ callback(itemArray, nil);
+ }
+ }];
} else if ([provider hasItemConformingToTypeIdentifier:TEXT_IDENTIFIER]){
textProvider = provider;
- *stop = YES;
+ [textProvider loadItemForTypeIdentifier:TEXT_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
+ NSString *text = (NSString *)item;
+ index += 1;
+ [itemArray addObject: @{
+ @"type": @"text/plain",
+ @"value": text
+ }];
+ if (callback && (index == [attachments count])) {
+ callback(itemArray, nil);
+ }
+ }];
} else if ([provider hasItemConformingToTypeIdentifier:IMAGE_IDENTIFIER]){
imageProvider = provider;
- *stop = YES;
+ [imageProvider loadItemForTypeIdentifier:IMAGE_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
+ /**
+ * Save the image to NSTemporaryDirectory(), which cleans itself tri-daily.
+ * This is necessary as the iOS 11 screenshot editor gives us a UIImage, while
+ * sharing from Photos and similar apps gives us a URL
+ * Therefore the solution is to save a UIImage, either way, and return the local path to that temp UIImage
+ * This path will be sent to React Native and can be processed and accessed RN side.
+ **/
+
+ UIImage *sharedImage;
+ NSString *filename;
+
+ if ([(NSObject *)item isKindOfClass:[UIImage class]]){
+ sharedImage = (UIImage *)item;
+ NSString *name = @"RNSE_TEMP_IMG_";
+ NSString *nbFiles = [NSString stringWithFormat:@"%@", @(index)];
+ NSString *fullname = [name stringByAppendingString:(nbFiles)];
+ filename = [fullname stringByAppendingPathExtension:@"png"];
+ }else if ([(NSObject *)item isKindOfClass:[NSURL class]]){
+ NSURL* url = (NSURL *)item;
+ filename = [[url lastPathComponent] lowercaseString];
+ NSData *data = [NSData dataWithContentsOfURL:url];
+ sharedImage = [UIImage imageWithData:data];
+ }
+ NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
+
+ [UIImageJPEGRepresentation(sharedImage, 1.0) writeToFile:filePath atomically:YES];
+ index += 1;
+
+ [itemArray addObject: @{
+ @"type": [filePath pathExtension],
+ @"value": filePath
+ }];
+ if (callback && (index == [attachments count])) {
+ callback(itemArray, nil);
+ }
+
+ }];
+ } else {
+ index += 1;
}
}];
-
- if(urlProvider) {
- [urlProvider loadItemForTypeIdentifier:URL_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
- NSURL *url = (NSURL *)item;
-
- if(callback) {
- callback([url absoluteString], @"text/plain", nil);
- }
- }];
- } else if (imageProvider) {
- [imageProvider loadItemForTypeIdentifier:IMAGE_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
-
- /**
- * Save the image to NSTemporaryDirectory(), which cleans itself tri-daily.
- * This is necessary as the iOS 11 screenshot editor gives us a UIImage, while
- * sharing from Photos and similar apps gives us a URL
- * Therefore the solution is to save a UIImage, either way, and return the local path to that temp UIImage
- * This path will be sent to React Native and can be processed and accessed RN side.
- **/
-
- UIImage *sharedImage;
- NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"RNSE_TEMP_IMG"];
- NSString *fullPath = [filePath stringByAppendingPathExtension:@"png"];
-
- if ([(NSObject *)item isKindOfClass:[UIImage class]]){
- sharedImage = (UIImage *)item;
- }else if ([(NSObject *)item isKindOfClass:[NSURL class]]){
- NSURL* url = (NSURL *)item;
- NSData *data = [NSData dataWithContentsOfURL:url];
- sharedImage = [UIImage imageWithData:data];
- }
-
- [UIImageJPEGRepresentation(sharedImage, 1.0) writeToFile:filePath atomically:YES];
-
- if(callback) {
- callback(fullPath, [fullPath pathExtension], nil);
- }
- }];
- } else if (textProvider) {
- [textProvider loadItemForTypeIdentifier:TEXT_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
- NSString *text = (NSString *)item;
-
- if(callback) {
- callback(text, @"text/plain", nil);
- }
- }];
- } else {
- if(callback) {
- callback(nil, nil, [NSException exceptionWithName:@"Error" reason:@"couldn't find provider" userInfo:nil]);
- }
- }
+ // }
}
@catch (NSException *exception) {
if(callback) {
- callback(nil, nil, exception);
+ callback(nil, exception);
}
}
}
-
-
@end
From f8c941516f4e51f059a5015fd67e95d5b19ad4a2 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Fri, 2 Mar 2018 17:11:44 +0100
Subject: [PATCH 12/21] Update example and readme
---
README.md | 20 +++++-
examples/Sample1/share.ios.js | 63 -------------------
.../Sample1/{share.android.js => share.js} | 2 +-
3 files changed, 18 insertions(+), 67 deletions(-)
delete mode 100644 examples/Sample1/share.ios.js
rename examples/Sample1/{share.android.js => share.js} (99%)
diff --git a/README.md b/README.md
index 4192b921..e9367fef 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,14 @@ This is a helper module which brings react native as an engine to drive share ex
+# Features
+- You can share within your app:
+ - a list of images,
+ - text
+ - url
+ - messages (from whatsapp for instance, we get either the text or the image)
+- Return an array like `[{type, value}]`
+
# Installation
Installation should be very easy by just installing it from npm.
@@ -148,15 +156,21 @@ RCT_EXPORT_MODULE();
# Set the NSExtensionActivationRule key in your Info.plist
-For the time being, this package only handles sharing of urls specifically from browsers. In order to tell the system to show your extension only when sharing a url, you must set the `NSExtensionActivationRule` key (under `NSExtensionAttributes`) in the share extension's Info.plist file as follows (this is also needed to pass Apple's reveiw):
+For the time being, this package handles sharing of urls, text or images. In order to tell the system to show your extension only when type is supported, you must set the `NSExtensionActivationRule` key (under `NSExtensionAttributes`) in the share extension's Info.plist file as follows (this is also needed to pass Apple's review):
```
NSExtensionAttributes
NSExtensionActivationRule
- NSExtensionActivationSupportsWebURLWithMaxCount
- 1
+ NSExtensionActivationSupportsImageWithMaxCount
+ 2
+ NSExtensionActivationSupportsMovieWithMaxCount
+ 0
+ NSExtensionActivationSupportsText
+
+ NSExtensionActivationSupportsWebURLWithMaxCount
+ 1
```
diff --git a/examples/Sample1/share.ios.js b/examples/Sample1/share.ios.js
deleted file mode 100644
index 5a2acf14..00000000
--- a/examples/Sample1/share.ios.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Sample React Native Share Extension
- * @flow
- */
-
-import React, { Component } from 'react'
-import Modal from 'react-native-modalbox'
-import ShareExtension from 'react-native-share-extension'
-
-import {
- Text,
- View,
- TouchableOpacity
-} from 'react-native'
-
-export default class Share extends Component {
- constructor(props, context) {
- super(props, context)
- this.state = {
- isOpen: true,
- type: '',
- value: ''
- }
- }
-
- async componentDidMount() {
- try {
- const { type, value } = await ShareExtension.data()
- this.setState({
- type,
- value
- })
- } catch(e) {
- console.log('errrr', e)
- }
- }
-
- onClose = () => ShareExtension.close()
-
- closing = () => this.setState({ isOpen: false });
-
- render() {
- return (
-
-
-
-
- Close
- type: { this.state.type }
- value: { this.state.value }
-
-
-
-
- );
- }
-}
diff --git a/examples/Sample1/share.android.js b/examples/Sample1/share.js
similarity index 99%
rename from examples/Sample1/share.android.js
rename to examples/Sample1/share.js
index 06a8571e..bd233bfe 100644
--- a/examples/Sample1/share.android.js
+++ b/examples/Sample1/share.js
@@ -28,7 +28,7 @@ export default class Share extends Component {
try {
const data = await ShareExtension.data();
this.setState({
- data,
+ data
})
} catch(e) {
console.log('errrr', e)
From ebdeec7372aeac1f39d025fcde06960e3dd64662 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Mon, 12 Mar 2018 14:55:18 +0100
Subject: [PATCH 13/21] Get IMAGE_IDENTIFIER first in case we get a path
---
ios/ReactNativeShareExtension.m | 54 ++++++++++++++++-----------------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/ios/ReactNativeShareExtension.m b/ios/ReactNativeShareExtension.m
index d872ed46..3556ae8f 100644
--- a/ios/ReactNativeShareExtension.m
+++ b/ios/ReactNativeShareExtension.m
@@ -69,33 +69,7 @@ - (void)extractDataFromContext:(NSExtensionContext *)context withCallback:(void(
__block NSUInteger index = 0;
[attachments enumerateObjectsUsingBlock:^(NSItemProvider *provider, NSUInteger idx, BOOL *stop) {
- if([provider hasItemConformingToTypeIdentifier:URL_IDENTIFIER]) {
- urlProvider = provider;
- index += 1;
- [urlProvider loadItemForTypeIdentifier:URL_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
- NSURL *url = (NSURL *)item;
- [itemArray addObject: @{
- @"type": @"text/plain",
- @"value": [url absoluteString]
- }];
- if (callback && (index == [attachments count])) {
- callback(itemArray, nil);
- }
- }];
- } else if ([provider hasItemConformingToTypeIdentifier:TEXT_IDENTIFIER]){
- textProvider = provider;
- [textProvider loadItemForTypeIdentifier:TEXT_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
- NSString *text = (NSString *)item;
- index += 1;
- [itemArray addObject: @{
- @"type": @"text/plain",
- @"value": text
- }];
- if (callback && (index == [attachments count])) {
- callback(itemArray, nil);
- }
- }];
- } else if ([provider hasItemConformingToTypeIdentifier:IMAGE_IDENTIFIER]){
+ if ([provider hasItemConformingToTypeIdentifier:IMAGE_IDENTIFIER]){
imageProvider = provider;
[imageProvider loadItemForTypeIdentifier:IMAGE_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
/**
@@ -135,6 +109,32 @@ - (void)extractDataFromContext:(NSExtensionContext *)context withCallback:(void(
}
}];
+ } else if([provider hasItemConformingToTypeIdentifier:URL_IDENTIFIER]) {
+ urlProvider = provider;
+ index += 1;
+ [urlProvider loadItemForTypeIdentifier:URL_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
+ NSURL *url = (NSURL *)item;
+ [itemArray addObject: @{
+ @"type": @"text/plain",
+ @"value": [url absoluteString]
+ }];
+ if (callback && (index == [attachments count])) {
+ callback(itemArray, nil);
+ }
+ }];
+ } else if ([provider hasItemConformingToTypeIdentifier:TEXT_IDENTIFIER]){
+ textProvider = provider;
+ [textProvider loadItemForTypeIdentifier:TEXT_IDENTIFIER options:nil completionHandler:^(id item, NSError *error) {
+ NSString *text = (NSString *)item;
+ index += 1;
+ [itemArray addObject: @{
+ @"type": @"text/plain",
+ @"value": text
+ }];
+ if (callback && (index == [attachments count])) {
+ callback(itemArray, nil);
+ }
+ }];
} else {
index += 1;
}
From dd69a60fb08f3cff21e5ed200bb547aca9e76a82 Mon Sep 17 00:00:00 2001
From: AudreyBramy
Date: Wed, 12 Sep 2018 15:29:28 +0200
Subject: [PATCH 14/21] Upgrade compileSdk and buildTools version
# |-------- 50 characters for the title --------|
# If applied, this commit will...
# |----------------- 72 characters for the body ----------------------|
# Why is this change needed? How do you solve it ?
---
android/build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/android/build.gradle b/android/build.gradle
index 0ec7bf23..fbb26960 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -11,8 +11,8 @@ buildscript {
apply plugin: 'com.android.library'
android {
- compileSdkVersion 23
- buildToolsVersion "23.0.1"
+ compileSdkVersion 26
+ buildToolsVersion "26.0.3"
defaultConfig {
minSdkVersion 16
From 57de8db134ffe7fbad7b3b9ea31b261e72329713 Mon Sep 17 00:00:00 2001
From: AudreyBramy
Date: Wed, 12 Sep 2018 15:36:59 +0200
Subject: [PATCH 15/21] Upgrade compileSdk and buildTools version
# |-------- 50 characters for the title --------|
# If applied, this commit will...
# |----------------- 72 characters for the body ----------------------|
# Why is this change needed? How do you solve it ?
---
android/build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/android/build.gradle b/android/build.gradle
index 0ec7bf23..fbb26960 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -11,8 +11,8 @@ buildscript {
apply plugin: 'com.android.library'
android {
- compileSdkVersion 23
- buildToolsVersion "23.0.1"
+ compileSdkVersion 26
+ buildToolsVersion "26.0.3"
defaultConfig {
minSdkVersion 16
From 94017b77276a84ee5c23708b1168c720456ccc36 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Wed, 19 Sep 2018 11:11:49 +0200
Subject: [PATCH 16/21] Update build.gradle
---
android/build.gradle | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/android/build.gradle b/android/build.gradle
index fbb26960..fe8a69e2 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,3 +1,7 @@
+def safeExtGet(prop, fallback) {
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
+}
+
buildscript {
repositories {
jcenter()
@@ -11,12 +15,12 @@ buildscript {
apply plugin: 'com.android.library'
android {
- compileSdkVersion 26
- buildToolsVersion "26.0.3"
+ compileSdkVersion safeExtGet('compileSdkVersion', 23)
+ buildToolsVersion safeExtGet('buildToolsVersion', "23.0.1")
defaultConfig {
- minSdkVersion 16
- targetSdkVersion 22
+ minSdkVersion safeExtGet('minSdkVersion', 16)
+ targetSdkVersion safeExtGet('targetSdkVersion', 22)
versionCode 1
versionName "1.0"
}
From f747bc6766fa5f59a4798e68e6aa91c2d8e9bbe1 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Mon, 12 Nov 2018 12:01:40 +0100
Subject: [PATCH 17/21] Fix error in resolving conflicts in merge
---
.../shareextension/RealPathUtil.java | 166 ------------------
1 file changed, 166 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
index 44f945c9..5f6015fe 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
@@ -9,171 +9,6 @@
import android.content.ContentUris;
import android.os.Environment;
-<<<<<<< HEAD
-import android.os.ParcelFileDescriptor;
-
-import java.io.*;
-import java.nio.channels.FileChannel;
-
-public class RealPathUtil {
- public static String getRealPathFromURI(final Context context, final Uri uri) {
-
- final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
-
- // DocumentProvider
- if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
- // ExternalStorageProvider
- if (isExternalStorageDocument(uri)) {
- final String docId = DocumentsContract.getDocumentId(uri);
- final String[] split = docId.split(":");
- final String type = split[0];
-
- if ("primary".equalsIgnoreCase(type)) {
- return Environment.getExternalStorageDirectory() + "/" + split[1];
- }
-
- // TODO handle non-primary volumes
- }
- // DownloadsProvider
- else if (isDownloadsDocument(uri)) {
-
- final String id = DocumentsContract.getDocumentId(uri);
- final Uri contentUri = ContentUris.withAppendedId(
- Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
-
- return getDataColumn(context, contentUri, null, null);
- }
- // MediaProvider
- else if (isMediaDocument(uri)) {
- final String docId = DocumentsContract.getDocumentId(uri);
- final String[] split = docId.split(":");
- final String type = split[0];
-
- Uri contentUri = null;
- if ("image".equals(type)) {
- contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- } else if ("video".equals(type)) {
- contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- } else if ("audio".equals(type)) {
- contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- }
-
- final String selection = "_id=?";
- final String[] selectionArgs = new String[]{
- split[1]
- };
-
- return getDataColumn(context, contentUri, selection, selectionArgs);
- }
- }
- // MediaStore (and general)
- else if ("content".equalsIgnoreCase(uri.getScheme())) {
-
- // Return the remote address
- if (isGooglePhotosUri(uri))
- return uri.getLastPathSegment();
- // try catch if no _data column in contentProvider
- String path = getDataColumn(context, uri, null, null);
- if (path != null) return path;
-
- // Try save to tmp file, and return tmp file path
- return getPathFromSavingTempFile(context, uri);
- }
- // File
- else if ("file".equalsIgnoreCase(uri.getScheme())) {
- return uri.getPath();
- }
-
- return null;
- }
-
- public static String getPathFromSavingTempFile(Context context, final Uri uri) {
- File tmpFile;
- try {
- String fileName = uri.getLastPathSegment();
- tmpFile = File.createTempFile("tmp", fileName, context.getCacheDir());
-
- ParcelFileDescriptor pfd = context.getContentResolver().openFileDescriptor(uri, "r");
-
- FileChannel src = new FileInputStream(pfd.getFileDescriptor()).getChannel();
- FileChannel dst = new FileOutputStream(tmpFile).getChannel();
- dst.transferFrom(src, 0, src.size());
- src.close();
- dst.close();
- } catch (IOException ex) {
- return null;
- }
- return tmpFile.getAbsolutePath();
- }
-
- /**
- * Get the value of the data column for this Uri. This is useful for
- * MediaStore Uris, and other file-based ContentProviders.
- *
- * @param context The context.
- * @param uri The Uri to query.
- * @param selection (Optional) Filter used in the query.
- * @param selectionArgs (Optional) Selection arguments used in the query.
- * @return The value of the _data column, which is typically a file path.
- */
- public static String getDataColumn(Context context, Uri uri, String selection,
- String[] selectionArgs) {
-
- Cursor cursor = null;
- final String column = "_data";
- final String[] projection = {
- column
- };
-
- try {
- cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
- null);
- if (cursor != null && cursor.moveToFirst()) {
- final int index = cursor.getColumnIndexOrThrow(column);
- return cursor.getString(index);
- }
- } catch (Exception e) {
- return null;
- } finally {
- if (cursor != null)
- cursor.close();
- }
- return null;
- }
-
-
- /**
- * @param uri The Uri to check.
- * @return Whether the Uri authority is ExternalStorageProvider.
- */
- public static boolean isExternalStorageDocument(Uri uri) {
- return "com.android.externalstorage.documents".equals(uri.getAuthority());
- }
-
- /**
- * @param uri The Uri to check.
- * @return Whether the Uri authority is DownloadsProvider.
- */
- public static boolean isDownloadsDocument(Uri uri) {
- return "com.android.providers.downloads.documents".equals(uri.getAuthority());
- }
-
- /**
- * @param uri The Uri to check.
- * @return Whether the Uri authority is MediaProvider.
- */
- public static boolean isMediaDocument(Uri uri) {
- return "com.android.providers.media.documents".equals(uri.getAuthority());
- }
-
- /**
- * @param uri The Uri to check.
- * @return Whether the Uri authority is Google Photos.
- */
- public static boolean isGooglePhotosUri(Uri uri) {
- return "com.google.android.apps.photos.content".equals(uri.getAuthority());
- }
-=======
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -324,7 +159,6 @@ public static String getImagePath(Context context, Uri uri){
public static boolean isGoogleOldPhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
->>>>>>> 02409d5cc22c19d55fe5e83a6e90dd7e91937ba9
public static boolean isGoogleNewPhotosUri(Uri uri) {
return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
From 90a6207a4fa7bbde7f8c1d1958d123e547544e7d Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Mon, 12 Nov 2018 16:54:11 +0100
Subject: [PATCH 18/21] Get image from Whatsapp
---
.../com/alinz/parkerdan/shareextension/RealPathUtil.java | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
index 5f6015fe..a7d27f80 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
@@ -20,7 +20,6 @@ public class RealPathUtil {
public static String getRealPathFromURI(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
-
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
@@ -139,16 +138,14 @@ public static boolean isMediaDocument(Uri uri) {
public static String getImagePath(Context context, Uri uri){
if ("content".equalsIgnoreCase(uri.getScheme())) {
-
if (isGoogleOldPhotosUri(uri)) {
// return http path, then download file.
return uri.getLastPathSegment();
- } else if (isGoogleNewPhotosUri(uri) || isMMSFile(uri)) {
+ } else if (isGoogleNewPhotosUri(uri) || isMMSFile(uri) || isWhatsappFile(uri)) {
// copy from uri. context.getContentResolver().openInputStream(uri);
return copyFile(context, uri);
}
}
-
return getDataColumn(context, uri, null, null);
}
@@ -168,6 +165,10 @@ public static boolean isMMSFile(Uri uri) {
return "com.android.mms.file".equals(uri.getAuthority());
}
+ public static boolean isWhatsappFile(Uri uri) {
+ return "com.whatsapp.provider.media".equals(uri.getAuthority());
+}
+
private static String copyFile(Context context, Uri uri) {
String filePath;
From 7c15c0b1e8d0185eb97876c6bb27093a96c8c08f Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Tue, 27 Nov 2018 17:07:23 +0100
Subject: [PATCH 19/21] Copy file only if we cannot get data column
---
.../shareextension/RealPathUtil.java | 35 +++++++------------
1 file changed, 13 insertions(+), 22 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
index a7d27f80..9beddbde 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
@@ -104,6 +104,8 @@ public static String getDataColumn(Context context, Uri uri, String selection,
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
+ } catch (Exception e) {
+ return null;
} finally {
if (cursor != null)
cursor.close();
@@ -137,16 +139,17 @@ public static boolean isMediaDocument(Uri uri) {
}
public static String getImagePath(Context context, Uri uri){
- if ("content".equalsIgnoreCase(uri.getScheme())) {
- if (isGoogleOldPhotosUri(uri)) {
- // return http path, then download file.
- return uri.getLastPathSegment();
- } else if (isGoogleNewPhotosUri(uri) || isMMSFile(uri) || isWhatsappFile(uri)) {
- // copy from uri. context.getContentResolver().openInputStream(uri);
- return copyFile(context, uri);
- }
- }
- return getDataColumn(context, uri, null, null);
+ final String dataColumn;
+ dataColumn = getDataColumn(context, uri, null, null);
+ if (dataColumn != null){
+ return dataColumn;
+ } else if (isGoogleOldPhotosUri(uri)) {
+ // return http path, then download file.
+ return uri.getLastPathSegment();
+ } else {
+ // copy from uri.context.getContentResolver().openInputStream(uri);
+ return copyFile(context, uri);
+ }
}
/**
@@ -157,18 +160,6 @@ public static boolean isGoogleOldPhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
- public static boolean isGoogleNewPhotosUri(Uri uri) {
- return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
- }
-
- public static boolean isMMSFile(Uri uri) {
- return "com.android.mms.file".equals(uri.getAuthority());
-}
-
- public static boolean isWhatsappFile(Uri uri) {
- return "com.whatsapp.provider.media".equals(uri.getAuthority());
-}
-
private static String copyFile(Context context, Uri uri) {
String filePath;
From 7c6128e9cd073d1ce51a091909366c03e43fdafd Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Wed, 28 Nov 2018 10:36:57 +0100
Subject: [PATCH 20/21] Get file from mms with mms in Authority
---
.../shareextension/RealPathUtil.java | 26 ++++++++++++++++---
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
index 9beddbde..d9072c5b 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
@@ -16,6 +16,8 @@
import java.io.InputStream;
import java.util.UUID;
+import com.sun.org.apache.xerces.internal.util.URI;
+
public class RealPathUtil {
public static String getRealPathFromURI(final Context context, final Uri uri) {
@@ -139,15 +141,18 @@ public static boolean isMediaDocument(Uri uri) {
}
public static String getImagePath(Context context, Uri uri){
+ if (isGoogleOldPhotosUri(uri)) {
+ // return http path, then download file.
+ return uri.getLastPathSegment();
+ } else if (isGoogleNewPhotosUri(uri) || isMMSFile(uri) || isWhatsappFile(uri)) {
+ // copy from uri. context.getContentResolver().openInputStream(uri);
+ return copyFile(context, uri);
+ }
final String dataColumn;
dataColumn = getDataColumn(context, uri, null, null);
if (dataColumn != null){
return dataColumn;
- } else if (isGoogleOldPhotosUri(uri)) {
- // return http path, then download file.
- return uri.getLastPathSegment();
} else {
- // copy from uri.context.getContentResolver().openInputStream(uri);
return copyFile(context, uri);
}
}
@@ -160,6 +165,19 @@ public static boolean isGoogleOldPhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
+ public static boolean isGoogleNewPhotosUri(Uri uri) {
+ return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
+ }
+
+ public static boolean isMMSFile(URI uri) {
+ // uri.getAuthority can be equal to "com.android.mms.file" and "mms"
+ return uri.getAuthority().contains("mms");
+}
+
+ public static boolean isWhatsappFile(Uri uri) {
+ return "com.whatsapp.provider.media".equals(uri.getAuthority());
+}
+
private static String copyFile(Context context, Uri uri) {
String filePath;
From 0f2b7c7cf6c08eeee2c0ae4544aa228185da3783 Mon Sep 17 00:00:00 2001
From: Bart Arribe
Date: Wed, 28 Nov 2018 11:04:16 +0100
Subject: [PATCH 21/21] Fix dumb import
---
.../java/com/alinz/parkerdan/shareextension/RealPathUtil.java | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
index d9072c5b..0957f839 100644
--- a/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
+++ b/android/src/main/java/com/alinz/parkerdan/shareextension/RealPathUtil.java
@@ -16,8 +16,6 @@
import java.io.InputStream;
import java.util.UUID;
-import com.sun.org.apache.xerces.internal.util.URI;
-
public class RealPathUtil {
public static String getRealPathFromURI(final Context context, final Uri uri) {
@@ -169,7 +167,7 @@ public static boolean isGoogleNewPhotosUri(Uri uri) {
return "com.google.android.apps.photos.contentprovider".equals(uri.getAuthority());
}
- public static boolean isMMSFile(URI uri) {
+ public static boolean isMMSFile(Uri uri) {
// uri.getAuthority can be equal to "com.android.mms.file" and "mms"
return uri.getAuthority().contains("mms");
}