expo-callkit-telecom 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +197 -0
- package/android/build.gradle +32 -0
- package/android/src/main/AndroidManifest.xml +33 -0
- package/android/src/main/java/expo/modules/callkittelecom/ExpoCallKitTelecomModule.kt +384 -0
- package/android/src/main/java/expo/modules/callkittelecom/IncomingCallActivity.kt +275 -0
- package/android/src/main/java/expo/modules/callkittelecom/events/CallEventEmitter.kt +151 -0
- package/android/src/main/java/expo/modules/callkittelecom/events/CallEvents.kt +59 -0
- package/android/src/main/java/expo/modules/callkittelecom/managers/CallAudioManager.kt +361 -0
- package/android/src/main/java/expo/modules/callkittelecom/managers/CallManager.kt +891 -0
- package/android/src/main/java/expo/modules/callkittelecom/managers/CallNotificationManager.kt +445 -0
- package/android/src/main/java/expo/modules/callkittelecom/managers/CaptureSessionManager.kt +27 -0
- package/android/src/main/java/expo/modules/callkittelecom/managers/DialtonePlayer.kt +171 -0
- package/android/src/main/java/expo/modules/callkittelecom/managers/FulfillRequestManager.kt +150 -0
- package/android/src/main/java/expo/modules/callkittelecom/managers/VoIPPushManager.kt +54 -0
- package/android/src/main/java/expo/modules/callkittelecom/models/CallModels.kt +269 -0
- package/android/src/main/java/expo/modules/callkittelecom/services/CallNotificationReceiver.kt +54 -0
- package/android/src/main/java/expo/modules/callkittelecom/services/ExpoCallKitTelecomMessagingService.kt +161 -0
- package/android/src/main/java/expo/modules/callkittelecom/store/CallStore.kt +181 -0
- package/android/src/main/java/expo/modules/callkittelecom/utils/CallKitTelecomLog.kt +52 -0
- package/android/src/main/java/expo/modules/callkittelecom/utils/PermissionUtils.kt +28 -0
- package/android/src/main/res/drawable/expo_callkit_telecom_bg_answer.xml +9 -0
- package/android/src/main/res/drawable/expo_callkit_telecom_bg_avatar.xml +5 -0
- package/android/src/main/res/drawable/expo_callkit_telecom_bg_decline.xml +9 -0
- package/android/src/main/res/drawable/expo_callkit_telecom_ic_answer.xml +9 -0
- package/android/src/main/res/drawable/expo_callkit_telecom_ic_decline.xml +9 -0
- package/android/src/main/res/drawable/expo_callkit_telecom_ic_videocam.xml +9 -0
- package/android/src/main/res/layout/activity_incoming_call.xml +169 -0
- package/app.json +8 -0
- package/app.plugin.js +1 -0
- package/build/Calls.d.ts +577 -0
- package/build/Calls.d.ts.map +1 -0
- package/build/Calls.js +715 -0
- package/build/Calls.js.map +1 -0
- package/build/Calls.types.d.ts +203 -0
- package/build/Calls.types.d.ts.map +1 -0
- package/build/Calls.types.js +2 -0
- package/build/Calls.types.js.map +1 -0
- package/build/ExpoCallKitTelecomModule.d.ts +3 -0
- package/build/ExpoCallKitTelecomModule.d.ts.map +1 -0
- package/build/ExpoCallKitTelecomModule.js +4 -0
- package/build/ExpoCallKitTelecomModule.js.map +1 -0
- package/build/hooks/index.d.ts +2 -0
- package/build/hooks/index.d.ts.map +1 -0
- package/build/hooks/index.js +2 -0
- package/build/hooks/index.js.map +1 -0
- package/build/hooks/useVoIPPushToken.d.ts +14 -0
- package/build/hooks/useVoIPPushToken.d.ts.map +1 -0
- package/build/hooks/useVoIPPushToken.js +26 -0
- package/build/hooks/useVoIPPushToken.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +4 -0
- package/build/index.js.map +1 -0
- package/expo-module.config.json +10 -0
- package/ios/AppDelegateSubscriber.swift +93 -0
- package/ios/ExpoCallKitTelecom.podspec +31 -0
- package/ios/ExpoCallKitTelecomLogger.swift +55 -0
- package/ios/ExpoCallKitTelecomModule.swift +503 -0
- package/ios/Managers/AudioManager.swift +363 -0
- package/ios/Managers/CallEventEmitter.swift +199 -0
- package/ios/Managers/CallManager+CXProviderDelegate.swift +195 -0
- package/ios/Managers/CallManager.swift +714 -0
- package/ios/Managers/CaptureSessionManager.swift +54 -0
- package/ios/Managers/DialtonePlayer.swift +126 -0
- package/ios/Managers/FulfillRequestManager.swift +154 -0
- package/ios/Managers/VoIPPushManager+PKPushRegistryDelegate.swift +123 -0
- package/ios/Managers/VoIPPushManager.swift +58 -0
- package/ios/Models/CallEvents.swift +263 -0
- package/ios/Models/CallOptions.swift +15 -0
- package/ios/Models/CallParticipant.swift +37 -0
- package/ios/Models/CallSession.swift +80 -0
- package/ios/Models/IncomingCallEvent.swift +196 -0
- package/ios/Stores/CallStore.swift +149 -0
- package/package.json +56 -0
- package/plugin/build/constants.d.ts +3 -0
- package/plugin/build/constants.js +7 -0
- package/plugin/build/withExpoCallKitTelecom.d.ts +67 -0
- package/plugin/build/withExpoCallKitTelecom.js +16 -0
- package/plugin/build/withExpoCallKitTelecomAndroid.d.ts +3 -0
- package/plugin/build/withExpoCallKitTelecomAndroid.js +177 -0
- package/plugin/build/withExpoCallKitTelecomIos.d.ts +3 -0
- package/plugin/build/withExpoCallKitTelecomIos.js +195 -0
- package/plugin/src/constants.ts +4 -0
- package/plugin/src/withExpoCallKitTelecom.ts +83 -0
- package/plugin/src/withExpoCallKitTelecomAndroid.ts +293 -0
- package/plugin/src/withExpoCallKitTelecomIos.ts +276 -0
- package/src/Calls.ts +848 -0
- package/src/Calls.types.ts +275 -0
- package/src/ExpoCallKitTelecomModule.ts +4 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useVoIPPushToken.ts +34 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type of VoIP push token reported by `getVoIPPushToken`.
|
|
3
|
+
*
|
|
4
|
+
* - `"APNS_VOIP"` — Apple Push Notification service VoIP channel (iOS)
|
|
5
|
+
* - `"FCM"` — Firebase Cloud Messaging (Android)
|
|
6
|
+
*/
|
|
7
|
+
export type PushTokenType = "APNS_VOIP" | "FCM";
|
|
8
|
+
|
|
9
|
+
// Native Event Metadata
|
|
10
|
+
|
|
11
|
+
/** Metadata attached to all native events */
|
|
12
|
+
export interface NativeEventMeta {
|
|
13
|
+
/** Whether the event was flushed from queue (true) or sent in real-time (false) */
|
|
14
|
+
flushed: boolean;
|
|
15
|
+
/** ISO8601 timestamp of when the event was created */
|
|
16
|
+
timestamp: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Base type for all native events with metadata */
|
|
20
|
+
export interface NativeEvent {
|
|
21
|
+
meta: NativeEventMeta;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Call Session
|
|
25
|
+
export interface CallSession {
|
|
26
|
+
id: string;
|
|
27
|
+
options: CallOptions;
|
|
28
|
+
origin: CallSessionOrigin;
|
|
29
|
+
remoteParticipants: CallParticipant[];
|
|
30
|
+
incomingCallEvent?: IncomingCallEvent;
|
|
31
|
+
status: CallSessionStatus;
|
|
32
|
+
connectedAt?: string;
|
|
33
|
+
isMuted: boolean;
|
|
34
|
+
isOnHold: boolean;
|
|
35
|
+
dtmfDigits?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface CallOptions {
|
|
39
|
+
hasVideo: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type CallSessionOrigin = "incoming" | "outgoingApp" | "outgoingSystem";
|
|
43
|
+
|
|
44
|
+
export interface CallParticipant {
|
|
45
|
+
/** Opaque, stable app identifier for this participant. */
|
|
46
|
+
id: string;
|
|
47
|
+
/** Display name. */
|
|
48
|
+
displayName?: string;
|
|
49
|
+
/** Avatar URL. */
|
|
50
|
+
avatarUrl?: string;
|
|
51
|
+
/** Phone number in E.164 (e.g. "+14155551234"). When present on iOS, the
|
|
52
|
+
* CallKit handle is set to this number, enabling Recents and Siri. */
|
|
53
|
+
phoneNumber?: string;
|
|
54
|
+
/** Email address. */
|
|
55
|
+
email?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Call session status representing the lifecycle of a call.
|
|
60
|
+
*
|
|
61
|
+
* Outgoing call flow: requesting → connecting → connected → ended
|
|
62
|
+
* Incoming call flow: ringing → connecting → connected → ended
|
|
63
|
+
*
|
|
64
|
+
* - `requesting` — Outgoing only. The call request has been submitted to
|
|
65
|
+
* CallKit/Telecom and is awaiting system acceptance.
|
|
66
|
+
* - `ringing` — Incoming only. The call has been reported to CallKit/Telecom
|
|
67
|
+
* and the user sees the native incoming call UI or notification.
|
|
68
|
+
* - `connecting` — Both directions. For outgoing calls, the system accepted the
|
|
69
|
+
* call and the dialtone is playing while waiting for the remote party to answer.
|
|
70
|
+
* For incoming calls, the user answered and media is being established.
|
|
71
|
+
* - `connected` — Both directions. Media is flowing and the call is active.
|
|
72
|
+
* - `ended` — Both directions. Transient state during teardown before the
|
|
73
|
+
* session is removed from the store.
|
|
74
|
+
*/
|
|
75
|
+
export type CallSessionStatus =
|
|
76
|
+
| "requesting"
|
|
77
|
+
| "connecting"
|
|
78
|
+
| "ringing"
|
|
79
|
+
| "connected"
|
|
80
|
+
| "ended";
|
|
81
|
+
|
|
82
|
+
// Call Session events
|
|
83
|
+
export interface CallSessionAddedEvent extends NativeEvent {
|
|
84
|
+
session: CallSession;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface CallSessionUpdatedEvent extends NativeEvent {
|
|
88
|
+
session: CallSession;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface CallSessionRemovedEvent extends NativeEvent {
|
|
92
|
+
id: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Microphone/Camera Permission Status
|
|
96
|
+
export type PermissionStatus =
|
|
97
|
+
| "granted"
|
|
98
|
+
| "denied"
|
|
99
|
+
| "undetermined"
|
|
100
|
+
| "restricted"
|
|
101
|
+
| "unknown";
|
|
102
|
+
|
|
103
|
+
// Audio Session
|
|
104
|
+
|
|
105
|
+
export interface AudioSession {
|
|
106
|
+
isActive: boolean;
|
|
107
|
+
/** iOS only: whether the WebRTC RTCAudioSession is active. */
|
|
108
|
+
rtcSessionIsActive?: boolean;
|
|
109
|
+
/** iOS only: whether the AVAudioSession is active. */
|
|
110
|
+
avSessionIsActive?: boolean;
|
|
111
|
+
/** iOS only: whether the RTCAudioSession audio track is enabled. */
|
|
112
|
+
isAudioEnabled?: boolean;
|
|
113
|
+
/** iOS only: whether manual audio mode is enabled on RTCAudioSession. */
|
|
114
|
+
useManualAudio?: boolean;
|
|
115
|
+
isOtherAudioPlaying: boolean;
|
|
116
|
+
category: string;
|
|
117
|
+
mode: string;
|
|
118
|
+
/** iOS only: AVAudioSession category options. */
|
|
119
|
+
categoryOptions?: string[];
|
|
120
|
+
sampleRate: number;
|
|
121
|
+
ioBufferDuration: number;
|
|
122
|
+
inputNumberOfChannels: number;
|
|
123
|
+
outputNumberOfChannels: number;
|
|
124
|
+
microphonePermission: PermissionStatus;
|
|
125
|
+
currentRoute: AudioRoute;
|
|
126
|
+
/** Available audio output devices. Populated on Android; undefined on iOS. */
|
|
127
|
+
availableRoutes?: AudioPort[];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface AudioRoute {
|
|
131
|
+
inputs: AudioPort[];
|
|
132
|
+
outputs: AudioPort[];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface AudioPort {
|
|
136
|
+
portType: AudioOutputPortType;
|
|
137
|
+
portName: string;
|
|
138
|
+
uid: string;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Cross-platform audio output port type identifiers.
|
|
143
|
+
* Both iOS and Android map their native audio device types to these shared values.
|
|
144
|
+
*/
|
|
145
|
+
export type AudioOutputPortType =
|
|
146
|
+
| "builtInReceiver" // Earpiece
|
|
147
|
+
| "builtInSpeaker" // Speaker
|
|
148
|
+
| "headphones" // Wired headphones
|
|
149
|
+
| "bluetoothA2DP" // Bluetooth A2DP audio
|
|
150
|
+
| "bluetoothLE" // Bluetooth Low Energy audio
|
|
151
|
+
| "bluetoothHFP" // Bluetooth Hands-Free Profile
|
|
152
|
+
| "airPlay" // AirPlay
|
|
153
|
+
| "hdmi" // HDMI output
|
|
154
|
+
| "carAudio" // CarPlay
|
|
155
|
+
| "usbAudio" // USB audio
|
|
156
|
+
| "lineOut" // Line out
|
|
157
|
+
| (string & {}); // Allow other unknown port types
|
|
158
|
+
|
|
159
|
+
// Audio Session Events
|
|
160
|
+
export interface AudioSessionCallInfo {
|
|
161
|
+
id: string;
|
|
162
|
+
status: CallSessionStatus;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface AudioSessionActivatedEvent extends NativeEvent {
|
|
166
|
+
calls: AudioSessionCallInfo[];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface AudioSessionDeactivatedEvent extends NativeEvent {
|
|
170
|
+
calls: AudioSessionCallInfo[];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface AudioRouteChangedEvent extends NativeEvent {
|
|
174
|
+
currentRoute: AudioRoute;
|
|
175
|
+
/** Available audio output devices. Populated on Android; undefined on iOS. */
|
|
176
|
+
availableRoutes?: AudioPort[];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Capture Session
|
|
180
|
+
export interface CaptureSession {
|
|
181
|
+
cameraPermission: PermissionStatus;
|
|
182
|
+
/** Whether the device supports multitasking camera access (iOS 16+). */
|
|
183
|
+
isMultitaskingCameraAccessSupported?: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Call Action events
|
|
187
|
+
export interface CallActionEvent extends NativeEvent {
|
|
188
|
+
id: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface OutgoingCallStartedEvent extends CallActionEvent {}
|
|
192
|
+
|
|
193
|
+
export interface IncomingCallEvent {
|
|
194
|
+
/** Unique event identifier (UUID). Used for dedup. */
|
|
195
|
+
eventId: string;
|
|
196
|
+
/** Your backend's id for this call. Distinct from {@link CallSession.id},
|
|
197
|
+
* which is the OS-assigned native call UUID. Use this id to talk to your
|
|
198
|
+
* server about the call (e.g. POST /calls/:serverCallId/answer). */
|
|
199
|
+
serverCallId: string;
|
|
200
|
+
/** True for video calls, false for audio. */
|
|
201
|
+
hasVideo: boolean;
|
|
202
|
+
/** RFC 3339 timestamp of when the call was placed. Optional; defaults to now. */
|
|
203
|
+
startedAt?: string;
|
|
204
|
+
/** Caller identity and addressing. */
|
|
205
|
+
caller: CallParticipant;
|
|
206
|
+
/**
|
|
207
|
+
* App-defined extra fields, forwarded verbatim from the push payload.
|
|
208
|
+
*
|
|
209
|
+
* The library treats this as opaque — put whatever your app needs here
|
|
210
|
+
* (chatId, tenantId, room name, etc.). Cast to your own type at the
|
|
211
|
+
* read site.
|
|
212
|
+
*/
|
|
213
|
+
metadata?: Record<string, unknown>;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface IncomingCallReportedEvent extends CallActionEvent {}
|
|
217
|
+
|
|
218
|
+
export interface CallAnsweredEvent extends CallActionEvent {
|
|
219
|
+
requestId: string;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface CallEndedEvent extends CallActionEvent {}
|
|
223
|
+
|
|
224
|
+
export type CallEndedReason =
|
|
225
|
+
| "failed"
|
|
226
|
+
| "remoteEnded"
|
|
227
|
+
| "unanswered"
|
|
228
|
+
| "answeredElsewhere"
|
|
229
|
+
| "declinedElsewhere"
|
|
230
|
+
| "unknown";
|
|
231
|
+
|
|
232
|
+
export interface CallReportedEnded extends CallActionEvent {
|
|
233
|
+
reason: CallEndedReason;
|
|
234
|
+
}
|
|
235
|
+
export interface SetMutedActionEvent extends CallActionEvent {
|
|
236
|
+
isMuted: boolean;
|
|
237
|
+
}
|
|
238
|
+
export interface VideoChangedEvent extends CallActionEvent {
|
|
239
|
+
hasVideo: boolean;
|
|
240
|
+
}
|
|
241
|
+
export interface SetHeldActionEvent extends CallActionEvent {
|
|
242
|
+
isOnHold: boolean;
|
|
243
|
+
}
|
|
244
|
+
export interface DTMFEvent extends CallActionEvent {
|
|
245
|
+
digits: string;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Call Intent Events
|
|
249
|
+
|
|
250
|
+
export type CallIntentHandleType = "phoneNumber" | "email" | "unknown";
|
|
251
|
+
|
|
252
|
+
export interface CallIntentReceivedEvent extends NativeEvent {
|
|
253
|
+
handle: string;
|
|
254
|
+
handleType: CallIntentHandleType;
|
|
255
|
+
hasVideo: boolean;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// VoIP Push
|
|
259
|
+
|
|
260
|
+
/** A VoIP push token bundled with its type. */
|
|
261
|
+
export interface VoIPPushToken {
|
|
262
|
+
/** The VoIP push token string. */
|
|
263
|
+
token: string;
|
|
264
|
+
/** The type of token this platform provides. */
|
|
265
|
+
type: PushTokenType;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// VoIP Push Events
|
|
269
|
+
|
|
270
|
+
export interface VoIPPushTokenUpdatedEvent extends NativeEvent {
|
|
271
|
+
/** The VoIP push token string, or undefined if invalidated */
|
|
272
|
+
token?: string;
|
|
273
|
+
/** The type of VoIP push token (e.g. "APNS_VOIP", "FCM"). */
|
|
274
|
+
type: PushTokenType;
|
|
275
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./useVoIPPushToken";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { addVoIPPushTokenUpdatedListener, getVoIPPushToken } from "../Calls";
|
|
4
|
+
import type { PushTokenType, VoIPPushToken } from "../Calls.types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Hook that returns the current VoIP push token and subscribes to updates.
|
|
8
|
+
*
|
|
9
|
+
* Reads the initial token synchronously and re-renders whenever the native
|
|
10
|
+
* `onVoIPPushTokenUpdated` event fires (e.g. when the OS provides a new token
|
|
11
|
+
* or invalidates the existing one).
|
|
12
|
+
*
|
|
13
|
+
* On iOS this returns an APNs VoIP token; on Android it returns an FCM token.
|
|
14
|
+
*
|
|
15
|
+
* @returns The current token, or `null` if not yet available.
|
|
16
|
+
*/
|
|
17
|
+
export function useVoIPPushToken(): VoIPPushToken | null {
|
|
18
|
+
const [token, setToken] = useState<VoIPPushToken | null>(() =>
|
|
19
|
+
getVoIPPushToken(),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
const subscription = addVoIPPushTokenUpdatedListener((event) => {
|
|
24
|
+
setToken(
|
|
25
|
+
event.token
|
|
26
|
+
? { token: event.token, type: event.type as PushTokenType }
|
|
27
|
+
: null,
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
return () => subscription.remove();
|
|
31
|
+
}, []);
|
|
32
|
+
|
|
33
|
+
return token;
|
|
34
|
+
}
|
package/src/index.ts
ADDED