さまざまな Pebble ハードウェア プラットフォーム間の機能の違いは、Hardware Information に記載されています。たとえば、Basalt、Chalk、Emery プラットフォームは 64 色をサポートしていますが、Aplite と Diorite プラットフォームは 2 色のみをサポートしています。これにより、他の非カラーハードウェアとの互換性を考慮する場合、豊富なカラーレイアウトを持つアプリの開発が困難になる可能性があります。もう 1 つの例は、Health や Dictation などのプラットフォーム固有の API を使用することです。
ユーザーの利便性を高めるため、開発者はすべてのプラットフォームで使用できる 1 つのアプリを作成するよう努めるべきです。開発者がこのタスクをより簡単に行えるように、Pebble SDK は、コード内でさまざまなハードウェア機能に対応するための多数のメソッドを提供しています。
#ifdef プリプロセッサステートメントを使用して、特定の目的のためにコンパイルされる特定のコードブロックを指定することができます。たとえば、Dictation API は、マイクがないプラットフォームでは除外する必要があります:
#if defined(PBL_MICROPHONE)
// Start dictation UI
dictation_session_start(s_dictation_session);
#else
// Microphone is not available
text_layer_set_text(s_some_layer, "Dictation not available!");
#endif
UI レイアウトを設計する場合、互換性のあるプラットフォームでの色の使用は、非カラープラットフォームでは黒または白のいずれかに適応できます。適切な機能が利用可能な場合、コンパイル時に PBL_COLOR と PBL_BW シンボルが定義されます:
#if defined(PBL_COLOR)
text_layer_set_text_color(s_text_layer, GColorRed);
text_layer_set_background_color(s_text_layer, GColorChromeYellow);
#else
text_layer_set_text_color(s_text_layer, GColorWhite);
text_layer_set_background_color(s_text_layer, GColorBlack);
#endif
これは、カラー サポートの可用性に応じて変化する複数のステートメントのブロックに役立ちます。単一のステートメントの場合、PBL_IF_COLOR_ELSE() マクロを使用してこれを実現することもできます。
window_set_background_color(s_main_window, PBL_IF_COLOR_ELSE(GColorJaegerGreen, GColorBlack));
利用可能な定義とマクロの完全なリストについては、以下を参照してください。
以下の表は、機能依存のコードを条件付きでコンパイルまたは省略するために利用可能なすべての定義と関連するマクロの完全な概要を示しています。マクロは個々の値の選択に適していますが、定義はコード ブロック全体を選択するのに適しています。
| Define | MACRO | Available |
|---|---|---|
PBL_BW |
PBL_IF_BW_ELSE() |
白黒のみをサポートするハードウェアで実行中。 |
PBL_COLOR |
PBL_IF_COLOR_ELSE() |
64 色をサポートするハードウェアで実行中。 |
PBL_MICROPHONE |
PBL_IF_MICROPHONE_ELSE() |
マイクを含むハードウェアで実行中。 |
PBL_COMPASS |
None | コンパスを含むハードウェアで実行中。 |
PBL_SMARTSTRAP |
PBL_IF_SMARTSTRAP_ELSE() |
smartstrap コネクタを含むハードウェアで実行中だが、コネクタが電力を供給できることは示されていない。 |
PBL_SMARTSTRAP_POWER |
None | 電力を供給できる smartstrap コネクタを含むハードウェアで実行中。 |
PBL_HEALTH |
PBL_IF_HEALTH_ELSE() |
Pebble Health と HealthService API をサポートするハードウェアで実行中。 |
PBL_RECT |
PBL_IF_RECT_ELSE() |
長方形のディスプレイを持つハードウェアで実行中。 |
PBL_ROUND |
PBL_IF_ROUND_ELSE() |
丸型のディスプレイを持つハードウェアで実行中。 |
PBL_DISPLAY_WIDTH |
None | 画面の幅をピクセル単位で決定。 |
PBL_DISPLAY_HEIGHT |
None | 画面の高さをピクセル単位で決定。 |
PBL_PLATFORM_APLITE |
None | Pebble/Pebble Steel 用にビルド。 |
PBL_PLATFORM_BASALT |
None | Pebble Time/Pebble Time Steel 用にビルド。 |
PBL_PLATFORM_CHALK |
None | Pebble Time Round 用にビルド。 |
PBL_PLATFORM_DIORITE |
None | Pebble 2 用にビルド。 |
PBL_PLATFORM_EMERY |
None | Pebble Time 2 用にビルド。 |
PBL_SDK_2 |
None | SDK 2.x でコンパイル(非推奨)。 |
PBL_SDK_3 |
None | SDK 3.x または 4.x でコンパイル。 |
注意: できるだけ具体的にするために、
PBL_PLATFORM定義ではなく、該当する機能定義を使用してコードを条件付きでコンパイルすることを強くお勧めします。
プラットフォームと機能の検出に加えて、特定の API メソッドが利用可能かどうかを検出する API 検出を提供するようになりました。プラットフォームと機能は変化する可能性があるため、このアプローチは将来性があると考えられます。簡単な例を見てみましょう:
#if PBL_API_EXISTS(health_service_peek_current_value)
// Do something if specific Health API exists
#endif
複数のディスプレイの形状と解像度が利用可能であるため、開発者はレイアウト値のハードコーディングを避けるよう努めるべきです。以下の例を考えてみましょう:
static void window_load(Window *window) {
// Create a full-screen Layer - BAD
s_some_layer = layer_create(GRect(0, 0, 144, 168));
}
このレイヤーのハードコードされた幅と高さは、Aplite、Basalt、Diorite では画面全体をカバーしますが、Chalk や Emery ではカバーしません。この種の画面サイズ依存の計算では、Window 自体の UnobstructedArea 境界を使用する必要があります:
static void window_load(Window *window) {
// Get the unobstructed bounds of the Window
Layer window_layer = window_get_root_layer(window);
GRect window_bounds = layer_get_unobstructed_bounds(window_layer);
// Properly create a full-screen Layer - GOOD
s_some_layer = layer_create(window_bounds);
}
この種の構造のもう 1 つの一般的な用途は、遮られない画面の高さの半分の Layer を作成することです。これも、Window の遮られない境界を使用して正しく実現できます:
GRect layer_bounds = window_bounds;
layer_bounds.size.h /= 2;
// Create a Layer that is half the screen height
s_some_layer = layer_create(layer_bounds);
このアプローチは、Window の遮られない境界が変化したときに比例レイアウト値が適切に適応するため、将来の新しい画面サイズ用にアプリを更新する際の簡素化にも有利です。
Emery プラットフォームの導入を容易にするため、Pebble SDK は、開発者が画面の幅と高さを決定できるようにする新しいコンパイラディレクティブを導入しました。これは、複数のプラットフォームが同じ画面の幅と高さを共有しているため、プラットフォーム検出を使用するよりも望ましいです。
#if PBL_DISPLAY_HEIGHT == 228
uint8_t offset_y = 100;
#elif PBL_DISPLAY_HEIGHT == 180
uint8_t offset_y = 80;
#else
uint8_t offset_y = 60;
#endif
注意: この方法はプラットフォーム検出よりも望ましいですが、ルートレイヤーの遮られない境界に基づいてディスプレイの幅と高さを動的に計算する方が良いです。
WatchInfo API を使用すると、アプリが実行されている Pebble のモデルと色を正確に判断できます。アプリは、この情報を使用して、ユーザーが着用している Pebble に応じてレイアウトや動作を動的に変更できます。
たとえば、Pebble Steel のディスプレイは、Pebble Time と比較して、ボタンに対して異なる垂直位置にあります。WatchInfoModel を使用して、これを補正するために画面上のボタンヒントを調整できます。
static void window_load(Window *window) {
Layer window_layer = window_get_root_layer(window);
GRect window_bounds = layer_get_bounds(window_layer);
int button_height, y_offset;
// Conditionally set layout parameters
switch(watch_info_get_model()) {
case WATCH_INFO_MODEL_PEBBLE_STEEL:
y_offset = 64;
button_height = 44;
break;
case WATCH_INFO_MODEL_PEBBLE_TIME:
y_offset = 58;
button_height = 56;
break;
/* Other cases */
default:
y_offset = 0;
button_height = 0;
break;
}
// Set the Layer frame
GRect layer_frame = GRect(0, y_offset, window_bounds.size.w, button_height);
// Create the Layer
s_label_layer = text_layer_create(layer_frame);
layer_add_child(window_layer, text_layer_get_layer(s_label_layer));
/* Other UI code */
}
開発者は、WatchInfoColor 値を使用して、利用可能な Pebble の各色に対してアプリをテーマ化することもできます。
static void window_load(Window *window) {
GColor text_color, background_color;
// Choose different theme colors per watch color
switch(watch_info_get_color()) {
case WATCH_INFO_COLOR_RED:
// Red theme
text_color = GColorWhite;
background_color = GColorRed;
break;
case WATCH_INFO_COLOR_BLUE:
// Blue theme
text_color = GColorBlack;
background_color = GColorVeryLightBlue;
break;
/* Other cases */
default:
text_color = GColorBlack;
background_color = GColorWhite;
break;
}
// Use the conditionally set value
text_layer_set_text_color(s_label_layer, text_color);
text_layer_set_background_color(s_label_layer, background_color);
/* Other UI code */
}
上記の Pebble C WatchInfo と同様に、PebbleKit JS の Pebble.getActiveWatchInfo() メソッドを使用すると、開発者はユーザーが着用している Pebble のモデルと色、および実行されているファームウェア バージョンを判断できます。たとえば、ウォッチのモデルを取得するには:
注意: 古いアプリバージョンでこの関数を使用する際の問題を回避するには、以下のセクションを参照してください。
// Get the watch info
var info = Pebble.getActiveWatchInfo();
console.log("Pebble model: " + info.model);
PebbleKit JS の多くの機能(Pebble.timelineSubscribe() や Pebble.getActiveWatchInfo() など)は SDK 3.x に存在します。アプリがこれらを利用できない古い Pebble モバイルアプリバージョンで使用しようとすると、JS アプリがクラッシュします。
これを防ぐには、関数を呼び出す前に、関数の可用性を必ず確認してください。たとえば、Pebble.getActiveWatchInfo() の場合:
if (Pebble.getActiveWatchInfo) {
// Available.
var info = Pebble.getActiveWatchInfo();
console.log("Pebble model: " + info.model);
} else {
// Gracefully handle no info available
}
Basalt、Chalk、Emery でカラー サポートが利用できるようになったため、開発者は以前に Pebble の白黒ディスプレイ用に前処理されていたリソースのカラーバージョンを含めることを希望する場合があります。リソースの両方のバージョンを含めることは、リソースストレージの観点からコストがかかり、複数のプラットフォーム用にビルドされた際に、Aplite または Diorite アプリに冗長なカラーリソースをパックする負担を負わせます。
この問題を解決するため、Pebble SDK を使用すると、開発者はファイル名に ~bw または ~color を追加して、各ディスプレイ タイプに使用する画像リソースのバージョンを指定できます。リソースは、各リソースの targetPlatforms プロパティを使用して、特定のプラットフォームにのみバンドルすることもできます。
各プラットフォームに固有のリソースのパッケージング、および ~color に類似した利用可能なその他のタグの詳細については、Platform-specific Resources - 特定のプラットフォーム向けリソースの設定 をお読みください。
Chalk プラットフォームの導入により、ピクセル解像度が向上した新しい丸型ディスプレイタイプが利用可能になりました。2 つの可能なディスプレイの形状を区別するために、開発者は定義を使用してコードセグメントを条件付きで含めることができます:
#if defined(PBL_RECT)
printf("This is a rectangular display!");
#elif defined(PBL_ROUND)
printf("This is a round display!");
#endif
この条件付きコンパイルへのもう 1 つのアプローチは、PBL_IF_RECT_ELSE() と PBL_IF_ROUND_ELSE() マクロを使用することです。これにより、前の例と同様の #define ステートメントのセットを必要とする可能性のある式に値を挿入できます。これは、実際には 1 行しか必要ないときに、4 行の余分なコードの不必要な冗長性をもたらすでしょう。これらは次のように使用されます:
// Conditionally print out the shape of the display
printf("This is a %s display!", PBL_IF_RECT_ELSE("rectangular", "round"));
このメカニズムは、ウィンドウ境界派生のレイアウトサイズと位置の値で最もよく使用されます。詳細については、上記の ハードコードされたレイアウト値を避ける セクションを参照してください。組み込みの Layer タイプをうまく利用することも、ディスプレイの形状とサイズの変更からアプリを保護するのに役立ちます。
もう 1 つ考慮すべきことは、丸型ディスプレイでのテキストのレンダリングです。丸い角のため、各水平テキスト行は、垂直位置に応じて異なる利用可能な幅を持ちます。