objective-c - UIActivityViewController che si blocca su iOS 8 iPad





ios8 (13)


Swift:

    let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)

    //if iPhone
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone) {
        self.presentViewController(activityViewController, animated: true, completion: nil)
    } else { //if iPad
        // Change Rect to position Popover
        var popoverCntlr = UIPopoverController(contentViewController: activityViewController)
        popoverCntlr.presentPopoverFromRect(CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0), inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)

    }

Attualmente sto testando la mia app con Xcode 6 (Beta 6). UIActivityViewController funziona perfettamente con dispositivi e simulatori iPhone ma si blocca con simulatori e dispositivi iPad (iOS 8) con i seguenti registri

Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController (<_UIAlertControllerActionSheetRegularPresentationController: 0x7fc7a874bd90>) should have a non-nil sourceView or barButtonItem set before the presentation occurs.'

Sto usando il seguente codice per iPhone e iPad sia per iOS 7 che per iOS 8

NSData *myData = [NSData dataWithContentsOfFile:_filename];
NSArray *activityItems = [NSArray arrayWithObjects:myData, nil];
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:nil applicationActivities:nil];
activityViewController.excludedActivityTypes = @[UIActivityTypeCopyToPasteboard];
[self presentViewController:activityViewController animated:YES completion:nil];

Sto ottenendo un crash simile anche in una delle mie altre app. Puoi per favore guidarmi? qualcosa è cambiato con UIActivityViewController in iOS 8? Ho controllato ma non ho trovato nulla su questo




Ho trovato questa soluzione In primo luogo, il controller di visualizzazione che presenta il popover dovrebbe implementare il protocollo <UIPopoverPresentationControllerDelegate> .

Successivamente, dovrai impostare il delegato di popoverPresentationController .

Aggiungi queste funzioni:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Assuming you've hooked this all up in a Storyboard with a popover presentation style
    if ([segue.identifier isEqualToString:@"showPopover"]) {
        UINavigationController *destNav = segue.destinationViewController;
        PopoverContentsViewController *vc = destNav.viewControllers.firstObject;

        // This is the important part
        UIPopoverPresentationController *popPC = destNav.popoverPresentationController;
        popPC.delegate = self;
    }
}

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController: (UIPresentationController *)controller {
    return UIModalPresentationNone;
}



Swift, iOS 9/10 (dopo UIPopoverController deprecato)

let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)

    if UIDevice.currentDevice().userInterfaceIdiom == .Pad {

       if activityViewController.respondsToSelector(Selector("popoverPresentationController")) {
          activityViewController.popoverPresentationController?.sourceView = self.view
        }
    }

    self.presentViewController(activityViewController, animated: true, completion: nil)



swift = ios7 / ios8

let activityViewController = UIActivityViewController(activityItems: sharingItems, applicationActivities: nil)

//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone) {
    // go on..
} else {
    //if iPad
    if activityViewController.respondsToSelector(Selector("popoverPresentationController")) {
        // on iOS8
        activityViewController.popoverPresentationController!.barButtonItem = self.shareButtonItem;
    }
}
self.presentViewController(activityViewController, animated: true, completion: nil)



Per Swift 2.0. Ho scoperto che funziona se stai cercando di ancorare il popover a un pulsante di condivisione su iPad. Ciò presuppone che tu abbia creato uno sbocco per il pulsante di condivisione nella barra degli strumenti.

func share(sender: AnyObject) {
    let firstActivityItem = "test"

    let activityViewController = UIActivityViewController(activityItems: [firstActivityItem], applicationActivities: nil)

    if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone {
        self.presentViewController(activityViewController, animated: true, completion: nil)
    }
    else {            
        if activityViewController.respondsToSelector("popoverPresentationController") {
            activityViewController.popoverPresentationController!.barButtonItem = sender as? UIBarButtonItem
            self.presentViewController(activityViewController, animated: true, completion: nil)
        }

    }
}



Ho provato il prossimo codice e funziona:

