ПРОГРАММИРОВАНИЕ ПОД IPHONE, IPAD OBJECTIVE-C часть 2

Связь Objective-C и JavaScript

Недавно я столкнулся с напервый взгляд сложной задачей. Мне потребовалось вызывать с Objective-C функции JavaScript. Как оказалось позже, это довольно просто и я уже это делал раньше, но не знал, что я делаю. Мне было достаточно того, что написаный мной код работает. Но по мере решения задач — поступали новые. И нужно было уже с JavaScript вызывать функции Objective-C. О том как настроить свой мост меджду этими двумя языками я покажу в этом примере. предпологается, что вы уже ознакомились с Создание собственного браузера и Методы делегата WebView.

 

Для начала создадим проект, в котором будем ставить все эксперименты. Нам подойдет самый простой шаблон Single View Application, я назвал свой проект JSExample. Теперь обеспечим минимальную реализацию UIWebView, которая нам необходима. Таким образом, файл ViewController.h должен выглядеть так:

 

<code data-result="[object Object]">#import &lt;UIKit/UIKit.h&gt;

@interface ViewController : UIViewController &lt;UIWebViewDelegate&gt;

@property (strong, nonatomic) IBOutlet UIWebView *myBrowser;

@end</code>

 

И соответственно, реализация класса ViewController.m:

 

<code data-result="[object Object]">#import "ViewController.h"

@implementation ViewController

@synthesize myBrowser;

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.myBrowser = nil;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSString *pathToFile = [[NSBundle mainBundle] pathForResource:@"js" ofType:@"html"];
    NSURL *url = [NSURL fileURLWithPath:pathToFile];

    [myBrowser loadRequest:[NSURLRequest requestWithURL:url]];
}

@end</code>

 

Теперь внесем изменения в ViewController.xib подобно тому как мы делали в первом примере работы с UIWebView (то есть, просто добавьте Web View на основной View, свяжите его с объектом myBrowser и не забудьте про делегат). Все что нам осталось, это добавить в проект сам файл js.html, который можно скачать по этой ссылке.

 

Если все сделано правильно при первом запуске должна получится примерно следующая картинка:

 

 

Как вы уже заметили, мы нигде не использовали UIAlertView, но он у нас отобразился на экране. Произошлно это потому, что так iOSотображает сообщения вызванные методами JavaScript. При загрузке страници вызывается функция  JSAlert(msg). Давайте попробуем эту функцию вызвать самостоятельно. Для этого в интерфейсе класса объявим два метода — showJSAlert и getHtmlBody (во втором методе мы будем вызывать другую функцию JavaScript). Теперь напишем реализацию этих методов:

 

<code data-result="[object Object]">- (IBAction)showJSAlert {
    [myBrowser stringByEvaluatingJavaScriptFromString:@"JSAlert('JS alert example')"];
}

- (IBAction)getHtmlBody {
    NSString *html = [myBrowser stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"];
    NSLog(@"%@", html);
}</code>

 

Осталось добавить две кнопки в наш интерфейс и связать нажатие на них с вызовами этих методов. И так, что же происходит в этих методах? В первом (showJSAlert) с помощью метода stringByEvaluatingJavaScriptFromString класса UIWebView мы вызываем функцию JavaScript, передавая в нее параметры. Имя функции и параметр записывается в виде строки. В getHtmlBody мы вызываем стандартную функцию JavaScript, которая возвращает нам тело html-страници в виде строки. Полученную строку выводим в консоль. Лучше способа прочитать html код с WebView трудно найти.

 

Вызывать функции JavaScript мы научились, но как это сделать обратно? Для этой цели в js.html я поместил кнопку. При нажатии на нее вызывается функция ObjCAlert(), а в ней осуществляется переход на другую страничку. Этот переход мы можем отлавливать в методе shouldStartLoadWithRequest и как я уже писал в Методы делегата WebView разрешить или запретить нашему WebViewпереходить по данному запросу. А адрес запроса — будет тем необходимым маркером который сообщит какой метод Objective-C нужно вызвать. Посмотрим как это выглядит на практике:

 

<code data-result="[object Object]">- (BOOL)webView:(UIWebView *)webView 
shouldStartLoadWithRequest:(NSURLRequest *)request 
 navigationType:(UIWebViewNavigationType)navigationType
{
    NSString *requestString = [[request URL] absoluteString];

    NSArray *components = [requestString componentsSeparatedByString:@":"];
    if (components.count) {
        if ([[components objectAtIndex:0] isEqualToString:@"jsexample"]) {
            if ([[components objectAtIndex:1] isEqualToString:@"alert"]) {
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Objective-C Alert" 
                                                                message:[components objectAtIndex:2] 
                                                               delegate:self 
                                                      cancelButtonTitle:@"OK" 
                                                      otherButtonTitles:nil];
                [alert show];
            }

            return NO;
        }
    }    

    return YES;
}</code>

 

Перед разрешением переходить по запросу мы разбиваем его на массив. О методе componentsSeparatedByString я писал еще в первых уроках NSString (Строки). Далее следует проверка маркеров и если они удовлетворяют условия — выводим сообщение уже с помощью Objective-C.

 

К сожалению, мне не удалось найти способа вызова Objective-C функции с JavaScript, которая бы возвращала данные в JavaScript. Предпологаю, что для этого следует создать еще одну функцию в JavaScript, которая будет принимать значение и изменять переменные в ответ на вызов метода Objective-C. Но как это сделать, я думаю, вы разберетесь сами.

 

Исходный код этого проекта можно скачать здесь.