I've tried sharing an NSData object of the file contents, and the activity view comes up with the mail option, and then the mail compose controller displays, but there's no attachment.
I've tried sharing an NSUrl with the path of the file, but in that case when the activity view comes up it takes up the whole screen but is blank except for the "cancel" button at the bottom. Weird. Also the activity view only comes up on the device in this case, it never even comes up on the simulator.
If I convert the NSData to an NSString, then it does work, but it just pastes the string into the body of the email. I don't want that, I want to attach a file.
I've used the debugger to verify that the NSData object has (the correct) data and that the NSUrl object has the right file path. No dice.
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var file = Path.Combine(documents, "file.txt");
NSData dataToShare = NSFileManager.DefaultManager.Contents(file);
UIActivityViewController activityViewController = new UIActivityViewController(new NSObject[] { dataToShare }, null); //Email comes up but data isn't attached
// OR
UIActivityViewController activityViewController = new UIActivityViewController(new NSObject[] { new NSUrl(file) }, null); //Activity view takes up the whole screen and is blank
// OR
UIActivityViewController activityViewController = new UIActivityViewController(new NSObject[] { (NSString)dataToShare.ToString() }, null); //Pastes string into email body
Related
I have a UIActivityViewController which takes in an array of URLs that resolve to images within the app's Documents folder and Strings:
var contentArray = [Any]();
contentArray.append("Test Text");
contentArray.append(URL(<<valid url to image in app's documents folder>>));
let shareSheet = UIActivityViewController(activityItems: contentArray, applicationActivities: nil);
if let popoverController = shareSheet.popoverPresentationController {
popoverController.sourceView = <<valid reference to sending view>>;
}
self.present(shareSheet, animated: true);
When the user clicks "Messages" it only shows the image that was retrieved from the local URL and the String "Test Text" is not appended to the message body.
However, if the URL is changed to an external URL such as https://google.com, both the URL and the "Test Text" appear in the Messages body.
Is there a reason both text (Strings) and images (URLs linking to the app's documents folder) aren't shown in the Messages body?
I want to use UIActivityViewController to share files from my iOS app. The main question for me is how do I handle different file types.
What I'v got so far:
Images
public void OpenInExternalApp(string filepath)
{
if (!File.Exists(filepath))
return;
UIImage uiImage = UIImage.FromFile(filepath);
// Define the content to share
var activityItems = new NSObject[] { uiImage };
UIActivity[] applicationActivities = null;
var activityController = new UIActivityViewController(activityItems, applicationActivities);
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone)
{
// Phone
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(activityController, true, null);
}
else
{
// Tablet
var popup = new UIPopoverController(activityController);
UIView view = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
CGRect rect = new CGRect(view.Frame.Width/2, view.Frame.Height, 50, 50);
popup.PresentFromRect(rect, view, UIPopoverArrowDirection.Any, true);
}
}
Don't know if from the memory management aspect it is a good idea to load the image at once. What will happen if the image is too big for holding it completely in RAM? See here for example.
Strings
var activityItems = new NSObject[] { UIActivity.FromObject(new NSString(text)) };
Only text.
NSUrl
NSUrl url = NSUrl.CreateFileUrl(filepath, false, null);
Here in most cases the same app appear. But for example the PDF reader doesn't appear for a PDF file. The preview in mail on the other side shows Adobe Acrobat.
Everything
var activityItems = new NSObject[] { NSData.FromFile(filepath) };
The last approach has the disadvantage that not all apps are displayed, which for example could open a PDF file. Also this applies.
I want to use all types of files. I don't think a subclass of UIActivity would help here. Perhaps a sublcass of UIActivityItemProvider?
Side note: You can also post your solutions in Objective C/Swift.
I tried to implement UIActivityItemProvider, but here again not all apps where shown for the corresponding filetype. E.g. for a docx-document Word was not shown.
Now I switched to UIDocumentInteractionController and now there are many apps available.
UIDocumentInteractionController documentController = new UIDocumentInteractionController();
documentController.Url = new NSUrl(filepath, false);
string fileExtension = Path.GetExtension(filepath).Substring(1);
string uti = UTType.CreatePreferredIdentifier(UTType.TagClassFilenameExtension.ToString(), fileExtension, null);
documentController.Uti = uti;
UIView presentingView = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
documentController.PresentOpenInMenu(CGRect.Empty, presentingView, true);
Imho there are too many apps, because the file type xml should not be really be supported by a PDF reader, but it is. Nevertheless, it seems to work now thanks to this post:
In general if you’re sharing an image or url, you might want to use a UIActivityViewController. If you’re sharing a document, you might want to use a UIDocumentInteractionController.
I am trying to share an audio file from my ios app to whatsapp, but with a direct opening of whatsapp, and not an opening of the sharing menu with all the tiles.
Here is what i have now:
// Getting the original file
let fileName = #MY FILE NAME#
let filePath = Bundle.main.path(forResource: fileName, ofType: "mp3")!
let urlData = URL.init(fileURLWithPath: filePath)
let nsData = NSData(contentsOf: urlData)
if (nsData != nil){
// Creating the temporary file to share in the accessible ressources
let newFileName = "file.mp3"
let newFilePath = "\(NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])/\(newFileName)"
nsData?.write(toFile: newFilePath, atomically: true)
let newUrlData = URL.init(fileURLWithPath: newFilePath)
// Sharing the file to whatsapp
// Possibility 1 (does not work yet)
// let documentController = UIDocumentInteractionController(url: newUrlData)
// documentController.uti = "net.whatsapp.audio"
// documentController.presentOpenInMenu(from: CGRect.zero, in: self.view, animated: true)
// Possibility 2 (works only with the sharing menu)
let activityVC = UIActivityViewController(activityItems: [NSURL(fileURLWithPath: newFilePath)], applicationActivities: nil)
self.present(activityVC, animated: true, completion: nil)
}
As I do this, sharing an audio file to whatsapp works, but it first open the sharing menu, with the messenger tile, message tile, notes tile, ... (and it doesn't works for the messenger app). In the end I would like to be able to share on messenger AND whatsapp.
As explicated here in the whatsapp documentation, I want to open directly the whatsapp application when I try to share the file:
Alternatively, if you want to show only WhatsApp in the application list (instead of WhatsApp plus any other public/*-conforming apps) you can specify a file of one of aforementioned types saved with the extension that is exclusive to WhatsApp:
images - «.wai» which is of type net.whatsapp.image
videos - «.wam» which is of type net.whatsapp.movie
audio files - «.waa» which is of type net.whatsapp.audio
When triggered, WhatsApp will immediately present the user with the contact/group picker screen. The media will be automatically sent to a selected contact/group.
So I tried to change the line :
let newFileName = "file.mp3"
To one of these :
let newFileName = "file.mp3.waa"
let newFileName = "file.waa"
let newFileName = "file.waa.mp3"
But it still shows the same sharing menu (and can't read the audiofile if it ends with the .waa extension).
-> 1) Is it possible to do what I want to do ?
-> 2) If not, is there a way to share to messenger & whatsapp with the same code keeping one sharing menu
-> 3) If not, is there a way to reduce the sharing menu to only one tile depending on different calling event, so there is no confusing choosing of tiles
Thanks,
Antoine
Cf: XCODE / IOS - How to use exclusive extension to immediately present whatsapp (.wai, .waa, .wam)
FYI: As I went through a lot of tests with this, I couldn't find any solution yet.
Whatsapp recognize the file extension, but cannot even read it. Once shared, when you click on it, it's written ".whatsapp audio file", nothing more (And it's not even shared directly).
I sent a email to whatsapp developper team, they said they have others problem to fix currently, so it's not even on their to do list.
Wait & see..
I want to use UIActivityViewController to share files from my iOS app. The main question for me is how do I handle different file types.
What I'v got so far:
Images
public void OpenInExternalApp(string filepath)
{
if (!File.Exists(filepath))
return;
UIImage uiImage = UIImage.FromFile(filepath);
// Define the content to share
var activityItems = new NSObject[] { uiImage };
UIActivity[] applicationActivities = null;
var activityController = new UIActivityViewController(activityItems, applicationActivities);
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone)
{
// Phone
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(activityController, true, null);
}
else
{
// Tablet
var popup = new UIPopoverController(activityController);
UIView view = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
CGRect rect = new CGRect(view.Frame.Width/2, view.Frame.Height, 50, 50);
popup.PresentFromRect(rect, view, UIPopoverArrowDirection.Any, true);
}
}
Don't know if from the memory management aspect it is a good idea to load the image at once. What will happen if the image is too big for holding it completely in RAM? See here for example.
Strings
var activityItems = new NSObject[] { UIActivity.FromObject(new NSString(text)) };
Only text.
NSUrl
NSUrl url = NSUrl.CreateFileUrl(filepath, false, null);
Here in most cases the same app appear. But for example the PDF reader doesn't appear for a PDF file. The preview in mail on the other side shows Adobe Acrobat.
Everything
var activityItems = new NSObject[] { NSData.FromFile(filepath) };
The last approach has the disadvantage that not all apps are displayed, which for example could open a PDF file. Also this applies.
I want to use all types of files. I don't think a subclass of UIActivity would help here. Perhaps a sublcass of UIActivityItemProvider?
Side note: You can also post your solutions in Objective C/Swift.
I tried to implement UIActivityItemProvider, but here again not all apps where shown for the corresponding filetype. E.g. for a docx-document Word was not shown.
Now I switched to UIDocumentInteractionController and now there are many apps available.
UIDocumentInteractionController documentController = new UIDocumentInteractionController();
documentController.Url = new NSUrl(filepath, false);
string fileExtension = Path.GetExtension(filepath).Substring(1);
string uti = UTType.CreatePreferredIdentifier(UTType.TagClassFilenameExtension.ToString(), fileExtension, null);
documentController.Uti = uti;
UIView presentingView = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
documentController.PresentOpenInMenu(CGRect.Empty, presentingView, true);
Imho there are too many apps, because the file type xml should not be really be supported by a PDF reader, but it is. Nevertheless, it seems to work now thanks to this post:
In general if you’re sharing an image or url, you might want to use a UIActivityViewController. If you’re sharing a document, you might want to use a UIDocumentInteractionController.
I'm attempting to print a PDF file in my Cordova application on iOS.
The file is generated using jsPDF in the Cordova app and then I've modified the katzer cordova-plugin-printer to accept the raw PDF data as a string, convert it to NSData and print it out.
- (void) printPDFFromData:(CDVInvokedUrlCommand*)command
{
if (!self.isPrintingAvailable)
{
return;
}
NSArray* arguments = [command arguments];
NSString* documentData = [arguments objectAtIndex:0];
NSData* pdfData = [documentData dataUsingEncoding:NSUTF8StringEncoding];
UIPrintInteractionController* controller = printController;
[self adjustSettingsForPrintController:controller];
controller.printingItem = pdfData;
[self openPrintController:controller];
[self commandDelegate];
}
Using the iOS print simulator (I don't have access to an AirPrint printer), the PDF appears to print out, except that the background image is not printed, just the vector drawings overlaying it.
The same raw output data when saved to a PDF file will display the background image and when you print that file, the background image is printed.
Is this just an anomaly of the printer simulator or do I need to somehow set the print controller to be able to print the image in the document?
I found a solution to the issue. Something was getting lost in the decoding of the string data from JavaScript into Objective-C.
To get around this I Base64 encoded the PDF document in my JS side before sending it off to the plugin:
var startIndexOfBase64Data = 28;
var base64Document = doc.output('dataurlstring').substring(startIndexOfBase64Data);
window.plugin.printer.printPDFFromData(base64Document);
Then I needed to add
NSData+Base64.m and NSData+Base64.h
from this sample project into my plugins directory to allow this line of code to convert the Base64 string into NSData:
NSData* pdfData = [NSData dataFromBase64String:documentData];
Then the document then printed out untainted.
Now I'm off to see if I can get it working with Android.