Puente JavaScript para iOS


Estoy trabajando en una aplicación donde voy a usar HTML5 en UIWebView y el marco de trabajo nativo de iOS juntos. Sé que puedo implementar la comunicación entre JavaScript y Objective-C. ¿Hay alguna librería que simplifique la implementación de esta comunicación? Sé que hay varias bibliotecas para crear aplicaciones nativas de iOS en HTML5 y javascript (por ejemplo appMobi, PhoneGap), pero no estoy seguro de si hay una biblioteca para ayudar a crear aplicaciones nativas de iOS con un uso intensivo de JavaScript. Necesito a:

  1. Ejecutar métodos JS desde Objective-C
  2. Ejecutar métodos Objective-C desde JS
  3. Escuchar eventos JS nativos de Objective-C (por ejemplo evento DOM ready)
Author: andr111, 2012-02-28

9 answers

Hay algunas bibliotecas, pero no usé ninguna de estas en grandes proyectos, por lo que es posible que desee probarlas:

-

Sin embargo, creo que es algo lo suficientemente simple como para que lo pruebes tú mismo. Yo personalmente hice exactamente esto cuando necesitaba hacer eso. Usted podría también cree una biblioteca simple que se adapte a sus necesidades.

1. Ejecutar métodos JS desde Objective-C

Esto es realmente solo una línea de código.

NSString *returnvalue = [webView stringByEvaluatingJavaScriptFromString:@"your javascript code string here"];

Más detalles sobre la documentación oficial de UIWebView .

2. Ejecutar métodos Objective-C desde JS

Esto es desafortunadamente un poco más complejo, porque no hay la misma propiedad windowScriptObject (y clase) que existe en Mac OSX que permite una comunicación completa entre dos.

Sin embargo, puede llamar fácilmente desde URL personalizadas de javascript, como:

window.location = yourscheme://callfunction/parameter1/parameter2?parameter3=value

E interceptarlo desde Objective-C con esto:

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
   NSURL *URL = [request URL]; 
   if ([[URL scheme] isEqualToString:@"yourscheme"]) {
       // parse the rest of the URL object and execute functions
   } 
}

Esto no es tan limpio como debería ser (o usando windowScriptObject) pero funciona.

3. Escuchar eventos JS nativos de Objective-C (por ejemplo evento DOM ready)

De la explicación anterior, ves que si quieres hacer eso, tienes que crear algún código JavaScript, adjuntarlo al evento que deseas monitoree y llame a la llamada window.location correcta para ser interceptada.

De nuevo, no está tan limpio como debería estar, pero funciona.

 147
Author: Folletto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-21 19:12:54

No se recomienda el método sugerido para llamar a objective c desde JS en la respuesta aceptada. Un ejemplo de problemas: si realiza dos llamadas consecutivas inmediatas, una se ignora (no puede cambiar la ubicación demasiado rápido).

Recomiendo el siguiente enfoque alternativo:

function execute(url) 
{
  var iframe = document.createElement("IFRAME");
  iframe.setAttribute("src", url);
  document.documentElement.appendChild(iframe);
  iframe.parentNode.removeChild(iframe);
  iframe = null;
}

Llama a la función execute repetidamente y como cada llamada se ejecuta en su propio iframe, no debe ignorarse cuando se llama rápidamente.

Créditos para este tipo .

 57
Author: talkol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-01 11:51:25

Actualizar: Esto ha cambiado en iOS 8. Mi respuesta se aplica a las versiones anteriores.

Una alternativa, que puede hacer que te rechacen de la app store, es usar WebScriptObject.

Estas API son públicas en OSX, pero no en iOS.

Necesita definir interfaces para las clases internas.

@interface WebScriptObject: NSObject
@end

@interface WebView
- (WebScriptObject *)windowScriptObject;
@end

@interface UIWebDocumentView: UIView
- (WebView *)webView;
@end

Necesita definir su objeto que va a servir como su WebScriptObject

@interface WebScriptBridge: NSObject
- (void)someEvent: (uint64_t)foo :(NSString *)bar;
- (void)testfoo;
+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector;
+ (WebScriptBridge*)getWebScriptBridge;
@end

static WebScriptBridge *gWebScriptBridge = nil;

@implementation WebScriptBridge
- (void)someEvent: (uint64_t)foo :(NSString *)bar
{
    NSLog(bar);
}

-(void)testfoo {
    NSLog(@"testfoo!");
}

+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
{
    return NO;
}

+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector;
{
    return NO;
}

+ (NSString *)webScriptNameForSelector:(SEL)sel
{
    // Naming rules can be found at: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/WebKit/Protocols/WebScripting_Protocol/Reference/Reference.html
    if (sel == @selector(testfoo)) return @"testfoo";
    if (sel == @selector(someEvent::)) return @"someEvent";

    return nil;
}
+ (WebScriptBridge*)getWebScriptBridge {
    if (gWebScriptBridge == nil)
        gWebScriptBridge = [WebScriptBridge new];

    return gWebScriptBridge;
}
@end

Ahora establezca esa instancia en su UIWebView

if ([uiWebView.subviews count] > 0) {
    UIView *scrollView = uiWebView.subviews[0];

    for (UIView *childView in scrollView.subviews) {
        if ([childView isKindOfClass:[UIWebDocumentView class]]) {
            UIWebDocumentView *documentView = (UIWebDocumentView *)childView;
            WebScriptObject *wso = documentView.webView.windowScriptObject;

            [wso setValue:[WebScriptBridge getWebScriptBridge] forKey:@"yourBridge"];
        }
    }
}

Ahora dentro de tu javascript puedes llamar:

yourBridge.someEvent(100, "hello");
yourBridge.testfoo();
 13
Author: Joseph Lennox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-08 04:12:24

En iOS8 puedes mirar WKWebView en lugar de UIWebView . Esto tiene la siguiente clase: WKScriptMessageHandler: Proporciona un método para recibir mensajes de JavaScript que se ejecutan en una página web.

 5
Author: Alex Stone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-18 19:08:31
 3
Author: CocoaChris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-12 16:05:24

Tu mejor apuesta es la oferta de Appcelerators Titanium. Ya han construido un puente javascript Obj-C usando el motor V8 motor JavaScriptCore utilizado por webkit. También es de código abierto, por lo que podrás descargarlo y jugar con el Obj-C como quieras.

 0
Author: hova,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-22 21:01:11

Eche un vistazo al proyecto KirinJS: Kirin JS que permite usar Javascript para la lógica de la aplicación y la interfaz de usuario nativa adecuada a la plataforma en la que se ejecuta.

 0
Author: rochal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-19 10:34:45

He creado una biblioteca como WebViewJavascriptBridge, pero es más similar a jQuery, tiene más fácil de configurar y es más fácil de usar. No depende de jQuery (aunque para su crédito, si hubiera sabido que WebViewJavascriptBridge existía antes de escribir esto, puede que me haya detenido un poco antes de sumergirme). Déjame saber lo que piensas! jockeyjs

 0
Author: Tim Coulter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-19 10:35:18

Si está utilizando WKWebView en iOS 8, eche un vistazo a XWebView que puede exponer automáticamente la interfaz nativa a javascript.

 0
Author: soflare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-28 15:09:21