summaryrefslogtreecommitdiff
path: root/StoneIsland/plugins/cordova-plugin-x-socialsharing/src
diff options
context:
space:
mode:
Diffstat (limited to 'StoneIsland/plugins/cordova-plugin-x-socialsharing/src')
-rw-r--r--[-rwxr-xr-x]StoneIsland/plugins/cordova-plugin-x-socialsharing/src/android/nl/xservices/plugins/SocialSharing.java280
-rw-r--r--StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/NSString+URLEncoding.h5
-rw-r--r--StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/NSString+URLEncoding.m30
-rw-r--r--[-rwxr-xr-x]StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.h3
-rw-r--r--[-rwxr-xr-x]StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.m157
-rw-r--r--[-rwxr-xr-x]StoneIsland/plugins/cordova-plugin-x-socialsharing/src/windows/SocialSharingProxy.js86
-rw-r--r--[-rwxr-xr-x]StoneIsland/plugins/cordova-plugin-x-socialsharing/src/wp8/SocialSharing.cs4
7 files changed, 477 insertions, 88 deletions
diff --git a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/android/nl/xservices/plugins/SocialSharing.java b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/android/nl/xservices/plugins/SocialSharing.java
index f1168f89..8de31da8 100755..100644
--- a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/android/nl/xservices/plugins/SocialSharing.java
+++ b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/android/nl/xservices/plugins/SocialSharing.java
@@ -26,7 +26,9 @@ import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Matcher;
@@ -36,6 +38,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";
@@ -47,7 +50,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_SENDVIAEMAIL = 2;
+ 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;
@@ -55,6 +61,7 @@ public class SocialSharing extends CordovaPlugin {
private abstract class SocialSharingRunnable implements Runnable {
public CallbackContext callbackContext;
+
SocialSharingRunnable(CallbackContext cb) {
this.callbackContext = cb;
}
@@ -68,23 +75,29 @@ public class SocialSharing extends CordovaPlugin {
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)) {
- return doSendIntent(callbackContext, args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), "whatsapp", false);
+ 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", 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));
@@ -94,7 +107,7 @@ public class SocialSharing extends CordovaPlugin {
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)) {
@@ -158,8 +171,17 @@ public class SocialSharing extends CordovaPlugin {
callbackContext.error(e.getMessage());
}
+ // this was added to start the intent in a new window as suggested in #300 to prevent crashes upon return
+ draft.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
draft.setType("application/octet-stream");
- cordova.startActivityForResult(plugin, Intent.createChooser(draft, "Choose Email App"), ACTIVITY_CODE_SENDVIAEMAIL);
+
+ // 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);
+ }
+ });
}
});
@@ -178,7 +200,30 @@ public class SocialSharing extends CordovaPlugin {
}
}
- 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;
@@ -222,6 +267,7 @@ public class SocialSharing extends CordovaPlugin {
if (notEmpty(subject)) {
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
}
+
// add the URL to the message, as there seems to be no separate field
if (notEmpty(url)) {
if (notEmpty(message)) {
@@ -238,6 +284,9 @@ public class SocialSharing extends CordovaPlugin {
}
}
+ // this was added to start the intent in a new window as suggested in #300 to prevent crashes upon return
+ sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
if (appPackageName != null) {
String packageName = appPackageName;
String passedActivityName = null;
@@ -254,7 +303,13 @@ public class SocialSharing extends CordovaPlugin {
sendIntent.addCategory(Intent.CATEGORY_LAUNCHER);
sendIntent.setComponent(new ComponentName(activity.applicationInfo.packageName,
passedActivityName != null ? passedActivityName : activity.name));
- mycordova.startActivityForResult(plugin, sendIntent, 0);
+
+ // 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, sendIntent, 0);
+ }
+ });
if (pasteMessage != null) {
// add a little delay because target app (facebook only atm) needs to be started first
@@ -275,7 +330,13 @@ public class SocialSharing extends CordovaPlugin {
if (peek) {
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
} else {
- mycordova.startActivityForResult(plugin, Intent.createChooser(sendIntent, null), 1);
+ // experimenting a bit
+ // 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, chooserTitle), boolResult ? ACTIVITY_CODE_SEND__BOOLRESULT : ACTIVITY_CODE_SEND__OBJECT);
+ }
+ });
}
}
}
@@ -306,7 +367,12 @@ public class SocialSharing extends CordovaPlugin {
private Uri getFileUriAndSetType(Intent sendIntent, String dir, String image, String subject, int nthFile) throws IOException {
// we're assuming an image, but this can be any filetype you like
String localImage = image;
- sendIntent.setType("image/*");
+ if (image.endsWith("mp4") || image.endsWith("mov") || image.endsWith("3gp")){
+ sendIntent.setType("video/*");
+ } else {
+ sendIntent.setType("image/*");
+ }
+
if (image.startsWith("http") || image.startsWith("www/")) {
String filename = getFileName(image);
localImage = "file://" + dir + "/" + filename;
@@ -319,6 +385,10 @@ public class SocialSharing extends CordovaPlugin {
Matcher matcher = dispositionPattern.matcher(disposition);
if (matcher.find()) {
filename = matcher.group(1).replaceAll("[^a-zA-Z0-9._-]", "");
+ if (filename.length() == 0) {
+ // in this case we can't determine a filetype so some targets (gmail) may not render it correctly
+ filename = "file";
+ }
localImage = "file://" + dir + "/" + filename;
}
}
@@ -365,10 +435,160 @@ public class SocialSharing extends CordovaPlugin {
localImage = "file://" + dir + "/" + fileName;
} else if (!image.startsWith("file://")) {
throw new IllegalArgumentException("URL_NOT_SUPPORTED");
+ } else {
+ //get file MIME type
+ String type = getMIMEType(image);
+ //set intent data and Type
+ sendIntent.setType(type);
}
return Uri.parse(localImage);
}
+ private String getMIMEType(String fileName) {
+ String type = "*/*";
+ int dotIndex = fileName.lastIndexOf(".");
+ if (dotIndex == -1) {
+ return type;
+ }
+ final String end = fileName.substring(dotIndex+1, fileName.length()).toLowerCase();
+ String fromMap = MIME_Map.get(end);
+ return fromMap == null ? type : fromMap;
+ }
+
+ private static final Map<String, String> MIME_Map = new HashMap<String, String>();
+ static {
+ MIME_Map.put("3gp", "video/3gpp");
+ MIME_Map.put("apk", "application/vnd.android.package-archive");
+ MIME_Map.put("asf", "video/x-ms-asf");
+ MIME_Map.put("avi", "video/x-msvideo");
+ MIME_Map.put("bin", "application/octet-stream");
+ MIME_Map.put("bmp", "image/bmp");
+ MIME_Map.put("c", "text/plain");
+ MIME_Map.put("class", "application/octet-stream");
+ MIME_Map.put("conf", "text/plain");
+ MIME_Map.put("cpp", "text/plain");
+ MIME_Map.put("doc", "application/msword");
+ MIME_Map.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ MIME_Map.put("xls", "application/vnd.ms-excel");
+ MIME_Map.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+ MIME_Map.put("exe", "application/octet-stream");
+ MIME_Map.put("gif", "image/gif");
+ MIME_Map.put("gtar", "application/x-gtar");
+ MIME_Map.put("gz", "application/x-gzip");
+ MIME_Map.put("h", "text/plain");
+ MIME_Map.put("htm", "text/html");
+ MIME_Map.put("html", "text/html");
+ MIME_Map.put("jar", "application/java-archive");
+ MIME_Map.put("java", "text/plain");
+ MIME_Map.put("jpeg", "image/jpeg");
+ MIME_Map.put("jpg", "image/*");
+ MIME_Map.put("js", "application/x-javascript");
+ MIME_Map.put("log", "text/plain");
+ MIME_Map.put("m3u", "audio/x-mpegurl");
+ MIME_Map.put("m4a", "audio/mp4a-latm");
+ MIME_Map.put("m4b", "audio/mp4a-latm");
+ MIME_Map.put("m4p", "audio/mp4a-latm");
+ MIME_Map.put("m4u", "video/vnd.mpegurl");
+ MIME_Map.put("m4v", "video/x-m4v");
+ MIME_Map.put("mov", "video/quicktime");
+ MIME_Map.put("mp2", "audio/x-mpeg");
+ MIME_Map.put("mp3", "audio/x-mpeg");
+ MIME_Map.put("mp4", "video/mp4");
+ MIME_Map.put("mpc", "application/vnd.mpohun.certificate");
+ MIME_Map.put("mpe", "video/mpeg");
+ MIME_Map.put("mpeg", "video/mpeg");
+ MIME_Map.put("mpg", "video/mpeg");
+ MIME_Map.put("mpg4", "video/mp4");
+ MIME_Map.put("mpga", "audio/mpeg");
+ MIME_Map.put("msg", "application/vnd.ms-outlook");
+ MIME_Map.put("ogg", "audio/ogg");
+ MIME_Map.put("pdf", "application/pdf");
+ MIME_Map.put("png", "image/png");
+ MIME_Map.put("pps", "application/vnd.ms-powerpoint");
+ MIME_Map.put("ppt", "application/vnd.ms-powerpoint");
+ MIME_Map.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
+ MIME_Map.put("prop", "text/plain");
+ MIME_Map.put("rc", "text/plain");
+ MIME_Map.put("rmvb", "audio/x-pn-realaudio");
+ MIME_Map.put("rtf", "application/rtf");
+ MIME_Map.put("sh", "text/plain");
+ MIME_Map.put("tar", "application/x-tar");
+ MIME_Map.put("tgz", "application/x-compressed");
+ MIME_Map.put("txt", "text/plain");
+ MIME_Map.put("wav", "audio/x-wav");
+ MIME_Map.put("wma", "audio/x-ms-wma");
+ MIME_Map.put("wmv", "audio/x-ms-wmv");
+ MIME_Map.put("wps", "application/vnd.ms-works");
+ MIME_Map.put("xml", "text/plain");
+ MIME_Map.put("z", "application/x-compress");
+ MIME_Map.put("zip", "application/x-zip-compressed");
+ MIME_Map.put("", "*/*");
+ }
+
+ private boolean shareViaWhatsAppDirectly(final CallbackContext callbackContext, String message, final String subject, final JSONArray files, final String url, final String number) {
+ // add the URL to the message, as there seems to be no separate field
+ if (notEmpty(url)) {
+ if (notEmpty(message)) {
+ message += " " + url;
+ } else {
+ message = url;
+ }
+ }
+ final String shareMessage = message;
+ final SocialSharing plugin = this;
+ cordova.getThreadPool().execute(new SocialSharingRunnable(callbackContext) {
+ public void run() {
+ final Intent intent = new Intent(Intent.ACTION_SENDTO);
+ intent.setData(Uri.parse("smsto:" + number));
+
+ intent.putExtra("sms_body", shareMessage);
+ intent.putExtra("sms_subject", subject);
+ intent.setPackage("com.whatsapp");
+
+ try {
+ if (files.length() > 0 && !"".equals(files.getString(0))) {
+ final boolean hasMultipleAttachments = files.length() > 1;
+ final String dir = getDownloadDir();
+ if (dir != null) {
+ ArrayList<Uri> fileUris = new ArrayList<Uri>();
+ Uri fileUri = null;
+ for (int i = 0; i < files.length(); i++) {
+ fileUri = getFileUriAndSetType(intent, dir, files.getString(i), subject, i);
+ if (fileUri != null) {
+ fileUris.add(fileUri);
+ }
+ }
+ if (!fileUris.isEmpty()) {
+ if (hasMultipleAttachments) {
+ intent.putExtra(Intent.EXTRA_STREAM, fileUris);
+ } else {
+ intent.putExtra(Intent.EXTRA_STREAM, fileUri);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ callbackContext.error(e.getMessage());
+ }
+ try {
+ // this was added to start the intent in a new window as suggested in #300 to prevent crashes upon return
+ // update: didn't help (doesn't seem to hurt either though)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ // 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, ACTIVITY_CODE_SENDVIAWHATSAPP);
+ }
+ });
+ } catch (Exception e) {
+ callbackContext.error(e.getMessage());
+ }
+ }
+ });
+ return true;
+ }
+
private boolean invokeSMSIntent(final CallbackContext callbackContext, JSONObject options, String p_phonenumbers) {
final String message = options.optString("message");
// TODO test this on a real SMS enabled device before releasing it
@@ -404,6 +624,9 @@ public class SocialSharing extends CordovaPlugin {
intent.putExtra(Intent.EXTRA_STREAM, fileUri);
}
}
+ // this was added to start the intent in a new window as suggested in #300 to prevent crashes upon return
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
cordova.startActivityForResult(plugin, intent, 0);
} catch (Exception e) {
callbackContext.error(e.getMessage());
@@ -451,10 +674,26 @@ public class SocialSharing extends CordovaPlugin {
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();
}
}
}
@@ -471,13 +710,16 @@ public class SocialSharing extends CordovaPlugin {
}
private static String getFileName(String url) {
+ if (url.endsWith("/")) {
+ url = url.substring(0, url.length()-1);
+ }
final String pattern = ".*/([^?#]+)?";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(url);
if (m.find()) {
return m.group(1);
} else {
- return null;
+ return "file";
}
}
diff --git a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/NSString+URLEncoding.h b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/NSString+URLEncoding.h
new file mode 100644
index 00000000..d7da331d
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/NSString+URLEncoding.h
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+
+@interface NSString (URLEncoding)
+@property (readonly) NSString *URLEncodedString;
+@end
diff --git a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/NSString+URLEncoding.m b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/NSString+URLEncoding.m
new file mode 100644
index 00000000..b737626c
--- /dev/null
+++ b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/NSString+URLEncoding.m
@@ -0,0 +1,30 @@
+#import "NSString+URLEncoding.h"
+
+@implementation NSString (URLEncoding)
+- (NSString*)URLEncodedString
+{
+ NSString* result = (NSString *)CFBridgingRelease(
+ CFURLCreateStringByAddingPercentEscapes(
+ kCFAllocatorDefault,
+ (CFStringRef)self,
+ CFSTR("#%"), // don't escape these
+ NULL, // allow escaping these
+ kCFStringEncodingUTF8
+ )
+ );
+
+ // we may have a URL with more than one '#' now - which iOS doesn't allow, so escape all but the first one
+ NSArray *parts = [result componentsSeparatedByString:@"#"];
+ NSString *finalResult = parts[0];
+ for (int i=1; i<parts.count; i++) {
+ NSString *part = [parts objectAtIndex:i];
+ if (i==1) {
+ finalResult = [finalResult stringByAppendingString:@"#"];
+ } else {
+ finalResult = [finalResult stringByAppendingString:@"%23"];
+ }
+ finalResult = [finalResult stringByAppendingString:part];
+ }
+ return finalResult;
+}
+@end \ No newline at end of file
diff --git a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.h b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.h
index b51474d3..0c731450 100755..100644
--- a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.h
+++ b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.h
@@ -4,13 +4,14 @@
@interface SocialSharing : CDVPlugin <UIPopoverControllerDelegate, MFMailComposeViewControllerDelegate, UIDocumentInteractionControllerDelegate>
@property (nonatomic, strong) MFMailComposeViewController *globalMailComposer;
-@property (retain) UIDocumentInteractionController * documentInteractionController;
+@property (nonatomic, strong) UIDocumentInteractionController * documentInteractionController;
@property (retain) NSString * tempStoredFile;
@property (retain) CDVInvokedUrlCommand * command;
- (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;
diff --git a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.m b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.m
index cd0913a4..014925bd 100755..100644
--- a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.m
+++ b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/ios/SocialSharing.m
@@ -1,4 +1,5 @@
#import "SocialSharing.h"
+#import "NSString+URLEncoding.h"
#import <Cordova/CDV.h>
#import <Social/Social.h>
#import <Foundation/NSException.h>
@@ -6,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;
@@ -51,23 +57,46 @@
}
- (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];
+
+ if (message != (id)[NSNull null] && message != nil) {
[activityItems addObject:message];
-
- NSMutableArray *files = [[NSMutableArray alloc] init];
- if (filenames != (id)[NSNull null] && filenames.count > 0) {
+ }
+
+ if (filenames != (id)[NSNull null] && filenames != nil && filenames.count > 0) {
+ NSMutableArray *files = [[NSMutableArray alloc] init];
for (NSString* filename in filenames) {
NSObject *file = [self getImage:filename];
if (file == nil) {
@@ -79,31 +108,47 @@
}
[activityItems addObjectsFromArray:files];
}
-
- if (urlString != (id)[NSNull null]) {
- [activityItems addObject:[NSURL URLWithString:urlString]];
+
+ if (urlString != (id)[NSNull null] && urlString != nil) {
+ [activityItems addObject:[NSURL URLWithString:[urlString URLEncodedString]]];
}
-
+
UIActivity *activity = [[UIActivity alloc] init];
NSArray *applicationActivities = [[NSArray alloc] initWithObjects:activity, nil];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:applicationActivities];
- if (subject != (id)[NSNull null]) {
+ if (subject != (id)[NSNull null] && subject != nil) {
[activityVC setValue:subject forKey:@"subject"];
}
-
- // TODO deprecated in iOS 8.0, change this some day
- [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];
- }];
-
+
+ if ([activityVC respondsToSelector:(@selector(setCompletionWithItemsHandler:))]) {
+ [activityVC setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray * returnedItems, NSError * 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];
+ 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"
+ }
+
NSArray * socialSharingExcludeActivities = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"SocialSharingExcludeActivities"];
if (socialSharingExcludeActivities!=nil && [socialSharingExcludeActivities count] > 0) {
activityVC.excludedActivityTypes = socialSharingExcludeActivities;
}
-
+
dispatch_async(dispatch_get_main_queue(), ^(void){
// iPad on iOS >= 8 needs a different approach
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
@@ -230,27 +275,27 @@
- (void)shareViaInternal:(CDVInvokedUrlCommand*)command
type:(NSString *) type {
-
+
NSString *message = [command.arguments objectAtIndex:0];
// subject is not supported by the SLComposeViewController
NSArray *filenames = [command.arguments objectAtIndex:2];
NSString *urlString = [command.arguments objectAtIndex:3];
-
+
// boldly invoke the target app, because the phone will display a nice message asking to configure the app
SLComposeViewController *composeViewController = [SLComposeViewController composeViewControllerForServiceType:type];
if (message != (id)[NSNull null]) {
[composeViewController setInitialText:message];
}
-
+
for (NSString* filename in filenames) {
UIImage* image = [self getImage:filename];
if (image != nil) {
[composeViewController addImage:image];
}
}
-
+
if (urlString != (id)[NSNull null]) {
- [composeViewController addURL:[NSURL URLWithString:urlString]];
+ [composeViewController addURL:[NSURL URLWithString:[urlString URLEncodedString]]];
}
[composeViewController setCompletionHandler:^(SLComposeViewControllerResult result) {
@@ -272,7 +317,7 @@
- (void)shareViaEmail:(CDVInvokedUrlCommand*)command {
if ([self isEmailAvailable]) {
-
+
if (TARGET_IPHONE_SIMULATOR && IsAtLeastiOSVersion(@"8.0")) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"SocialSharing plugin"
message:@"Sharing via email is not supported on the iOS 8 simulator."
@@ -282,38 +327,40 @@
[alert show];
return;
}
-
+
+ [self cycleTheGlobalMailComposer];
+
self.globalMailComposer.mailComposeDelegate = self;
-
+
if ([command.arguments objectAtIndex:0] != (id)[NSNull null]) {
NSString *message = [command.arguments objectAtIndex:0];
BOOL isHTML = [message rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch].location != NSNotFound;
[self.globalMailComposer setMessageBody:message isHTML:isHTML];
}
-
+
if ([command.arguments objectAtIndex:1] != (id)[NSNull null]) {
[self.globalMailComposer setSubject: [command.arguments objectAtIndex:1]];
}
-
+
if ([command.arguments objectAtIndex:2] != (id)[NSNull null]) {
[self.globalMailComposer setToRecipients:[command.arguments objectAtIndex:2]];
}
-
+
if ([command.arguments objectAtIndex:3] != (id)[NSNull null]) {
[self.globalMailComposer setCcRecipients:[command.arguments objectAtIndex:3]];
}
-
+
if ([command.arguments objectAtIndex:4] != (id)[NSNull null]) {
[self.globalMailComposer setBccRecipients:[command.arguments objectAtIndex:4]];
}
-
+
if ([command.arguments objectAtIndex:5] != (id)[NSNull null]) {
NSArray* attachments = [command.arguments objectAtIndex:5];
NSFileManager* fileManager = [NSFileManager defaultManager];
for (NSString* path in attachments) {
NSURL *file = [self getFile:path];
NSData* data = [fileManager contentsAtPath:file.path];
-
+
NSString* fileName;
NSString* mimeType;
NSString* basename = [self getBasenameFromAttachmentPath:path];
@@ -331,14 +378,14 @@
[self.globalMailComposer addAttachmentData:data mimeType:mimeType fileName:fileName];
}
}
-
+
// remember the command, because we need it in the didFinishWithResult method
_command = command;
[self.commandDelegate runInBackground:^{
[[self getTopMostViewController] presentViewController:self.globalMailComposer animated:YES completion:nil];
}];
-
+
} else {
CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not available"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
@@ -358,7 +405,7 @@
NSString* pathWithoutPrefix = [path stringByReplacingOccurrencesOfString:@"base64:" withString:@""];
return [pathWithoutPrefix substringToIndex:[pathWithoutPrefix rangeOfString:@"//"].location];
}
- return path;
+ return [path componentsSeparatedByString: @"?"][0];
}
- (NSString*) getMimeTypeFromFileExtension:(NSString*)extension {
@@ -406,7 +453,7 @@
NSString *message = [options objectForKey:@"message"];
NSString *subject = [options objectForKey:@"subject"];
NSString *image = [options objectForKey:@"image"];
-
+
MFMessageComposeViewController *picker = [[MFMessageComposeViewController alloc] init];
picker.messageComposeDelegate = (id) self;
if (message != (id)[NSNull null]) {
@@ -424,7 +471,7 @@
}
}
}
-
+
if (phonenumbers != (id)[NSNull null]) {
[picker setRecipients:[phonenumbers componentsSeparatedByString:@","]];
}
@@ -469,7 +516,7 @@
}
- (void)shareViaInstagram:(CDVInvokedUrlCommand*)command {
-
+
// on iOS9 canShareVia('instagram'..) will only work if instagram:// is whitelisted.
// If it's not, this method will ask permission to the user on iOS9 for opening the app,
// which is of course better than Instagram sharing not working at all because you forgot to whitelist it.
@@ -492,7 +539,7 @@
image = [self getImage:filename];
break;
}
-
+
// NSData *imageObj = [NSData dataFromBase64String:objectAtIndex0];
NSString *tmpDir = NSTemporaryDirectory();
NSString *path = [tmpDir stringByAppendingPathComponent:@"instagram.igo"];
@@ -513,11 +560,15 @@
// remember the command for the delegate method
_command = command;
- [_documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.webView animated:YES];
+
+ // test for #513
+ dispatch_async(dispatch_get_main_queue(), ^(void){
+ [_documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.webView animated:YES];
+ });
}
- (void)shareViaWhatsApp:(CDVInvokedUrlCommand*)command {
-
+
// on iOS9 canShareVia('whatsapp'..) will only work if whatsapp:// is whitelisted.
// If it's not, this method will ask permission to the user on iOS9 for opening the app,
// which is of course better than WhatsApp sharing not working at all because you forgot to whitelist it.
@@ -534,6 +585,7 @@
// subject is not supported by the SLComposeViewController
NSArray *filenames = [command.arguments objectAtIndex:2];
NSString *urlString = [command.arguments objectAtIndex:3];
+ NSString *abid = [command.arguments objectAtIndex:4];
// only use the first image (for now.. maybe we can share in a loop?)
UIImage* image = nil;
@@ -561,14 +613,18 @@
if ([shareString isEqual: @""]) {
shareString = urlString;
} else {
- shareString = [NSString stringWithFormat:@"%@ %@", shareString, urlString];
+ shareString = [NSString stringWithFormat:@"%@ %@", shareString, [urlString URLEncodedString]];
}
}
NSString * encodedShareString = [shareString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// also encode the '=' character
encodedShareString = [encodedShareString stringByReplacingOccurrencesOfString:@"=" withString:@"%3D"];
encodedShareString = [encodedShareString stringByReplacingOccurrencesOfString:@"&" withString:@"%26"];
- NSString * encodedShareStringForWhatsApp = [NSString stringWithFormat:@"whatsapp://send?text=%@", encodedShareString];
+ NSString * abidString = @"";
+ if (abid != (id)[NSNull null]) {
+ abidString = [NSString stringWithFormat:@"abid=%@&", abid];
+ }
+ NSString * encodedShareStringForWhatsApp = [NSString stringWithFormat:@"whatsapp://send?%@text=%@", abidString, encodedShareString];
NSURL *whatsappURL = [NSURL URLWithString:encodedShareStringForWhatsApp];
[[UIApplication sharedApplication] openURL: whatsappURL];
@@ -641,7 +697,8 @@
if ([fileName hasPrefix:@"http"]) {
NSURL *url = [NSURL URLWithString:fileName];
NSData *fileData = [NSData dataWithContentsOfURL:url];
- file = [NSURL fileURLWithPath:[self storeInFile:(NSString*)[[fileName componentsSeparatedByString: @"/"] lastObject] fileData:fileData]];
+ NSString *name = (NSString*)[[fileName componentsSeparatedByString: @"/"] lastObject];
+ file = [NSURL fileURLWithPath:[self storeInFile:[name componentsSeparatedByString: @"?"][0] fileData:fileData]];
} else if ([fileName hasPrefix:@"www/"]) {
NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
NSString *fullPath = [NSString stringWithFormat:@"%@/%@", bundlePath, fileName];
diff --git a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/windows/SocialSharingProxy.js b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/windows/SocialSharingProxy.js
index 99e0af15..ff257d52 100755..100644
--- a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/windows/SocialSharingProxy.js
+++ b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/windows/SocialSharingProxy.js
@@ -10,6 +10,36 @@ module.exports = {
var fileOrFileArray = args[2];
//Web link
var url = args[3];
+
+ var folder = Windows.Storage.ApplicationData.current.temporaryFolder;
+
+ var getExtension = function (strBase64) {
+ return strBase64.substring(strBase64.indexOf("/") + 1, strBase64.indexOf(";base64"));
+ };
+
+ var replaceAll = function (str, find, replace) {
+ return str.replace(new RegExp(find, 'g'), replace);
+ };
+
+ var sanitizeFilename = function (name) {
+ return replaceAll(name, "[:\\\\/*?|<> ]", "_");
+ };
+
+ var getFileName = function (position, fileExtension) {
+ var fileName = (subject ? sanitizeFilename(subject) : "file") + (position == 0 ? "" : "_" + position) + "." + fileExtension;
+ return fileName;
+ };
+
+ var createTemporalFile = function (fileName, buffer) {
+
+ var filePath = "";
+ return folder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {
+ filePath = file.path;
+ return Windows.Storage.FileIO.writeBufferAsync(file, buffer);
+ }).then(function(){
+ return Windows.Storage.StorageFile.getFileFromPathAsync(filePath);
+ });
+ };
var doShare = function (e) {
e.request.data.properties.title = subject?subject: "Sharing";
@@ -19,25 +49,49 @@ module.exports = {
var deferral = e.request.getDeferral();
var storageItems = [];
var filesCount = fileOrFileArray.length;
+
+ var completeFile = function () {
+ if (!--filesCount) {
+ storageItems.length && e.request.data.setStorageItems(storageItems);
+ deferral.complete();
+ }
+ };
+
for (var i = 0; i < fileOrFileArray.length; i++) {
- Windows.Storage.StorageFile.getFileFromPathAsync(fileOrFileArray[i]).done(
- function (file) {
- storageItems.push(file);
- if (!--filesCount) {
- e.request.data.setStorageItems(storageItems);
- deferral.complete();
- }
- },
- function() {
- if (!--filesCount) {
- e.request.data.setStorageItems(storageItems);
- deferral.complete();
+
+ var file = fileOrFileArray[i];
+ if (file.indexOf("data:") >= 0) {
+ var fileName = getFileName(i, getExtension(file));
+ var buffer = Windows.Security.Cryptography.CryptographicBuffer.decodeFromBase64String(file.split(',')[1]);
+ if (buffer) {
+ createTemporalFile(fileName, buffer).done(
+ function (file) {
+ storageItems.push(file);
+ completeFile();
+ },
+ function () {
+ completeFile();
+ }
+ );
+ }
+ else {
+ completeFile();
+ }
+ }
+ else {
+ Windows.Storage.StorageFile.getFileFromPathAsync(file).done(
+ function (file) {
+ storageItems.push(file);
+ completeFile();
+ },
+ function () {
+ completeFile();
}
- }
- );
+ );
+ }
}
}
- }
+ };
var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
@@ -96,7 +150,7 @@ module.exports = {
);
}
}
- }
+ };
var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
diff --git a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/wp8/SocialSharing.cs b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/wp8/SocialSharing.cs
index 1a165127..9d63b2f4 100755..100644
--- a/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/wp8/SocialSharing.cs
+++ b/StoneIsland/plugins/cordova-plugin-x-socialsharing/src/wp8/SocialSharing.cs
@@ -26,7 +26,7 @@ namespace Cordova.Extension.Commands
var files = JsonHelper.Deserialize<string[]>(options[2]);
var link = options[3];
- if (!"null".Equals(link))
+ if (link != null && !"null".Equals(link))
{
ShareLinkTask shareLinkTask = new ShareLinkTask();
shareLinkTask.Title = title;
@@ -100,4 +100,4 @@ namespace Cordova.Extension.Commands
public string message { get; set; }
}
-} \ No newline at end of file
+}