web-dev-qa-db-fra.com

Comment invoquer la méthode Objective C à partir de Javascript et renvoyer des données à Javascript dans iOS?

Sous iOS, comment puis-je appeler une méthode Objective-C à partir de Javascript dans un UIWebView et lui faire renvoyer des données vers Javascript? Je sais que cela pourrait être fait sur OS X en utilisant la bibliothèque Webkit, mais est-ce possible sur iOS? Comment PhoneGap y parvient-il?

31
Krishnan

Il existe une API pour appeler JavaScript directement depuis Objective-C, mais vous ne pouvez pas appeler Objective-C directement depuis Javascript.

Comment dire à votre code Objective-C de faire quelque chose à partir du Javascript dans votre WebView

Vous devez sérialiser votre action Javascript en une URL spéciale et intercepter cette URL dans la méthode shouldStartLoadWithRequest du délégué UIWebView.

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

Là, vous pouvez désérialiser cette URL spéciale et l'interpréter pour faire ce que vous voulez du côté Objective-C. (Vous devez retourner NO dans la méthode shouldStartLoadWithRequest ci-dessus pour que UIWebView n'utilise pas votre URL bidon pour réellement faire une requête HTTP pour charger une page Web.)

Comment exécuter du code Javascript à partir d'Objective-C

Ensuite, vous pouvez exécuter Javascript à partir d'Objective-C en appelant cette méthode sur votre vue Web.

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

Exemple de code

Je recommande d'utiliser un schéma d'URL bidon afin qu'il soit facile de faire la différence entre vos URL d'action et vos demandes légitimes. Vous pouvez faire cette demande dans le Javascript en suivant ces lignes:

// 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;

Ensuite, dans la méthode shouldStartLoadWithRequest de UIWebView.delegate, Vous pouvez inspecter le schéma d'URL et le fragment pour vérifier s'il s'agit d'une demande normale ou de l'une de vos actions spéciales. (Le fragment d'une URL est ce qui vient après le #.)

- (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;
}

(Lisez cette réponse si vous avez besoin d'aide pour désérialiser votre chaîne json en NSDictionary.)

64
zekel

La modification de l'emplacement de la page peut entraîner plusieurs problèmes :

  1. Tout setInterval et setTimeout s'arrêtent immédiatement lors d'un changement de lieu
  2. Chaque innerHTML ne fonctionnera pas après un changement de lieu annulé!
  3. Vous pouvez avoir d'autres bugs vraiment bizarres, très difficiles à diagnostiquer…

La solution proposée ici , est:

Continuez à utiliser la même technique d'URL (sur js et objective-c), changez simplement l'emplacement avec un iframe:

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

J'espère que cela pourra aider

11
Yaniv Efraim

Depuis Objective-C: vous pouvez transmettre une fonction javascript dans une chaîne à UIWebView. La page Web l'exécutera et retournera un résultat. De cette façon, vous pouvez transmettre des variables et récupérer des données à partir de Javascript.

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

Exemple:

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

Depuis Javascript: passez vos données dans l'URL. Intercepter les demandes d'URL dans UIWebViewDelegate. Obtenez les données et annulez la demande d'URL en renvoyant NON.

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

Intercepter la demande d'URL

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