41 votes

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.

52voto

Sixten Otto Points 10267

Le standard de la solution de contournement pour UIWebView est de mettre un UIWebViewDelegate, et de mettre en œuvre la méthode de webView:shouldStartLoadWithRequest:navigationType:. Dans votre code JavaScript, accédez à certains faux URL encode les informations que vous souhaitez transmettre à votre application, comme, par exemple:

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

Dans votre délégué de la méthode, à l'affût de ces faux Url, extraire les informations dont vous avez besoin, prendre des mesures appropriées, et de revenir NO pour annuler la navigation. Il est probablement mieux si vous vous en remettez une longue traitement à l'aide d' une sorte de performSelector.

32voto

talkol Points 4279

De la fenêtre.la méthode de localisation de l'appelant objective c JS n'est pas recommandé. Un exemple de problèmes: si vous faites deux appels consécutifs est ignoré (puisque vous ne pouvez pas modifier l'emplacement trop vite) - essayez-le vous-même..

Je recommande ce qui suit approche alternative:

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

Vous appelez l' execute fonction à plusieurs reprises et depuis chaque appel s'exécute dans son propre iframe, ils ne devraient pas être ignorées lorsqu'il est appelé rapidement.

Les crédits de ce mec.

4voto

sm abbas Points 655

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

3voto

John Points 31

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.

2voto

J'ai eu un problème avec cette approche: j'ai voulu envoyer plusieurs messages dans le dispositif de l'iphone, mais il me semblait qu'ils étaient "overlaped" comme ils ne pouvaient pas traiter tous 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 j'avais à faire était la suivante:

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 a appeler MsgProcessed() après le traitement de l'appel. De cette façon fonctionne pour moi, et peut-être aider quelqu'un avec le même problème!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X