Skip to content

Commit

Permalink
EddyVerbruggen#541 Is it possible to return which one is shared to?
Browse files Browse the repository at this point in the history
  • Loading branch information
EddyVerbruggen committed Apr 24, 2016
1 parent a150913 commit 07c2655
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 40 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,33 @@ However, what exactly gets shared, depends on the application the user chooses t
- Facebook iOS: message, image (other filetypes are not supported), link. Beware that since a Fb update in April 2015 sharing a prefilled message is no longer possible when the Fb app is installed (like Android), see #344. Alternative: use `shareViaFacebookWithPasteMessageHint`.

### Using the share sheet
Since versin 5.1.0 (for iOS and Android) it's recommended to use `shareWithOptions` as it's the most feature rich way to share stuff cross-platform.

It will also tell you if sharing to an app completed and which app that was (if that app plays nice, that is).

```js
// this is the complete list of currently supported params you can pass to the plugin (all optional)
var options = {
message: 'share this', // not supported on some apps (Facebook, Instagram)
subject: 'the subject', // fi. for email
files: ['', ''], // an array of filenames either locally or remotely
url: 'https://www.website.com/foo/#bar?a=b',
chooserTitle: 'Pick an app' // Android only, you can override the default share sheet title
}

var onSuccess = function(result) {
console.log("Share completed? " + result.completed); // On Android apps mostly return false even while it's true
console.log("Shared to app: " + result.app); // On Android result.app is currently empty. On iOS it's empty when sharing is cancelled (result.completed=false)
}

var onError = function(msg) {
console.log("Sharing failed with message: " + msg);
}

window.plugins.socialsharing.shareWithOptions(options, onSuccess, onError);
```

