2015年04月02日

Tizenアプリ開発事始め (2)

昨日(04/01)から日吉の街は若者達で溢れかえっています。昨日、慶応大学の入学式があったようです。クラスやクラブの仲間同士で親睦会をやっているのでしょう。街中の喫茶店、カフェ、レストラン、ファミレスはどこも新入生らしい若者で一杯で、他の客はいつも以上に入りづらい雰囲気が漂っています。リクルート・スーツの新社会人もそうですが、大学の新入生を見分けるのはすごく簡単です。私服に慣れていない様子で一目で判ってしまいます。特に地方から上京してきたらしい女子学生は、私服がぜんぜん様になっていないので一発でそれだと判ります(いま三くらいアダルティな服装が似合っておらず、私服の着こなしに慣れていないのが丸分かりです)。私は大学へは進学しなかったので当事者としての経験はありませんが、これが学生街特有の春の雰囲気というものなのですね。彼らを観ていると、若さへの羨望が湧き上がってきて複雑な気持ちになります。人生の黄昏時を迎えている私にとっては眩しすぎる光景です。

さて、前記事の続きを書きます。Tizen Developer Guideの掲載されているチュートリアルを読みながら、Tizen(Tizen Mobile)のNative ApplicationモデルのHello Worldアプリを作成してEmulatorで実行できることを確認するのがゴールです。

■ Native Applicationモデル・アプリの作成


最初にやるべきことは、Native Applicationモデルのプロジェクトの作成です。

Tizen IDEの[File] > [New] > [Project]メニューを選択すると、下のようなウィンドウが開きます。
SCShot_150402_0003-Creating_HelloWorld_NativeApp-TizenIDE-525x500.png
このウィンドウの[Tizen] > [Tizen Native Project]という項目を選択して、[Next > ]ボタンを押すと、さらに下のような[New Tizen Native Project]ウィンドウが開きます。
SCShot_150402_0008-Creating_HelloWorld_NativeApp-TizenIDE-910x759
チュートリアルに従って、このウィンドウでは[Template] > [MOBILE-2.3] → [UI Application] > [Basic UI Application]という項目を選択し、[Project name]エディットボックスにプロジェクト名を入力した上で、[Finish]ボタンを押しました。この操作によって、新しいNative Applicationモデルのプロジェクトが作成されます。

作成されたプロジェクトは、Workbenchウィンドウの[Project Explorler]ビュー内にエントリとして追加されます。
SCShot_150402_0010-Creating_HelloWorld_NativeApp-TizenIDE-1024x742
プロジェクトを作成できたので、さっそくこれをビルドしてみました(上のスクリーンショットは、プロジェクトをビルドした後のものです)。ビルドのやり方はWeb Applicationと同じです。

■ EmulatorによるNative Applicationの実行


Native Applicationモデルのプロジェクトが作成できたので、Tizen SDKのEmulatorを使ってこれを実行してみしまた。Emulatorの仮想マシンでプロジェクトを実行する手順は、Web Applicationと同じなので省略します(前記事を参照のこと)。
SCShot_150402_0011-Creating_HelloWorld_NativeApp-TizenIDE-434x452.png
SCShot_150402_0012-Creating_HelloWorld_NativeApp-TizenIDE-434x452.png

■ Native Application Hello Worldチュートリアル


以上でNative Applicationモデル・アプリの作成とEmulatorによる実行は終わりですが、「Creating Your First Tizen Application」チュートリアルには、プロジェクトに変更を加えてEmulatorで実行するまでの手順が書かれています。続きの作業として、このチュートリアルの内容を最後までやってみました。

Tizen IDEの[Project Explorler]内のプロジェクトの構成ファイルからsrc/helloworldnativeapp.c(このソースファイルの名前はプロジェクト名に連動して決まるようです。つまりプロジェクト名によってファイル名が変わります)をダブルクリックすると、下のような[Editor]ビューが開いて、その中にhelloworldnativeapp.cの内容が表示されます。
SCShot_150402_0013-Creating_HelloWorld_NativeApp-TizenIDE-1024x742
helloworldnativeapp.cにはC/C++で書かれたアプリの処理コードが含まれています。

