Как позвонить в Objective-C из Javascript? - PullRequest
41 голосов
/ 02 ноября 2009

У меня есть WebView, и я хочу вызвать представление в Objective-C из JavaScript. Кто-нибудь знает, как я могу это сделать?


У меня есть этот код в моем 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.
}

И в Javascript:

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

Но ничего не происходит.

Ответы [ 8 ]

52 голосов
/ 02 ноября 2009

Стандартный обходной путь для UIWebView - установить UIWebViewDelegate и реализовать метод webView:shouldStartLoadWithRequest:navigationType:.В своем коде JavaScript перейдите к некоторому фальшивому URL-адресу, который кодирует информацию, которую вы хотите передать в свое приложение, например:

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

В вашем методе делегата найдите эти фальшивые URL-адреса, извлеките информацию, которую вынужно, выполнить любое действие и вернуть NO, чтобы отменить навигацию.Вероятно, будет лучше, если вы отложите длительную обработку, используя некоторый вариант performSelector.

32 голосов
/ 01 ноября 2012

Метод window.location для вызова цели c из JS не рекомендуется. Один из примеров проблем: если вы делаете два немедленных последовательных вызова, один из них игнорируется (поскольку вы не можете изменить местоположение слишком быстро) - попробуйте сами ..

Я рекомендую следующий альтернативный подход:

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

Вы вызываете функцию execute несколько раз, и, поскольку каждый вызов выполняется в своем собственном фрейме, они не должны игнорироваться при быстром вызове.

Кредиты этому парню .

4 голосов
/ 22 октября 2011

Obliviux,

Ваш код кажется идеальным.

Причина проблемы в том, что вы, должно быть, пропустили отображение делегата.

Либо

  1. Соединить делегата webView с владельцем файла в файле .xib

или

  1. Использование webView.delegate = self;

в вашем viewDidLoad.

Спасибо

3 голосов
/ 20 сентября 2010

Как говорили здесь люди, вы должны использовать метод webView: shouldStartLoadWithRequest: navigationType: from UIWebviewDelegate.

Этот API http://code.google.com/p/jsbridge-to-cocoa/ делает это для вас. Это очень легкий. Вы можете передавать изображения, строки и массивы из JavaScript в Objective-C.

2 голосов
/ 06 сентября 2012

У меня была проблема с этим подходом: я хотел отправить несколько сообщений на устройство iphone, но казалось, что они были «перекрыты», поскольку не могли обрабатывать их все последовательно.

Пример: при выполнении этого кода:

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

Действие foo никогда не выполнялось.

То, что я должен был сделать, было следующим:

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");

При таком подходе iphone должен вызывать MsgProcessed () после обработки вызова. Этот способ работает для меня и, возможно, помогает кому-то с той же проблемой!

1 голос
/ 08 мая 2012

Отметьте это - понимание ответов XMLHttpRequest с использованием этой (или других javascript) функций? , она использует цель C для вызова функции ajax js и получения ответа после ее завершения, вы знаете, хитрость в том, что Веб-просмотр будет запускаться при изменении местоположения в javascript, поэтому вы можете проверить местоположение, чтобы узнать, является ли он вашим вызовом JavaScript или реальным запросом.

1 голос
/ 02 ноября 2009

Предполагая, что вы делаете приложение, вы можете посмотреть, как PhoneGap реализует это (или даже использует его). Это библиотека, которая поддерживает двустороннюю связь между JS и OBJ-C. Есть и другие библиотеки и решения.

Если вы говорите о веб-приложении (то, что пользователь получает от Mobile Safari), вы не сможете попасть в Objective-C оттуда.

0 голосов
/ 19 декабря 2017

Хотя это очень старый вопрос, он продолжает возвращаться Google, и теперь есть хороший ответ: неофициальный протокол WebScripting. Это позволяет вам представить объектный объект C в Javascript.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...