Reputation: 13615
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?
Upvotes: 6
Views: 3703
Reputation: 4379
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:
Add the PassKit framework to the project if it isn't already.
#import <PassKit/PassKit.h>
Set up a delegate for the UIWebView (for example the view controller launching the UIWebView)
<UIWebViewDelegate>
Add a class variable to cache the UIWebView requests
NSURLRequest *_lastRequest;
Set the delegate
self.webView.delegate = self;
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;
}
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
Upvotes: 4
Reputation: 69469
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.
Upvotes: 3