Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WKWebView Support #27

Open
tomerlevi444 opened this issue Nov 26, 2014 · 4 comments
Open

WKWebView Support #27

tomerlevi444 opened this issue Nov 26, 2014 · 4 comments

Comments

@tomerlevi444
Copy link

Are there any plans on supporting iOS8's WKWebView?

@geoffharcourt
Copy link

+1 here. The performance gains are pretty incredible, and apps for iOS8 forward are going to increasingly use it.

@tcoulter
Copy link
Owner

@tomerlevi444: I'm not using this in production as much as I was, so I haven't been adding new features. If you submit a PR, I'm happy to merge it.

@geoffharcourt
Copy link

@tcoulter, upon further research, WKWebKitView has some code that's designed to accomplish Jockey's functionality, so it's probably best to tell users to just implement using Apple's built-in functionality rather than complicate the UIWebView code that already exists and performs well.

@jordanmaguire
Copy link

This works fine:

In JockeyWK.h

#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>

@interface JockeyWK : NSObject

typedef void (^ JockeyWKHandler)(NSDictionary *payload);
typedef void (^ JockeyWKAsyncHandler)(WKWebView *webView, NSDictionary *payload, void (^complete)());

+ (void)on:(NSString*)type perform:(JockeyWKHandler)handler;
+ (void)on:(NSString*)type performAsync:(JockeyWKAsyncHandler)handler;
+ (void)send:(NSString*)type withPayload:(id)payload toWebView:(WKWebView*)webView;

+ (BOOL)webView:(WKWebView*)webView withUrl:(NSURL*)url;

@property (strong, atomic) NSNumber *messageCount;
@property (strong, nonatomic) NSMutableDictionary *listeners;
@property (strong, nonatomic) NSMutableDictionary *callbacks;

@end

In JockeyWK.m

#import "JockeyWK.h"

@implementation JockeyWK

+ (id)sharedInstance
{
    static dispatch_once_t once;
    static JockeyWK *sharedInstance;
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] init];
        sharedInstance.messageCount = @0;
        sharedInstance.listeners = [[NSMutableDictionary alloc] init];
        sharedInstance.callbacks = [[NSMutableDictionary alloc] init];
    });
    return sharedInstance;
}

+ (void)on:(NSString*)type perform:(JockeyWKHandler)handler {
    void (^ extended)(WKWebView *webView, NSDictionary *payload, void (^ complete)()) = ^(WKWebView *webView, NSDictionary *payload, void(^ complete)()) {
        handler(payload);
        complete();
    };

    [self on:type performAsync:extended];
}

+ (void)on:(NSString *)type performAsync:(JockeyWKAsyncHandler)handler
{
    JockeyWK *instance = [JockeyWK sharedInstance];

    NSDictionary *listeners = [instance listeners];

    NSMutableArray *listenerList = [listeners objectForKey:type];

    if (listenerList == nil) {
        listenerList = [[NSMutableArray alloc] init];

        [instance.listeners setValue:listenerList forKey:type];
    }

    [listenerList addObject:handler];
}

+ (void)send:(NSString*)type withPayload:(id)payload toWebView:(WKWebView*)webView {
    JockeyWK *jockey = [JockeyWK sharedInstance];

    NSNumber *messageId = jockey.messageCount;

    NSError *err;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:payload options:NSJSONWritingPrettyPrinted error:&err];
    NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    NSString *javascript = [NSString stringWithFormat:@"Jockey.trigger(\"%@\", %i, %@);", type, (int)[messageId integerValue], jsonString];

    [webView evaluateJavaScript:javascript completionHandler:nil];

    jockey.messageCount = @([jockey.messageCount integerValue] + 1);
}

+ (BOOL)webView:(WKWebView*)webView withUrl:(NSURL*)url
{
    if ( [[url scheme] isEqualToString:@"jockey"] )
    {
        NSString *eventType = [url host];
        NSString *messageId = [[url path] substringFromIndex:1];
        NSString *query = [url query];
        NSString *jsonString = [query stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

        NSError *error;
        NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData: [jsonString dataUsingEncoding:NSUTF8StringEncoding]
                                                             options: NSJSONReadingMutableContainers
                                                               error: &error];

        if ([eventType isEqualToString:@"event"]) {
            [[self sharedInstance] triggerEventFromWebView:webView withData:JSON];
        } else if ([eventType isEqualToString:@"callback"]) {
            [[self sharedInstance] triggerCallbackForMessage:@([messageId integerValue])];
        }

        return NO;
    }
    return YES;
}

# pragma mark - Private methods

- (void)triggerCallbackForMessage:(NSNumber *)messageId {
    NSString *messageIdString = [messageId stringValue];

    void (^ callback)() = [_callbacks objectForKey:messageIdString];

    if (callback != nil) {
        callback();
    }

    [_callbacks removeObjectForKey:messageIdString];
}

- (void)triggerCallbackOnWebView:(WKWebView*)webView forMessage:(NSString*)messageId
{
    NSString *javascript = [NSString stringWithFormat:@"Jockey.triggerCallback(\"%@\");", messageId];
    [webView evaluateJavaScript:javascript completionHandler:nil];
}

- (void)triggerEventFromWebView:(WKWebView*)webView withData:(NSDictionary*)envelope
{
    NSDictionary *listeners = [[JockeyWK sharedInstance] listeners];

    NSString *messageId = [envelope objectForKey:@"id"];
    NSString *type = [envelope objectForKey:@"type"];

    NSDictionary *payload = [envelope objectForKey:@"payload"];

    NSArray *listenerList = (NSArray*)[listeners objectForKey: type];

    __block NSInteger executedCount = 0;

    void (^complete)() = ^() {
        executedCount += 1;

        if (executedCount >= [listenerList count]) {
            [[JockeyWK sharedInstance] triggerCallbackOnWebView: webView forMessage: messageId];
        }
    };

    for (JockeyWKAsyncHandler handler in listenerList) {
        handler(webView, payload, complete);
    }
}

@end

and just interact with it the same way you'd interact with Jockey usually.

I don't know the exact version of Jockey I'm interacting with tho. From 2013 at least.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants