iOS原生最近通话列表触发VOIP呼叫及CallKit元数据存储问询
Absolutely, using a custom URL Scheme is a perfect fit for your requirements—this is exactly how Apple's Speakerbox sample handles linking the Recents list to the app, and it works seamlessly for both outgoing call initiation from Recents and handling missed calls with metadata.
1. Why URL Scheme Works for Recents List Interaction
iOS’s Recents list relies on the CXHandle associated with each CallKit call record to determine which app to open when a user taps an entry. By using a custom URL Scheme as the .custom type handle, you’re telling the system to trigger your app’s URL handler when that entry is tapped—exactly what you need to launch your app and initiate the call with the right metadata.
2. Storing Metadata in CXHandle
You can’t store a raw custom object directly in CXHandle, but you can encode your metadata (like receiverID, call type, etc.) into a URL string and use that as the value of a .custom type CXHandle. Here’s how to do it step by step:
Step 1: Configure Your App’s URL Scheme
First, add your custom URL Scheme to Info.plist:
- Open your project’s Info tab, expand "URL Types"
- Add a new entry, set "URL Schemes" to something unique (e.g.,
yourappcalls) - Set "Role" to "Editor"
Step 2: Encode Metadata into the CXHandle Value
When creating a call (either outgoing or reporting a missed call), construct a URL string with your metadata as query parameters. For example:
// For an outgoing call with receiverID "12345" and video call type let callURLString = "yourappcalls://initiateCall?receiverID=12345&callType=video" let handle = CXHandle(type: .custom, value: callURLString) // When reporting a missed call (store the same metadata so tapping Recents reuses it) let missedCallUpdate = CXCallUpdate() missedCallUpdate.remoteHandle = handle // ... set other call update properties (localized caller name, etc.) callController.reportNewIncomingCall(with: UUID(), update: missedCallUpdate, completion: { error in })
Make sure to URL-encode any special characters in your metadata (e.g., if receiverID has spaces or symbols, use addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)).
Step 3: Handle the URL Scheme in Your App
When the user taps a Recents entry, iOS will open your app via the URL Scheme. You need to parse the URL to extract the metadata and initiate the call:
In SceneDelegate (for iOS 13+):
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) { guard let url = URLContexts.first?.url else { return } handleCallURL(url) } private func handleCallURL(_ url: URL) { guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false), let receiverID = components.queryItems?.first(where: { $0.name == "receiverID" })?.value, let callType = components.queryItems?.first(where: { $0.name == "callType" })?.value else { // Invalid URL, handle error return } // Use your WebRTC implementation to initiate the call with receiverID and callType yourCallManager.startCall(with: receiverID, isVideo: callType == "video") }
For older iOS versions, use AppDelegate’s application(_:open:options:) method instead.
Key Notes
- Uniqueness: Ensure your URL Scheme is unique to avoid conflicts with other apps.
- Sensitivity: Avoid putting sensitive data in the URL query parameters, as URLs can be logged by the system or other apps.
- Call Consistency: Make sure the
CXHandleyou use for outgoing calls matches what you set for missed calls—this ensures the Recents entry links correctly back to your app’s call initiation flow.
This approach aligns perfectly with Apple’s CallKit design patterns, and it’s exactly how the Speakerbox sample app implements Recents list integration. You’ll be able to handle both outgoing call taps and missed call re-initiation with all the metadata you need.
内容的提问来源于stack exchange,提问作者i70ro

