Skip to content

feat(voip): migrate iOS accept/reject from DDP to REST#7124

Open
diegolmello wants to merge 10 commits intofeat.voip-lib-newfrom
refactor.ddp-ios
Open

feat(voip): migrate iOS accept/reject from DDP to REST#7124
diegolmello wants to merge 10 commits intofeat.voip-lib-newfrom
refactor.ddp-ios

Conversation

@diegolmello
Copy link
Copy Markdown
Member

@diegolmello diegolmello commented Apr 10, 2026

Proposed changes

Migrate VoIP accept() and reject() on iOS from DDP (WebSocket) signaling to REST calls against the existing POST /api/v1/media-calls.answer endpoint. This eliminates the per-call WebSocket lifecycle (connect → DDP connect → login → subscribe → send) from the accept/reject path, significantly simplifying the native iOS VoIP layer.

What changed:

  • New MediaCallsAnswerRequest API request struct (ios/Shared/RocketChat/API/MediaCallsAnswerRequest.swift)
  • VoipService.accept(): replaced DDP client.callMethod/queueMethodCall with API.fetch(request:)
  • VoipService.reject(): replaced DDP with REST (renamed from sendRejectSignal)
  • Removed dead buildMediaCallAnswerParams() and VoipMediaCallAnswerKind enum
  • DDPClient/VoipPerCallDdpRegistry kept — still used by startListeningForCallEnd (call-end DDP listener)

What did NOT change:

  • startListeningForCallEnd DDP subscription (separate problem — persistent WebSocket needed for real-time call-end events)
  • Android VoIP accept/reject (different code path via JS SDK)

Issue(s)

https://rocketchat.atlassian.net/browse/VMUX-67

How to test or reproduce

  1. Receive an incoming VoIP call on iOS
  2. Accept the call — verify POST /api/v1/media-calls.answer is called with answer: "accept"
  3. Reject the call — verify POST /api/v1/media-calls.answer is called with answer: "reject"
  4. Verify call-end detection still works (DDP listener for stream-notify-user)

Screenshots

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability of media call accept and reject operations
    • Enhanced call state management and cleanup handling for ended calls

Accept/reject now go through REST (MediaCallsAnswerRequest) in handleNativeAccept
and reject(). The DDP-based buildMediaCallAnswerParams and its VoipMediaCallAnswerKind
enum are no longer referenced anywhere.
@diegolmello diegolmello changed the base branch from develop to feat.voip-lib-new April 10, 2026 12:49
@diegolmello
Copy link
Copy Markdown
Member Author

PRD

Problem Statement

The native iOS VoIP implementation opens a per-call WebSocket (DDP) connection solely to send two signals: accept and reject. This requires a full DDP client with connect/login/subscribe/callback-queue logic that is significantly more complex than the actual business logic. The same accept/reject signal can be sent via a single HTTP POST using the server's existing media-calls.answer REST endpoint.

The DDP complexity also makes the code hard to reason about, test, and maintain — particularly the VoipPerCallDdpRegistry, the login-race queuing, and the pending-callback machinery.

Solution

Replace the DDP-based accept/reject signaling from iOS native (VoipService) with REST calls to the existing POST /api/v1/media-calls.answer endpoint. This eliminates the DDP WebSocket lifecycle, login handshake, subscription management, and call queuing entirely from the accept/reject path.

The DDP listener for call-end detection (hangup from remote, accepted-on-another-device) is not migrated — it requires a persistent WebSocket subscription and is a separate problem.

User Stories

  1. As an iOS VoIP caller, I want my accept/reject signals to reach the server reliably with minimal infrastructure, so that call setup is fast and reliable.
  2. As a maintainer, I want VoipService to be understandable at a glance, so I can debug call flows without tracing through DDP client state machines.
  3. As a tester, I want to test VoipService's accept/reject logic without setting up a WebSocket server, so tests are fast and deterministic.
  4. As a developer, I want accept/reject signaling to use the same auth mechanism as the rest of the iOS native layer, so there are no new auth patterns to maintain.

