|
| 1 | +--- |
| 2 | +title: Cross Device Resume (XDR) Using Continuity SDK |
| 3 | +description: Guidelines for first & third party developers to integrate with Windows XDR experiences using the Continuity SDK. |
| 4 | +ms.date: 08/12/2025 |
| 5 | +ms.topic: how-to |
| 6 | +# customer intent: As a Windows developer, I want to learn how to integrate my app with Windows XDR experiences so that I can provide a seamless experience for my users. |
| 7 | +--- |
| 8 | + |
| 9 | +# Cross Device Resume (XDR) using Continuity SDK (Android and Windows Applications) |
| 10 | + |
| 11 | +This article provides comprehensive guidelines for first-party and third-party developers on how to integrate features using the Continuity SDK in your applications. The Continuity SDK enables seamless cross-device experiences, allowing users to resume activities across different platforms, including Android and Windows. |
| 12 | + |
| 13 | +By following this guidance, you can create a smooth and integrated user experience across multiple devices by leveraging the XDR using Continuity SDK. |
| 14 | + |
| 15 | +> [!IMPORTANT] |
| 16 | +> **Onboarding to Resume in Windows** |
| 17 | +> |
| 18 | +> Resume is a Limited Access Feature (LAF). To gain access to this API, you'll need to get approval from Microsoft to interoperate with the "Link to Windows" package on Android mobile devices. |
| 19 | +> |
| 20 | +> To request access, email [[email protected]](mailto:[email protected]) with the information listed below: |
| 21 | +> |
| 22 | +> - A description of your user experience |
| 23 | +> - A screenshot of your application where a user natively accesses web or documents |
| 24 | +> - The **PackageId** of your application |
| 25 | +> - The Google Play store URL for your application |
| 26 | +> |
| 27 | +> If the request is approved, you will receive instructions on how to unlock the feature. Approvals will be based on your communication, provided that your scenario meets the outlined [Scenario Requirements](/windows/cross-device/phonelink/#scenario-requirements). |
| 28 | +
|
| 29 | +## Prerequisites |
| 30 | + |
| 31 | +For Android applications, ensure the following requirements are met before integrating the Continuity SDK: |
| 32 | + |
| 33 | +- Minimum SDK Version: 24 |
| 34 | +- Kotlin Version: 1.9.x |
| 35 | +- Link to Windows (LTW): 1.241101.XX |
| 36 | + |
| 37 | +For Windows applications, ensure the following requirements are met: |
| 38 | + |
| 39 | +- Minimum Windows Version: Windows 11 |
| 40 | +- Development Environment: Visual Studio 2019 or later |
| 41 | + |
| 42 | +> [!NOTE] |
| 43 | +> iOS applications are not supported for integration with the Continuity SDK at this time. |
| 44 | +
|
| 45 | +## Configure your development environment |
| 46 | + |
| 47 | +The following sections provide step-by-step instructions for setting up the development environment for both Android and Windows applications. |
| 48 | + |
| 49 | +### Android setup |
| 50 | + |
| 51 | +To set up the development environment for Android, follow these steps: |
| 52 | + |
| 53 | +1. To set up the bundle, download and use the .aar file via libraries provided in the following releases: [Windows Cross-Device SDK releases](https://github.com/microsoft/Windows-Cross-Device/releases). |
| 54 | + |
| 55 | +1. Add the meta tags in the AndroidManifest.xml file of your Android application. The following snippet demonstrates how to add the required meta tags: |
| 56 | + |
| 57 | + ```xml |
| 58 | + <meta-data |
| 59 | + android:name="com.microsoft.crossdevice.resumeActivityProvider" |
| 60 | + android:value="true" /> |
| 61 | + |
| 62 | + <meta-data |
| 63 | + android:name="com.microsoft.crossdevice.trigger.PartnerApp" |
| 64 | + android:value="4" /> |
| 65 | + ``` |
| 66 | + |
| 67 | +## API integration steps |
| 68 | + |
| 69 | +After the manifest declarations, app developers can easily send their app context by following a simple code example. |
| 70 | + |
| 71 | +The App must: |
| 72 | + |
| 73 | +1. Initialize/DeInitialize the Continuity SDK: |
| 74 | + 1. The app should determine the appropriate time to call the Initialize and DeInitialize functions. |
| 75 | + 1. After calling the Initialize function, a callback that implements IAppContextEventHandler should be triggered. |
| 76 | +1. Send/Delete **AppContext**: |
| 77 | + 1. After initializing the SDK, if **onContextRequestReceived** is called, it indicates the connection is established. The app can then send (including create and update) **AppContext** to LTW or delete **AppContext** from LTW. |
| 78 | + 1. After **onSyncServiceDisconnected** or deinitializing the SDK, the app should not send an **AppContext**. |
| 79 | + |
| 80 | +Below is a code example. For all the required and optional fields in **AppContext**, please refer to the [AppContext description](#appcontext). |
| 81 | + |
| 82 | +The following Android code snippet demonstrates how to make API requests using the Continuity SDK: |
| 83 | + |
| 84 | +```kotlin MainActivity.kt |
| 85 | +class MainActivity : ComponentActivity() { |
| 86 | + |
| 87 | + // Required code for Continuity SDK integration |
| 88 | + private val appContextResponse = object : IAppContextResponse { |
| 89 | + override fun onContextResponseSuccess(response: AppContext) { |
| 90 | + Log.d("MainActivity", "onContextResponseSuccess") |
| 91 | + } |
| 92 | + |
| 93 | + override fun onContextResponseError(response: AppContext, throwable: Throwable) { |
| 94 | + Log.d("MainActivity", "onContextResponseError") |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + private lateinit var appContextEventHandler: IAppContextEventHandler |
| 99 | + |
| 100 | + private val appContext: AppContext = AppContext() |
| 101 | + |
| 102 | + override fun onCreate(savedInstanceState: Bundle?) { |
| 103 | + super.onCreate(savedInstanceState) |
| 104 | + var ready = false |
| 105 | + // Existing code... |
| 106 | + |
| 107 | + // Required code for Continuity SDK integration |
| 108 | + appContextEventHandler = object : IAppContextEventHandler { |
| 109 | + override fun onContextRequestReceived(contextRequestInfo: ContextRequestInfo) { |
| 110 | + Log.d("MainActivity", "onContextRequestReceived") |
| 111 | + ready = true |
| 112 | + |
| 113 | + sendResume() |
| 114 | + } |
| 115 | + |
| 116 | + override fun onSyncServiceDisconnected() { |
| 117 | + Log.d("MainActivity", "onSyncServiceDisconnected") |
| 118 | + } |
| 119 | + |
| 120 | + override fun onInvalidContextRequestReceived(throwable: Throwable) { |
| 121 | + Log.d("MainActivity", "onInvalidContextRequestReceived") |
| 122 | + ready = false |
| 123 | + deleteResume() |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + // Required code for Continuity SDK integration |
| 128 | + AppContextManager.initialize(this.applicationContext, appContextEventHandler) |
| 129 | + } |
| 130 | + |
| 131 | + // Required code for Continuity SDK integration |
| 132 | + private fun sendResume() { |
| 133 | + appContext.setContextId("13f53be4-d0d1-448a-8c78-af28820af119") |
| 134 | + appContext.setAppId(this.packageName) |
| 135 | + appContext.type = ProtocolConstants.TYPE_RESUME_ACTIVITY |
| 136 | + |
| 137 | + // Set context fields. Refer to the AppContext section for detailed field descriptions. |
| 138 | + AppContextManager.sendAppContext(this.applicationContext, appContext, appContextResponse) |
| 139 | + } |
| 140 | + |
| 141 | + // Required code for Continuity SDK integration |
| 142 | + private fun deleteResume() { |
| 143 | + AppContextManager.deleteAppContext(this.applicationContext, "13f53be4-d0d1-448a-8c78-af28820af119", appContextResponse) |
| 144 | + } |
| 145 | + |
| 146 | + // Existing code |
| 147 | +} |
| 148 | +``` |
| 149 | + |
| 150 | +## Integration validation steps |
| 151 | + |
| 152 | +To validate the integration of the Continuity SDK in your application, follow these steps: |
| 153 | + |
| 154 | +### Preparation |
| 155 | + |
| 156 | +The following steps are required to prepare for the integration validation: |
| 157 | + |
| 158 | +1. Ensure private LTW is installed. |
| 159 | +1. Connect LTW to your PC: |
| 160 | + |
| 161 | + Refer to [How to manage your mobile device on your PC](https://support.microsoft.com/topic/phone-link-requirements-and-setup-cd2a1ee7-75a7-66a6-9d4e-bf22e735f9e3#bkmk_cdeh_learn_more) for instructions. |
| 162 | + |
| 163 | + > [!NOTE] |
| 164 | + > If after scanning the QR code you aren't redirected to LTW, please open LTW first and scan the QR code within the app. |
| 165 | +
|
| 166 | +1. Verify that the partner app has integrated the Continuity SDK. |
| 167 | + |
| 168 | +### Validation |
| 169 | + |
| 170 | +Next, follow these steps to validate the integration: |
| 171 | + |
| 172 | +1. Launch the app and initialize the SDK. Confirm that **onContextRequestReceived** is called. |
| 173 | +1. After **onContextRequestReceived** has been called, the app can send the **AppContext** to LTW. If **onContextResponseSuccess** is called after sending **AppContext**, the SDK integration is successful. |
| 174 | + |
| 175 | +## AppContext |
| 176 | + |
| 177 | +XDR defines **AppContext** as metadata through which XDR can understand which app to resume, along with the context with which the application must be resumed. Apps can use activities to enable users to get back to what they were doing in their app, across multiple devices. Activities created by any mobile app appear on users' Windows device(s) so long as those devices have been Cross Device Experience Host (CDEH) provisioned. |
| 178 | + |
| 179 | +Every application is different, and it's up to Windows to understand the target application for resume and up to specific applications on Windows to understand the context. XDR is proposing a generic schema which can cater to requirements for all first party as well as third party app resume scenarios. |
| 180 | + |
| 181 | +### contextId |
| 182 | + |
| 183 | +- Required: Yes |
| 184 | +- Description: This is a unique identifier used to distinguish one **AppContext** from another. It ensures that each **AppContext** is uniquely identifiable. |
| 185 | +- Usage: Make sure to generate a unique contextId for each **AppContext** to avoid conflicts. |
| 186 | + |
| 187 | +### type |
| 188 | + |
| 189 | +- Required: Yes |
| 190 | +- Description: This is a binary flag that indicates the type of **AppContext** being sent to Link to Windows (LTW). The value should be consistent with the requestedContextType. |
| 191 | +- Usage: Set this flag according to the type of context you are sending. For example, `ProtocolConstants.TYPE_RESUME_ACTIVITY`. |
| 192 | + |
| 193 | +### createTime |
| 194 | + |
| 195 | +- Required: Yes |
| 196 | +- Description: This timestamp represents the creation time of the **AppContext**. |
| 197 | +- Usage: Record the exact time when the **AppContext** is created. |
| 198 | + |
| 199 | +### intentUri |
| 200 | + |
| 201 | +- Required: No, if **weblink** is provided |
| 202 | +- Description: This URI indicates which app can continue the **AppContext** handed over from the originating device. |
| 203 | +- Usage: Provide this if you want to specify a particular app to handle the context. |
| 204 | + |
| 205 | +### weblink |
| 206 | + |
| 207 | +- Required: No, if **intentUri** is provided |
| 208 | +- Description: This URI is used to launch the web endpoint of the application if they choose not to use store apps. This parameter is used only when **intentUri** is not provided. If both are provided, **intentUri** will be used to resume the application on Windows. |
| 209 | +- Usage: Only to be use if application wants to resume on web endpoints and not the store applications. |
| 210 | + |
| 211 | +### appId |
| 212 | + |
| 213 | +- Required: Yes |
| 214 | +- Description: This is the package name of the application the context is for. |
| 215 | +- Usage: Set this to the package name of your application. |
| 216 | + |
| 217 | +### title |
| 218 | + |
| 219 | +- Required: Yes |
| 220 | +- Description: This is the title of the **AppContext**, such as a document name or web page title. |
| 221 | +- Usage: Provide a meaningful title that represents the **AppContext**. |
| 222 | + |
| 223 | +### preview |
| 224 | + |
| 225 | +- Required: No |
| 226 | +- Description: These are bytes of the preview image that can represent the **AppContext**. |
| 227 | +- Usage: Provide a preview image if available to give users a visual representation of the **AppContext**. |
| 228 | + |
| 229 | +### LifeTime |
| 230 | + |
| 231 | +- Required: No |
| 232 | +- Description: This is the lifetime of the `AppContext` in milliseconds. It is only used for ongoing scenarios. If not set, the default value is 5 minutes. |
| 233 | +- Usage: Set this to define how long the `AppContext` should be valid. You can set a value up to a maximum of 5 minutes. Any greater value will automatically be shortened to 5 minutes. |
| 234 | + |
| 235 | +## Intent URIs |
| 236 | + |
| 237 | +URIs allow you to launch another app to perform a specific task, enabling helpful app-to-app scenarios. For more infomation about launching apps using URIs, see [Launch the default Windows app for a URI](/windows/apps/develop/launch/launch-default-app) and [Create Deep Links to App Content | Android Developers](https://developer.android.com/training/app-links/deep-linking). |
| 238 | + |
| 239 | +## Handling API responses in Windows |
| 240 | + |
| 241 | +This section describes how to handle the API responses in Windows applications. The Continuity SDK provides a way to handle the API responses for Win32, UWP, and Windows App SDK apps. |
| 242 | + |
| 243 | +### Win32 app example |
| 244 | + |
| 245 | +For Win32 apps to handle protocol URI launch, the following steps are required: |
| 246 | + |
| 247 | +1. First, an entry needs to be made to the registry as follows: |
| 248 | + |
| 249 | + ``` |
| 250 | + [HKEY_CLASSES_ROOT\partnerapp] |
| 251 | + @="URL:PartnerApp Protocol" |
| 252 | + "URL Protocol"="" |
| 253 | + |
| 254 | + [HKEY_CLASSES_ROOT\partnerapp\shell\open\command] |
| 255 | + @="\"C:\\path\\to\\PartnerAppExecutable.exe\" \"%1\"" |
| 256 | + ``` |
| 257 | +
|
| 258 | +1. The launch must be handled in the main function of the Win32 app: |
| 259 | +
|
| 260 | + ```cpp |
| 261 | + #include <windows.h> |
| 262 | + #include <shellapi.h> |
| 263 | + #include <string> |
| 264 | + #include <iostream> |
| 265 | + |
| 266 | + int CALLBACK wWinMain(HINSTANCE, HINSTANCE, PWSTR lpCmdLine, int) |
| 267 | + { |
| 268 | + // Check if there's an argument passed via lpCmdLine |
| 269 | + std::wstring cmdLine(lpCmdLine); |
| 270 | + std::wstring arguments; |
| 271 | + |
| 272 | + if (!cmdLine.empty()) |
| 273 | + { |
| 274 | + // Check if the command-line argument starts with "partnerapp://", indicating a URI launch |
| 275 | + if (cmdLine.find(L"partnerapp://") == 0) |
| 276 | + { |
| 277 | + // This is a URI protocol launch |
| 278 | + // Process the URI as needed |
| 279 | + // Example: Extract action and parameters from the URI |
| 280 | + arguments = cmdLine; // or further parse as required |
| 281 | + } |
| 282 | + else |
| 283 | + { |
| 284 | + // Launched by command line or activation APIs |
| 285 | + } |
| 286 | + } |
| 287 | + else |
| 288 | + { |
| 289 | + // Handle cases where no arguments were passed |
| 290 | + } |
| 291 | + |
| 292 | + return 0; |
| 293 | + } |
| 294 | + ``` |
| 295 | +
|
| 296 | +### UWP Apps |
| 297 | +
|
| 298 | +For UWP apps, the protocol URI can be registered in the project's app manifest. The following steps demonstrate how to handle protocol activation in a UWP app. |
| 299 | +
|
| 300 | +1. First, the protocol URI is registered in the `Package.appxmanifest` file as follows: |
| 301 | +
|
| 302 | + ```xml |
| 303 | + <Applications> |
| 304 | + <Application Id= ... > |
| 305 | + <Extensions> |
| 306 | + <uap:Extension Category="windows.protocol"> |
| 307 | + <uap:Protocol Name="alsdk"> |
| 308 | + <uap:Logo>images\icon.png</uap:Logo> |
| 309 | + <uap:DisplayName>SDK Sample URI Scheme</uap:DisplayName> |
| 310 | + </uap:Protocol> |
| 311 | + </uap:Extension> |
| 312 | + </Extensions> |
| 313 | + ... |
| 314 | + </Application> |
| 315 | + <Applications> |
| 316 | + ``` |
| 317 | +
|
| 318 | +1. Next, in the `App.xaml.cs` file, override the `OnActivated` method as follows: |
| 319 | +
|
| 320 | + ```csharp |
| 321 | + public partial class App |
| 322 | + { |
| 323 | + protected override void OnActivated(IActivatedEventArgs args) |
| 324 | + { |
| 325 | + if (args.Kind == ActivationKind.Protocol) |
| 326 | + { |
| 327 | + ProtocolActivatedEventArgs eventArgs = args as ProtocolActivatedEventArgs; |
| 328 | + // TODO: Handle URI activation |
| 329 | + // The received URI is eventArgs.Uri.AbsoluteUri |
| 330 | + } |
| 331 | + } |
| 332 | + } |
| 333 | + ``` |
| 334 | +
|
| 335 | +For more information on handling URI launch in UWP apps, see step 3 in [Handle URI activation](/windows/apps/develop/launch/handle-uri-activation#step-3-handle-the-activated-event). |
| 336 | +
|
| 337 | +### WinUI 3 example |
| 338 | +
|
| 339 | +The following code snippet demonstrates how to handle protocol activation in a C++ WinUI app with Windows App SDK: |
| 340 | +
|
| 341 | +```cpp |
| 342 | +void App::OnActivated(winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const& args) |
| 343 | +{ |
| 344 | + if (args.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::Protocol) |
| 345 | + { |
| 346 | + auto protocolArgs = args.as<winrt::Windows::ApplicationModel::Activation::ProtocolActivatedEventArgs>(); |
| 347 | + auto uri = protocolArgs.Uri(); |
| 348 | + std::wstring uriString = uri.AbsoluteUri().c_str(); |
| 349 | + //Process the URI as per argument scheme |
| 350 | + } |
| 351 | +} |
| 352 | +``` |
| 353 | + |
| 354 | +## Weblink |
| 355 | + |
| 356 | +Using a weblink will launch the web endpoint of the application. App developers need to ensure that the weblink provided from their Android application is valid because XDR will use default browser of the system to redirect to the weblink provided. |
| 357 | + |
| 358 | +## Handling arguments obtained from Cross Device Resume |
| 359 | + |
| 360 | +It is the responsibility of each app to deserialize and decrypt the argument received and process the information accordingly to transfer the ongoing context from phone to PC. For example, if a call needs to be transferred, the app must be able to communicate that context from phone and the desktop app must understand that context appropriately and continue loading. |
| 361 | + |
| 362 | +## Related content |
| 363 | + |
| 364 | +- [Handle URI activation](/windows/apps/develop/launch/handle-uri-activation) |
| 365 | +- [Integrate with Windows](index.md) |
| 366 | +- [Cross Device People API](cross-device-people-api.md) |
0 commit comments