12

我正在使用 WebKit 框架的 WKWebView 并尝试提交到应用商店时,我收到此错误:

Your app contains non-public API usage. Please review the errors, correct them, and resubmit your application.
The app links to non-public libraries in Payload...: /System/Library/PrivateFrameworks/WebKit.framework/WebKit

如果我将部署目标设置为 8.0,那么错误就会消失,但我也想支持 iOS 7。该错误似乎是 iOS7 也具有 WebKit 框架的结果,但当时它是私有的。

因此,我想动态链接到 WebKit 库。我怎样才能在 XCode 中做到这一点?

4

1 回答 1

16

Well, finally got this working after many hours of frustration.

Until Apple fixes the validation, the key is to dynamically link to the WebKit framework at runtime. Your project should already be using runtime checks to gracefully fall back to UIWebView for iOS7 and earlier, i.e. checking for [WKWebView class].

Step 1: Remove the WebKit framework from the project settings. Go to your target -> General -> Linked Frameworks and Libraries, and remove WebKit. At this point, your code will compile but fail to link because it cannot resolve the WKWebView and associated symbols.

Step 2: Edit your main.m file to load the library dynamically:

#import <UIKit/UIKit.h>
#import <TargetConditionals.h>
#import <dlfcn.h>
#import "MyAppDelegate.h"

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

int main(int argc, char * argv[])
{
    @autoreleasepool {
        // Dynamically load WebKit if iOS version >= 8
        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
#if TARGET_IPHONE_SIMULATOR
            NSString *frameworkPath = [[NSProcessInfo processInfo] environment][@"DYLD_FALLBACK_FRAMEWORK_PATH"];
            if (frameworkPath) {
                NSString webkitLibraryPath = [NSString pathWithComponents:@[frameworkPath, @"WebKit.framework", @"WebKit"]];
                dlopen([webkitLibraryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_LAZY);
            }
#else
            dlopen("/System/Library/Frameworks/WebKit.framework/WebKit", RTLD_LAZY);
#endif
        }

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([MyAppDelegate class]));
    }
}

I use a runtime OS version check because Apple only allow dynamic library loading starting in iOS 8. The library location is different for the simulator vs actual devices, so I use conditional compilation to check for that.

Step 3: Since the library is loaded dynamically, calling [WKWebView class] and [WKWebView alloc] won't work. Go through your code, changing every instance of

[WKWebView class]
// change to:
NSClassFromString(@"WKWebView")

And change every time you allocate a WKWebView:

[WKWebView alloc]
// change to:
[NSClassFromString(@"WKWebView") alloc]

You must also do this for the associated classes, including WKWebViewConfiguration, WKProcessPool, WKUserScript, and whatever others you are using. Check your linker errors for anything you may have missed.

Step 4: Now your code should successfully compile. Package, submit to the app store, and celebrate.

于 2014-09-19T01:43:14.140 回答