├── bun.lockb ├── modules └── live-activities │ ├── app.plugin.js │ ├── expo-module.config.json │ ├── plugin │ └── withLiveActivities.js │ ├── ios │ ├── Attributes.swift │ ├── ExpoLiveActivities.podspec │ ├── ExpoLiveActivitiesAppDelegate.swift │ └── ExpoLiveActivities.swift │ ├── src │ ├── LiveActivities.types.ts │ ├── LiveActivitiesModule.ios.ts │ └── LiveActivitiesModule.ts │ └── index.ts ├── assets ├── icon.png ├── favicon.png ├── splash-icon.png └── adaptive-icon.png ├── targets └── widgets │ ├── Assets.xcassets │ ├── Contents.json │ ├── Airple.imageset │ │ ├── Airple.png │ │ └── Contents.json │ ├── Car_side.imageset │ │ ├── Car.png │ │ └── Contents.json │ ├── Airple_light.imageset │ │ ├── Airple_light.png │ │ └── Contents.json │ ├── Car.imageset │ │ ├── Airple Customer Mobile Top.png │ │ └── Contents.json │ ├── Location.imageset │ │ ├── Airple Customer App Location.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Color.colorset │ │ └── Contents.json │ ├── expo-target.config.js │ ├── Info.plist │ ├── Attributes.swift │ ├── index.swift │ ├── PrivacyInfo.xcprivacy │ └── AirpleWidget.swift ├── tsconfig.json ├── index.ts ├── .gitignore ├── package.json ├── app.json ├── App.tsx └── README.md /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/bun.lockb -------------------------------------------------------------------------------- /modules/live-activities/app.plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./plugin/withLiveActivities"); 2 | -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/assets/favicon.png -------------------------------------------------------------------------------- /assets/splash-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/assets/splash-icon.png -------------------------------------------------------------------------------- /assets/adaptive-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/assets/adaptive-icon.png -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Airple.imageset/Airple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/targets/widgets/Assets.xcassets/Airple.imageset/Airple.png -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Car_side.imageset/Car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/targets/widgets/Assets.xcassets/Car_side.imageset/Car.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "expo/tsconfig.base", 3 | "compilerOptions": { 4 | "strict": true, 5 | "paths": { 6 | "@local:*": ["./modules/*"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Airple_light.imageset/Airple_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/targets/widgets/Assets.xcassets/Airple_light.imageset/Airple_light.png -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Car.imageset/Airple Customer Mobile Top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/targets/widgets/Assets.xcassets/Car.imageset/Airple Customer Mobile Top.png -------------------------------------------------------------------------------- /modules/live-activities/expo-module.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "platforms": ["apple"], 3 | "apple": { 4 | "modules": ["ExpoLiveActivities"], 5 | "appDelegateSubscribers": ["ExpoLiveActivitiesAppDelegate"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Location.imageset/Airple Customer App Location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrevanzak/expo-live-activities-demo/HEAD/targets/widgets/Assets.xcassets/Location.imageset/Airple Customer App Location.png -------------------------------------------------------------------------------- /targets/widgets/expo-target.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */ 2 | module.exports = { 3 | type: "widget", 4 | name: "Live Activity", 5 | frameworks: ["SwiftUI", "ActivityKit"], 6 | deploymentTarget: "16.2", 7 | }; 8 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import { registerRootComponent } from 'expo'; 2 | 3 | import App from './App'; 4 | 5 | // registerRootComponent calls AppRegistry.registerComponent('main', () => App); 6 | // It also ensures that whether you load the app in Expo Go or in a native build, 7 | // the environment is set up appropriately 8 | registerRootComponent(App); 9 | -------------------------------------------------------------------------------- /targets/widgets/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.widgetkit-extension 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Airple.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Airple.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Car_side.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Car.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Airple_light.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Airple_light.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Car.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Airple Customer Mobile Top.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Location.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Airple Customer App Location.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /modules/live-activities/plugin/withLiveActivities.js: -------------------------------------------------------------------------------- 1 | const { withInfoPlist } = require("@expo/config-plugins"); 2 | 3 | /** 4 | * @type {import('@expo/config-plugins').ConfigPlugin<{ frequentUpdates?: boolean }>} 5 | */ 6 | const withLiveActivities = (config, { frequentUpdates = false }) => 7 | withInfoPlist(config, (config) => { 8 | config.modResults.NSSupportsLiveActivities = true; 9 | config.modResults.NSSupportsLiveActivitiesFrequentUpdates = frequentUpdates; 10 | return config; 11 | }); 12 | 13 | module.exports = withLiveActivities; 14 | -------------------------------------------------------------------------------- /targets/widgets/Attributes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AirpleAttributes.swift 3 | // Airple 4 | // 5 | // Created by Revanza on 2024-08-09. 6 | // 7 | 8 | import ActivityKit 9 | import SwiftUI 10 | 11 | struct AirpleAttributes: ActivityAttributes { 12 | public typealias AirpleStatus = ContentState 13 | 14 | public struct ContentState: Codable, Hashable { 15 | var progress: Double 16 | var title: String 17 | var status: String 18 | var estimated: String 19 | var widgetUrl: String? 20 | } 21 | 22 | var key: String 23 | } -------------------------------------------------------------------------------- /modules/live-activities/ios/Attributes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AirpleAttributes.swift 3 | // Airple 4 | // 5 | // Created by Revanza on 2024-08-09. 6 | // 7 | 8 | import ActivityKit 9 | import SwiftUI 10 | 11 | struct AirpleAttributes: ActivityAttributes { 12 | public typealias AirpleStatus = ContentState 13 | 14 | public struct ContentState: Codable, Hashable { 15 | var progress: Double 16 | var title: String 17 | var status: String 18 | var estimated: String 19 | var widgetUrl: String? 20 | } 21 | 22 | var key: String 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files 2 | 3 | # dependencies 4 | node_modules/ 5 | 6 | # Expo 7 | .expo/ 8 | dist/ 9 | web-build/ 10 | expo-env.d.ts 11 | 12 | # Native 13 | *.orig.* 14 | *.jks 15 | *.p8 16 | *.p12 17 | *.key 18 | *.mobileprovision 19 | 20 | # Metro 21 | .metro-health-check* 22 | 23 | # debug 24 | npm-debug.* 25 | yarn-debug.* 26 | yarn-error.* 27 | 28 | # macOS 29 | .DS_Store 30 | *.pem 31 | 32 | # local env files 33 | .env*.local 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | 38 | # native build 39 | android 40 | ios 41 | !/modules/**/ios 42 | -------------------------------------------------------------------------------- /targets/widgets/index.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import WidgetKit 3 | 4 | @main 5 | struct exportWidgets: WidgetBundle { 6 | var body: some Widget { 7 | if #available(iOSApplicationExtension 18.0, *) { 8 | return iOS18Widgets 9 | } else { 10 | return widgets 11 | } 12 | } 13 | 14 | @available(iOSApplicationExtension 18.0, *) 15 | @WidgetBundleBuilder 16 | private var iOS18Widgets: some Widget { 17 | AirpleWidgetIOS18() 18 | } 19 | 20 | @WidgetBundleBuilder 21 | private var widgets: some Widget { 22 | AirpleWidget() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /modules/live-activities/ios/ExpoLiveActivities.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'ExpoLiveActivities' 3 | s.version = '1.0.0' 4 | s.summary = 'Tracking Live Activity Module for Airple' 5 | s.description = 'Tracking Live Activity Module for Airple' 6 | s.author = 'mrevanzak' 7 | s.homepage = 'https://docs.expo.dev/modules/' 8 | s.platforms = { :ios => '13.4' } 9 | s.source = { git: '' } 10 | s.static_framework = true 11 | 12 | s.dependency 'ExpoModulesCore' 13 | 14 | # Swift/Objective-C compatibility 15 | s.pod_target_xcconfig = { 16 | 'DEFINES_MODULE' => 'YES', 17 | 'SWIFT_COMPILATION_MODE' => 'wholemodule', 18 | } 19 | 20 | s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}" 21 | end 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "expo-live-activities-demo", 3 | "version": "1.0.0", 4 | "main": "index.ts", 5 | "scripts": { 6 | "start": "expo start", 7 | "android": "expo run:android", 8 | "ios": "expo run:ios", 9 | "web": "expo start --web" 10 | }, 11 | "dependencies": { 12 | "@bacons/apple-targets": "^0.1.15", 13 | "expo": "~52.0.23", 14 | "expo-notifications": "^0.29.11", 15 | "expo-status-bar": "~2.0.0", 16 | "react": "18.3.1", 17 | "react-native": "0.76.5" 18 | }, 19 | "devDependencies": { 20 | "@babel/core": "^7.25.2", 21 | "@types/react": "~18.3.12", 22 | "typescript": "^5.3.3" 23 | }, 24 | "private": true, 25 | "expo": { 26 | "autolinking": { 27 | "nativeModulesDir": "./modules" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /modules/live-activities/src/LiveActivities.types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * state of the live activity 3 | * should be match with property on Attributes.swift 4 | * @see ios/Attributes.swift 5 | */ 6 | export interface LiveActivityState { 7 | progress: number; 8 | title: string; 9 | status: string; 10 | estimated: string; 11 | widgetUrl?: string; 12 | } 13 | 14 | export type LiveActivityFn = (key: string, state: LiveActivityState) => void; 15 | 16 | export interface onPushTokenChangePayload { 17 | token: string; 18 | } 19 | 20 | export type LiveActivitiesModuleEvent = { 21 | "LiveActivities.pushTokenDidChange": ( 22 | params: onPushTokenChangePayload & { key: string }, 23 | ) => void; 24 | "LiveActivities.startTokenDidChange": ( 25 | params: onPushTokenChangePayload, 26 | ) => void; 27 | }; 28 | -------------------------------------------------------------------------------- /targets/widgets/Assets.xcassets/Color.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "display-p3", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0xA1", 9 | "green" : "0x54", 10 | "red" : "0x19" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0xFF", 27 | "green" : "0xC2", 28 | "red" : "0x62" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /modules/live-activities/src/LiveActivitiesModule.ios.ts: -------------------------------------------------------------------------------- 1 | import { NativeModule, requireNativeModule } from "expo-modules-core"; 2 | import type { LiveActivitiesModuleEvent } from "./LiveActivities.types"; 3 | 4 | declare class ExpoLiveActivities extends NativeModule { 5 | areActivitiesEnabled(): boolean; 6 | startActivity( 7 | key: string, 8 | progress: number, 9 | title: string, 10 | status: string, 11 | estimated: string, 12 | widgetUrl?: string 13 | ): void; 14 | updateActivity( 15 | key: string, 16 | progress: number, 17 | title: string, 18 | status: string, 19 | estimated: string, 20 | widgetUrl?: string 21 | ): void; 22 | endActivity( 23 | key: string, 24 | progress: number, 25 | title: string, 26 | status: string, 27 | estimated: string, 28 | widgetUrl?: string 29 | ): void; 30 | } 31 | 32 | export default requireNativeModule("ExpoLiveActivities"); 33 | -------------------------------------------------------------------------------- /modules/live-activities/src/LiveActivitiesModule.ts: -------------------------------------------------------------------------------- 1 | import { NativeModule, requireNativeModule } from "expo-modules-core"; 2 | import type { LiveActivitiesModuleEvent } from "./LiveActivities.types"; 3 | 4 | class ExpoLiveActivities extends NativeModule { 5 | areActivitiesEnabled() { 6 | return false; 7 | } 8 | startActivity( 9 | _key: string, 10 | _progress: number, 11 | _title: string, 12 | _status: string, 13 | _estimated: string, 14 | _widgetUrl?: string 15 | ) { 16 | return; 17 | } 18 | updateActivity( 19 | _key: string, 20 | _progress: number, 21 | _title: string, 22 | _status: string, 23 | _estimated: string, 24 | _widgetUrl?: string 25 | ) { 26 | return; 27 | } 28 | endActivity( 29 | _key: string, 30 | _progress: number, 31 | _title: string, 32 | _status: string, 33 | _estimated: string, 34 | _widgetUrl?: string 35 | ) { 36 | return; 37 | } 38 | } 39 | 40 | export default requireNativeModule("LiveActivities"); 41 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "expo-live-activities-demo", 4 | "slug": "expo-live-activities-demo", 5 | "version": "1.0.0", 6 | "orientation": "portrait", 7 | "icon": "./assets/icon.png", 8 | "userInterfaceStyle": "light", 9 | "newArchEnabled": true, 10 | "splash": { 11 | "image": "./assets/splash-icon.png", 12 | "resizeMode": "contain", 13 | "backgroundColor": "#ffffff" 14 | }, 15 | "ios": { 16 | "supportsTablet": true, 17 | "bundleIdentifier": "com.mrevanzak.expo-live-activities-demo" 18 | }, 19 | "android": { 20 | "adaptiveIcon": { 21 | "foregroundImage": "./assets/adaptive-icon.png", 22 | "backgroundColor": "#ffffff" 23 | }, 24 | "package": "com.mrevanzak.expoliveactivitiesdemo" 25 | }, 26 | "web": { 27 | "favicon": "./assets/favicon.png" 28 | }, 29 | "plugins": [ 30 | "@bacons/apple-targets", 31 | [ 32 | "./modules/live-activities/app.plugin.js", 33 | { 34 | "frequentUpdates": true 35 | } 36 | ], 37 | [ 38 | "expo-notifications", 39 | { 40 | "enableBackgroundRemoteNotifications": true 41 | } 42 | ] 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /targets/widgets/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyAccessedAPITypes 6 | 7 | 8 | NSPrivacyAccessedAPIType 9 | NSPrivacyAccessedAPICategoryFileTimestamp 10 | NSPrivacyAccessedAPITypeReasons 11 | 12 | C617.1 13 | 0A2A.1 14 | 3B52.1 15 | 16 | 17 | 18 | NSPrivacyAccessedAPIType 19 | NSPrivacyAccessedAPICategoryUserDefaults 20 | NSPrivacyAccessedAPITypeReasons 21 | 22 | CA92.1 23 | 1C8F.1 24 | C56D.1 25 | 26 | 27 | 28 | NSPrivacyAccessedAPIType 29 | NSPrivacyAccessedAPICategorySystemBootTime 30 | NSPrivacyAccessedAPITypeReasons 31 | 32 | 35F9.1 33 | 34 | 35 | 36 | NSPrivacyAccessedAPIType 37 | NSPrivacyAccessedAPICategoryDiskSpace 38 | NSPrivacyAccessedAPITypeReasons 39 | 40 | E174.1 41 | 85F4.1 42 | 43 | 44 | 45 | NSPrivacyCollectedDataTypes 46 | 47 | NSPrivacyTracking 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /modules/live-activities/ios/ExpoLiveActivitiesAppDelegate.swift: -------------------------------------------------------------------------------- 1 | import ActivityKit 2 | import ExpoModulesCore 3 | 4 | public class ExpoLiveActivitiesAppDelegate: ExpoAppDelegateSubscriber { 5 | public func application( 6 | _ application: UIApplication, 7 | didFinishLaunchingWithOptions launchOptions: [UIApplication 8 | .LaunchOptionsKey: Any]? = nil 9 | ) -> Bool { 10 | if #available(iOS 17.2, *) { 11 | Task { 12 | for await pushToken in Activity 13 | .pushToStartTokenUpdates 14 | { 15 | let pushTokenString = pushToken.reduce("") { 16 | $0 + String(format: "%02x", $1) 17 | } 18 | NotificationCenter.default.post( 19 | name: .onStartPushTokenChange, object: pushTokenString) 20 | } 21 | } 22 | } 23 | 24 | if #available(iOS 17.2, *) { 25 | Task { 26 | for await activity in Activity.activityUpdates 27 | { 28 | Task { 29 | for await pushToken in activity.pushTokenUpdates { 30 | let pushTokenString = pushToken.reduce("") { 31 | $0 + String(format: "%02x", $1) 32 | } 33 | NotificationCenter.default.post( 34 | name: .onPushTokenChange, 35 | object: pushTokenString, 36 | userInfo: ["key": activity.attributes.key] 37 | ) 38 | } 39 | } 40 | } 41 | } 42 | } 43 | return true 44 | } 45 | } 46 | 47 | extension Notification.Name { 48 | static var onStartPushTokenChange: Notification.Name { 49 | return .init("LiveActivities.onStartPushTokenChange") 50 | } 51 | static var onPushTokenChange: Notification.Name { 52 | return .init("LiveActivities.onPushTokenChange") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /App.tsx: -------------------------------------------------------------------------------- 1 | import { StatusBar } from "expo-status-bar"; 2 | import { Button, StyleSheet, Text, View } from "react-native"; 3 | 4 | import * as LiveActivities from "@local:live-activities"; 5 | import { useState } from "react"; 6 | 7 | export default function App() { 8 | const [token, setToken] = useState(); 9 | const [startToken, setStartToken] = useState(); 10 | 11 | LiveActivities.useLiveActivitiesSetup(({ token }) => { 12 | setStartToken(token); 13 | }); 14 | 15 | LiveActivities.useGetPushToken(({ token }) => { 16 | setToken(token); 17 | }); 18 | 19 | return ( 20 | 21 | 22 | 23 | Token: {token} 24 | Start Token: {startToken} 25 |