@cliffhelsel/capacitor-live-activity
Version:
A Capacitor plugin for managing iOS Live Activities using ActivityKit and Swift.
376 lines (248 loc) • 14.4 kB
Markdown
# 📡 capacitor-live-activity
[](https://www.npmjs.com/package/capacitor-live-activity)
[](https://bundlephobia.com/result?p=capacitor-live-activity)
[](./LICENSE)
[](#-platform-behavior)
[](https://capacitorjs.com/)
A Capacitor plugin for managing iOS Live Activities using ActivityKit and Swift.
> [!TIP]
> 🚀 Looking for a ready-to-run demo? → [Try the Example App](./example-app/)
## 🧭 Table of contents
- [🧭 Table of contents](#-table-of-contents)
- [📦 Install](#-install)
- [🧩 Widget Setup (Required)](#-widget-setup-required)
- [1. Add a Widget Extension in Xcode](#1-add-a-widget-extension-in-xcode)
- [2. Configure the Widget (Example)](#2-configure-the-widget-example)
- [3. Add GenericAttributes.swift to your Widget Target](#3-add-genericattributesswift-to-your-widget-target)
- [To make it available in your widget extension:](#to-make-it-available-in-your-widget-extension)
- [Why is this needed?](#why-is-this-needed)
- [4. Add Capability](#4-add-capability)
- [5. Ensure Inclusion in Build](#5-ensure-inclusion-in-build)
- [📱 Example App](#-example-app)
- [🛠 API](#-api)
## 📦 Install
```bash
npm install capacitor-live-activity
npx cap sync
```
> [!NOTE]
> This plugin requires **iOS 16.2+** to work properly due to `ActivityKit` API usage.
> [!IMPORTANT]
> This plugin **requires a Live Activity widget extension** to be present and configured in your Xcode project.
> Without a widget, Live Activities will not appear on the lock screen or Dynamic Island.
## 🧩 Widget Setup (Required)
To use Live Activities, your app must include a widget extension that defines the UI for the Live Activity using ActivityKit. Without this, the Live Activity will not appear on the Lock Screen or Dynamic Island.
### 1. Add a Widget Extension in Xcode
1. Open your app’s iOS project in Xcode.
2. Go to File > New > Target…
3. Choose Widget Extension.
4. Name it e.g. LiveActivityWidget.
5. Check the box “Include Live Activity”.
6. Finish and wait for Xcode to generate the files.
### 2. Configure the Widget (Example)
Make sure the widget uses the same attribute type as the plugin (e.g. GenericAttributes.swift):
```swift
import ActivityKit
import WidgetKit
import SwiftUI
struct LiveActivityWidgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: GenericAttributes.self) { context in
// Lock Screen UI
VStack {
Text(context.state.values["title"] ?? "⏱")
Text(context.state.values["status"] ?? "-")
}
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
Text(context.state.values["title"] ?? "")
}
DynamicIslandExpandedRegion(.trailing) {
Text(context.state.values["status"] ?? "")
}
DynamicIslandExpandedRegion(.bottom) {
Text(context.state.values["message"] ?? "")
}
} compactLeading: {
Text("🔔")
} compactTrailing: {
Text(context.state.values["status"] ?? "")
} minimal: {
Text("🎯")
}
}
}
}
```
### 3. Add GenericAttributes.swift to your Widget Target
To support Live Activities with dynamic values, this plugin uses a shared Swift struct called GenericAttributes.
> By default, it’s located under: Pods > CapacitorLiveActivity > LiveActivityPlugin > Shared > GenericAttributes.swift
#### To make it available in your widget extension:
1. Open Xcode and go to the File Navigator.
2. Expand Pods > CapacitorLiveActivity > Shared.
3. Copy GenericAttributes.swift to Widget Extension Target, e.g. LiveActivityWidget
4. Make sure to select "Copy files to destination"
#### Why is this needed?
Xcode doesn’t automatically include files from a CocoaPods plugin into your widget target.
Without this step, your widget won’t compile because it cannot find GenericAttributes.
### 4. Add Capability
Go to your main app target → Signing & Capabilities tab and add:
- Background Modes → Background fetch
### 5. Ensure Inclusion in Build
- In your **App target’s Info.plist**, ensure:
```xml
<key>NSSupportsLiveActivities</key>
<true/>
```
- Clean and rebuild the project (Cmd + Shift + K, then Cmd + B).
## 📱 Example App
This plugin includes a fully functional demo app under the [`example-app/`](./example-app) directory.
The demo is designed to run on real iOS devices and showcases multiple Live Activity types like delivery, timer, taxi, workout, and more.
- Launch and test various Live Activities interactively
- Trigger updates and alert banners
- View JSON state changes in a live log console
> [!NOTE]
> For full instructions, see [example-app/README.md](./example-app/README.md)
## 🛠 API
<docgen-index>
* [`startActivity(...)`](#startactivity)
* [`startObservingPushToStartToken()`](#startobservingpushtostarttoken)
* [`addListener('pushToStartToken', ...)`](#addlistenerpushtostarttoken-)
* [`updateActivity(...)`](#updateactivity)
* [`endActivity(...)`](#endactivity)
* [`isAvailable()`](#isavailable)
* [`isRunning(...)`](#isrunning)
* [`getCurrentActivity(...)`](#getcurrentactivity)
* [Interfaces](#interfaces)
* [Type Aliases](#type-aliases)
</docgen-index>
<docgen-api>
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
### startActivity(...)
```typescript
startActivity(options: StartActivityOptions) => Promise<void>
```
Starts a new Live Activity on iOS using the provided options.
| Param | Type |
| ------------- | --------------------------------------------------------------------- |
| **`options`** | <code><a href="#startactivityoptions">StartActivityOptions</a></code> |
**Since:** 0.0.1
--------------------
### startObservingPushToStartToken()
```typescript
startObservingPushToStartToken() => Promise<void>
```
--------------------
### addListener('pushToStartToken', ...)
```typescript
addListener(eventName: 'pushToStartToken', listenerFunc: (data: { token: string; }) => void) => Promise<PluginListenerHandle>
```
| Param | Type |
| ------------------ | -------------------------------------------------- |
| **`eventName`** | <code>'pushToStartToken'</code> |
| **`listenerFunc`** | <code>(data: { token: string; }) => void</code> |
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
--------------------
### updateActivity(...)
```typescript
updateActivity(options: UpdateActivityOptions) => Promise<void>
```
Updates the currently active Live Activity.
| Param | Type |
| ------------- | ----------------------------------------------------------------------- |
| **`options`** | <code><a href="#updateactivityoptions">UpdateActivityOptions</a></code> |
**Since:** 0.0.1
--------------------
### endActivity(...)
```typescript
endActivity(options: EndActivityOptions) => Promise<void>
```
Ends the Live Activity and optionally provides a final state and dismissal policy.
| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| **`options`** | <code><a href="#endactivityoptions">EndActivityOptions</a></code> |
**Since:** 0.0.1
--------------------
### isAvailable()
```typescript
isAvailable() => Promise<boolean>
```
Returns whether Live Activities are available on this device and allowed by the user.
**Returns:** <code>Promise<boolean></code>
**Since:** 0.0.1
--------------------
### isRunning(...)
```typescript
isRunning(options: { id: string; }) => Promise<boolean>
```
Returns true if a Live Activity with the given ID is currently running.
| Param | Type |
| ------------- | ---------------------------- |
| **`options`** | <code>{ id: string; }</code> |
**Returns:** <code>Promise<boolean></code>
**Since:** 0.0.1
--------------------
### getCurrentActivity(...)
```typescript
getCurrentActivity(options?: { id?: string | undefined; } | undefined) => Promise<LiveActivityState | undefined>
```
Returns the current active Live Activity state, if any.
If an ID is provided, returns that specific activity.
If no ID is given, returns the most recently started activity.
| Param | Type |
| ------------- | ----------------------------- |
| **`options`** | <code>{ id?: string; }</code> |
**Returns:** <code>Promise<<a href="#liveactivitystate">LiveActivityState</a>></code>
**Since:** 0.0.1
--------------------
### Interfaces
#### StartActivityOptions
Options for starting a Live Activity.
| Prop | Type | Description |
| ------------------ | --------------------------------------------------------------- | --------------------------------------------------------- |
| **`id`** | <code>string</code> | Unique ID to identify the Live Activity. |
| **`attributes`** | <code><a href="#record">Record</a><string, string></code> | Immutable attributes that are part of the Live Activity. |
| **`contentState`** | <code><a href="#record">Record</a><string, string></code> | Initial content state (dynamic values). |
| **`timestamp`** | <code>number</code> | Optional timestamp (Unix) when the Live Activity started. |
#### PluginListenerHandle
| Prop | Type |
| ------------ | ----------------------------------------- |
| **`remove`** | <code>() => Promise<void></code> |
#### UpdateActivityOptions
Options for updating a Live Activity.
| Prop | Type | Description |
| ------------------ | ----------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| **`id`** | <code>string</code> | ID of the Live Activity to update. |
| **`contentState`** | <code><a href="#record">Record</a><string, string></code> | Updated content state (dynamic values). |
| **`alert`** | <code><a href="#alertconfiguration">AlertConfiguration</a></code> | Optional alert configuration to show a notification banner or Apple Watch alert. |
| **`timestamp`** | <code>number</code> | Optional timestamp (Unix) when the update occurred. |
#### AlertConfiguration
Configuration for alert notifications.
| Prop | Type | Description |
| ----------- | ------------------- | -------------------------------------- |
| **`title`** | <code>string</code> | Optional title of the alert. |
| **`body`** | <code>string</code> | Optional body text of the alert. |
| **`sound`** | <code>string</code> | Optional sound file name or "default". |
#### EndActivityOptions
Options for ending a Live Activity.
| Prop | Type | Description |
| ------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| **`id`** | <code>string</code> | ID of the Live Activity to end. |
| **`contentState`** | <code><a href="#record">Record</a><string, string></code> | Final state to show before dismissal. |
| **`timestamp`** | <code>number</code> | Optional timestamp (Unix) when the end occurred. |
| **`dismissalDate`** | <code>number</code> | Optional dismissal time in the future (Unix). If not provided, system default applies. |
#### LiveActivityState
Represents an active Live Activity state.
| Prop | Type | Description |
| --------------- | --------------------------------------------------------------- | ----------------------------------------------- |
| **`id`** | <code>string</code> | The unique identifier of the activity. |
| **`values`** | <code><a href="#record">Record</a><string, string></code> | The current dynamic values of the activity. |
| **`isStale`** | <code>boolean</code> | Whether the activity is stale. |
| **`isEnded`** | <code>boolean</code> | Whether the activity has ended. |
| **`startedAt`** | <code>string</code> | ISO string timestamp when the activity started. |
### Type Aliases
#### Record
Construct a type with a set of properties K of type T
<code>{
[P in K]: T;
}</code>
</docgen-api>