ios objective-c ios8 uiwebview uiimagepickercontroller

iOS 8 SDK: modal UIWebView y selector de cámara/imagen



objective-c ios8 (7)

He encontrado que, al compilar para iOS 8 (y ejecutar en iOS 8), un UIWebView no puede mostrar el selector de cámara / imagen si el UIWebView está en un controlador de vista presentado de manera modal. Funciona sin problemas en los controladores de vista directamente "colgando" de la ventana rootViewController o en los controladores de vista empujados desde ella.

La aplicación de prueba se puede encontrar en https://dl.dropboxusercontent.com/u/6214425/TestModalWebCamera.zip pero lo describiré a continuación.

Mi aplicación de prueba (construida con guiones gráficos, pero la aplicación real no los usa) tiene dos controladores de vista (llamados originalmente ViewController y ViewController2 ). ViewController está contenido en un UINavigationController que es el controlador de vista raíz. ViewController contiene un UIWebView (funciona bien), un botón que "muestra" ("empuja") ViewController2 y un UIBarButtonItem que presenta ViewController2 modal. ViewController2 tiene otro UIWebView que funciona cuando se "empuja" pero no cuando se "presenta".

Tanto ViewController como ViewController2 están cargados con:

- (void)viewDidLoad { [super viewDidLoad]; [self.webView loadHTMLString:@"<input type=/"file/" accept=/"image/*;capture=camera/">" baseURL:nil]; }

Al intentar usar el modal UIWebView Xcode imprime lo siguiente en la consola y descarta el modal de la aplicación:

Warning: Attempt to present <UIImagePickerController: 0x150ab800> on <ViewController2: 0x14623580> whose view is not in the window hierarchy!

Mi teoría actual es que los cambios en UIActionSheet a UIAlertController podrían haber producido esta situación, pero es bastante difícil de probar. Abriré un Radar con Apple, por si acaso.

¿Alguien ha encontrado la misma situación y alguna solución?


Descubrí que en iOS 8.0.2 el iPad no parece tener ese error, pero el iPhone todavía lo tiene.

Sin embargo, anulando el siguiente en el controlador de vista que contiene la uiwebview

-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion

Y comprobar que hay un PresentViewController parece funcionar.

Pero es necesario verificar los efectos secundarios

#import "UiWebViewVC.h" @interface UiWebViewVC () @property (weak, nonatomic) IBOutlet UIWebView *uiwebview; @end @implementation UiWebViewVC - (void)viewDidLoad { [super viewDidLoad]; NSURL *url = [NSURL URLWithString:@"http://html5demos.com/file-api-simple"]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; self.uiwebview.scalesPageToFit = YES; [self.uiwebview loadRequest:request]; } -(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion { if ( self.presentedViewController) { [super dismissViewControllerAnimated:flag completion:completion]; } } @end


Estaba teniendo un problema similar y descubrí que los elementos UIWebView en IOS no admiten el elemento html:

No estoy seguro de por qué Apple decidió no admitir este elemento html IMPORTANTE, pero estoy seguro de que tienen sus razones. (Aunque este elemento funciona perfectamente en Safari en iOS).

En muchos casos, cuando el usuario hace clic en este tipo de botón en un UIWebView, les permitirá tomar / elegir una foto. SIN EMBARGO, el UIWebView en IOS no tiene la capacidad de adjuntar archivos como este en los datos POST cuando se envía el formulario.

La solución: para realizar la misma tarea, puede crear un formulario similar en InterfaceBuilder con un botón que active el UIImagePickerController. Luego, crea una solicitud HTTP POST con todos los datos del formulario y la imagen. No es tan difícil como parece, consulte el siguiente enlace para ver un código de muestra que hace el trabajo: ios Cargar imagen y texto usando HTTP POST


Lo que hice cada vez que cambia el controlador de vista, convierte la vista de destino en la raíz.

desde el primer controlador de vista:

let web = self.storyboard?.instantiateViewController(withIdentifier:"web") as! UINavigationController view.window?.rootViewController = web

así es como paso la raíz a la otra, y cuando regreso a la primera, hice esto.

desde el controlador de vista web:

let first = self.storyboard?.instantiateViewController(withIdentifier: "reveal") as! SWRevealViewController present(first, animated: true, completion: nil)

y todo está bien, puedo mostrar el modal para seleccionar una foto de la biblioteca, tomar una foto y todo lo demás.

No sé si es una buena práctica, pero funciona bien en emulador y dispositivo.

Espero eso ayude.


Mi solución es crear un controlador de vista personalizado con una presentación modal personalizada basada en la jerarquía de controladores hijo-padre. La animación será la misma para que el usuario no note la diferencia.

Mis sugerencias para la animación:

animateWithDuration:(animated ? 0.6 : 0.0) delay:0.0 usingSpringWithDamping:1.f initialSpringVelocity:0.6f options:UIViewAnimationOptionCurveEaseOut

Se verá exactamente como la animación de presentación modal predeterminada en iOS7 / 8.


Muy bien, aquí está la solución que terminé usando. Es un cambio de 2 minutos, bastante hacky, pero funciona como se esperaba y evita el error que todos tenemos. Básicamente, en lugar de presentar el controlador de vista secundario modalmente, lo configuro en rootViewController de la ventana y mantengo una referencia al controlador principal. Entonces, donde solía tener esto (en el controlador de vista principal):

presentViewController(newController, animated: true, completion: nil)

Ahora tengo esto

view.window?.rootViewController = newController

En ambos casos, el controlador newController es el delegado de newController , y así es como mantengo la referencia.

newController.delegate = self

Finalmente, en mi devolución de llamada delegada para cerrar el modal, donde solía tener esto:

dismissViewControllerAnimated(true, completion: nil)

Ahora tengo esto:

viewController.view.window?.rootViewController = self

Entonces obtenemos el mismo efecto de un controlador de vista que se apodera completamente de la pantalla y luego cede su control cuando está hecho. En este caso, sin embargo, no está animado. Tengo la sensación de que animar la transición del controlador no sería muy difícil con algunas de las animaciones de vista incorporadas.

Con suerte, ya está utilizando el patrón de delegado para administrar la comunicación con el controlador modal, según la recomendación de Apple, pero si no lo está, estoy seguro de que puede usar cualquier número de métodos que mantengan una referencia y que le devuelvan la llamada.


Para mí, tiendo a tener un UINavigationController personalizado para que múltiples vistas puedan compartir la misma lógica. Entonces, para mi solución (en Swift), esto es lo que puse en mi NavigationController personalizado.

import UIKit class NavigationController: UINavigationController { override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } override func dismissViewControllerAnimated(flag: Bool, completion: (() -> Void)?) { if let vc = self.presentedViewController { // don''t bother dismissing if the view controller being presented is a doc/image picker if !vc.isKindOfClass(UIDocumentMenuViewController) || !vc.isKindOfClass(UIImagePickerController) { super.dismissViewControllerAnimated(flag, completion:completion) } } } override func viewDidLoad() { super.viewDidLoad() // make sure that the navigation controller can''t be dismissed self.view.window?.rootViewController = self } }

Esto significa que puede tener un montón de controladores de vista con vistas web y todos trabajarán con el elemento de carga de archivos.


Tengo el mismo problema en iOS 9. Intente agregar ivar ''_flag'' y luego anule estos métodos en el controlador de vista con UIWebView

#pragma mark - Avoiding iOS bug - (UIViewController *)presentingViewController { // Avoiding iOS bug. UIWebView with file input doesn''t work in modal view controller if (_flagged) { return nil; } else { return [super presentingViewController]; } } - (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion { // Avoiding iOS bug. UIWebView with file input doesn''t work in modal view controller if ([viewControllerToPresent isKindOfClass:[UIDocumentMenuViewController class]] ||[viewControllerToPresent isKindOfClass:[UIImagePickerController class]]) { _flagged = YES; } [super presentViewController:viewControllerToPresent animated:flag completion:completion]; } - (void)trueDismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion { // Avoiding iOS bug. UIWebView with file input doesn''t work in modal view controller _flagged = NO; [self dismissViewControllerAnimated:flag completion:completion]; }

Esto me funciona bien