Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Open In apps for plain text

I would like to provide the ability for users to tap the Action button and up pops the usual share sheet, which should include other apps to the right of the Messages, Facebook, etc icons - applications that can work with .txt files, or just an NSString.

I am currently displaying a Share sheet via UIActivityViewController, which is working great but it does not include other apps in the list. From reading other SO questions I concluded it's only possible to get those other apps to appear if you use UIDocumentInteractionController instead. I looked into creating a .txt file in a temp directory to share that file (instead of just sharing an NSString), but only Mail (no Copy) shows up when I tap the Share button. [Do note that if I run it on a real device not the simulator more apps other than Mail will appear and AirDrop too.] When I tap Mail, the app crashes: Unable to get data for URL: The operation couldn’t be completed. (Cocoa error 260.) Something is wrong with the way I'm creating/retrieving the .txt file.

My questions are:

  • Why is my code resulting in a crash when attempting to share the .txt file?
  • How can I get the Copy option to appear in the same Share sheet as the one that includes other apps?

To summarize: I need a share sheet that includes: Copy, AirDrop, Messages, Mail, Facebook, Twitter, Pages, Dropbox, etc for a simple string of text. Thanks!

The following lines of code lie inside my IBAction share button tap function:
UIActivityViewController approach:

UIActivityViewController *activityView = [[UIActivityViewController alloc] initWithActivityItems:@[self.myUITextField.text] applicationActivities:nil];
[self presentViewController:activityView animated:YES completion:nil];

Result:
enter image description here

UIDocumentInteractionController approach:

NSString *fileName = [NSString stringWithFormat:@"%@mytextfile.txt", NSTemporaryDirectory()];
[self.myUITextField.text writeToFile:fileName
                          atomically:NO
                            encoding:NSStringEncodingConversionAllowLossy
                               error:nil];
NSURL *textFileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"mytextfile.txt"]];

UIDocumentInteractionController *documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:textFileURL];
[documentInteractionController presentOptionsMenuFromBarButtonItem:sender animated:YES];

Result (will show more apps and AirDrop if I run on a real device):

enter image description here

Example of what I want to obtain - minus the 3 extra options at the bottom:

enter image description here

If I cannot obtain the above screenshot with a string (instead of a photo) for some reason, I am willing to implement it how Dropbox has done it. They added an Open In button at the bottom that presents a different sheet that only shows additional apps. Note that I would still need a Copy option on the original sheet.

enter image description here

enter image description here

like image 259
Jordan H Avatar asked Dec 06 '25 14:12

Jordan H


1 Answers

Question 1: Why is my code resulting in a crash

Cocoa error 260 is an NSFileReadNoSuchFileError according to the Foundation Constants Reference document. Looking at your code, the only way how I can see that file creation might fail is if self.myUITextField is nil.

I suggest that you check this first. If the property is not nil, then check whether writeToFile:atomically:encoding:error: returns an error.


Question 2: How can I get the Copy option to appear

First, assign a delegate to the controller:

documentInteractionController.delegate = self;

Then implement the following two delegate methods:

- (BOOL) documentInteractionController:(UIDocumentInteractionController*)controller canPerformAction:(SEL)action
{
  if (@selector(copy:) == action)
    return YES;
  else
    return NO;
}

- (BOOL) documentInteractionController:(UIDocumentInteractionController*)controller performAction:(SEL)action
{
  if (@selector(copy:) != action)
    return NO;
  // Perform the copy: action
  return YES;
}

Both methods are marked deprecated since iOS 6, but they still seem to work in iOS 7. Unfortunately, I have no idea how to implement the copy: action without those two methods - and neither does Apple, or so it seems to me, since they do not offer a replacement, and the official Document Interaction Programming Topics for iOS document still happily refers to the methods without indication that they are deprecated.

Anyway, here's a simple but complete implementation of the second delegate method:

- (BOOL) documentInteractionController:(UIDocumentInteractionController*)controller performAction:(SEL)action
{
  if (@selector(copy:) != action)
    return NO;

  NSStringEncoding usedEncoding;
  NSError* error;
  NSString* fileContent = [NSString stringWithContentsOfURL:controller.URL
                                               usedEncoding:&usedEncoding
                                                      error:&error];
  UIPasteboard* pasteboard = [UIPasteboard generalPasteboard];
  [pasteboard setString:fileContent];
  return YES;
}
like image 151
herzbube Avatar answered Dec 08 '25 06:12

herzbube



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!