Создание нативной библиотеки расширений для OpenFL, часть вторая

http://labe.me/en/blog/posts/2013-06-24-OpenFL-extension-2.html
  • Перевод
  • Tutorial

Предисловие


Это продолжение перевода серии статей о создании расширений для OpenFL от Laurent Bédubourg. В первой части мы создали простое расширение и скомпилировали его для нативных платформ (Linux/Windows, Android, iOS). В этой части мы добавим в наше приложение на iOS возможность отправлять твиты.

Что мы узнаем:
  • как структурировать исходный код нашего расширения для различных платформ
  • как связать код на haxe и функции из нашего расширения
  • как линковаться с iOS фреймворками (с фреймворком Twitter, в частности)


Что делать?


Давайте начнем с того, что посмотрим как структурирован, например, проект NME.

На первый взгляд Build.xml выглядит сложно и мы вернемся в нему позже. Посмотрев на содержимое каталога, мы увидим следующее:
  • include/ содержит заголовочные файлы, которые будут реализованы в common/ и plaforms
  • common/ платформо-независимый c++ код (более менее платформо-независимый, мы можем использовать #if defined(HX_xxxx) чтобы добиться максимальной платформо-независимости)
  • common/ExternalIterface.cpp экспортирует функции в среду исполнения (DEFINE_PRIM)
  • platform в данном каталоге содержатся реализации под конкретные платформы (iPhone, maс, windows и другие)

На мой взгляд такая структура выглядит довольно удобной, давайте и мы будем ее использовать.

Начнем с нашего предыдущего расширения, мы должны объявить функцию Tweet() в существующем файле include/Util.h (по уму, мы должны использовать отдельный заголовочный файл, но я сегодня слишком ленив для этого).
namespace testextension {
  int SampleMethod(int inputValue);
  bool Tweet(const char* msg);
}

Теперь нам необходимо реализовать ее для платформы iphone:
cd project
mkdir iPhone

Создадим файл iPhone/Tweet.mm:
#import <Foundation/Foundation.h>
#import <Twitter/Twitter.h>

namespace testextension {
    bool Tweet(const char* message){
        // Простите за этот кусок кода на Objective-C
        // Я просто скопировал его из другого поекта
        // Мы должны проверить инициализирован ли клиент твитера
        // Но я оставлю эту задачу читателю для самостоятельного решения :)
        NSString* str = [[NSString alloc] initWithUTF8String:message];
        TWTweetComposeViewController* tweetView = [[TWTweetComposeViewController alloc] init];
        [tweetView setInitialText:str];
        TWTweetComposeViewControllerCompletionHandler completionHandler =
            ^(TWTweetComposeViewControllerResult result) {
                [[[[UIApplication sharedApplication] keyWindow] rootViewController] dismissModalViewControllerAnimated:YES];
            };
        [tweetView setCompletionHandler:completionHandler];
        [[[[UIApplication sharedApplication] keyWindow] rootViewController]  presentModalViewController:tweetView animated:YES];
        return true;
    }
}

И зарегистрируем функцию Tweet в haxe, для этого отредактируем файл common/ExternalInterface.cpp:
static value testextension_tweet(value message){
    // мы знаем, что message это строка и просто получим ее значение
    const char* cStr = val_get_string(message);
    // вызовем нашу функцию Tweet и вернем в haxe true или false
    if (testextension::Tweet(cStr))
        return val_true;
    return val_false;
}
// зарегистрируем нашу функцию, наша функция принимает один аргумент
DEFINE_PRIM(testextension_tweet, 1)

DEFINE_PRIME, val_get_string, val_true и всё остальное являются частью hxcpp и определены в hx/CFFI.h.

Изучение ExternalInterface.cpp из NME поможет вам понять, как зарегистрировать ваши функции.

Часть haxe находится в TextExtension.hx и выглядит вот так:
class TestExtension {

// загружаем нашу функцию
private static var testextension_tweet = Lib.load("testextension", "testextension_tweet", 1);

// внутри типизированного метода вызываем нативную функцию
public static function tweet(message:String) : Bool {
    return testextension_tweet(message);
}
}

Как скомпилировать


Мне пришлось приложить усилия, чтобы разобраться как скомпилировать и слинковать проект, но в результате все оказалось довольно просто.

Сперва необходимо создать файл project/Build.xml:
<!-- мы добавили этот список файлов для ios -->
<files id="iphone">
  <file name="iPhone/Tweet.mm"/>
</files>

<!--
  Я также был вынужден скомпилировать расширение для Мака, чтобы избавиться от
  следующей ошибки:
  "Library TestExtension version dev does not have a neko dll for your system"
-->
<files id="mac">
  <file name="Mac/Tweet.mm"/>
</files>

В секцию с id = NDLL необходимо добавить файлы, которые будут компилироваться:
<files id="mac" if="mac"/>
<files id="iphone" if="ios"/>

И, наконец, мы должны добавить фреймворк Twitter в зависимости в include.xml. Через этот файл hxcpp узнает какие фреймворки необходимо добавить в наше приложение.
<dependency name="Twitter.framework" if="ios"/>

Я скомпилировал расширение, также как я делал это в первой части.
haxelib run hxcpp Build.xml -Dmac
haxelib run hxcpp Build.xml -Diphoneos -DHXCPP_ARMV7
haxelib run hxcpp Build.xml -Diphonesim

Как запустить


Чтобы протестировать работу расширения, я добавил в свое тестовое приложение следующий вызов:
TestExtension.tweet("This is my tweet message");

И запустил его в симуляторе и на моем iOS устройстве:
cd TestApp
openfl test project.xml iphone -simulator
openfl test project.xml iphone

Окно приложения на iPhone
Мы можем твитить используя нативный API из нашего приложения! Круто, не правда ли?! :)

Хочу отметить одну очень важную вещь — способ, которым я получал информацию — находил ее в исходном коде hxcpp и nme, на гитхабе.

Пытаясь заставить все это работать я столкнулся с несколькими проблемами. Если вы экспериментируете и у вас что-то не получается, не забывайте очищать каталоги ndl/ и project/obj и пересобирать весь проект. Я продолжал экспериментировать, пока не нашел подходящий формат для Build.xml и include.xml.

Единственной реальной сложностью является недостаток документации по формату Build.xml в hxcpp. Но, слава богу, есть примеры, на которых можно учиться.

Следующее, что я хочу сделать, попробовать собрать расширение под андроид, чтобы убедиться, что и на этой платформе все работает. Говорят, что не только разработать расширение на java, но и описать это процесс будет полезным :)

Я обновил репозиторий расширения на гитхабе, в надежде, что мой небольшой вклад будет полезен другим хаксерам! Надеюсь данное руководство будет работать на вашей системе… хотя иногда все идет не так как задумывается ;)
Поделиться публикацией
Комментарии 0

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

Самое читаемое