Xcode 6 + iOS 8 SDK but deploy on iOS 7 (UIWebKit & WKWebKit)

14,362

Solution 1

You will need to check if WKWebView is available, and fall back to UIWebView if its not.

Make sure you weak link WebKit.framework (set to optional)

Objective-C:

WKWebView *wkWebView = nil;
UIWebView *uiWebView = nil;

Class wkWebViewClass = NSClassFromString(@"WKWebView");
if(wkWebViewClass) {
    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    // ...
    wkWebView = [[wkWebViewClass alloc] initWithFrame:frame configuration:config];
    [self.view addSubview:wkWebView];
}
else {
    uiWebView = [[UIWebView alloc] initWithFrame:frame];
    [self.view addSubview:uiWebView];
}

Swift:

var wkWebView : WKWebView?
var uiWebView : UIWebView?

if NSClassFromString("WKWebView") {
    let config = WKWebViewConfiguration()
    // ...
    wkWebView = WKWebView(frame: frame, configuration: config)
    self.view.addSubview(wkWebView)
}
else {
    uiWebView = UIWebView(frame: frame)
    self.view.addSubview(uiWebView)
}

Then elsewhere in your code:

Objective-C:

if(wkWebView) {
    // WKWebView specific code
}
else {
    // UIWebView specific code
}

Swift:

if let w=wkWebView {
    // WKWebView specific code
}
else if let w=uiWebView {
    // UIWebView specific code
}

Solution 2

If you need to support iOS7, you cannot use WebKit2 (WK*) classes, or you need to implement twice the logic, once for iOS8 using WK* and once using UIWeb*, and at runtime choose according to the operating system version.

Share:
14,362

Related videos on Youtube

netwire
Author by

netwire

Updated on September 15, 2022

Comments

  • netwire
    netwire over 1 year

    We are creating an app using Xcode 6 beta 5 + Swift on iOS 8 SDK. We'd like to deploy to iOS 7 as well. Is that possible? When we set the deployment target of the project to 7.0, we get compile time errors like this:

    Undefined symbols for architecture x86_64:
      "_OBJC_CLASS_$_WKPreferences", referenced from:
          __TMaCSo13WKPreferences in WebViewController.o
      "_OBJC_CLASS_$_WKWebView", referenced from:
          __TMaCSo9WKWebView in WebViewController.o
      "_OBJC_CLASS_$_WKWebViewConfiguration", referenced from:
          __TMaCSo22WKWebViewConfiguration in WebViewController.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    I believe that's because we are using WKWebKit, which is supported by iOS 8+ only. We are ok with using UIWebKit for iOS 7 but WKWebKit for iOS 8. How do we define that?

    Our class definition looks like this...

    import WebKit
    
    class WebViewController: UIViewController, WKNavigationDelegate {
       ...
    }
    

    and it's called by:

            let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let destinationVC = mainStoryboard.instantiateViewControllerWithIdentifier("WebViewController") as WebViewController
            presentViewController(destinationVC, animated: true, completion: nil)
    

    I was thinking about using this fragment to call presentViewController but that doesn't solve the compile time issues. (NSFoundationVersionNumber doesn't solve compile time issues either)

        if ((UIDevice.currentDevice().systemVersion as NSString).floatValue >= 8.0) {
    
        } else {
    
        }
    

    UPDATE: kkoltzau has the correct answer. I'm adding some more info for others.

    First, go to your Project, click on General, scroll down to Linked Frameworks and Libraries, and add WebKit.framework as Optional. (I also did it for UIKit.framework) See screenshot:

    enter image description here

    As for my WebViewController class. It still imports UIKit and WebKit. but the viewDidLoad() sets the view based on kkoltzau's example. Then whenever I need to load/reload the web page, it checks for existence of wkWebView.

  • rmaddy
    rmaddy over 9 years
    None of this addresses the question which is about linker errors.
  • netwire
    netwire over 9 years
    Thanks kkoltzau, let me try and report back. Interesting to know you can set class via 'NSClassFromString'
  • kevin
    kevin over 9 years
    @rmaddy Weak linking to WebKit.framework, mentioned in the second sentence, covers the linker error.
  • netwire
    netwire over 9 years
    Thanks kkoltzau about setting WebKit.framework to optional. I can't paste screenshot, but I'll do so as an answer for others.
  • netwire
    netwire over 9 years
    My class also implements WKNavigationDelegate, including methods such as ` func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation)` and func webView(webView: WKWebView, didCommitNavigation navigation: WKNavigation). How do I include them in this example?
  • netwire
    netwire over 9 years
    The app was able to compile, but at runtime, on an iOS 8 device, it's giving me an error that wkWebView = WKWebView(frame: webViewWrapper.bounds, configuration: configuration) resulted in nil, as no WKWebView was created. I can't tell if it's because let configuration = WKWebViewConfiguration() failed or not.
  • kevin
    kevin over 9 years
    @Dean Regarding WKNavigationDelegate, just implement it as usual. I don't know why WKWebView would fail to create assuming WebKit.framework is properly linked.
  • ABeanSits
    ABeanSits over 9 years
    @kkoltzau I understand why you would instantiate the WKWebView class from a string, but what is the reason for doing it with the WKWebViewConfiguration class as well?
  • Piwaf
    Piwaf almost 9 years
    That sentence 2 about "Make sure you weak link WebKit.framework (set to optional)" is super important. I actually didn't even have WebKit.Framework listed so I needed to added it and set to Optional.