このチュートリアルでは、Pebble の C API を使ってシンプルなウォッチフェイスを作成する基本を学びます。カスタマイズ性は Pebble 哲学の中核をなすものなので、ユーザー向けのエキサイティングな機能も追加していきます!
このセクションのチュートリアルを完了すると、次のような新しい基本的なウォッチフェイスが完成します:



それでは、始めましょう!
チュートリアルを始める前に、Pebble SDK をインストールする必要があります。まだインストールしていない場合は、ダウンロードページにアクセスして SDK を入手し、指示に従って PC にインストールしてください。インストールが完了したら、ここに戻って続きを進めることができます。
SDK をインストールしたら、任意のディレクトリに移動してpebble new-project watchfaceを実行します(ここでいう'watchface'は新しいプロジェクトの名前を指します。)。これにより新しいプロジェクトが開始され、関連するすべてのファイルがセットアップされます。
SDK プロジェクトでは、アプリの設定方法に関するすべての情報(名前、作成者、機能、リソースリストなど)が、プロジェクトのルートディレクトリにあるpackage.jsonというファイルに保存されます。このプロジェクトはウォッチフェイスになるため、このファイル内のwatchappオブジェクトを次のように変更する必要があります:
"watchapp": {
"watchface": true
}
この 2 つの種類の主な違いは、ウォッチフェイスが時計のデフォルト表示として機能し、Up ボタンと Down ボタンで Pebble タイムラインを使用できる点です。つまり、これらのボタンはカスタム動作には使用できません(Back ボタンと Select ボタンもウォッチフェイスでは使用できません)。対照的に、watchapp は Pebble システムメニューから起動されます。これらにはボタンクリックやメニュー要素などのより多くの機能がありますが、それらについては後ほど説明します。
最後に、companyNameの値を設定すれば、コードを書き始めることができます!
最初のソースファイルは、pebbleコマンドラインツールによってすでに作成されており、プロジェクトのsrcディレクトリにあります。デフォルトでは、このファイルにはサンプルコードが含まれていますが、ゼロから始めるので安全に削除できます。不要という場合には、プロジェクトを作成する際に--simpleフラグを使用することで、これを回避することもできます。
すべての Pebble ウォッチフェイスやア Pebble アプリに必要な基本的なコードセグメントを追加しましょう。まず、ファイルの先頭に Pebble SDK を使用するためのメインディレクティブを追加します:
#include <pebble.h>
この最初の行の後、推奨されるアプリ構造から始める必要があります。具体的には、標準 C のmain()関数と、すべての Pebble SDK 要素の作成と破棄を整理するための 2 つの関数です。これにより、メモリの割り当てと解放の管理をできるだけシンプルにすることができます。さらに、main()はapp_event_loop()も呼び出し、watchapp が終了するまでシステムイベントを待機できるようにします。
推奨される構造を以下に示します。これをメイン C ファイルの基礎として使用できます:
#include <pebble.h>
static void init() {
}
static void deinit() {
}
int main(void) {
init();
app_event_loop();
deinit();
}
最初のWindowを追加するには、まずWindow変数への静的ポインタを宣言します。これにより、必要な場所(主にinit()とdeinit()関数)でアクセスできるようになります。この宣言を#includeの下に追加し、s_をプレフィックスとして付けてstaticの性質を示します(ここでのstaticは、このファイル内でのみアクセス可能であることを意味します):
static Window *s_main_window;
次のステップは、このポインタに割り当てるWindowのインスタンスを作成することです。これは、適切な Pebble SDK 関数を使用してinit()で行います。このプロセスでは、追加の抽象化レイヤーを提供する 2 つのハンドラ関数を割り当て、後続のWindowサブ要素の作成を管理します。これは、init()とdeinit()が watchapp 全体に対してこのタスクを実行する方法と同様です。これら 2 つの関数はinit()の上に作成する必要があり、次のシグネチャに一致する必要があります(ただし、名前は異なっていても構いません):
static void main_window_load(Window *window) {
}
static void main_window_unload(Window *window) {
}
これが完了したら、Window要素の作成を完了できます。Windowが構築されるたびにシステムによって呼び出されるこれら 2 つの新しいハンドラ関数を参照します。このプロセスを以下に示します。これはinit()で行われます:
static void init() {
// Create main Window element and assign to pointer
s_main_window = window_create();
// Set handlers to manage the elements inside the Window
window_set_window_handlers(s_main_window, (WindowHandlers) {
.load = main_window_load,
.unload = main_window_unload
});
// Show the Window on the watch, with animated=true
window_stack_push(s_main_window, true);
}
この初期段階で学ぶべき良いベストプラクティスは、すべての Pebble SDK の_create()関数呼び出しと、それに対応する_destroy()関数を一致させて、アプリが終了したときに使用されたすべてのメモリがシステムに返されるようにすることです。メインWindow要素について、deinit()でこれを行いましょう:
static void deinit() {
// Destroy Window
window_destroy(s_main_window);
}
これで、このウォッチフェイスをコンパイルして実行できますが、まだ興味深いものは表示されません。変更ごとにコードがまだ有効であることを反復的に確認するのも良い習慣なので、今それを行いましょう。
ウォッチフェイスをコンパイルするには、プロジェクトファイルを保存したことを確認してから、プロジェクトのルートディレクトリからpebble buildを実行します。インストール可能な.pbwファイルはbuildディレクトリに保存されます。コンパイルが成功すると、'build' finished successfullyというメッセージが表示されます。コードに問題がある場合、コンパイラはエラーのある行を教えてくれるので、修正できます。
ウォッチフェイスを Pebble にインストールするには、まずPebble Developer Connectionをセットアップしてください。最新バージョンの Pebble アプリを使用していることを確認してください。
pebble installを実行して watchapp をインストールします。--phoneフラグでスマートフォンの IP アドレスを指定します。例: pebble install --phone 192.168.1.78。
毎回--phone フラグを使用する代わりに、PEBBLE_PHONE 環境変数を設定できます:
export PEBBLE_PHONE=192.168.1.78とすれば、単にpebble installを使用できます。
おめでとうございます!ウォッチフェイスメニューに新しいアイテムが表示されます。でも、画面には何も表示されません!