チュートリアルにはNative Applicationプログラムの基本原則とTizen IDEのコード入力支援機能についての概要説明が書かれており、それに続いて、helloworldnativeapp.cに対する改造版サンプル・コードが掲載されています。[Editor]ビュー内のコードを編集して、このサンプル・コードをhelloworldnativeapp.cへ追加してみました。
#include <tizen.h>
#include "helloworldnativeapp.h"

#if 0
typedef struct appdata {
Evas_Object *win;
Evas_Object *conform;
Evas_Object *label;
} appdata_s;
#endif
#if 1
typedef struct appdata
{
// All graphical objects here are pointers to the value of the type Evas_Object.
Evas_Object *win;
Evas_Object *conformant;
Evas_Object *naviframe;
} appdata_s;
#endif

static void
win_delete_request_cb(void *data, Evas_Object *obj, void *event_info)
{
ui_app_exit();
}

#if 0
static void
win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
appdata_s *ad = data;
/* Let window go to hide state. */
elm_win_lower(ad->win);
}
#endif
#if 1
static void
clicked_cb(void *user_data, Evas_Object *obj, void *event_info)
{
elm_exit();
}
#endif

#if 0
static void
create_base_gui(appdata_s *ad)
{
/* Window */
ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
elm_win_autodel_set(ad->win, EINA_TRUE);

if (elm_win_wm_rotation_supported_get(ad->win)) {
int rots[4] = { 0, 90, 180, 270 };
elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
}

evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL);
eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad);

/* Conformant */
ad->conform = elm_conformant_add(ad->win);
elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);
elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_OPAQUE);
evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(ad->win, ad->conform);
evas_object_show(ad->conform);

/* Label*/
ad->label = elm_label_add(ad->conform);
elm_object_text_set(ad->label, "Hello EFL");
evas_object_size_hint_weight_set(ad->label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_object_content_set(ad->conform, ad->label);
evas_object_show(ad->label);

/* Show window after base gui is set up */
evas_object_show(ad->win);
}
#endif

#if 1
static void
create_gui(appdata_s *ad)
{
// Create the window
ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
elm_win_conformant_set(ad->win, EINA_TRUE);

// Advertise which rotations are supported by the application; the
// device_orientation callback is used to do the actual rotation when
// the system detects the device's orientation has changed
if (elm_win_wm_rotation_supported_get(ad->win)) {
int rots[4] = { 0, 90, 180, 270 };
elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
}

// Add a callback on the "delete,request" event; it is emitted when
// the system closes the window
evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL);

// Alternatively, elm_win_autodel_set() can be used to close
// the window (not the application) automatically
// with the Back button, for example
// elm_win_autodel_set(ad->win, EINA_TRUE);

// Create the conformant
ad->conformant = elm_conformant_add(ad->win);

// Set the conformant use as much horizontal and vertical space as
// possible, that is, expand in both directions
evas_object_size_hint_weight_set(ad->conformant, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);

// Set the conformant as the resize object for the window:
// the window and the conformant grow together
// in proportion to each other
elm_win_resize_object_add(ad->win, ad->conformant);

// Show the conformant since all widgets are hidden by default
evas_object_show(ad->conformant);

// Create the naviframe
ad->naviframe = elm_naviframe_add(ad->conformant);
elm_object_content_set(ad->conformant, ad->naviframe);

// Show the box
evas_object_show(ad->conformant);

// Create the box
Evas_Object *box = elm_box_add(ad->naviframe);

// Set the box vertical
elm_box_horizontal_set(box, EINA_FALSE);

// The box expands when its contents need more space
evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);

// The box fills the available space
evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);

// Add the box in the naviframe container
elm_naviframe_item_push(ad->naviframe, "Hello World", NULL, NULL, box, NULL);

// Show the box
evas_object_show(box);

// Create the label
Evas_Object *label = elm_label_add(box);
// The label expands when its contents need more space
evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
// The box fills the available space on the horizontal axis and is
// centered on the vertical axis (placed at 0.5 vertically, that is, in the
// middle)
evas_object_size_hint_align_set(label, EVAS_HINT_FILL, 0.5);

