iOS 8 SDK: modal UIWebView and camera/image picker

2019-01-04 08:36发布

I have found that, when compiling for iOS 8 (and running in iOS 8), a UIWebView cannot show the camera/image picker if the UIWebView is in a view controller presented modally. It works without problem in view controllers directly “hanging” from the window rootViewController or view controllers pushed from it.

The test application can be found at https://dl.dropboxusercontent.com/u/6214425/TestModalWebCamera.zip but I will describe it below.

My test application (built with storyboards, but the real application doesn’t use them) has two view controllers (unoriginally named ViewController and ViewController2). ViewController is contained in a UINavigationController which is the root view controller. ViewController contains a UIWebView (works OK), a button that “shows” (“pushes”) ViewController2, and a UIBarButtonItem which modally presents ViewController2. ViewController2 has another UIWebView which works when “pushed” but not when “presented”.

Both ViewController and ViewController2 are loaded with:

- (void)viewDidLoad {
  [super viewDidLoad];

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

When trying to use the modal UIWebView Xcode prints the following in the console and dismisses the app modal:

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

My current theory is that the changes in UIActionSheet to UIAlertController might have produced this situation, but it’s quite hard to prove. I will open a Radar with Apple, just in case.

Has someone found the same situation and some workaround?

7条回答
smile是对你的礼貌
2楼-- · 2019-01-04 09:24

Alright, here's the workaround I ended up using. It's a 2 minute change, pretty hacky, but works as expected and avoids the bug we're all having. Basically, rather than presenting the child view controller modally, I set it to the window's rootViewController and keep a reference to the parent controller. So where I used to have this (in parent view controller):

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

I now have this

view.window?.rootViewController = newController

In both cases, the parent controller is newController's delegate, which is how I keep the reference.

newController.delegate = self

Finally, where in my delegate callback for closing the modal, where I used to have this:

dismissViewControllerAnimated(true, completion: nil)

I now have this:

viewController.view.window?.rootViewController = self

So we get the same effect of a view controller taking over the screen entirely, then yielding its control when it's done. In this case though, it's not animated. I have a feeling animating the controller transition wouldn't be very hard with some of the built in view animations.

Hopefully you're already using the delegate pattern to manage communication with the modal controller, per Apple's recommendation, but if you're not I'm sure you can use any number of methods that keep a reference and get called back.

查看更多
登录 后发表回答