کاربران اغلب کارهایی را در تلفن اندرویدی خود شروع میکنند - مانند بررسی یک سند، مرتبسازی پیامها یا مرور مجموعهای از موارد - و سپس میخواهند به یک گوگلبوک با صفحه نمایش بزرگتر، صفحه کلید فیزیکی و فضای کاری چند پنجرهای آن نقل مکان کنند.
ویژگی «ادامه دادن» در اندروید ۱۷ (سطح API ۳۷) و بالاتر، نوار وظیفه گوگلبوک را قادر میسازد تا یک آیکون برنامه (به نام پیشنهاد ) برای فعالیتی که کاربر در تلفن همراه نزدیک خود در حال انجام آن بوده است، نمایش دهد. کاربران میتوانند با یک کلیک، فعالیت خود را در گوگلبوک خود ادامه دهند.
پیادهسازی قابلیت انتقال بین دستگاهی (cross-device handoff) به برنامه شما اجازه میدهد تا زمینه فعالیت (activity context) را منتقل کند، بنابراین کاربر میتواند گردش کار خود را، چه در برنامه اندروید تطبیقی شما و چه در مرورگر دسکتاپ، دقیقاً از همان جایی که در تلفن خود متوقف شده بود، از سر بگیرد.
یک جریان تحویل را انتخاب کنید
قبل از فعال کردن انتقال بین دستگاهی، تصمیم بگیرید که هر فعالیت در برنامه تلفن شما چگونه باید باز شود وقتی کاربر پیشنهاد ادامه در Googlebook را انتخاب میکند:
| جریان تحویل | هدف در گوگل بوک | بهترین برای | API کلید |
|---|---|---|---|
| انتقال از برنامه به برنامه دیگر | اجرای برنامه بومی اندروید در پنجره دسکتاپ | برنامههای بهینه شده برای صفحه نمایشهای بزرگ و پنجرههای دسکتاپ در گوگل پلی | HandoffActivityData.Builder |
| انتقال از برنامه به برنامه دیگر با قابلیت اتصال مجدد از طریق وب | برنامه بومی اندروید در صورت نصب؛ در غیر این صورت، یک URL در مرورگر پیشفرض دسکتاپ | برنامههایی که برای تجربه پنجره دسکتاپ بومی بهینه شدهاند اما در صورت عدم نصب برنامه روی گوگلبوک، به یک مرورگر جایگزین قابل اعتماد نیاز دارند | setFallbackUri |
| انتقال مستقیم به وب | آدرس اینترنتی (URL) در مرورگر پیشفرض دسکتاپ (یا اگر برای پیوندهای برنامه اندروید پیکربندی شده باشد، توسط برنامه اصلی رهگیری میشود) | گردشهای کاری که در آنها برنامه وب شما، تجربه اصلی دسکتاپ است | HandoffActivityData.createWebHandoff |
فعال کردن handoff برای یک فعالیت
گزینه «ادامه روشن» به طور پیشفرض غیرفعال است و برای هر فعالیت پیکربندی میشود. این مراحل را در هر فعالیت ارسال در تلفن دنبال کنید:
- تابع
setHandoffEnabledرا فراخوانی کنید و پس از اینکه activity حالت مورد نیاز برای handoff را بارگذاری کرد، مقدارtrueبه آن بدهید. پس از فعالسازی، سیستم میتواند دادههای handoff را در حالی که activity در پیشزمینه است یا به پسزمینه منتقل میشود، درخواست کند. - تابع
onHandoffActivityDataRequestedرا برای برگرداندن یک شیءHandoffActivityDataغیر تهی، نادیده بگیرید. میتوانید در هر زمانی ازisHandoffEnabledبرای بررسی فعال بودن handoff برای فعالیت مورد نظر، پرسوجو کنید.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.os.Bundle
import android.os.PersistableBundle
class DocumentEditorActivity : Activity() {
private var documentId: String = "doc_42"
private var scrollOffsetPx: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Enable handoff once the activity is ready to transfer state.
setHandoffEnabled(true, null)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val extras = PersistableBundle().apply {
putString(EXTRA_DOCUMENT_ID, documentId)
putInt(EXTRA_SCROLL_OFFSET, scrollOffsetPx)
}
return HandoffActivityData.Builder(getComponentName())
.setExtras(extras)
.build()
}
companion object {
const val EXTRA_DOCUMENT_ID = "extra_document_id"
const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
}
}
وضعیت فعالیت بسته برای handoff
سیستم در دو سناریو، متد onHandoffActivityDataRequested را فراخوانی میکند:
- انتقال پیشزمینه: فعالیت در پیشزمینه گوشی است و کاربر از نوار وظیفه گوگلبوک، انتقال را آغاز میکند.
- ضبط وضعیت پسزمینه: فعالیت به پسزمینه گوشی منتقل میشود و سیستم، دادههای مربوط به انتقال را در حافظه پنهان (cache) ذخیره میکند تا در صورتی که کاربر بعداً پیشنهاد را در گوگلبوک انتخاب کند، از آنها استفاده کند.
بررسی کنید که آیا درخواست انتقال فعال است یا خیر
با استفاده از isActiveRequest HandoffActivityDataRequestInfo بررسی کنید تا بین یک handoff فعال که توسط کاربر آغاز شده و یک ذخیره پسزمینه تمایز قائل شوید:
- اگر
isActiveRequesttrueرا برگرداند، کاربر به طور فعال درخواست ادامه فعالیت در دستگاه دیگری را در حالی که فعالیت قابل مشاهده است، داده است. - اگر
isActiveRequestfalseرا برگرداند، سیستم در حال ذخیره وضعیت (state) در زمان توقف فعالیت (activity) است.
اگر یک نشانگر بصری روی گوشی نمایش داده شود که تأیید کند وظیفه به Googlebook منتقل میشود، بهروزرسانی رابط کاربری را به صورت ناهمگام برنامهریزی کنید تا onHandoffActivityDataRequested بدون تأخیر بازگردد.
موارد اضافی ایالت و یک پشتیبان وب را ضمیمه کنید
یک دادهی HandoffActivityData شامل اطلاعات زیر است:
- کامپوننت هدف (برای انتقال از برنامه به برنامه مورد نیاز است):
this.getComponentName()(ComponentNameاکتیویتی) یا یکComponentName(this, TargetActivity::class.java)صریح را بهHandoffActivityData.Builderارسال کنید تا مشخص شود کدام اکتیویتی در Googlebook اجرا میشود. - موارد اضافی (اختیاری): یک
PersistableBundleبهsetExtras()ارسال کنید که شامل شناسهها و مختصات رابط کاربری (برای مثال، شناسههای سند باز، کلیدهای تب فعال یا موقعیتهای اسکرول) باشد. حجم بسته باید کمتر از ۵۰ کیلوبایت باشد. - آدرس اینترنتی جایگزین (اختیاری): یک
Uriوب بهsetFallbackUriارسال کنید تا اگر برنامه اندروید شما نصب نشده باشد، گوگلبوک بتواند وظیفه را در مرورگر پیشفرض باز کند.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
import android.os.PersistableBundle
class ArticleReaderActivity : Activity() {
private var articleId: String = "android-desktop-windowing"
private var readingProgressPercent: Int = 45
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHandoffEnabled(
true,
HandoffActivityParams.Builder()
.setAllowHandoffWithoutPackageInstalled(true)
.build()
)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
if (handoffRequestInfo.isActiveRequest()) {
window.decorView.post {
onHandoffStartedToSecondaryDevice()
}
}
val extras = PersistableBundle().apply {
putString(EXTRA_ARTICLE_ID, articleId)
putInt(EXTRA_READING_PROGRESS, readingProgressPercent)
}
val fallbackWebUri = Uri.Builder()
.scheme("https")
.authority("example.com")
.appendPath("articles")
.appendPath(articleId)
.appendQueryParameter("progress", readingProgressPercent.toString())
.build()
return HandoffActivityData.Builder(getComponentName())
.setExtras(extras)
.setFallbackUri(fallbackWebUri)
.build()
}
private fun onHandoffStartedToSecondaryDevice() {
// Save local drafts and update phone UI without blocking handoff.
}
companion object {
const val EXTRA_ARTICLE_ID = "extra_article_id"
const val EXTRA_READING_PROGRESS = "extra_reading_progress"
}
}
پیکربندی انتقال مستقیم به وب
اگر تجربه اصلی دسکتاپ شما در گوگلبوک یک برنامه وب است، HandoffActivityParams به همراه setAllowHandoffWithoutPackageInstalled(true) به setHandoffEnabled ارسال کنید و به جای استفاده از HandoffActivityData.Builder ، HandoffActivityData.createWebHandoff را فراخوانی کنید:
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
class WebDashboardActivity : Activity() {
private var projectId: String = "proj_901"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHandoffEnabled(
true,
HandoffActivityParams.Builder()
.setAllowHandoffWithoutPackageInstalled(true)
.build()
)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val webUri = Uri.Builder()
.scheme("https")
.authority("app.example.com")
.appendPath("projects")
.appendPath(projectId)
.build()
return HandoffActivityData.createWebHandoff(webUri)
}
}
دریافت و بازیابی وضعیت در گوگلبوک
وقتی کاربر پیشنهاد «ادامه به ادامه» را در نوار وظیفه گوگلبوک انتخاب میکند، سیستم ComponentName هدف را در یک پنجره دسکتاپ اجرا میکند و افزونههای PersistableBundle را به Intent اجرا متصل میکند.
در گوگلبوک، با در نظر گرفتن پنجرهبندی دسکتاپ و طرحبندیهای چندبخشی، تحویل ورودی را مدیریت کنید:
- استخراج موارد اضافی تحویل داده شده: در هر دو متد
onCreateوonNewIntentاز اکتیویتی گیرنده، موارد اضافی را ازIntentورودی بازیابی کنید. مدیریتonNewIntentتضمین میکند که اگر اکتیویتی شما از حالت راهاندازیsingleTopاستفاده میکند یا به یک پنجره دسکتاپ موجود مسیردهی میکند، پنجره به مورد تحویل داده شده بهروزرسانی شود. - تطبیق وضعیت با طرحبندیهای چندبخشی: وضعیتی که نمای جزئیات تمامصفحه را در تلفن اشغال میکرد، اغلب در Googlebook به یک مورد انتخابشده در طرحبندی لیست-جزئیات یا صفحه پشتیبانی نگاشت میشود. هم انتخاب لیست اصلی و هم صفحه جزئیات را پر کنید تا پنجره دسکتاپ زمینه کاملی داشته باشد.
- حفظ حالت بازیابیشده در طول تغییر اندازه پنجره: حالت تحویل دادهشده را در یک
ViewModel(SavedStateHandle) ذخیره کنید یا در Jetpack ComposerememberSaveableکنید تا تغییر اندازه پنجره در حالت آزاد در Googlebook، جلسه بازیابیشده را مجدداً تنظیم نکند.
import android.app.Activity
import android.content.Intent
import android.os.Bundle
class DocumentEditorReceiverActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Restore from the handoff intent only on initial launch so subsequent
// desktop window configuration changes use saved instance state.
if (savedInstanceState == null) {
handleHandoffIntent(intent)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleHandoffIntent(intent)
}
private fun handleHandoffIntent(incomingIntent: Intent?) {
val documentId = incomingIntent?.getStringExtra(EXTRA_DOCUMENT_ID)
?: return
val scrollOffsetPx = incomingIntent.getIntExtra(EXTRA_SCROLL_OFFSET, 0)
openDocumentInDesktopWorkspace(
documentId = documentId,
initialScrollOffsetPx = scrollOffsetPx
)
}
private fun openDocumentInDesktopWorkspace(
documentId: String,
initialScrollOffsetPx: Int
) {
// Load the document into the list-detail layout and restore scroll position.
}
companion object {
const val EXTRA_DOCUMENT_ID = "extra_document_id"
const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
}
}
تست هندآف بین گوشی و گوگلبوک
برای تأیید پیادهسازی خود از ابتدا تا انتها:
- هر دو دستگاه را آماده کنید
- هم در گوشی اندروید خود (با اندروید ۱۷ یا بالاتر) و هم در گوگلبوک خود (یا یک دستگاه آزمایشی که در حالت پنجرهای دسکتاپ اجرا میشود) به یک حساب گوگل وارد شوید.
- بلوتوث را روشن کنید و هر دو دستگاه را به یک شبکه وایفای متصل کنید.
- در هر دو دستگاه، تنظیمات > دستگاههای متصل > تنظیمات اتصال > سرویسهای بین دستگاهی > ادامه فعالیت را باز کنید، دستورالعملهای راهاندازی را دنبال کنید و وظایف را فعال کنید. برای پیشنیازهای کامل محیط، به راهاندازی و آزمایش مراجعه کنید.
- برنامه خود را نصب کنید
- برای انتقال از یک برنامه به برنامه دیگر ، نسخه ساخته شده خود را هم روی گوشی و هم روی گوگل بوک نصب کنید.
- برای بازگشت به وب یا انتقال مستقیم به وب ، نسخهٔ ساختهشده را روی گوشی نصب کنید و برنامه را روی گوگلبوک حذف نصب کنید تا بتوانید تأیید کنید که مرورگر، آدرس اینترنتی مورد انتظار را باز میکند.
- شروع فرآیند تحویل کالا
- در گوشی، برنامه خود را باز کنید و به اکتیویتی که handoff را فعال میکند بروید (برای handoff از برنامه به برنامه،
setHandoffEnabled(true, null)را فراخوانی کنید، یا هنگام تست با برنامهای که در Googlebook حذف نصب شده است،HandoffActivityParamsرا باsetAllowHandoffWithoutPackageInstalled(true)ارسال کنید). - در گوگلبوک، سمت راست نوار وظیفه را برای یافتن آیکون برنامه خود با نشان «ادامه دهید» بررسی کنید و آن را انتخاب کنید.
- در گوشی، برنامه خود را باز کنید و به اکتیویتی که handoff را فعال میکند بروید (برای handoff از برنامه به برنامه،
- تأیید بازیابی دسکتاپ
- تأیید کنید که برنامه شما در یک پنجره دسکتاپ (یا برگه مرورگر) در موقعیت دقیق آیتم و اسکرول از طریق گوشی باز میشود.
- اندازه پنجره برنامه را در Googlebook تغییر دهید و تأیید کنید که محتوا و انتخاب بازیابی شده در طول انتقال کلاس اندازه پنجره باقی میمانند.
منابع اضافی
- ساخت برنامههای تطبیقی برای گوگلبوک
- درباره ویژگی «ادامه»
- فعال کردن و سفارشیسازی انتقال بین دستگاهی
- ذخیره حالتهای رابط کاربری
کاربران اغلب کارهایی را در تلفن اندرویدی خود شروع میکنند - مانند بررسی یک سند، مرتبسازی پیامها یا مرور مجموعهای از موارد - و سپس میخواهند به یک گوگلبوک با صفحه نمایش بزرگتر، صفحه کلید فیزیکی و فضای کاری چند پنجرهای آن نقل مکان کنند.
ویژگی «ادامه دادن» در اندروید ۱۷ (سطح API ۳۷) و بالاتر، نوار وظیفه گوگلبوک را قادر میسازد تا یک آیکون برنامه (به نام پیشنهاد ) برای فعالیتی که کاربر در تلفن همراه نزدیک خود در حال انجام آن بوده است، نمایش دهد. کاربران میتوانند با یک کلیک، فعالیت خود را در گوگلبوک خود ادامه دهند.
پیادهسازی قابلیت انتقال بین دستگاهی (cross-device handoff) به برنامه شما اجازه میدهد تا زمینه فعالیت (activity context) را منتقل کند، بنابراین کاربر میتواند گردش کار خود را، چه در برنامه اندروید تطبیقی شما و چه در مرورگر دسکتاپ، دقیقاً از همان جایی که در تلفن خود متوقف شده بود، از سر بگیرد.
یک جریان تحویل را انتخاب کنید
قبل از فعال کردن انتقال بین دستگاهی، تصمیم بگیرید که هر فعالیت در برنامه تلفن شما چگونه باید باز شود وقتی کاربر پیشنهاد ادامه در Googlebook را انتخاب میکند:
| جریان تحویل | هدف در گوگل بوک | بهترین برای | API کلید |
|---|---|---|---|
| انتقال از برنامه به برنامه دیگر | اجرای برنامه بومی اندروید در پنجره دسکتاپ | برنامههای بهینه شده برای صفحه نمایشهای بزرگ و پنجرههای دسکتاپ در گوگل پلی | HandoffActivityData.Builder |
| انتقال از برنامه به برنامه دیگر با قابلیت اتصال مجدد از طریق وب | برنامه بومی اندروید در صورت نصب؛ در غیر این صورت، یک URL در مرورگر پیشفرض دسکتاپ | برنامههایی که برای تجربه پنجره دسکتاپ بومی بهینه شدهاند اما در صورت عدم نصب برنامه روی گوگلبوک، به یک مرورگر جایگزین قابل اعتماد نیاز دارند | setFallbackUri |
| انتقال مستقیم به وب | آدرس اینترنتی (URL) در مرورگر پیشفرض دسکتاپ (یا اگر برای پیوندهای برنامه اندروید پیکربندی شده باشد، توسط برنامه اصلی رهگیری میشود) | گردشهای کاری که در آنها برنامه وب شما، تجربه اصلی دسکتاپ است | HandoffActivityData.createWebHandoff |
فعال کردن handoff برای یک فعالیت
گزینه «ادامه روشن» به طور پیشفرض غیرفعال است و برای هر فعالیت پیکربندی میشود. این مراحل را در هر فعالیت ارسال در تلفن دنبال کنید:
- تابع
setHandoffEnabledرا فراخوانی کنید و پس از اینکه activity حالت مورد نیاز برای handoff را بارگذاری کرد، مقدارtrueبه آن بدهید. پس از فعالسازی، سیستم میتواند دادههای handoff را در حالی که activity در پیشزمینه است یا به پسزمینه منتقل میشود، درخواست کند. - تابع
onHandoffActivityDataRequestedرا برای برگرداندن یک شیءHandoffActivityDataغیر تهی، نادیده بگیرید. میتوانید در هر زمانی ازisHandoffEnabledبرای بررسی فعال بودن handoff برای فعالیت مورد نظر، پرسوجو کنید.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.os.Bundle
import android.os.PersistableBundle
class DocumentEditorActivity : Activity() {
private var documentId: String = "doc_42"
private var scrollOffsetPx: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Enable handoff once the activity is ready to transfer state.
setHandoffEnabled(true, null)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val extras = PersistableBundle().apply {
putString(EXTRA_DOCUMENT_ID, documentId)
putInt(EXTRA_SCROLL_OFFSET, scrollOffsetPx)
}
return HandoffActivityData.Builder(getComponentName())
.setExtras(extras)
.build()
}
companion object {
const val EXTRA_DOCUMENT_ID = "extra_document_id"
const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
}
}
وضعیت فعالیت بسته برای handoff
سیستم در دو سناریو، متد onHandoffActivityDataRequested را فراخوانی میکند:
- انتقال پیشزمینه: فعالیت در پیشزمینه گوشی است و کاربر از نوار وظیفه گوگلبوک، انتقال را آغاز میکند.
- ضبط وضعیت پسزمینه: فعالیت به پسزمینه گوشی منتقل میشود و سیستم، دادههای مربوط به انتقال را در حافظه پنهان (cache) ذخیره میکند تا در صورتی که کاربر بعداً پیشنهاد را در گوگلبوک انتخاب کند، از آنها استفاده کند.
بررسی کنید که آیا درخواست انتقال فعال است یا خیر
با استفاده از isActiveRequest HandoffActivityDataRequestInfo بررسی کنید تا بین یک handoff فعال که توسط کاربر آغاز شده و یک ذخیره پسزمینه تمایز قائل شوید:
- اگر
isActiveRequesttrueرا برگرداند، کاربر به طور فعال درخواست ادامه فعالیت در دستگاه دیگری را در حالی که فعالیت قابل مشاهده است، داده است. - اگر
isActiveRequestfalseرا برگرداند، سیستم در حال ذخیره وضعیت (state) در زمان توقف فعالیت (activity) است.
اگر یک نشانگر بصری روی گوشی نمایش داده شود که تأیید کند وظیفه به Googlebook منتقل میشود، بهروزرسانی رابط کاربری را به صورت ناهمگام برنامهریزی کنید تا onHandoffActivityDataRequested بدون تأخیر بازگردد.
موارد اضافی ایالت و یک پشتیبان وب را ضمیمه کنید
یک دادهی HandoffActivityData شامل اطلاعات زیر است:
- کامپوننت هدف (برای انتقال از برنامه به برنامه مورد نیاز است):
this.getComponentName()(ComponentNameاکتیویتی) یا یکComponentName(this, TargetActivity::class.java)صریح را بهHandoffActivityData.Builderارسال کنید تا مشخص شود کدام اکتیویتی در Googlebook اجرا میشود. - موارد اضافی (اختیاری): یک
PersistableBundleبهsetExtras()ارسال کنید که شامل شناسهها و مختصات رابط کاربری (برای مثال، شناسههای سند باز، کلیدهای تب فعال یا موقعیتهای اسکرول) باشد. حجم بسته باید کمتر از ۵۰ کیلوبایت باشد. - آدرس اینترنتی جایگزین (اختیاری): یک
Uriوب بهsetFallbackUriارسال کنید تا اگر برنامه اندروید شما نصب نشده باشد، گوگلبوک بتواند وظیفه را در مرورگر پیشفرض باز کند.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
import android.os.PersistableBundle
class ArticleReaderActivity : Activity() {
private var articleId: String = "android-desktop-windowing"
private var readingProgressPercent: Int = 45
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHandoffEnabled(
true,
HandoffActivityParams.Builder()
.setAllowHandoffWithoutPackageInstalled(true)
.build()
)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
if (handoffRequestInfo.isActiveRequest()) {
window.decorView.post {
onHandoffStartedToSecondaryDevice()
}
}
val extras = PersistableBundle().apply {
putString(EXTRA_ARTICLE_ID, articleId)
putInt(EXTRA_READING_PROGRESS, readingProgressPercent)
}
val fallbackWebUri = Uri.Builder()
.scheme("https")
.authority("example.com")
.appendPath("articles")
.appendPath(articleId)
.appendQueryParameter("progress", readingProgressPercent.toString())
.build()
return HandoffActivityData.Builder(getComponentName())
.setExtras(extras)
.setFallbackUri(fallbackWebUri)
.build()
}
private fun onHandoffStartedToSecondaryDevice() {
// Save local drafts and update phone UI without blocking handoff.
}
companion object {
const val EXTRA_ARTICLE_ID = "extra_article_id"
const val EXTRA_READING_PROGRESS = "extra_reading_progress"
}
}
پیکربندی انتقال مستقیم به وب
اگر تجربه اصلی دسکتاپ شما در گوگلبوک یک برنامه وب است، HandoffActivityParams به همراه setAllowHandoffWithoutPackageInstalled(true) به setHandoffEnabled ارسال کنید و به جای استفاده از HandoffActivityData.Builder ، HandoffActivityData.createWebHandoff را فراخوانی کنید:
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
class WebDashboardActivity : Activity() {
private var projectId: String = "proj_901"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHandoffEnabled(
true,
HandoffActivityParams.Builder()
.setAllowHandoffWithoutPackageInstalled(true)
.build()
)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val webUri = Uri.Builder()
.scheme("https")
.authority("app.example.com")
.appendPath("projects")
.appendPath(projectId)
.build()
return HandoffActivityData.createWebHandoff(webUri)
}
}
دریافت و بازیابی وضعیت در گوگلبوک
وقتی کاربر پیشنهاد «ادامه به ادامه» را در نوار وظیفه گوگلبوک انتخاب میکند، سیستم ComponentName هدف را در یک پنجره دسکتاپ اجرا میکند و افزونههای PersistableBundle را به Intent اجرا متصل میکند.
در گوگلبوک، با در نظر گرفتن پنجرهبندی دسکتاپ و طرحبندیهای چندبخشی، تحویل ورودی را مدیریت کنید:
- استخراج موارد اضافی تحویل داده شده: در هر دو متد
onCreateوonNewIntentاز اکتیویتی گیرنده، موارد اضافی را ازIntentورودی بازیابی کنید. مدیریتonNewIntentتضمین میکند که اگر اکتیویتی شما از حالت راهاندازیsingleTopاستفاده میکند یا به یک پنجره دسکتاپ موجود مسیردهی میکند، پنجره به مورد تحویل داده شده بهروزرسانی شود. - تطبیق وضعیت با طرحبندیهای چندبخشی: وضعیتی که نمای جزئیات تمامصفحه را در تلفن اشغال میکرد، اغلب در Googlebook به یک مورد انتخابشده در طرحبندی لیست-جزئیات یا صفحه پشتیبانی نگاشت میشود. هم انتخاب لیست اصلی و هم صفحه جزئیات را پر کنید تا پنجره دسکتاپ زمینه کاملی داشته باشد.
- حفظ حالت بازیابیشده در طول تغییر اندازه پنجره: حالت تحویل دادهشده را در یک
ViewModel(SavedStateHandle) ذخیره کنید یا در Jetpack ComposerememberSaveableکنید تا تغییر اندازه پنجره در حالت آزاد در Googlebook، جلسه بازیابیشده را مجدداً تنظیم نکند.
import android.app.Activity
import android.content.Intent
import android.os.Bundle
class DocumentEditorReceiverActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Restore from the handoff intent only on initial launch so subsequent
// desktop window configuration changes use saved instance state.
if (savedInstanceState == null) {
handleHandoffIntent(intent)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleHandoffIntent(intent)
}
private fun handleHandoffIntent(incomingIntent: Intent?) {
val documentId = incomingIntent?.getStringExtra(EXTRA_DOCUMENT_ID)
?: return
val scrollOffsetPx = incomingIntent.getIntExtra(EXTRA_SCROLL_OFFSET, 0)
openDocumentInDesktopWorkspace(
documentId = documentId,
initialScrollOffsetPx = scrollOffsetPx
)
}
private fun openDocumentInDesktopWorkspace(
documentId: String,
initialScrollOffsetPx: Int
) {
// Load the document into the list-detail layout and restore scroll position.
}
companion object {
const val EXTRA_DOCUMENT_ID = "extra_document_id"
const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
}
}
تست هندآف بین گوشی و گوگلبوک
برای تأیید پیادهسازی خود از ابتدا تا انتها:
- هر دو دستگاه را آماده کنید
- هم در گوشی اندروید خود (با اندروید ۱۷ یا بالاتر) و هم در گوگلبوک خود (یا یک دستگاه آزمایشی که در حالت پنجرهای دسکتاپ اجرا میشود) به یک حساب گوگل وارد شوید.
- بلوتوث را روشن کنید و هر دو دستگاه را به یک شبکه وایفای متصل کنید.
- در هر دو دستگاه، تنظیمات > دستگاههای متصل > تنظیمات اتصال > سرویسهای بین دستگاهی > ادامه فعالیت را باز کنید، دستورالعملهای راهاندازی را دنبال کنید و وظایف را فعال کنید. برای پیشنیازهای کامل محیط، به راهاندازی و آزمایش مراجعه کنید.
- برنامه خود را نصب کنید
- برای انتقال از یک برنامه به برنامه دیگر ، نسخه ساخته شده خود را هم روی گوشی و هم روی گوگل بوک نصب کنید.
- برای بازگشت به وب یا انتقال مستقیم به وب ، نسخهٔ ساختهشده را روی گوشی نصب کنید و برنامه را روی گوگلبوک حذف نصب کنید تا بتوانید تأیید کنید که مرورگر، آدرس اینترنتی مورد انتظار را باز میکند.
- شروع فرآیند تحویل کالا
- در گوشی، برنامه خود را باز کنید و به اکتیویتی که handoff را فعال میکند بروید (برای handoff از برنامه به برنامه،
setHandoffEnabled(true, null)را فراخوانی کنید، یا هنگام تست با برنامهای که در Googlebook حذف نصب شده است،HandoffActivityParamsرا باsetAllowHandoffWithoutPackageInstalled(true)ارسال کنید). - در گوگلبوک، سمت راست نوار وظیفه را برای یافتن آیکون برنامه خود با نشان «ادامه دهید» بررسی کنید و آن را انتخاب کنید.
- در گوشی، برنامه خود را باز کنید و به اکتیویتی که handoff را فعال میکند بروید (برای handoff از برنامه به برنامه،
- تأیید بازیابی دسکتاپ
- تأیید کنید که برنامه شما در یک پنجره دسکتاپ (یا برگه مرورگر) در موقعیت دقیق آیتم و اسکرول از طریق گوشی باز میشود.
- اندازه پنجره برنامه را در Googlebook تغییر دهید و تأیید کنید که محتوا و انتخاب بازیابی شده در طول انتقال کلاس اندازه پنجره باقی میمانند.
منابع اضافی
- ساخت برنامههای تطبیقی برای گوگلبوک
- درباره ویژگی «ادامه»
- فعال کردن و سفارشیسازی انتقال بین دستگاهی
- ذخیره حالتهای رابط کاربری
کاربران اغلب کارهایی را در تلفن اندرویدی خود شروع میکنند - مانند بررسی یک سند، مرتبسازی پیامها یا مرور مجموعهای از موارد - و سپس میخواهند به یک گوگلبوک با صفحه نمایش بزرگتر، صفحه کلید فیزیکی و فضای کاری چند پنجرهای آن نقل مکان کنند.
ویژگی «ادامه دادن» در اندروید ۱۷ (سطح API ۳۷) و بالاتر، نوار وظیفه گوگلبوک را قادر میسازد تا یک آیکون برنامه (به نام پیشنهاد ) برای فعالیتی که کاربر در تلفن همراه نزدیک خود در حال انجام آن بوده است، نمایش دهد. کاربران میتوانند با یک کلیک، فعالیت خود را در گوگلبوک خود ادامه دهند.
پیادهسازی قابلیت انتقال بین دستگاهی (cross-device handoff) به برنامه شما اجازه میدهد تا زمینه فعالیت (activity context) را منتقل کند، بنابراین کاربر میتواند گردش کار خود را، چه در برنامه اندروید تطبیقی شما و چه در مرورگر دسکتاپ، دقیقاً از همان جایی که در تلفن خود متوقف شده بود، از سر بگیرد.
یک جریان تحویل را انتخاب کنید
قبل از فعال کردن انتقال بین دستگاهی، تصمیم بگیرید که هر فعالیت در برنامه تلفن شما چگونه باید باز شود وقتی کاربر پیشنهاد ادامه در Googlebook را انتخاب میکند:
| جریان تحویل | هدف در گوگل بوک | بهترین برای | API کلید |
|---|---|---|---|
| انتقال از برنامه به برنامه دیگر | اجرای برنامه بومی اندروید در پنجره دسکتاپ | برنامههای بهینه شده برای صفحه نمایشهای بزرگ و پنجرههای دسکتاپ در گوگل پلی | HandoffActivityData.Builder |
| انتقال از برنامه به برنامه دیگر با قابلیت اتصال مجدد از طریق وب | برنامه بومی اندروید در صورت نصب؛ در غیر این صورت، یک URL در مرورگر پیشفرض دسکتاپ | برنامههایی که برای تجربه پنجره دسکتاپ بومی بهینه شدهاند اما در صورت عدم نصب برنامه روی گوگلبوک، به یک مرورگر جایگزین قابل اعتماد نیاز دارند | setFallbackUri |
| انتقال مستقیم به وب | آدرس اینترنتی (URL) در مرورگر پیشفرض دسکتاپ (یا اگر برای پیوندهای برنامه اندروید پیکربندی شده باشد، توسط برنامه اصلی رهگیری میشود) | گردشهای کاری که در آنها برنامه وب شما، تجربه اصلی دسکتاپ است | HandoffActivityData.createWebHandoff |
فعال کردن handoff برای یک فعالیت
گزینه «ادامه روشن» به طور پیشفرض غیرفعال است و برای هر فعالیت پیکربندی میشود. این مراحل را در هر فعالیت ارسال در تلفن دنبال کنید:
- تابع
setHandoffEnabledرا فراخوانی کنید و پس از اینکه activity حالت مورد نیاز برای handoff را بارگذاری کرد، مقدارtrueبه آن بدهید. پس از فعالسازی، سیستم میتواند دادههای handoff را در حالی که activity در پیشزمینه است یا به پسزمینه منتقل میشود، درخواست کند. - تابع
onHandoffActivityDataRequestedرا برای برگرداندن یک شیءHandoffActivityDataغیر تهی، نادیده بگیرید. میتوانید در هر زمانی ازisHandoffEnabledبرای بررسی فعال بودن handoff برای فعالیت مورد نظر، پرسوجو کنید.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.os.Bundle
import android.os.PersistableBundle
class DocumentEditorActivity : Activity() {
private var documentId: String = "doc_42"
private var scrollOffsetPx: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Enable handoff once the activity is ready to transfer state.
setHandoffEnabled(true, null)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val extras = PersistableBundle().apply {
putString(EXTRA_DOCUMENT_ID, documentId)
putInt(EXTRA_SCROLL_OFFSET, scrollOffsetPx)
}
return HandoffActivityData.Builder(getComponentName())
.setExtras(extras)
.build()
}
companion object {
const val EXTRA_DOCUMENT_ID = "extra_document_id"
const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
}
}
وضعیت فعالیت بسته برای handoff
سیستم در دو سناریو، متد onHandoffActivityDataRequested را فراخوانی میکند:
- انتقال پیشزمینه: فعالیت در پیشزمینه گوشی است و کاربر از نوار وظیفه گوگلبوک، انتقال را آغاز میکند.
- ضبط وضعیت پسزمینه: فعالیت به پسزمینه گوشی منتقل میشود و سیستم، دادههای مربوط به انتقال را در حافظه پنهان (cache) ذخیره میکند تا در صورتی که کاربر بعداً پیشنهاد را در گوگلبوک انتخاب کند، از آنها استفاده کند.
بررسی کنید که آیا درخواست انتقال فعال است یا خیر
با استفاده از isActiveRequest HandoffActivityDataRequestInfo بررسی کنید تا بین یک handoff فعال که توسط کاربر آغاز شده و یک ذخیره پسزمینه تمایز قائل شوید:
- اگر
isActiveRequesttrueرا برگرداند، کاربر به طور فعال درخواست ادامه فعالیت در دستگاه دیگری را در حالی که فعالیت قابل مشاهده است، داده است. - اگر
isActiveRequestfalseرا برگرداند، سیستم در حال ذخیره وضعیت (state) در زمان توقف فعالیت (activity) است.
اگر یک نشانگر بصری روی گوشی نمایش داده شود که تأیید کند وظیفه به Googlebook منتقل میشود، بهروزرسانی رابط کاربری را به صورت ناهمگام برنامهریزی کنید تا onHandoffActivityDataRequested بدون تأخیر بازگردد.
موارد اضافی ایالت و یک پشتیبان وب را ضمیمه کنید
یک دادهی HandoffActivityData شامل اطلاعات زیر است:
- کامپوننت هدف (برای انتقال از برنامه به برنامه مورد نیاز است):
this.getComponentName()(ComponentNameاکتیویتی) یا یکComponentName(this, TargetActivity::class.java)صریح را بهHandoffActivityData.Builderارسال کنید تا مشخص شود کدام اکتیویتی در Googlebook اجرا میشود. - موارد اضافی (اختیاری): یک
PersistableBundleبهsetExtras()ارسال کنید که شامل شناسهها و مختصات رابط کاربری (برای مثال، شناسههای سند باز، کلیدهای تب فعال یا موقعیتهای اسکرول) باشد. حجم بسته باید کمتر از ۵۰ کیلوبایت باشد. - آدرس اینترنتی جایگزین (اختیاری): یک
Uriوب بهsetFallbackUriارسال کنید تا اگر برنامه اندروید شما نصب نشده باشد، گوگلبوک بتواند وظیفه را در مرورگر پیشفرض باز کند.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
import android.os.PersistableBundle
class ArticleReaderActivity : Activity() {
private var articleId: String = "android-desktop-windowing"
private var readingProgressPercent: Int = 45
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHandoffEnabled(
true,
HandoffActivityParams.Builder()
.setAllowHandoffWithoutPackageInstalled(true)
.build()
)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
if (handoffRequestInfo.isActiveRequest()) {
window.decorView.post {
onHandoffStartedToSecondaryDevice()
}
}
val extras = PersistableBundle().apply {
putString(EXTRA_ARTICLE_ID, articleId)
putInt(EXTRA_READING_PROGRESS, readingProgressPercent)
}
val fallbackWebUri = Uri.Builder()
.scheme("https")
.authority("example.com")
.appendPath("articles")
.appendPath(articleId)
.appendQueryParameter("progress", readingProgressPercent.toString())
.build()
return HandoffActivityData.Builder(getComponentName())
.setExtras(extras)
.setFallbackUri(fallbackWebUri)
.build()
}
private fun onHandoffStartedToSecondaryDevice() {
// Save local drafts and update phone UI without blocking handoff.
}
companion object {
const val EXTRA_ARTICLE_ID = "extra_article_id"
const val EXTRA_READING_PROGRESS = "extra_reading_progress"
}
}
پیکربندی انتقال مستقیم به وب
اگر تجربه اصلی دسکتاپ شما در گوگلبوک یک برنامه وب است، HandoffActivityParams به همراه setAllowHandoffWithoutPackageInstalled(true) به setHandoffEnabled ارسال کنید و به جای استفاده از HandoffActivityData.Builder ، HandoffActivityData.createWebHandoff را فراخوانی کنید:
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
class WebDashboardActivity : Activity() {
private var projectId: String = "proj_901"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHandoffEnabled(
true,
HandoffActivityParams.Builder()
.setAllowHandoffWithoutPackageInstalled(true)
.build()
)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val webUri = Uri.Builder()
.scheme("https")
.authority("app.example.com")
.appendPath("projects")
.appendPath(projectId)
.build()
return HandoffActivityData.createWebHandoff(webUri)
}
}
دریافت و بازیابی وضعیت در گوگلبوک
وقتی کاربر پیشنهاد «ادامه به ادامه» را در نوار وظیفه گوگلبوک انتخاب میکند، سیستم ComponentName هدف را در یک پنجره دسکتاپ اجرا میکند و افزونههای PersistableBundle را به Intent اجرا متصل میکند.
در گوگلبوک، با در نظر گرفتن پنجرهبندی دسکتاپ و طرحبندیهای چندبخشی، تحویل ورودی را مدیریت کنید:
- استخراج موارد اضافی تحویل داده شده: در هر دو متد
onCreateوonNewIntentاز اکتیویتی گیرنده، موارد اضافی را ازIntentورودی بازیابی کنید. مدیریتonNewIntentتضمین میکند که اگر اکتیویتی شما از حالت راهاندازیsingleTopاستفاده میکند یا به یک پنجره دسکتاپ موجود مسیردهی میکند، پنجره به مورد تحویل داده شده بهروزرسانی شود. - تطبیق وضعیت با طرحبندیهای چندبخشی: وضعیتی که نمای جزئیات تمامصفحه را در تلفن اشغال میکرد، اغلب در Googlebook به یک مورد انتخابشده در طرحبندی لیست-جزئیات یا صفحه پشتیبانی نگاشت میشود. هم انتخاب لیست اصلی و هم صفحه جزئیات را پر کنید تا پنجره دسکتاپ زمینه کاملی داشته باشد.
- حفظ حالت بازیابیشده در طول تغییر اندازه پنجره: حالت تحویل دادهشده را در یک
ViewModel(SavedStateHandle) ذخیره کنید یا در Jetpack ComposerememberSaveableکنید تا تغییر اندازه پنجره در حالت آزاد در Googlebook، جلسه بازیابیشده را مجدداً تنظیم نکند.
import android.app.Activity
import android.content.Intent
import android.os.Bundle
class DocumentEditorReceiverActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Restore from the handoff intent only on initial launch so subsequent
// desktop window configuration changes use saved instance state.
if (savedInstanceState == null) {
handleHandoffIntent(intent)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleHandoffIntent(intent)
}
private fun handleHandoffIntent(incomingIntent: Intent?) {
val documentId = incomingIntent?.getStringExtra(EXTRA_DOCUMENT_ID)
?: return
val scrollOffsetPx = incomingIntent.getIntExtra(EXTRA_SCROLL_OFFSET, 0)
openDocumentInDesktopWorkspace(
documentId = documentId,
initialScrollOffsetPx = scrollOffsetPx
)
}
private fun openDocumentInDesktopWorkspace(
documentId: String,
initialScrollOffsetPx: Int
) {
// Load the document into the list-detail layout and restore scroll position.
}
companion object {
const val EXTRA_DOCUMENT_ID = "extra_document_id"
const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
}
}
تست هندآف بین گوشی و گوگلبوک
برای تأیید پیادهسازی خود از ابتدا تا انتها:
- هر دو دستگاه را آماده کنید
- هم در گوشی اندروید خود (با اندروید ۱۷ یا بالاتر) و هم در گوگلبوک خود (یا یک دستگاه آزمایشی که در حالت پنجرهای دسکتاپ اجرا میشود) به یک حساب گوگل وارد شوید.
- بلوتوث را روشن کنید و هر دو دستگاه را به یک شبکه وایفای متصل کنید.
- در هر دو دستگاه، تنظیمات > دستگاههای متصل > تنظیمات اتصال > سرویسهای بین دستگاهی > ادامه فعالیت را باز کنید، دستورالعملهای راهاندازی را دنبال کنید و وظایف را فعال کنید. برای پیشنیازهای کامل محیط، به راهاندازی و آزمایش مراجعه کنید.
- برنامه خود را نصب کنید
- برای انتقال از یک برنامه به برنامه دیگر ، نسخه ساخته شده خود را هم روی گوشی و هم روی گوگل بوک نصب کنید.
- برای بازگشت به وب یا انتقال مستقیم به وب ، نسخهٔ ساختهشده را روی گوشی نصب کنید و برنامه را روی گوگلبوک حذف نصب کنید تا بتوانید تأیید کنید که مرورگر، آدرس اینترنتی مورد انتظار را باز میکند.
- شروع فرآیند تحویل کالا
- در گوشی، برنامه خود را باز کنید و به اکتیویتی که handoff را فعال میکند بروید (برای handoff از برنامه به برنامه،
setHandoffEnabled(true, null)را فراخوانی کنید، یا هنگام تست با برنامهای که در Googlebook حذف نصب شده است،HandoffActivityParamsرا باsetAllowHandoffWithoutPackageInstalled(true)ارسال کنید). - در گوگلبوک، سمت راست نوار وظیفه را برای یافتن آیکون برنامه خود با نشان «ادامه دهید» بررسی کنید و آن را انتخاب کنید.
- در گوشی، برنامه خود را باز کنید و به اکتیویتی که handoff را فعال میکند بروید (برای handoff از برنامه به برنامه،
- تأیید بازیابی دسکتاپ
- تأیید کنید که برنامه شما در یک پنجره دسکتاپ (یا برگه مرورگر) در موقعیت دقیق آیتم و اسکرول از طریق گوشی باز میشود.
- اندازه پنجره برنامه را در Googlebook تغییر دهید و تأیید کنید که محتوا و انتخاب بازیابی شده در طول انتقال کلاس اندازه پنجره باقی میمانند.
منابع اضافی
- ساخت برنامههای تطبیقی برای گوگلبوک
- درباره ویژگی «ادامه»
- فعال کردن و سفارشیسازی انتقال بین دستگاهی
- ذخیره حالتهای رابط کاربری
کاربران اغلب کارهایی را در تلفن اندرویدی خود شروع میکنند - مانند بررسی یک سند، مرتبسازی پیامها یا مرور مجموعهای از موارد - و سپس میخواهند به یک گوگلبوک با صفحه نمایش بزرگتر، صفحه کلید فیزیکی و فضای کاری چند پنجرهای آن نقل مکان کنند.
ویژگی «ادامه دادن» در اندروید ۱۷ (سطح API ۳۷) و بالاتر، نوار وظیفه گوگلبوک را قادر میسازد تا یک آیکون برنامه (به نام پیشنهاد ) برای فعالیتی که کاربر در تلفن همراه نزدیک خود در حال انجام آن بوده است، نمایش دهد. کاربران میتوانند با یک کلیک، فعالیت خود را در گوگلبوک خود ادامه دهند.
پیادهسازی قابلیت انتقال بین دستگاهی (cross-device handoff) به برنامه شما اجازه میدهد تا زمینه فعالیت (activity context) را منتقل کند، بنابراین کاربر میتواند گردش کار خود را، چه در برنامه اندروید تطبیقی شما و چه در مرورگر دسکتاپ، دقیقاً از همان جایی که در تلفن خود متوقف شده بود، از سر بگیرد.
یک جریان تحویل را انتخاب کنید
قبل از فعال کردن انتقال بین دستگاهی، تصمیم بگیرید که هر فعالیت در برنامه تلفن شما چگونه باید باز شود وقتی کاربر پیشنهاد ادامه در Googlebook را انتخاب میکند:
| جریان تحویل | هدف در گوگل بوک | بهترین برای | API کلید |
|---|---|---|---|
| انتقال از برنامه به برنامه دیگر | اجرای برنامه بومی اندروید در پنجره دسکتاپ | برنامههای بهینه شده برای صفحه نمایشهای بزرگ و پنجرههای دسکتاپ در گوگل پلی | HandoffActivityData.Builder |
| انتقال از برنامه به برنامه دیگر با قابلیت اتصال مجدد از طریق وب | برنامه بومی اندروید در صورت نصب؛ در غیر این صورت، یک URL در مرورگر پیشفرض دسکتاپ | برنامههایی که برای تجربه پنجره دسکتاپ بومی بهینه شدهاند اما در صورت عدم نصب برنامه روی گوگلبوک، به یک مرورگر جایگزین قابل اعتماد نیاز دارند | setFallbackUri |
| انتقال مستقیم به وب | آدرس اینترنتی (URL) در مرورگر پیشفرض دسکتاپ (یا اگر برای پیوندهای برنامه اندروید پیکربندی شده باشد، توسط برنامه اصلی رهگیری میشود) | گردشهای کاری که در آنها برنامه وب شما، تجربه اصلی دسکتاپ است | HandoffActivityData.createWebHandoff |
فعال کردن handoff برای یک فعالیت
گزینه «ادامه روشن» به طور پیشفرض غیرفعال است و برای هر فعالیت پیکربندی میشود. این مراحل را در هر فعالیت ارسال در تلفن دنبال کنید:
- تابع
setHandoffEnabledرا فراخوانی کنید و پس از اینکه activity حالت مورد نیاز برای handoff را بارگذاری کرد، مقدارtrueبه آن بدهید. پس از فعالسازی، سیستم میتواند دادههای handoff را در حالی که activity در پیشزمینه است یا به پسزمینه منتقل میشود، درخواست کند. - تابع
onHandoffActivityDataRequestedرا برای برگرداندن یک شیءHandoffActivityDataغیر تهی، نادیده بگیرید. میتوانید در هر زمانی ازisHandoffEnabledبرای بررسی فعال بودن handoff برای فعالیت مورد نظر، پرسوجو کنید.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.os.Bundle
import android.os.PersistableBundle
class DocumentEditorActivity : Activity() {
private var documentId: String = "doc_42"
private var scrollOffsetPx: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Enable handoff once the activity is ready to transfer state.
setHandoffEnabled(true, null)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val extras = PersistableBundle().apply {
putString(EXTRA_DOCUMENT_ID, documentId)
putInt(EXTRA_SCROLL_OFFSET, scrollOffsetPx)
}
return HandoffActivityData.Builder(getComponentName())
.setExtras(extras)
.build()
}
companion object {
const val EXTRA_DOCUMENT_ID = "extra_document_id"
const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
}
}
وضعیت فعالیت بسته برای handoff
سیستم در دو سناریو، متد onHandoffActivityDataRequested را فراخوانی میکند:
- انتقال پیشزمینه: فعالیت در پیشزمینه گوشی است و کاربر از نوار وظیفه گوگلبوک، انتقال را آغاز میکند.
- ضبط وضعیت پسزمینه: فعالیت به پسزمینه گوشی منتقل میشود و سیستم، دادههای مربوط به انتقال را در حافظه پنهان (cache) ذخیره میکند تا در صورتی که کاربر بعداً پیشنهاد را در گوگلبوک انتخاب کند، از آنها استفاده کند.
بررسی کنید که آیا درخواست انتقال فعال است یا خیر
با استفاده از isActiveRequest HandoffActivityDataRequestInfo بررسی کنید تا بین یک handoff فعال که توسط کاربر آغاز شده و یک ذخیره پسزمینه تمایز قائل شوید:
- اگر
isActiveRequesttrueرا برگرداند، کاربر به طور فعال درخواست ادامه فعالیت در دستگاه دیگری را در حالی که فعالیت قابل مشاهده است، داده است. - اگر
isActiveRequestfalseرا برگرداند، سیستم در حال ذخیره وضعیت (state) در زمان توقف فعالیت (activity) است.
اگر یک نشانگر بصری روی گوشی نمایش داده شود که تأیید کند وظیفه به Googlebook منتقل میشود، بهروزرسانی رابط کاربری را به صورت ناهمگام برنامهریزی کنید تا onHandoffActivityDataRequested بدون تأخیر بازگردد.
موارد اضافی ایالت و یک پشتیبان وب را ضمیمه کنید
یک دادهی HandoffActivityData شامل اطلاعات زیر است:
- کامپوننت هدف (برای انتقال از برنامه به برنامه مورد نیاز است):
this.getComponentName()(ComponentNameاکتیویتی) یا یکComponentName(this, TargetActivity::class.java)صریح را بهHandoffActivityData.Builderارسال کنید تا مشخص شود کدام اکتیویتی در Googlebook اجرا میشود. - موارد اضافی (اختیاری): یک
PersistableBundleبهsetExtras()ارسال کنید که شامل شناسهها و مختصات رابط کاربری (برای مثال، شناسههای سند باز، کلیدهای تب فعال یا موقعیتهای اسکرول) باشد. حجم بسته باید کمتر از ۵۰ کیلوبایت باشد. - آدرس اینترنتی جایگزین (اختیاری): یک
Uriوب بهsetFallbackUriارسال کنید تا اگر برنامه اندروید شما نصب نشده باشد، گوگلبوک بتواند وظیفه را در مرورگر پیشفرض باز کند.
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
import android.os.PersistableBundle
class ArticleReaderActivity : Activity() {
private var articleId: String = "android-desktop-windowing"
private var readingProgressPercent: Int = 45
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHandoffEnabled(
true,
HandoffActivityParams.Builder()
.setAllowHandoffWithoutPackageInstalled(true)
.build()
)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
if (handoffRequestInfo.isActiveRequest()) {
window.decorView.post {
onHandoffStartedToSecondaryDevice()
}
}
val extras = PersistableBundle().apply {
putString(EXTRA_ARTICLE_ID, articleId)
putInt(EXTRA_READING_PROGRESS, readingProgressPercent)
}
val fallbackWebUri = Uri.Builder()
.scheme("https")
.authority("example.com")
.appendPath("articles")
.appendPath(articleId)
.appendQueryParameter("progress", readingProgressPercent.toString())
.build()
return HandoffActivityData.Builder(getComponentName())
.setExtras(extras)
.setFallbackUri(fallbackWebUri)
.build()
}
private fun onHandoffStartedToSecondaryDevice() {
// Save local drafts and update phone UI without blocking handoff.
}
companion object {
const val EXTRA_ARTICLE_ID = "extra_article_id"
const val EXTRA_READING_PROGRESS = "extra_reading_progress"
}
}
پیکربندی انتقال مستقیم به وب
اگر تجربه اصلی دسکتاپ شما در گوگلبوک یک برنامه وب است، HandoffActivityParams به همراه setAllowHandoffWithoutPackageInstalled(true) به setHandoffEnabled ارسال کنید و به جای استفاده از HandoffActivityData.Builder ، HandoffActivityData.createWebHandoff را فراخوانی کنید:
import android.app.Activity
import android.app.HandoffActivityData
import android.app.HandoffActivityDataRequestInfo
import android.app.HandoffActivityParams
import android.net.Uri
import android.os.Bundle
class WebDashboardActivity : Activity() {
private var projectId: String = "proj_901"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHandoffEnabled(
true,
HandoffActivityParams.Builder()
.setAllowHandoffWithoutPackageInstalled(true)
.build()
)
}
override fun onHandoffActivityDataRequested(
handoffRequestInfo: HandoffActivityDataRequestInfo
): HandoffActivityData {
val webUri = Uri.Builder()
.scheme("https")
.authority("app.example.com")
.appendPath("projects")
.appendPath(projectId)
.build()
return HandoffActivityData.createWebHandoff(webUri)
}
}
دریافت و بازیابی وضعیت در گوگلبوک
وقتی کاربر پیشنهاد «ادامه به ادامه» را در نوار وظیفه گوگلبوک انتخاب میکند، سیستم ComponentName هدف را در یک پنجره دسکتاپ اجرا میکند و افزونههای PersistableBundle را به Intent اجرا متصل میکند.
در گوگلبوک، با در نظر گرفتن پنجرهبندی دسکتاپ و طرحبندیهای چندبخشی، تحویل ورودی را مدیریت کنید:
- استخراج موارد اضافی تحویل داده شده: در هر دو متد
onCreateوonNewIntentاز اکتیویتی گیرنده، موارد اضافی را ازIntentورودی بازیابی کنید. مدیریتonNewIntentتضمین میکند که اگر اکتیویتی شما از حالت راهاندازیsingleTopاستفاده میکند یا به یک پنجره دسکتاپ موجود مسیردهی میکند، پنجره به مورد تحویل داده شده بهروزرسانی شود. - تطبیق وضعیت با طرحبندیهای چندبخشی: وضعیتی که نمای جزئیات تمامصفحه را در تلفن اشغال میکرد، اغلب در Googlebook به یک مورد انتخابشده در طرحبندی لیست-جزئیات یا صفحه پشتیبانی نگاشت میشود. هم انتخاب لیست اصلی و هم صفحه جزئیات را پر کنید تا پنجره دسکتاپ زمینه کاملی داشته باشد.
- حفظ حالت بازیابیشده در طول تغییر اندازه پنجره: حالت تحویل دادهشده را در یک
ViewModel(SavedStateHandle) ذخیره کنید یا در Jetpack ComposerememberSaveableکنید تا تغییر اندازه پنجره در حالت آزاد در Googlebook، جلسه بازیابیشده را مجدداً تنظیم نکند.
import android.app.Activity
import android.content.Intent
import android.os.Bundle
class DocumentEditorReceiverActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Restore from the handoff intent only on initial launch so subsequent
// desktop window configuration changes use saved instance state.
if (savedInstanceState == null) {
handleHandoffIntent(intent)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
handleHandoffIntent(intent)
}
private fun handleHandoffIntent(incomingIntent: Intent?) {
val documentId = incomingIntent?.getStringExtra(EXTRA_DOCUMENT_ID)
?: return
val scrollOffsetPx = incomingIntent.getIntExtra(EXTRA_SCROLL_OFFSET, 0)
openDocumentInDesktopWorkspace(
documentId = documentId,
initialScrollOffsetPx = scrollOffsetPx
)
}
private fun openDocumentInDesktopWorkspace(
documentId: String,
initialScrollOffsetPx: Int
) {
// Load the document into the list-detail layout and restore scroll position.
}
companion object {
const val EXTRA_DOCUMENT_ID = "extra_document_id"
const val EXTRA_SCROLL_OFFSET = "extra_scroll_offset"
}
}
تست هندآف بین گوشی و گوگلبوک
برای تأیید پیادهسازی خود از ابتدا تا انتها:
- هر دو دستگاه را آماده کنید
- هم در گوشی اندروید خود (با اندروید ۱۷ یا بالاتر) و هم در گوگلبوک خود (یا یک دستگاه آزمایشی که در حالت پنجرهای دسکتاپ اجرا میشود) به یک حساب گوگل وارد شوید.
- بلوتوث را روشن کنید و هر دو دستگاه را به یک شبکه وایفای متصل کنید.
- در هر دو دستگاه، تنظیمات > دستگاههای متصل > تنظیمات اتصال > سرویسهای بین دستگاهی > ادامه فعالیت را باز کنید، دستورالعملهای راهاندازی را دنبال کنید و وظایف را فعال کنید. برای پیشنیازهای کامل محیط، به راهاندازی و آزمایش مراجعه کنید.
- برنامه خود را نصب کنید
- برای انتقال از یک برنامه به برنامه دیگر ، نسخه ساخته شده خود را هم روی گوشی و هم روی گوگل بوک نصب کنید.
- برای بازگشت به وب یا انتقال مستقیم به وب ، نسخهٔ ساختهشده را روی گوشی نصب کنید و برنامه را روی گوگلبوک حذف نصب کنید تا بتوانید تأیید کنید که مرورگر، آدرس اینترنتی مورد انتظار را باز میکند.
- شروع فرآیند تحویل کالا
- در گوشی، برنامه خود را باز کنید و به اکتیویتی که handoff را فعال میکند بروید (برای handoff از برنامه به برنامه،
setHandoffEnabled(true, null)را فراخوانی کنید، یا هنگام تست با برنامهای که در Googlebook حذف نصب شده است،HandoffActivityParamsرا باsetAllowHandoffWithoutPackageInstalled(true)ارسال کنید). - در گوگلبوک، سمت راست نوار وظیفه را برای یافتن آیکون برنامه خود با نشان «ادامه دهید» بررسی کنید و آن را انتخاب کنید.
- در گوشی، برنامه خود را باز کنید و به اکتیویتی که handoff را فعال میکند بروید (برای handoff از برنامه به برنامه،
- تأیید بازیابی دسکتاپ
- تأیید کنید که برنامه شما در یک پنجره دسکتاپ (یا برگه مرورگر) در موقعیت دقیق آیتم و اسکرول از طریق گوشی باز میشود.
- اندازه پنجره برنامه را در Googlebook تغییر دهید و تأیید کنید که محتوا و انتخاب بازیابی شده در طول انتقال کلاس اندازه پنجره باقی میمانند.
منابع اضافی
- ساخت برنامههای تطبیقی برای گوگلبوک
- درباره ویژگی «ادامه»
- فعال کردن و سفارشیسازی انتقال بین دستگاهی
- ذخیره حالتهای رابط کاربری