@capgo/capacitor-realtimekit 7.0.6 → 7.1.2
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/Package.swift +4 -2
- package/android/src/main/java/ee/forgr/plugin/capacitor_realtimekit/CapacitorRealtimekitPlugin.java +93 -15
- package/ios/Sources/CapacitorRealtimekitPlugin/CapacitorRealtimekit.swift +70 -25
- package/ios/Sources/CapacitorRealtimekitPlugin/CapacitorRealtimekitPlugin.swift +9 -3
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Martin Donadieu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Package.swift
CHANGED
|
@@ -11,7 +11,8 @@ let package = Package(
|
|
|
11
11
|
],
|
|
12
12
|
dependencies: [
|
|
13
13
|
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0"),
|
|
14
|
-
.package(url: "https://github.com/dyte-in/RealtimeKitCoreiOS.git", from: "1.0.0")
|
|
14
|
+
.package(url: "https://github.com/dyte-in/RealtimeKitCoreiOS.git", from: "1.0.0"),
|
|
15
|
+
.package(url: "https://github.com/dyte-in/RealtimeKitUI.git", from: "0.5.3")
|
|
15
16
|
],
|
|
16
17
|
targets: [
|
|
17
18
|
.target(
|
|
@@ -19,7 +20,8 @@ let package = Package(
|
|
|
19
20
|
dependencies: [
|
|
20
21
|
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
21
22
|
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
|
22
|
-
.product(name: "RealtimeKit", package: "RealtimeKitCoreiOS")
|
|
23
|
+
.product(name: "RealtimeKit", package: "RealtimeKitCoreiOS"),
|
|
24
|
+
.product(name: "RealtimeKitUI", package: "RealtimeKitUI")
|
|
23
25
|
],
|
|
24
26
|
path: "ios/Sources/CapacitorRealtimekitPlugin"),
|
|
25
27
|
.testTarget(
|
package/android/src/main/java/ee/forgr/plugin/capacitor_realtimekit/CapacitorRealtimekitPlugin.java
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
package ee.forgr.plugin.capacitor_realtimekit;
|
|
2
2
|
|
|
3
3
|
import android.Manifest;
|
|
4
|
+
import android.app.Activity;
|
|
4
5
|
import android.util.Log;
|
|
6
|
+
import com.cloudflare.realtimekit.models.RtkMeetingInfo;
|
|
7
|
+
import com.cloudflare.realtimekit.ui.RealtimeKitUI;
|
|
8
|
+
import com.cloudflare.realtimekit.ui.RealtimeKitUIBuilder;
|
|
9
|
+
import com.cloudflare.realtimekit.ui.RealtimeKitUIInfo;
|
|
5
10
|
import com.getcapacitor.JSObject;
|
|
11
|
+
import com.getcapacitor.PermissionState;
|
|
6
12
|
import com.getcapacitor.Plugin;
|
|
7
13
|
import com.getcapacitor.PluginCall;
|
|
8
14
|
import com.getcapacitor.PluginMethod;
|
|
9
15
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
10
16
|
import com.getcapacitor.annotation.Permission;
|
|
17
|
+
import com.getcapacitor.annotation.PermissionCallback;
|
|
11
18
|
|
|
12
19
|
@CapacitorPlugin(
|
|
13
20
|
name = "CapacitorRealtimekit",
|
|
@@ -19,8 +26,23 @@ import com.getcapacitor.annotation.Permission;
|
|
|
19
26
|
public class CapacitorRealtimekitPlugin extends Plugin {
|
|
20
27
|
|
|
21
28
|
private static final String TAG = "RealtimekitPlugin";
|
|
22
|
-
private final String
|
|
29
|
+
private static final String REALTIMEKIT_BASE_DOMAIN = "realtime.cloudflare.com";
|
|
30
|
+
private final String pluginVersion = "7.1.2";
|
|
23
31
|
private boolean isInitialized = false;
|
|
32
|
+
private PendingMeetingRequest pendingMeetingRequest;
|
|
33
|
+
|
|
34
|
+
private static final class PendingMeetingRequest {
|
|
35
|
+
|
|
36
|
+
private final String authToken;
|
|
37
|
+
private final boolean enableAudio;
|
|
38
|
+
private final boolean enableVideo;
|
|
39
|
+
|
|
40
|
+
private PendingMeetingRequest(String authToken, boolean enableAudio, boolean enableVideo) {
|
|
41
|
+
this.authToken = authToken;
|
|
42
|
+
this.enableAudio = enableAudio;
|
|
43
|
+
this.enableVideo = enableVideo;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
24
46
|
|
|
25
47
|
@Override
|
|
26
48
|
public void load() {
|
|
@@ -30,8 +52,6 @@ public class CapacitorRealtimekitPlugin extends Plugin {
|
|
|
30
52
|
|
|
31
53
|
@PluginMethod
|
|
32
54
|
public void initialize(PluginCall call) {
|
|
33
|
-
// Initialize the RealtimeKit SDK
|
|
34
|
-
// TODO: Add Cloudflare RealtimeKit SDK initialization here
|
|
35
55
|
isInitialized = true;
|
|
36
56
|
Log.d(TAG, "RealtimeKit initialized");
|
|
37
57
|
call.resolve();
|
|
@@ -53,20 +73,21 @@ public class CapacitorRealtimekitPlugin extends Plugin {
|
|
|
53
73
|
Boolean enableAudio = call.getBoolean("enableAudio", true);
|
|
54
74
|
Boolean enableVideo = call.getBoolean("enableVideo", true);
|
|
55
75
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
76
|
+
String trimmedToken = authToken.trim();
|
|
77
|
+
if (trimmedToken.isEmpty()) {
|
|
78
|
+
call.reject("authToken is required");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
PendingMeetingRequest request = new PendingMeetingRequest(trimmedToken, enableAudio, enableVideo);
|
|
62
83
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
84
|
+
if (!hasMediaPermissions()) {
|
|
85
|
+
pendingMeetingRequest = request;
|
|
86
|
+
requestPermissionForAliases(new String[] { "camera", "microphone" }, call, "startMeetingPermissionsCallback");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
66
89
|
|
|
67
|
-
|
|
68
|
-
// Real implementation would launch the meeting UI here
|
|
69
|
-
call.resolve();
|
|
90
|
+
launchMeeting(call, request);
|
|
70
91
|
}
|
|
71
92
|
|
|
72
93
|
@PluginMethod
|
|
@@ -79,4 +100,61 @@ public class CapacitorRealtimekitPlugin extends Plugin {
|
|
|
79
100
|
call.reject("Could not get plugin version", e);
|
|
80
101
|
}
|
|
81
102
|
}
|
|
103
|
+
|
|
104
|
+
@PermissionCallback
|
|
105
|
+
private void startMeetingPermissionsCallback(PluginCall call) {
|
|
106
|
+
if (call == null) {
|
|
107
|
+
pendingMeetingRequest = null;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!hasMediaPermissions()) {
|
|
112
|
+
pendingMeetingRequest = null;
|
|
113
|
+
call.reject("Camera and microphone permissions are required to start a meeting.");
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
PendingMeetingRequest request = pendingMeetingRequest;
|
|
118
|
+
pendingMeetingRequest = null;
|
|
119
|
+
|
|
120
|
+
if (request == null) {
|
|
121
|
+
call.reject("Missing meeting configuration after granting permissions.");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
launchMeeting(call, request);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private boolean hasMediaPermissions() {
|
|
129
|
+
return getPermissionState("camera") == PermissionState.GRANTED && getPermissionState("microphone") == PermissionState.GRANTED;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private void launchMeeting(PluginCall call, PendingMeetingRequest request) {
|
|
133
|
+
pendingMeetingRequest = null;
|
|
134
|
+
Activity activity = getActivity();
|
|
135
|
+
if (activity == null) {
|
|
136
|
+
call.reject("Unable to access the current Activity to show the meeting UI.");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
activity.runOnUiThread(() -> {
|
|
141
|
+
try {
|
|
142
|
+
RtkMeetingInfo meetingInfo = new RtkMeetingInfo(
|
|
143
|
+
request.authToken,
|
|
144
|
+
request.enableAudio,
|
|
145
|
+
request.enableVideo,
|
|
146
|
+
REALTIMEKIT_BASE_DOMAIN
|
|
147
|
+
);
|
|
148
|
+
RealtimeKitUIInfo uiInfo = new RealtimeKitUIInfo(activity, meetingInfo);
|
|
149
|
+
RealtimeKitUI realtimeKitUI = RealtimeKitUIBuilder.build(uiInfo);
|
|
150
|
+
RealtimeKitUIBuilder.getMeeting().setUiKitInfo("capacitor-android", pluginVersion);
|
|
151
|
+
realtimeKitUI.startMeeting();
|
|
152
|
+
Log.d(TAG, "RealtimeKit meeting started successfully");
|
|
153
|
+
call.resolve();
|
|
154
|
+
} catch (Exception e) {
|
|
155
|
+
Log.e(TAG, "Failed to start RealtimeKit meeting", e);
|
|
156
|
+
call.reject("Failed to start meeting: " + e.getMessage(), e);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
82
160
|
}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
+
import Capacitor
|
|
1
2
|
import Foundation
|
|
3
|
+
import RealtimeKit
|
|
4
|
+
import RealtimeKitUI
|
|
2
5
|
import UIKit
|
|
3
6
|
|
|
4
|
-
public class CapacitorRealtimekit: NSObject {
|
|
7
|
+
public final class CapacitorRealtimekit: NSObject {
|
|
8
|
+
private weak var plugin: CAPPlugin?
|
|
9
|
+
private let pluginVersion: String
|
|
10
|
+
private let baseDomain = "realtime.cloudflare.com"
|
|
5
11
|
private var isInitialized = false
|
|
12
|
+
private var realtimeKitUI: RealtimeKitUI?
|
|
13
|
+
|
|
14
|
+
init(plugin: CAPPlugin, pluginVersion: String) {
|
|
15
|
+
self.plugin = plugin
|
|
16
|
+
self.pluginVersion = pluginVersion
|
|
17
|
+
super.init()
|
|
18
|
+
}
|
|
6
19
|
|
|
7
20
|
public func initialize() {
|
|
8
|
-
// Initialize the RealtimeKit SDK
|
|
9
|
-
// TODO: Add Cloudflare RealtimeKit SDK initialization here
|
|
10
21
|
isInitialized = true
|
|
11
22
|
print("RealtimeKit initialized")
|
|
12
23
|
}
|
|
@@ -18,31 +29,65 @@ public class CapacitorRealtimekit: NSObject {
|
|
|
18
29
|
completion: @escaping (Error?) -> Void
|
|
19
30
|
) {
|
|
20
31
|
guard isInitialized else {
|
|
21
|
-
|
|
22
|
-
domain: "CapacitorRealtimekit",
|
|
23
|
-
code: -1,
|
|
24
|
-
userInfo: [NSLocalizedDescriptionKey: "RealtimeKit not initialized. Call initialize() first."]
|
|
25
|
-
)
|
|
26
|
-
completion(error)
|
|
32
|
+
completion(makeError("RealtimeKit not initialized. Call initialize() first."))
|
|
27
33
|
return
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
print("Starting meeting with authToken: \(authToken)")
|
|
40
|
-
print("Audio enabled: \(enableAudio)")
|
|
41
|
-
print("Video enabled: \(enableVideo)")
|
|
42
|
-
|
|
43
|
-
// For now, just complete successfully
|
|
44
|
-
// Real implementation would present the meeting UI here
|
|
45
|
-
completion(nil)
|
|
36
|
+
let trimmedToken = authToken.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
37
|
+
guard !trimmedToken.isEmpty else {
|
|
38
|
+
completion(makeError("authToken is required"))
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
guard let presenter = topViewController(from: plugin?.bridge?.viewController) else {
|
|
43
|
+
completion(makeError("Unable to find a view controller to present the meeting UI."))
|
|
44
|
+
return
|
|
46
45
|
}
|
|
46
|
+
|
|
47
|
+
DispatchQueue.main.async { [weak self] in
|
|
48
|
+
guard let self else { return }
|
|
49
|
+
|
|
50
|
+
let meetingInfo = RtkMeetingInfo(
|
|
51
|
+
authToken: trimmedToken,
|
|
52
|
+
enableAudio: enableAudio,
|
|
53
|
+
enableVideo: enableVideo,
|
|
54
|
+
baseDomain: self.baseDomain
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
let uiKit = RealtimeKitUI(meetingInfo: meetingInfo)
|
|
58
|
+
uiKit.rtkClient.setUiKitInfo(name: "capacitor-ios", version: self.pluginVersion)
|
|
59
|
+
self.realtimeKitUI = uiKit
|
|
60
|
+
|
|
61
|
+
let meetingController = uiKit.startMeeting { [weak self] in
|
|
62
|
+
self?.realtimeKitUI = nil
|
|
63
|
+
}
|
|
64
|
+
meetingController.modalPresentationStyle = .fullScreen
|
|
65
|
+
|
|
66
|
+
presenter.present(meetingController, animated: true) {
|
|
67
|
+
completion(nil)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private func topViewController(from root: UIViewController?) -> UIViewController? {
|
|
73
|
+
guard let root else { return nil }
|
|
74
|
+
|
|
75
|
+
if let presented = root.presentedViewController {
|
|
76
|
+
return topViewController(from: presented)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if let navigation = root as? UINavigationController {
|
|
80
|
+
return topViewController(from: navigation.visibleViewController ?? navigation)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if let tab = root as? UITabBarController {
|
|
84
|
+
return topViewController(from: tab.selectedViewController ?? tab)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return root
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private func makeError(_ message: String) -> NSError {
|
|
91
|
+
NSError(domain: "CapacitorRealtimekit", code: -1, userInfo: [NSLocalizedDescriptionKey: message])
|
|
47
92
|
}
|
|
48
93
|
}
|
|
@@ -7,7 +7,7 @@ import Capacitor
|
|
|
7
7
|
*/
|
|
8
8
|
@objc(CapacitorRealtimekitPlugin)
|
|
9
9
|
public class CapacitorRealtimekitPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
10
|
-
private let pluginVersion: String = "7.
|
|
10
|
+
private let pluginVersion: String = "7.1.2"
|
|
11
11
|
public let identifier = "CapacitorRealtimekitPlugin"
|
|
12
12
|
public let jsName = "CapacitorRealtimekit"
|
|
13
13
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -16,7 +16,7 @@ public class CapacitorRealtimekitPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
16
16
|
CAPPluginMethod(name: "getPluginVersion", returnType: CAPPluginReturnPromise)
|
|
17
17
|
]
|
|
18
18
|
|
|
19
|
-
private
|
|
19
|
+
private lazy var implementation = CapacitorRealtimekit(plugin: self, pluginVersion: pluginVersion)
|
|
20
20
|
|
|
21
21
|
@objc func initialize(_ call: CAPPluginCall) {
|
|
22
22
|
implementation.initialize()
|
|
@@ -29,11 +29,17 @@ public class CapacitorRealtimekitPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
29
29
|
return
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
let trimmedToken = authToken.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
33
|
+
if trimmedToken.isEmpty {
|
|
34
|
+
call.reject("authToken is required")
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
let enableAudio = call.getBool("enableAudio") ?? true
|
|
33
39
|
let enableVideo = call.getBool("enableVideo") ?? true
|
|
34
40
|
|
|
35
41
|
implementation.startMeeting(
|
|
36
|
-
authToken:
|
|
42
|
+
authToken: trimmedToken,
|
|
37
43
|
enableAudio: enableAudio,
|
|
38
44
|
enableVideo: enableVideo
|
|
39
45
|
) { error in
|
package/package.json
CHANGED