Pebble Watch iOS SDK Overview
-
Upload
matthew-morey -
Category
Technology
-
view
112 -
download
0
description
Transcript of Pebble Watch iOS SDK Overview
Pebble Watchmatthewmorey.com | @xzolian
matthewmorey.com | @xzolian
☐ What is the Pebble☐ Why you should develop for the Pebble☐ How to develop for the Pebble
Agenda
Demo
vs
ARM Cortex-M3 MCU 120 MHz
Apple A6ARMv7 1.3 GHz
Dual Core
128 KB RAMUp to 8 apps
1 GB RAMUp to 64 GB storage
144 x 168 pixels1-bit color“e-paper”
1,136 × 640 pixels24-bit Color
“Retina”
Pebble iPhone 5
CPU
Memory
Screen
Bluetooth 2.1 and 4.0 LE
Bluetooth 4.0802.11a/b/g/n Wi-Fi
Cellular LTE
3-axis accelerometerAmbient light
Magnetometer
Three-axis gyroAccelerometer
Proximity sensorAmbient light sensor
4 buttonsVibration
Screen backlight
Touch screenButtons
VibrationCamera
Pebble iPhone 5
Comm.
Sensors
IO
2 to 14 days ~1 day
FreeRTOSPebble SDK
PebbleKit
iOSiOS SDK
5 ATM water resistance
22 mm watch band
Not water resistantCan’t wear on wrist
Pebble iPhone 5
Battery
Software
Other
Issues
☑ What is the Pebble☐ Why you should develop for the Pebble☐ How to develop for the Pebble
Agenda
LunaTik
“I agree to wear you around and share a lot of personal data
with you.”
- Customers
$10,266,846 - Pebble Watch (design)
$8,596,475 - OUYA (Android console)
$5,702,153 - Veronica Mars (movie)
$4,188,927 - Torment: Tides of Numenera (game)
$3,986,929 - Project Eternity (game)
$6 Billionper year
Units Sold
Pebble iPhone
>100,000
>250 Million
iOS 7
☑ What is the Pebble☑ Why you should develop for the Pebble☐ How to develop for the Pebble
Agenda
Pebble SDK
1. Pebble SDK dependencies2. Pebble SDK3. ARM dependencies4. Pebble ARM toolchain
Install
Hello World
$ create_pebble_project.py \ > PebbleSDK-1.12/Pebble/sdk \ > hello_world
1 #include "pebble_os.h" 2 #include "pebble_app.h" 3 #include "pebble_fonts.h" 4 5 #define MY_UUID { 6 0x20, 0xD9, 0xFB, 0x8F, 0xBE, 0xCF, 0x49, 7 0x94, 0xA9, 0xE8, 0x70, 0xC0, 0xEA, 0xC6, 8 0x50, 0x16 9 }10 11 PBL_APP_INFO(12 MY_UUID,13 "Hello World",14 "Acme Corp",15 1, 0, /* App version */16 DEFAULT_MENU_ICON,17 APP_INFO_STANDARD_APP18 );
1 #include "pebble_os.h" 2 #include "pebble_app.h" 3 #include "pebble_fonts.h" 4 5 #define MY_UUID { 6 0x20, 0xD9, 0xFB, 0x8F, 0xBE, 0xCF, 0x49, 7 0x94, 0xA9, 0xE8, 0x70, 0xC0, 0xEA, 0xC6, 8 0x50, 0x16 9 }10 11 PBL_APP_INFO(12 MY_UUID,13 "Hello World",14 "Acme Corp",15 1, 0, /* App version */16 DEFAULT_MENU_ICON,17 APP_INFO_STANDARD_APP18 );
1 #include "pebble_os.h" 2 #include "pebble_app.h" 3 #include "pebble_fonts.h" 4 5 #define MY_UUID { 6 0x20, 0xD9, 0xFB, 0x8F, 0xBE, 0xCF, 0x49, 7 0x94, 0xA9, 0xE8, 0x70, 0xC0, 0xEA, 0xC6, 8 0x50, 0x16 9 }10 11 PBL_APP_INFO(12 MY_UUID,13 "Hello World",14 "Acme Corp",15 1, 0, /* App version */16 DEFAULT_MENU_ICON,17 APP_INFO_STANDARD_APP18 );
20 Window window;21 22 void handle_init(AppContextRef ctx) {23 window_init(&window, "Window Name");24 window_stack_push(&window,true/*Animated*/);25 }26 27 28 void pbl_main(void *params) {29 PebbleAppHandlers handlers = {30 .init_handler = &handle_init31 };32 app_event_loop(params, &handlers);33 }
20 Window window;21 22 void handle_init(AppContextRef ctx) {23 window_init(&window, "Window Name");24 window_stack_push(&window,true/*Animated*/);25 }26 27 28 void pbl_main(void *params) {29 PebbleAppHandlers handlers = {30 .init_handler = &handle_init31 };32 app_event_loop(params, &handlers);33 }
20 Window window;21 22 void handle_init(AppContextRef ctx) {23 window_init(&window, "Window Name");24 window_stack_push(&window,true/*Animated*/);25 }26 27 28 void pbl_main(void *params) {29 PebbleAppHandlers handlers = {30 .init_handler = &handle_init31 };32 app_event_loop(params, &handlers);33 }
20 Window window;21 22 void handle_init(AppContextRef ctx) {23 window_init(&window, "Window Name");24 window_stack_push(&window,true/*Animated*/);25 }26 27 28 void pbl_main(void *params) {29 PebbleAppHandlers handlers = {30 .init_handler = &handle_init31 };32 app_event_loop(params, &handlers);33 }
15 TextLayer hello_layer;16 17 void handle_init(AppContextRef ctx) {18 19 window_init(&window, "Window Name");20 window_stack_push(&window, true /* Animated */);21 22 text_layer_init(&hello_layer, GRect(0, 65, 144, 30));23 text_layer_set_text_alignment(&hello_layer,GTextAlignmentCenter);24 text_layer_set_text(&hello_layer, "Hello World!");25 text_layer_set_font(26 &hello_layer,27 fonts_get_system_font(FONT_KEY_ROBOTO_CONDENSED_21)28 );2930 layer_add_child(&window.layer, &hello_layer.layer);31 32 }
15 TextLayer hello_layer;16 17 void handle_init(AppContextRef ctx) {18 19 window_init(&window, "Window Name");20 window_stack_push(&window, true /* Animated */);21 22 text_layer_init(&hello_layer, GRect(0, 65, 144, 30));23 text_layer_set_text_alignment(&hello_layer,GTextAlignmentCenter);24 text_layer_set_text(&hello_layer, "Hello World!");25 text_layer_set_font(26 &hello_layer,27 fonts_get_system_font(FONT_KEY_ROBOTO_CONDENSED_21)28 );2930 layer_add_child(&window.layer, &hello_layer.layer);31 32 }
$ ./waf configure$ ./waf build$ python -m SimpleHTTPServer 8000
$ ./waf configure$ ./waf build$ python -m SimpleHTTPServer 8000
Demo
PBW Filehello_world.pbw (zip archive)
app_resources.pbpack (binary)
manifest.json (txt/json)
pebble-app.bin (binary)
App Watch Face
Sports Apps
Event Handlers
On-screen Layers
Resources
Window Stack
View Lifecycle
load
appear
disappear
unload
viewDidLoad
viewWillAppear
viewDidAppear
viewWillDisappear
viewDidDisappear
Pebble iOS
Layers
Layers10
Layers20
10
Frame
Layers
20
20
Frame
Layers
-100
Bounds
Layers
60
20
Bounds
animation_init() ...animation_schedule()
.update called
.update called ....update called
Animation scheduled
.stopped called
App Pebble OS
Animation
Animation stopped
.started called
Input Handlers
Resourcesraw
png
png-trans
font
Debuggingapp_log
vibes_short_pulsevibes_double_pulsevibes_long_pulse
light_enable_interaction
Watch <=> Phone
app_message_out_send() Dictionary
ACK .out_sent calledAccepted
app_message_out_send() Dictionary
NACK .out_failed calledRejected
Pebble Phone
AppMessage
.in_received called Dictionary
ACK
Sending
Pebble Phone
AppMessage
.in_received called Dictionary
NACK
Sending
app_sync_set(...)
tuple_changed
Accepted
Sending
Pebble Phone
AppSync
190 - (void)setTargetWatch:(PBWatch*)watch {191 192 self.watch = watch;193 194 // Test if the Pebble's firmware supports AppMessages195 [watch appMessagesGetIsSupported: ^(PBWatch *watch, BOOL isAppMessagesSupported) {196197 if (isAppMessagesSupported) {198 199 // Configure communications channel to target the weather app:200 uint8_t bytes[] = {201 0x42, 0xc8, 0x6e, 0xa4, 0x1c, 0x3e, 0x4a, 0x07, 202 0xb8, 0x89, 0x2c, 0xcc, 0xca, 0x91, 0x41, 0x98};203 NSData *uuid = [NSData dataWithBytes:bytes length:sizeof(bytes)];204 [watch appMessagesSetUUID:uuid];205 206 [self updateWatch];207 208 } 209210 }];211 } iOS
190 - (void)setTargetWatch:(PBWatch*)watch {191 192 self.watch = watch;193 194 // Test if the Pebble's firmware supports AppMessages195 [watch appMessagesGetIsSupported: ^(PBWatch *watch, BOOL isAppMessagesSupported) {196197 if (isAppMessagesSupported) {198 199 // Configure communications channel to target the weather app:200 uint8_t bytes[] = {201 0x42, 0xc8, 0x6e, 0xa4, 0x1c, 0x3e, 0x4a, 0x07, 202 0xb8, 0x89, 0x2c, 0xcc, 0xca, 0x91, 0x41, 0x98};203 NSData *uuid = [NSData dataWithBytes:bytes length:sizeof(bytes)];204 [watch appMessagesSetUUID:uuid];205 206 [self updateWatch];207 208 } 209210 }];211 } iOS
190 - (void)setTargetWatch:(PBWatch*)watch {191 192 self.watch = watch;193 194 // Test if the Pebble's firmware supports AppMessages195 [watch appMessagesGetIsSupported: ^(PBWatch *watch, BOOL isAppMessagesSupported) {196197 if (isAppMessagesSupported) {198 199 // Configure communications channel to target the weather app:200 uint8_t bytes[] = {201 0x42, 0xc8, 0x6e, 0xa4, 0x1c, 0x3e, 0x4a, 0x07, 202 0xb8, 0x89, 0x2c, 0xcc, 0xca, 0x91, 0x41, 0x98};203 NSData *uuid = [NSData dataWithBytes:bytes length:sizeof(bytes)];204 [watch appMessagesSetUUID:uuid];205 206 [self updateWatch];207 208 } 209210 }];211 } iOS
259 - (void)updateWatch {260 261 NSDictionary *update = @{262 kKeyWatchIcon:[NSNumber numberWithUint8:1],263 kKeyWatchTemperature:[NSString stringWithFormat:@"%.1f \u00B0F", @”90”]264 };265 266 [self.watch appMessagesPushUpdate:update onSent: ^(PBWatch *watch, NSDictionary *update, NSError *error) {267 268 if (error) {269 // Message was not sent270 } else {271 // Message was sent272 }273 274 }];275 276 }
iOS
259 - (void)updateWatch {260 261 NSDictionary *update = @{262 kKeyWatchIcon:[NSNumber numberWithUint8:1],263 kKeyWatchTemperature:[NSString stringWithFormat:@"%.1f \u00B0F", @”90”]264 };265 266 [self.watch appMessagesPushUpdate:update onSent: ^(PBWatch *watch, NSDictionary *update, NSError *error) {267 268 if (error) {269 // Message was not sent270 } else {271 // Message was sent272 }273 274 }];275 276 }
iOS
259 - (void)updateWatch {260 261 NSDictionary *update = @{262 kKeyWatchIcon:[NSNumber numberWithUint8:1],263 kKeyWatchTemperature:[NSString stringWithFormat:@"%.1f \u00B0F", @”90”]264 };265 266 [self.watch appMessagesPushUpdate:update onSent: ^(PBWatch *watch, NSDictionary *update, NSError *error) {267 268 if (error) {269 // Message was not sent270 } else {271 // Message was sent272 }273 274 }];275 276 }
iOS
296 - (BOOL)handleWatchUpdate:(PBWatch *)watch message:(NSDictionary *)message {299 300 if ([message objectForKey:kKeyWatchRequestUpdate]) {301 NSLog(@"Forecast update requested");303 return YES;304 }305 306 return NO;307 308 }
402 self.updateHandler = [self.watch appMessagesAddReceiveUpdateHandler: ^BOOL(PBWatch *watch, NSDictionary *update) {403 return [self handleWatchUpdate:watch message:update];404 }];
iOS
296 - (BOOL)handleWatchUpdate:(PBWatch *)watch message:(NSDictionary *)message {299 300 if ([message objectForKey:kKeyWatchRequestUpdate]) {301 NSLog(@"Forecast update requested");303 return YES;304 }305 306 return NO;307 308 }
402 self.updateHandler = [self.watch appMessagesAddReceiveUpdateHandler: ^BOOL(PBWatch *watch, NSDictionary *update) {403 return [self handleWatchUpdate:watch message:update];404 }];
iOS
296 - (BOOL)handleWatchUpdate:(PBWatch *)watch message:(NSDictionary *)message {299 300 if ([message objectForKey:kKeyWatchRequestUpdate]) {301 NSLog(@"Forecast update requested");303 return YES;304 }305 306 return NO;307 308 }
402 self.updateHandler = [self.watch appMessagesAddReceiveUpdateHandler: ^BOOL(PBWatch *watch, NSDictionary *update) {403 return [self handleWatchUpdate:watch message:update];404 }];
iOS
171 void pbl_main(void *params) {172 173 PebbleAppHandlers handlers = {174 175 .init_handler = &app_init,176 .deinit_handler = &app_deinit,177 .messaging_info = {178 .buffer_sizes = {179 .inbound = 64,180 .outbound = 16,181 }182 },183 // Handle time updates184 .tick_info = {185 .tick_handler = &handle_minute_tick,186 .tick_units = MINUTE_UNIT187 }188 };189 190 app_event_loop(params, &handlers);191 192 }
Pebble
171 void pbl_main(void *params) {172 173 PebbleAppHandlers handlers = {174 175 .init_handler = &app_init,176 .deinit_handler = &app_deinit,177 .messaging_info = {178 .buffer_sizes = {179 .inbound = 64,180 .outbound = 16,181 }182 },183 // Handle time updates184 .tick_info = {185 .tick_handler = &handle_minute_tick,186 .tick_units = MINUTE_UNIT187 }188 };189 190 app_event_loop(params, &handlers);191 192 }
Pebble
171 void pbl_main(void *params) {172 173 PebbleAppHandlers handlers = {174 175 .init_handler = &app_init,176 .deinit_handler = &app_deinit,177 .messaging_info = {178 .buffer_sizes = {179 .inbound = 64,180 .outbound = 16,181 }182 },183 // Handle time updates184 .tick_info = {185 .tick_handler = &handle_minute_tick,186 .tick_units = MINUTE_UNIT187 }188 };189 190 app_event_loop(params, &handlers);191 192 }
Pebble
171 void pbl_main(void *params) {172 173 PebbleAppHandlers handlers = {174 175 .init_handler = &app_init,176 .deinit_handler = &app_deinit,177 .messaging_info = {178 .buffer_sizes = {179 .inbound = 64,180 .outbound = 16,181 }182 },183 // Handle time updates184 .tick_info = {185 .tick_handler = &handle_minute_tick,186 .tick_units = MINUTE_UNIT187 }188 };189 190 app_event_loop(params, &handlers);191 192 }
Pebble
171 void pbl_main(void *params) {172 173 PebbleAppHandlers handlers = {174 175 .init_handler = &app_init,176 .deinit_handler = &app_deinit,177 .messaging_info = {178 .buffer_sizes = {179 .inbound = 64,180 .outbound = 16,181 }182 },183 // Handle time updates184 .tick_info = {185 .tick_handler = &handle_minute_tick,186 .tick_units = MINUTE_UNIT187 }188 };189 190 app_event_loop(params, &handlers);191 192 }
Pebble
116 static void app_init(AppContextRef c) {117118 resource_init_current_app(&WEATHER_APP_RESOURCES);119 120 Window* window = &s_data.window;121 window_init(window, "PebbleWeather");122 window_set_background_color(window, GColorBlack);123 window_set_fullscreen(window, true);124
...149 // Watch <--> Phone communication150 Tuplet initial_values[] = {151 TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),152 TupletCString(WEATHER_TEMPERATURE_KEY, "-\u00B0C"),153 };154 app_sync_init(&s_data.sync, s_data.sync_buffer, sizeof(s_data.sync_buffer), initial_values, ARRAY_LENGTH(initial_values), sync_tuple_changed_callback, sync_error_callback, NULL);155 156 window_stack_push(window, true);157 168 } Pebble
116 static void app_init(AppContextRef c) {117118 resource_init_current_app(&WEATHER_APP_RESOURCES);119 120 Window* window = &s_data.window;121 window_init(window, "PebbleWeather");122 window_set_background_color(window, GColorBlack);123 window_set_fullscreen(window, true);124
...149 // Watch <--> Phone communication150 Tuplet initial_values[] = {151 TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),152 TupletCString(WEATHER_TEMPERATURE_KEY, "-\u00B0C"),153 };154 app_sync_init(&s_data.sync, s_data.sync_buffer, sizeof(s_data.sync_buffer), initial_values, ARRAY_LENGTH(initial_values), sync_tuple_changed_callback, sync_error_callback, NULL);155 156 window_stack_push(window, true);157 168 } Pebble
116 static void app_init(AppContextRef c) {117118 resource_init_current_app(&WEATHER_APP_RESOURCES);119 120 Window* window = &s_data.window;121 window_init(window, "PebbleWeather");122 window_set_background_color(window, GColorBlack);123 window_set_fullscreen(window, true);124
...149 // Watch <--> Phone communication150 Tuplet initial_values[] = {151 TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),152 TupletCString(WEATHER_TEMPERATURE_KEY, "-\u00B0C"),153 };154 app_sync_init(&s_data.sync, s_data.sync_buffer, sizeof(s_data.sync_buffer), initial_values, ARRAY_LENGTH(initial_values), sync_tuple_changed_callback, sync_error_callback, NULL);155 156 window_stack_push(window, true);157 168 } Pebble
116 static void app_init(AppContextRef c) {117118 resource_init_current_app(&WEATHER_APP_RESOURCES);119 120 Window* window = &s_data.window;121 window_init(window, "PebbleWeather");122 window_set_background_color(window, GColorBlack);123 window_set_fullscreen(window, true);124
...149 // Watch <--> Phone communication150 Tuplet initial_values[] = {151 TupletInteger(WEATHER_ICON_KEY, (uint8_t) 1),152 TupletCString(WEATHER_TEMPERATURE_KEY, "-\u00B0C"),153 };154 app_sync_init(&s_data.sync, s_data.sync_buffer, sizeof(s_data.sync_buffer), initial_values, ARRAY_LENGTH(initial_values), sync_tuple_changed_callback, sync_error_callback, NULL);155 156 window_stack_push(window, true);157 168 } Pebble
104 // Send message to phone asking for a weather update105 void request_weather_update() {106 107 vibes_double_pulse();108 109 Tuplet values[] = {110 TupletInteger(WEATHER_FORECAST_REQUEST_KEY, 1),111 };112 app_sync_set(&s_data.sync, values, ARRAY_LENGTH(values));113 114 }
Pebble
104 // Send message to phone asking for a weather update105 void request_weather_update() {106 107 vibes_double_pulse();108 109 Tuplet values[] = {110 TupletInteger(WEATHER_FORECAST_REQUEST_KEY, 1),111 };112 app_sync_set(&s_data.sync, values, ARRAY_LENGTH(values));113 114 }
Pebble
65 // Tuple changed 66 static void sync_tuple_changed_callback( const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) { 67 68 switch (key) { 69 case WEATHER_ICON_KEY: 70 load_bitmap(WEATHER_ICONS[new_tuple->value->uint8]); 71 bitmap_layer_set_bitmap( &s_data.icon_layer, &s_data.icon_bitmap.bmp ); 72 break; 73 74 case WEATHER_TEMPERATURE_KEY: 75 text_layer_set_text( &s_data.temperature_layer, new_tuple->value->cstring ); 76 break; 77 78 default: 79 return; 80 } 81 } Pebble
65 // Tuple changed 66 static void sync_tuple_changed_callback( const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) { 67 68 switch (key) { 69 case WEATHER_ICON_KEY: 70 load_bitmap(WEATHER_ICONS[new_tuple->value->uint8]); 71 bitmap_layer_set_bitmap( &s_data.icon_layer, &s_data.icon_bitmap.bmp ); 72 break; 73 74 case WEATHER_TEMPERATURE_KEY: 75 text_layer_set_text( &s_data.temperature_layer, new_tuple->value->cstring ); 76 break; 77 78 default: 79 return; 80 } 81 } Pebble
65 // Tuple changed 66 static void sync_tuple_changed_callback( const uint32_t key, const Tuple* new_tuple, const Tuple* old_tuple, void* context) { 67 68 switch (key) { 69 case WEATHER_ICON_KEY: 70 load_bitmap(WEATHER_ICONS[new_tuple->value->uint8]); 71 bitmap_layer_set_bitmap( &s_data.icon_layer, &s_data.icon_bitmap.bmp ); 72 break; 73 74 case WEATHER_TEMPERATURE_KEY: 75 text_layer_set_text( &s_data.temperature_layer, new_tuple->value->cstring ); 76 break; 77 78 default: 79 return; 80 } 81 } Pebble
☑ What is the Pebble☑ Why you should develop for the Pebble☑ How to develop for the Pebble
Agenda
Questions?
matthewmorey.com | @xzolian
CreditsPicturesPebble, Pebble Forums, Pebble SubReddit, iFixIt, Wired, Verge, Lifehacker, BBC, MyPebbleFaces, Kickstarter, indiegogo, Wikipedia