UIDocumentInteractionController for Open In menu - Doesn't Work - ios

I implemented a UIDocumentInteractionController to send files to other apps. The file is a .txt file.
Here's the code:
UIDocumentInteractionController *interactionController = [[UIDocumentInteractionController alloc] init];
[interactionController setURL:[NSURL fileURLWithPath:filePath]];
[interactionController setUTI:#"public.text"];
[interactionController setDelegate:self];
[interactionController presentOpenInMenuFromBarButtonItem:actionBarButtonItem animated:YES];
The menu opens fine, showing apps like Pages, Dropbox, etc. as I expect. But when I tap one of them, the Open In menu dismisses and no action is performed (the file is not sent and the target application never opens.
I tried implementing the delegate methods documentInteractionController:canPerformAction: and documentInteractionController:performAction: for triggering copy: and print: calls using the options menu (as opposed to the open in menu) and that pulled up a menu with only Pages listed, but that still did not work.
How might this be resolved?

I found the answer, and it's memory management. I create the UIDocumentInteractionController and then present it, but I don't have it as an instance variable. ARC deallocates it before it has the opportunity to do anything. This includes sending the document to the external app.
This bug didn't appear on the iPhone, but on the iPad it gives an error because the popover architecture works a bit differently and it ends up trying to draw it when it's deallocated. That's what alerted me to the bug.

This bug also appears on iPhone/iPod. Just set:
#property (nonatomic, retain) UIDocumentInteractionController *docController;
and it will be retain and the document passed to the new application.

it's enough to add the following code:
[interactionController retain];

Related

Repeated speech in email compose window when using Voiceover

As Voiceover users attempt to dictate in an email compose window, their words are repeated back to them as they speak.
Although this does not happen in Mail, it does occur both in my complex shipped app, and in a very simple test app, which is just a default template with only this code added...
#interface ViewController () <MFMailComposeViewControllerDelegate>
-(void) viewDidAppear:(BOOL)animated {
MFMailComposeViewController *mailViewController = [[MFMailComposeViewController alloc] init];
mailViewController.mailComposeDelegate = self;
[mailViewController setSubject:#"Subject Goes Here."];
[mailViewController setMessageBody:#"Your message goes here." isHTML:NO];
[self presentViewController:mailViewController animated:YES completion:NULL];
}
Has anyone seen this, and knows of a solution, or can confirm that it is an iOS bug? I see almost no similar reports of it around the web.
I do wonder if I am using Voiceover incorrectly, but I don't see a similar problem in Mail. Normal dictation into this window works fine (although I am seeing a stereo waveform displayed instead of the usual mono one at the moment- I'm not sure if that is relevant)
I was able to replicate the behavior, but you have to do some weird things. The only way I was able to get this to happen was by moving accessibility focus away and back into the composer view after enabling dictation. This is a bug and since it's a bug contained in a bit of private API it's a bug you can't really work around. In practice I would suspect that it's a bug that wouldn't show itself very frequently.

UIDocumentPickerViewController and 'Locations' not showing in mode UIDocumentPickerModeMoveToService

I have Dropbox installed on my iOS 8.02 iPad.
I want to export files to either Dropbox or iCloud Drive via the UIDocumentPickerViewController.
If I present my controller using mode 'UIDocumentPickerModeMoveToService'
UIDocumentPickerViewController *viewController = [[UIDocumentPickerViewController alloc] initWithURL:self.datasource.myFileUrl inMode:UIDocumentPickerModeMoveToService];
viewController.delegate = self;
[self presentViewController:viewController animated:YES completion:^{}];
I do not get a Locations nav-bar button and so cannot select DropBox as an alternative location...
Whereas is I use mode 'UIDocumentPickerModeExportToService' when creating my controller, I do get the Locations menu item...
According to the Apple docs, there's a subtle difference between the two modes...
UIDocumentPickerModeExportToService The document picker exports a
local file to a destination outside the app’s sandbox.
Available in iOS 8.0 and later.
UIDocumentPickerModeMoveToService The document picker moves a local
file outside the app’s sandbox and provides access to it as an
external file.
Available in iOS 8.0 and later.
Which to me, doesn't signal that Locations will be restricted depending on which mode I select.
Is this a bug, or am I doing something wrong here?
This appears to have been a bug as it is now working correctly in 8.1

Iphone app that launches a website without url bar

I need to make a simple app for iOS. After opening it, i want it to open up safari with a certain website and that the address bar wouldn't show.
I'm completely new to iOS apps and I couldn't find anything similar from google. Maybe somebody has done it and can share the code or point me to somewhere where I can find it?
You can simply use a UIWebView, which by default doesn't include any controls or an address bar.
Class documentation here
Here is a small example of usage:
UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"www.google.ie"]]];
[self.view addSubview:webView];
This will effectively give you a browser view inside your application, without invoking Safari itself.
You can embed this UIWebView in a UINavigationController, or use it anywhere else in your applications view hierarchy.
One final point, the UIWebView class has many delegate methods which you can implement, these methods will be called by the system when a given event happens (URL loads, has errors, etc).

