Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Artikel ini menyediakan panduan komprehensif untuk pengembang pihak pertama dan pihak ketiga tentang cara mengintegrasikan fitur menggunakan SDK Kelangsungan di aplikasi Anda. SDK Kelangsungan memungkinkan pengalaman lintas perangkat yang mulus, memungkinkan pengguna untuk melanjutkan aktivitas di berbagai platform, termasuk Android dan Windows.
Dengan mengikuti panduan ini, Anda dapat membuat pengalaman pengguna yang lancar dan terintegrasi di beberapa perangkat dengan memanfaatkan XDR menggunakan Continuity SDK.
Penting
Pengenalan di Windows akan Dilaksanakan Kembali
Resume adalah fitur Akses Terbatas (LAF). Untuk mendapatkan akses ke API ini, Anda harus mendapatkan persetujuan dari Microsoft untuk berinteroperasi dengan paket "Tautkan ke Windows" di perangkat seluler Android.
Untuk meminta access, email wincrossdeviceapi@microsoft.com dengan informasi yang tercantum di bawah ini:
- Deskripsi pengalaman pengguna Anda
- Cuplikan layar aplikasi Anda di mana pengguna secara asli mengakses web atau dokumen
- PackageId aplikasi Anda
- URL Google Play Store untuk aplikasi Anda
Jika permintaan disetujui, Anda akan menerima instruksi tentang cara membuka kunci fitur. Persetujuan akan didasarkan pada komunikasi Anda, asalkan skenario Anda memenuhi Persyaratan Skenario yang diuraikan.
Prasyarat
Untuk aplikasi Android, pastikan persyaratan berikut terpenuhi sebelum mengintegrasikan Continuity SDK:
- Versi SDK Minimum: 24
- Versi Kotlin: 1.9.x
- Tautan ke Windows (LTW): 1.241101.XX
Untuk aplikasi Windows, pastikan persyaratan berikut terpenuhi:
- Versi Windows Minimum: Windows 11
- Lingkungan Pengembangan: Visual Studio 2019 atau yang lebih baru
Nota
Aplikasi iOS tidak didukung untuk integrasi dengan SDK Kelangsungan saat ini.
Mengonfigurasi lingkungan pengembangan Anda
Bagian berikut memberikan instruksi langkah demi langkah untuk menyiapkan lingkungan pengembangan untuk aplikasi Android dan Windows.
Penyiapan Android
Untuk menyiapkan lingkungan pengembangan untuk Android, ikuti langkah-langkah berikut:
Untuk menyiapkan bundel, unduh dan gunakan file .aar melalui pustaka yang disediakan dalam rilis SDK Lintas Perangkat Windows berikut.
Tambahkan tag meta di file AndroidManifest.xml aplikasi Android Anda. Cuplikan berikut menunjukkan cara menambahkan tag meta yang diperlukan:
<meta-data android:name="com.microsoft.crossdevice.resumeActivityProvider" android:value="true" /> <meta-data android:name="com.microsoft.crossdevice.trigger.PartnerApp" android:value="4" />
Langkah-langkah integrasi API
Setelah deklarasi manifes, pengembang aplikasi dapat dengan mudah mengirim konteks aplikasi mereka dengan mengikuti contoh kode sederhana.
Aplikasi harus:
- Inisialisasi/Deinisialisasi SDK Kontinuitas:
- Aplikasi harus menentukan waktu yang tepat untuk memanggil fungsi Inisialisasi dan DeInitialisasi.
- Setelah memanggil fungsi Inisialisasi, panggilan balik yang mengimplementasikan IAppContextEventHandler harus dipicu.
- Kirim/Hapus AppContext:
- Setelah menginisialisasi SDK, jika onContextRequestReceived dipanggil, itu menunjukkan koneksi dibuat. Aplikasi kemudian dapat mengirim (termasuk membuat dan memperbarui) AppContext ke LTW atau menghapus AppContext dari LTW.
- Jika tidak ada koneksi antara telepon dan PC dan aplikasi mengirim AppContext ke LTW, aplikasi akan menerima onContextResponseError dengan pesan "PC tidak terhubung."
- Ketika koneksi dibuat kembali, onContextRequestReceived dipanggil lagi. Aplikasi kemudian dapat mengirim AppContext saat ini ke LTW.
- Setelah onSyncServiceDisconnected atau deinisialisasi SDK, aplikasi tidak boleh mengirim AppContext.
Di bawah ini adalah contoh kode. Untuk semua bidang yang diperlukan dan opsional di AppContext, silakan lihat deskripsi AppContext.
Cuplikan kode Android berikut menunjukkan cara membuat permintaan API menggunakan Continuity SDK:
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()}"
}
}
Langkah-langkah validasi integrasi
Untuk memvalidasi integrasi SDK Kelangsungan di aplikasi Anda, ikuti langkah-langkah berikut:
Persiapan
Langkah-langkah berikut diperlukan untuk mempersiapkan validasi integrasi:
Pastikan LTW pribadi terpasang.
Sambungkan LTW ke PC Anda:
Lihat Cara mengelola perangkat seluler Anda di PC untuk mengetahui petunjuknya.
Nota
Jika setelah memindai kode QR, Anda tidak dialihkan ke LTW, buka LTW terlebih dahulu dan pindai kode QR dalam aplikasi.
Verifikasi bahwa aplikasi mitra telah mengintegrasikan SDK Kelangsungan.
Validation
Selanjutnya, ikuti langkah-langkah berikut untuk memvalidasi integrasi:
- Luncurkan aplikasi dan inisialisasi SDK. Konfirmasikan bahwa onContextRequestReceived dipanggil.
- Setelah onContextRequestReceived dipanggil, aplikasi dapat mengirim AppContext ke LTW. Jika onContextResponseSuccess dipanggil setelah mengirim AppContext, integrasi SDK berhasil.
- Jika aplikasi mengirim AppContext saat PC terkunci atau terputus, verifikasi bahwa onContextResponseError dipanggil dengan "PC tidak tersambung."
- Ketika koneksi dipulihkan, pastikan onContextRequestReceived dipanggil lagi dan aplikasi kemudian dapat mengirim AppContext saat ini ke LTW.
Cuplikan layar di bawah ini menunjukkan entri log ketika PC terputus dengan pesan kesalahan "PC tidak terhubung" dan entri log setelah koneksi ulang ketika onContextRequestReceived dipanggil lagi.
AppContext
XDR mendefinisikan AppContext sebagai metadata di mana XDR dapat memahami aplikasi mana yang akan dilanjutkan, bersama dengan konteks di mana aplikasi harus dilanjutkan. Aplikasi dapat menggunakan aktivitas untuk memungkinkan pengguna kembali ke apa yang mereka lakukan di aplikasi mereka, di beberapa perangkat. Aktivitas yang dibuat oleh aplikasi seluler apa pun muncul di perangkat Windows pengguna selama perangkat tersebut telah disediakan Cross Device Experience Host (CDEH).
Setiap aplikasi berbeda, dan terserah Windows untuk memahami aplikasi target untuk melanjutkan, dan terserah aplikasi tertentu di Windows untuk memahami konteksnya. XDR mengusulkan skema generik yang dapat memenuhi persyaratan untuk semua pihak pertama serta skenario resume aplikasi pihak ketiga.
contextId
- Diperlukan: Ya
- Deskripsi: Ini adalah pengidentifikasi unik yang digunakan untuk membedakan satu AppContext dari yang lain. Ini memastikan bahwa setiap AppContext dapat diidentifikasi secara unik.
- Penggunaan: Pastikan untuk menghasilkan contextId unik untuk setiap AppContext untuk menghindari konflik.
jenis
- Diperlukan: Ya
- Deskripsi: Ini adalah flag biner yang menunjukkan jenis AppContext yang dikirim ke Link ke Windows (LTW). Nilai harus konsisten dengan tipe konteks yang diminta.
- Penggunaan: Atur bendera ini sesuai dengan jenis konteks yang Anda kirim. Contohnya,
ProtocolConstants.TYPE_RESUME_ACTIVITY.
createTime
- Diperlukan: Ya
- Deskripsi: Tanda waktu ini mewakili waktu pembuatan AppContext.
- Penggunaan: Rekam waktu yang tepat saat AppContext dibuat.
intentUri
- Diperlukan: Tidak, jika weblink disediakan
- Deskripsi: URI ini menunjukkan aplikasi mana yang dapat melanjutkan AppContext yang diserahkan dari perangkat asal.
- Penggunaan: Berikan ini jika Anda ingin menentukan aplikasi tertentu untuk menangani konteks.
weblink
- Diperlukan: Tidak, jika intentUri disediakan
- Deskripsi: URI ini digunakan untuk meluncurkan titik akhir web aplikasi jika mereka memilih untuk tidak menggunakan aplikasi penyimpanan. Parameter ini hanya digunakan ketika intentUri tidak disediakan. Jika keduanya disediakan, intentUri akan digunakan untuk melanjutkan aplikasi di Windows.
- Penggunaan: Hanya untuk digunakan jika aplikasi ingin melanjutkan di titik akhir web dan bukan aplikasi penyimpanan.
appId
- Diperlukan: Ya
- Deskripsi: Ini adalah nama paket dari aplikasi yang terkait dengan konteks ini.
- Penggunaan: Atur ini ke nama paket aplikasi Anda.
title
- Diperlukan: Ya
- Deskripsi: Ini adalah judul AppContext, seperti nama dokumen atau judul halaman web.
- Penggunaan: Berikan judul yang bermakna yang mewakili AppContext.
pratinjau
- Diperlukan: Tidak
- Deskripsi: Ini adalah byte gambar pratinjau yang dapat mewakili AppContext.
- Penggunaan: Berikan gambar pratinjau jika tersedia untuk memberi pengguna representasi visual AppContext.
Seumur hidup
- Diperlukan: Tidak
- Deskripsi: Ini adalah masa pakai
AppContextdalam milidetik. Ini hanya digunakan untuk skenario yang sedang berlangsung. Jika tidak diatur, nilai defaultnya adalah 5 menit. - Penggunaan: Atur ini untuk menentukan berapa lama
AppContextseharusnya valid. Anda dapat mengatur nilai hingga maksimum 5 menit. Nilai yang lebih besar akan secara otomatis dipersingkat menjadi 5 menit.
Intent URI
URI memungkinkan Anda meluncurkan aplikasi lain untuk melakukan tugas tertentu, memungkinkan skenario aplikasi-ke-aplikasi yang bermanfaat. Untuk informasi selengkapnya tentang meluncurkan aplikasi menggunakan URI, lihat Luncurkan aplikasi default Windows untuk URI dan Buat Deep Links ke Konten Aplikasi | Pengembang Android.
Menangani respons API di Windows
Bagian ini menjelaskan cara menangani respons API di aplikasi Windows. SDK Kelangsungan menyediakan cara untuk menangani respons API untuk aplikasi Win32 dan WinUI.
Contoh aplikasi Win32
Agar aplikasi Win32 dapat menangani peluncuran URI protokol, langkah-langkah berikut diperlukan:
Pertama, entri perlu dibuat ke registri sebagai berikut:
[HKEY_CLASSES_ROOT\partnerapp] @="URL:PartnerApp Protocol" "URL Protocol"="" [HKEY_CLASSES_ROOT\partnerapp\shell\open\command] @="\"C:\\path\\to\\PartnerAppExecutable.exe\" \"%1\""Peluncuran harus ditangani dalam fungsi utama aplikasi 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; }
Aplikasi WinUI
Untuk aplikasi WinUI yang dikemas, URI protokol dapat didaftarkan dalam manifes aplikasi proyek. Langkah-langkah berikut menunjukkan cara menangani aktivasi protokol di aplikasi WinUI.
Pertama, URI protokol terdaftar dalam
Package.appxmanifestfile sebagai berikut:<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>
Contoh WinUI 3
Cuplikan kode berikut menunjukkan cara menangani aktivasi protokol di aplikasi C++ WinUI dengan 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
}
}
Tautan Web
Menggunakan weblink akan meluncurkan titik akhir web aplikasi. Pengembang aplikasi perlu memastikan bahwa weblink yang disediakan dari aplikasi Android mereka valid karena XDR akan menggunakan browser default sistem untuk mengalihkan ke tautan web yang disediakan.
Menangani argumen yang diperoleh dari Resume Lintas Perangkat
Adalah tanggung jawab setiap aplikasi untuk mendeserialisasi dan mendekripsi argumen yang diterima dan memproses informasi yang sesuai untuk mentransfer konteks yang sedang berlangsung dari telepon ke PC. Misalnya, jika panggilan perlu ditransfer, aplikasi harus dapat mengomunikasikan konteks tersebut dari telepon dan aplikasi desktop harus memahami konteks tersebut dengan tepat dan melanjutkan pemuatan.
Konten terkait
Windows developer