使用者經常在 Android 手機上開始執行工作,例如查看文件、分類訊息或瀏覽各種項目,然後想改用 Googlebook,因為 Googlebook 的螢幕較大、有實體鍵盤,而且提供多視窗模式工作區。
Android 17 (API 級別 37) 以上版本的「繼續操作」功能,可讓 Googlebook 工作列顯示應用程式圖示 (稱為「建議」),方便使用者繼續在附近的手機上執行的活動。使用者只要按一下,即可在 Googlebook 上繼續先前的活動。
導入跨裝置交接功能後,應用程式就能轉移活動內容,讓使用者在適應性 Android 應用程式或電腦瀏覽器中,從手機上中斷的地方繼續工作流程。
選擇交接流程
啟用跨裝置接續功能前,請先決定使用者在 Googlebook 上選取「繼續在其他裝置上操作」建議時,手機應用程式中的各項活動應如何開啟:
| 交接流程 | Googlebook 目標 | 適用情境 | Key API |
|---|---|---|---|
| 應用程式間交接 | 在電腦視窗中執行的原生 Android 應用程式 | Google Play 上針對大螢幕和電腦分割視窗功能最佳化的應用程式 | HandoffActivityData.Builder |
| 應用程式間交接 (網頁備用) | 如果已安裝,則為原生 Android 應用程式;否則為預設電腦版瀏覽器中的網址 | 應用程式已針對原生電腦視窗體驗進行最佳化,但如果 Googlebook 未安裝應用程式,則需要可靠的瀏覽器備援機制 | setFallbackUri |
| 直接交接給網頁 | 預設電腦瀏覽器中的網址 (或由原生應用程式攔截,前提是已設定 Android 應用程式連結) | 網頁應用程式是主要電腦版體驗的工作流程 | HandoffActivityData.createWebHandoff |
為活動啟用交接功能
「繼續操作」預設為停用,且會針對每個活動進行設定。在手機上進行每項傳送活動時,請按照下列步驟操作:
- 活動載入移交所需的狀態後,請呼叫
setHandoffEnabled並傳遞true。啟用後,系統可以在活動位於前景或移至背景時,要求移交資料。 - 覆寫
onHandoffActivityDataRequested,傳回非空值的HandoffActivityData物件。您可以隨時查詢isHandoffEnabled,確認活動是否已啟用交接功能。
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"
}
}
交接的套件活動狀態
系統會在以下兩種情況呼叫 onHandoffActivityDataRequested:
- 前景交接:活動在手機上處於前景,使用者從 Googlebook 工作列啟動交接。
- 擷取背景狀態:活動會移至手機背景,系統會快取交接酬載,以防使用者稍後在 Googlebook 上選取建議。
檢查交接要求是否有效
使用 isActiveRequest 檢查 HandoffActivityDataRequestInfo,區分使用者主動發起的交接和背景儲存作業:
- 如果
isActiveRequest傳回true,表示使用者在活動顯示期間主動要求在其他裝置上繼續操作。 - 如果
isActiveRequest回傳false,系統會在活動停止時快取狀態。
如果在手機上顯示視覺指標,確認工作正在移至 Googlebook,請以非同步方式排定 UI 更新作業,確保 onHandoffActivityDataRequested 立即傳回。
附加狀態額外資訊和網頁備用內容
HandoffActivityData 酬載包含下列資訊:
- 目標元件 (應用程式間交接作業的必要條件):傳遞
this.getComponentName()(活動的ComponentName) 或明確的ComponentName(this, TargetActivity::class.java)至HandoffActivityData.Builder,指定要在 Googlebook 上啟動的活動。 - 其他 (選用):將
PersistableBundle傳遞至setExtras(),其中包含 ID 和 UI 座標 (例如開啟的文件 ID、有效索引標籤鍵或捲動位置)。組合包大小不得超過 50 KB。 - 後備 URI (選用):將網頁
Uri傳遞至setFallbackUri,這樣一來,如果未安裝 Android 應用程式,Googlebook 就能在預設瀏覽器中開啟工作。
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"
}
}
設定直接轉移至網站
如果 Googlebook 的主要電腦體驗是網頁應用程式,請傳遞 HandoffActivityParams (含 setAllowHandoffWithoutPackageInstalled(true) 至 setHandoffEnabled,並呼叫 HandoffActivityData.createWebHandoff,而非使用 HandoffActivityData.Builder:
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)
}
}
在 Googlebook 上接收及還原狀態
使用者在 Googlebook 工作列中選取「繼續使用」建議時,系統會在桌面視窗中啟動目標 ComponentName,並將 PersistableBundle 額外內容附加至啟動 Intent。
在 Googlebook 上處理傳入的交接作業時,請考量電腦分割視窗模式和多窗格版面配置:
- 擷取交接額外項目:在接收活動的
onCreate和onNewIntent方法中,從傳入的Intent擷取額外項目。處理onNewIntent可確保活動使用singleTop啟動模式或路徑至現有電腦視窗時,視窗會更新為交接項目。 - 配合多窗格版面配置調整狀態:在手機上佔用全螢幕詳細資料檢視畫面的狀態,通常會對應到 Googlebook 上清單詳細資料或支援窗格版面配置中的所選項目。填入主要清單選取項目和詳細資料窗格,讓電腦視窗擁有完整脈絡。
- 在調整視窗大小時保留還原的狀態:將移交的狀態儲存在 Jetpack Compose 的
ViewModel(SavedStateHandle) 或rememberSaveable中,這樣在 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"
}
}
測試手機和 Googlebook 之間的接續功能
如要進行端對端驗證,請按照下列步驟操作:
- 準備兩部裝置
- 在 Android 手機 (搭載 Android 17 以上版本) 和 Googlebook (或以電腦分割視窗模式執行的測試裝置) 上登入同一個 Google 帳戶。
- 開啟藍牙,並將兩部裝置連上相同的 Wi-Fi 網路。
- 在兩部裝置上依序開啟「設定」>「已連結的裝置」>「連線偏好設定」>「跨裝置服務」>「繼續先前的活動」,然後按照設定提示操作,並啟用「工作」。如需完整的環境必要條件,請參閱「設定及測試」。
- 安裝應用程式
- 如要進行應用程式間交接,請在手機和 Googlebook 上安裝建構版本。
- 如果是網頁備援或直接移交至網頁,請在手機上安裝建構版本,並在 Googlebook 上解除安裝應用程式,以便確認瀏覽器是否開啟預期網址。
- 觸發交接
- 在手機上開啟應用程式,然後前往可啟用交接的活動 (撥打電話
setHandoffEnabled(true, null)進行應用程式間交接,或在 Googlebook 上測試時,傳遞HandoffActivityParams和setAllowHandoffWithoutPackageInstalled(true))。 - 在 Googlebook 上,查看工作列右側是否有應用程式圖示, 並選取附有「在其他裝置上繼續」徽章的圖示。
- 在手機上開啟應用程式,然後前往可啟用交接的活動 (撥打電話
- 確認桌面還原作業
- 確認應用程式在電腦視窗 (或瀏覽器分頁) 中開啟時,會顯示手機上完全相同的項目和捲動位置。
- 在 Googlebook 上調整應用程式視窗大小,並確認還原的內容和選取項目在視窗大小類別轉換期間會持續存在。