#### You can still use the older `share` method as well
Here are some examples you can copy-paste to test the various combinations:
```html
<button onclick="window.plugins.socialsharing.share('Message only')">message only</button>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-x-socialsharing",
"version": "5.0.12",
"version": "5.1.0",
"description": "Share text, images (and other files), or a link via the native sharing widget of your device. Android is fully supported, as well as iOS 6 and up. WP8 has somewhat limited support.",
"cordova": {
"id": "cordova-plugin-x-socialsharing",
Expand Down
2 changes: 1 addition & 1 deletion plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-x-socialsharing"
version="5.0.12">
version="5.1.0">

<name>SocialSharing</name>

Expand Down
85 changes: 64 additions & 21 deletions src/android/nl/xservices/plugins/SocialSharing.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class SocialSharing extends CordovaPlugin {

private static final String ACTION_AVAILABLE_EVENT = "available";
private static final String ACTION_SHARE_EVENT = "share";
private static final String ACTION_SHARE_WITH_OPTIONS_EVENT = "shareWithOptions";
private static final String ACTION_CAN_SHARE_VIA = "canShareVia";
private static final String ACTION_CAN_SHARE_VIA_EMAIL = "canShareViaEmail";
private static final String ACTION_SHARE_VIA = "shareVia";
Expand All @@ -47,9 +48,10 @@ public class SocialSharing extends CordovaPlugin {
private static final String ACTION_SHARE_VIA_SMS_EVENT = "shareViaSMS";
private static final String ACTION_SHARE_VIA_EMAIL_EVENT = "shareViaEmail";

private static final int ACTIVITY_CODE_SEND = 1;
private static final int ACTIVITY_CODE_SENDVIAEMAIL = 2;
private static final int ACTIVITY_CODE_SENDVIAWHATSAPP = 3;
private static final int ACTIVITY_CODE_SEND__BOOLRESULT = 1;
private static final int ACTIVITY_CODE_SEND__OBJECT = 2;
private static final int ACTIVITY_CODE_SENDVIAEMAIL = 3;
private static final int ACTIVITY_CODE_SENDVIAWHATSAPP = 4;

private CallbackContext _callbackContext;

Expand All @@ -71,27 +73,29 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
return true;
} else if (ACTION_SHARE_EVENT.equals(action)) {
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), null, false);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), null, null, false, true);
} else if (ACTION_SHARE_WITH_OPTIONS_EVENT.equals(action)) {
return shareWithOptions(callbackContext, args.getJSONObject(0));
} else if (ACTION_SHARE_VIA_TWITTER_EVENT.equals(action)) {
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "twitter", false);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "twitter", null, false, true);
} else if (ACTION_SHARE_VIA_FACEBOOK_EVENT.equals(action)) {
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", false);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", null, false, true);
} else if (ACTION_SHARE_VIA_FACEBOOK_WITH_PASTEMESSAGEHINT.equals(action)) {
this.pasteMessage = args.getString(4);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", false);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "com.facebook.katana", null, false, true);
} else if (ACTION_SHARE_VIA_WHATSAPP_EVENT.equals(action)) {
if (notEmpty(args.getString(4))) {
return shareViaWhatsAppDirectly(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4));
} else {
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "whatsapp", false);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "whatsapp", null, false, true);
}
} else if (ACTION_SHARE_VIA_INSTAGRAM_EVENT.equals(action)) {
if (notEmpty(args.getString(0))) {
copyHintToClipboard(args.getString(0), "Instagram paste message");
}
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "instagram", false);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "instagram", null, false, true);
} else if (ACTION_CAN_SHARE_VIA.equals(action)) {
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4), true);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4), null, true, true);
} else if (ACTION_CAN_SHARE_VIA_EMAIL.equals(action)) {
if (isEmailAvailable()) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
Expand All @@ -101,7 +105,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
return false;
}
} else if (ACTION_SHARE_VIA.equals(action)) {
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4), false);
return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), args.getString(4), null, false, true);
} else if (ACTION_SHARE_VIA_SMS_EVENT.equals(action)) {
return invokeSMSIntent(callbackContext, args.getJSONObject(0), args.getString(1));
} else if (ACTION_SHARE_VIA_EMAIL_EVENT.equals(action)) {
Expand Down Expand Up @@ -173,9 +177,9 @@ public void run() {
// as an experiment for #300 we're explicitly running it on the ui thread here
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
cordova.startActivityForResult(plugin, Intent.createChooser(draft, "Choose Email App"), ACTIVITY_CODE_SENDVIAEMAIL);
}
});
cordova.startActivityForResult(plugin, Intent.createChooser(draft, "Choose Email App"), ACTIVITY_CODE_SENDVIAEMAIL);
}
});
}
});

Expand All @@ -194,7 +198,30 @@ private String getDownloadDir() throws IOException {
}
}

private boolean doSendIntent(final CallbackContext callbackContext, final String msg, final String subject, final JSONArray files, final String url, final String appPackageName, final boolean peek) {
private boolean shareWithOptions(CallbackContext callbackContext, JSONObject jsonObject) {
return doSendIntent(
callbackContext,
jsonObject.optString("message", null),
jsonObject.optString("subject", null),
jsonObject.optJSONArray("files") == null ? new JSONArray() : jsonObject.optJSONArray("files"),
jsonObject.optString("url", null),
null,
jsonObject.optString("chooserTitle", null),
false,
false
);
}

private boolean doSendIntent(
final CallbackContext callbackContext,
final String msg,
final String subject,
final JSONArray files,
final String url,
final String appPackageName,
final String chooserTitle,
final boolean peek,
final boolean boolResult) {

final CordovaInterface mycordova = cordova;
final CordovaPlugin plugin = this;
Expand Down Expand Up @@ -305,12 +332,12 @@ public void run() {
// as an experiment for #300 we're explicitly running it on the ui thread here
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
mycordova.startActivityForResult(plugin, Intent.createChooser(sendIntent, null), ACTIVITY_CODE_SEND);
mycordova.startActivityForResult(plugin, Intent.createChooser(sendIntent, chooserTitle), boolResult ? ACTIVITY_CODE_SEND__BOOLRESULT : ACTIVITY_CODE_SEND__OBJECT);
}
});
}
}
}
}
});
return true;
}
Expand Down Expand Up @@ -554,10 +581,26 @@ private JSONArray getShareActivities(List<ResolveInfo> activityList) {
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (_callbackContext != null) {
if (ACTIVITY_CODE_SENDVIAEMAIL == requestCode) {
_callbackContext.success();
} else {
_callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, resultCode == Activity.RESULT_OK));
switch (requestCode) {
case ACTIVITY_CODE_SEND__BOOLRESULT:
_callbackContext.sendPluginResult(new PluginResult(
PluginResult.Status.OK,
resultCode == Activity.RESULT_OK));
break;
case ACTIVITY_CODE_SEND__OBJECT:
JSONObject json = new JSONObject();
try {
json.put("completed", resultCode == Activity.RESULT_OK);
json.put("app", ""); // we need a completely different approach if we want to support this on Android. Idea: https://clickclickclack.wordpress.com/2012/01/03/intercepting-androids-action_send-intents/
_callbackContext.sendPluginResult(new PluginResult(
PluginResult.Status.OK,
json));
} catch (JSONException e) {
_callbackContext.error(e.getMessage());
}
break;
default:
_callbackContext.success();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/ios/SocialSharing.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- (void)available:(CDVInvokedUrlCommand*)command;
- (void)setIPadPopupCoordinates:(CDVInvokedUrlCommand*)command;
- (void)share:(CDVInvokedUrlCommand*)command;
- (void)shareWithOptions:(CDVInvokedUrlCommand*)command;
- (void)canShareVia:(CDVInvokedUrlCommand*)command;
- (void)canShareViaEmail:(CDVInvokedUrlCommand*)command;
- (void)shareVia:(CDVInvokedUrlCommand*)command;
Expand Down
64 changes: 47 additions & 17 deletions src/ios/SocialSharing.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
#import <MessageUI/MFMailComposeViewController.h>
#import <MobileCoreServices/MobileCoreServices.h>

static NSString *const kShareOptionMessage = @"message";
static NSString *const kShareOptionSubject = @"subject";
static NSString *const kShareOptionFiles = @"files";
static NSString *const kShareOptionUrl = @"url";

@implementation SocialSharing {
UIPopoverController *_popover;
NSString *_popupCoordinates;
Expand Down Expand Up @@ -52,17 +57,37 @@ - (CGRect)getPopupRectFromIPadPopupCoordinates:(NSArray*)comps {
}

- (void)share:(CDVInvokedUrlCommand*)command {
[self shareInternal:command
withOptions:@{
kShareOptionMessage: [command.arguments objectAtIndex:0],
kShareOptionSubject: [command.arguments objectAtIndex:1],
kShareOptionFiles: [command.arguments objectAtIndex:2],
kShareOptionUrl: [command.arguments objectAtIndex:3]
}
isBooleanResponse:YES
];
}

- (void)shareWithOptions:(CDVInvokedUrlCommand*)command {
NSDictionary* options = [command.arguments objectAtIndex:0];
[self shareInternal:command
withOptions:options
isBooleanResponse:NO
];
}

- (void)shareInternal:(CDVInvokedUrlCommand*)command withOptions:(NSDictionary*)options isBooleanResponse:(BOOL)boolResponse {
[self.commandDelegate runInBackground:^{ //avoid main thread block especially if sharing big files from url
if (!NSClassFromString(@"UIActivityViewController")) {
CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

NSString *message = [command.arguments objectAtIndex:0];
NSString *subject = [command.arguments objectAtIndex:1];
NSArray *filenames = [command.arguments objectAtIndex:2];
NSString *urlString = [command.arguments objectAtIndex:3];
NSString *message = options[kShareOptionMessage];
NSString *subject = options[kShareOptionSubject];
NSArray *filenames = options[kShareOptionFiles];
NSString *urlString = options[kShareOptionUrl];

NSMutableArray *activityItems = [[NSMutableArray alloc] init];
[activityItems addObject:message];
Expand Down Expand Up @@ -93,21 +118,26 @@ - (void)share:(CDVInvokedUrlCommand*)command {
}

if ([activityVC respondsToSelector:(@selector(setCompletionWithItemsHandler:))]) {
[activityVC setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError) {
[self cleanupStoredFiles];
NSLog(@"SocialSharing app selected: %@", activityType);
CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:completed];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}];
}else{
[activityVC setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray * __nullable returnedItems, NSError * __nullable activityError) {
[self cleanupStoredFiles];
if (boolResponse) {
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:completed]
callbackId:command.callbackId];
} else {
NSDictionary * result = @{@"completed":@(completed), @"app":activityType == nil ? @"" : activityType};
[self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result]
callbackId:command.callbackId];
}
}];
} else {
// let's suppress this warning otherwise folks will start opening issues while it's not relevant
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) {
[self cleanupStoredFiles];
NSLog(@"SocialSharing app selected: %@", activityType);
CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsBool:completed];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}];
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) {
[self cleanupStoredFiles];
NSDictionary * result = @{@"completed":@(completed), @"app":activityType};
CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:result];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}];
#pragma GCC diagnostic warning "-Wdeprecated-declarations"
}

Expand Down
5 changes: 5 additions & 0 deletions www/SocialSharing.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ SocialSharing.prototype.available = function (callback) {
}, null, "SocialSharing", "available", []);
};

// this is the recommended way to share as it is the most feature-rich with respect to what you pass in and get back
SocialSharing.prototype.shareWithOptions = function (options, successCallback, errorCallback) {
cordova.exec(successCallback, this._getErrorCallback(errorCallback, "shareWithOptions"), "SocialSharing", "shareWithOptions", [options]);
};

SocialSharing.prototype.share = function (message, subject, fileOrFileArray, url, successCallback, errorCallback) {
cordova.exec(successCallback, this._getErrorCallback(errorCallback, "share"), "SocialSharing", "share", [message, subject, this._asArray(fileOrFileArray), url]);
};
Expand Down

0 comments on commit 07c2655

Please sign in to comment.