Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 732
netwire Avatar asked Aug 16 '14 14:08

netwire


2 Answers

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
}
like image 151
kevin Avatar answered Nov 18 '22 14:11

kevin


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.

like image 2
Léo Natan Avatar answered Nov 18 '22 12:11

Léo Natan