@capgo/capacitor-realtimekit 7.0.6 → 7.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/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(
@@ -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 pluginVersion = "7.0.6";
29
+ private static final String REALTIMEKIT_BASE_DOMAIN = "realtime.cloudflare.com";
30
+ private final String pluginVersion = "7.1.0";
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
- // Start meeting with the built-in UI
57
- // TODO: Integrate with Cloudflare RealtimeKit SDK to launch meeting UI
58
- // In a real implementation, this would:
59
- // 1. Create and configure the RealtimeKit meeting activity/fragment
60
- // 2. Set the auth token, audio, and video settings
61
- // 3. Launch the meeting UI
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
- Log.d(TAG, "Starting meeting with authToken: " + authToken);
64
- Log.d(TAG, "Audio enabled: " + enableAudio);
65
- Log.d(TAG, "Video enabled: " + enableVideo);
84
+ if (!hasMediaPermissions()) {
85
+ pendingMeetingRequest = request;
86
+ requestPermissionForAliases(new String[] { "camera", "microphone" }, call, "startMeetingPermissionsCallback");
87
+ return;
88
+ }
66
89
 
67
- // For now, just resolve successfully
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
- let error = NSError(
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
- // Start meeting with the built-in UI
31
- // TODO: Integrate with Cloudflare RealtimeKit SDK to launch meeting UI
32
- DispatchQueue.main.async {
33
- // Placeholder implementation
34
- // In a real implementation, this would:
35
- // 1. Create and configure the RealtimeKit meeting view controller
36
- // 2. Set the auth token, audio, and video settings
37
- // 3. Present the meeting UI modally
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.0.6"
10
+ private let pluginVersion: String = "7.1.0"
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 let implementation = CapacitorRealtimekit()
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: authToken,
42
+ authToken: trimmedToken,
37
43
  enableAudio: enableAudio,
38
44
  enableVideo: enableVideo
39
45
  ) { error in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-realtimekit",
3
- "version": "7.0.6",
3
+ "version": "7.1.0",
4
4
  "description": "Cloudflare Calls integration for Capacitor apps with built-in UI for meetings.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",