npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rn-live-activities

v0.1.0

Published

Cross-platform Live Activities for React Native: iOS ActivityKit and Android 16 Live Updates, driven by local calls or push events

Readme

rn-live-activities

Live Activities for React Native on both platforms with one API:

  • iOS 16.2+: ActivityKit Live Activities on the lock screen and in the Dynamic Island
  • Android 16+: promoted Live Updates (status-bar chip, lock screen, top of the shade); older Android versions get a regular ongoing notification

Activities update the same way on both: locally from JS, or by push from your server while the app is backgrounded or killed (APNs on iOS, FCM on Android).

const activity = await startActivity({
  id: 'order-1042',
  template: 'progress',
  tintColor: '#FF6B00',
  state: { title: 'Order #1042', status: 'Preparing', progress: 0.2, progressLabel: '25 min' },
});

await updateActivity('order-1042', { title: 'Order #1042', status: 'On the way', progress: 0.7, progressLabel: '8 min' });
await endActivity('order-1042', { title: 'Order #1042', status: 'Delivered', progress: 1 });

Status: early development (v0.1). The API may still change.

Installation

npm install rn-live-activities

Expo (development builds)

{
  "expo": {
    "ios": { "bundleIdentifier": "com.example.app" },
    "plugins": [["rn-live-activities", { "apsEnvironment": "development" }]]
  }
}

Then npx expo prebuild. The plugin adds the widget extension, NSSupportsLiveActivities and the push entitlement. Options:

| Option | Default | | |---|---|---| | apsEnvironment | "development" | "production" for release builds, or false to manage the entitlement yourself | | frequentUpdates | false | Sets NSSupportsLiveActivitiesFrequentUpdates |

Expo Go is not supported, because the library ships native code.

Bare React Native

npx rn-live-activities-setup-ios --bundle-id com.example.app
cd ios && pod install

This adds a LiveActivitiesWidget extension target to your Xcode project and enables NSSupportsLiveActivities. It is safe to re-run after upgrading, since it refreshes the library's widget sources. LiveActivitiesWidget/LiveActivitiesWidgetBundle.swift belongs to you; add your own widgets there. For push updates, enable the Push Notifications capability on the app target.

Android needs no setup. The manifest entries (POST_NOTIFICATIONS, POST_PROMOTED_NOTIFICATIONS) merge in automatically.

Templates

| Template | Uses | iOS | Android 16 | |---|---|---|---| | progress | progress (0–1), progressLabel | Progress bar; circular progress when minimal | ProgressStyle bar, label in the status chip | | status | status, subtitle | Status on the trailing side | Status in the chip, subtitle as big text | | countdown | endsAt (epoch ms) | Live timer | Chronometer counting down |

Every template uses title, subtitle, status, icon and tintColor. icon is an SF Symbol name on iOS and a drawable resource name on Android; if it's missing, the app icon is used.

API

requestPermission(): Promise<boolean>        // Android 13+ asks for POST_NOTIFICATIONS
areActivitiesEnabled(): Promise<boolean>

startActivity(options): Promise<LiveActivity>
updateActivity(id, state, { alert?, staleDate?, relevanceScore? }): Promise<void>
endActivity(id, finalState?, { dismissal?: 'default' | 'immediate' | Date | number }): Promise<void>
endAllActivities(): Promise<void>
getActivities(): Promise<LiveActivity[]>

addActivityStateListener(({ activityId, state }) => …)   // active | ended | dismissed | stale
addPushTokenListener(({ activityId, token }) => …)       // iOS, per activity
addPushToStartTokenListener((token) => …)                // iOS 17.2+
getPushToStartToken(): Promise<string | null>            // iOS 17.2+

handlePushMessage(remoteMessage.data): Promise<boolean>  // Android, from JS

Updates replace the whole state, the same way ActivityKit content-state works, so always send every field you want shown.

Push updates

Both platforms use the same state object. Only the transport differs.

iOS (APNs)

  1. Start with enablePushUpdates: true and send the token from addPushTokenListener to your server.
  2. Send to APNs with apns-push-type: liveactivity and apns-topic: <bundle-id>.push-type.liveactivity:
{
  "aps": {
    "timestamp": 1761120000,
    "event": "update",
    "content-state": {
      "title": "Order #1042",
      "status": "On the way",
      "progress": 0.7,
      "progressLabel": "8 min"
    }
  }
}

Use "event": "end" (optionally with "dismissal-date") to end the activity. To start one by push (iOS 17.2+), send to the push-to-start token with "event": "start", "attributes-type": "LiveActivityAttributes" and "attributes": { "activityId": "order-1042", "template": "progress", "tintColor": "#FF6B00" }.

Android (FCM)

Send a data-only message (no notification block). Its liveactivity field holds the same event as a JSON string:

{
  "message": {
    "token": "<fcm device token>",
    "android": { "priority": "high" },
    "data": {
      "liveactivity": "{\"event\":\"update\",\"activityId\":\"order-1042\",\"timestamp\":1761120000,\"state\":{\"title\":\"Order #1042\",\"status\":\"On the way\",\"progress\":0.7,\"progressLabel\":\"8 min\"}}"
    }
  }
}

event is start (which also takes template and tintColor), update or end (which takes an optional dismissalDate in seconds). As on iOS, timestamp is used to drop out-of-order deliveries.

Hand the message to the library from your FirebaseMessagingService. This applies the update without starting the JS runtime:

override fun onMessageReceived(message: RemoteMessage) {
  if (LiveActivitiesPush.handleMessage(this, message.data)) return
  // ...your other messages
}

If you use @react-native-firebase/messaging, you can call handlePushMessage(message.data) from setBackgroundMessageHandler and onMessage instead.

How it works

| | iOS | Android | |---|---|---| | Rendering | SwiftUI ActivityConfiguration in a widget extension | Notification with setRequestPromotedOngoing and ProgressStyle | | State | Owned by ActivityKit | Persisted in SharedPreferences, so FCM updates work with the app cold | | Push transport | APNs, applied by the OS | FCM data message, applied by LiveActivitiesPush | | User dismissal | dismissed state | Swipe → dismissed state (via the delete intent) |

Contributing

License

MIT