5

Is it possible to download and add a passbook from within a webview without modifying the app to support the new MIME type or unknown MIME types like Sparrow did?

I have a news ios app with a webview. In the webview I display the news items and a banner. When you click the banner I want to open a url to a .pkpass file and add it to my passbook. Instead I get a FrameLoadInterrupted error and nothing visible happens. If I open the url from safari this works fine, chrome, since earlier this week (version 23) also opens the url like intended.

Is this some weird strategy from Apple maybe? not allowing this MIME type to properly open from a webview?

Ben
  • 13,297
  • 4
  • 47
  • 68
  • He Ben, I'm sure that the default Safari can handle the. If you open this site: [http://passkit.com/samples/](http://passkit.com/samples/) you can download some examples. You might want to try opening this page in a `UIWebView` to if they still work. – rckoenes Nov 30 '12 at 14:12
  • Safari handles it fine as I mentioned. From a UIWebView nothing happens. – Ben Nov 30 '12 at 15:02
  • It does appear that the `UIWebView` can't open the passbook files. – rckoenes Nov 30 '12 at 15:12
  • Is there now way to trick the UIWebView to open a .pkpass? Because I think the alternative would be to extend the app in question to support this MIME type. – Ben Nov 30 '12 at 15:24
  • Do you think that it will work to solve my problem? http://stackoverflow.com/questions/42415655/ios-passbook-download-a-file-pkpass-from-dynamic-link-from-ios-webview – luismaAto Feb 23 '17 at 16:39

2 Answers2

3

My best bet is that the UIWebView is just not capable of handling the Passbook passes. You could however try and catch the downloading in the UIWebViewDelegate method -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType.

What I mean to say is that you have to handle this part your self, since the http://passkit.com/samples/ I used does not return an url which ends pkpass thus it is totally depended on how you request the passbook files.

If you do in include the .pkpass extension you can check for the extension in the request.

If you know what kind of URL the passbook file is at you write your own download code here and pass it to passbook via the passbook api.


There does not seem to be any great on fix for this, you could load the failed ULR in safari:

- (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
    NSLog(@"Webview: %@", error);

    if ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102) {
        NSString *failedURL = [error.userInfo objectForKey:NSURLErrorFailingURLStringErrorKey];

        if (failedURL == nil) {
            return;
        }
        NSURL *url = [NSURL URLWithString:failedURL];

        [[UIApplication sharedApplication] openURL:url];
    }
}

But this is just really bad coding.

rckoenes
  • 69,092
  • 8
  • 134
  • 166
  • Yes I do agree, but the demo app I build using [`http://passkit.com/samples/`](http://passkit.com/samples/) did not handle the redirect, so the most I could get out of it was an url like `https://pass.is/bEmKtX` thus I could not really any generic code the handle `. pkpass`. Thus that solution will not work. – rckoenes Nov 30 '12 at 15:37
  • I don't quite understand what you're doing here, but the first two paragraphs are correct, you have to catch the request and handle it yourself. There are samples out there that show how to do this. – ohmi Dec 01 '12 at 00:28
3

Okay, talked to the engineers at WWDC and this is a know bug in UIWebView but Apple probably won't fix it because they're encouraging people to adopt the new SFSafariViewController. We did come up with a hack to fix it should you need to support iOS 6-8:

  1. Add the PassKit framework to the project if it isn't already.

    #import <PassKit/PassKit.h>
    
  2. Set up a delegate for the UIWebView (for example the view controller launching the UIWebView)

    <UIWebViewDelegate>
    
  3. Add a class variable to cache the UIWebView requests

    NSURLRequest *_lastRequest;
    
  4. Set the delegate

    self.webView.delegate = self;
    
  5. Add the callback to grab all requests and cache in case of failure

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
        _lastRequest = request;
        return YES;
    }
    
  6. Add the failure callback and re-fetch the URL to see if it is a pass and if so, present the pass to the user

    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
        // try to get headers in case of passbook pass
        NSOperationQueue *queue = [[NSOperationQueue alloc] init];
        [NSURLConnection sendAsynchronousRequest:_lastRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            // check for PKPass
            if ([response.MIMEType isEqualToString:@"application/vnd.apple.pkpass"]) {
                NSError *error;
                PKPass *pass = [[PKPass alloc] initWithData:data error:&error];
                if (error) {
                    NSLog(@"Error: %@", error);
                } else {
                    PKAddPassesViewController *apvc = [[PKAddPassesViewController alloc] initWithPass:pass];
                    [self presentViewController:apvc animated:YES completion:nil];
                }
            }
        }];
    }
    

It's a horrible hack for what should be supported, but it works regardless of the extension and should support re-directs. If you want to pile on the bug train, you can reference radar://21314226

Kudit
  • 4,212
  • 2
  • 26
  • 32