prima metti un oggetto nel tuo View Controller e poi crea un IBOutlet:

@property(weak,nonatomic)IBOutlet UIBarButtonItem *barButtonItem;

successivamente nel file .m: yourUIActivityViewController.popoverPresentationController.barButtonItem = self.barButtonItem;




Lo stesso problema è arrivato al mio progetto quindi ho trovato la soluzione che per aprire UIActivityViewController in iPad dobbiamo usare UIPopoverController

Ecco un codice per usarlo in iPhone e iPad entrambi

//to attach the image and text with sharing 
UIImage *image=[UIImage imageNamed:@"giraffe.png"];
NSString *[email protected]"Image form My app";
NSArray *[email protected][str,image];

UIActivityViewController *controller = [[UIActivityViewController alloc] initWithActivityItems:postItems applicationActivities:nil];

//if iPhone
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
    [self presentViewController:controller animated:YES completion:nil];
}
//if iPad
else {
    // Change Rect to position Popover
    UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:controller];
    [popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/4, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}

Per il rapido 3

let imageURL: URL = URL(string: product.images[0].fullImageUrlString)!
let objectsToShare: [AnyObject] = [imageURL as AnyObject]
let activityViewController = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view
activityViewController.excludedActivityTypes = [ UIActivityType.airDrop]
self.present(activityViewController, animated: true, completion: nil)



Su iPad, il controller della visualizzazione attività verrà visualizzato come un popover utilizzando il nuovo UIPopoverPresentationController , richiede che venga specificato un punto di ancoraggio per la presentazione del popover utilizzando una delle seguenti tre proprietà:

Per specificare il punto di ancoraggio è necessario ottenere un riferimento a UIPopoverPresentationController di UIActivityController e impostare una delle proprietà come segue:

if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) { 
// iOS8
 activityViewController.popoverPresentationController.sourceView =
parentView;
 }



Fai attenzione se stai sviluppando per iPad usando swift, funzionerà bene nel debug, ma si bloccherà nel rilascio. Per farlo funzionare con testFlight e AppStore, disabilita l'ottimizzazione per swift usando -none for release.




Swift 3:

class func openShareActions(image: UIImage, vc: UIViewController) {
    let activityVC = UIActivityViewController(activityItems: [image], applicationActivities: nil)
    if UIDevice.current.userInterfaceIdiom == .pad {
        if activityVC.responds(to: #selector(getter: UIViewController.popoverPresentationController)) {
            activityVC.popoverPresentationController?.sourceView = vc.view
        }
    }
    vc.present(activityVC, animated: true, completion: nil)
}



Correzione per Swift 2.0

    if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.Phone {
        self.presentViewController(activityVC, animated: true, completion: nil)
    }
    else {
        let popup: UIPopoverController = UIPopoverController(contentViewController: activityVC)
        popup.presentPopoverFromRect(CGRectMake(self.view.frame.size.width / 2, self.view.frame.size.height / 4, 0, 0), inView: self.view, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true)
    }



In Swift per risolvere questo problema per iPad, il modo migliore è quello di fare come ho trovato.

    let things = ["Things to share"]
    let avc = UIActivityViewController(activityItems:things, applicationActivities:nil)
    avc.setValue("Subject title", forKey: "subject")
    avc.completionWithItemsHandler = {
        (s: String!, ok: Bool, items: [AnyObject]!, err:NSError!) -> Void in
    }

    self.presentViewController(avc, animated:true, completion:nil)
    if let pop = avc.popoverPresentationController {
        let v = sender as! UIView // sender would be the button view tapped, but could be any view
        pop.sourceView = v
        pop.sourceRect = v.bounds
    }



Controlla questo: al momento questo è solo per Debug su dispositivo iOS non simulatore

  1. Scarica l'SDK da Apple
  2. Copia questo file immagine iOS 11.0 in: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/
  3. Riavvia Xcode.




ios objective-c ios8 uiactivityviewcontroller