// Set the text for the label and set formatting through the HTML tags:
// - "Hello World!" centered on the first line
// - skip a line
// - Add a longer text that does not fit on a single line but wraps at
// the word boundaries
elm_object_text_set(label,
"<align=center>Hello World!</align>< br >"
"< br >"
"<wrap = word>Clicking on the button below closes the application.</wrap>");

// Add the label at the end of the box
elm_box_pack_end(box, label);

// Show the label
evas_object_show(label);

// Create the button
Evas_Object *button = elm_button_add(box);

// The box expands when its contents need more space
evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);

// The button fills the available space on the horizontal axis and is
// placed at the bottom of the vertical axis (1 is the end of the axis,
// the coordinates start at (0, 0) on the top-left corner
evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 1);

// Set the text for the button
elm_object_text_set(button, "Close!");

// Add a callback on the button for the "clicked" event; implementation of
// the callback is below
evas_object_smart_callback_add(button, "clicked", clicked_cb, NULL);

// Add the widget at the end of the box; since the axis starts in the top left
// corner and the box is vertical, the end of the box is below the label
elm_box_pack_end(box, button);

// Show the button
evas_object_show(button);

// Show window after the GUI is set up
evas_object_show(ad->win);
}
#endif

static bool
app_create(void *data)
{
/* Hook to take necessary actions before main event loop starts
Initialize UI resources and application's data
If this function returns true, the main loop of application starts
If this function returns false, the application is terminated */
appdata_s *ad = data;

#if 0
create_base_gui(ad);
#endif
#if 1
create_gui(ad);
#endif
return true;
}

static void
app_control(app_control_h app_control, void *data)
{
/* Handle the launch request. */
}

static void
app_pause(void *data)
{
/* Take necessary actions when application becomes invisible. */
}

static void
app_resume(void *data)
{
/* Take necessary actions when application becomes visible. */
}

static void
app_terminate(void *data)
{
/* Release all resources. */
}

static void
ui_app_lang_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LANGUAGE_CHANGED*/
char *locale = NULL;
system_settings_get_value_string(SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale);
elm_language_set(locale);
free(locale);
return;
}

static void
ui_app_orient_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_DEVICE_ORIENTATION_CHANGED*/
return;
}

static void
ui_app_region_changed(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_REGION_FORMAT_CHANGED*/
}

static void
ui_app_low_battery(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LOW_BATTERY*/
}

static void
ui_app_low_memory(app_event_info_h event_info, void *user_data)
{
/*APP_EVENT_LOW_MEMORY*/
}

int
main(int argc, char *argv[])
{
appdata_s ad = {0,};
int ret = 0;

ui_app_lifecycle_callback_s event_callback = {0,};
app_event_handler_h handlers[5] = {NULL, };

event_callback.create = app_create;
event_callback.terminate = app_terminate;
event_callback.pause = app_pause;
event_callback.resume = app_resume;
event_callback.app_control = app_control;

ui_app_add_event_handler(&handlers[APP_EVENT_LOW_BATTERY], APP_EVENT_LOW_BATTERY, ui_app_low_battery, &ad);
ui_app_add_event_handler(&handlers[APP_EVENT_LOW_MEMORY], APP_EVENT_LOW_MEMORY, ui_app_low_memory, &ad);
ui_app_add_event_handler(&handlers[APP_EVENT_DEVICE_ORIENTATION_CHANGED], APP_EVENT_DEVICE_ORIENTATION_CHANGED, ui_app_orient_changed, &ad);
ui_app_add_event_handler(&handlers[APP_EVENT_LANGUAGE_CHANGED], APP_EVENT_LANGUAGE_CHANGED, ui_app_lang_changed, &ad);
ui_app_add_event_handler(&handlers[APP_EVENT_REGION_FORMAT_CHANGED], APP_EVENT_REGION_FORMAT_CHANGED, ui_app_region_changed, &ad);
ui_app_remove_event_handler(handlers[APP_EVENT_LOW_MEMORY]);

ret = ui_app_main(argc, argv, &event_callback, &ad);
if (ret != APP_ERROR_NONE) {
dlog_print(DLOG_ERROR, LOG_TAG, "app_main() is failed. err = %d", ret);
}

return ret;
}

