mirror of
https://github.com/google/pebble.git
synced 2025-03-22 03:32:20 +00:00
290 lines
10 KiB
Markdown
290 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.
|