2011-04-15 22 views
23

Necesito saber qué se debe hacer para usar JavaScript en un HTML sentado en UIWebView para notificar a Objective-C que algo ha sucedido?enviar una notificación desde javascript en UIWebView a ObjectiveC

Para ser más exactos, estoy reproduciendo algunas animaciones de JavaScript en HTML y debo alertar al código Objective-C de que la animación ha finalizado.

+1

simplemente me encontré con una pregunta más antigua preguntando lo mismo: http://stackoverflow.com/questions/1662473/how-to-call-objective-c-from-javascript. Mi respuesta a continuación da la misma solución ... –

+0

Este es un truco ingenioso, pero se puede encontrar una técnica mejor [aquí] [1]. [1]: http://stackoverflow.com/questions/1662473/how-to-call-objective-c-from-javascript –

Respuesta

46

Parece que no hay un método oficial para hacerlo. Sin embargo, thestandardworkaround implica leer y analizar las solicitudes de URL entrantes, básicamente con su propio protocolo de mensajería serializada. El manejo de mensajes debe hacerse en el método webView:shouldStartLoadWithRequest:navigationType de su controlador de vista.

Nota: hay varias bibliotecas libres (PhoneGap, QuickConnect, JS-to-Cocoa Bridge) que envuelven esta funcionalidad (además de hacer mucho más). Para reinventar la rueda (o saber por qué es redonda, por así decirlo), sigue leyendo.

Desde JavaScript, invocará la devolución de llamada al tratar de navegar a una nueva URL:

// In JavaScript 
window.location = 'myapp:myaction:param1:param2'; // etc... 

En Objective-C, aplicar el protocolo UIWebViewDelegate en su archivo .h:

// In your header file 
@interface MyAppViewController : UIViewController <UIWebViewDelegate> { 
    ... 
} 
@end 

A continuación, implemente el método en su archivo .m:

// In your implementation file 
-(BOOL)webView:(UIWebView *)webView2 
     shouldStartLoadWithRequest:(NSURLRequest *)request 
     navigationType:(UIWebViewNavigationType)navigationType 
{ 
    // Break apart request URL 
    NSString *requestString = [[request URL] absoluteString]; 
    NSArray *components = [requestString componentsSeparatedByString:@":"]; 

    // Check for your protocol 
    if ([components count] > 1 && 
     [(NSString *)[components objectAtIndex:0] isEqualToString:@"myapp"]) 
    { 
    // Look for specific actions 
    if ([(NSString *)[components objectAtIndex:1] isEqualToString:@"myaction"]) 
    { 
     // Your parameters can be found at 
     // [components objectAtIndex:n] 
     // where 'n' is the ordinal position of the colon-delimited parameter 
    } 

    // Return 'NO' to prevent navigation 
    return NO; 
    } 

    // Return 'YES', navigate to requested URL as normal 
    return YES; 
} 

Dos notas importantes:

  1. Contexto: navegar a myapp:whatever será (por supuesto) fallar en cualquier otro contexto. Tenga esto en cuenta si está cargando páginas multiplataforma.

  2. sincronización: si un segundo window.location = llamada se realiza antes de las primeras vueltas, se pondrá 'perdido'. Por lo tanto, agrupe sus llamadas, demore la ejecución manualmente o implemente una cola que combine lo anterior con JS queries into Objective-C objects.

+0

gracias !! ¡Lo intentaré! – mkto

+0

@dunforget, hágamelo saber cómo va. Tengo esta parte trabajando en un proyecto de prueba, así que avíseme si necesita ayuda. Estoy probando PhoneGap en este momento y estoy muy impresionado (¡es fácil de configurar!) –

3

realidad para medir el tiempo en IOS (quizás no para OSX?), Si una segunda window.location llamada se realiza antes de las anteriores ejecuta window.location de llamada, entonces el primer window.location llamada se pierde. Creo que la llamada window.location se ejecuta de manera asincrónica con JavaScript después de que se invoca, y si se realiza otra llamada antes de que se ejecute, cancela la primera.

Por ejemplo, en la captura de eventos de toque, he visto ontouchstart no son enviadas a través de window.location, si un evento se produce a ontouchmove después rápidamente (por ejemplo, en un golpe de dedo rápido). Por lo tanto, su Objective-C no obtiene el evento ontouchstart. Esto es más un problema en el iPad original que en el iPad2, supongo que debido a la velocidad de procesamiento.

1

La respuesta de zourtney es correcta, pero se olvidó de mencionar una cosa ..necesario para registrar delegado a vistaweb por

- (void)viewDidLoad { 
    [super viewDidLoad]; --- instantiate _webview next .. then 

    _webview.delegate = self; //important .. needed to register webview to delegate 
} 

esperanza esto ayuda .....

0

Swift Versión

class ViewController: UIViewController,UIWebViewDelegate{ 

    @IBOutlet weak var webviewInstance: UIWebView! 
    override func viewDidLoad() { 
     webviewInstance.delegate = self 
     super.viewDidLoad() 

    } 


    func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { 
     let requestString: String = (request.URL?.absoluteString)! 
     var components: [AnyObject] = requestString.componentsSeparatedByString(":") 
     // Check for your protocol 
     if components.count > 1 && (String(components[0]) == "myapp") { 
      // Look for specific actions 
      if (String(components[1]) == "myaction") { 
       // Your parameters can be found at 
       // [components objectAtIndex:n] 
      } 
      return false 
     } 
     return true 
    } 
} 
Cuestiones relacionadas