Как вызвать метод Objective C из Javascript и отправить данные в Javascript в iOS?

В iOS, как я могу вызвать метод Objective-C из Javascript в UIWebView и отправить его обратно в Javascript? Я знаю, что это можно сделать в OS X, используя библиотеку Webkit, но возможно ли это на iOS? Как PhoneGap достигает этого?

Ответ 1

Существует API для вызова JavaScript непосредственно из Objective-C, но вы не можете вызвать Objective-C непосредственно из Javascript.

Как сообщить вашему коду Objective-C что-то сделать из Javascript в вашем WebView

Вы должны сериализовать действие Javascript в специальный URL-адрес и перехватить этот URL-адрес в делететом shouldStartLoadWithRequest в интерфейсе UIWebView.

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

Здесь вы можете десериализовать этот специальный URL-адрес и интерпретировать его, чтобы сделать то, что вы хотите на стороне Objective-C. (Вы должны вернуть NO в приведенном выше методе shouldStartLoadWithRequest, чтобы UIWebView не использовал ваш фиктивный URL, чтобы фактически сделать HTTP-запрос для загрузки веб-страницы.)

Как запустить Javascript-код из Objective-C

Затем вы можете запустить Javascript из Objective-C, вызвав этот метод в своем веб-просмотре.

- (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.delegate shouldStartLoadWithRequest вы можете проверить схему и фрагмент URL, чтобы проверить, является ли это обычным запросом или одним из ваших специальных действий. (Фрагмент 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.)

Ответ 2

Изменение местоположения страницы может вызвать несколько вопросов:

  • Все setInterval и setTimeout немедленно останавливаются при изменении местоположения
  • Каждый innerHTML не работает после отмены изменения местоположения!
  • Вы можете получить другие действительно странные ошибки, очень трудно диагностировать...

Решение, предложенное здесь, следующее:

Продолжайте использовать тот же метод 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;

Надеюсь, что поможет

Ответ 3

Из Objective-C: вы можете передать функцию javascript в строке в UIWebView. Веб-страница выполнит его и вернет результат. Таким образом, вы можете передавать переменные и получать данные из Javascript.

  - (NSString *) stringByEvaluatingJavaScriptFromString: (NSString *) script
Код>

Пример:

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

Из Javascript: передайте свои данные внутри URL-адреса. Перехват запросов URL в UIWebViewDelegate. Получите данные и прервите запрос URL, вернув NO.

  <script> window.location = "url://key1/value1"; </сценарий >
Код>

Перехват запроса URL

  - (BOOL) webView: (UIWebView *) webView shouldStartLoadWithRequest: (NSURLRequest *) request navigationType: (UIWebViewNavigationType) navigationType
Код>