2

UIWebView デリゲート shouldStartLoadWithRequest() メソッドを使用して、iOS で JavaScript から Objective-C に通信する唯一の方法と思われるものを実装しました。

最初は問題なく動作しているように見えましたが、短期間に JavaScript から Objective-C を複数回呼び出すと、2 回目の呼び出しは通常無視されることに気付きました (アプリケーションはピアノの鍵盤で、キーを押すたびに呼び出しがトリガーされます)。複数のタッチを処理する場合、ネイティブコードはすべての指で呼び出されるわけではありません)。

これは、javascript 呼び出しに応答するための私の Objective-C コードです。私が知っているのはかなりダーピーですが、今のところ機能するものが欲しかっただけです。

- (BOOL)webView:(UIWebView *)webView2 shouldStartLoadWithRequest:(NSURLRequest *)request 
        navigationType:(UIWebViewNavigationType)navigationType 
{  
  // Intercept custom location change, URL begins with "js-call:"
  NSString * requestString = [[request URL] absoluteString];
  if ([requestString hasPrefix:@"js-call:"]) 
  {
    // Extract the selector name from the URL
    NSArray * components = [requestString componentsSeparatedByString:@":"];
    NSString * functionCall = [components objectAtIndex:1];
    NSArray * params = [functionCall componentsSeparatedByString:@"%20"];
    NSString * functionName = [params objectAtIndex:0];

    // Parse playnote event
    if ([functionName isEqualToString:@"playNote"])
    {
      NSString * param = [params objectAtIndex:1];
      NoteInstanceID note_id = [m_audioController playNote:[param intValue]];
      NSString * jscall = [NSString stringWithFormat:@"document.PlayNoteCallback(%i);", note_id];
      NSLog(@"playNote: %i", (int)note_id);
      [m_webView stringByEvaluatingJavaScriptFromString:jscall];
    }

    // Parse stopnote event
    if ([functionName isEqualToString:@"stopNote"])
    {
      NSString * param = [params objectAtIndex:1];
      NoteInstanceID note_id = [param intValue];
      NSLog(@"stopNote: %i", (int)note_id); 
      [m_audioController stopNote:note_id];
    }

    // Parse log event
    if ([functionName isEqualToString:@"debugLog"])
    {
      NSString * str = [requestString stringByReplacingOccurrencesOfString:@"%20" withString:@" "];
      NSLog(@"%s", [str cStringUsingEncoding:NSStringEncodingConversionAllowLossy]);
    }

    // Cancel the location change
    return NO;
  }

  // Accept this location change
  return YES;

}

javascript から、1 つの非表示の iframe の src 属性を設定して、objective-c メソッドを呼び出します。これにより、objective-c のデリゲート メソッドがトリガーされ、目的のネイティブ コードが呼び出されます。

$("#app_handle").attr("src", "js-call:playNote " + key.data("pitch"));

app_handle は、問題の iframe の ID です。

要約すると、私のメソッドの基本は機能しますが、短期間に複数回呼び出すことは機能しません。これは、javascript から Objective-C への通信を強いられている恐ろしい方法の単なる成果物ですか? それとも私は何か間違ったことをしていますか?PhoneGap が同じ目標を達成するために似たようなことをしていることは知っています。私はむしろ PhoneGap を使用したくないので、彼らがこの問題を抱えていなければ、彼らがこれを機能させるために何をしているのかを知りたいです.

アップデート:

私はちょうどこれを見つけました: UIWebView の javascript から ObjectiveC に通知を送信し ます。どうやら、別の呼び出しを行うまでにURLリクエストが返されるように、呼び出しをまとめるか、手動で呼び出しを遅らせる必要があるようです。

4

2 に答える 2

4

最初の変更が処理される前に到着した場所の変更は依然として無視されるため、受け入れられた回答は問題を解決しません。最初のコメントを参照してください。

次のアプローチをお勧めします。

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

関数を繰り返し呼び出します。execute各呼び出しは独自の iframe で実行されるため、すぐに呼び出されたときに無視されるべきではありません。

この男のクレジット。

于 2012-11-01T11:45:39.043 に答える
1

JavaScript 側ですべてをキューに入れるよりも、GCD を使用してメイン スレッドから複雑なロジック (オーディオ ハンドラーの呼び出しなど) を移動する方が、おそらくはるかに簡単で高速です。dispatch_async()イベントをキューに入れるために使用できます。それらをシリアル キューに入れると、確実に順番に実行されますが、JavaScript にすばやく戻ることができます。例えば:

  • 初期化中にオブジェクトのキューを作成します。

    self.queue = dispatch_queue_create("プレイヤー", NULL);

  • あなたのコールバックで:

    if ([functionName isEqualToString:@"stopNote"])
    {
      NSString * param = [params objectAtIndex:1];
      NoteInstanceID note_id = [param intValue];
      NSLog(@"stopNote: %i", (int)note_id); 
      dispatch_async(self.queue, ^{[m_audioController stopNote:note_id]});
    }
    
于 2012-05-15T22:29:32.450 に答える