9

I am currently developing an application specifically for iOS7 that utilizes UIDocumentInteractionController open in menu and need a method that notifies me when a user cancels and does not choose an available option.

UIDocumentInteractionControllerDelegate offers:

- (void)documentInteractionControllerDidDismissOptionsMenu:(UIDocumentInteractionController *) controller

but this does not specify whether the user tapped one of the available options or cancel.

Any ideas?

morcutt
  • 3,739
  • 8
  • 30
  • 47

4 Answers4

9

NOTE: This will not work for iOS 8 anymore, only iOS7 and earlier

To determine whether the user has canceled the menu or selected an option, you have to make use of the following delegate methods:

1-

- (void)documentInteractionController:(UIDocumentInteractionController *)controller
           didEndSendingToApplication:(NSString *)application
{
    //get called only when the user selected an option and then the delegate method bellow get called
    // Set flag here _isOptionSelected = YES;
    _isOptionSelected = YES;
}

2-

- (void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller
{
    //called whether the user has selected option or not
    // check your flag here 
    if(_isOptionSelected == NO) {
        //the user has canceled the menu
     }
    _isOptionSelected = NO;
}

iOS 8

For iOS 8 and above, use this method instead of the one in step 2:

- (void)documentInteractionController:(UIDocumentInteractionController *)controller
           didEndSendingToApplication:(NSString *)application
Basheer_CAD
  • 4,908
  • 24
  • 36
  • 3
    This won't work, `DidDismissOpenInMenu` is called before `DidEndSendingToApplication`. You need to use `WillBeginSendingToApplication` instead. – Luke Oct 28 '14 at 08:35
  • lukech is right. This answer is on the right track but flawed, despite the multiple up votes and bounty. I think Basheer_CAD had the answer, but the post had a typo. You need to check WillBegin... rather than DidEnd... to determine if the user selected an app. – BuvinJ Jun 04 '15 at 14:41
  • Thanks @BuvinJ, please edit the answer I will approve your edit, thank you – Basheer_CAD Jun 17 '15 at 15:49
  • I provided an edit. I tried to not change too much! It's similar to what I'm using now for iOS 5 through 8. – BuvinJ Jun 17 '15 at 19:26
  • I think my edits are being rejected, as they are disappearing. I don't know how that works. I'm not getting any direct notification of it. – BuvinJ Jun 18 '15 at 16:43
  • @BuvinJ, unfortunately your edit was not approved by admins, there was more rejects votes than approves – Basheer_CAD Jun 18 '15 at 18:11
  • Ok... I don't get that, since my edits are definitively accurate. Thanks for the explanation Basheer! – BuvinJ Jun 18 '15 at 19:28
  • @Basheer_CAD, why don't you just edit it instead of waiting that someone else do it and his change get approved? if you edit it it doesn't need approval – jcesarmobile Dec 01 '15 at 12:33
0

This will work on iOS7 && iOS8

BOOL didSelectOptionFromDocumentController = NO;//**set this to "NO" every time you present your documentInteractionController too

-(void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application {
    didSelectOptionFromDocumentController = YES;
}


-(void)documentInteractionControllerDidDismissOpenInMenu:(UIDocumentInteractionController *)controller {
    if (didSelectOptionFromDocumentController == NO) {//user cancelled.
        
    }
}
Community
  • 1
  • 1
Albert Renshaw
  • 17,282
  • 18
  • 107
  • 195
0

This works for iOS8 & iOS9 for 3rd party apps AND System Apps!

It's not pretty but it works.

Can anyone tell me if this will pass App Review? Not sure as I'm referring to a class name which is not publicly accessible (_UIDocumentActivityViewController). This is Swift 2.2!

NSObject Extension to get a string of the class name:

extension NSObject {
    var theClassName: String {
        return NSStringFromClass(self.dynamicType)
    }
}

Your Viewcontroller where you're calling the UIDocumentInteractionController from:

var appOpened = false
var presentedVCMonitoringTimer: NSTimer!
var docController: UIDocumentInteractionController!

func openDocController() {
    docController = UIDocumentInteractionController(URL: yourURL!)
    docController.UTI = "your.UTI"
    docController.delegate = self
    docController.presentOptionsMenuFromRect(CGRectZero, inView: self.view, animated: true)

    // Check the class of the presentedViewController every 2 seconds
    presentedVCMonitoringTimer = NSTimer.scheduledTimerWithTimeInterval(2, target: self, selector: #selector(self.checkPresentedVC), userInfo: nil, repeats: true)
}

func checkPresentedVC() {
    if let navVC = UIApplication.sharedApplication().keyWindow?.rootViewController as? UINavigationController {
        print(navVC.presentedViewController?.theClassName)
        if navVC.presentedViewController != nil && (navVC.presentedViewController?.theClassName)! != "_UIDocumentActivityViewController" && (navVC.presentedViewController?.theClassName)! != self.theClassName {
            // A system App was chosen from the 'Open In' dialog
            // The presented ViewController is not the DocumentInteractionController (anymore) and it's not this viewcontroller anymore (could be for example the MFMailComposeViewController if the user chose the mail app)
            appOpened = true
            presentedVCMonitoringTimer?.invalidate()
            presentedVCMonitoringTimer = nil
        }
    }
}

func documentInteractionControllerDidDismissOptionsMenu(controller: UIDocumentInteractionController) {
    print("dismissedOptionsMenu")
    presentedVCMonitoringTimer?.invalidate()
    presentedVCMonitoringTimer = nil
    if appOpened {
        // Do your thing. The cancel button was not pressed
        appOpened = false
    }
    else {
        // Do your thing. The cancel button was pressed
    }
}

func documentInteractionController(controller: UIDocumentInteractionController, willBeginSendingToApplication application: String?) {
    // A third party app was chosen from the 'Open In' menu.
    appOpened = true
    presentedVCMonitoringTimer?.invalidate()
    presentedVCMonitoringTimer = nil
}
guido
  • 2,792
  • 1
  • 21
  • 40
0

For Swift 4, use this:

 func documentInteractionControllerDidDismissOpenInMenu(_ controller: UIDocumentInteractionController) {

        // this function get called when users finish their work, 
        // either for sharing thing within the same app or exit to other app will do
 }

I use it when after users have shared image to Facebook and Instagram.