@capgo/capacitor-stream-call 7.4.0 → 7.7.7
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/README.md +20 -2
- package/android/build.gradle +2 -2
- package/android/src/main/java/ee/forgr/capacitor/streamcall/StreamCallPlugin.kt +19 -8
- package/dist/docs.json +19 -0
- package/dist/esm/definitions.d.ts +9 -0
- package/dist/esm/definitions.js.map +1 -1
- package/ios/Sources/StreamCallPlugin/StreamCallPlugin.swift +35 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
<a href="https://capgo.app/"><img src='https://raw.githubusercontent.com/Cap-go/capgo/main/assets/capgo_banner.png' alt='Capgo - Instant updates for capacitor'/></a>
|
|
3
3
|
|
|
4
4
|
<div align="center">
|
|
5
|
-
<h2><a href="https://capgo.app/?ref=
|
|
6
|
-
<h2><a href="https://capgo.app/consulting/?ref=
|
|
5
|
+
<h2><a href="https://capgo.app/?ref=plugin_streamcall"> ➡️ Get Instant updates for your App with Capgo</a></h2>
|
|
6
|
+
<h2><a href="https://capgo.app/consulting/?ref=plugin_streamcall"> Missing a feature? We’ll build the plugin for you 💪</a></h2>
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
9
|
A Capacitor plugin that uses the [Stream Video SDK](https://getstream.io/) to enable video calling functionality in your app.
|
|
10
10
|
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
The most complete doc is available here: https://capgo.app/docs/plugins/streamcall/
|
|
14
|
+
|
|
11
15
|
## Installation
|
|
12
16
|
|
|
13
17
|
```bash
|
|
@@ -259,6 +263,7 @@ export class CallService {
|
|
|
259
263
|
* [`setDynamicStreamVideoApikey(...)`](#setdynamicstreamvideoapikey)
|
|
260
264
|
* [`getDynamicStreamVideoApikey()`](#getdynamicstreamvideoapikey)
|
|
261
265
|
* [`getCurrentUser()`](#getcurrentuser)
|
|
266
|
+
* [`getPluginVersion()`](#getpluginversion)
|
|
262
267
|
* [Interfaces](#interfaces)
|
|
263
268
|
* [Type Aliases](#type-aliases)
|
|
264
269
|
* [Enums](#enums)
|
|
@@ -612,6 +617,19 @@ Get the current user's information
|
|
|
612
617
|
--------------------
|
|
613
618
|
|
|
614
619
|
|
|
620
|
+
### getPluginVersion()
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
getPluginVersion() => Promise<{ version: string; }>
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
Get the native Capacitor plugin version
|
|
627
|
+
|
|
628
|
+
**Returns:** <code>Promise<{ version: string; }></code>
|
|
629
|
+
|
|
630
|
+
--------------------
|
|
631
|
+
|
|
632
|
+
|
|
615
633
|
### Interfaces
|
|
616
634
|
|
|
617
635
|
|
package/android/build.gradle
CHANGED
|
@@ -77,8 +77,8 @@ dependencies {
|
|
|
77
77
|
|
|
78
78
|
|
|
79
79
|
// Stream dependencies
|
|
80
|
-
implementation("io.getstream:stream-video-android-ui-compose:1.
|
|
81
|
-
implementation("io.getstream:stream-video-android-core:1.
|
|
80
|
+
implementation("io.getstream:stream-video-android-ui-compose:1.16.0")
|
|
81
|
+
implementation("io.getstream:stream-video-android-core:1.16.0")
|
|
82
82
|
implementation("io.getstream:stream-android-push:1.3.2")
|
|
83
83
|
implementation("io.getstream:stream-android-push-firebase:1.3.2")
|
|
84
84
|
|
|
@@ -107,6 +107,7 @@ import kotlinx.coroutines.flow.collectLatest
|
|
|
107
107
|
// It's a spaghetti-like, tangled, unreadable mess and frankly, I am deeply sorry for the code crimes commited in the Android impl
|
|
108
108
|
@CapacitorPlugin(name = "StreamCall")
|
|
109
109
|
class StreamCallPlugin : Plugin() {
|
|
110
|
+
private val pluginVersion = "7.7.4"
|
|
110
111
|
private var streamVideoClient: StreamVideo? = null
|
|
111
112
|
private var state: State = State.NOT_INITIALIZED
|
|
112
113
|
private var overlayView: ComposeView? = null
|
|
@@ -265,6 +266,7 @@ class StreamCallPlugin : Plugin() {
|
|
|
265
266
|
if (action === "io.getstream.video.android.action.INCOMING_CALL") {
|
|
266
267
|
Log.d("StreamCallPlugin", "handleOnNewIntent: Matched INCOMING_CALL action")
|
|
267
268
|
// We need to make sure the activity is visible on locked screen in such case
|
|
269
|
+
bringAppToForeground()
|
|
268
270
|
changeActivityAsVisibleOnLockScreen(this@StreamCallPlugin.activity, true)
|
|
269
271
|
activity?.runOnUiThread {
|
|
270
272
|
val cid = intent.streamCallId(NotificationHandler.INTENT_EXTRA_CALL_CID)
|
|
@@ -275,6 +277,12 @@ class StreamCallPlugin : Plugin() {
|
|
|
275
277
|
val call = streamVideoClient?.call(id = cid.id, type = cid.type)
|
|
276
278
|
Log.d("StreamCallPlugin", "handleOnNewIntent: INCOMING_CALL - Got call object: ${call?.id}")
|
|
277
279
|
|
|
280
|
+
val preview = JSObject().apply {
|
|
281
|
+
put("cid", cid.cid)
|
|
282
|
+
put("type", "incoming")
|
|
283
|
+
}
|
|
284
|
+
notifyListeners("incomingCall", preview, true)
|
|
285
|
+
|
|
278
286
|
// Try to get caller information from the call
|
|
279
287
|
kotlinx.coroutines.GlobalScope.launch {
|
|
280
288
|
try {
|
|
@@ -301,9 +309,6 @@ class StreamCallPlugin : Plugin() {
|
|
|
301
309
|
|
|
302
310
|
// Notify WebView/JS about incoming call so it can render its own UI
|
|
303
311
|
notifyListeners("incomingCall", payload, true)
|
|
304
|
-
// Delay bringing app to foreground to allow the event to be processed first
|
|
305
|
-
kotlinx.coroutines.delay(500) // 500ms delay
|
|
306
|
-
bringAppToForeground()
|
|
307
312
|
} catch (e: Exception) {
|
|
308
313
|
Log.e("StreamCallPlugin", "Error getting call info for incoming call", e)
|
|
309
314
|
// Fallback to basic payload without caller info
|
|
@@ -313,9 +318,6 @@ class StreamCallPlugin : Plugin() {
|
|
|
313
318
|
}
|
|
314
319
|
notifyListeners("incomingCall", payload, true)
|
|
315
320
|
ringingCallId = cid.cid;
|
|
316
|
-
// Delay bringing app to foreground to allow the event to be processed first
|
|
317
|
-
kotlinx.coroutines.delay(500) // 500ms delay
|
|
318
|
-
bringAppToForeground()
|
|
319
321
|
}
|
|
320
322
|
}
|
|
321
323
|
} else {
|
|
@@ -1370,8 +1372,6 @@ class StreamCallPlugin : Plugin() {
|
|
|
1370
1372
|
updateCallStatusAndNotify(call.cid, "joined")
|
|
1371
1373
|
CallUIController.layoutType.value = LayoutType.GRID
|
|
1372
1374
|
ringingCallId = ""
|
|
1373
|
-
// Make sure activity is visible on lock screen
|
|
1374
|
-
changeActivityAsVisibleOnLockScreen(this@StreamCallPlugin.activity, true)
|
|
1375
1375
|
|
|
1376
1376
|
cameraStatusJob?.cancel()
|
|
1377
1377
|
microphoneStatusJob?.cancel()
|
|
@@ -3256,4 +3256,15 @@ class StreamCallPlugin : Plugin() {
|
|
|
3256
3256
|
false
|
|
3257
3257
|
}
|
|
3258
3258
|
}
|
|
3259
|
+
|
|
3260
|
+
@PluginMethod
|
|
3261
|
+
fun getPluginVersion(call: PluginCall) {
|
|
3262
|
+
try {
|
|
3263
|
+
val ret = JSObject()
|
|
3264
|
+
ret.put("version", pluginVersion)
|
|
3265
|
+
call.resolve(ret)
|
|
3266
|
+
} catch (e: Exception) {
|
|
3267
|
+
call.reject("Could not get plugin version", e)
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3259
3270
|
}
|
package/dist/docs.json
CHANGED
|
@@ -598,6 +598,25 @@
|
|
|
598
598
|
"CurrentUserResponse"
|
|
599
599
|
],
|
|
600
600
|
"slug": "getcurrentuser"
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
"name": "getPluginVersion",
|
|
604
|
+
"signature": "() => Promise<{ version: string; }>",
|
|
605
|
+
"parameters": [],
|
|
606
|
+
"returns": "Promise<{ version: string; }>",
|
|
607
|
+
"tags": [
|
|
608
|
+
{
|
|
609
|
+
"name": "returns",
|
|
610
|
+
"text": "an Promise with version for this device"
|
|
611
|
+
},
|
|
612
|
+
{
|
|
613
|
+
"name": "throws",
|
|
614
|
+
"text": "An error if the something went wrong"
|
|
615
|
+
}
|
|
616
|
+
],
|
|
617
|
+
"docs": "Get the native Capacitor plugin version",
|
|
618
|
+
"complexTypes": [],
|
|
619
|
+
"slug": "getpluginversion"
|
|
601
620
|
}
|
|
602
621
|
],
|
|
603
622
|
"properties": []
|
|
@@ -369,6 +369,15 @@ export interface StreamCallPlugin {
|
|
|
369
369
|
* console.log(currentUser);
|
|
370
370
|
*/
|
|
371
371
|
getCurrentUser(): Promise<CurrentUserResponse>;
|
|
372
|
+
/**
|
|
373
|
+
* Get the native Capacitor plugin version
|
|
374
|
+
*
|
|
375
|
+
* @returns {Promise<{ id: string }>} an Promise with version for this device
|
|
376
|
+
* @throws An error if the something went wrong
|
|
377
|
+
*/
|
|
378
|
+
getPluginVersion(): Promise<{
|
|
379
|
+
version: string;
|
|
380
|
+
}>;
|
|
372
381
|
}
|
|
373
382
|
/**
|
|
374
383
|
* @interface IncomingCallPayload
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @interface LoginOptions\n * @description Configuration options for logging into the Stream Video service\n * @property {string} token - Stream Video API token for authentication\n * @property {string} userId - Unique identifier for the current user\n * @property {string} name - Display name for the current user\n * @property {string} [imageURL] - Avatar URL for the current user\n * @property {string} apiKey - Stream Video API key for your application\n * @property {string} [magicDivId] - DOM element ID where video will be rendered\n */\nexport interface LoginOptions {\n /** Stream Video API token */\n token: string;\n /** User ID for the current user */\n userId: string;\n /** Display name for the current user */\n name: string;\n /** Optional avatar URL for the current user */\n imageURL?: string;\n /** Stream Video API key */\n apiKey: string;\n /** ID of the HTML element where the video will be rendered */\n magicDivId?: string;\n pushNotificationsConfig?: PushNotificationsConfig;\n}\n\nexport interface PushNotificationsConfig {\n pushProviderName: string;\n voipProviderName: string;\n}\n\n/**\n * @typedef CallState\n * @description Represents all possible call states from API and UI\n */\nexport type CallState =\n // User-facing states\n | 'idle'\n | 'ringing'\n | 'joining'\n | 'reconnecting'\n | 'joined'\n | 'leaving'\n | 'left'\n // Event-specific states\n | 'created'\n | 'session_started'\n | 'rejected'\n | 'participant_counts'\n | 'missed'\n | 'accepted'\n | 'ended'\n | 'camera_enabled'\n | 'camera_disabled'\n | 'speaker_enabled'\n | 'speaker_disabled'\n | 'microphone_enabled'\n | 'microphone_disabled'\n | 'outgoing_call_ended'\n | 'unknown';\n\n/**\n * @typedef CallType\n * @description Represents the pre-defined types of a call.\n * - `default`: Simple 1-1 or group video calling with sensible defaults. Video/audio enabled, backstage disabled. Admins/hosts have elevated permissions.\n * - `audio_room`: For audio-only spaces (like Clubhouse). Backstage enabled (requires `goLive`), pre-configured permissions for requesting to speak.\n * - `livestream`: For one-to-many streaming. Backstage enabled (requires `goLive`), access granted to all authenticated users.\n * - `development`: For testing ONLY. All permissions enabled, backstage disabled. **Not recommended for production.**\n */\nexport type CallType = 'default' | 'audio' | 'audio_room' | 'livestream' | 'development';\n\n/**\n * @typedef StreamCallLayout\n * @description Layout modes matching the Stream React SDK; includes native aliases.\n */\nexport type StreamCallLayout = 'grid' | 'spotlight' | 'dynamic' | 'fullScreen' | 'fullscreen';\n\n/**\n * @interface CallMember\n * @description Information about a call member/participant\n * @property {string} userId - User ID of the member\n * @property {string} [name] - Display name of the user\n * @property {string} [imageURL] - Profile image URL of the user\n * @property {string} [role] - Role of the user in the call\n */\nexport interface CallMember {\n /** User ID of the member */\n userId: string;\n /** Display name of the user */\n name?: string;\n /** Profile image URL of the user */\n imageURL?: string;\n /** Role of the user in the call */\n role?: string;\n}\n\n/**\n * @interface CallEvent\n * @description Event emitted when call state changes\n * @property {string} callId - Unique identifier of the call\n * @property {CallState} state - Current state of the call\n * @property {string} [userId] - User ID of the participant who triggered the event\n * @property {string} [reason] - Reason for the call state change\n * @property {CallMember} [caller] - Information about the caller (for incoming calls)\n * @property {CallMember[]} [members] - List of call members\n */\nexport interface CallEvent {\n /** ID of the call */\n callId: string;\n /** Current state of the call */\n state: CallState;\n /** User ID of the participant in the call who triggered the event */\n userId?: string;\n /** Reason for the call state change, if applicable */\n reason?: string;\n /** Information about the caller (for incoming calls) */\n caller?: CallMember;\n /** List of call members */\n members?: CallMember[];\n\n custom?: Record<\n string,\n | string\n | boolean\n | number\n | null\n | Record<string, string | boolean | number | null>\n | string[]\n | boolean[]\n | number[]\n >;\n\n count?: number;\n}\n\nexport interface CameraEnabledResponse {\n enabled: boolean;\n}\n\n/**\n * @interface DynamicApiKeyResponse\n * @description Response from getDynamicStreamVideoApikey\n * @property {string|null} apiKey - The dynamic API key if set, null if not\n * @property {boolean} hasDynamicKey - Whether a dynamic key is currently set\n */\nexport interface DynamicApiKeyResponse {\n /** The dynamic API key if set, null if not */\n apiKey: string | null;\n /** Whether a dynamic key is currently set */\n hasDynamicKey: boolean;\n}\n\n/**\n * @interface CurrentUserResponse\n * @description Response from getCurrentUser containing user information\n * @property {string} userId - User ID of the current user\n * @property {string} name - Display name of the current user\n * @property {string} [imageURL] - Avatar URL of the current user\n * @property {boolean} isLoggedIn - Whether the user is currently logged in\n */\nexport interface CurrentUserResponse {\n /** User ID of the current user */\n userId: string;\n /** Display name of the current user */\n name: string;\n /** Avatar URL of the current user */\n imageURL?: string;\n /** Whether the user is currently logged in */\n isLoggedIn: boolean;\n}\n\n/**\n * @interface SuccessResponse\n * @description Standard response indicating operation success/failure\n * @property {boolean} success - Whether the operation succeeded\n */\nexport interface SuccessResponse {\n /** Whether the operation was successful */\n success: boolean;\n callId?: string;\n}\n\n/**\n * @interface CallOptions\n * @description Options for initiating a video call\n * @property {string[]} userIds - IDs of the users to call\n * @property {CallType} [type=default] - Type of call\n * @property {boolean} [ring=true] - Whether to send ring notification\n * @property {string} [team] - Team name to call\n */\nexport interface CallOptions {\n /** User ID of the person to call */\n userIds: string[];\n /** Type of call, defaults to 'default' */\n type?: CallType;\n /** Whether to ring the other user, defaults to true */\n ring?: boolean;\n /** Team name to call */\n team?: string;\n /** Whether to start the call with video enabled, defaults to false */\n video?: boolean;\n /** Custom data to be passed to the call */\n custom?: Record<\n string,\n | string\n | boolean\n | number\n | null\n | Record<string, string | boolean | number | null>\n | string[]\n | boolean[]\n | number[]\n >;\n}\n\n/**\n * @interface StreamCallPlugin\n * @description Capacitor plugin for Stream Video calling functionality\n */\nexport interface StreamCallPlugin {\n /**\n * Login to Stream Video service\n * @param {LoginOptions} options - Login configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.login({\n * token: 'your-token',\n * userId: 'user-123',\n * name: 'John Doe',\n * apiKey: 'your-api-key'\n * });\n */\n login(options: LoginOptions): Promise<SuccessResponse>;\n\n /**\n * Logout from Stream Video service\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.logout();\n */\n logout(): Promise<SuccessResponse>;\n\n /**\n * Initiate a call to another user\n * @param {CallOptions} options - Call configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.call({\n * userId: 'user-456',\n * type: 'video',\n * ring: true\n * });\n */\n call(options: CallOptions): Promise<SuccessResponse>;\n\n /**\n * End the current call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.endCall();\n */\n endCall(): Promise<SuccessResponse>;\n\n /**\n * Join an existing call\n * @param {{ callId: string, callType: string }} options - Microphone state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.joinCall({ callId: 'call001', callType: 'default' });\n */\n joinCall?(options: { callId: string; callType: string }): Promise<SuccessResponse>;\n\n /**\n * Enable or disable microphone\n * @param {{ enabled: boolean }} options - Microphone state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setMicrophoneEnabled({ enabled: false });\n */\n setMicrophoneEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Enable or disable camera\n * @param {{ enabled: boolean }} options - Camera state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setCameraEnabled({ enabled: false });\n */\n setCameraEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Add listener for call events\n * @param {'callEvent'} eventName - Name of the event to listen for\n * @param {(event: CallEvent) => void} listenerFunc - Callback function\n * @returns {Promise<{ remove: () => Promise<void> }>} Function to remove listener\n * @example\n * const listener = await StreamCall.addListener('callEvent', (event) => {\n * console.log(`Call ${event.callId} is now ${event.state}`);\n * });\n */\n addListener(\n eventName: 'callEvent',\n listenerFunc: (event: CallEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Listen for lock-screen incoming call (Android only).\n * Fired when the app is shown by full-screen intent before user interaction.\n */\n addListener(\n eventName: 'incomingCall',\n listenerFunc: (event: IncomingCallPayload) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Remove all event listeners\n * @returns {Promise<void>}\n * @example\n * await StreamCall.removeAllListeners();\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Enable bluetooth audio\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.enableBluetooth();\n */\n enableBluetooth?(): Promise<SuccessResponse>;\n\n /**\n * Accept an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.acceptCall();\n */\n acceptCall(): Promise<SuccessResponse>;\n\n /**\n * Reject an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.rejectCall();\n */\n rejectCall(): Promise<SuccessResponse>;\n\n /**\n * Check if camera is enabled\n * @returns {Promise<CameraEnabledResponse>} Camera enabled status\n * @example\n * const isCameraEnabled = await StreamCall.isCameraEnabled();\n * console.log(isCameraEnabled);\n */\n isCameraEnabled(): Promise<CameraEnabledResponse>;\n\n /**\n * Get the current call status\n * @returns {Promise<CallEvent>} Current call status as a CallEvent\n * @example\n * const callStatus = await StreamCall.getCallStatus();\n * console.log(callStatus);\n */\n getCallStatus(): Promise<CallEvent>;\n\n /**\n * Get the current ringing call\n * @returns {Promise<CallEvent>} Current ringing call status as a CallEvent\n * @example\n * const ringingCall = await StreamCall.getRingingCall();\n * console.log(ringingCall);\n */\n getRingingCall?(): Promise<CallEvent>;\n\n /**\n * Cycle through the available video layouts\n * @returns {Promise<{ newLayout: StreamCallLayout }>} The layout that is now active\n * @example\n * const { newLayout } = await StreamCall.toggleViews();\n * console.log(`Layout switched to ${newLayout}`);\n */\n toggleViews?(): Promise<{ newLayout: StreamCallLayout }>;\n\n /**\n * Set speakerphone on\n * @param {{ name: string }} options - Speakerphone name\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setSpeaker({ name: 'speaker' });\n */\n setSpeaker(options: { name: string }): Promise<SuccessResponse>;\n\n /**\n * Switch camera\n * @param {{ camera: 'front' | 'back' }} options - Camera to switch to\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.switchCamera({ camera: 'back' });\n */\n switchCamera(options: { camera: 'front' | 'back' }): Promise<SuccessResponse>;\n\n /**\n * Get detailed information about an active call including caller details\n * @param options - Options containing the call ID\n */\n getCallInfo(options: { callId: string }): Promise<CallEvent>;\n\n /**\n * Set a dynamic Stream Video API key that overrides the static one\n * @param {{ apiKey: string }} options - The API key to set\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setDynamicStreamVideoApikey({ apiKey: 'new-api-key' });\n */\n setDynamicStreamVideoApikey(options: { apiKey: string }): Promise<SuccessResponse>;\n\n /**\n * Get the currently set dynamic Stream Video API key\n * @returns {Promise<DynamicApiKeyResponse>} The dynamic API key and whether it's set\n * @example\n * const result = await StreamCall.getDynamicStreamVideoApikey();\n * if (result.hasDynamicKey) {\n * console.log('Dynamic API key:', result.apiKey);\n * } else {\n * console.log('Using static API key from resources');\n * }\n */\n getDynamicStreamVideoApikey(): Promise<DynamicApiKeyResponse>;\n\n /**\n * Get the current user's information\n * @returns {Promise<CurrentUserResponse>} Current user information\n * @example\n * const currentUser = await StreamCall.getCurrentUser();\n * console.log(currentUser);\n */\n getCurrentUser(): Promise<CurrentUserResponse>;\n}\n\n/**\n * @interface IncomingCallPayload\n * @description Payload delivered with \"incomingCall\" event (Android lock-screen).\n * @property {string} cid - Call CID (type:id)\n * @property {string} type - Always \"incoming\" for this event\n * @property {CallMember} [caller] - Information about the caller\n */\nexport interface IncomingCallPayload {\n /** Full call CID (e.g. default:123) */\n cid: string;\n /** Event type (currently always \"incoming\") */\n type: 'incoming';\n /** Information about the caller */\n caller?: CallMember;\n /** Custom data to be passed to the call */\n custom?: Record<\n string,\n | string\n | boolean\n | number\n | null\n | Record<string, string | boolean | number | null>\n | string[]\n | boolean[]\n | number[]\n >;\n\n /**\n * Get the native Capacitor plugin version\n *\n * @returns {Promise<{ id: string }>} an Promise with version for this device\n * @throws An error if the something went wrong\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @interface LoginOptions\n * @description Configuration options for logging into the Stream Video service\n * @property {string} token - Stream Video API token for authentication\n * @property {string} userId - Unique identifier for the current user\n * @property {string} name - Display name for the current user\n * @property {string} [imageURL] - Avatar URL for the current user\n * @property {string} apiKey - Stream Video API key for your application\n * @property {string} [magicDivId] - DOM element ID where video will be rendered\n */\nexport interface LoginOptions {\n /** Stream Video API token */\n token: string;\n /** User ID for the current user */\n userId: string;\n /** Display name for the current user */\n name: string;\n /** Optional avatar URL for the current user */\n imageURL?: string;\n /** Stream Video API key */\n apiKey: string;\n /** ID of the HTML element where the video will be rendered */\n magicDivId?: string;\n pushNotificationsConfig?: PushNotificationsConfig;\n}\n\nexport interface PushNotificationsConfig {\n pushProviderName: string;\n voipProviderName: string;\n}\n\n/**\n * @typedef CallState\n * @description Represents all possible call states from API and UI\n */\nexport type CallState =\n // User-facing states\n | 'idle'\n | 'ringing'\n | 'joining'\n | 'reconnecting'\n | 'joined'\n | 'leaving'\n | 'left'\n // Event-specific states\n | 'created'\n | 'session_started'\n | 'rejected'\n | 'participant_counts'\n | 'missed'\n | 'accepted'\n | 'ended'\n | 'camera_enabled'\n | 'camera_disabled'\n | 'speaker_enabled'\n | 'speaker_disabled'\n | 'microphone_enabled'\n | 'microphone_disabled'\n | 'outgoing_call_ended'\n | 'unknown';\n\n/**\n * @typedef CallType\n * @description Represents the pre-defined types of a call.\n * - `default`: Simple 1-1 or group video calling with sensible defaults. Video/audio enabled, backstage disabled. Admins/hosts have elevated permissions.\n * - `audio_room`: For audio-only spaces (like Clubhouse). Backstage enabled (requires `goLive`), pre-configured permissions for requesting to speak.\n * - `livestream`: For one-to-many streaming. Backstage enabled (requires `goLive`), access granted to all authenticated users.\n * - `development`: For testing ONLY. All permissions enabled, backstage disabled. **Not recommended for production.**\n */\nexport type CallType = 'default' | 'audio' | 'audio_room' | 'livestream' | 'development';\n\n/**\n * @typedef StreamCallLayout\n * @description Layout modes matching the Stream React SDK; includes native aliases.\n */\nexport type StreamCallLayout = 'grid' | 'spotlight' | 'dynamic' | 'fullScreen' | 'fullscreen';\n\n/**\n * @interface CallMember\n * @description Information about a call member/participant\n * @property {string} userId - User ID of the member\n * @property {string} [name] - Display name of the user\n * @property {string} [imageURL] - Profile image URL of the user\n * @property {string} [role] - Role of the user in the call\n */\nexport interface CallMember {\n /** User ID of the member */\n userId: string;\n /** Display name of the user */\n name?: string;\n /** Profile image URL of the user */\n imageURL?: string;\n /** Role of the user in the call */\n role?: string;\n}\n\n/**\n * @interface CallEvent\n * @description Event emitted when call state changes\n * @property {string} callId - Unique identifier of the call\n * @property {CallState} state - Current state of the call\n * @property {string} [userId] - User ID of the participant who triggered the event\n * @property {string} [reason] - Reason for the call state change\n * @property {CallMember} [caller] - Information about the caller (for incoming calls)\n * @property {CallMember[]} [members] - List of call members\n */\nexport interface CallEvent {\n /** ID of the call */\n callId: string;\n /** Current state of the call */\n state: CallState;\n /** User ID of the participant in the call who triggered the event */\n userId?: string;\n /** Reason for the call state change, if applicable */\n reason?: string;\n /** Information about the caller (for incoming calls) */\n caller?: CallMember;\n /** List of call members */\n members?: CallMember[];\n\n custom?: Record<\n string,\n | string\n | boolean\n | number\n | null\n | Record<string, string | boolean | number | null>\n | string[]\n | boolean[]\n | number[]\n >;\n\n count?: number;\n}\n\nexport interface CameraEnabledResponse {\n enabled: boolean;\n}\n\n/**\n * @interface DynamicApiKeyResponse\n * @description Response from getDynamicStreamVideoApikey\n * @property {string|null} apiKey - The dynamic API key if set, null if not\n * @property {boolean} hasDynamicKey - Whether a dynamic key is currently set\n */\nexport interface DynamicApiKeyResponse {\n /** The dynamic API key if set, null if not */\n apiKey: string | null;\n /** Whether a dynamic key is currently set */\n hasDynamicKey: boolean;\n}\n\n/**\n * @interface CurrentUserResponse\n * @description Response from getCurrentUser containing user information\n * @property {string} userId - User ID of the current user\n * @property {string} name - Display name of the current user\n * @property {string} [imageURL] - Avatar URL of the current user\n * @property {boolean} isLoggedIn - Whether the user is currently logged in\n */\nexport interface CurrentUserResponse {\n /** User ID of the current user */\n userId: string;\n /** Display name of the current user */\n name: string;\n /** Avatar URL of the current user */\n imageURL?: string;\n /** Whether the user is currently logged in */\n isLoggedIn: boolean;\n}\n\n/**\n * @interface SuccessResponse\n * @description Standard response indicating operation success/failure\n * @property {boolean} success - Whether the operation succeeded\n */\nexport interface SuccessResponse {\n /** Whether the operation was successful */\n success: boolean;\n callId?: string;\n}\n\n/**\n * @interface CallOptions\n * @description Options for initiating a video call\n * @property {string[]} userIds - IDs of the users to call\n * @property {CallType} [type=default] - Type of call\n * @property {boolean} [ring=true] - Whether to send ring notification\n * @property {string} [team] - Team name to call\n */\nexport interface CallOptions {\n /** User ID of the person to call */\n userIds: string[];\n /** Type of call, defaults to 'default' */\n type?: CallType;\n /** Whether to ring the other user, defaults to true */\n ring?: boolean;\n /** Team name to call */\n team?: string;\n /** Whether to start the call with video enabled, defaults to false */\n video?: boolean;\n /** Custom data to be passed to the call */\n custom?: Record<\n string,\n | string\n | boolean\n | number\n | null\n | Record<string, string | boolean | number | null>\n | string[]\n | boolean[]\n | number[]\n >;\n}\n\n/**\n * @interface StreamCallPlugin\n * @description Capacitor plugin for Stream Video calling functionality\n */\nexport interface StreamCallPlugin {\n /**\n * Login to Stream Video service\n * @param {LoginOptions} options - Login configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.login({\n * token: 'your-token',\n * userId: 'user-123',\n * name: 'John Doe',\n * apiKey: 'your-api-key'\n * });\n */\n login(options: LoginOptions): Promise<SuccessResponse>;\n\n /**\n * Logout from Stream Video service\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.logout();\n */\n logout(): Promise<SuccessResponse>;\n\n /**\n * Initiate a call to another user\n * @param {CallOptions} options - Call configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.call({\n * userId: 'user-456',\n * type: 'video',\n * ring: true\n * });\n */\n call(options: CallOptions): Promise<SuccessResponse>;\n\n /**\n * End the current call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.endCall();\n */\n endCall(): Promise<SuccessResponse>;\n\n /**\n * Join an existing call\n * @param {{ callId: string, callType: string }} options - Microphone state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.joinCall({ callId: 'call001', callType: 'default' });\n */\n joinCall?(options: { callId: string; callType: string }): Promise<SuccessResponse>;\n\n /**\n * Enable or disable microphone\n * @param {{ enabled: boolean }} options - Microphone state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setMicrophoneEnabled({ enabled: false });\n */\n setMicrophoneEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Enable or disable camera\n * @param {{ enabled: boolean }} options - Camera state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setCameraEnabled({ enabled: false });\n */\n setCameraEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Add listener for call events\n * @param {'callEvent'} eventName - Name of the event to listen for\n * @param {(event: CallEvent) => void} listenerFunc - Callback function\n * @returns {Promise<{ remove: () => Promise<void> }>} Function to remove listener\n * @example\n * const listener = await StreamCall.addListener('callEvent', (event) => {\n * console.log(`Call ${event.callId} is now ${event.state}`);\n * });\n */\n addListener(\n eventName: 'callEvent',\n listenerFunc: (event: CallEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Listen for lock-screen incoming call (Android only).\n * Fired when the app is shown by full-screen intent before user interaction.\n */\n addListener(\n eventName: 'incomingCall',\n listenerFunc: (event: IncomingCallPayload) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Remove all event listeners\n * @returns {Promise<void>}\n * @example\n * await StreamCall.removeAllListeners();\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Enable bluetooth audio\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.enableBluetooth();\n */\n enableBluetooth?(): Promise<SuccessResponse>;\n\n /**\n * Accept an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.acceptCall();\n */\n acceptCall(): Promise<SuccessResponse>;\n\n /**\n * Reject an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.rejectCall();\n */\n rejectCall(): Promise<SuccessResponse>;\n\n /**\n * Check if camera is enabled\n * @returns {Promise<CameraEnabledResponse>} Camera enabled status\n * @example\n * const isCameraEnabled = await StreamCall.isCameraEnabled();\n * console.log(isCameraEnabled);\n */\n isCameraEnabled(): Promise<CameraEnabledResponse>;\n\n /**\n * Get the current call status\n * @returns {Promise<CallEvent>} Current call status as a CallEvent\n * @example\n * const callStatus = await StreamCall.getCallStatus();\n * console.log(callStatus);\n */\n getCallStatus(): Promise<CallEvent>;\n\n /**\n * Get the current ringing call\n * @returns {Promise<CallEvent>} Current ringing call status as a CallEvent\n * @example\n * const ringingCall = await StreamCall.getRingingCall();\n * console.log(ringingCall);\n */\n getRingingCall?(): Promise<CallEvent>;\n\n /**\n * Cycle through the available video layouts\n * @returns {Promise<{ newLayout: StreamCallLayout }>} The layout that is now active\n * @example\n * const { newLayout } = await StreamCall.toggleViews();\n * console.log(`Layout switched to ${newLayout}`);\n */\n toggleViews?(): Promise<{ newLayout: StreamCallLayout }>;\n\n /**\n * Set speakerphone on\n * @param {{ name: string }} options - Speakerphone name\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setSpeaker({ name: 'speaker' });\n */\n setSpeaker(options: { name: string }): Promise<SuccessResponse>;\n\n /**\n * Switch camera\n * @param {{ camera: 'front' | 'back' }} options - Camera to switch to\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.switchCamera({ camera: 'back' });\n */\n switchCamera(options: { camera: 'front' | 'back' }): Promise<SuccessResponse>;\n\n /**\n * Get detailed information about an active call including caller details\n * @param options - Options containing the call ID\n */\n getCallInfo(options: { callId: string }): Promise<CallEvent>;\n\n /**\n * Set a dynamic Stream Video API key that overrides the static one\n * @param {{ apiKey: string }} options - The API key to set\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setDynamicStreamVideoApikey({ apiKey: 'new-api-key' });\n */\n setDynamicStreamVideoApikey(options: { apiKey: string }): Promise<SuccessResponse>;\n\n /**\n * Get the currently set dynamic Stream Video API key\n * @returns {Promise<DynamicApiKeyResponse>} The dynamic API key and whether it's set\n * @example\n * const result = await StreamCall.getDynamicStreamVideoApikey();\n * if (result.hasDynamicKey) {\n * console.log('Dynamic API key:', result.apiKey);\n * } else {\n * console.log('Using static API key from resources');\n * }\n */\n getDynamicStreamVideoApikey(): Promise<DynamicApiKeyResponse>;\n\n /**\n * Get the current user's information\n * @returns {Promise<CurrentUserResponse>} Current user information\n * @example\n * const currentUser = await StreamCall.getCurrentUser();\n * console.log(currentUser);\n */\n getCurrentUser(): Promise<CurrentUserResponse>;\n\n /**\n * Get the native Capacitor plugin version\n *\n * @returns {Promise<{ id: string }>} an Promise with version for this device\n * @throws An error if the something went wrong\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n\n/**\n * @interface IncomingCallPayload\n * @description Payload delivered with \"incomingCall\" event (Android lock-screen).\n * @property {string} cid - Call CID (type:id)\n * @property {string} type - Always \"incoming\" for this event\n * @property {CallMember} [caller] - Information about the caller\n */\nexport interface IncomingCallPayload {\n /** Full call CID (e.g. default:123) */\n cid: string;\n /** Event type (currently always \"incoming\") */\n type: 'incoming';\n /** Information about the caller */\n caller?: CallMember;\n /** Custom data to be passed to the call */\n custom?: Record<\n string,\n | string\n | boolean\n | number\n | null\n | Record<string, string | boolean | number | null>\n | string[]\n | boolean[]\n | number[]\n >;\n\n /**\n * Get the native Capacitor plugin version\n *\n * @returns {Promise<{ id: string }>} an Promise with version for this device\n * @throws An error if the something went wrong\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n"]}
|
|
@@ -12,7 +12,7 @@ import WebKit
|
|
|
12
12
|
*/
|
|
13
13
|
@objc(StreamCallPlugin)
|
|
14
14
|
public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
15
|
-
private let
|
|
15
|
+
private let pluginVersion: String = "7.7.7"
|
|
16
16
|
public let identifier = "StreamCallPlugin"
|
|
17
17
|
public let jsName = "StreamCall"
|
|
18
18
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -68,6 +68,8 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
68
68
|
|
|
69
69
|
@Injected(\.callKitAdapter) var callKitAdapter
|
|
70
70
|
@Injected(\.callKitPushNotificationAdapter) var callKitPushNotificationAdapter
|
|
71
|
+
@Injected(\.utils) var utils
|
|
72
|
+
|
|
71
73
|
private var webviewDelegate: WebviewNavigationDelegate?
|
|
72
74
|
|
|
73
75
|
// Declare as optional and initialize in load() method
|
|
@@ -227,13 +229,6 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
227
229
|
"state": "rejected"
|
|
228
230
|
]
|
|
229
231
|
notifyListeners("callEvent", data: data)
|
|
230
|
-
case let .typeCallAcceptedEvent(response):
|
|
231
|
-
if let streamUserId = self.streamVideo?.user.id,
|
|
232
|
-
response.user.id == streamUserId,
|
|
233
|
-
response.callCid != self.currentCallId {
|
|
234
|
-
|
|
235
|
-
self.updateCallStatusAndNotify(callId: response.callCid, state: "joined")
|
|
236
|
-
}
|
|
237
232
|
case let .typeCallEndedEvent(response):
|
|
238
233
|
let data: [String: Any] = [
|
|
239
234
|
"callId": response.callCid,
|
|
@@ -283,6 +278,12 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
283
278
|
viewModel.setActiveCall(activeCall)
|
|
284
279
|
viewModel.update(participantsLayout: .grid)
|
|
285
280
|
|
|
281
|
+
if let callId = viewModel.call?.cId, !self.hasNotifiedCallJoined || callId != self.currentCallId {
|
|
282
|
+
print("Notifying call joined: \(callId)")
|
|
283
|
+
self.updateCallStatusAndNotify(callId: callId, state: "joined")
|
|
284
|
+
self.hasNotifiedCallJoined = true
|
|
285
|
+
}
|
|
286
|
+
|
|
286
287
|
// Subscribe to speaker status for this active call
|
|
287
288
|
self.speakerSubscription = activeCall.speaker.$status
|
|
288
289
|
.receive(on: DispatchQueue.main)
|
|
@@ -316,6 +317,17 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
316
317
|
print("Active call became nil, cleaning up speaker subscription")
|
|
317
318
|
self.speakerSubscription?.cancel()
|
|
318
319
|
self.speakerSubscription = nil
|
|
320
|
+
|
|
321
|
+
print("Call actually ending: \(self.currentCallId)")
|
|
322
|
+
|
|
323
|
+
// Notify that call has ended - use the stored call ID
|
|
324
|
+
self.updateCallStatusAndNotify(callId: self.currentCallId, state: "left")
|
|
325
|
+
|
|
326
|
+
// Reset notification flag when call ends
|
|
327
|
+
self.hasNotifiedCallJoined = false
|
|
328
|
+
|
|
329
|
+
// Remove the call overlay view and touch intercept view when not in a call
|
|
330
|
+
self.ensureViewRemoved()
|
|
319
331
|
}
|
|
320
332
|
}
|
|
321
333
|
|
|
@@ -340,6 +352,9 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
340
352
|
case .outgoing = previousState {
|
|
341
353
|
print("Call state changed from outgoing to idle. Ending call with ID: \(self.currentCallId)")
|
|
342
354
|
|
|
355
|
+
// Stop ongoing sound when call is cancelled
|
|
356
|
+
self.utils.callSoundsPlayer.stopOngoingSound()
|
|
357
|
+
|
|
343
358
|
// End the call using the stored call ID and type
|
|
344
359
|
if !self.currentCallId.isEmpty {
|
|
345
360
|
Task {
|
|
@@ -389,6 +404,9 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
389
404
|
// Create/update overlay and make visible when there's an active call
|
|
390
405
|
self.createCallOverlayView()
|
|
391
406
|
|
|
407
|
+
// Stop ongoing sound when call is joined
|
|
408
|
+
self.utils.callSoundsPlayer.stopOngoingSound()
|
|
409
|
+
|
|
392
410
|
// Notify that a call has started - but only if we haven't notified for this call yet
|
|
393
411
|
if let callId = viewModel.call?.cId, !self.hasNotifiedCallJoined || callId != self.currentCallId {
|
|
394
412
|
print("Notifying call joined: \(callId)")
|
|
@@ -399,28 +417,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
399
417
|
} else if case .incoming(let incomingCall) = newState {
|
|
400
418
|
self.updateCallStatusAndNotify(callId: incomingCall.id, state: "ringing")
|
|
401
419
|
// }
|
|
402
|
-
} else if newState == .idle {
|
|
403
|
-
print("Call state changed to idle. CurrentCallId: \(self.currentCallId), ActiveCall: \(String(describing: self.streamVideo?.state.activeCall?.cId))")
|
|
404
|
-
|
|
405
|
-
// Only notify about call ending if we have a valid stored call ID and there's truly no active call
|
|
406
|
-
// This prevents false "left" events during normal state transitions
|
|
407
|
-
if !self.currentCallId.isEmpty && self.streamVideo?.state.activeCall == nil {
|
|
408
|
-
print("Call actually ending: \(self.currentCallId)")
|
|
409
|
-
|
|
410
|
-
// Notify that call has ended - use the stored call ID
|
|
411
|
-
self.updateCallStatusAndNotify(callId: self.currentCallId, state: "left")
|
|
412
|
-
|
|
413
|
-
// Reset notification flag when call ends
|
|
414
|
-
self.hasNotifiedCallJoined = false
|
|
415
|
-
|
|
416
|
-
// Remove the call overlay view and touch intercept view when not in a call
|
|
417
|
-
self.ensureViewRemoved()
|
|
418
|
-
|
|
419
|
-
} else {
|
|
420
|
-
print("Not sending left event - CurrentCallId: \(self.currentCallId), ActiveCall exists: \(self.streamVideo?.state.activeCall != nil)")
|
|
421
|
-
}
|
|
422
420
|
}
|
|
423
|
-
|
|
424
421
|
// Update the previous state for next comparison
|
|
425
422
|
self.previousCallingState = newState
|
|
426
423
|
} catch {
|
|
@@ -692,6 +689,8 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
692
689
|
print("- Users: \(members)")
|
|
693
690
|
print("- Should Ring: \(shouldRing)")
|
|
694
691
|
print("- Team: \(String(describing: team))")
|
|
692
|
+
// Play outgoing call sound
|
|
693
|
+
self.utils.callSoundsPlayer.playOutgoingCallSound()
|
|
695
694
|
|
|
696
695
|
// Create the call object
|
|
697
696
|
await self.callViewModel?.startCall(
|
|
@@ -821,6 +820,9 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
821
820
|
}
|
|
822
821
|
|
|
823
822
|
private func endCallInternal() {
|
|
823
|
+
// Stop ongoing sound when call ends
|
|
824
|
+
self.utils.callSoundsPlayer.stopOngoingSound()
|
|
825
|
+
|
|
824
826
|
do {
|
|
825
827
|
try requireInitialized()
|
|
826
828
|
|
|
@@ -905,6 +907,9 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
905
907
|
}
|
|
906
908
|
|
|
907
909
|
@objc func endCall(_ call: CAPPluginCall) {
|
|
910
|
+
// Stop ongoing sound when call ends
|
|
911
|
+
self.utils.callSoundsPlayer.stopOngoingSound()
|
|
912
|
+
|
|
908
913
|
do {
|
|
909
914
|
try requireInitialized()
|
|
910
915
|
|
|
@@ -1631,7 +1636,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
1631
1636
|
}
|
|
1632
1637
|
|
|
1633
1638
|
@objc func getPluginVersion(_ call: CAPPluginCall) {
|
|
1634
|
-
call.resolve(["version": self.
|
|
1639
|
+
call.resolve(["version": self.pluginVersion])
|
|
1635
1640
|
}
|
|
1636
1641
|
|
|
1637
1642
|
}
|
package/package.json
CHANGED