Modules

New: ios/Shared/RocketChat/API/MediaCallsAnswerRequest.swift

  • Implements the Request protocol for POST /api/v1/media-calls.answer
  • Constructs JSON body from callId, contractId, answer ("accept"/"reject"), optional supportedFeatures
  • Response: { success: Bool }

Modify: ios/Libraries/VoipService.swift

  • accept(): Replace DDP client.callMethod/queueMethodCall with API.fetch(request: MediaCallsAnswerRequest(...))
  • reject(): Same replacement with answer: "reject" (renamed from sendRejectSignal)
  • Remove: buildMediaCallAnswerParams(), VoipMediaCallAnswerKind enum, queueRejectSignal()
  • Keep: ddpRegistry for startListeningForCallEnd (call-end DDP listener — separate problem)

Delete: ios/Libraries/DDPClient.swift (deferred — still needed for startListeningForCallEnd)

Auth

The Request.request(for:) extension auto-injects x-user-id and x-auth-token headers from Storage().getCredentials(). No new auth infrastructure needed.

Payload shape

{
  "callId": "...",
  "contractId": "DeviceUID",
  "answer": "accept|reject",
  "supportedFeatures": ["audio"]  // only on accept
}

Architecture

VoipService.accept(payload)
  → API.fetch(MediaCallsAnswerRequest(...))   ← new REST path
    → Request.request(for: API)              ← injects x-user-id / x-auth-token
      → URLSession POST to /api/v1/media-calls.answer

Out of Scope

  • Migrating startListeningForCallEnd (DDP subscription for call-end/hangup detection) to REST/SSE
  • Migrating MediaSessionInstance.ts (JS layer WebRTC ICE signaling via DDP) to REST
  • Server-side media-calls.answer endpoint changes
  • Video or screen-share features (only "audio" supported)
  • Android VoIP accept/reject (different code path via JS SDK)

@diegolmello
Copy link
Copy Markdown
Member Author

Implementation Progress

Slice 1 — MediaCallsAnswerRequest (new file) ✅

Commit: 0a1938852

  • MediaCallsAnswerRequest conforms to Request
  • body() serializes correctly for accept/reject variants
  • ResponseType is MediaCallsAnswerResponse with success: Bool
  • Path: /api/v1/media-calls.answer, Method: POST
  • Reviewed & APPROVED

Slice 2 — accept() → REST ✅

  • Committed in Slice 3's commit
  • DDP code (client.callMethod, queueMethodCall) removed from accept()
  • REST call uses API.fetch(request: MediaCallsAnswerRequest(...)) with answer: "accept"
  • finishAccept(true) on HTTP success, finishAccept(false) on failure
  • Reviewed & APPROVED

Slice 3 — reject() → REST ✅

Commit: f48c448f0

  • reject() sends HTTP POST with answer: "reject"
  • queueRejectSignal removed entirely
  • DDP code path removed
  • Reviewed & APPROVED

Slice 4 — Delete dead DDP code ✅

Commit: 9167fa42f

  • Removed buildMediaCallAnswerParams() and VoipMediaCallAnswerKind enum
  • DDPClient.swift and VoipPerCallDdpRegistry.swift kept — still needed for startListeningForCallEnd (call-end DDP listener)
  • ddpRegistry kept — needed for call-end detection
  • Reviewed & APPROVED

Slice Order

Slice 1 ────────────────── Slice 2 ───────────────┐
 (MediaCallsAnswerRequest)   (accept → REST)        │
Slice 3 ──────────── Slice 4 ──────────────────────┘
  (reject → REST)     (Delete dead DDP)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Media call accept/reject signaling is migrated from DDP-based to REST API-based communication. The VoipMediaCallAnswerKind enum and DDP branching logic are removed, replaced by REST calls via the new MediaCallsAnswerRequest. VoipService methods are reworked to send accept/reject via REST, and CallKit "call ended" handling is updated to use REST-based rejection.

