wake-up-neo.net

iOS 8 SDK: Modal UIWebView und Kamera-/Bildauswahl

Ich habe festgestellt, dass beim Kompilieren für iOS 8 (und Ausführen unter iOS 8) ein UIWebView den Kamera-/Bild-Picker nicht anzeigen kann, wenn der UIWebView in einem View-Controller modal dargestellt ist. Es funktioniert problemlos in View-Controllern, die direkt aus dem Fenster rootViewController "hängen" oder View-Controllern, die aus diesem Fenster verschoben werden.

Die Testanwendung ist unter https://dl.dropboxusercontent.com/u/6214425/TestModalWebCamera.Zip zu finden, ich werde sie jedoch unten beschreiben.

Meine Testanwendung (mit Storyboards erstellt, die reale Anwendung verwendet sie jedoch nicht) verfügt über zwei Ansichtscontroller (die ursprünglich nicht ViewController und ViewController2 heißen). ViewController ist in einem UINavigationController enthalten, bei dem es sich um den Root-View-Controller handelt. ViewController enthält einen UIWebView (funktioniert OK), eine Schaltfläche, die ViewController2 „zeigt“ („drückt“) und ein UIBarButtonItem, das ViewController2 modal darstellt. ViewController2 hat ein anderes UIWebView, das funktioniert, wenn es gedrückt wird, aber nicht, wenn es angezeigt wird.

Sowohl ViewController als auch ViewController2 werden geladen mit:

- (void)viewDidLoad {
  [super viewDidLoad];

  [self.webView loadHTMLString:@"<input type=\"file\" accept=\"image/*;capture=camera\">" baseURL:nil];
}

Beim Versuch, das Modal zu verwenden, UIWebView Xcode druckt Folgendes in der Konsole und das App-Modal wird verworfen:

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

Meine derzeitige Theorie ist, dass die Änderungen in UIActionSheet in UIAlertController diese Situation hervorgerufen haben könnten, aber es ist ziemlich schwer zu beweisen. Ich werde ein Radar mit Apple öffnen, nur für den Fall.

Hat jemand die gleiche Situation und einen Workaround gefunden?

35
yonosoytu

Ich habe festgestellt, dass das iPad in iOS 8.0.2 diesen Fehler nicht zu haben scheint, aber das iPhone noch immer.

Überschreibt jedoch Folgendes in dem View Controller, der den uiwebview enthält

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

Und zu prüfen, dass es einen PresentViewController gibt, scheint zu funktionieren. 

Aber müssen Nebenwirkungen überprüfen

#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
46
seeinvisible

Ich habe das gleiche Problem unter iOS 9. Versuchen Sie, ivar '_flag' hinzuzufügen, und überschreiben Sie dann diese Methoden im Ansichts-Controller mit 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];
}

Das funktioniert gut für mich

7
Artyom Devyatov

Für mich tendiere ich dazu, einen benutzerdefinierten UINavigationController zu haben, so dass mehrere Ansichten dieselbe Logik verwenden können. Für meinen Workaround (in Swift) stelle ich Folgendes in meinen benutzerdefinierten NavigationController ein.

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
    }
}

Dies bedeutet, dass Sie eine Menge View-Controller mit Webviews haben können, die alle mit dem Datei-Upload-Element funktionieren.

2
Jeremy JC Paul

Ich hatte ein ähnliches Problem und habe festgestellt, dass die UIWebView-Elemente in IOS das HTML-Element nicht unterstützen:

Ich bin nicht sicher, warum Apple dieses WICHTIGE HTML-Element nicht unterstützt, aber ich bin sicher, dass sie ihre Gründe haben. (Auch wenn dieses Element auf Safari unter IOS perfekt funktioniert.)

Wenn der Benutzer in einem UIWebView auf diese Schaltfläche klickt, kann er in vielen Fällen ein Foto aufnehmen/auswählen. Die UIWebView in IOS kann jedoch Dateien wie diese nicht an die POST - Daten anhängen, wenn das Formular gesendet wird.

Die Lösung: Um dieselbe Aufgabe zu erfüllen, können Sie in InterfaceBuilder ein ähnliches Formular mit einer Schaltfläche erstellen, die den UIImagePickerController auslöst. Anschließend erstellen Sie eine HTTP-Anforderung POST mit allen Formulardaten und dem Image. Es ist nicht so hart, wie es sich anhört. Schauen Sie sich den folgenden Link an, um Beispielcode zu erhalten, mit dem die Arbeit erledigt wird: ios Bild und Text mit HTTP hochladen POST

1
Takide

Was ich bei jeder Änderung des View-Controllers getan habe, konvertiere die Zielansicht in root.

aus erster Sicht Controller:

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

view.window?.rootViewController = web

so übergebe ich die Wurzel an die andere und beim Comeback an die erste habe ich dies gemacht.

vom Web-View-Controller:

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

und alles ist in Ordnung, ich kann die Modalität für ausgewähltes Foto aus der Bibliothek zeigen, Fotos machen und alles andere.

Ich weiß nicht, ob das eine gute Praxis ist, funktioniert aber gut in Emulator und Gerät.

Ich hoffe es hilft.

0
Jason Sa

Okay, hier ist die Problemumgehung, die ich am Ende verwendet habe. Es ist eine Änderung von 2 Minuten, ziemlich hackig, funktioniert aber wie erwartet und vermeidet den Fehler, den wir alle haben. Grundsätzlich habe ich den untergeordneten View-Controller nicht modal dargestellt, sondern auf rootViewController des Fensters gesetzt und einen Verweis auf den übergeordneten Controller beibehalten. Wo hatte ich das (im übergeordneten Ansichtscontroller):

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

Ich habe jetzt das

view.window?.rootViewController = newController

In beiden Fällen ist der übergeordnete Controller der Delegierte von newController, und so bewahre ich die Referenz auf.

newController.delegate = self

Schließlich, wo in meinem Delegierten Callback für das Schließen des Modals, wo ich das hatte:

dismissViewControllerAnimated(true, completion: nil)

Ich habe jetzt folgendes:

viewController.view.window?.rootViewController = self

Wir haben also den gleichen Effekt, wenn ein View-Controller den Bildschirm vollständig übernimmt und seine Kontrolle übernimmt, wenn er fertig ist. In diesem Fall wird es jedoch nicht animiert. Ich habe das Gefühl, dass der Controller-Übergang mit einigen der integrierten Ansichtsanimationen nicht sehr schwer ist.

Hoffentlich verwenden Sie bereits das Delegatenmuster, um die Kommunikation mit dem modalen Controller gemäß den Empfehlungen von Apple zu verwalten. Wenn Sie sich jedoch nicht sicher sind, können Sie eine beliebige Anzahl von Methoden verwenden, die eine Referenz enthalten und zurückgerufen werden.

0
bloudermilk

Meine Lösung besteht darin, einen benutzerdefinierten View Controller mit einer benutzerdefinierten modalen Darstellung zu erstellen, die auf der untergeordneten Parent-Hierarchie der Controller basiert. Die Animation ist die gleiche, so dass der Benutzer den Unterschied nicht bemerkt.

Meine Vorschläge zur Animation:

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

In iOS7/8 sieht es genauso aus wie die standardmäßige modale Präsentationsanimation.

0
kelin