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.
Mobile Android-Geräte, die das Paket "Link zu Windows" installiert haben, können programmgesteuert aktuelle Aufgaben aus Ihrer Android-App freigeben, um auf Ihrem Windows-PC fortgesetzt zu werden (z. B. Website-URLs, Dokumentlinks, Musiktitel usw.).
Cross Device Task Continuity entwickelt sich weiter, um das Continuity SDK zu verwenden, um eine tiefere native Integration in windows Taskbar zu bieten, um Kunden auf natürliche und intuitive Weise besser zu bedienen. Während die ursprüngliche Implementierung der Aufgabenkontinuitäts-App für Phone Link weiterhin unterstützt wird, empfehlen wir für neue Implementierungen die Verwendung von Cross Device Resume (XDR) im Continuity SDK für die Windows-Taskleistenintegration. Weitere Informationen: Cross Device Resume (XDR) mit Continuity SDK (Android- und Windows-Anwendungen).
Das Continuity SDK ermöglicht eine nahtlosere geräteübergreifende Oberfläche mit XDR (Cross Device Resume) mit Fortsetzungssymbolen für Aufgaben, damit Sie Ihre aktuellen Android-Geräteaufgaben direkt über die Windows-Taskleiste fortsetzen können (ohne dass sie auf die App-Schnittstelle "Phone Link" angewiesen werden müssen).
So integrieren Sie Ihre Android-App in die Aufgabenkontinuität von Phone Link
Erfahren Sie, wie Sie aktuelle Aufgaben aus Ihrer Android-App (z. B. Website-URLs, Dokumentlinks, Musiktitel usw.) programmgesteuert für einen Windows-PC freigeben, auf dem die Telefonverbindung eingerichtet wurde. Dieses Feature ist nur auf unterstützten Geräten für Telefonlink-Erfahrungen verfügbar.
Szenarioanforderungen
Die folgenden Bedingungen müssen erfüllt sein, damit Ihre Android-App auf die Aufgabenkontinuität "Verknüpfen mit Windows" zugreifen kann:
- DO sync valid web URLs to be accessible by the Windows PC
- DO sync cloud document links to be accessible by the Windows PC
- Synchronisieren Sie lokale Dokumentlinks mit dem Windows-PC, auf den über Ihre App auf dem mobilen Gerät zugegriffen werden muss.
- Synchronisieren Sie nicht öfters als 60 Mal pro Minute
- Synchronisieren Sie nicht, wenn der/die Benutzer*in Ihre App nicht verwendet
Surface "Telefonverknüpfung" und "Geräteübergreifendes Fortsetzen"
Der Telefonlink zeigt Ihren synchronisierten Inhalt im Knoten "Apps" unter "Zuletzt verwendet" und "Zuletzt verwendete Websites" und in einem Benachrichtigungs-Flyout an.
Geräteübergreifende Lebenslauf (Cross Device Resume, XDR) mithilfe des Continuity SDK (Android und Windows-Anwendungen) werden Ihre synchronisierten Inhalte auf der Windows-Taskleiste angezeigt.
Genehmigung des Features für eingeschränkten Zugriff (Limited Access Feature, LAF)
Die Aufgabenkontinuität von Telefonlinks ist ein Feature für eingeschränkten Zugriff (Limited Access Feature, LAF). Um Zugriff zu erhalten, müssen Sie die Genehmigung von Microsoft erhalten, um mit dem vorab geladenen Paket "Link zu Windows" auf mobilen Android-Geräten zu arbeiten.
Um den Zugriff anzufordern, senden Sie eine E-Mail mit den unten aufgeführten Informationen an wincrossdeviceapi@microsoft.com.
- Beschreibung Ihrer Benutzererfahrung
- Screenshot Ihrer Anwendung, in der ein*e Benutzer*in nativ auf das Web oder Dokumente zugreift
- Package-ID Ihrer Anwendung
- Google Play Store-Link für Ihre Anwendung
Wenn die Anforderung genehmigt wurde, erhalten Sie Anweisungen zum Entsperren des Features. Die Genehmigungen werden basierend auf den Angaben dazu erteilt, inwiefern das Szenario die oben beschriebenen Anforderungen für das Szenario erfüllt.
Datenverarbeitung
Mit der Kontinuität der Telefonverbindung verarbeitet und übertragen Microsoft Ihre Daten gemäß dem Microsoft-Servicevertrag und den Microsoft-Datenschutzbestimmungen. Daten, die an die verknüpften Benutzergeräte übertragen werden, können über die Cloud-Dienste von Microsoft verarbeitet werden, um eine zuverlässige Datenweitergabe zwischen den Geräten sicherzustellen. Die von dieser API verarbeiteten Daten werden nicht von den Cloud-Diensten von Microsoft gespeichert, die der Kontrolle durch den Endbenutzer/die Endbenutzerin unterliegen.
Das Continuity SDK, das Sie in Ihr App-Paket integrieren, stellt sicher, dass die für die API bereitgestellten Daten nur von vertrauenswürdigen Microsoft-Paketen behandelt werden.
Codebeispiele für die Integration von Telefonlinks
Nachfolgend finden Sie allgemeine Richtlinien und Codebeispiele für die Integration. Ausführliche Anleitungen zur Integration finden Sie im Kotlin-Dokument des SDK.
Manifestdeklarationen für Android-Apps
Das App-Manifest ist eine XML-Datei, die als Blaupause für Ihre Android-App dient. Die Deklarationsdatei enthält Informationen zum Betriebssystem über die Struktur, Komponenten, Berechtigungen usw. Ihrer App. Die folgenden Deklarationen sind für die Aufgabenkontinuität mit "Verknüpfen mit Windows" erforderlich.
Featuremetadaten
Partner-Apps müssen zuerst Metadaten in Ihrem App-Manifest registrieren.
Um am App-Kontextvertrag teilzunehmen, müssen Metadaten für den unterstützten App-Kontexttyp deklariert werden. So fügen Sie beispielsweise Metadaten des App-Kontextanbieters für das Feature "App-Handoff " hinzu:
<application...>
<meta-data
android:name="com.microsoft.crossdevice.applicationContextProvider"
android:value="true" />
</application>
Wenn Ihre App mehr als einen App-Kontext unterstützt, müssen alle Metadatentypen hinzugefügt werden. Zu den derzeit unterstützten Metadatentypen gehören:
<meta-data
android:name="com.microsoft.crossdevice.browserContextProvider"
android:value="true" />
<meta-data
android:name="com.microsoft.crossdevice.applicationContextProvider"
android:value="true" />
<meta-data
android:name="com.microsoft.crossdevice.resumeActivityProvider
android:value="true" />
Um einen neuen Typ hinzuzufügen, sollte das Metadatennamenformat "com.microsoft.crossdevice.xxxProvider" lauten.
Apps müssen auch die Metadaten des Triggertyps im Manifest deklarieren. Diese Deklarationen helfen dem System zu bestimmen, wie und wann die App Load-Time Weben (LTW) darüber benachrichtigen soll, dass bestimmte Features aktiv sind.
Bei einem Selbstbenachrichtigungsauslöser, bei dem die App selbst für die Benachrichtigung des Systems verantwortlich ist und auf allen Geräten aktiviert ist, unabhängig vom Originalgerätehersteller (OEM), sollte der Triggertyp wie folgt deklariert werden:
<application ...
<meta-data
android:name="com.microsoft.crossdevice.trigger.PartnerApp"
android:value="the sum value of all features' binary codes" />
</application>
Bei einem System-API-Trigger, bei dem die App system-APIs verwendet, um das Feature "Link zu Windows" auszulösen, aktiviert nur auf bestimmten OEM-Geräten, sollte der Triggertyp wie folgt deklariert werden:
<application ...
<meta-data
android:name="com.microsoft.crossdevice.trigger.SystemApi"
android:value="the sum value of all features' binary codes" />
</application>
Die Binären Codes der Features sind jetzt:
APPLICATION_CONTEXT: 1
BROWSER_HISTORY: 2
RESUME_ACTIVITY: 4
Die App-Manifestregistrierung kann wie in diesem Beispiel aussehen:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<application …
<!--
This is the meta-data represents this app supports XDR, LTW will check
the package before we request app context.
-->
<meta-data
android:name="com.microsoft.crossdevice.resumeActivityProvider"
android:value="true" />
<!--
This is the meta-data represents this app supports trigger from app, the
Value is the code of XDR feature, LTW will check if the app support partner
app trigger when receiving trigger broadcast.
-->
<meta-data
android:name="com.microsoft.crossdevice.trigger.PartnerApp"
android:value="4" />
</application>
</manifest>
Codebeispiel zum Senden des App-Kontexts
Nachdem die App-Manifestdeklarationen hinzugefügt wurden, müssen Partner-Apps mit "Link zu Windows" folgendes ausführen:
Ermitteln Sie die geeignete Anzeigedauer, um die Funktionen Initialize und DeInitialize für das Continuity SDK aufzurufen. Nach dem Aufrufen der Initialize-Funktion sollte ein Rückruf ausgelöst werden, der implementiert
IAppContextEventHandlerwird.Nach der Initialisierung des Continuity SDK, falls
onContextRequestReceived()aufgerufen, wird die Verbindung hergestellt. Die App kann dann (einschließlich Erstellen und Aktualisieren) an LTW sendenAppContextoder aus LTW löschenAppContext.
Vermeiden Sie das Senden vertraulicher Daten in AppContext, z. B. Zugriffstoken. Wenn die Lebensdauer zu kurz festgelegt ist, läuft die AppContext Lebensdauer möglicherweise ab, bevor sie an den PC gesendet wird. Es wird empfohlen, eine Mindestlebensdauer von mindestens 5 Minuten festzulegen.
class MainActivity : AppCompatActivity() {
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()
}
}
}
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
val buttonSend: Button = findViewById(R.id.buttonSend)
val buttonDelete: Button = findViewById(R.id.buttonDelete)
val buttonUpdate: Button = findViewById(R.id.buttonUpdate)
setButtonDisabled(buttonSend)
setButtonDisabled(buttonDelete)
setButtonDisabled(buttonUpdate)
buttonSend.setOnClickListener {
if (ready) {
sendAppContext()
}
}
buttonDelete.setOnClickListener {
if (ready) {
deleteAppContext()
}
}
buttonUpdate.setOnClickListener {
if (ready) {
updateAppContext()
}
}
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 app context to LTW
private fun sendAppContext() {
val appContext = AppContext().apply {
this.contextId = generateContextId()
this.appId = applicationContext.packageName
this.createTime = System.currentTimeMillis()
this.lastUpdatedTime = System.currentTimeMillis()
// Set the type of app context, for example, resume activity.
this.type = ProtocolConstants.TYPE_RESUME_ACTIVITY
// Set the rest fields in appContext
//……
}
_currentAppContext.value = appContext
AppContextManager.sendAppContext(this.applicationContext, appContext, appContextResponse)
}
// Delete app context from LTW
private fun deleteAppContext() {
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")
}
}
// Update app context from LTW
private fun updateAppContext() {
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)
}
private fun generateContextId(): String {
return "${packageName}.${UUID.randomUUID()}"
}
}
Informationen zu allen erforderlichen und optionalen Feldern finden Sie unter "AppContext Description".
AppContext-Beschreibung
Beim Senden des App-Kontexts sollten Partner-Apps die folgenden Werte bereitstellen:
| Schlüssel | Wert | Zusätzliche Informationen |
|---|---|---|
| contextId [erforderlich] | Wird verwendet, um ihn von anderen App-Kontexten zu unterscheiden. | Eindeutig für jeden App-Kontext. Format: "${packageName}.${UUID.randomUUID()}" |
| Typ [erforderlich] | Ein binäres Flag, das angibt, welcher App-Kontexttyp an LTW gesendet wird. | Der Wert sollte mit requestedContextType oben konsistent sein. |
| createTime[required] [FR1] | Zeitstempel, der angibt, zu welcher Uhrzeit der App-Kontext erstellt wurde. | |
| lastUpdatedTime[required] | Zeitstempel, der angibt, zu welcher Uhrzeit der App-Kontext zuletzt aktualisiert wurde. | Jedes Mal, wenn App-Kontextfelder aktualisiert werden, muss die aktualisierte Uhrzeit aufgezeichnet werden. |
| teamId [optional] | Wird verwendet, um die Organisation oder Gruppe zu identifizieren, der die App gehört. | |
| intentUri [optional] | Gibt an, welche App mit dem App-Kontext fortfahren kann, der vom ursprünglichen Gerät übergeben wurde. | Die maximale Länge beträgt 2083 Zeichen. |
| appId [optional] | Das Paket der Anwendung, für das der Kontext vorgesehen ist. | |
| title[optional] | Der Titel dieses App-Kontexts, z. B. ein Dokumentname oder ein Webseitentitel. | |
| Weblink[optional] | Die URL der Webseite, die in einem Browser geladen werden soll, um den App-Kontext fortzusetzen. | Die maximale Länge beträgt 2083 Zeichen. |
| Vorschau[optional] | Bytes des Vorschaubilds, das den App-Kontext darstellen kann | |
| extras[optional] | Ein Schlüssel-Wert-Paarobjekt, das App-spezifische Statusinformationen enthält, die zum Fortsetzen eines App-Kontexts auf dem fortfahrenden Gerät erforderlich sind. | Muss angeben, wenn der App-Kontext seine eindeutigen Daten enthält. |
| LifeTime[optional] | Die Lebensdauer des App-Kontexts in Millisekunden. | Wird nur für fortlaufende Szenarien verwendet, falls nicht festgelegt, beträgt der Standardwert 30 Tage). |
Codebeispiel für Browserkontinuität
In diesem Beispiel wird die Verwendung des Browserkontinuitätstyps hervorgehoben, der sich von anderen AppContext Typen unterscheidet.
class MainActivity : AppCompatActivity() {
private val appContextResponse = object : IAppContextResponse {
override fun onContextResponseSuccess(response: AppContext) {
Log.d("MainActivity", "onContextResponseSuccess")
}
override fun onContextResponseError(response: AppContext, throwable: Throwable) {
Log.d("MainActivity", "onContextResponseError: ${throwable.message}")
}
}
private lateinit var appContextEventHandler: IAppContextEventHandler
private val browserHistoryContext: BrowserHistoryContext = BrowserHistoryContext()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//……
LogUtils.setDebugMode(true)
var ready = false
val buttonSend: Button = findViewById(R.id.buttonSend)
val buttonDelete: Button = findViewById(R.id.buttonDelete)
setButtonDisabled(buttonSend)
setButtonDisabled(buttonDelete)
buttonSend.setOnClickListener {
if (ready) {
sendBrowserHistory ()
}
}
buttonDelete.setOnClickListener {
if (ready) {
clearBrowserHistory ()
}
}
appContextEventHandler = object : IAppContextEventHandler {
override fun onContextRequestReceived(contextRequestInfo: ContextRequestInfo) {
LogUtils.d("MainActivity", "onContextRequestReceived")
ready = true
setButtonEnabled(buttonSend)
setButtonEnabled(buttonDelete)
}
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)
}
// Send browser history to LTW
private fun sendBrowserHistory () {
browserHistoryContext.setAppId(this.packageName)
browserHistoryContext.addBrowserContext(System.currentTimeMillis(),
Uri.parse("https://www.bing.com/"), "Bing Search", null
)
AppContextManager.sendAppContext(this.applicationContext, browserHistoryContext, appContextResponse)
}
// Clear browser history from LTW
private fun clearBrowserHistory() {
browserHistoryContext.setAppId(this.packageName)
browserHistoryContext.setBrowserContextEmptyFlag(true)
AppContextManager.sendAppContext(this.applicationContext, browserHistoryContext, appContextResponse)
}
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)
}
//……
}
Alle erforderlichen und optionalen Felder finden Sie unter BrowserContext Description.
BrowserContext-Beschreibung
Partner-Apps können die addBrowserContext Methode aufrufen, um den Browserverlauf hinzuzufügen. Die folgenden Werte sollten beim Hinzufügen des Browserverlaufs bereitgestellt werden:
| Schlüssel | Wert |
|---|---|
| browserWebUri [erforderlich] | Ein Web-URI, der im Browser auf dem PC geöffnet wird (http: oder https:). |
| Titel [erforderlich] | Der Titel der Webseite. |
| Zeitstempel [erforderlich] | Der Zeitstempel, der angibt, wann die Webseite zuerst geöffnet oder zuletzt aktualisiert wurde. |
| favIcon [optional] | Das Favicon der Webseite in Bytes; sollte allgemeinen klein sein. |
Schritte zur Integrationsüberprüfung
Vorbereiten, indem Sie sicherstellen, dass private LTW installiert ist. Vergewissern Sie sich, dass LTW mit PC verbunden ist: Verwalten Ihres mobilen Geräts auf Ihrem PC. Vergewissern Sie sich, dass LTW mit der Telefonverbindung verbunden ist: Anforderungen und Einrichtung des Telefonlinks. Wenn Sie nach dem Scannen des QR-Codes nicht in LTW springen können, öffnen Sie LTW zuerst, und scannen Sie den QR-Code innerhalb der App. Überprüfen Sie abschließend, ob die Partner-App das Continuity SDK integriert hat.
Überprüfen Sie , indem Sie die App starten und das Continuity SDK initialisieren. Bestätigen Sie, dass
onContextRequestReceived()aufgerufen wird. SobaldonContextRequestReceived()der Aufruf erfolgt, kann die App den App-Kontext an LTW senden. WennonContextResponseSuccess()nach dem Senden des App-Kontexts aufgerufen wird, ist die SDK-Integration erfolgreich.
Geräteübergreifendes Windows-Repository auf GitHub
Informationen zum Integrieren des geräteübergreifenden Windows-SDKs in Ihr Projekt finden Sie unter Geräteübergreifendes Windows-Repository auf GitHub.
Häufig gestellte Fragen zu Phone Link
Eine Liste der häufig gestellten Fragen finden Sie unter Häufig gestellte Fragen zu Phone Link.
Windows developer