¿Cómo invocar el método Objective C desde Javascript y enviar datos de vuelta a Javascript en iOS?

En iOS, ¿cómo puedo llamar a un método Objective-C desde Javascript en una UIWebView y hacer que envíe datos de vuelta al Javascript? Sé que esto podría hacerse en OS X usando la biblioteca Webkit, pero ¿es posible en iOS? ¿Cómo logra PhoneGap esto?

Hay una API para llamar a JavaScript directamente desde Objective-C, pero no puede llamar a Objective-C directamente desde Javascript.

Cómo decirle a su código Objective-C que haga algo desde el Javascript en su WebView

Debe serializar su acción de Javascript en una URL especial e interceptar esa URL en el método shouldStartLoadWithRequest del delegado de shouldStartLoadWithRequest .

 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType; 

Allí puede deserializar esa URL especial e interpretarla para hacer lo que quiera en el lado de Objective-C. (Debe devolver NO en el método anterior, debe shouldStartLoadWithRequest método de shouldStartLoadWithRequest , por lo que UIWebView no utiliza su URL falsa para realizar una request HTTP para cargar una página web).

Cómo ejecutar código JavaScript desde Objective-C

Entonces puedes ejecutar Javascript desde Objective-C llamando a este método en tu webview.

 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script; 

Ejemplo de código

Recomiendo utilizar un esquema de URL falso para que sea fácil distinguir entre sus URL de acción y las requestes legítimas. Puede hacer esta request en el Javascript en estas líneas:

 // JavaScript to send an action to your Objective-C code var myAppName = 'myfakeappname'; var myActionType = 'myJavascriptActionType'; var myActionParameters = {}; // put extra info into a dict if you need it // (separating the actionType from parameters makes it easier to parse in ObjC.) var jsonString = (JSON.stringify(myActionParameters)); var escapedJsonParameters = escape(jsonString); var url = myAppName + '://' + myActionType + "#" + escapedJsonParameters; document.location.href = url; 

Luego, en el método shouldStartLoadWithRequest 's shouldStartLoadWithRequest , puede inspeccionar el esquema de URL y el fragment para verificar si es una request normal o una de sus acciones especiales. (El fragment de una URL es lo que viene después del # .)

 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // these need to match the values defined in your JavaScript NSString *myAppScheme = @"myfakeappname"; NSString *myActionType = @"myJavascriptActionType"; // ignore legit webview requests so they load normally if (![request.URL.scheme isEqualToString:myAppScheme]) { return YES; } // get the action from the path NSString *actionType = request.URL.host; // deserialize the request JSON NSString *jsonDictString = [request.URL.fragment stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding]; // look at the actionType and do whatever you want here if ([actionType isEqualToString:myActionType]) { // do something in response to your javascript action // if you used an action parameters dict, deserialize and inspect it here } // make sure to return NO so that your webview doesn't try to load your made-up URL return NO; } 

(Lea esta respuesta si necesita ayuda para deserializar su cadena json en un NSDictionary).

Cambiar la location de la página puede causar varios problemas :

  1. Todos setInterval y setTimeout se detienen inmediatamente en el cambio de location.
  2. ¡Cada innerHTML no funcionará después de un cambio de location cancelado!
  3. Puedes get otros errores realmente extraños, muy difíciles de diagnosticar …

La solución, tal como se ofrece aquí , es:

Siga usando la misma técnica de URL (en js y objective-c), simplemente cambie la location con un iframe:

  var iframe = document.createElement("IFRAME"); iframe.setAttribute("src", "js-frame:myObjectiveCFunction"; document.documentElement.appendChild(iframe); iframe.parentNode.removeChild(iframe); iframe = null; 

Espero que ayude

Desde Objective-C: puede pasar una function javascript en una cadena a UIWebView. La página web lo ejecutará y devolverá un resultado. De esta manera puede pasar variables y recuperar datos de Javascript.

 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script 

Ejemplo:

 NSString *script = @"document.getElementById('myTextField').value"; NSString *output = [myWebView stringByEvaluatingJavaScriptFromString:script]; 

Desde Javascript: pasa tus datos dentro de la URL. Interceptar requestes de URL en UIWebViewDelegate. Obtenga los datos y cancele la request de URL devolviendo NO.

 <script>window.location = "url://key1/value1"; </script> 

Intercepta la request URL

 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType