Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
adf060f
Add audio, video sharing for android
Jul 4, 2017
7a6c3e8
Update example to make it work
Jul 4, 2017
b6ad992
Update example and readme
Jul 4, 2017
bce7004
Retrieve path from other apps
Jul 5, 2017
ce00a3f
Add SEND_MULTIPLE and return array for android
Jul 5, 2017
d595c62
Update android example
Jul 5, 2017
f49b63c
Update Readme and example
Jul 5, 2017
27cef78
Reindent properly two Java files
Jul 11, 2017
c1beafb
Merge remote-tracking branch 'upstream/master' into multipleDataType
Aug 10, 2017
fbd9cea
Remove non-used createJSModules (RN 0.47)
Aug 16, 2017
77f8b1d
Merge branch 'master' of git://github.com/alinz/react-native-share-ex…
Mar 2, 2018
25737ad
keep image orientation in temp file saved
Mar 2, 2018
f76c216
Enable sharing multi content
Mar 2, 2018
f8c9415
Update example and readme
Mar 2, 2018
ebdeec7
Get IMAGE_IDENTIFIER first in case we get a path
Mar 12, 2018
dd69a60
Upgrade compileSdk and buildTools version
AudreyBramy Sep 12, 2018
57de8db
Upgrade compileSdk and buildTools version
AudreyBramy Sep 12, 2018
94017b7
Update build.gradle
Sep 19, 2018
06c690f
Merge branch 'master' of github.com:arribbar/react-native-share-exten…
Nov 9, 2018
269977c
Merge branch 'master' of https://github.com/alinz/react-native-share-…
Nov 9, 2018
f747bc6
Fix error in resolving conflicts in merge
Nov 12, 2018
90a6207
Get image from Whatsapp
Nov 12, 2018
7c15c0b
Copy file only if we cannot get data column
Nov 27, 2018
7c6128e
Get file from mms with mms in Authority
Nov 28, 2018
0f2b7c7
Fix dumb import
Nov 28, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ This is a helper module which brings react native as an engine to drive share ex
<img src ="https://raw.githubusercontent.com/alinz/react-native-share-extension/master/assets/android-demo.gif" />
</p>

# 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.
Expand Down Expand Up @@ -150,15 +158,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):

```
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>2</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>0</integer>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
</dict>
```
Expand Down Expand Up @@ -287,7 +301,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;
}

Expand Down Expand Up @@ -321,11 +335,16 @@ public class MainApplication extends Application implements ReactApplication {
android:theme="@style/Theme.Share.Transparent" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
// for sharing links include
<data android:mimeType="text/plain" />
// for sharing photos include
<data android:mimeType="image/*" />
// for sharing photos include
<data android:mimeType="image/*" />
// for sharing videos include
<data android:mimeType="video/*"/>
// for sharing audio include
<data android:mimeType="audio/*"/>
</intent-filter>
</activity>
```
Expand Down
12 changes: 8 additions & 4 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

buildscript {
repositories {
jcenter()
Expand All @@ -11,12 +15,12 @@ buildscript {
apply plugin: 'com.android.library'

android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
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"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -105,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();
Expand Down Expand Up @@ -138,18 +139,20 @@ 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)) {
// copy from uri. context.getContentResolver().openInputStream(uri);
return copyFile(context, uri);
}
}

return getDataColumn(context, uri, null, null);
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 {
return copyFile(context, uri);
}
}

/**
Expand All @@ -165,7 +168,12 @@ public static boolean isGoogleNewPhotosUri(Uri uri) {
}

public static boolean isMMSFile(Uri uri) {
return "com.android.mms.file".equals(uri.getAuthority());
// 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,72 +5,85 @@
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.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.ArrayList;

public class ShareModule extends ReactContextBaseJavaModule {


public ShareModule(ReactApplicationContext reactContext) {
super(reactContext);
}

@Override
public String getName() {
return "ReactNativeShareExtension";
}

@ReactMethod
public void close() {
getCurrentActivity().finish();
}

@ReactMethod
public void data(Promise promise) {
promise.resolve(processIntent());
}

public WritableMap processIntent() {
WritableMap map = Arguments.createMap();

String value = "";
String type = "";
String action = "";

Activity currentActivity = getCurrentActivity();

if (currentActivity != null) {
Intent intent = currentActivity.getIntent();
action = intent.getAction();
type = intent.getType();
if (type == null) {
type = "";
}
if (Intent.ACTION_SEND.equals(action) && "text/plain".equals(type)) {
value = intent.getStringExtra(Intent.EXTRA_TEXT);
public ShareModule(ReactApplicationContext reactContext) {
super(reactContext);
}

@Override
public String getName() {
return "ReactNativeShareExtension";
}

@ReactMethod
public void close() {
getCurrentActivity().finish();
}

@ReactMethod
public void data(Promise promise) {
promise.resolve(processIntent());
}

public WritableArray processIntent() {
WritableArray dataArrayMap = Arguments.createArray();
Set<String> mediaTypesSupported = new HashSet<String>();
mediaTypesSupported.add("video");
mediaTypesSupported.add("audio");
mediaTypesSupported.add("image");

String type = "";
String action = "";
String typePart = "";

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<Uri> 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);
}
}
}
else if (Intent.ACTION_SEND.equals(action) && ("image/*".equals(type) || "image/jpeg".equals(type) || "image/png".equals(type) || "image/jpg".equals(type) ) ) {
Uri uri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
value = "file://" + RealPathUtil.getRealPathFromURI(currentActivity, uri);

} else {
value = "";
}
} else {
value = "";
type = "";
}

map.putString("type", type);
map.putString("value",value);

return map;
}
return dataArrayMap;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
return Arrays.<NativeModule>asList(new ShareModule(reactContext));
}

public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
return Arrays.<NativeModule>asList(new ShareExModule(reactContext));
}

public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
Expand Down
10 changes: 9 additions & 1 deletion examples/Sample1/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,16 @@
android:theme="@style/Theme.Share.Transparent" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
// for sharing links include
<data android:mimeType="text/plain" />
// for sharing photos include
<data android:mimeType="image/*" />
// for sharing videos include
<data android:mimeType="video/*"/>
// for sharing audio include
<data android:mimeType="audio/*"/>
</intent-filter>
</activity>
</application>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}
Expand Down
Loading