Telefon Bağlantısı - Sorunsuz görev sürekliliği

"Windows Bağlantısı" paketini yüklemiş olan Android mobil cihazlar, Windows bilgisayarınızda (web sitesi URL'leri, belge bağlantıları, müzik parçaları vb.) devam etmek için Android uygulamanızdaki son görevleri program aracılığıyla paylaşabilir.

Cihazlar Arası Görev Sürekliliği, Windows Görev Çubuğu ile daha derin bir yerel tümleştirme sunmak ve müşterilere doğal ve sezgisel bir şekilde daha iyi hizmet vermek için Süreklilik SDK'sını kullanacak şekilde gelişmektedir. Telefon Bağlantısı görev sürekliliği uygulamasının özgün uygulaması hala desteklense de, yeni uygulamalar için Windows Görev Çubuğu tümleştirmesi için Süreklilik SDK'sında Cihazlar Arası Özgeçmiş (XDR) kullanmanızı öneririz. Daha fazla bilgi edinin: Süreklilik SDK'sı (Android ve Windows Uygulamaları) kullanarak Cihazlar Arası Özgeçmiş (XDR).

Süreklilik SDK'sı, en son Android cihaz görevlerinizi doğrudan Windows Görev Çubuğu'ndan (Telefon Bağlantısı uygulama arabirimine güvenmenize gerek kalmadan) sürdürmenize yardımcı olmak için Görev devamlılığı simgeleri görüntüleyen Cihazlar Arası Özgeçmiş (XDR) ile daha sorunsuz cihazlar arası deneyimler sağlar.

Android uygulamanızdaki son görevleri (web sitesi URL'leri, belge bağlantıları, müzik parçaları vb.) Program aracılığıyla Telefon Bağlantısı'nın ayarlandığı bir Windows bilgisayarla nasıl paylaşacağınızı öğrenin. Bu özellik yalnızca Telefon Bağlantısı deneyimleri için desteklenen cihazlarda kullanılabilir.

Senaryo gereksinimleri

Android uygulamanızın "Windows bağlantısı" görev sürekliliğine erişebilmesi için aşağıdaki koşulların karşılanması gerekir:

  • Do sync valid web URL'leri windows bilgisayar tarafından erişilebilir
  • 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
  • Dakikada 60 kereden fazla eşitleme YAPMAYIN
  • Kullanıcı uygulama deneyiminizle etkileşime geçmiyorsa içeriği EŞITLEMEYİN

Telefon Bağlantısı, eşitlenen içeriğinizi Uygulamalar düğümünde "Son kullanılanlar" ve "Son kullanılan web siteleri" altında ve bir bildirim açılır öğesinde gösterir.

Son kullanılan uygulamaların ve web sitelerinin Telefon Bağlantısı ekran görüntüsü

Süreklilik SDK'sını (Android ve Windows Uygulamaları) kullanan Cihazlar Arası Özgeçmiş (XDR), eşitlenmiş içeriğinizi Windows Görev Çubuğu'nda ortaya çıkaracaktır.

Windows Görev Çubuğu ekran görüntüsü

Sınırlı Erişim Özelliği (LAF) onayı

Telefon Bağlantısı görev sürekliliği Sınırlı Erişim Özelliğidir (LAF). Erişim kazanmak için, Android mobil cihazlarda önceden yüklenmiş "Windows Bağlantısı" paketiyle birlikte çalışabilmek için Microsoft'tan onay almanız gerekir.

Erişim istemek için, aşağıda listelenen bilgileri içeren e-posta wincrossdeviceapi@microsoft.com 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 için Google Play store bağlantısı

İstek onaylanırsa özelliğin kilidini açma yönergelerini alırsınız. Onaylar, senaryonuzun yukarıda özetlenen Senaryo Gereksinimleri'ni karşılaması koşuluyla iletişiminizi temel alır.

Veri İşleme

Microsoft, Telefon Bağlantısı görev sürekliliğini kullanarak verilerinizi Microsoft Hizmet Sözleşmesi'ne ve Microsoft Gizlilik Bildirimi'ne uygun olarak işler ve aktarır. Kullanıcının bağlı cihazlarına aktarılan veriler, cihazlar arasında güvenilir veri aktarımı sağlamak için Microsoft'un bulut hizmetleri aracılığıyla işlenebilir. Bu API tarafından işlenen veriler, Microsoft'un bulut hizmetleri tarafından son kullanıcı denetimine tabi olarak korunmaz.

Uygulama paketinizle tümleştirdiğiniz Süreklilik SDK'sı, API'ye sağlanan verilerin yalnızca güvenilen Microsoft paketleri tarafından işlenmesini sağlar.

Tümleştirmeye yönelik genel yönergeler ve kod örnekleri aşağıdadır. Ayrıntılı tümleştirme kılavuzu için SDK'nın Kotlin belgesine bakın.

Android uygulama manifest bildirimleri

Uygulama bildirimi, Android uygulamanız için şema görevi görecek bir XML dosyasıdır. Bildirim dosyası, işletim sistemine uygulamanızın yapısı, bileşenleri, izinleri vb. hakkında bilgi sağlar. "Windows Bağlantısı" ile görev sürekliliği için aşağıdaki bildirimler gereklidir.

Özellik Meta Verileri

İş ortağı uygulamalarının önce uygulama bildiriminize meta verileri kaydetmesi gerekir.

Uygulama bağlamı sözleşmesine katılmak için desteklenen uygulama bağlamı türü için meta verilerin bildirilmesi gerekir. Örneğin, Uygulama İletimi özelliğine uygulama bağlam sağlayıcısı meta verileri eklemek için:

<application...>
<meta-data
android:name="com.microsoft.crossdevice.applicationContextProvider"
android:value="true" />
</application>

Uygulamanız birden fazla uygulama bağlamı türünü destekliyorsa, her meta veri türü eklenmelidir. Şu anda desteklenen meta veri türleri şunlardır:

<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" />

Yeni bir tür eklemek için meta veri adı biçimi "com.microsoft.crossdevice.xxxProvider" olmalıdır.

Uygulamaların bildirimde tetikleyici türü meta verilerini de bildirmesi gerekir. Bu bildirimler, sistemin uygulamanın Load-Time Dokuma'ya (LTW) belirli özelliklerin etkin olduğunu nasıl ve ne zaman bildirmesi gerektiğini belirlemesine yardımcı olur.

Özgün Donanım Üreticisi (OEM) ne olursa olsun, uygulamanın sisteme bildirimden sorumlu olduğu ve tüm cihazlarda etkinleştirildiği kendi kendine bildirim tetikleyicisi için tetikleyici türü şu şekilde bildirilmelidir:

<application ...
<meta-data
android:name="com.microsoft.crossdevice.trigger.PartnerApp"
android:value="the sum value of all features' binary codes" />

</application>

Uygulamanın yalnızca belirli OEM cihazlarında etkinleştirilen "Windows'a Bağlantı" özelliğini tetikleme amacıyla sistem API'lerine bağlı olduğu bir sistem API'si tetikleyicisi için tetikleyici türü şu şekilde bildirilmelidir:

<application ...
<meta-data
android:name="com.microsoft.crossdevice.trigger.SystemApi"
android:value="the sum value of all features' binary codes" />

</application>

Özelliklerin ikili kodları şu şekildedir:

APPLICATION_CONTEXT: 1
BROWSER_HISTORY:     2
RESUME_ACTIVITY:     4

Uygulama bildirim kaydı şu örneğe benzer olabilir:

<?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> 

Uygulama bağlamı göndermek için kod örneği

Uygulama bildirimi bildirimleri eklendikten sonra "Windows bağlantısı" iş ortağı uygulamalarının şunları yapmanız gerekir:

  1. Süreklilik SDK'sı için Initialize ve DeInitialize işlevlerini çağırmak için uygun zamanlamayı belirleyin. Initialize işlevi çağrıldıktan sonra, uygulayan IAppContextEventHandler bir geri çağırma tetiklenmelidir.

  2. Süreklilik SDK'sı başlatıldıktan sonra çağrılırsa onContextRequestReceived() bağlantının kurulduğunu gösterir. Uygulama daha sonra LTW'ye gönderebilir AppContext (oluşturma ve güncelleştirme dahil) veya LTW'den silebilir AppContext .

içinde erişim belirteçleri gibi hassas verilerin AppContextgönderilmesini önlemeyi unutmayın. Ayrıca, yaşam süresi çok kısa ayarlanırsa, AppContext bilgisayara gönderilmeden önce süresi dolabilir. En az 5 dakikalık bir ömrün ayarlanması önerilir.

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()}"
    }
}

