web-dev-qa-db-fra.com

Comment appeler Objective-C à partir de Javascript?

J'ai une vue Web et je souhaite appeler une vue en Objective-C à partir de JavaScript. Est-ce que quelqu'un sait comment je peux faire ça?


J'ai ce code dans mon ViewController:

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

 NSString *requestString = [[request URL] absoluteString];
 NSArray *components = [requestString componentsSeparatedByString:@":"];

 if ([components count] > 1 && 
  [(NSString *)[components objectAtIndex:0] isEqualToString:@"myapp"]) {
  if([(NSString *)[components objectAtIndex:1] isEqualToString:@"myfunction"]) 
  {

   NSLog([components objectAtIndex:2]); [[Airship shared] displayStoreFront]; //<- This is the code to open the Store
   NSLog([components objectAtIndex:3]); // param2
   // Call your method in Objective-C method using the above...
  }
  return NO;
 }

 return YES; // Return YES to make sure regular navigation works as expected.
}

Et en Javascript:

function store(event)
{
    document.location = "myapp:" + "myfunction:" + param1 + ":" + param2;
}

Mais rien ne se passe.

41
Obliviux

La solution standard pour UIWebView consiste à définir une UIWebViewDelegate et à implémenter la méthode webView:shouldStartLoadWithRequest:navigationType: . Dans votre code JavaScript, accédez à une fausse URL qui code les informations que vous souhaitez transmettre à votre application, par exemple:

window.location = "fake://myApp/something_happened:param1:param2:param3";

Dans votre méthode de délégué, recherchez ces fausses URL, extrayez les informations dont vous avez besoin, prenez les mesures appropriées et renvoyez NO pour annuler la navigation. Il est probablement préférable de différer tout traitement de longue durée en utilisant un peu de performSelector .

52
Sixten Otto

La méthode window.location consistant à appeler Objective C à partir de JS n'est pas recommandée. Un exemple de problème: si vous effectuez deux appels consécutifs immédiats, l’un est ignoré (car vous ne pouvez pas changer d’emplacement trop rapidement) - essayez vous-même ..

Je recommande l'approche alternative suivante:

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

Vous appelez la fonction execute à plusieurs reprises et, chaque appel étant exécuté dans sa propre iframe, ils ne doivent pas être ignorés lorsqu'ils sont appelés rapidement.

Crédits à ce gars .

32
talkol

Obliviux,

Votre code semble être parfait.

La raison du problème est que vous devez avoir oublié de mapper le délégué.

Non plus 

  1. Connectez le délégué de la webView au propriétaire du fichier dans le fichier .xib

ou

  1. Utilisez webView.delegate = self;

dans votre viewDidLoad.

Merci

4
sm abbas

Comme les gens le disent ici, vous devez utiliser la méthode webView: shouldStartLoadWithRequest: navigationType: à partir de UIWebviewDelegate.

Cette api http://code.google.com/p/jsbridge-to-cocoa/ le fait pour vous. C'est très léger. Vous pouvez transmettre des images, des chaînes et des tableaux de javascript à Objective-C.

3
John

J'avais un problème avec cette approche: je voulais envoyer plusieurs messages sur le périphérique iPhone, mais il semblait qu'ils étaient "superposés" car ils ne pouvaient pas tous les traiter de manière séquentielle.

Exemple: lors de l'exécution de ce code:

window.location = "app://action/foo";
window.location = "app://action/bar";

L'action foo n'a jamais été exécutée.

Ce que je devais faire était le suivant:

waitingForMessage = false;

function MsgProcessed(){
    waitingForMessage = false;
}

function SyncLaunchURL(url){
    if (waitingForMessage){
        setTimeout(function(){SyncLaunchURL(url)},100);
    }else{
        window.location = url
        waitingForMessage = true;   
    }
}

SyncLaunchURL("app://action/foo");
SyncLaunchURL("app://action/bar");

Avec cette approche, l'iphone doit appeler MsgProcessed () après le traitement de l'appel. Cette méthode fonctionne pour moi et aide peut-être quelqu'un qui a le même problème!

2
Guillermo Barbero

Cochez cette case - comprenant les réponses XMLHttpRequest en utilisant cette fonction (ou d’autres fonctions javascript)? , il utilise Objective C pour appeler la fonction ajax js et obtenir la réponse une fois l'opération terminée. Vous savez que l'astuce est que la visualisation Web est déclenchée lorsque vous modifiez l'emplacement en javascript. Vous pouvez donc vérifier l'emplacement pour connaître son javascript. appel ou la vraie demande.

1
Tom

En supposant que vous utilisez une application, vous pouvez voir comment PhoneGap le met en œuvre (ou même l’utilisez). C'est une bibliothèque qui prend en charge la communication entre JS et OBJ-C. Il y a aussi d'autres bibliothèques et solutions.

Si vous parlez d'une application Web (quelque chose que l'utilisateur obtient de Mobile Safari), vous ne pouvez pas accéder à Objective-C à partir de là.

1
Nosredna

Bien que la question soit très ancienne maintenant, elle continue à nous être renvoyée par Google et la réponse est bonne: le protocole informel WebScripting. Il vous permet d'exposer un objet Objective C à Javascript.

http://developer.Apple.com/library/safari/documentation/appleapplications/Conceptual/SafariJSProgTopics/Tasks/ObjCFromJavaScript.html#// Apple_ref/doc/uid/30001215-BBCBFJCD

0
O'Rooney