Changes

Cohort / File(s) Summary
Media Call REST API
ios/Shared/RocketChat/API/Requests/MediaCallsAnswerRequest.swift
New request struct defining POST /api/v1/media-calls.answer endpoint with callId, contractId, answer, and optional supportedFeatures parameters.
VoIP Service Refactoring
ios/Libraries/VoipService.swift
Removed DDP-based VoipMediaCallAnswerKind enum and related DDP signaling logic. Reworked handleNativeAccept to use REST via MediaCallsAnswerRequest. Updated rejectBusyCall to send REST reject and stop per-call DDP client. Modified CallKit "call ended" handling to remove DDP branching and invoke REST-based rejection.
Project Configuration
ios/RocketChatRN.xcodeproj/project.pbxproj
Added MediaCallsAnswerRequest.swift to build phases and source groups. Updated CocoaPods framework references and build phase entries. Added new .xcconfig references for debug/release configurations. Updated build script inputPaths quoting.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive The PR objectives clearly state scope and implementation details, but the linked issue (VMUX-67) lacks specific coding requirements to validate against. Review the actual requirements in VMUX-67 to confirm the implementation meets all coding objectives and test expectations.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: migrating iOS VoIP accept/reject signaling from DDP (WebSocket) to REST protocol.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the stated migration objective: replacing DDP-based accept/reject with REST calls, introducing MediaCallsAnswerRequest, and removing related DDP helpers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
ios/Shared/RocketChat/API/MediaCallsAnswerRequest.swift (1)

28-38: Silent failure in body() could mask issues.

Using try? means if JSONSerialization.data(withJSONObject:) fails, the request body is silently nil. While failure is unlikely for this simple dictionary, consider logging or handling the error for debuggability during development.

That said, for these basic types (String, [String]?), serialization failure is practically impossible, so this is acceptable as-is.