Gerekli ve isteğe bağlı tüm alanlar için AppContext Açıklaması'na bakın.

AppContext açıklaması

Uygulama bağlamı gönderilirken iş ortağı uygulamaları tarafından aşağıdaki değerler sağlanmalıdır:

Anahtar Değer Ek bilgiler
contextId [gerekli] Bunu diğer uygulama bağlamlarından ayırmak için kullanılır. Her uygulama bağlamı için benzersizdir. Biçim: "${packageName}.${UUID.randomUUID()}"
tür [gerekli] LTW'ye hangi uygulama bağlam türünün gönderildiğini gösteren ikili bayrak. Değer yukarıdaki requestedContextType ile tutarlı olmalıdır
createTime[required] [FR1] Uygulama bağlamının oluşturma zamanını temsil eden zaman damgası.
lastUpdatedTime[gerekli] Uygulama bağlamının son güncelleştirilmiş zamanını temsil eden zaman damgası. Uygulama bağlamının herhangi bir alanı güncelleştirildiğinde, güncelleştirilmiş saatin kaydedilmesi gerekir.
teamId [isteğe bağlı] Uygulamanın ait olduğu kuruluşu veya grubu tanımlamak için kullanılır.
intentUri [isteğe bağlı] Hangi uygulamanın kaynak cihazdan teslim edilen uygulama bağlamını sürdürebileceğini belirtmek için kullanılır. Uzunluk üst sınırı 2083 karakterdir.
appId [isteğe bağlı] Bağlamın olduğu uygulamanın paketi.
title[isteğe bağlı] Belge adı veya web sayfası başlığı gibi bu uygulama bağlamının başlığı.
weblink[isteğe bağlı] Uygulama bağlamını sürdürmek için tarayıcıda yüklenecek web sayfasının URL'si. Uzunluk üst sınırı 2083 karakterdir.
önizleme[isteğe bağlı] Uygulama bağlamını temsil eden önizleme görüntüsünün baytları
extras[isteğe bağlı] Devam eden cihazda uygulama bağlamını sürdürmek için gereken uygulamaya özgü durum bilgilerini içeren anahtar-değer çifti nesnesi. Uygulama bağlamı benzersiz verilerine sahip olduğunda sağlamanız gerekir.
LifeTime[isteğe bağlı] Uygulama bağlamının milisaniye cinsinden ömrü. Yalnızca devam eden senaryo için kullanılır, ayarlanmadıysa varsayılan değer 30 gündür).