※「#if 0 〜 #endif」で挟まれた行はオリジナルのコードを無効化した部分、「#if 1 〜 #endif」で挟まれた行が追加したコードです。また、160行目と161行目に“< br >”という文字列が存在しますが、これは“<br>”が正しいです。“<br>”だとHTMLの改行タグと解釈されてしまうため、わざと“< br >”に変えています。上のソースコードをコピペして利用する場合は、この2箇所を修正してください。

上のhelloworldnativeapp.cの処理コードの詳細はまだ理解できていません。これからTizenのアプリ開発を続けていけば、自然に理解できるようになるでしょう。

上記の操作が終わった後、プロジェクトを再ビルドした上で、Emulator Managerの仮想マシンでプロジェクトを再度実行してみました。すると、アプリの起動画面は下のような表示に変わりました。
SCShot_150402_0014-Creating_HelloWorld_NativeApp-TizenIDE-434x452.png
チュートリアルに掲載されているスクリーンショットと若干の相違がありますが、ほぼ同じアプリの起動画面が表示されたので、これでゴール到達とします。

Web ApplicationとNative Applicationを比較すると、前者のプログラミング言語はHTML5とJavaScriptなのに対して後者はC/C++になります。プログラミングの手軽さではやはりWeb Applicationの方に軍配を上げざるをえません。モバイル・アプリ開発ではフットワークの軽さはすごく重要だと思います。C/C++だと単機能な軽いアプリでも最低丸一日かかりますが、HTML5 + JavaScriptだと数時間で出来てしまうじゃないかという気がします(もちろんOS側のフレームワークやAPIに精通していることは条件になりますが)。TizenやFirefox OSでHTML5 + JavaScriptでアプリが書けることは、iOSやAndroidと比較して大きな利点だと思います(iOSやAndroidにもHTML5 + JavaScriptでアプリ開発ができるフレームワークやツールは存在します)。HTML5 + JavaScriptの有利さを知って、益々Tizenへの興味が膨らんできました。HTML5とJavaScriptを本格的に勉強してみたかったので、TizenやFirefox OSのアプリ開発は良い素材になりそうです。組込み、モバイル、Webプログラミングが融合した研究テーマであることに気づかされました。

以上で、TizenのHello Worldアプリの作成とEmlator/Web Simulatorによる動作確認は終了です。記事を書きながら作業を進めたので2日かかってしまいましたが、全体でも1〜2時間でできる作業だと思います。03/27の記事と合わせて、Tizenへの取り組みを始めるプログラマ達の役に立てば幸いです。

私がTizenの研究を始めた理由は、組込みLinuxとモバイル・アプリ開発の両方に取り組めるテーマだからです。JavaのフレームワークでLinuxを覆い隠しているAndroidよりは、システム側をいじくり回す機会が多いんじゃないかと思っています(私がAndroidを嫌っている大きな理由がこれです。個人研究のプログラミングでJavaは使いたくないです)。Yocto Linuxの記事へのアクセス数があまりに少ないので、もう少しメジャーな研究テーマへシフトしたかったことも理由の一つです(Tizenはまだまだメジャーではないですが、Yocto Linuxよりは検索する人が多いんじゃないかと思います)。Yocto Linuxのネタはまだたくさん有るのですが、こちらはサブのテーマに格下げして、これからはTizenの方をメインの研究テーマとして取り組んでいきます。他にも挑戦してみたい研究テーマもいくつかあるのですが、当面はTizenメインでやっていきます。

やはり実機ターゲットが無いと意欲が湧いてこないので、近いうちにTizenが動くターゲットを一台入手しようと目論んでいます。現在はまだ情報収集中ですが、Androidスマホ(Samsung製限定?)かx86 Atom Bay Trail シリーズを搭載したタブレット辺りでTizenを動かすことに挑戦してみようと計画しています。Firefox OSより情報は少ないですが、ググるといくつかの情報がヒットするので、すでに色々やっている人はいるようです。この計画の実作業を始めたら、その内容も記事に書きたいと思っています。

【参考ページ】

  1. [Tizen]ネイティブアプリを作成しエミュレータ上で実行してみる | GCG研究所
  2. GClue blog: Tizen のNative アプリを実行してみる
posted by とみやん at 09:59| Comment(0) | TrackBack(0) | モバイルOS研究 > Tizen
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/116067167

この記事へのトラックバック