{"$schema": "https://raw.githubusercontent.com/guitaripod/wwdc-sessions/master/schema/transcript.schema.json", "id": "wwdc2026-226", "language": "eng", "source": "https://developer.apple.com/videos/play/wwdc2026/226", "wordCount": 2881, "segments": [{"start": 7.0, "text": "Hi, I'm Yaseen, a Software Engineer at Apple."}, {"start": 10.0, "text": "In this session, I'll show you how to deliver a rich, native conversation UI"}, {"start": 14.0, "text": "that puts your app right where people need it,"}, {"start": 16.0, "text": "from a full-screen presentation on the Lock Screen"}, {"start": 18.0, "text": "to seamless multitasking with the Dynamic Island."}, {"start": 22.0, "text": "It starts the moment a conversation comes in."}, {"start": 24.0, "text": "When your app adopts this API,"}, {"start": 26.0, "text": "its conversations get a full-screen presentation on the Lock Screen,"}, {"start": 29.0, "text": "complete with the contact's name, photo, and a standard set of controls."}, {"start": 33.0, "text": "This is exactly what appears when the phone rings."}, {"start": 40.0, "text": "Apps that adopt this API get the same presentation."}, {"start": 43.0, "text": "Conversations can also show up in Phone app Recents"}, {"start": 46.0, "text": "and in contact details."}, {"start": 48.0, "text": "Recents shows who the person spoke with and when,"}, {"start": 50.0, "text": "and they can tap to start a new conversation."}, {"start": 53.0, "text": "LiveCommunicationKit is the modern way to create communication apps"}, {"start": 56.0, "text": "that integrate with these system experiences."}, {"start": 58.0, "text": "If you have an app that uses traditional approaches,"}, {"start": 61.0, "text": "like the CXProvider API,"}, {"start": 62.0, "text": "now is a great time to move over to LiveCommunicationKit."}, {"start": 66.0, "text": "It provides a more flexible and feature-rich API"}, {"start": 68.0, "text": "to integrate all of the different types of real-time conversations"}, {"start": 71.0, "text": "that your app supports."}, {"start": 73.0, "text": "I'll start with the core concepts:"}, {"start": 75.0, "text": "what a conversation is;"}, {"start": 76.0, "text": "how it moves through its lifecycle;"}, {"start": 78.0, "text": "and how your app communicates with the system."}, {"start": 81.0, "text": "Then I'll walk through receiving conversations,"}, {"start": 84.0, "text": "from waking your app with a push notification"}, {"start": 86.0, "text": "to presenting the conversation on the Lock Screen."}, {"start": 89.0, "text": "Then, starting outgoing conversations from inside your app"}, {"start": 91.0, "text": "and making them available through Siri and Recents."}, {"start": 95.0, "text": "And finally, group conversations,"}, {"start": 97.0, "text": "managing participants and merging conversations together."}, {"start": 101.0, "text": "To explore how all of this works,"}, {"start": 103.0, "text": "I'll follow a group of college friends,"}, {"start": 105.0, "text": "David,"}, {"start": 106.0, "text": "Ryan,"}, {"start": 107.0, "text": "Andre,"}, {"start": 108.0, "text": "and Adam,"}, {"start": 109.0, "text": "as they use my audio conversation app"}, {"start": 111.0, "text": "to plan their annual reunion trip."}, {"start": 114.0, "text": "But first, a quick introduction to how LiveCommunicationKit works."}, {"start": 118.0, "text": "Every experience I just walked through is driven by a single object -"}, {"start": 122.0, "text": "a conversation."}, {"start": 123.0, "text": "A conversation represents a single real-time interaction between people."}, {"start": 128.0, "text": "It lives only as long as someone is in it."}, {"start": 130.0, "text": "When everyone leaves, it's gone."}, {"start": 133.0, "text": "A conversation has two parts:"}, {"start": 135.0, "text": "handles, which represent the people in the conversation,"}, {"start": 138.0, "text": "and capabilities, which describe what the conversation can do."}, {"start": 141.0, "text": "I'll start with handles."}, {"start": 144.0, "text": "A handle identifies a person."}, {"start": 146.0, "text": "It has three properties: kind, value, and display name."}, {"start": 150.0, "text": "I'll go through each one."}, {"start": 152.0, "text": "The kind tells the system what type of identifier the handle is:"}, {"start": 155.0, "text": "a phone number, an email address or a generic string."}, {"start": 158.0, "text": "If your app already identifies people by phone number or email,"}, {"start": 162.0, "text": "setting the right kind allows the system to match"}, {"start": 164.0, "text": "the person's handle to a saved contact"}, {"start": 166.0, "text": "and show their name and photo in the system conversation UI."}, {"start": 171.0, "text": "The value is the identifier itself -"}, {"start": 172.0, "text": "the phone number, email address, or generic string."}, {"start": 175.0, "text": "This is what the system uses to look up the contact"}, {"start": 178.0, "text": "and what your app gets back when someone redials from Recents."}, {"start": 182.0, "text": "And the display name is what the system shows"}, {"start": 184.0, "text": "when it can't match the handle to a contact."}, {"start": 186.0, "text": "Set this to the name your app already knows for the person"}, {"start": 189.0, "text": "so the conversation UI always has something to display."}, {"start": 193.0, "text": "Capabilities tell the system what a conversation can do."}, {"start": 196.0, "text": "The system uses them to decide which controls to show"}, {"start": 198.0, "text": "and which gestures to enable"}, {"start": 200.0, "text": "so that the conversation UI only offers what your app actually supports."}, {"start": 205.0, "text": "The system shows a standard set of in-conversation controls:"}, {"start": 208.0, "text": "Mute, Speaker, Keypad and More."}, {"start": 211.0, "text": "Some of them only appear when my app opts in."}, {"start": 214.0, "text": "Here, the pausing capability is declared"}, {"start": 217.0, "text": "so a long press on the Mute button puts the conversation on hold."}, {"start": 220.0, "text": "Without that capability, the long press does nothing."}, {"start": 224.0, "text": "The video capability tells the system this is a video conversation."}, {"start": 228.0, "text": "The video button itself is enabled by my app's provider configuration,"}, {"start": 232.0, "text": "which I'll cover later."}, {"start": 234.0, "text": "Capabilities can change over the lifetime of a conversation;"}, {"start": 237.0, "text": "when this one upgrades from audio to video,"}, {"start": 240.0, "text": "my app updates the capabilities"}, {"start": 241.0, "text": "and the system reflects the change immediately."}, {"start": 244.0, "text": "Now that you know what makes a conversation,"}, {"start": 247.0, "text": "I'll walk through how it moves through its lifecycle with the system."}, {"start": 250.0, "text": "When your app first reports a conversation to the system,"}, {"start": 253.0, "text": "the conversation starts in the idle state,"}, {"start": 255.0, "text": "and the device starts ringing."}, {"start": 257.0, "text": "While it's ringing, your app can begin its local setup."}, {"start": 261.0, "text": "When the person answers, your app sets the state to joining."}, {"start": 264.0, "text": "The system updates the UI to show the conversation as connecting"}, {"start": 267.0, "text": "while your app finishes setting up and gets ready to join."}, {"start": 270.0, "text": "No audio or video capture happens yet."}, {"start": 273.0, "text": "When your app finishes preparing,"}, {"start": 275.0, "text": "it sets the state to joined"}, {"start": 276.0, "text": "and starts capturing and sending audio and video,"}, {"start": 279.0, "text": "and the conversation is now live."}, {"start": 281.0, "text": "If the person switches to AirPods or connects to car Bluetooth,"}, {"start": 284.0, "text": "your app gets a route change notification and updates its capture pipeline to match."}, {"start": 290.0, "text": "If your app declares the pausing capability,"}, {"start": 292.0, "text": "the system enables its hold control."}, {"start": 294.0, "text": "When someone holds the conversation,"}, {"start": 297.0, "text": "the system asks your app to pause."}, {"start": 299.0, "text": "Your app pauses its media streams and reports the new state."}, {"start": 303.0, "text": "When the person resumes the conversation,"}, {"start": 305.0, "text": "the system asks your app to resume the conversation's media streams"}, {"start": 308.0, "text": "and report the change."}, {"start": 311.0, "text": "When the conversation ends,"}, {"start": 312.0, "text": "your app sets the state to leaving."}, {"start": 315.0, "text": "This is where your app tears down the conversation"}, {"start": 317.0, "text": "and cleans up its connections."}, {"start": 319.0, "text": "After teardown, your app sets the state to left,"}, {"start": 321.0, "text": "and the conversation is over."}, {"start": 324.0, "text": "How does your app actually drive all of this?"}, {"start": 326.0, "text": "I'll start with the architecture."}, {"start": 328.0, "text": "Your app drives the conversation lifecycle through the ConversationManager"}, {"start": 332.0, "text": "and its delegate."}, {"start": 333.0, "text": "Your app reports conversations and events through the manager."}, {"start": 337.0, "text": "Every time you tell the system about a new conversation"}, {"start": 340.0, "text": "or about a change to an existing one,"}, {"start": 342.0, "text": "you go through the manager."}, {"start": 343.0, "text": "That's how your conversations show up on the Lock Screen,"}, {"start": 346.0, "text": "in the Dynamic Island,"}, {"start": 347.0, "text": "and everywhere else."}, {"start": 350.0, "text": "The delegate is where your app responds to the system."}, {"start": 352.0, "text": "Whenever something needs to happen on a conversation,"}, {"start": 355.0, "text": "the action arrives at a delegate method,"}, {"start": 357.0, "text": "and your app does the work to fulfill it."}, {"start": 360.0, "text": "They communicate through actions."}, {"start": 362.0, "text": "When someone interacts with the system UI -"}, {"start": 364.0, "text": "for example, accepting a conversation from the Lock Screen"}, {"start": 367.0, "text": "or ending one from the Dynamic Island -"}, {"start": 370.0, "text": "the system creates an action and sends it to your delegate."}, {"start": 373.0, "text": "And when someone taps a button in your app's own UI,"}, {"start": 375.0, "text": "your app creates the action instead."}, {"start": 378.0, "text": "Every interaction,"}, {"start": 380.0, "text": "whether it starts from the system UI or from within the app,"}, {"start": 383.0, "text": "flows through the same delegate callback,"}, {"start": 385.0, "text": "so there's exactly one place to put the logic for each action."}, {"start": 388.0, "text": "That single code path means there's no duplicated state management"}, {"start": 391.0, "text": "and no risk of the app and the system getting out of sync."}, {"start": 395.0, "text": "Before my app can report any conversations,"}, {"start": 397.0, "text": "it needs a ConversationManager."}, {"start": 399.0, "text": "Here's how my app creates one."}, {"start": 402.0, "text": "The ConversationManager's configuration"}, {"start": 404.0, "text": "tells the system everything it needs"}, {"start": 405.0, "text": "to present and manage conversations for your app."}, {"start": 409.0, "text": "You can update this configuration at any time during the app's lifetime."}, {"start": 413.0, "text": "Here, my app provides a ringtone from its bundle"}, {"start": 416.0, "text": "and a PNG of its icon."}, {"start": 418.0, "text": "The system presents both"}, {"start": 419.0, "text": "alongside my app's conversations across the system UI."}, {"start": 423.0, "text": "Next are the conversation group limits."}, {"start": 425.0, "text": "When conversations get merged together,"}, {"start": 427.0, "text": "they form a group."}, {"start": 429.0, "text": "These values cap how many groups can exist at once,"}, {"start": 432.0, "text": "and how many conversations each group can hold."}, {"start": 435.0, "text": "Then, there's whether my app's conversations"}, {"start": 437.0, "text": "show up in the Phone app's Recents list"}, {"start": 440.0, "text": "(for something like a one-time room that doesn't support redialing,"}, {"start": 443.0, "text": "pass 'false' to keep it out);"}, {"start": 445.0, "text": "and whether the app supports video,"}, {"start": 447.0, "text": "which enables the video button in the system UI;"}, {"start": 449.0, "text": "and, which handle types my app supports."}, {"start": 452.0, "text": "With that, my app creates its ConversationManager."}, {"start": 455.0, "text": "Because the manager is needed for the entire lifetime of the app,"}, {"start": 458.0, "text": "my app creates it right at launch."}, {"start": 461.0, "text": "Finally, my app sets the manager's delegate."}, {"start": 464.0, "text": "To continue conversations when the app is backgrounded or the device is locked,"}, {"start": 469.0, "text": "my app registers for the Audio and Voice over IP background modes"}, {"start": 473.0, "text": "in the app target's capabilities in Xcode."}, {"start": 476.0, "text": "With the ConversationManager configured,"}, {"start": 478.0, "text": "I'll walk through an incoming conversation from start to finish."}, {"start": 482.0, "text": "David wants to start planning this year's reunion trip"}, {"start": 485.0, "text": "so he starts a conversation with Adam to talk about potential destinations."}, {"start": 489.0, "text": "Adam's device is locked,"}, {"start": 491.0, "text": "but when David's conversation comes in,"}, {"start": 492.0, "text": "it appears right on the lock screen."}, {"start": 494.0, "text": "Here's how my app makes this happen."}, {"start": 497.0, "text": "When David starts the conversation with Adam,"}, {"start": 499.0, "text": "the app on his device builds a payload with two fields:"}, {"start": 502.0, "text": "a handle representing David's phone number"}, {"start": 505.0, "text": "and a unique identifier for the conversation."}, {"start": 508.0, "text": "David's app then sends that payload to my app's server,"}, {"start": 512.0, "text": "and the server forwards it to Adam's device."}, {"start": 514.0, "text": "When Adam's device receives the push,"}, {"start": 516.0, "text": "my app wakes up and decodes the payload."}, {"start": 519.0, "text": "It then uses the decoded handle to build a Conversation.Update."}, {"start": 523.0, "text": "This update also includes the conversation's capabilities,"}, {"start": 526.0, "text": "in this case, video, pausing, and merging."}, {"start": 530.0, "text": "My app then uses the update to report"}, {"start": 532.0, "text": "the conversation to the ConversationManager,"}, {"start": 534.0, "text": "and the system updates its UI to match."}, {"start": 537.0, "text": "PushKit is what wakes your app when a conversation arrives,"}, {"start": 540.0, "text": "and the app isn't already running."}, {"start": 542.0, "text": "When your app's server sends a Voice over IP push,"}, {"start": 545.0, "text": "PushKit launches your app"}, {"start": 546.0, "text": "and delivers the payload to the delegate method immediately."}, {"start": 549.0, "text": "Your app must report the conversation before the method returns"}, {"start": 552.0, "text": "or the system will terminate the app."}, {"start": 555.0, "text": "For more on Voice over IP push handling, check out the PushKit documentation."}, {"start": 560.0, "text": "Here's that PushKit delegate method in my app."}, {"start": 563.0, "text": "This is the entry point every incoming conversation goes through."}, {"start": 566.0, "text": "My app first extracts the handle and conversation UUID from the payload."}, {"start": 572.0, "text": "Then it builds a Conversation.Update with the decoded handle"}, {"start": 575.0, "text": "and the conversation's capabilities and reports it."}, {"start": 579.0, "text": "Adam sees the incoming conversation and slides to answer."}, {"start": 583.0, "text": "The system updates the UI to show the conversation is connecting"}, {"start": 586.0, "text": "then sends my app a JoinConversationAction through the delegate."}, {"start": 590.0, "text": "Every time someone answers, pauses or merges a conversation,"}, {"start": 594.0, "text": "the system delivers it to my app as an action."}, {"start": 597.0, "text": "My app handles them in one place,"}, {"start": 599.0, "text": "the perform action delegate callback."}, {"start": 601.0, "text": "The ConversationManager calls this every time an action comes in."}, {"start": 605.0, "text": "Inside, my app uses a switch statement to route each action type"}, {"start": 609.0, "text": "to its appropriate handler."}, {"start": 610.0, "text": "I'll trace the join action."}, {"start": 613.0, "text": "To handle the join action,"}, {"start": 615.0, "text": "my app first verifies that the ConversationManager"}, {"start": 617.0, "text": "is tracking a conversation matching the action's unique identifier."}, {"start": 621.0, "text": "If no matching conversation is found,"}, {"start": 623.0, "text": "my app fails the action."}, {"start": 625.0, "text": "Then it reports the conversation has started connecting,"}, {"start": 628.0, "text": "which will set the state to joining."}, {"start": 631.0, "text": "Once my app reports the connecting event,"}, {"start": 633.0, "text": "the system updates the conversation UI on Adam's device."}, {"start": 637.0, "text": "Now my app does its own setup,"}, {"start": 639.0, "text": "connecting to its server and configuring the media stream."}, {"start": 642.0, "text": "That work is async,"}, {"start": 643.0, "text": "so my app wraps it in a Task to keep the delegate responsive."}, {"start": 647.0, "text": "After setup finishes, my app reports the connection and fulfills the action."}, {"start": 652.0, "text": "If setup fails for any reason,"}, {"start": 653.0, "text": "my app marks the action accordingly"}, {"start": 655.0, "text": "so the system can clean up the conversation on its side."}, {"start": 658.0, "text": "The conversation is now in the joined state,"}, {"start": 660.0, "text": "and the UI updates accordingly ."}, {"start": 663.0, "text": "After weighing a few options,"}, {"start": 665.0, "text": "they settle on Iceland for this year's destination,"}, {"start": 668.0, "text": "and Adam taps the End button."}, {"start": 670.0, "text": "As soon as he does, the conversation transitions into the leaving state,"}, {"start": 674.0, "text": "and the UI updates to match."}, {"start": 677.0, "text": "The system then sends my app"}, {"start": 678.0, "text": "an EndConversationAction through the delegate,"}, {"start": 681.0, "text": "and my app tears down the media stream and fulfills the action."}, {"start": 684.0, "text": "And on Adam's device,"}, {"start": 686.0, "text": "the conversation disappears from the system UI ."}, {"start": 690.0, "text": "Next, I'll talk about how to place outgoing conversations."}, {"start": 693.0, "text": "Now that David and Adam have settled on Iceland,"}, {"start": 696.0, "text": "Adam starts a conversation with Ryan to figure out where the friends will stay."}, {"start": 700.0, "text": "This time, Adam starts the conversation from inside my app."}, {"start": 703.0, "text": "When someone starts a conversation from inside your app,"}, {"start": 706.0, "text": "you should report it to the system so people can keep the conversation going"}, {"start": 710.0, "text": "while they're using other apps."}, {"start": 712.0, "text": "To do this, your app creates a start action to ring the recipient's device."}, {"start": 716.0, "text": "Then it calls perform on the ConversationManager"}, {"start": 718.0, "text": "and handles the action in its delegate"}, {"start": 720.0, "text": "the same way as the join action from earlier."}, {"start": 723.0, "text": "Once the action is handled,"}, {"start": 725.0, "text": "the recipient either answers"}, {"start": 726.0, "text": "or your app reports that the conversation went unanswered or failed."}, {"start": 731.0, "text": "Here's how my app represents Adam's conversation with Ryan."}, {"start": 734.0, "text": "It builds a StartConversationAction"}, {"start": 737.0, "text": "with a fresh unique identifier and Ryan's handle."}, {"start": 740.0, "text": "Then it sends the action to the ConversationManager."}, {"start": 743.0, "text": "The manager first updates the system UI,"}, {"start": 746.0, "text": "then it forwards the action to the delegate."}, {"start": 749.0, "text": "From here, my app handles it the same way as the join action from earlier."}, {"start": 754.0, "text": "Once the conversation connects,"}, {"start": 756.0, "text": "Adam and Ryan look through a few options"}, {"start": 758.0, "text": "before finally settling on a cabin near Reykjavík."}, {"start": 761.0, "text": "With lodging decided,"}, {"start": 763.0, "text": "they catch up for a few more minutes,"}, {"start": 764.0, "text": "then they say their goodbyes and hang up."}, {"start": 767.0, "text": "After a conversation ends,"}, {"start": 768.0, "text": "people can redial them from Spotlight or Recents."}, {"start": 772.0, "text": "Your app handles this by having support for the start call intent."}, {"start": 775.0, "text": "This intent will be delivered to your app's scene to continue"}, {"start": 778.0, "text": "as an NSUserActivity."}, {"start": 780.0, "text": "When your app's conversations are saved to recents,"}, {"start": 782.0, "text": "Apple Intelligence already knows about them"}, {"start": 785.0, "text": "but, to surface your app's own representation of the conversation,"}, {"start": 789.0, "text": "donate your own intent at the end of each conversation as well."}, {"start": 793.0, "text": "To learn more about integrating intents in your app,"}, {"start": 795.0, "text": "check out the session \"Get to know App Intents\"."}, {"start": 798.0, "text": "Everything so far has been one-to-one."}, {"start": 801.0, "text": "Group conversations bring in multiple participants."}, {"start": 804.0, "text": "Having settled on a destination and lodging,"}, {"start": 806.0, "text": "Adam starts a group conversation with David and Ryan to plan their itinerary."}, {"start": 811.0, "text": "Group conversations track two types of members."}, {"start": 814.0, "text": "Members include everyone who's been invited to the conversation"}, {"start": 817.0, "text": "whereas activeRemoteMembers includes only those with media actively flowing."}, {"start": 822.0, "text": "The system needs both;"}, {"start": 823.0, "text": "members tells it how many participants the conversation has,"}, {"start": 826.0, "text": "and activeRemoteMembers tells it which ones are actively sending media."}, {"start": 831.0, "text": "When reporting a group conversation,"}, {"start": 833.0, "text": "my app creates a handle for each participant"}, {"start": 836.0, "text": "then creates a startAction"}, {"start": 838.0, "text": "with all invited members and reports it."}, {"start": 841.0, "text": "After the conversation starts, David and Ryan both join."}, {"start": 844.0, "text": "To report this change,"}, {"start": 846.0, "text": "my app builds a conversation update."}, {"start": 848.0, "text": "It names Adam as the localMember,"}, {"start": 851.0, "text": "declares the new activeRemoteMembership,"}, {"start": 853.0, "text": "and lists the capabilities the conversation supports,"}, {"start": 856.0, "text": "including merging and unmerging, which I'll come back to in a moment."}, {"start": 861.0, "text": "My app then reports the conversation update through the manager,"}, {"start": 864.0, "text": "and the system updates the conversation to reflect the new membership."}, {"start": 868.0, "text": "While Adam, David, and Ryan are working through the itinerary,"}, {"start": 872.0, "text": "Ryan realizes Andre still needs to confirm that the trip dates work for him..."}, {"start": 876.0, "text": "so, Ryan starts a separate conversation with Andre to loop him in."}, {"start": 881.0, "text": "Now two conversations are running in parallel,"}, {"start": 883.0, "text": "the original group with Adam, David, and Ryan,"}, {"start": 886.0, "text": "and Ryan's side conversation with Andre."}, {"start": 888.0, "text": "Ryan is in both conversations but only active on the one with Andre."}, {"start": 892.0, "text": "Once Andre and Ryan have agreed on the trip dates,"}, {"start": 895.0, "text": "they want to bring everyone back together to review the full plan."}, {"start": 898.0, "text": "Rather than the group having to hang up and start a new conversation,"}, {"start": 901.0, "text": "my app can merge the two together."}, {"start": 904.0, "text": "My app declares the merging capability,"}, {"start": 906.0, "text": "and the system enables its merge control UI."}, {"start": 909.0, "text": "When Ryan taps it, my app merges the two conversations,"}, {"start": 912.0, "text": "and the whole group, now with Andre,"}, {"start": 914.0, "text": "can finish planning their itinerary."}, {"start": 916.0, "text": "I'll walk through the conversation merging code next."}, {"start": 919.0, "text": "Unmerging follows the same delegation pattern,"}, {"start": 922.0, "text": "so once you've seen the merge handler, the unmerge one will seem familiar."}, {"start": 926.0, "text": "When two conversations merge,"}, {"start": 928.0, "text": "the ConversationManager delivers"}, {"start": 930.0, "text": "a MergeConversationAction to my app's delegate."}, {"start": 933.0, "text": "The merge action carries two unique identifiers,"}, {"start": 936.0, "text": "one for each conversation being merged."}, {"start": 938.0, "text": "The handler uses these to look up my app's local representation"}, {"start": 941.0, "text": "of both conversations."}, {"start": 943.0, "text": "If either one is missing (maybe it already ended),"}, {"start": 946.0, "text": "the handler fails the action immediately."}, {"start": 949.0, "text": "Once my app has both conversations,"}, {"start": 952.0, "text": "it combines the media streams on its server with combineStreams,"}, {"start": 956.0, "text": "then it reports the updated membership and fulfills the action."}, {"start": 959.0, "text": "If anything throws, the catch block fails the action instead."}, {"start": 964.0, "text": "Once my app has merged the two conversations,"}, {"start": 966.0, "text": "the system updates the conversation UI to reflect the new merged conversation."}, {"start": 971.0, "text": "With everyone in the same conversation,"}, {"start": 973.0, "text": "the group finalizes their itinerary:"}, {"start": 975.0, "text": "a soak in the Blue Lagoon,"}, {"start": 977.0, "text": "a day on the Golden Circle,"}, {"start": 978.0, "text": "and a few glacier hikes."}, {"start": 980.0, "text": "With the itinerary set,"}, {"start": 981.0, "text": "Andre and Ryan want to split off and book their flights together"}, {"start": 984.0, "text": "so they can sit next to each other on the plane."}, {"start": 987.0, "text": "Since the conversation supports the unmerging capability,"}, {"start": 990.0, "text": "they can go back to their own conversation"}, {"start": 992.0, "text": "while Adam and David wrap up the last few details."}, {"start": 995.0, "text": "That's LiveCommunicationKit."}, {"start": 997.0, "text": "From a single incoming conversation on the Lock Screen"}, {"start": 1000.0, "text": "all the way to merging group conversations,"}, {"start": 1002.0, "text": "the framework gives your app system-level conversation UI"}, {"start": 1005.0, "text": "everywhere people expect it:"}, {"start": 1006.0, "text": "on the Lock Screen,"}, {"start": 1008.0, "text": "in Recents, and Siri."}, {"start": 1010.0, "text": "Here's what to do next."}, {"start": 1012.0, "text": "Adopt ConversationManager"}, {"start": 1013.0, "text": "and report your first incoming conversation on the Lock Screen."}, {"start": 1017.0, "text": "Donate intents so Siri knows how to start conversations."}, {"start": 1021.0, "text": "Replace any transient tokens with stable handles to support redialing from Recents,"}, {"start": 1025.0, "text": "and make sure to keep conversation membership updated."}, {"start": 1028.0, "text": "Thanks for watching."}]}