Tarayıcı Sürekliliği kod örneği

Bu örnek, diğer AppContext türlerden farklı olan Tarayıcı Sürekliliği türünün kullanımını vurgular.

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)
    }

    //……
}

Gerekli ve isteğe bağlı tüm alanlar için bkz. BrowserContext Description.

BrowserContext açıklaması

İş ortağı uygulamaları tarayıcı geçmişi eklemek için yöntemini çağırabilir addBrowserContext . Tarayıcı geçmişi eklenirken aşağıdaki değerler sağlanmalıdır:

Anahtar Değer
browserWebUri [gerekli] Bilgisayarda tarayıcıda açılacak bir web URI'si (http: veya https:).
title [required] Web sayfasının başlığı.
zaman damgası [gerekli] Web sayfasının ilk kez açıldığı veya son yenilendiği zaman damgası.
favIcon [isteğe bağlı] Web sayfasının bayt cinsinden favicon değeri genel olarak küçük olmalıdır.

Tümleştirme doğrulama adımları

  1. Özel LTW'nin yüklendiğinden emin olarak hazırlanın. LTW'nin bilgisayara bağlı olduğunu onaylayın: Bilgisayarınızda mobil cihazınızı yönetme. LTW'nin Telefon Bağlantısı: Telefon Bağlantısı gereksinimleri ve kurulumuna bağlı olduğunu onaylayın. QR kodunu taradıktan sonra LTW'ye atlayamazsanız, önce LTW'yi açın ve uygulama içindeki QR kodunu tarayın. Son olarak, iş ortağı uygulamasının Süreklilik SDK'sını tümleştirdiğini doğrulayın.

  2. Uygulamayı başlatıp Süreklilik SDK'sını başlatarak doğrulayın. Bunun çağrıldığını onContextRequestReceived() onaylayın. Çağrıldıktan sonra onContextRequestReceived() uygulama bağlamını LTW'ye gönderebilir. Uygulama bağlamı gönderildikten sonra çağrılırsa onContextResponseSuccess() SDK tümleştirmesi başarılı olur.

GitHub'da Windows Cihazlar Arası deposu

GitHub'daki Windows Cihazlar Arası Depo'da Windows Cihazlar Arası SDK'yı projenizle tümleştirme hakkında bilgi edinin.

SSS listesi için bkz. Telefon Bağlantısı Sık Sorulan Sorular.