mirror of
https://github.com/google/pebble.git
synced 2025-03-23 04:02:19 +00:00
289 lines
10 KiB
Markdown
289 lines
10 KiB
Markdown
---
|
||
# Copyright 2025 Google LLC
|
||
#
|
||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
# you may not use this file except in compliance with the License.
|
||
# You may obtain a copy of the License at
|
||
#
|
||
# http://www.apache.org/licenses/LICENSE-2.0
|
||
#
|
||
# Unless required by applicable law or agreed to in writing, software
|
||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
# See the License for the specific language governing permissions and
|
||
# limitations under the License.
|
||
|
||
title: PebbleKit iOS
|
||
description: How to use PebbleKit to communicate with a watchapp on iOS.
|
||
guide_group: communication
|
||
order: 3
|
||
---
|
||
|
||
[PebbleKit iOS](https://github.com/pebble/pebble-ios-sdk/) is an Objective-C
|
||
framework that works with the Pebble SDK and can be embedded in any iOS
|
||
application for **iOS 7.1** and above. Using the classes and methods in this
|
||
framework, an iOS app can find and exchange data with a Pebble watch.
|
||
|
||
This section assumes that the reader has a basic knowledge of Objective-C, Xcode
|
||
as an IDE, and the delegate and block patterns.
|
||
|
||
> PebbleKit iOS should be compatible if your app uses Swift. The framework
|
||
> itself is written in Objective-C to avoid the requirement of the Swift runtime
|
||
> in pure Objective-C apps, and to improve the backwards and forwards
|
||
> compatibility.
|
||
|
||
### Setting Up PebbleKit iOS
|
||
|
||
If the project is using [CocoaPods](http://cocoapods.org/) (which is the
|
||
recommended approach), just add `pod 'PebbleKit'` to the `Podfile` and execute
|
||
`pod install`.
|
||
|
||
After installing PebbleKit iOS in the project, perform these final steps:
|
||
|
||
* If the iOS app needs to run in the background, you should update your target’s
|
||
“Capabilities” in Xcode. Enable “Background Modes” and select both “Uses
|
||
Bluetooth LE accessories” and “Acts as a Bluetooth LE accessory”. This should
|
||
add the keys `bluetooth-peripheral` (“App shares data using CoreBluetooth”)
|
||
and `bluetooth-central` (“App communicates using CoreBluetooth”) to your
|
||
target’s `Info.plist` file.
|
||
* If you are using Xcode 8 or greater (and recommended for previous versions),
|
||
you must also add the key `NSBluetoothPeripheralUsageDescription` (“Privacy -
|
||
Bluetooth Peripheral Usage Description”) to your `Info.plist`.
|
||
|
||
> To add PebbleKit iOS manually, or some other alternatives follow the steps in
|
||
> the [repository](https://github.com/pebble/pebble-ios-sdk/). The documentation
|
||
> might also include more information that might be useful. Read it carefully.
|
||
|
||
### Targeting a Companion App
|
||
|
||
Before an iOS companion app can start communicating or exchange messages with a
|
||
watchapp on Pebble, it needs to give PebbleKit a way to identify the watchapp.
|
||
The UUID of your watchapp is used for this purpose.
|
||
|
||
Set the app UUID associated with the PBPebbleCentral instance. A simple way to
|
||
create a UUID in standard representation to `NSUUID` is shown here:
|
||
|
||
```objective-c
|
||
// Set UUID of watchapp
|
||
NSUUID *myAppUUID =
|
||
[[NSUUID alloc] initWithUUIDString:@"226834ae-786e-4302-a52f-6e7efc9f990b"];
|
||
[PBPebbleCentral defaultCentral].appUUID = myAppUUID;
|
||
```
|
||
|
||
If you are trying to communicate with the built-in Sports or Golf apps, their
|
||
UUID are available as part of PebbleKit with ``PBSportsUUID`` and
|
||
``PBGolfUUID``. You must register those UUID if you intend to communicate with
|
||
those apps.
|
||
|
||
### Becoming a Delegate
|
||
|
||
To communicate with a Pebble watch, the class must implement
|
||
`PBPebbleCentralDelegate`:
|
||
|
||
```objective-c
|
||
@interface ViewController () <PBPebbleCentralDelegate>
|
||
```
|
||
|
||
The `PBPebbleCentral` class should not be instantiated directly. Instead, always
|
||
use the singleton provided by `[PBPebbleCentral defaultCentral]`. An example is
|
||
shown below, with the Golf app UUID:
|
||
|
||
```objective-c
|
||
central = [PBPebbleCentral defaultCentral];
|
||
central.appUUID = myAppUUID;
|
||
[central run];
|
||
```
|
||
|
||
Once this is done, set the class to be the delegate:
|
||
|
||
```objective-c
|
||
[PBPebbleCentral defaultCentral].delegate = self;
|
||
```
|
||
|
||
This delegate will get two callbacks: `pebbleCentral:watchDidConnect:isNew:` and
|
||
`pebbleCentral:watchDidDisconnect:` every time a Pebble connects or disconnects.
|
||
The app won't get connection callbacks if the Pebble is already connected when
|
||
the delegate is set.
|
||
|
||
Implement these to receive the associated connection/disconnection events:
|
||
|
||
```objective-c
|
||
- (void)pebbleCentral:(PBPebbleCentral *)central watchDidConnect:(PBWatch *)watch isNew:(BOOL)isNew {
|
||
NSLog(@"Pebble connected: %@", watch.name);
|
||
|
||
// Keep a reference to this watch
|
||
self.connectedWatch = watch;
|
||
}
|
||
|
||
- (void)pebbleCentral:(PBPebbleCentral *)central watchDidDisconnect:(PBWatch *)watch {
|
||
NSLog(@"Pebble disconnected: %@", watch.name);
|
||
|
||
// If this was the recently connected watch, forget it
|
||
if ([watch isEqual:self.connectedWatch]) {
|
||
self.connectedWatch = nil;
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
### Initiating Bluetooth Communication
|
||
|
||
Once the iOS app is correctly set up to communicate with Pebble, the final step
|
||
is to actually begin communication. No communication can take place until the
|
||
following is called:
|
||
|
||
```objective-c
|
||
[[PBPebbleCentral defaultCentral] run];
|
||
```
|
||
|
||
> Once this occurs, the user _may_ be shown a dialog asking for confirmation
|
||
> that they want the app to communicate. This means the app should not call
|
||
> `run:` until the appropriate moment in the UI.
|
||
|
||
|
||
### Sending Messages from iOS
|
||
|
||
Since iOS apps are built separately from their companion Pebble apps, there is
|
||
no way for the build system to automatically create matching app message keys.
|
||
You must therefore manually specify them in `package.json`, like so:
|
||
|
||
```js
|
||
{
|
||
"Temperature": 0,
|
||
"WindSpeed": 1,
|
||
"WindDirection": 2,
|
||
"RequestData": 3,
|
||
"LocationName": 4
|
||
}
|
||
```
|
||
|
||
These numeric values can then be used as app message keys in your iOS app.
|
||
|
||
|
||
Messages are constructed with the `NSDictionary` class and sent to the C
|
||
watchapp or watchface by the `PBPebbleCentralDelegate` when the
|
||
`appMessagesPushUpdate:` function is invoked.
|
||
|
||
To send a message, prepare an `NSDictionary` object with the data to be sent to
|
||
the C watchapp. Data items are added to the
|
||
[`NSDictionary`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/)
|
||
using key-value pairs of standard data types. An example containing a string and
|
||
an integer is shown below:
|
||
|
||
```objective-c
|
||
NSDictionary *update = @{ @(0):[NSNumber pb_numberWithUint8:42],
|
||
@(1):@"a string" };
|
||
```
|
||
|
||
Send this dictionary to the watchapp using `appMessagesPushUpdate:`. The first
|
||
argument is the update dictionary to send and the second argument is a callback
|
||
block that will be invoked when the data has been acknowledged by the watch (or
|
||
if an error occurs).
|
||
|
||
```objective-c
|
||
[self.connectedWatch appMessagesPushUpdate:update onSent:^(PBWatch *watch, NSDictionary *update, NSError *error) {
|
||
if (!error) {
|
||
NSLog(@"Successfully sent message.");
|
||
} else {
|
||
NSLog(@"Error sending message: %@", error);
|
||
}
|
||
}];
|
||
```
|
||
|
||
Once delivered, this dictionary will be available in the C app via the
|
||
``AppMessageInboxReceived`` callback, as detailed in
|
||
{% guide_link communication/sending-and-receiving-data#inbox-received %}.
|
||
|
||
|
||
### Receiving Messages on iOS
|
||
|
||
To receive messages from a watchapp, register a receive handler (a block)
|
||
with `appMessagesAddReceiveUpdateHandler:`. This block will be invoked with two
|
||
parameters - a pointer to a `PBWatch` object describing the Pebble that sent the
|
||
message and an `NSDictionary` with the message received.
|
||
|
||
```objective-c
|
||
[self.connectedWatch appMessagesAddReceiveUpdateHandler:^BOOL(PBWatch *watch, NSDictionary *update) {
|
||
NSLog(@"Received message: %@", update);
|
||
|
||
// Send Ack to Pebble
|
||
return YES;
|
||
}];
|
||
```
|
||
|
||
> Always return `YES` in the handler. This instructs PebbleKit to automatically
|
||
> send an ACK to Pebble, to avoid the message timing out.
|
||
|
||
Data can be read from the `NSDictionary` by first testing for each key's
|
||
presence using a `!= nil` check, and reading the value if it is present:
|
||
|
||
```objective-c
|
||
NSNumber *key = @1;
|
||
|
||
// If the key is present in the received dictionary
|
||
if (update[key]) {
|
||
// Read the integer value
|
||
int value = [update[key] intValue];
|
||
}
|
||
```
|
||
|
||
|
||
### Other Capabilities
|
||
|
||
In addition to sending and receiving messages, PebbleKit iOS also allows
|
||
more intricate interactions with Pebble. See the
|
||
[PebbleKit iOS Documentation](/docs/pebblekit-ios/)
|
||
for more information. Some examples are shown below of what is possible:
|
||
|
||
* Checking if the watch is connected using the `connected` property of a
|
||
`PBWatch`.
|
||
|
||
```objective-c
|
||
BOOL isConnected = self.watch.connected;
|
||
```
|
||
|
||
* Receiving `watchDidConnect` and `watchDidDisconnect` events through being a
|
||
`PBDataloggingServiceDelegate`.
|
||
|
||
|
||
### Limitations of PebbleKit on iOS
|
||
|
||
The iOS platform imposes some restrictions on what apps can do with accessories.
|
||
It also limits the capabilities of apps that are in the background. It is
|
||
critical to understand these limitations when developing an app that relies on
|
||
PebbleKit iOS.
|
||
|
||
On iOS, all communication between a mobile app and Pebble is managed through a
|
||
communication session. This communication session is a protocol specific to iOS,
|
||
with notable limitations that the reader should know and understand when
|
||
developing an iOS companion app for Pebble.
|
||
|
||
|
||
#### Bluetooth Low Energy (BLE) Connections
|
||
|
||
For Pebble apps that communicate with Pebble in BLE mode, a session can be
|
||
created for each app that requires one. This removes the 'one session only'
|
||
restriction, but only for these BLE apps. Currently, there are several
|
||
BLE only devices, such as Pebble Time Round, and Pebble 2, but all the devices
|
||
using a firmware 3.8 or greater can use BLE to communicate with PebbleKit.
|
||
|
||
For BLE apps, the 'phone must launch' restriction is removed. The iOS
|
||
companion app can be restarted by the watchapp if it stops working if user
|
||
force-quits iOS app, or it crashes. Note that the app will not work after
|
||
rebooting iOS device, which requires it be launched by the iPhone user once
|
||
after boot.
|
||
|
||
|
||
#### Communication with firmware older than 3.0
|
||
|
||
PebbleKit iOS 3.1.1 is the last PebbleKit that supports communication with
|
||
firmwares older than 3.0. PebbleKit iOS 4.0.0 can only communicate with Pebble
|
||
devices with firmware newer than 3.0.
|
||
|
||
For newer devices like Pebble Time, Pebble Time Steel, Pebble Time Round, and
|
||
Pebble 2 there should be no problem. For previous generation devices like Pebble
|
||
and Pebble Steel it means that their users should upgrade their firmware to the
|
||
latest firmware available for their devices using the new apps.
|
||
|
||
This change allows better compatibility and new features to be developed by 3rd
|
||
parties.
|