UIActivityViewController falla en iPads con iOS 8

Resuelto Bhumit Mehta asked hace 54 años • 21 respuestas

Actualmente estoy probando mi aplicación con Xcode 6 (Beta 6). UIActivityViewController funciona bien con dispositivos y simuladores de iPhone, pero falla con simuladores y dispositivos de iPad (iOS 8) con los siguientes registros

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

Estoy usando el siguiente código para iPhone y iPad tanto para iOS 7 como para 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];

También recibo un fallo similar en otra de mis aplicaciones. ¿Puedes por favor guiarme? ¿Ha cambiado algo con UIActivityViewController en iOS 8? Revisé pero no encontré nada sobre esto.

Bhumit Mehta avatar Jan 01 '70 08:01 Bhumit Mehta
Aceptado

En iPad, el controlador de vista de actividad se mostrará como una ventana emergente usando el nuevo UIPopoverPresentationController ; requiere que especifique un punto de anclaje para la presentación de la ventana emergente usando una de las tres propiedades siguientes:

  • barraBotónArtículo
  • fuenteVer
  • fuenteRect

Para especificar el punto de anclaje, necesitará obtener una referencia al UIPopoverPresentationController de UIActivityController y establecer una de las propiedades de la siguiente manera:

if ( [activityViewController respondsToSelector:@selector(popoverPresentationController)] ) { 
// iOS8
 activityViewController.popoverPresentationController.sourceView =
parentView;
 }
mmccomb avatar Sep 03 '2014 12:09 mmccomb

El mismo problema llegó a mi proyecto y luego encontré la solución de que para abrir el UIActivityViewControlleriPad tenemos que usarUIPopoverController

Aquí hay un código para usarlo tanto en iPhone como en iPad:

//to attach the image and text with sharing 
UIImage *image=[UIImage imageNamed:@"giraffe.png"];
NSString *str=@"Image form My app";
NSArray *postItems=@[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];
}

Para rápido 4,2/rápido 5

func openShareDilog() {
    let text = "share text will goes here"

    // set up activity view controller
    let textToShare = [text]
    let activityViewController = UIActivityViewController(activityItems: textToShare, applicationActivities: nil)
    activityViewController.excludedActivityTypes = [.airDrop]

    if let popoverController = activityViewController.popoverPresentationController {
        popoverController.sourceRect = CGRect(x: UIScreen.main.bounds.width / 2, y: UIScreen.main.bounds.height / 2, width: 0, height: 0)
        popoverController.sourceView = self.view
        popoverController.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
    }

    self.present(activityViewController, animated: true, completion: nil)
}
Hardik Thakkar avatar Nov 28 '2014 13:11 Hardik Thakkar

Me encontré con este problema exacto recientemente (la pregunta original) en Swift 2.0, donde UIActivityViewControllerfuncionó bien para iPhones, pero causó fallas al simular iPads.

Solo quiero agregar a este hilo de respuestas que, al menos en Swift 2.0, no necesitas una declaración if. Puedes hacer lo popoverPresentationControlleropcional.

Como comentario rápido, la respuesta aceptada parece decir que podría tener solo un sourceView, solo un sourceRect o solo un barButtonItem, pero de acuerdo con la documentación de Apple para UIPopoverPresentationController necesita uno de los siguientes:

  • barraBotónArtículo
  • fuenteView y fuenteRect

El ejemplo particular en el que estaba trabajando se encuentra a continuación, donde estoy creando una función que toma UIView(para sourceView y sourceRect) y String(el único elemento de actividad de UIActivityViewController).

func presentActivityViewController(sourceView: UIView, activityItem: String ) {

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

    activityViewController.popoverPresentationController?.sourceView = sourceView
    activityViewController.popoverPresentationController?.sourceRect = sourceView.bounds

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

Este código funciona en iPhone y iPad (e incluso en tvOS, creo). Si el dispositivo no es compatible popoverPresentationController, las dos líneas de código que lo mencionan se ignoran esencialmente.

Es bueno que todo lo que necesitas hacer para que funcione para iPads sea simplemente agregar dos líneas de código, ¡o solo una si estás usando un barButtonItem!

Galen avatar Jan 04 '2016 16:01 Galen

Veo a mucha gente codificando iPhone/iPad, etc. mientras usan código Swift.

Esto no es necesario, debe utilizar las funciones de idioma. El siguiente código supone que utilizará UIBarButtonItem y funcionará tanto en iPhone como en iPad.

@IBAction func share(sender: AnyObject) {
    let vc = UIActivityViewController(activityItems: ["hello"], applicationActivities: nil)
    vc.popoverPresentationController?.barButtonItem = sender as? UIBarButtonItem
    self.presentViewController(vc, animated: true, completion: nil)
 }

Observe cómo no hay declaraciones If ni ninguna otra locura. El desenvolvimiento opcional será nulo en iPhone, por lo que la línea vc.popoverPresentationController?no hará nada en iPhones.

Martin Marconcini avatar Jan 22 '2016 01:01 Martin Marconcini