Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makale, uygulamalarınızda Süreklilik SDK'sını kullanarak özellikleri tümleştirme konusunda birinci taraf ve üçüncü taraf geliştiriciler için kapsamlı yönergeler sağlar. Süreklilik SDK'sı sorunsuz cihazlar arası deneyimler sağlayarak kullanıcıların Android ve Windows gibi farklı platformlarda etkinlikleri sürdürmesine olanak tanır.
Bu kılavuzu izleyerek, Süreklilik SDK'sını kullanarak Windows Özgeçmiş'i kullanarak birden çok cihazda sorunsuz ve tümleşik bir kullanıcı deneyimi oluşturabilirsiniz.
Önemli
Windows'ta Uygulama Başlangıcı
Özgeçmiş Sınırlı Erişim Özelliğidir (LAF). Bu API'ye access kazanmak için Microsoft'tan Android mobil cihazlarda "Windows Bağlantısı" paketiyle birlikte çalışma onayı almanız gerekir.
Erişim talep etmek için, aşağıda listelenen bilgileri içeren bir e-posta wincrossdeviceapi@microsoft.com adresine gönderin.
- Kullanıcı deneyiminizin açıklaması
- Kullanıcının web'e veya belgelere yerel olarak eriştiği uygulamanızın ekran görüntüsü
- Uygulamanızın PackageId değeri
- Uygulamanızın Google Play store URL'si
İstek onaylanırsa özelliğin kilidini açma yönergelerini alırsınız. Onaylar, senaryonuzun ana hatlarıyla belirtilen Senaryo Gereksinimlerini karşılaması koşuluyla iletişiminizi temel alır.
Önkoşullar
Android uygulamaları için Süreklilik SDK'sını tümleştirmeden önce aşağıdaki gereksinimlerin karşılandığından emin olun:
- En Düşük SDK Sürümü: 24
- Kotlin Sürümü: 1.9.x
- Windows bağlantısı (LTW): 1.241101.XX
Windows uygulamaları için aşağıdaki gereksinimlerin karşılandığından emin olun:
- En Düşük Windows Sürümü: Windows 11
- Geliştirme Ortamı: Visual Studio 2019 veya üzeri
Uyarı
iOS uygulamaları şu anda Süreklilik SDK'sı ile tümleştirme için desteklenmiyor.
Geliştirme ortamınızı yapılandırma
Aşağıdaki bölümlerde hem Android hem de Windows uygulamaları için geliştirme ortamını ayarlamaya yönelik adım adım yönergeler sağlanır.
Android kurulumu
Android için geliştirme ortamını ayarlamak için şu adımları izleyin:
Paketi ayarlamak için aşağıdaki sürümlerde sağlanan kitaplıklar aracılığıyla .aar dosyasını indirin ve kullanın: Windows Cihazlar Arası SDK sürümleri.
Meta etiketleri Android uygulamanızın AndroidManifest.xml dosyasına ekleyin. Aşağıdaki kod parçacığında gerekli meta etiketlerin nasıl ekleneceği gösterilmektedir:
<meta-data android:name="com.microsoft.crossdevice.resumeActivityProvider" android:value="true" /> <meta-data android:name="com.microsoft.crossdevice.trigger.PartnerApp" android:value="4" />
API tümleştirme adımları
Bildirim bildirimlerinden sonra, uygulama geliştiricileri basit bir kod örneğini izleyerek uygulama bağlamlarını kolayca gönderebilir.
Uygulamanın yapması gerekenler:
- Süreklilik SDK'sını Başlatma/Kaldırma:
- Uygulamanın Initialize ve DeInitialize işlevlerini çağırmak için uygun zamanı belirlemesi gerekir.
- Initialize işlevi çağrıldıktan sonra, IAppContextEventHandler uygulayan bir geri çağırma tetiklenmelidir.
-
AppContext Gönderme/Silme:
- SDK'yı başlatdıktan sonra onContextRequestReceived çağrılırsa bağlantının kurulduğunu gösterir. Uygulama daha sonra APPContext'i LTW'ye gönderebilir (oluşturma ve güncelleştirme dahil) veya APPContext'i LTW'den silebilir.
- Telefon ve bilgisayar arasında bağlantı yoksa ve uygulama LTW'ye AppContext gönderirse, uygulama "Bilgisayar bağlı değil" iletisiyle onContextResponseError alır.
- Bağlantı yeniden kurulduğunda , onContextRequestReceived yeniden çağrılır. Uygulama daha sonra geçerli AppContext'i LTW'ye gönderebilir.
- onSyncServiceDisconnected veya SDK'yı kaldırdıktan sonra uygulama appContext göndermemelidir.
Aşağıda bir kod örneği verilmiştir. AppContext'te gerekli ve isteğe bağlı tüm alanlar için lütfen AppContext açıklamasına bakın.
Aşağıdaki Android kod parçacığı, Süreklilik SDK'sını kullanarak API isteklerinin nasıl yapılacağını gösterir:
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()}"
}
}
Tümleştirme doğrulama adımları
Süreklilik SDK'sının uygulamanızda tümleştirmesini doğrulamak için şu adımları izleyin:
Hazırlık
Tümleştirme doğrulamasına hazırlanmak için aşağıdaki adımlar gereklidir:
Özel LTW'nin yüklendiğinden emin olun.
LTW'yi bilgisayarınıza bağlayın:
Yönergeler için bkz. Bilgisayarınızda mobil cihazınızı yönetme .
Uyarı
QR kodunu taradıktan sonra LTW'ye yönlendirilmezseniz, lütfen önce LTW'yi açın ve uygulama içindeki QR kodunu tarayın.
İş ortağı uygulamasının Süreklilik SDK'sını tümleştirdiğini doğrulayın.
Validation
Ardından, tümleştirmeyi doğrulamak için şu adımları izleyin:
- Uygulamayı başlatın ve SDK'yi başlatın. onContextRequestReceived öğesinin çağrıldığını onaylayın.
- onContextRequestReceived çağrıldıktan sonra uygulama AppContext'i LTW'ye gönderebilir. AppContext'i gönderdikten sonra onContextResponseSuccess çağrılırsa SDK tümleştirmesi başarılı olur.
- Uygulama, bilgisayar kilitli veya bağlantısı kesilmiş durumdayken AppContext gönderirse, onContextResponseError'ın "Bilgisayar bağlı değil" ile çağrıldığını doğrulayın.
- Bağlantı geri yüklendiğinde onContextRequestReceived öğesinin yeniden çağrıldığından ve uygulamanın geçerli AppContext'i LTW'ye gönderebildiğinden emin olun.
Aşağıdaki ekran görüntüsünde, bilgisayarın bağlantısı "Bilgisayar bağlı değil" hata iletisiyle kesildiğinde günlük girdisi ve onContextRequestReceived yeniden çağrıldığında yeniden bağlandıktan sonra günlük girişi gösterilir.
AppContext
Windows Resume, AppContext'i, Windows Resume'un hangi uygulamanın devam ettirileceğini ve uygulamanın hangi bağlamda devam ettirileceğini anlayabilmesini sağlayan meta veriler olarak tanımlar. Uygulamalar, kullanıcıların uygulamalarında yaptıklarına birden çok cihazda geri dönmelerini sağlamak için etkinlikleri kullanabilir. Herhangi bir mobil uygulama tarafından oluşturulan etkinlikler, bu cihazlar Cihazlar Arası Deneyim Konağı (CDEH) ile donatıldığında kullanıcıların Windows cihazlarında görünür.
Her uygulama farklıdır ve özgeçmiş için hedef uygulamayı ve bağlamı anlamak için Windows'ta belirli uygulamalara kadar olan hedef uygulamayı anlamak Windows'a bağlıdır. Windows Özgeçmiş, tüm birinci taraf ve üçüncü taraf uygulama özgeçmiş senaryoları için gereksinimleri karşılayan genel bir şema kullanır.
contextId
- Gerekli: Evet
- Açıklama: Bu, bir AppContext'i diğerinden ayırmak için kullanılan benzersiz bir tanımlayıcıdır. Her AppContext'in benzersiz bir şekilde tanımlanabilir olmasını sağlar.
- Kullanım: Çakışmaları önlemek için her AppContext için benzersiz bir contextId oluşturduğunuzdan emin olun.
type
- Gerekli: Evet
- Açıklama: Bu, Windows Bağlantısı'na (LTW) gönderilen AppContext türünü gösteren ikili bir bayraktır. Değerin requestedContextType ile tutarlı olması gerekir.
- Kullanım: Bu bayrağı gönderdiğiniz bağlam türüne göre ayarlayın. Örneğin,
ProtocolConstants.TYPE_RESUME_ACTIVITY.
createTime
- Gerekli: Evet
- Açıklama: Bu zaman damgası AppContext'in oluşturma zamanını temsil eder.
- Kullanım: AppContext'in oluşturulduğu zamanı tam olarak kaydedin.
intentUri
- Gerekli: Hayır, web bağlantısı sağlanmışsa
- Açıklama: Bu URI, kaynak cihazdan teslim edilen AppContext'e hangi uygulamanın devamebileceğini gösterir.
- Kullanım: Bağlamı işlemek için belirli bir uygulama belirtmek istiyorsanız bunu sağlayın.
web bağlantısı
- Gerekli mi: Hayır, eğer intentUri sağlanmışsa
- Açıklama: Bu URI, mağaza uygulamalarını kullanmamayı seçerse uygulamanın web uç noktasını başlatmak için kullanılır. Bu parametre yalnızca intentUri sağlanmadığında kullanılır. Her ikisi de sağlanmışsa, uygulamayı Windows'ta sürdürmek için intentUri kullanılır.
- Kullanım: Yalnızca uygulama web uç noktalarında devam etmek isteyip mağaza uygulamalarını yeniden başlatmak istemiyorsa kullanılabilir.
appId (uygulama kimliği)
- Gerekli: Evet
- Açıklama: Bu, bağlamın olduğu uygulamanın paket adıdır.
- Kullanım: Bunu uygulamanızın paket adı olarak ayarlayın.
title
- Gerekli: Evet
- Açıklama: Bu, belge adı veya web sayfası başlığı gibi AppContext'in başlığıdır.
- Kullanım: AppContext'i temsil eden anlamlı bir başlık sağlayın.
Önizleme
- Gerekli: Hayır
- Açıklama: Bunlar AppContext'i temsil eden önizleme görüntüsünün baytlarıdır.
- Kullanım: Kullanıcılara AppContext'in görsel bir gösterimini sağlamak için varsa bir önizleme görüntüsü sağlayın.
Ömür
- Gerekli: Hayır
- Açıklama: Bu, milisaniye cinsinden yaşam süresidir
AppContext. Yalnızca devam eden senaryolar için kullanılır. Ayarlanmadıysa, varsayılan değer 5 dakikadır. - Kullanım: Geçerli olması gereken zamanı
AppContexttanımlamak için bunu ayarlayın. En fazla 5 dakikaya kadar bir değer ayarlayabilirsiniz. Daha büyük değerler otomatik olarak 5 dakikaya kısaltılır.
Amaç URI'leri
URI'ler, belirli bir görevi gerçekleştirmek için başka bir uygulama başlatmanıza olanak tanıyarak uygulamadan uygulamaya senaryolara yardımcı olur. URI'leri kullanarak uygulama başlatma hakkında daha fazla bilgi için Bir URI için Varsayılan Windows Uygulamasını Başlatma ve Uygulama İçeriğine Derin Bağlantılar Oluşturma | Android Geliştiriciler belgelerine bakın.
Windows'da API yanıtlarını işleme
Bu bölümde, Windows uygulamalarında API yanıtlarının nasıl işleneceğini açıklanmaktadır. Süreklilik SDK'sı, Win32 ve WinUI uygulamaları için API yanıtlarını işlemek için bir yol sağlar.
Win32 uygulama örneği
Win32 uygulamalarının protokol URI başlatma işlemini işlemesi için aşağıdaki adımlar gereklidir:
İlk olarak, kayıt defterine aşağıdaki gibi bir giriş yapılması gerekir:
[HKEY_CLASSES_ROOT\partnerapp] @="URL:PartnerApp Protocol" "URL Protocol"="" [HKEY_CLASSES_ROOT\partnerapp\shell\open\command] @="\"C:\\path\\to\\PartnerAppExecutable.exe\" \"%1\""Başlatma, Win32 uygulamasının ana işlevinde işlenmelidir:
#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; }
WinUI uygulamaları
Paketlenmiş WinUI uygulamaları için protokol URI'si projenin uygulama bildirimine kaydedilebilir. Aşağıdaki adımlarda bir WinUI uygulamasında protokol etkinleştirmenin nasıl işleneceğini gösterilmektedir.
İlk olarak, protokol URI'si dosyaya
Package.appxmanifestaşağıdaki gibi kaydedilir:<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>
WinUI 3 örneği
Aşağıdaki kod parçacığı, Windows Uygulama SDK'sı ile bir C++ WinUI uygulamasında protokol etkinleştirmenin nasıl işleneceğini gösterir:
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
}
}
Web bağlantısı
Web bağlantısı kullanıldığında uygulamanın web uç noktası başlatılır. Uygulama geliştiricilerin Android uygulamasından sağlanan web bağlantısının geçerli olduğundan emin olmaları gerekir çünkü Windows Özgeçmiş, sağlanan web bağlantısına yeniden yönlendirmek için sistemin varsayılan tarayıcısını kullanır.
Windows Özgeçmiş'ten alınan bağımsız değişkenleri işleme
Her uygulamanın, alınan bağımsız değişkeni seri durumdan çıkarmak ve şifresini çözmek, ardından devam eden veriyi telefondan bilgisayara aktarmak için bilgileri buna göre işlemesi gerekliliği vardır. Örneğin, bir çağrının aktarılması gerekiyorsa uygulamanın bu bağlamı telefondan iletişim kurabilmesi ve masaüstü uygulamasının bu bağlamı uygun şekilde anlayıp yüklemeye devam etmesi gerekir.
İlgili içerik
Windows developer