7

I'm using SFSafariViewController to grab user's cookie in my app. Here's is my code:

SFSafariViewController *safari = [[SFSafariViewController alloc]initWithURL:[NSURL URLWithString:referrerUrl] entersReaderIfAvailable:NO];
    safari.delegate = self;
    safari.modalPresentationStyle = UIModalPresentationOverCurrentContext;
    safari.view.alpha = 0.0;
    safari.view.hidden = true;
    [self dismissViewControllerAnimated:false completion:nil];
    NSLog(@"[referrerService - StoreViewController] presenting safari VC");
    [self presentViewController:safari animated:false completion:nil];

This works well on iOS 9. but on iOS 10 it seems that the SF controller doesn't work (it also block my current context - which happens to be another UIWebView).

Anyone can suggest of an alternative way to hide a SFSafariViewController?

oriharel
  • 10,418
  • 14
  • 48
  • 57

4 Answers4

12

Updated answer:

Apple prohibits this kind of SafariViewController usage in last version of review guidelines:

SafariViewContoller must be used to visibly present information to users; the controller may not be hidden or obscured by other views or layers. Additionally, an app may not use SafariViewController to track users without their knowledge and consent.

Old answer:

In iOS 10 there are some additional requirements for presented SFSafariViewController:

1) Your view should not be hidden, so hidden should be set to NO

2) The minimum value for alpha is 0.05

3) You need to add controller manually with addChildViewController: / didMoveToParentViewController: (callback's doesn't called otherwise).

4) UIApplication.keyWindow.frame and SFSafariViewController.view.frame should have non-empty intersection (in appropriate coordinate space), that means:

  • safari view size should be greater than CGSizeZero

  • you can't place safari view off the screen

  • but you can hide safari view under your own view

Code example:

self.safariVC = [[SFSafariViewController alloc] initWithURL:referrerUrl];
self.safariVC.delegate = self;
self.safariVC.view.alpha = 0.05;
[self addChildViewController:self.safariVC];
self.safariVC.view.frame = CGRectMake(0.0, 0.0, 0.5, 0.5);
[self.view insertSubview:self.safariVC.view atIndex:0];
[self.safariVC didMoveToParentViewController:self];

Also, don't forget to remove safariVC properly after the end of the usage:

[self.safariVC willMoveToParentViewController:nil];
[self.safariVC.view removeFromSuperview];
[self.safariVC removeFromParentViewController];
Roman Ermolov
  • 7,898
  • 5
  • 27
  • 35
  • Is this documented somewhere? – Brian Sep 02 '16 at 00:31
  • @Zaph0d42 nope, this knowledge comes from tests and reverse engineering. – Roman Ermolov Sep 02 '16 at 04:16
  • I ended up doing something similar to that. (changed the alpha to 0.05). The app is not in the AppStore yet. – oriharel Sep 03 '16 at 11:57
  • @oriharel FYI: Apple prohibits this kind of SafariViewController usage in last version of [review guidelines](https://developer.apple.com/app-store/review/guidelines). – Roman Ermolov Sep 03 '16 at 12:27
  • @RomanErmolov I'm using this method for install referrer purposes. following this post https://library.launchkit.io/how-ios-9-s-safari-view-controller-could-completely-change-your-app-s-onboarding-experience-2bcf2305137f#.l1petjuia. Do you know of any alternative of achieving what Google is providing as INSTALL_REFERRER for the Android SDK? – oriharel Sep 03 '16 at 13:24
  • @oriharel unfortunately, I don't know another 100% way to attribution. AFAIK most of analytic systems, that provide attribution on iOS use hidden SafariVC to match click & install, when it possible. If it is impossible, they use heuristic behavior. – Roman Ermolov Sep 03 '16 at 17:05
  • there are a lot of questionable things like this that apps get away with. Are apps getting removed from the app store for this? – faceyspacey.com Nov 12 '16 at 16:23
  • @faceyspacey.com I don't know about concrete apps, but think that it is possible – Roman Ermolov Nov 13 '16 at 09:55
2

New info: Don't do this. The revised App Store guidelines prohibit this practice.

https://developer.apple.com/app-store/review/guidelines/

I'll leave this below for posterity: I call the following code from my app delegate's didFinishLaunchingWithOptions.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self checkCookie];
}

- (void)checkCookie
{
    NSURL *url = [NSURL URLWithString:@"http://domainToCheck.com"];
    SFSafariViewController *vc = [[SFSafariViewController alloc] initWithURL:url];
    vc.delegate = self;

    UIViewController *windowRootController = [[UIViewController alloc] init];

    self.secondWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.secondWindow.rootViewController = windowRootController;
    [self.secondWindow makeKeyAndVisible];
    [self.secondWindow setAlpha:0.1];

    [windowRootController presentViewController:vc animated:NO completion:nil];
    self.window.windowLevel = 10;
}

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(nonnull NSDictionary<NSString *,id> *)options
{
    [self.secondWindow.rootViewController dismissViewControllerAnimated:NO completion:nil];
    self.secondWindow = nil;
    self.window.windowLevel = 0;

    return YES;
}
Brian
  • 772
  • 1
  • 13
  • 31
0

I was able to achieve this affect using invisible child view controller:

_safariViewController = [[SFSafariViewController alloc] initWithURL:_requestURL];
_safariViewController.delegate = self;
_safariViewController.view.userInteractionEnabled = NO;
_safariViewController.view.alpha = 0.0;
[_containerViewController addChildViewController:_safariViewController];
[_containerViewController.view addSubview:_safariViewController.view];
[_safariViewController didMoveToParentViewController:_containerViewController];
_safariViewController.view.frame = CGRectZero;
Zorayr
  • 23,770
  • 8
  • 136
  • 129
  • Can you explain what is _containerViewController? In my case, 'self' is a view controller. could I use that instead? I actually tried and I get exceptions. – oriharel Aug 24 '16 at 19:22
  • _containerViewController can be any VC that's currently visible. Can you tell me more about your exception? – Zorayr Aug 25 '16 at 20:42
-1

its possible to use this on swift 3 for xcode 8.3.2 becausa i get all i delegate anduse correctly , but i have this error

[12:05] 2017-04-25 12:05:03.680 pruebaslibrary[7476:136239] Warning: Attempt to present on whose view is not in the window hierarchy!