UIActivityViewController: Choosing an activity for which permissions are denied leads to a dead end

I am using a UIActivityViewController to implement image sharing.
UIActivityViewController *shareVC = [[UIActivityViewController alloc] initWithActivityItems:#[image] applicationActivities:nil];
[shareVC setCompletionHandler:^(NSString *activityType, BOOL completed){
NSLog(#"completed image export activity: %# - %d", activityType, completed);
}];
[self presentViewController:shareVC animated:true completion:nil];
In testing, I have noticed that if the user selects, for example, "Assign to Contact", but then denies the permission in the ensuing dialog, then they are taken to a screen that says "This app does not have access to your contacts. You can enable access in Privacy Settings.", from which there is no way to back out. The only way for them then to get back to the actual app is to manually restart it.
I'm fairly happy to leave this behaviour as is for now since I don't anticipate any users will be particularly bothered by it, but I'd like to know if there is a sensible way to work around it, and if it is indeed the expected behaviour.
Hmm, maybe you could check if a segue is called when the new "This app does not have access to your contacts. You can..."-Viewcontroller is shown. Then you could manipulate the destinationViewController property of the segue and add for example a button, with an action enabling the user to go back.
All highly theroretical.
I am working on the iPad platform, and in that context presenting a UIActivityViewController directly is wrong according to the documentation, which states that
When presenting the view controller, you must do so using the appropriate means for the current device. On iPad, you must present the view controller in a popover. On iPhone and iPod touch, you must present it modally.
In most ways, the behaviour of the modally presented view controller on iPad seemed perfectly fine, but this case illustrates why it is not appropriate. I don't know how the equivalent case is handled on iPhone / iPod touch as I haven't really looked at those platforms just yet.
Now that I am presenting it in a UIPopoverController, the view explaining that the app doesn't have access to contacts appears within the popup, and is dismissed as the popup is dismissed. Unfortunately it appears that the completion handler is not called in this case; I'm not sure if that's an iOS bug or if I lack understanding of something. It is a slight problem for me at the moment, so I'll have to work around it.
Unfortunately, it seems relatively unlikely that anyone experiencing a related problem will be helped by my question / answer; maybe I'll try to edit the question.

UIImagePickerController and External display

I am writing an iPad kiosk-type application that allows a visitor to record a video using the front facing camera and view existing videos in the Camera Roll that are targeting an External monitor. I am just learning XCode, and working in Xcode 4.4.1 targeting iOS 5. It seems like a lot has changed recently and this is making it much harder to learn so I am trying to keep things as simple as possible, that's why I am using UIImagePicker.
Everything is working as I wish, with one exception – I am not able to toggle between the external display and the iPad as I want. When the user records a video, it is full screen on the iPad. That's fine, however after they stop recording, the video is immediately sent to the external display for approval and a placeholder image is left in the UIPopover. What I would rather see/do is either keep the video preview full screen on the iPad, or target the video to the UIPopover.
The reason is that the external display is not easily viewable from where the user is accessing the iPad. Therefore, they are being asked to approve (click Use) on something they can't really see. It would be much better to keep it on the iPad. The code below is what I have used to allow recording.
Everything else works great, I want the user to select videos from the Library and display on the External monitor, and since that's the default behavior it works fine.
The closest answer I could find so far is this: UIImagePickerController in an existing UIPopoverController
Is there a simple way to disable the external display or keep the video preview from being sent?
- (IBAction)useCameraRoll:(id)sender
{
if([self.popoverController isPopoverVisible]) {
[self.popoverController dismissPopoverAnimated:YES];
} else {
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum])
{
UIImagePickerController *imagePicker =
[[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *) kUTTypeMovie, nil];
imagePicker.allowsEditing = NO;
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:imagePicker];
//self.popoverController = [[UIPopoverController alloc] setContentViewController:animated];
self.popoverController.delegate = self;
[self.popoverController
presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
newMedia = NO;
}
}
}
Coincidentally, I have been working on a similar kiosk app with an iPad. In my case it utilizes some Augmented Reality to show relevant content on the external display. I use the iPad screen as a configuration panel for the augmented reality experience.
Best way, that I found, to approach this, would be to use separate windows with the two UIScreens for each of the displays. This enables you to craft the experience properly. I am not sure if you are using this approach already, but if you aren't, then this is the way to go.
To get started you can read the ExternalDisplay code sample. From the excerpt:
From the ExternalDisplay sample code in the iOS Developer Library:
To display content on an external display, do the following:
Use the screens class method of the UIScreen class to determine if an external display is available.
If an external screen is available, get the screen object and look at the values in its availableModes property. This property contains
the configurations supported by the screen.
Select the UIScreenMode object corresponding to the desired resolution and assign it to the currentMode property of the screen
object.
Create a new window object (UIWindow) to display your content.
Assign the screen object to the screen property of your new window.
Configure the window (by adding views or setting up your OpenGL ES rendering context).
Show the window.
Also, the UIScreen documentation is quitehelpful.

Resources