web-dev-qa-db-ja.com

JavascriptからObjective Cメソッドを呼び出し、iOSでJavascriptにデータを送り返す方法は?

IOSでは、UIWebView内のJavascriptからObjective-Cメソッドを呼び出して、Javascriptにデータを返送する方法を教えてください。これはWebkitライブラリを使用してOS Xで実行できることを知っていますが、これはiOSでも可能ですか? PhoneGapはこれをどのように達成しますか?

31
Krishnan

Objective-CからJavaScriptを直接呼び出すAPIがありますが、JavascriptからObjective-Cを直接呼び出すことはできません。

Objective-CコードにWebViewのJavascriptから何かをするように指示する方法

Javascriptアクションを特別なURLにシリアル化し、UIWebViewのデリゲートのshouldStartLoadWithRequestメソッドでそのURLをインターセプトする必要があります。

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

そこで、その特別なURLをデシリアライズし、Objective-C側で必要なことを行うためにそれを解釈できます。 (上記のNOメソッドでshouldStartLoadWithRequestメソッドを返す必要があります。これにより、UIWebViewは偽のURLを使用してWebページをロードするためのHTTPリクエストを実際に作成しません。)

Objective-CからJavaScriptコードを実行する方法

次に、Webビューでこのメソッドを呼び出すことにより、Objective-CからJavascriptを実行できます。

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

サンプルコード

偽のURLスキームを使用することをお勧めします。そうすれば、アクションURLと正当なリクエストの違いを簡単に判断できます。次の行に沿ってJavascriptでこのリクエストを行うことができます。

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

次に、UIWebView.delegateshouldStartLoadWithRequestメソッドでは、URLスキームとフラグメントを調べて、それが通常のリクエストであるか、特別なアクションの1つであるかを確認できます。 (URLのフラグメントは、#。)

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

(json文字列をNSDictionaryにデシリアライズするのに助けが必要な場合は この回答 を読んでください。)

64
zekel

ページの場所を変更すると、複数の 問題 が発生する可能性があります。

  1. すべてのsetIntervalおよびsetTimeoutは、場所が変更されるとすぐに停止します
  2. 場所の変更をキャンセルすると、すべてのinnerHTMLが機能しなくなります。
  3. 診断するのが本当に難しい他の本当に奇妙なバグを得るかもしれません…

here で提供されるソリューションは次のとおりです。

同じURLテクニック(jsとObjective-C)を使用して、iframeで場所を変更するだけです:

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

役立つことを願っています

11
Yaniv Efraim

Objective-Cから:文字列のjavascript関数をUIWebViewに渡すことができます。 Webページはそれを実行し、結果を返します。これにより、変数を渡し、Javascriptからデータを取得できます。

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

例:

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

JavaScriptから:URL内にデータを渡します。 UIWebViewDelegateでURLリクエストをインターセプトします。データを取得し、NOを返すことでURL要求を中止します。

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

RLリクエストのインターセプト

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