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.
Tento článek obsahuje komplexní pokyny pro vývojáře první a třetí strany, jak integrovat funkce pomocí Continuity SDK do vašich aplikací. Sada SDK pro kontinuitu umožňuje bezproblémová prostředí napříč zařízeními, což uživatelům umožňuje pokračovat v aktivitách na různých platformách, včetně Androidu a Windows.
Podle těchto pokynů můžete vytvořit bezproblémové a integrované uživatelské prostředí napříč několika zařízeními pomocí XDR pomocí sady SDK pro kontinuitu.
Důležité
Onboarding pro obnovení ve Windows
Obnovení je funkce s omezeným přístupem (LAF). Pokud chcete získat access k tomuto rozhraní API, budete muset získat schválení od Microsoftu, abyste mohli spolupracovat s balíčkem Odkaz na Windows na mobilních zařízeních s Androidem.
Pokud chcete požádat o access, 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
- Adresa URL obchodu 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 stanovené požadavky na scénář.
Požadavky
Před integrací sady SDK pro kontinuitu se ujistěte, že jsou splněny následující požadavky pro aplikace pro Android:
- Minimální verze sady SDK: 24
- Verze Kotlin: 1.9.x
- Odkaz na Windows (LTW): 1.241101.XX
V případě aplikací pro Windows se ujistěte, že jsou splněny následující požadavky:
- Minimální verze Windows: Windows 11
- Vývojové prostředí: Visual Studio 2019 nebo novější
Poznámka:
Aplikace pro iOS nejsou v tuto chvíli podporovány pro integraci se sadou SDK pro kontinuitu.
Konfigurace vývojového prostředí
Následující části obsahují podrobné pokyny k nastavení vývojového prostředí pro aplikace pro Android i Windows.
Nastavení Androidu
Pokud chcete nastavit vývojové prostředí pro Android, postupujte takto:
Pokud chcete sadu nastavit, stáhněte a použijte soubor .aar prostřednictvím knihoven uvedených v následujících verzích: Windows vydané verze sady SDK pro různé zařízení.
Přidejte metaznačky do AndroidManifest.xml souboru aplikace pro Android. Následující fragment kódu ukazuje, jak přidat požadované metaznačky:
<meta-data android:name="com.microsoft.crossdevice.resumeActivityProvider" android:value="true" /> <meta-data android:name="com.microsoft.crossdevice.trigger.PartnerApp" android:value="4" />
Kroky integrace rozhraní API
Po deklarací manifestu můžou vývojáři aplikací snadno odeslat kontext aplikace pomocí jednoduchého příkladu kódu.
Aplikace musí:
- Inicializace/Deinicializace SDK pro kontinuitu:
- Aplikace by měla určit odpovídající čas volání funkcí Initialize a DeInitialize.
- Po volání funkce Initialize by se mělo aktivovat zpětné volání, které implementuje IAppContextEventHandler.
- Send/Delete AppContext:
- Po inicializaci sady SDK se zavolá onContextRequestReceived , znamená to, že se naváže připojení. Aplikace pak může posílat (včetně vytvoření a aktualizace) AppContext do LTW nebo odstranit AppContext z LTW.
- Pokud není mezi telefonem a počítačem žádné připojení a aplikace odešle AplikaciContext do LTW, aplikace obdrží onContextResponseError se zprávou "Počítač není připojený".
- Při opětovném navázání připojení se znovu zavolá onContextRequestReceived . Aplikace pak může odeslat aktuální AppContext do LTW.
- Po odpojení služby onSyncServiceDisconnected nebo deaktivaci sady SDK by aplikace neměla odesílat AppContext.
Níže je příklad kódu. Všechna povinná a volitelná pole v AppContextu najdete v popisu AppContext.
Následující fragment kódu Androidu ukazuje, jak provádět požadavky rozhraní API pomocí sady SDK pro kontinuitu:
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()}"
}
}
Kroky ověření integrace
Pokud chcete ověřit integraci sady SDK pro kontinuitu ve vaší aplikaci, postupujte takto:
Příprava
K přípravě na ověření integrace se vyžadují následující kroky:
Ujistěte se, že je nainstalován soukromý LTW.
Připojte LTW k počítači:
Pokyny najdete v tématu Jak spravovat mobilní zařízení na počítači .
Poznámka:
Pokud po naskenování kódu QR nejste přesměrováni na LTW, prosím, nejdříve otevřete LTW a poté naskenujte kód QR v aplikaci.
Ověřte, že partnerová aplikace integrovala sadu SDK pro kontinuitu.
Validation
Dále postupujte podle těchto kroků a ověřte integraci:
- Spusťte aplikaci a inicializujete sadu SDK. Potvrďte, že je onContextRequestReceived volána.
- Po zavolání onContextRequestReceived může aplikace odeslat AppContext do LTW. Pokud je onContextResponseSuccess volána po odeslání AppContext, integrace SDK je úspěšná.
- Pokud aplikace odesílá AppContext , když je počítač uzamčený nebo odpojený, ověřte, jestli je onContextResponseError volána s textem Počítač není připojený.
- Po obnovení připojení se ujistěte, že se znovu volá onContextRequestReceived a aplikace pak může odeslat aktuální AppContext do LTW.
Následující snímek obrazovky ukazuje položku protokolu, když je počítač odpojený s chybovou zprávou "Počítač není připojený" a položku protokolu po opětovném připojení, když je onContextRequestReceived volána znovu.
AppContext
XDR definuje AppContext jako metadata, pomocí kterých XDR dokáže pochopit, která aplikace se má obnovit, spolu s kontextem, se kterým musí být aplikace obnovena. Aplikace můžou pomocí aktivit umožnit uživatelům vrátit se k tomu, co dělali ve své aplikaci, na více zařízeních. Aktivity vytvořené libovolnou mobilní aplikací se zobrazují na zařízeních s Windows uživatelů, pokud jsou tato zařízení zřízená službou CDEH (Cross Device Experience Host).
Každá aplikace je jiná, a proto je na systému Windows, aby porozuměl cílové aplikaci pro obnovení, a na konkrétních aplikacích ve Windows, aby porozuměly kontextu. XDR navrhuje obecné schéma, které může pokrýt požadavky pro všechny prvotní i třetí strany včetně scénářů obnovení provozu aplikací.
contextId
- Povinné: Ano
- Popis: Jedná se o jedinečný identifikátor, který slouží k odlišení jednoho objektu AppContext od jiného. Zajišťuje, aby každý AppContext byl jednoznačně identifikovatelný.
- Použití: Ujistěte se, že pro každý AppContext vygenerujete jedinečné id kontextu, abyste se vyhnuli konfliktům.
typ
- Povinné: Ano
- Popis: Toto je binární příznak, který označuje typ AppContext, který se odesílá na Link to Windows (LTW). Hodnota by měla být konzistentní s požadovaným typemContextType.
- Použití: Nastavte tento příznak podle typu kontextu, který odesíláte. Například:
ProtocolConstants.TYPE_RESUME_ACTIVITY.
čas vytvoření
- Povinné: Ano
- Popis: Toto časové razítko představuje čas vytvoření objektu AppContext.
- Použití: Zaznamenejte přesný čas vytvoření AppContextu .
intentUri
- Povinné: Ne, pokud je k dispozici webový odkaz
- Popis: Tento identifikátor URI označuje, která aplikace může pokračovat v předávání AppContext z původního zařízení.
- Použití: Tuto možnost zadejte, pokud chcete zadat konkrétní aplikaci, která bude zpracovávat kontext.
odkaz na web
- Povinné: Ne, pokud je zadaný identifikátor INTENTURI
- Popis: Tento identifikátor URI se používá ke spuštění webového koncového bodu aplikace, pokud se rozhodnou nepoužívat Store aplikace. Tento parametr se používá pouze v případě, že není zadaný identifikátor INTENTURI . Pokud jsou k dispozici obě možnosti, použije se k obnovení aplikace ve Windows identifikátor intentUri .
- Použití: Pouze pokud aplikace chce pokračovat na webových koncových bodech a nikoli v aplikacích pro obchod.
Id aplikace
- Povinné: Ano
- Popis: Toto je název balíčku aplikace, pro který je kontext určen.
- Použití: Nastavte ho na název balíčku vaší aplikace.
title
- Povinné: Ano
- Popis: Toto je název AppContext, například název dokumentu nebo název webové stránky.
- Použití: Zadejte smysluplný název, který představuje AppContext.
Preview
- Povinné: Ne
- Popis: Jedná se o bajty obrázku náhledu, který může představovat AppContext.
- Použití: Zadejte náhled obrázku, pokud je k dispozici, abyste uživatelům poskytli vizuální reprezentaci AppContextu.
Životnost
- Povinné: Ne
- Popis: Jedná se o životnost
AppContextmilisekund. Používá se jenom pro průběžné scénáře. Pokud není nastavená, výchozí hodnota je 5 minut. - Použití: Nastavte tuto možnost tak, aby definovala, jak dlouho
AppContextmá být platná. Můžete nastavit hodnotu maximálně 5 minut. Jakákoli větší hodnota se automaticky zkrátí na 5 minut.
Identifikátory URI záměru
Identifikátory URI umožňují spustit jinou aplikaci, aby prováděla konkrétní úlohu a umožňovala užitečné scénáře mezi aplikacemi. Další informace o spouštění aplikací pomocí identifikátorů URI najdete v tématu Spusťte výchozí aplikaci Windows pro URI a Vytvoření přímých odkazů na obsah aplikace | Vývoj pro Android
Zpracování odpovědí rozhraní API ve Windows
Tato část popisuje, jak zpracovávat odpovědi rozhraní API v aplikacích pro Windows. Sada SDK pro kontinuitu poskytuje způsob, jak zpracovat odpovědi rozhraní API pro aplikace Win32 a WinUI.
Příklad aplikace Win32
Aby aplikace Win32 zpracovávaly spuštění identifikátoru URI protokolu, jsou potřeba následující kroky:
Nejprve je nutné provést záznam do registru následujícím způsobem:
[HKEY_CLASSES_ROOT\partnerapp] @="URL:PartnerApp Protocol" "URL Protocol"="" [HKEY_CLASSES_ROOT\partnerapp\shell\open\command] @="\"C:\\path\\to\\PartnerAppExecutable.exe\" \"%1\""Spuštění musí být zpracováno v hlavní funkci aplikace Win32:
#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; }
Aplikace WinUI
U zabalených aplikací WinUI je možné identifikátor URI protokolu zaregistrovat v manifestu aplikace projektu. Následující kroky ukazují, jak zpracovat aktivaci protokolu v aplikaci WinUI.
Nejprve se v
Package.appxmanifestsouboru zaregistruje identifikátor URI protokolu následujícím způsobem:<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>
Příklad WinUI 3
Následující fragment kódu ukazuje, jak zpracovat aktivaci protokolu v aplikaci C++ WinUI pomocí 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
}
}
Odkaz na web
Pomocí webového odkazu se spustí webový koncový bod aplikace. Vývojáři aplikací musí zajistit, aby byl webový odkaz poskytnutý ze své aplikace pro Android platný, protože XDR použije výchozí prohlížeč systému k přesměrování na poskytnutý webový odkaz.
Zpracování argumentů získaných z funkce obnovení přes zařízení
Za deserializaci a dešifrování argumentu přijatého a zpracování informací je zodpovědností každé aplikace, aby se průběžný kontext přenesl z telefonu do počítače. Pokud je třeba například hovor přepojet, musí být aplikace schopná komunikovat s tímto kontextem z telefonu a desktopová aplikace musí tento kontext správně pochopit a pokračovat v načítání.
Související obsah
Windows developer