2010-02-18 5 views
13

En Windows, cuando el control ActiveX "Shell.Explorer" está incrustado en una aplicación, es posible registrar un manejador "externo" - en el objeto que implementa IDispatch, de modo que los scripts en la página web puedan llamar a la aplicación de alojamiento .Webkit incorporado - devoluciones de guiones ¿cómo?

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

Ahora, he trasladaron al desarrollo Mac y pensé que podría conseguir algo de trabajo similar de WebKit incrustado en la aplicación Cocoa. Pero, realmente no parece haber ninguna posibilidad de permitir que los scripts vuelvan a llamar a la aplicación de alojamiento.

Un consejo fue conectar window.alert y obtener secuencias de comandos para pasar una cadena de mensaje formateado como la cadena de alerta. También me pregunto si WebKit quizás pueda dirigirse a un plugin NPAPI alojado en una aplicación usando NPPVpluginScriptableNPObject.

¿Echo de menos algo? ¿De verdad es tan difícil alojar un WebView y permitir que los scripts interactúen con el host?

Respuesta

30

Debe implementar los diversos métodos de protocolo de WebScripting. Aquí está un ejemplo básico:

@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 

Después de implementar este código en su controlador, ahora se puede llamar Cocoa.log('foo'); desde el entorno de JavaScript y el método logJavaScriptString: se llamará.

+0

Hace [webView mainFrame] loadData: desencadena el didClearWindowObject:? Tengo el [webView setFrameLoadDelegate: self]; setup pero esto no está configurando el windowScriptObject cuando intento un punto de interrupción. – Luke

+1

Lo tengo funcionando de esta manera, pero ¿cómo se llama a un controlador (función JS) de Cocoa, como una devolución de llamada que algo sucedió en Cocoa. Por supuesto, puede obtener el 'windowScriptObject' de' WebView' pero ¿hay alguna manera para que 'Cocoa' sepa a qué instancia de' WebScriptObject' pertenece? –

+0

Excelente. ¡Gracias! ;-) –

1

Esto es muy fácil de hacer con el WebScriptObject API en combinación con el marco JavaScriptCore.