次のステップであるTextLayer要素を使って、基本的なウォッチフェイスへと変えていきましょう。
メイン C ファイルを再度開いてコードを追加していきましょう。
ウォッチフェイスやウォッチアプリにテキストを表示する最良の方法は、TextLayer要素を使用することです。これを行う最初のステップは、Windowの設定に使用したのと同様の手順に従い、ポインタを使って設定することです。理想的にはs_main_windowの下に追加します:
static TextLayer *s_time_layer;
これはWindowに追加される最初の要素なので、main_window_load()で Pebble SDK 関数呼び出しを行って作成します。text_layer_create()を呼び出した後、他の関数を作成して呼び出します。関数名には、その機能を正確に説明する平易な英語名をつけます。その機能とは、TextLayerに表示されるテキストのレイアウトプロパティ(色、配置、フォントサイズなど)の設定を支援することです。また、TextLayerが正しく設定されていることを確認するために、"00:00"でtext_layer_set_text()を呼び出します。
レイアウトパラメータは、ディスプレイの形状によって異なります。丸型と長方形のディスプレイ形状のそれぞれで使用される垂直位置の値を簡単に指定するために、PBL_IF_ROUND_ELSE()を使用します。したがって、main_window_load()は次のようになります:
static void main_window_load(Window *window) {
// Get information about the Window
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);
// Create the TextLayer with specific bounds
s_time_layer = text_layer_create(
GRect(0, PBL_IF_ROUND_ELSE(58, 52), bounds.size.w, 50));
// Improve the layout to be more like a watchface
text_layer_set_background_color(s_time_layer, GColorClear);
text_layer_set_text_color(s_time_layer, GColorBlack);
text_layer_set_text(s_time_layer, "00:00");
text_layer_set_font(s_time_layer, fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD));
text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
// Add it as a child layer to the Window's root layer
layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
}
GColorBlackやFONT_KEY_BITHAM_42_BOLDなどの SDK 値の使用に注目してください。これらにより、組み込み機能と動作を使用できます。これらの例は、黒色と組み込みシステムフォントです。後ほど、この値を置き換えるために使用できるカスタムフォントファイルの読み込みについて説明します。
Windowと同様に、作成した各要素を必ず破棄する必要があります。これをmain_window_unload()で行い、TextLayerの管理を、それが関連付けられているWindowの読み込みとアンロード内に完全に保ちます。この関数は次のようになります:
static void main_window_unload(Window *window) {
// Destroy TextLayer
text_layer_destroy(s_time_layer);
}
これで基本的なウォッチフェイスレイアウトの設定が完了しました。pebble build && pebble install(スマートフォンの IP アドレスを指定)を実行して新しいビルドを行うと、次のように表示されるはずです:



最後のステップは、現在の時刻を取得してTextLayerを使用して表示することです。これはTickTimerServiceを使って行います。
TickTimerServiceは、時刻が変わるたびに実行される関数をサブスクライブすることで、現在の時刻にアクセスできるようにする Event Service です。通常、これは毎分ですが、毎時、または毎秒にすることもできます。ただし、後者は追加のバッテリーコストが発生するため、控えめに使用してください。これはtick_timer_service_subscribe()を呼び出すことで実行できますが、まず時刻が変わるたびにサービスが呼び出すための関数を作成する必要があり、次のシグネチャに一致する必要があります:
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
}
これは、時刻が変わるたびに、さまざまな形式で現在の時刻を含むstruct tm型のデータ構造と、どの単位が変更されたかを示す定数TimeUnits値が提供され、動作のフィルタリングを可能にすることを意味します。TickHandlerを作成したら、次のようにinit()で Event Service に登録できます:
// Register with TickTimerService
tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
時刻TextLayerを更新するロジックは、update_time()という関数で作成されます。これにより、TickHandlerから呼び出すだけでなく、main_window_load()からも呼び出して、最初から時刻が表示されるようにすることができます。
この関数はstrftime()を使用します(フォーマットについてはこちらを参照)。struct tmデータ構造から時と分を抽出し、文字バッファに書き込みます。このバッファは、テキストが表示される限り長く存続する必要があります。これはTextLayerにコピーされるのではなく、単に参照されるためです。これを実現するために、バッファをstaticにして、update_time()への複数の呼び出しにわたって永続化します。したがって、この関数はmain_window_load()の前に作成され、次のようになります:
static void update_time() {
// Get a tm structure
time_t temp = time(NULL);
struct tm *tick_time = localtime(&temp);
// Write the current hours and minutes into a buffer
static char s_buffer[8];
strftime(s_buffer, sizeof(s_buffer), clock_is_24h_style() ?
"%H:%M" : "%I:%M", tick_time);
// Display this time on the TextLayer
text_layer_set_text(s_time_layer, s_buffer);
}
TickHandlerは正しい関数シグネチャに従い、まさにそれを行うためのupdate_time()への単一の呼び出しのみを含みます:
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
update_time();
}
最後に、init()を修正してwindow_stack_push()の後にupdate_time()への呼び出しを含め、ウォッチフェイスが読み込まれたときに時刻が正しく表示されるようにします:
// Make sure the time is displayed from the start
update_time();
これで時刻を表示できるようになったので、main_window_load()内のtext_layer_set_text()への呼び出しは、レイアウトのテストに必要なくなったため削除できます。
ウォッチフェイスを再コンパイルして Pebble に再インストールすると、次のように表示されるはずです:



以上で、新しい Pebble ウォッチフェイスを作成するために必要な基本的なプロセスが完了しました!これを実現するために、次のことを行いました:
Windowをセットアップしました。TextLayerをセットアップしました。TickTimerServiceをサブスクライブして時刻の更新を取得し、これらをTextLayerに表示するためのバッファに書き込みました。コードに問題がある場合は、以下のボタンを使用して提供されているサンプルソースコードと照らし合わせて確認してください。
チュートリアルの次のセクションでは、ウォッチフェイスにカスタムフォントとビットマップ画像を追加する方法を紹介します。