Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Mobilní zařízení s Androidem, která nainstalovala balíček "Odkaz na Windows", můžou programově sdílet nedávné úkoly z aplikace pro Android, aby pokračovala na počítači s Windows (například adresy URL webu, odkazy na dokumenty, hudební skladby atd.).
Cross Device Task Continuity se vyvíjí tak, že využívá SDK pro kontinuitu pro nabídku hlubší nativní integrace s Panelem úloh Windows zákazníkům přirozeným a intuitivním způsobem. I když je stále podporována původní implementace aplikace pro kontinuitu úloh Phone Link, pro nové implementace doporučujeme použít funkci XDR (Cross Device Resume) v sadě SDK pro kontinuitu pro integraci hlavního panelu Windows. Další informace: Pokračování mezi zařízeními (XDR) pomocí Continuity SDK (aplikace pro Android a Windows)
Sada SDK pro kontinuitu umožňuje plynulejší prostředí napříč zařízeními pomocí funkce XDR (Cross Device Resume), která zobrazuje ikony pokračování úloh, které vám pomůžou pokračovat v posledních úlohách zařízení s Androidem přímo z hlavního panelu Windows (bez nutnosti spoléhat se na rozhraní aplikace Phone Link).
Jak integrovat vaši aplikaci pro Android s nepřerušeným pokračováním úloh Phone Link
Naučte se programově sdílet poslední úkoly z aplikace pro Android (například adresy URL webu, odkazy na dokumenty, hudební skladby atd.) na počítač s Windows, který nastavil Phone Link. Tato funkce je dostupná jenom na podporovaných zařízeních pro funkce Phone Link.
Požadavky na scénář
Aby vaše aplikace pro Android měla přístup k pokračování úloh Propojení s Windows, musí být splněny následující podmínky:
- Proveďte synchronizaci platných webových adres URL, které budou přístupné z počítače s Windows.
- Proveďte synchronizaci cloudových odkazů na dokumenty, aby byly přístupné z PC s Windows
- Nezapomeňte synchronizovat odkazy na místní dokumenty na počítač s Windows, aby byly přístupné na mobilním zařízení prostřednictvím vaší aplikace.
- NEsynchronizovat více než 60krát za minutu
- NEsynchronizujte obsah, pokud se uživatel nezapojuje do prostředí vaší aplikace.
Propojení telefonu a obnovení na různých zařízeních
Odkaz na telefon zobrazí váš synchronizovaný obsah v uzlu Aplikace pod položkami "Naposledy použité" a "Poslední weby" a ve vyskakovacím oznámení.
Obnovení mezi zařízeními (XDR) s použitím sady SDK Continuity (aplikace pro Android a Windows) zobrazí váš synchronizovaný obsah na hlavním panelu Windows.
Schválení funkce omezeného přístupu (LAF)
Kontinuita úloh Phone Link je funkce s omezeným přístupem (LAF). Pokud chcete získat přístup, budete muset získat schválení od Microsoftu, abyste mohli spolupracovat s balíčkem Odkaz na Windows, který je předinstalovaný na mobilních zařízeních s Androidem.
Pokud chcete požádat o přístup, pošlete e-mail wincrossdeviceapi@microsoft.com s níže uvedenými informacemi.
- Popis uživatelského prostředí
- Snímek obrazovky aplikace, kde uživatel nativně přistupuje k webu nebo dokumentům
- PackageId vaší aplikace
- Odkaz na obchod Google Play pro vaši aplikaci
Pokud je žádost schválená, obdržíte pokyny k odemknutí funkce. Schválení budou vycházet z vaší komunikace za předpokladu, že váš scénář splňuje výše uvedené požadavky na scénář .
Zpracování dat
Pomocí kontinuity úkolů Phone Link bude Společnost Microsoft zpracovávat a přenášet vaše data v souladu se smlouvou o poskytování služeb společnosti Microsoft a prohlášením o zásadách ochrany osobních údajů společnosti Microsoft. Data přenášená do propojených zařízení uživatele se můžou zpracovávat prostřednictvím cloudových služeb Microsoftu, aby se zajistil spolehlivý přenos dat mezi zařízeními. Data zpracovávaná tímto rozhraním API se neuchovávají cloudovými službami Microsoftu, které podléhají řízení koncových uživatelů.
Sada SDK pro kontinuitu, kterou integrujete do balíčku aplikace, zajišťuje, že data poskytnutá rozhraní API se zpracovávají pouze důvěryhodnými balíčky Microsoftu.
Ukázky kódu pro integraci s Phone Linkem
Níže jsou uvedené obecné pokyny a ukázky kódu pro integraci. Najdete podrobné pokyny k integraci v dokumentaci SDK Kotlinu.
Deklarace manifestu aplikace pro Android
Manifest aplikace je soubor XML, který slouží jako podrobný plán pro vaši aplikaci pro Android. Soubor deklarace poskytuje operačnímu systému informace o struktuře, komponentách, oprávněních atd. Následující deklarace jsou vyžadovány pro kontinuitu úkolů s odkazem na Windows.
Metadata funkcí
Partnerské aplikace musí nejprve zaregistrovat metadata v manifestu aplikace.
Aby bylo možné se účastnit kontraktu kontextu aplikace, musí být metadata deklarována pro podporovaný typ kontextu aplikace. Pokud chcete například přidat metadata poskytovatele kontextu aplikace pro funkci Předání aplikace :
<application...>
<meta-data
android:name="com.microsoft.crossdevice.applicationContextProvider"
android:value="true" />
</application>
Pokud vaše aplikace podporuje více než jeden typ kontextu aplikace, musí se přidat každý typ meta-dat. Mezi aktuálně podporované typy meta-dat patří:
<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" />
Chcete-li přidat nový typ, formát názvu meta-dat by měl být "com.microsoft.crossdevice.xxxProvider".
Aplikace musí také deklarovat metadata typu triggeru v manifestu. Tyto deklarace pomáhají systému určit, kdy a jak má aplikace informovat o aktivaci určitých funkcí pro Load-Time Weaving (LTW).
V případě triggeru s automatickým oznámením, kdy samotná aplikace zodpovídá za oznamování systému a je povolená na všech zařízeních bez ohledu na výrobce OEM (Original Equipment Manufacturer), by měl být typ triggeru deklarován takto:
<application ...
<meta-data
android:name="com.microsoft.crossdevice.trigger.PartnerApp"
android:value="the sum value of all features' binary codes" />
</application>
V případě triggeru systémového rozhraní API, ve kterém aplikace spoléhá na systémová rozhraní API k aktivaci funkce "Odkaz na Windows", povolená pouze na konkrétních zařízeních OEM, by se typ triggeru měl deklarovat takto:
<application ...
<meta-data
android:name="com.microsoft.crossdevice.trigger.SystemApi"
android:value="the sum value of all features' binary codes" />
</application>
Binární kódy funkcí jsou nyní:
APPLICATION_CONTEXT: 1
BROWSER_HISTORY: 2
RESUME_ACTIVITY: 4
Registrace manifestu aplikace může vypadat jako v tomto příkladu:
<?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>
Ukázka kódu pro odesílání kontextu aplikace
Po přidání deklarací manifestu aplikace bude potřeba vytvořit odkaz na partnerské aplikace pro Windows:
Určete vhodné načasování pro volání funkcí Initialize a DeInitialize pro sadu SDK pro kontinuitu. Po volání funkce Initialize by měl být aktivován zpětný volací mechanismus, který implementuje
IAppContextEventHandler.Po inicializaci sady SDK pro kontinuitu, pokud je volána
onContextRequestReceived(), to značí navázání připojení. Aplikace pak může odeslatAppContext(včetně vytvoření a aktualizace) do LTW nebo odstranitAppContextz LTW.
Nezapomeňte se vyhnout odesílání citlivých dat, jako jsou AppContext, například přístupové tokeny. Kromě toho platí, že pokud je doba života nastavená příliš krátká, AppContext platnost může vypršet před odesláním do počítače. Doporučuje se nastavit minimální životnost nejméně 5 minut.
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()}"
}
}
Pro všechna povinná a volitelná pole se podívejte na popis AppContext.
Popis AppContext
Při odesílání kontextu aplikace by měly partnerské aplikace poskytovat následující hodnoty:
| Klíč | Hodnota | Další informace |
|---|---|---|
| contextId [vyžadováno] | Používá se k odlišení od jiných kontextů aplikace. | Jedinečné pro každý kontext aplikace. Formát: "${packageName}.${UUID.randomUUID()}" |
| typ [povinné] | Binární příznak, který určuje, jaký typ kontextu aplikace je odeslán do LTW. | Hodnota by měla být konzistentní s požadovaným typemContextType výše. |
| createTime[required] [FR1] | Časové razítko představující čas vytvoření kontextu aplikace | |
| lastUpdatedTime[required] | Časové razítko představující čas poslední aktualizace kontextu aplikace | Kdykoli se aktualizují jakákoli pole kontextu aplikace, je potřeba zaznamenat aktualizovaný čas. |
| teamId [volitelné] | Používá se k identifikaci organizace nebo skupiny, do které aplikace patří. | |
| intentUri [volitelné] | Používá se k označení, která aplikace může pokračovat v kontextu aplikace předávané z původního zařízení. | Maximální délka je 2083 znaků. |
| appId [volitelné] | Balíček aplikace, pro který je kontext určen. | |
| title[optional] | Název tohoto kontextu aplikace, například název dokumentu nebo název webové stránky. | |
| weblink[volitelné] | Adresa URL webové stránky, která se má načíst v prohlížeči, aby pokračovala v kontextu aplikace. | Maximální délka je 2083 znaků. |
| Preview[volitelné] | Bajty obrázku ve verzi Preview, který může představovat kontext aplikace | |
| extra[volitelné] | Objekt páru klíč-hodnota obsahující informace o stavu specifické pro aplikaci, které jsou potřeba k pokračování kontextu aplikace na pokračujícím zařízení. | Je potřeba zadat údaje, když kontext aplikace obsahuje jedinečná data. |
| LifeTime[volitelné] | Životnost kontextu aplikace v milisekundách. | Používá se pouze pro probíhající scénář, pokud není nastavená, výchozí hodnota je 30 dnů). |
Ukázka kódu kontinuity prohlížeče
Tato ukázka zvýrazňuje použití typu Kontinuita prohlížeče , který se liší od jiných AppContext typů.
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)
}
//……
}
Pro všechna povinná a nepovinná pole viz BrowserContext Popis.
Popis BrowserContextu
Partnerské aplikace můžou volat metodu addBrowserContext pro přidání historie prohlížeče. Při přidávání historie prohlížeče by se měly poskytnout následující hodnoty:
| Klíč | Hodnota |
|---|---|
| browserWebUri [povinné] | Webový identifikátor URI, který se otevře v prohlížeči na počítači (http: nebo https:). |
| název [required] | Název webové stránky. |
| časové razítko [povinné] | Časový údaj, kdy byla webová stránka poprvé otevřena nebo naposledy aktualizována. |
| favIcon [volitelné] | Favicon webové stránky v bajtech, by měl být obecně malý. |
Kroky ověření integrace
Připravte se tím, že zajistíte instalaci privátního LTW. Ověřte, že je LTW připojený k počítači: Jak spravovat mobilní zařízení na počítači. Ověřte, že je LTW připojený k telefonnímu propojení: požadavky na telefonní propojení a nastavení. Pokud po naskenování kódu QR nemůžete přejít na LTW, nejdřív otevřít LTW a naskenovat kód QR v aplikaci. Nakonec ověřte, že partnerová aplikace integrovala sadu SDK pro kontinuitu.
Ověřte spuštěním aplikace a inicializací sady SDK pro kontinuitu. Potvrďte, že
onContextRequestReceived()je voláno. PoonContextRequestReceived()zavolání může aplikace odeslat kontext aplikace do LTW. PokudonContextResponseSuccess()se volá po odeslání kontextu aplikace, integrace sady SDK je úspěšná.
Repozitář Windows napříč zařízeními na GitHubu
Najděte informace o integraci sady WINDOWS SDK pro různé zařízení do projektu v úložišti Windows-Cross-Device na GitHubu.
Nejčastější dotazy k aplikaci Phone Link
Seznam nejčastějších dotazů najdete v tématu Nejčastější dotazy k odkazu na telefon.
Windows developer