Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
I dispositivi mobili Android che hanno installato il pacchetto "Collega a Windows" possono condividere a livello di codice le attività recenti dall'app Android per continuare nel PC Windows (ad esempio URL del sito Web, collegamenti a documenti, tracce musicali e così via).
La continuità delle attività tra dispositivi è in continua evoluzione per l'uso di Continuity SDK per offrire un'integrazione nativa più approfondita con la barra delle applicazioni di Windows, offrendo una migliore gestione dei clienti in modo naturale e intuitivo. Anche se l'implementazione originale dell'app di continuità dell'attività Phone Link è ancora supportata, per le nuove implementazioni, è consigliabile usare Cross Device Resume (XDR) nell'integrazione di Continuity SDK per la barra delle applicazioni di Windows. Altre informazioni: Cross Device Resume (XDR) con Continuity SDK (Applicazioni Android e Windows).
Continuity SDK consente esperienze tra dispositivi più semplici con cross-device resume (XDR) che visualizzano icone di continuazione delle attività per riprendere le attività recenti del dispositivo Android direttamente dalla barra delle applicazioni di Windows (senza la necessità di basarsi sull'interfaccia dell'app Collegamento telefonico).
Come integrare l'app Android con la continuità delle attività Phone Link
Scopri come condividere attività recenti a livello di codice dall'app Android (ad esempio URL del sito Web, collegamenti a documenti, tracce musicali e così via) a un PC Windows che ha configurato Il collegamento telefonico. Questa funzionalità è disponibile solo nei dispositivi supportati per le esperienze di Collegamento telefonico.
Requisiti dello scenario
Per consentire all'app Android di accedere alla continuità delle attività "Collega a Windows" devono essere soddisfatte le condizioni seguenti:
- Eseguire la sincronizzazione degli URL Web validi per essere accessibili dal PC Windows
- DO sync cloud document links to be accessible by the Windows PC
- Do sync local document links to the Windows PC that must be accessible on the mobile device through your app (Esegui sincronizzazione documenti locali al PC Windows che deve essere accessibile nel dispositivo mobile tramite la tua app)
- NON sincronizzare per più di 60 volte al minuto
- NON sincronizzare il contenuto se l'utente non è coinvolto nell'esperienza dell'app
Collegamento telefonico e superficie di ripresa tra dispositivi
Il collegamento telefonico visualizzerà il contenuto sincronizzato nel nodo App in "Siti Web recenti" e "Siti Web recenti" e in un riquadro a comparsa delle notifiche.
La ripresa tra dispositivi (XDR) con Continuity SDK (Applicazioni Android e Windows) esporterà il contenuto sincronizzato sulla barra delle applicazioni di Windows.
Approvazione della funzionalità di accesso limitato (LAF)
La continuità dell'attività Collegamento telefonico è una funzionalità di accesso limitato (LAF). Per ottenere l'accesso, è necessario ottenere l'approvazione da Microsoft per interagire con il pacchetto "Collega a Windows" precaricata nei dispositivi mobili Android.
Per richiedere l'accesso, inviare un messaggio di posta elettronica a wincrossdeviceapi@microsoft.com contenente le informazioni elencate di seguito.
- Descrizione dell'esperienza utente
- Screenshot dell'applicazione in cui un utente accede in modo nativo al Web o ai documenti
- PackageId dell'applicazione
- Collegamento a Google Play Store per l'applicazione
Se la richiesta viene approvata, si riceveranno istruzioni su come sbloccare la funzionalità. Le approvazioni si basano sulla comunicazione, purché lo scenario soddisfi i Requisiti dello scenario precedentemente descritti.
Trattamento dei dati
Usando la continuità dell'attività Collegamento telefonico, Microsoft elabora e trasferisce i dati in conformità al Contratto dei Servizi Microsoft e all'Informativa sulla privacy di Microsoft. I dati trasferiti ai dispositivi collegati dell'utente possono essere elaborati tramite i servizi cloud di Microsoft per garantire un trasferimento affidabile dei dati tra dispositivi. I dati gestiti da questa API non vengono conservati dai servizi cloud Microsoft soggetti al controllo dell'utente finale.
Continuity SDK che si integrerà nel pacchetto dell'app garantisce che i dati forniti all'API vengano gestiti solo da pacchetti Microsoft attendibili.
Esempi di codice di integrazione di Collegamento telefonico
Di seguito sono riportate le linee guida generali e gli esempi di codice per l'integrazione. Per indicazioni dettagliate sull'integrazione, vedere il documento Kotlin dell'SDK.
Dichiarazioni del manifesto dell'app Android
Il manifesto dell'app è un file XML che funge da progetto per l'app Android. Il file di dichiarazione fornisce informazioni al sistema operativo sulla struttura, i componenti, le autorizzazioni e così via dell'app. Le dichiarazioni seguenti sono necessarie per la continuità delle attività con "Collega a Windows".
Metadati delle funzionalità
Le app partner devono prima registrare i metadati nel manifesto dell'app.
Per partecipare al contratto di contesto dell'app, i metadati devono essere dichiarati per il tipo di contesto dell'app supportato. Ad esempio, per aggiungere i metadati del provider di contesto dell'app per la funzionalità Handoff dell'app :
<application...>
<meta-data
android:name="com.microsoft.crossdevice.applicationContextProvider"
android:value="true" />
</application>
Se l'app supporta più tipi di contesto dell'app, è necessario aggiungere ogni tipo di metadati. I tipi di metadati attualmente supportati includono:
<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" />
Per aggiungere un nuovo tipo, il formato del nome dei metadati deve essere "com.microsoft.crossdevice.xxxProvider".
Le app devono anche dichiarare il tipo di trigger metadati nel manifesto. Queste dichiarazioni aiutano il sistema a determinare come e quando l'app deve notificare Load-Time La trama (LTW) su determinate funzionalità attive.
Per un trigger di notifica automatica, in cui l'app stessa è responsabile della notifica al sistema ed è abilitata in tutti i dispositivi, indipendentemente dal produttore oem (Original Equipment Manufacturer), il tipo di trigger deve essere dichiarato come:
<application ...
<meta-data
android:name="com.microsoft.crossdevice.trigger.PartnerApp"
android:value="the sum value of all features' binary codes" />
</application>
Per un trigger api di sistema, in cui l'app si basa sulle API di sistema per attivare la funzionalità "Collega a Windows", abilitata solo in dispositivi OEM specifici, il tipo di trigger deve essere dichiarato come:
<application ...
<meta-data
android:name="com.microsoft.crossdevice.trigger.SystemApi"
android:value="the sum value of all features' binary codes" />
</application>
I codici binari delle funzionalità sono ora:
APPLICATION_CONTEXT: 1
BROWSER_HISTORY: 2
RESUME_ACTIVITY: 4
La registrazione del manifesto dell'app può essere simile all'esempio seguente:
<?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>
Esempio di codice per l'invio del contesto dell'app
Dopo aver aggiunto le dichiarazioni del manifesto dell'app, le app partner "Collega a Windows" dovranno:
Determinare la tempistica appropriata per chiamare le funzioni Initialize e DeInitialize per Continuity SDK. Dopo aver chiamato la funzione Initialize, deve essere attivato un callback che implementa
IAppContextEventHandler.Dopo l'inizializzazione di Continuity SDK, se
onContextRequestReceived()viene chiamato, indica che viene stabilita la connessione. L'app può quindi inviareAppContext(inclusa la creazione e l'aggiornamento) a LTW o eliminareAppContextda LTW.
Assicurarsi di evitare di inviare dati sensibili in AppContext, ad esempio i token di accesso. Inoltre, se la durata è impostata troppo breve, il AppContext può scadere prima che venga inviato al PC. È consigliabile impostare una durata minima di almeno 5 minuti.
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()}"
}
}
Per tutti i campi obbligatori e facoltativi , vedere AppContext Description.
Descrizione di AppContext
I valori seguenti devono essere forniti dalle app partner durante l'invio del contesto dell'app:
| Chiave | valore | Informazioni aggiuntive |
|---|---|---|
| contextId [obbligatorio] | Usato per distinguerlo da altri contesti dell'app. | Univoco per ogni contesto dell'app. Formato: "${packageName}.${UUID.randomUUID()}" |
| tipo [obbligatorio] | Flag binario che indica il tipo di contesto dell'app inviato a LTW. | Il valore deve essere coerente con requestedContextType precedente |
| createTime[required] [FR1] | Timestamp che rappresenta l'ora di creazione del contesto dell'app. | |
| lastUpdatedTime[required] | Timestamp che rappresenta l'ora dell'ultimo aggiornamento del contesto dell'app. | Ogni volta che vengono aggiornati i campi del contesto dell'app, è necessario registrare l'ora aggiornata. |
| teamId [facoltativo] | Usato per identificare l'organizzazione o il gruppo a cui appartiene l'app. | |
| intentUri [facoltativo] | Usato per indicare quale app può continuare il contesto dell'app passato dal dispositivo di origine. | La lunghezza massima è di 2083 caratteri. |
| appId [facoltativo] | Il pacchetto dell'applicazione per cui si trova il contesto. | |
| title[facoltativo] | Titolo del contesto dell'app, ad esempio un nome di documento o un titolo della pagina Web. | |
| weblink[facoltativo] | URL della pagina Web da caricare in un browser per continuare il contesto dell'app. | La lunghezza massima è di 2083 caratteri. |
| anteprima[facoltativo] | Byte dell'immagine di anteprima che può rappresentare il contesto dell'app | |
| extra[facoltativo] | Oggetto coppia chiave-valore contenente informazioni sullo stato specifiche dell'app necessarie per continuare un contesto dell'app nel dispositivo continuo. | È necessario specificare quando il contesto dell'app ha i dati univoci. |
| LifeTime[facoltativo] | Durata del contesto dell'app in millisecondi. | Usato solo per lo scenario in corso, se non impostato, il valore predefinito è 30 giorni. |
Esempio di codice di continuità del browser
In questo esempio viene evidenziato l'uso del tipo continuità browser , che differisce da altri AppContext tipi.
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)
}
//……
}
Per tutti i campi obbligatori e facoltativi, vedere BrowserContext Description.For all the required and optional fields, see BrowserContext Description.
Descrizione browserContext
Le app partner possono chiamare il metodo per aggiungere la addBrowserContext cronologia del browser. Quando si aggiunge la cronologia del browser, è necessario specificare i valori seguenti:
| Chiave | valore |
|---|---|
| browserWebUri [obbligatorio] | URI Web che verrà aperto nel browser nel PC (http: o https:). |
| title [obbligatorio] | Titolo della pagina Web. |
| timestamp [obbligatorio] | Timestamp che la pagina Web è stata aperta o aggiornata per la prima volta. |
| favIcon [facoltativo] | Il favicon della pagina Web in byte dovrebbe essere piccolo in generale. |
Passaggi di convalida dell'integrazione
Prepararsi assicurandosi che sia installato LTW privato. Verificare che LTW sia connesso al PC: come gestire il dispositivo mobile nel PC. Verificare che LTW sia connesso a Collegamento telefonico: requisiti e configurazione del collegamento telefonico. Se dopo aver scansionato il codice a matrice, non è possibile passare a LTW, aprire prima LTW e analizzare il codice a matrice all'interno dell'app. Infine, verificare che l'app partner abbia integrato Continuity SDK.
Convalidare avviando l'app e inizializzando Continuity SDK. Verificare che
onContextRequestReceived()venga chiamato . Una voltaonContextRequestReceived()chiamato, l'app può inviare il contesto dell'app a LTW. SeonContextResponseSuccess()viene chiamato dopo l'invio del contesto dell'app, l'integrazione dell'SDK ha esito positivo.
Repository tra dispositivi Windows in GitHub
Informazioni sull'integrazione di Windows Cross-Device SDK nel progetto nel repository tra dispositivi Windows in GitHub.
Domande frequenti su Phone Link
Per un elenco delle domande frequenti, consultare la sezione Domande frequenti su Phone Link.