2010-02-18 12 views
13

Wenn das ActiveX-Steuerelement "Shell.Explorer" in eine Anwendung eingebettet ist, ist es möglich, einen "externen" Handler für ein Objekt zu registrieren, das IDispatch implementiert, sodass Skripts auf der Webseite die Hostanwendung aufrufen können . JetztEmbedded Webkit - Skript-Callbacks wie?

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

, bewegte ive zu Mac Entwicklung und dachte, dass ich etwas ähnliche Arbeiten von WebKit in meiner Cocoa-Anwendung eingebettet bekommen konnte. Aber es scheint wirklich keine Möglichkeit zu geben, Skripten den Rückruf an die Hosting-Anwendung zu erlauben.

Ein Ratschlag war, window.alert zu haken und Skripte zu erhalten, um eine formatierte Nachrichtenfolge als Alert-String zu übergeben. Ich frage mich auch, ob WebKit vielleicht mit NPPVpluginScriptableNPObject auf eine Anwendung gehosteten NPAPI-Plugin verwiesen werden kann.

Fehle ich etwas? Ist es wirklich so schwierig, ein WebView zu hosten und Skripts mit dem Host interagieren zu lassen?

Antwort

30

Sie müssen die verschiedenen WebScripting-Protokollmethoden implementieren. Hier ist ein einfaches Beispiel:

@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 

Nach diesen Code in Ihrem Controller Implementierung können Sie jetzt Cocoa.log('foo'); aus der JavaScript-Umgebung aufrufen und die logJavaScriptString: Methode aufgerufen wird.

+0

Wird [webView mainFrame] loadData: das didClearWindowObject ausgelöst:? Ich habe das [webView setFrameLoadDelegate: self]; Setup, aber dies ist nicht das Einrichten des windowScriptObject, wenn ich einen Haltepunkt versuche. – Luke

+1

Ich habe es so herumlaufen, aber wie rufen Sie einen Handler (JS-Funktion) von Cocoa, als Rückruf, dass etwas in Cocoa passiert ist. Natürlich können Sie das 'windowScriptObject' aus dem' WebView' holen, aber gibt es eine Möglichkeit für 'Cocoa' zu wissen, zu welcher' WebScriptObject'-Instanz es gehört? –

+0

Großer. Vielen Dank! ;-) –

1

Dies ist sehr einfach mit der WebScriptObject API in Verbindung mit dem JavaScriptCore-Framework zu tun.