💡 Optional: Add debug logging for serialization failure
 func body() -> Data? {
     var dict: [String: Any] = [
         "callId": callId,
         "contractId": contractId,
         "answer": answer
     ]
     if let features = supportedFeatures {
         dict["supportedFeatures"] = features
     }
-    return try? JSONSerialization.data(withJSONObject: dict)
+    do {
+        return try JSONSerialization.data(withJSONObject: dict)
+    } catch {
+        `#if` DEBUG
+        print("[MediaCallsAnswerRequest] JSON serialization failed: \(error)")
+        `#endif`
+        return nil
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ios/Shared/RocketChat/API/MediaCallsAnswerRequest.swift` around lines 28 -
38, The body() method currently swallows JSONSerialization errors with try?,
which can hide rare failures; update MediaCallsAnswerRequest.body() to use
do-catch around JSONSerialization.data(withJSONObject:) (or propagate the thrown
error) and in the catch log the error via the existing logging facility (or
return nil only after logging) so serialization failures are visible during
debugging while preserving the same return semantics for production.
ios/Libraries/VoipService.swift (1)

519-521: Consider logging rejected call failures for observability.

The completion handler discards the result entirely. While reject doesn't need to affect UI, logging failures would help diagnose issues where callers see "missed call" notifications despite the callee having rejected.

📊 Optional: Add debug logging
     )) { _ in
+        `#if` DEBUG
+        print("[\(TAG)] Reject request completed for call \(payload.callId)")
+        `#endif`
         self.stopDDPClientInternal(callId: payload.callId)
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ios/Libraries/VoipService.swift` around lines 519 - 521, The completion
handler that currently just calls self.stopDDPClientInternal(callId:
payload.callId) is dropping the reject result; update that closure to inspect
the reject call result and log failures (including payload.callId and error
details) for observability—use the app's existing logger (or NSLog/os_log if
none) to emit a debug/error message when the reject operation fails before
calling stopDDPClientInternal(callId:).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ios/Libraries/VoipService.swift`:
- Around line 471-485: API(server: payload.host) can be nil and currently the
fetch is skipped leaving finishAccept uncalled; update the call site to unwrap
the API(server: payload.host) result (or guard-let it) before calling fetch, and
if it is nil immediately call finishAccept(false) (optionally log the invalid
host and ensure the finishAccept call is dispatched to the main queue like the
existing completion path). Specifically, handle the nil case around the
API(server:) invocation used with fetch and MediaCallsAnswerRequest so every
execution path invokes finishAccept.
- Around line 513-522: The reject function doesn't handle API(server:) == nil so
no reject is sent and stopDDPClientInternal(callId:) may never be called; update
reject to handle the nil case by ensuring stopDDPClientInternal(callId:
payload.callId) is always invoked and, when API(server:) returns non-nil, still
send the MediaCallsAnswerRequest(callId:contractId:answer:supportedFeatures:) as
before; reference the reject(payload: VoipPayload) method, the API(server:)
initializer, MediaCallsAnswerRequest, and stopDDPClientInternal to locate and
implement the nil-guard and guaranteed cleanup.

---

Nitpick comments:
In `@ios/Libraries/VoipService.swift`:
- Around line 519-521: The completion handler that currently just calls
self.stopDDPClientInternal(callId: payload.callId) is dropping the reject
result; update that closure to inspect the reject call result and log failures
(including payload.callId and error details) for observability—use the app's
existing logger (or NSLog/os_log if none) to emit a debug/error message when the
reject operation fails before calling stopDDPClientInternal(callId:).

In `@ios/Shared/RocketChat/API/MediaCallsAnswerRequest.swift`:
- Around line 28-38: The body() method currently swallows JSONSerialization
errors with try?, which can hide rare failures; update
MediaCallsAnswerRequest.body() to use do-catch around
JSONSerialization.data(withJSONObject:) (or propagate the thrown error) and in
the catch log the error via the existing logging facility (or return nil only
after logging) so serialization failures are visible during debugging while
preserving the same return semantics for production.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3f7f3778-f428-4684-aed7-c09ecccdecd8

📥 Commits

Reviewing files that changed from the base of the PR and between 1110468 and 9167fa4.

📒 Files selected for processing (2)
  • ios/Libraries/VoipService.swift
  • ios/Shared/RocketChat/API/MediaCallsAnswerRequest.swift
📜 Review details
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate

Applied to files:

  • ios/Libraries/VoipService.swift
📚 Learning: 2026-03-05T06:06:19.755Z
Learnt from: divyanshu-patil
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6957
File: ios/RCTWatchModule.mm:19-24
Timestamp: 2026-03-05T06:06:19.755Z
Learning: In the Rocket.Chat React Native iOS app, `WCSession` (WatchConnectivity) is activated with its delegate in `ios/RocketChat Watch App/Loaders/WatchSession.swift`, not in `RCTWatchModule.mm`. Since `WCSession.defaultSession` is a singleton, activating it once in `WatchSession.swift` is sufficient; `RCTWatchModule.mm` does not need to re-activate or re-set the delegate.

Applied to files:

  • ios/Libraries/VoipService.swift
🔇 Additional comments (3)
ios/Shared/RocketChat/API/MediaCallsAnswerRequest.swift (1)

10-43: LGTM! Clean REST request/response implementation.

The structure correctly implements the Request protocol with proper HTTP method, path, and body serialization. The optional supportedFeatures handling is appropriately conditional.

ios/Libraries/VoipService.swift (2)

4-4: LGTM!

Import added correctly for accessing MediaCallsAnswerRequest from the RocketChat module.


505-507: LGTM! Clean migration to REST-based reject.

The reject paths in both rejectBusyCall and handleObservedCallChanged now correctly route through the new reject(payload:) method, which uses the REST endpoint instead of DDP.

Also applies to: 587-587

Handle the case when API(server:) returns nil by:
- accept: call finishAccept(false) on the main queue with a DEBUG log
- reject: call stopDDPClientInternal to clean up the DDP client with a DEBUG log

Without this, a nil API silently skipped the REST call, leaving
CallKit in an indeterminate state (accept) or DDP client leaking (reject).
When the user ended an incoming call before it connected,
handleObservedCallChanged sent the REST reject but never notified
CallKit to remove the call from the system Recents UI.

Also deduplicate MediaCallsAnswerResponse with MessageResponse.
@diegolmello diegolmello requested a deployment to approve_e2e_testing April 10, 2026 13:34 — with GitHub Actions Waiting
@diegolmello diegolmello requested a deployment to official_android_build April 10, 2026 13:38 — with GitHub Actions Waiting
@diegolmello diegolmello requested a deployment to experimental_ios_build April 10, 2026 13:38 — with GitHub Actions Waiting
@diegolmello diegolmello requested a deployment to experimental_android_build April 10, 2026 13:38 — with GitHub Actions Waiting
When the user ended an incoming call before it connected,
handleObservedCallChanged sent the REST reject but never notified
CallKit to remove the call from the system Recents UI.

Also deduplicate MediaCallsAnswerResponse with MessageResponse,
and remove unnecessary import RocketChat that was causing module
resolution failures in the Libraries target.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ios/RocketChatRN.xcodeproj/project.pbxproj`:
- Line 370: MediaCallsAnswerRequest.swift currently has only one PBXBuildFile
entry so it's only compiled into the RocketChatRN target; add a second
PBXBuildFile entry (with a new unique PBX identifier) referencing the same
fileRef (MediaCallsAnswerRequest.swift) and include that new PBXBuildFile in the
Rocket.Chat target's Sources list to mirror the dual-target pattern used by
other shared Swift files (e.g., VoipService.swift), ensuring both RocketChatRN
and Rocket.Chat build the file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f5e0215b-90b1-4f66-8b91-8ed591bfc8e6

📥 Commits

Reviewing files that changed from the base of the PR and between ba637f8 and ff477fd.

⛔ Files ignored due to path filters (1)
  • ios/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • ios/Libraries/VoipService.swift
  • ios/RocketChatRN.xcodeproj/project.pbxproj
  • ios/Shared/RocketChat/API/Requests/MediaCallsAnswerRequest.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • ios/Libraries/VoipService.swift
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: format
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate

Applied to files:

  • ios/RocketChatRN.xcodeproj/project.pbxproj
📚 Learning: 2026-03-05T06:06:19.755Z
Learnt from: divyanshu-patil
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6957
File: ios/RCTWatchModule.mm:19-24
Timestamp: 2026-03-05T06:06:19.755Z
Learning: In the Rocket.Chat React Native iOS app, `WCSession` (WatchConnectivity) is activated with its delegate in `ios/RocketChat Watch App/Loaders/WatchSession.swift`, not in `RCTWatchModule.mm`. Since `WCSession.defaultSession` is a singleton, activating it once in `WatchSession.swift` is sufficient; `RCTWatchModule.mm` does not need to re-activate or re-set the delegate.

Applied to files:

  • ios/RocketChatRN.xcodeproj/project.pbxproj
🔇 Additional comments (1)
ios/Shared/RocketChat/API/Requests/MediaCallsAnswerRequest.swift (1)

10-41: Nice extraction of the answer REST payload.

Keeping this request isolated here makes the accept/reject migration much easier to follow, and the conditional supportedFeatures serialization matches the two call paths cleanly.

…RocketChat target

Deleted the duplicate copy at Shared/RocketChat/API/ and kept the one
at Shared/RocketChat/API/Requests/ to match SendMessage.swift layout.
Added PBXBuildFile entry for the RocketChat target so VoipService.swift
can reference MediaCallsAnswerRequest when compiled into that target.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
ios/RocketChatRN.xcodeproj/project.pbxproj (1)

1144-1151: Remove the orphaned Deleted Rogue API Group.

This adds a second top-level RocketChat group that only contains an empty placeholder group. It won’t affect the build, but it will make the navigator misleading.

Cleanup diff
-		543368E8E0F7A6A03AD7C8F9 /* RocketChat */ = {
-			isa = PBXGroup;
-			children = (
-				9327C58E3506F20CD4FCE7E0 /* API */,
-			);
-			name = RocketChat;
-			sourceTree = "<group>";
-		};
...
-				543368E8E0F7A6A03AD7C8F9 /* RocketChat */,
...
-		9327C58E3506F20CD4FCE7E0 /* API */ = {
-			isa = PBXGroup;
-			children = (
-			);
-			name = "Deleted Rogue API Group";
-			sourceTree = "<group>";
-		};

Also applies to: 1214-1214, 1233-1239

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ios/RocketChatRN.xcodeproj/project.pbxproj` around lines 1144 - 1151, Remove
the orphaned duplicate top-level PBXGroup block (the PBXGroup with GUID
543368E8E0F7A6A03AD7C8F9 named "RocketChat" that only contains the child GUID
9327C58E3506F20CD4FCE7E0 /* API */) and any referenced empty child group entries
(e.g., 9327C58E3506F20CD4FCE7E0) from the project.pbxproj; also remove any
references to these GUIDs from other PBXGroup children arrays so only the real
RocketChat group remains (check the other duplicate blocks mentioned in the
review and delete the redundant PBXGroup and its child placeholders).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@ios/RocketChatRN.xcodeproj/project.pbxproj`:
- Around line 1144-1151: Remove the orphaned duplicate top-level PBXGroup block
(the PBXGroup with GUID 543368E8E0F7A6A03AD7C8F9 named "RocketChat" that only
contains the child GUID 9327C58E3506F20CD4FCE7E0 /* API */) and any referenced
empty child group entries (e.g., 9327C58E3506F20CD4FCE7E0) from the
project.pbxproj; also remove any references to these GUIDs from other PBXGroup
children arrays so only the real RocketChat group remains (check the other
duplicate blocks mentioned in the review and delete the redundant PBXGroup and
its child placeholders).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 186b3c92-f02d-441c-8b04-957d42980136

📥 Commits

Reviewing files that changed from the base of the PR and between ff477fd and 65b3789.

📒 Files selected for processing (1)
  • ios/RocketChatRN.xcodeproj/project.pbxproj
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: format
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate
📚 Learning: 2026-04-07T17:49:17.538Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat.ReactNative PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-07T17:49:17.538Z
Learning: Applies to app/lib/services/voip/**/*.{ts,tsx} : Implement VoIP with WebRTC peer-to-peer audio calls in app/lib/services/voip/ using Zustand stores instead of Redux, with native CallKit (iOS) and Telecom (Android) integration; keep VoIP and VideoConf separate

Applied to files:

  • ios/RocketChatRN.xcodeproj/project.pbxproj
🔇 Additional comments (1)
ios/RocketChatRN.xcodeproj/project.pbxproj (1)

370-372: MediaCallsAnswerRequest.swift is wired into the shared native targets correctly.

The file reference, group placement, and Sources memberships line up cleanly for RocketChatRN, Rocket.Chat, and NotificationService.

Also applies to: 660-660, 893-893, 2157-2157, 2380-2380, 2439-2439

Conflict in ios/RocketChatRN.xcodeproj/project.pbxproj: both branches
modified Pods-related entries with different UUIDs (different pod install
runs). Resolution: take feat.voip-lib-new as base, inject
MediaCallsAnswerRequest entries from refactor.ddp-ios, then re-run
pod install to regenerate consistent UUIDs.

- Added MediaCallsAnswerRequest.swift PBXBuildFile entries for
  RocketChatRN, NotificationService, and Rocket.Chat targets
- Added PBXFileReference for MediaCallsAnswerRequest.swift
- Added PBXGroup children entry for the file
- Added PBXSourcesBuildPhase entries for all three targets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant