1

I work on a native Objective-C library and I'm exposing some of the API into JavaScript. The purpose is to make it accessible on both Android and iOS

On iOS, I use JSContext and JSExport as described here

Objective-C

 @import JavaScriptCore;


@protocol PersonExports <JSExport>

+ (void)sayHello:(NSString *)name;

@end

@interface Person : NSObject

+ (void)sayHello:(NSString *)name;

@end

Then I add the exposed object to the JSContext of a UIWebView when it finishes loading:

JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

if (nil != context) {
    context[@"Person"] = [Person class];
}

After this, I can access the object from the JavaScript in the loaded page and call the method on it:

JavaScript

<script type="text/javascript">

Person.sayHello(@"Mickey");

</script>

The question is how can I achieve this in a WKWebView?

Jan
  • 7,444
  • 9
  • 50
  • 74
  • I haven't found a good solution to this in the `WKWebView`. In terms of synchronous communication between JavaScript and native code, there are some hacks allowing this in the `UIWebView`. See my question here for some approaches http://stackoverflow.com/questions/26851630/javascript-synchronous-native-communication-to-wkwebview. – paulvs Oct 20 '16 at 23:52

1 Answers1

0
// Create a WKWebView instance
self.webView = [[WKWebView alloc]initWithFrame:self.view.frame configuration:self.webConfig];

// Delegate to handle navigation of web content
self.webView.navigationDelegate = self;

[self.view addSubview:self.webView];

setup accessor for self.webConfig

#pragma mark - accessors
-(WKWebViewConfiguration*) webConfig {
if (!_webConfig) {
    // Create WKWebViewConfiguration instance
    _webConfig = [[WKWebViewConfiguration alloc]init];

    // Setup WKUserContentController instance for injecting user script
    WKUserContentController* userController = [[WKUserContentController alloc]init];

    // Add a script message handler for receiving  "buttonClicked" event notifications posted from the JS document using window.webkit.messageHandlers.buttonClicked.postMessage script message
    [userController addScriptMessageHandler:self name:@"buttonClicked"];

    // Get script that's to be injected into the document
    NSString* js = [self buttonClickEventTriggeredScriptToAddToDocument];

    // Specify when and where and what user script needs to be injected into the web document
    WKUserScript* userScript = [[WKUserScript alloc]initWithSource:js injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:NO];

    // Add the user script to the WKUserContentController instance
    [userController addUserScript:userScript];

    // Configure the WKWebViewConfiguration instance with the WKUserContentController
    _webConfig.userContentController = userController;

}
return _webConfig;

}

implement script message handler method from protocol

#pragma mark -WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message     {
if ([message.name isEqualToString:@"buttonClicked"]) {
    self.buttonClicked ++;
}

// JS objects are automatically mapped to ObjC objects
id messageBody = message.body;
if ([messageBody isKindOfClass:[NSDictionary class]]) {
    NSString* idOfTappedButton = messageBody[@"ButtonId"];
    [self updateColorOfButtonWithId:idOfTappedButton];
}

}

and post the message form js like this

var button = document.getElementById("clickMeButton");
button.addEventListener("click", function() {
    var messgeToPost = {'ButtonId':'clickMeButton'};
    window.webkit.messageHandlers.buttonClicked.postMessage(messgeToPost);
},false);

this will help you because i also faced this issue while setting context nad calling method form JSExport

Anurag Soni
  • 1,077
  • 10
  • 14