Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Dieser Artikel enthält umfassende Richtlinien für Entwickler von Erstanbietern und Drittanbietern, wie Features mithilfe des Continuity SDK in Ihre Anwendungen integriert werden können. Das Continuity SDK ermöglicht eine nahtlose geräteübergreifende Benutzererfahrung, sodass Benutzer Aktivitäten auf verschiedenen Plattformen fortsetzen können, einschließlich Android und Windows.
Anhand dieser Anleitung können Sie eine reibungslose und integrierte Benutzeroberfläche auf mehreren Geräten erstellen, indem Sie den XDR mithilfe des Continuity SDK nutzen.
Von Bedeutung
Onboarding zum Fortsetzen in Windows
Resume ist ein eingeschränktes Access Feature (LAF). Um access zu dieser API zu erhalten, müssen Sie die Genehmigung von Microsoft erhalten, um mit dem Paket "Link zu Windows" auf mobilen Android-Geräten zu arbeiten.
Um Zugriff anzufordern, senden Sie eine E-Mail an wincrossdeviceapi@microsoft.com mit den unten aufgeführten Informationen:
- Eine Beschreibung Ihrer Benutzererfahrung
- Screenshot Ihrer Anwendung, in dem ein Benutzer nativ auf Web oder Dokumente zugreift
- Die PackageId Ihrer Anwendung
- Die Google Play Store-URL für Ihre Anwendung
Wenn die Anforderung genehmigt wurde, erhalten Sie Anweisungen zum Entsperren des Features. Genehmigungen basieren auf Ihrer Kommunikation, sofern Ihr Szenario die beschriebenen Szenarioanforderungen erfüllt.
Voraussetzungen
Stellen Sie für Android-Anwendungen sicher, dass die folgenden Anforderungen erfüllt sind, bevor Sie das Continuity SDK integrieren:
- Mindest-SDK-Version: 24
- Kotlin Version: 1.9.x
- Link zu Windows (LTW): 1.241101.XX
Stellen Sie für Windows-Anwendungen sicher, dass die folgenden Anforderungen erfüllt sind:
- Mindestversion von Windows: Windows 11
- Entwicklungsumgebung: Visual Studio 2019 oder höher
Hinweis
iOS-Anwendungen werden zurzeit nicht für die Integration mit dem Continuity SDK unterstützt.
Konfigurieren Ihrer Entwicklungsumgebung
Die folgenden Abschnitte enthalten schrittweise Anleitungen zum Einrichten der Entwicklungsumgebung für Android- und Windows-Anwendungen.
Android-Setup
Führen Sie die folgenden Schritte aus, um die Entwicklungsumgebung für Android einzurichten:
Um das Bundle einzurichten, laden Sie die .aar-Datei mithilfe von Bibliotheken herunter, die in den folgenden freigegebenen Versionen bereitgestellt werden: Windows Cross-Device SDK-Versionen.
Fügen Sie die Metatags in der AndroidManifest.xml Datei Ihrer Android-Anwendung hinzu. Der folgende Codeausschnitt veranschaulicht, wie die erforderlichen Metatags hinzugefügt werden:
<meta-data android:name="com.microsoft.crossdevice.resumeActivityProvider" android:value="true" /> <meta-data android:name="com.microsoft.crossdevice.trigger.PartnerApp" android:value="4" />
API-Integrationsschritte
Nach den Manifestdeklarationen können App-Entwickler ihren App-Kontext ganz einfach senden, indem Sie einem einfachen Codebeispiel folgen.
Die App muss:
- Initialisieren/Deinitialisieren des Continuity SDKs:
- Die App sollte den geeigneten Zeitpunkt für den Aufruf der Initialize- und DeInitialize-Funktionen bestimmen.
- Nach dem Aufrufen der Initialize-Funktion sollte ein Rückruf, der IAppContextEventHandler implementiert, ausgelöst werden.
-
AppContext senden/löschen:
- Nach der Initialisierung des SDK deutet ein Aufruf von onContextRequestReceived darauf hin, dass die Verbindung hergestellt ist. Die App kann dann AppContext (einschließlich Erstellen und Aktualisieren) an LTW senden oder AppContext aus LTW löschen.
- Wenn keine Verbindung zwischen dem Telefon und dem PC besteht und die App App AppContext an LTW sendet, empfängt die App "onContextResponseError " mit der Meldung "PC ist nicht verbunden".
- Wenn die Verbindung erneut hergestellt wird, wird "onContextRequestReceived " erneut aufgerufen. Die App kann dann den aktuellen AppContext an LTW senden.
- Nachdem onSyncServiceDisconnected oder der SDK-Deinitialisierung sollte die App keinen AppContext senden.
Nachfolgend sehen Sie ein Codebeispiel. Alle erforderlichen und optionalen Felder in AppContext finden Sie in der AppContext-Beschreibung.
Der folgende Android-Codeausschnitt veranschaulicht, wie API-Anforderungen mithilfe des Continuity SDK ausgeführt werden:
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()}"
}
}
Schritte zur Integrationsüberprüfung
Führen Sie die folgenden Schritte aus, um die Integration des Continuity SDK in Ihrer Anwendung zu überprüfen:
Vorbereitung
Die folgenden Schritte sind erforderlich, um die Integrationsüberprüfung vorzubereiten:
Stellen Sie sicher, dass das private LTW installiert ist.
Verbinden Sie LTW mit Ihrem PC:
Anweisungen finden Sie unter "So verwalten Sie Ihr mobiles Gerät auf Ihrem PC ".
Hinweis
Wenn Sie nach dem Scannen des QR-Codes nicht zu LTW umgeleitet werden, öffnen Sie bitte zuerst LTW und scannen Sie den QR-Code innerhalb der App.
Stellen Sie sicher, dass die Partner-App das Continuity SDK integriert hat.
Validation
Führen Sie als Nächstes die folgenden Schritte aus, um die Integration zu überprüfen:
- Starten Sie die App, und initialisieren Sie das SDK. Vergewissern Sie sich, dass onContextRequestReceived aufgerufen wird.
- Nachdem onContextRequestReceived aufgerufen wurde, kann die App den AppContext an LTW senden. Wenn onContextResponseSuccess nach dem Senden von AppContext aufgerufen wird, ist die SDK-Integration erfolgreich.
- Wenn die App AppContext sendet, während der PC gesperrt oder getrennt ist, überprüfen Sie, ob onContextResponseError mit "PC ist nicht verbunden" aufgerufen wird.
- Stellen Sie beim Wiederherstellen der Verbindung sicher, dass onContextRequestReceived erneut aufgerufen wird, und die App kann dann den aktuellen AppContext an LTW senden.
Der folgende Screenshot zeigt den Protokolleintrag, wenn der PC mit der Fehlermeldung "PC ist nicht verbunden" getrennt wird, und der Protokolleintrag nach der erneuten Verbindung, wenn onContextRequestReceived erneut aufgerufen wird.
AppContext
XDR definiert AppContext als Metadaten, über die XDR verstehen kann, welche App fortgesetzt werden soll, zusammen mit dem Kontext, mit dem die Anwendung fortgesetzt werden muss. Apps können Aktivitäten verwenden, um Benutzern die Möglichkeit zu geben, auf mehrere Geräte zurück zu den Aktionen in ihrer App zu gelangen. Aktivitäten, die von einer mobilen App erstellt werden, erscheinen auf den Windows-Geräten der Benutzer, solange diese Geräte als Cross Device Experience Host (CDEH) bereitgestellt wurden.
Jede Anwendung unterscheidet sich, und es liegt an Windows, die Zielanwendung für den Lebenslauf und bis zu bestimmten Anwendungen unter Windows zu verstehen, um den Kontext zu verstehen. XDR schlägt ein generisches Schema vor, das Anforderungen für alle Erstanbieter- sowie Drittanbieter-App-Wiederaufnahmeszenarien erfüllen kann.
contextId
- Erforderlich: Ja
- Beschreibung: Dies ist ein eindeutiger Bezeichner, der verwendet wird, um einen AppContext von einem anderen zu unterscheiden. Dadurch wird sichergestellt, dass jeder AppContext eindeutig identifizierbar ist.
- Verwendung: Erstellen Sie für jeden AppContext eine eindeutige ContextId, um Konflikte zu vermeiden.
type
- Erforderlich: Ja
- Beschreibung: Dies ist ein binäres Flag, das den Typ von AppContext angibt, der an "Link to Windows" (LTW) gesendet wird. Der Wert sollte mit dem requestedContextType konsistent sein.
- Verwendung: Legen Sie dieses Kennzeichen entsprechend dem Typ des Kontexts fest, den Sie senden. Beispiel:
ProtocolConstants.TYPE_RESUME_ACTIVITY.
Erstellungszeit
- Erforderlich: Ja
- Beschreibung: Dieser Zeitstempel stellt die Erstellungszeit des AppContext dar.
- Verwendung: Notieren Sie sich den genauen Zeitpunkt, zu dem der AppContext erstellt wird.
intentUri
- Erforderlich: Nein, wenn Weblink bereitgestellt wird
- Beschreibung: Dieser URI gibt an, welche App den appContext fortsetzen kann, der vom ursprünglichen Gerät übergeben wird.
- Verwendung: Geben Sie dies an, wenn Sie eine bestimmte App für die Verarbeitung des Kontexts angeben möchten.
Web-Verknüpfung
- Erforderlich: Nein, wenn intentUri bereitgestellt wird
- Beschreibung: Dieser URI wird verwendet, um den Webendpunkt der Anwendung zu starten, wenn sie sich entscheiden, keine Store-Apps zu verwenden. Dieser Parameter wird nur verwendet, wenn intentUri nicht bereitgestellt wird. Wenn beides angegeben wird, wird intentUri verwendet, um die Anwendung unter Windows fortzusetzen.
- Verwendung: Nur zu verwenden, wenn die Anwendung auf Webendpunkten und nicht auf den Speicheranwendungen fortgesetzt werden möchte.
App-ID
- Erforderlich: Ja
- Beschreibung: Dies ist der Paketname der Anwendung, für die der Kontext gilt.
- Verwendung: Legen Sie dies auf den Paketnamen Ihrer Anwendung fest.
title
- Erforderlich: Ja
- Beschreibung: Dies ist der Titel des AppContext, z. B. eines Dokumentnamens oder eines Webseitentitels.
- Verwendung: Geben Sie einen aussagekräftigen Titel an, der den AppContext darstellt.
Vorschau
- Erforderlich: Nein
- Beschreibung: Dies sind Bytes des Vorschaubilds, die den AppContext darstellen können.
- Verwendung: Bereitstellen eines Vorschaubilds, falls verfügbar, um Benutzern eine visuelle Darstellung des AppContext zu ermöglichen.
Lebensdauer
- Erforderlich: Nein
- Beschreibung: Dies ist die Lebensdauer der
AppContextin Millisekunden. Sie wird nur für laufende Szenarien verwendet. Wenn sie nicht festgelegt ist, beträgt der Standardwert 5 Minuten. - Verwendung: Legen Sie dies fest, um festzulegen, wie lange die Gültigkeitsdauer
AppContextbeträgt. Sie können einen Wert bis zu 5 Minuten festlegen. Jeder größere Wert wird automatisch auf 5 Minuten gekürzt.
Intent-URIs
URIs ermöglichen es Ihnen, eine andere App zu starten, um eine bestimmte Aufgabe auszuführen und hilfreiche App-zu-App-Szenarien zu ermöglichen. Weitere Informationen zum Starten von Apps mit URIs finden Sie unter Starten Sie die Standard-Windows-App für eine URI und Erstellen Sie Deep Links zu App-Inhalten | Android-Entwickler.
Behandeln von API-Antworten in Windows
In diesem Abschnitt wird beschrieben, wie die API-Antworten in Windows-Anwendungen behandelt werden. Das Continuity SDK bietet eine Möglichkeit, die API-Antworten für Win32-, UWP- und Windows App SDK-Apps zu behandeln.
Beispiel für Win32-App
Für Win32-Apps zum Behandeln des Protokoll-URI-Starts sind die folgenden Schritte erforderlich:
Zunächst muss ein Eintrag wie folgt im System-Registry erfolgen:
[HKEY_CLASSES_ROOT\partnerapp] @="URL:PartnerApp Protocol" "URL Protocol"="" [HKEY_CLASSES_ROOT\partnerapp\shell\open\command] @="\"C:\\path\\to\\PartnerAppExecutable.exe\" \"%1\""Der Start muss in der Hauptfunktion der Win32-App behandelt werden:
#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; }
UWP-Apps
Für UWP-Apps kann der Protokoll-URI im App-Manifest des project registriert werden. Die folgenden Schritte veranschaulichen die Behandlung der Protokollaktivierung in einer UWP-App.
Zunächst wird der Protokoll-URI wie folgt in der
Package.appxmanifestDatei registriert:<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>Als nächstes überschreiben Sie in der
App.xaml.csDatei dieOnActivatedMethode wie folgt:public partial class App { protected override void OnActivated(IActivatedEventArgs args) { if (args.Kind == ActivationKind.Protocol) { ProtocolActivatedEventArgs eventArgs = args as ProtocolActivatedEventArgs; // TODO: Handle URI activation // The received URI is eventArgs.Uri.AbsoluteUri } } }
Weitere Informationen zum Behandeln des URI-Starts in UWP-Apps finden Sie in Schritt 3 bei der Behandlung der URI-Aktivierung.
WinUI 3-Beispiel
Der folgende Codeausschnitt veranschaulicht, wie die Protokollaktivierung in einer C++-WinUI-App mit Windows App SDK behandelt wird:
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
Wenn Sie einen Weblink verwenden, wird der Webendpunkt der Anwendung gestartet. App-Entwickler müssen sicherstellen, dass der von ihrer Android-Anwendung bereitgestellte Weblink gültig ist, da XDR den Standardbrowser des Systems verwendet, um auf den bereitgestellten Weblink umzuleiten.
Verarbeiten von Argumenten, die von Cross Device Resume abgerufen werden
Es liegt in der Verantwortung jeder App, das empfangene Argument zu deserialisieren und zu entschlüsseln und die Informationen entsprechend zu verarbeiten, um den laufenden Kontext von Telefon zu PC zu übertragen. Wenn beispielsweise ein Anruf übertragen werden muss, muss die App diesen Kontext über Telefon kommunizieren können, und die Desktop-App muss diesen Kontext entsprechend verstehen und den Ladevorgang fortsetzen.
Verwandte Inhalte
Windows developer