2010-02-18 4 views
13

Sous Windows, lorsque le contrôle ActiveX "Shell.Explorer" est incorporé dans une application, il est possible d'enregistrer un gestionnaire "externe" qui implémente IDispatch, de sorte que les scripts de la page Web puissent appeler l'application d'hébergement .Embedded Webkit - callbacks de script comment?

<button onclick="window.external.Test('called from script code')">test</button> 

Maintenant, ive déplacé au développement Mac et pensé que je pourrais obtenir quelque chose de semblable travail de WebKit intégré dans mon application Cocoa. Mais, il ne semble vraiment pas y avoir de possibilité d'autoriser les scripts à rappeler à l'application d'hébergement.

Un conseil était d'accrocher window.alert et obtenir des scripts pour passer une chaîne de message formatée comme chaîne d'alerte. Je me demande également si WebKit peut peut-être être dirigé vers un plugin NPAPI hébergé par une application en utilisant NPPVpluginScriptableNPObject.

Ai-je raté quelque chose? Est-ce vraiment difficile d'héberger un WebView et d'autoriser les scripts à interagir avec l'hôte?

Répondre

30

Vous devez implémenter les différentes méthodes de protocole WebScripting. Voici un exemple de base:

@interface WebController : NSObject 
{ 
    IBOutlet WebView* webView; 
} 

@end 

@implementation WebController 

//this returns a nice name for the method in the JavaScript environment 
+(NSString*)webScriptNameForSelector:(SEL)sel 
{ 
    if(sel == @selector(logJavaScriptString:)) 
     return @"log"; 
    return nil; 
} 

//this allows JavaScript to call the -logJavaScriptString: method 
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)sel 
{ 
    if(sel == @selector(logJavaScriptString:)) 
     return NO; 
    return YES; 
} 

//called when the nib objects are available, so do initial setup 
- (void)awakeFromNib 
{ 
    //set this class as the web view's frame load delegate 
    //we will then be notified when the scripting environment 
    //becomes available in the page 
    [webView setFrameLoadDelegate:self]; 

    //load a file called 'page.html' from the app bundle into the WebView 
    NSString* pagePath = [[NSBundle mainBundle] pathForResource:@"page" ofType:@"html"]; 
    NSURL* pageURL = [NSURL fileURLWithPath:pagePath]; 
    [[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:pageURL]]; 
} 


//this is a simple log command 
- (void)logJavaScriptString:(NSString*) logText 
{ 
    NSLog(@"JavaScript: %@",logText); 
} 

//this is called as soon as the script environment is ready in the webview 
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowScriptObject forFrame:(WebFrame *)frame 
{ 
    //add the controller to the script environment 
    //the "Cocoa" object will now be available to JavaScript 
    [windowScriptObject setValue:self forKey:@"Cocoa"]; 
} 

@end 

Après application de ce code dans votre contrôleur, vous pouvez maintenant appeler Cocoa.log('foo'); de l'environnement JavaScript et la méthode logJavaScriptString: sera appelée.

+0

Est-ce que [webView mainFrame] loadData: déclenche l'objet didClearWindowObject:? J'ai le [webView setFrameLoadDelegate: self]; setup mais ceci ne configure pas windowScriptObject quand j'essaye un point d'arrêt. – Luke

+1

Je l'ai fait fonctionner de cette façon, mais comment appelez-vous un gestionnaire (fonction JS) de Cocoa, comme un rappel que quelque chose est arrivé dans Cocoa. Bien sûr, vous pouvez obtenir 'windowScriptObject' à partir de' WebView', mais est-il possible pour 'Cocoa' de savoir à quelle instance' WebScriptObject' il appartient? –

+0

Excellent. Merci! ;-) –

1

Ceci est très facile à faire avec le WebScriptObject API en combinaison avec le framework JavaScriptCore.