Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Dit artikel bevat uitgebreide richtlijnen voor externe en externe ontwikkelaars over het integreren van functies met behulp van de Continuity SDK in uw toepassingen. De Continuity SDK maakt naadloze ervaringen tussen apparaten mogelijk, zodat gebruikers activiteiten op verschillende platforms kunnen hervatten, waaronder Android en Windows.
Door deze richtlijnen te volgen, kunt u een soepele en geïntegreerde gebruikerservaring op meerdere apparaten maken door gebruik te maken van de XDR met behulp van Continuity SDK.
Belangrijk
Onboarding om te hervatten in Windows
Resume is een beperkte toegang-functie (LAF). Als u access wilt krijgen voor deze API, moet u goedkeuring van Microsoft krijgen om samen te werken met het pakket Koppeling naar Windows op mobiele Android-apparaten.
Als u access wilt aanvragen, e-mailt u wincrossdeviceapi@microsoft.com met de onderstaande informatie:
- Een beschrijving van uw gebruikerservaring
- Een schermopname van uw toepassing waarbij een gebruiker systeemeigen toegang heeft tot internet of documenten
- De PackageId van uw toepassing
- De URL van de Google Play Store voor uw toepassing
Als de aanvraag is goedgekeurd, ontvangt u instructies voor het ontgrendelen van de functie. Goedkeuringen worden gebaseerd op uw communicatie, mits uw scenario voldoet aan de beschreven scenariovereisten.
Vereiste voorwaarden
Voor Android-toepassingen moet u ervoor zorgen dat aan de volgende vereisten wordt voldaan voordat u de Continuity SDK integreert:
- Minimale SDK-versie: 24
- Kotlin-versie: 1.9.x
- Koppeling naar Windows (LTW): 1.241101.XX
Voor Windows-toepassingen moet aan de volgende vereisten worden voldaan:
- Minimale Windows-versie: Windows 11
- Ontwikkelomgeving: Visual Studio 2019 of hoger
Opmerking
iOS-toepassingen worden momenteel niet ondersteund voor integratie met de Continuity SDK.
Uw ontwikkelomgeving configureren
De volgende secties bevatten stapsgewijze instructies voor het instellen van de ontwikkelomgeving voor zowel Android- als Windows-toepassingen.
Android-installatie
Voer de volgende stappen uit om de ontwikkelomgeving voor Android in te stellen:
Als u de bundel wilt instellen, downloadt en gebruikt u het .aar-bestand via bibliotheken in de volgende releases: Windows Cross-Device SDK-releases.
Voeg de metatags toe aan het AndroidManifest.xml-bestand van uw Android-toepassing. Het volgende codefragment laat zien hoe u de vereiste metatags toevoegt:
<meta-data android:name="com.microsoft.crossdevice.resumeActivityProvider" android:value="true" /> <meta-data android:name="com.microsoft.crossdevice.trigger.PartnerApp" android:value="4" />
API-integratiestappen
Na de manifestdeclaraties kunnen app-ontwikkelaars eenvoudig hun app-context verzenden door een eenvoudig codevoorbeeld te volgen.
De app moet:
- Initialiseer/De-initialiseer de Continuity SDK.
- De app moet de juiste tijd bepalen om de functies Initialize en DeInitialize aan te roepen.
- Nadat u de functie Initialize hebt aangeroepen, moet een callback die IAppContextEventHandler implementeert, worden geactiveerd.
-
AppContext verzenden/verwijderen:
- Als onContextRequestReceived wordt aangeroepen nadat de SDK is geïnitialiseerd, geeft dit aan dat de verbinding tot stand is gebracht. De app kan vervolgens AppContext verzenden (inclusief maken en bijwerken) naar LTW of AppContext verwijderen uit LTW.
- Als er geen verbinding is tussen de telefoon en pc en de app AppContext naar LTW verzendt, ontvangt de app onContextResponseError met het bericht 'PC is niet verbonden'.
- Wanneer de verbinding opnieuw tot stand is gebracht, wordt onContextRequestReceived opnieuw aangeroepen. De app kan vervolgens de huidige AppContext verzenden naar LTW.
- Nadat onSyncServiceDisconnected of de sdk is gedeinitialaliseerd, mag de app geen AppContext verzenden.
Hieronder ziet u een codevoorbeeld. Raadpleeg de beschrijving van AppContext voor alle vereiste en optionele velden in AppContext.
Het volgende Android-codefragment laat zien hoe u API-aanvragen maakt met behulp van de Continuity SDK:
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import com.microsoft.crossdevicesdk.continuity.AppContext
import com.microsoft.crossdevicesdk.continuity.AppContextManager
import com.microsoft.crossdevicesdk.continuity.ContextRequestInfo
import com.microsoft.crossdevicesdk.continuity.IAppContextEventHandler
import com.microsoft.crossdevicesdk.continuity.IAppContextResponse
import com.microsoft.crossdevicesdk.continuity.LogUtils
import com.microsoft.crossdevicesdk.continuity.ProtocolConstants
import java.util.UUID
class MainActivity : AppCompatActivity() {
//Make buttons member variables ---
private lateinit var buttonSend: Button
private lateinit var buttonDelete: Button
private lateinit var buttonUpdate: Button
private val appContextResponse = object : IAppContextResponse {
override fun onContextResponseSuccess(response: AppContext) {
Log.d("MainActivity", "onContextResponseSuccess")
runOnUiThread {
Toast.makeText(
this@MainActivity,
"Context response success: ${response.contextId}",
Toast.LENGTH_SHORT
).show()
}
}
override fun onContextResponseError(response: AppContext, throwable: Throwable) {
Log.d("MainActivity", "onContextResponseError: ${throwable.message}")
runOnUiThread {
Toast.makeText(
this@MainActivity,
"Context response error: ${throwable.message}",
Toast.LENGTH_SHORT
).show()
// Check if the error message contains the specific string
if (throwable.message?.contains("PC is not connected") == true) {
//App should stop sending intent once this callback is received
}
}
}
}
private lateinit var appContextEventHandler: IAppContextEventHandler
private val _currentAppContext = MutableLiveData<AppContext?>()
private val currentAppContext: LiveData<AppContext?> get() = _currentAppContext
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
LogUtils.setDebugMode(true)
var ready = false
buttonSend = findViewById(R.id.buttonSend)
buttonDelete = findViewById(R.id.buttonDelete)
buttonUpdate = findViewById(R.id.buttonUpdate)
setButtonDisabled(buttonSend)
setButtonDisabled(buttonDelete)
setButtonDisabled(buttonUpdate)
buttonSend.setOnClickListener {
if (ready) {
sendResumeActivity()
}
}
buttonDelete.setOnClickListener {
if (ready) {
deleteResumeActivity()
}
}
buttonUpdate.setOnClickListener {
if (ready) {
updateResumeActivity()
}
}
appContextEventHandler = object : IAppContextEventHandler {
override fun onContextRequestReceived(contextRequestInfo: ContextRequestInfo) {
LogUtils.d("MainActivity", "onContextRequestReceived")
ready = true
setButtonEnabled(buttonSend)
setButtonEnabled(buttonDelete)
setButtonEnabled(buttonUpdate)
}
override fun onInvalidContextRequestReceived(throwable: Throwable) {
Log.d("MainActivity", "onInvalidContextRequestReceived")
}
override fun onSyncServiceDisconnected() {
Log.d("MainActivity", "onSyncServiceDisconnected")
ready = false
setButtonDisabled(buttonSend)
setButtonDisabled(buttonDelete)
}
}
// Initialize the AppContextManager
AppContextManager.initialize(this.applicationContext, appContextEventHandler)
// Update currentAppContext text view.
val textView = findViewById<TextView>(R.id.appContext)
currentAppContext.observe(this, Observer { appContext ->
appContext?.let {
textView.text =
"Current app context: ${it.contextId}\n App ID: ${it.appId}\n Created: ${it.createTime}\n Updated: ${it.lastUpdatedTime}\n Type: ${it.type}"
Log.d("MainActivity", "Current app context: ${it.contextId}")
} ?: run {
textView.text = "No current app context available"
Log.d("MainActivity", "No current app context available")
}
})
}
// Send resume activity to LTW
private fun sendResumeActivity() {
val appContext = AppContext().apply {
this.contextId = generateContextId()
this.appId = applicationContext.packageName
this.createTime = System.currentTimeMillis()
this.lastUpdatedTime = System.currentTimeMillis()
this.type = ProtocolConstants.TYPE_RESUME_ACTIVITY
}
_currentAppContext.value = appContext
AppContextManager.sendAppContext(this.applicationContext, appContext, appContextResponse)
}
// Delete resume activity from LTW
private fun deleteResumeActivity() {
currentAppContext.value?.let {
AppContextManager.deleteAppContext(
this.applicationContext,
it.contextId,
appContextResponse
)
_currentAppContext.value = null
} ?: run {
Toast.makeText(this, "No resume activity to delete", Toast.LENGTH_SHORT).show()
Log.d("MainActivity", "No resume activity to delete")
}
}
private fun updateResumeActivity() {
currentAppContext.value?.let {
it.lastUpdatedTime = System.currentTimeMillis()
AppContextManager.sendAppContext(this.applicationContext, it, appContextResponse)
_currentAppContext.postValue(it)
} ?: run {
Toast.makeText(this, "No resume activity to update", Toast.LENGTH_SHORT).show()
Log.d("MainActivity", "No resume activity to update")
}
}
private fun setButtonDisabled(button: Button) {
button.isEnabled = false
button.alpha = 0.5f
}
private fun setButtonEnabled(button: Button) {
button.isEnabled = true
button.alpha = 1.0f
}
override fun onDestroy() {
super.onDestroy()
// Deinitialize the AppContextManager
AppContextManager.deInitialize(this.applicationContext)
}
override fun onStart() {
super.onStart()
// AppContextManager.initialize(this.applicationContext, appContextEventHandler)
}
override fun onStop() {
super.onStop()
// AppContextManager.deInitialize(this.applicationContext)
}
private fun generateContextId(): String {
return "${packageName}.${UUID.randomUUID()}"
}
}
Integratievalidatiestappen
Voer de volgende stappen uit om de integratie van de Continuity SDK in uw toepassing te valideren:
Voorbereiding
De volgende stappen zijn vereist om de integratievalidatie voor te bereiden:
Zorg ervoor dat de private LTW is geïnstalleerd.
Ltw verbinden met uw pc:
Raadpleeg Hoe u uw mobiele apparaat op uw pc beheert voor instructies.
Opmerking
Als u na het scannen van de QR-code niet wordt omgeleid naar LTW, opent u EERST LTW en scant u de QR-code in de app.
Controleer of de partner-app de Continuity SDK heeft geïntegreerd.
Validation
Volg vervolgens deze stappen om de integratie te valideren:
- Start de app en initialiseer de SDK. Controleer of onContextRequestReceived is aangeroepen.
- Nadat onContextRequestReceived is aangeroepen, kan de app de AppContext verzenden naar LTW. Als onContextResponseSuccess wordt aangeroepen nadat AppContext is verzonden, is de SDK-integratie geslaagd.
- Als de app AppContext verzendt terwijl de pc is vergrendeld of verbroken, controleert u of onContextResponseError wordt aangeroepen met 'PC is niet verbonden'.
- Wanneer de verbinding is hersteld, moet u ervoor zorgen dat onContextRequestReceived opnieuw wordt aangeroepen en de app vervolgens de huidige AppContext naar LTW kan verzenden.
In de onderstaande schermopname ziet u de logboekvermelding wanneer de verbinding met de pc is verbroken met het foutbericht 'PC is niet verbonden' en de logboekvermelding na opnieuw verbinding maken wanneer onContextRequestReceived opnieuw wordt aangeroepen.
AppContext
XDR definieert AppContext als metagegevens waarmee XDR begrijpt welke app moet worden hervat, samen met de context waarmee de toepassing moet worden hervat. Apps kunnen activiteiten gebruiken om gebruikers in staat te stellen terug te gaan naar wat ze in hun app deden, op meerdere apparaten. Activiteiten die zijn gemaakt door een mobiele app, worden weergegeven op de Windows-apparaten van gebruikers zolang deze apparaten zijn ingericht voor Cross Device Experience Host (CDEH).
Elke toepassing is anders, en is het aan Windows om begrip te krijgen van de doeltoepassing voor het hervatten van en ligt het bij specifieke toepassingen in Windows om begrip te krijgen van de context. XDR stelt een algemeen schema voor dat kan voldoen aan vereisten voor scenario's voor het hervatten van apps van zowel eerste als derde partijen.
contextId
- Vereist: Ja
- Beschrijving: Dit is een unieke id die wordt gebruikt om een AppContext van een andere te onderscheiden. Het zorgt ervoor dat elke AppContext uniek identificeerbaar is.
- Gebruik: zorg ervoor dat u een unieke contextId genereert voor elke AppContext om conflicten te voorkomen.
type
- Vereist: Ja
- Beschrijving: Dit is een binaire vlag die aangeeft welk type AppContext wordt verzonden naar Koppeling naar Windows (LTW). De waarde moet consistent zijn met het requestedContextType.
- Gebruik: Stel deze vlag in op basis van het type context dat u verzendt. Bijvoorbeeld:
ProtocolConstants.TYPE_RESUME_ACTIVITY.
createTime
- Vereist: Ja
- Beschrijving: Deze tijdstempel vertegenwoordigt de aanmaaktijd van de AppContext.
- Gebruik: Noteer de exacte tijd waarop de AppContext wordt gemaakt.
intentUri
- Vereist: Nee, indien weblink is opgegeven
- Beschrijving: Deze URI geeft aan welke app de AppContext kan voortzetten van het oorspronkelijke apparaat.
- Gebruik: geef dit op als u een bepaalde app wilt opgeven om de context te verwerken.
weblink
- Vereist: Nee, indien intentUri is opgegeven
- Beschrijving: Deze URI wordt gebruikt om het webeindpunt van de toepassing te starten als ze ervoor kiezen geen Store-apps te gebruiken. Deze parameter wordt alleen gebruikt wanneer intentUri niet is opgegeven. Als beide worden opgegeven, wordt intentUri gebruikt om de toepassing in Windows te hervatten.
- Gebruik: Alleen te gebruiken als de toepassing wil hervatten op webeindpunten en niet op de store-toepassingen.
appId
- Vereist: Ja
- Beschrijving: Dit is de pakketnaam van de toepassing waarvoor de context is bedoeld.
- Gebruik: Stel dit in op de pakketnaam van uw toepassing.
title
- Vereist: Ja
- Beschrijving: Dit is de titel van de AppContext, zoals een documentnaam of webpaginatitel.
- Gebruik: Geef een betekenisvolle titel op die de AppContext vertegenwoordigt.
Voorbeeld
- Vereist: Nee
- Beschrijving: Dit zijn bytes van de voorbeeldafbeelding die de AppContext kunnen vertegenwoordigen.
- Gebruik: Geef een voorbeeldafbeelding op, indien beschikbaar om gebruikers een visuele weergave van de AppContext te geven.
Levensduur
- Vereist: Nee
- Beschrijving: Dit is de levensduur van de
AppContextin milliseconden. Deze wordt alleen gebruikt voor lopende scenario's. Als deze niet is ingesteld, is de standaardwaarde vijf minuten. - Gebruik: Stel dit in om te bepalen hoe lang de
AppContextwaarde geldig moet zijn. U kunt een waarde instellen tot maximaal 5 minuten. Elke grotere waarde wordt automatisch ingekort tot 5 minuten.
Intent-URI's
Met URI's kunt u een andere app starten om een specifieke taak uit te voeren, waardoor nuttige app-naar-app-scenario's mogelijk zijn. Zie Start de standaard-Windows app voor een URI en Deep Links naar app-inhoud maken | Android-ontwikkelaars voor meer informatie over het starten van apps met URI's.
API-antwoorden verwerken in Windows
In deze sectie wordt beschreven hoe u de API-antwoorden in Windows-toepassingen kunt verwerken. De Continuity SDK biedt een manier om de API-antwoorden voor Win32- en WinUI-apps te verwerken.
Voorbeeld van Win32-app
Voor win32-apps voor het starten van protocol-URI's zijn de volgende stappen vereist:
Eerst moet er als volgt een vermelding in het register worden gemaakt:
[HKEY_CLASSES_ROOT\partnerapp] @="URL:PartnerApp Protocol" "URL Protocol"="" [HKEY_CLASSES_ROOT\partnerapp\shell\open\command] @="\"C:\\path\\to\\PartnerAppExecutable.exe\" \"%1\""De start moet worden verwerkt in de hoofdfunctie van de Win32-app:
#include <windows.h> #include <shellapi.h> #include <string> #include <iostream> int CALLBACK wWinMain(HINSTANCE, HINSTANCE, PWSTR lpCmdLine, int) { // Check if there's an argument passed via lpCmdLine std::wstring cmdLine(lpCmdLine); std::wstring arguments; if (!cmdLine.empty()) { // Check if the command-line argument starts with "partnerapp://", indicating a URI launch if (cmdLine.find(L"partnerapp://") == 0) { // This is a URI protocol launch // Process the URI as needed // Example: Extract action and parameters from the URI arguments = cmdLine; // or further parse as required } else { // Launched by command line or activation APIs } } else { // Handle cases where no arguments were passed } return 0; }
WinUI-apps
Voor verpakte WinUI-apps kan de protocol-URI worden geregistreerd in het app-manifest van het project. De volgende stappen laten zien hoe u protocolactivering in een WinUI-app kunt afhandelen.
Eerst wordt de protocol-URI als volgt geregistreerd in het
Package.appxmanifestbestand:<Applications> <Application Id= ... > <Extensions> <uap:Extension Category="windows.protocol"> <uap:Protocol Name="alsdk"> <uap:Logo>images\icon.png</uap:Logo> <uap:DisplayName>SDK Sample URI Scheme</uap:DisplayName> </uap:Protocol> </uap:Extension> </Extensions> ... </Application> <Applications>
WinUI 3-voorbeeld
Het volgende codefragment laat zien hoe u protocolactivering kunt afhandelen in een C++ WinUI-app met Windows App SDK:
void App::OnActivated(winrt::Windows::ApplicationModel::Activation::IActivatedEventArgs const& args)
{
if (args.Kind() == winrt::Windows::ApplicationModel::Activation::ActivationKind::Protocol)
{
auto protocolArgs = args.as<winrt::Windows::ApplicationModel::Activation::ProtocolActivatedEventArgs>();
auto uri = protocolArgs.Uri();
std::wstring uriString = uri.AbsoluteUri().c_str();
//Process the URI as per argument scheme
}
}
Weblink
Als u een weblink gebruikt, wordt het webeindpunt van de toepassing gestart. App-ontwikkelaars moeten ervoor zorgen dat de weblink die is opgegeven vanuit hun Android-toepassing geldig is, omdat XDR de standaardbrowser van het systeem gebruikt om om te leiden naar de opgegeven weblink.
Argumenten verwerken die zijn verkregen van het hervatten op meerdere apparaten
Het is de verantwoordelijkheid van elke app om het ontvangen argument te deserialiseren en ontsleutelen en de informatie dienovereenkomstig verwerken om de doorlopende context van telefoon naar pc over te dragen. Als een oproep bijvoorbeeld moet worden overgedragen, moet de app die context van de telefoon kunnen communiceren en moet de desktop-app die context op de juiste manier begrijpen en doorgaan met laden.
Verwante inhoud
Windows developer