工作資料夾

Android 平台可讓裝置具有工作資料夾 (有時稱為受管理的設定檔)。工作資料夾是由 IT 管理員控管,其可用功能與使用者主要設定檔的功能分開設定。這個方法可讓機構控管公司專用應用程式和資料在使用者裝置上執行的環境,同時讓使用者使用其個人應用程式和設定檔。

本課程將介紹如何修改應用程式,讓應用程式在設有工作資料夾的裝置上可靠地運作。除了一般的應用程式開發最佳做法之外,你不需要採取任何行動。但是,部分最佳做法對於設有工作資料夾的裝置尤其重要。本文件會重點說明您需要注意的問題。

總覽

使用者通常會希望在企業環境中使用個人裝置。在這種情況下,機構可能會面臨難題。如果使用者可以使用自己的裝置,機構就必須擔心機密資訊 (例如員工電子郵件和聯絡人) 位於機構無法控管的裝置上。

為解決這種情況,Android 5.0 (API 級別 21) 會允許機構設定工作資料夾。如果裝置設有工作資料夾,則設定檔的設定是由 IT 管理員控管。IT 管理員可以選擇要允許該設定檔使用哪些應用程式,以及只控制設定檔可使用哪些裝置功能。

如果裝置設有工作資料夾,則無論應用程式執行的是哪個設定檔,都會影響裝置上執行的應用程式:

  • 根據預設,大多數意圖都不會從一個設定檔跨越不同的設定檔。如果設定檔上執行的應用程式觸發了意圖,該設定檔的意圖就不會有處理常式,且由於設定檔限制導致該意圖無法跨越其他設定檔,則要求會失敗,應用程式也可能會意外關閉。
  • 設定檔 IT 管理員可以限制工作資料夾中可用的系統應用程式。這項限制也可能導致工作資料夾中沒有某些常見意圖的處理常式。
  • 由於個人資料夾和工作資料夾具有不同的儲存空間區域,因此一個設定檔上的有效檔案 URI 對另一個設定檔無效。任何在某個設定檔上觸發的意圖,可能會在其他設定檔中處理 (視設定檔設定而定),因此無法將檔案 URI 附加至意圖。

防止失敗的意圖

在設有工作資料夾的裝置上,系統會限制意圖是否可以從一個設定檔跨越另一個設定檔。在大多數情況下,意圖觸發時,系統會在觸發意圖的設定檔中處理該意圖。如果「該設定檔上」沒有適用於意圖的處理常式,系統就不會處理意圖,觸發該意圖的應用程式也可能會意外關閉,即使其他設定檔上有該意圖的處理常式也一樣。

設定檔管理員可以選擇可以從一個設定檔跨越不同的意圖。由於 IT 管理員做出這項決定,您無法事先得知「哪些」意圖可以跨越這個邊界。IT 管理員會設定這項政策,並能隨時變更。

在應用程式啟動活動之前,您應確認是否有適當的解析度。您可以呼叫 Intent.resolveActivity() 來確認是否有可接受的解析度。如果無法解析意圖,這個方法會傳回 null。如果方法傳回非空值,則至少有一種方式可以解析意圖,而且可以放心觸發意圖。在這種情況下,由於目前的設定檔已有處理常式,或是意圖符合另一個設定檔的處理常式,因此該意圖可解析。(如要進一步瞭解解決意圖,請參閱常見意圖)。

舉例來說,如果應用程式需要設定計時器,則必須檢查 ACTION_SET_TIMER 意圖是否有效處理常式。如果應用程式無法解析意圖,則應採取適當的動作 (例如顯示錯誤訊息)。

Kotlin

fun startTimer(message: String, seconds: Int) {

    // Build the "set timer" intent
    val timerIntent = Intent(AlarmClock.ACTION_SET_TIMER).apply {
        putExtra(AlarmClock.EXTRA_MESSAGE, message)
        putExtra(AlarmClock.EXTRA_LENGTH, seconds)
        putExtra(AlarmClock.EXTRA_SKIP_UI, true)
    }

    // Check if there's a handler for the intent
    if (timerIntent.resolveActivity(packageManager) == null) {

        // Can't resolve the intent! Fail this operation cleanly
        // (perhaps by showing an error message)

    } else {
        // Intent resolves, it's safe to fire it off
        startActivity(timerIntent)

    }
}

Java

public void startTimer(String message, int seconds) {

    // Build the "set timer" intent
    Intent timerIntent = new Intent(AlarmClock.ACTION_SET_TIMER)
            .putExtra(AlarmClock.EXTRA_MESSAGE, message)
            .putExtra(AlarmClock.EXTRA_LENGTH, seconds)
            .putExtra(AlarmClock.EXTRA_SKIP_UI, true);

    // Check if there's a handler for the intent
    if (timerIntent.resolveActivity(getPackageManager()) == null) {

        // Can't resolve the intent! Fail this operation cleanly
        // (perhaps by showing an error message)

    } else {
        // Intent resolves, it's safe to fire it off
        startActivity(timerIntent);

    }
}

在不同的設定檔之間分享檔案

有時應用程式需要讓其他應用程式存取自己的檔案。舉例來說,圖片庫應用程式可能會想要與圖片編輯器分享圖片。通常您可以透過兩種方式共用檔案:使用檔案 URI內容 URI

檔案 URI 的開頭為 file: 前置字串,後接裝置儲存空間中檔案的絕對路徑。不過,由於工作資料夾和個人設定檔分別使用不同的儲存區域,因此在一個設定檔上有效的檔案 URI 對另一個設定檔無效。在這種情況下,如果您將檔案 URI 附加到意圖,而意圖是在另一個設定檔中處理,則處理常式無法存取檔案。

請改為透過內容 URI 共用檔案。內容 URI 能夠以更安全、可共用的方式識別檔案。內容 URI 包含檔案路徑,同時也包含提供檔案的授權單位,以及識別檔案的 ID 編號。您可以使用 FileProvider 產生任何檔案的內容 ID。接著,你就可以將 Content ID 與其他應用程式分享 (即使在其他個人資料上也沒關係)。接收者可以使用內容 ID 存取實際檔案。

例如,以下說明如何取得特定檔案 URI 的內容 URI:

Kotlin

// Open File object from its file URI
val fileToShare = File(fileUriToShare)

val contentUriToShare: Uri = FileProvider.getUriForFile(
        context,
        "com.example.myapp.fileprovider",
        fileToShare
)

Java

// Open File object from its file URI
File fileToShare = new File(fileUriToShare);

Uri contentUriToShare = FileProvider.getUriForFile(getContext(),
        "com.example.myapp.fileprovider", fileToShare);

呼叫 getUriForFile() 方法時,您必須在應用程式資訊清單的 <provider> 元素中指定檔案供應器的授權 (在本範例中為 "com.example.myapp.fileprovider")。如要進一步瞭解如何透過內容 URI 共用檔案,請參閱「共用檔案」。

聽取通知

應用程式通常會提供 NotificationListenerService 子類別,以接收系統發送通知變更的回呼。設有工作資料夾的裝置可能會影響 NotificationListenerService 與應用程式搭配運作的方式。

工作資料夾

您無法在工作資料夾中執行的應用程式使用 NotificationListenerService。如果應用程式在工作資料夾中執行,系統會忽略應用程式的 NotificationListenerService。不過,在個人資料夾中執行的應用程式可以監聽通知。

儲存在個人資料夾中

當應用程式在個人資料夾中執行時,在工作資料夾中執行的應用程式可能無法收到通知。根據預設,所有個人設定檔應用程式都會接收回呼,但 IT 管理員可以將一或多個個人設定檔應用程式加入許可清單,允許他們監聽通知變更。接著,系統會封鎖未加入許可清單的應用程式。在 Android 8.0 (API 級別 26) 以上版本中,管理工作資料夾的裝置政策控制器 (DPC) 可能會禁止應用程式透過 DevicePolicyManager 方法 setPermittedCrossProfileNotificationListeners() 監聽工作資料夾的通知。應用程式仍會收到回呼,用於接收有關個人設定檔中的通知。

測試應用程式與工作資料夾的相容性

建議您在工作資料夾環境中測試應用程式,找出會導致應用程式在設有工作資料夾的裝置上無法執行的問題。特別是,在工作資料夾裝置上進行測試,有助於確保應用程式正確處理意圖,例如不觸發無法處理的意圖、附加無效設定檔的 URI 等等。

我們提供了 TestDPC 範例應用程式,可讓您在搭載 Android 5.0 (API 級別 21) 以上版本的 Android 裝置上設定工作資料夾。這個應用程式可讓您輕鬆在工作資料夾環境中測試應用程式。您也可以使用這個應用程式設定工作資料夾,如下所示:

  • 指定受管理的設定檔能使用的預設應用程式
  • 設定哪些意圖可以從一個設定檔跨越另一個設定檔

如果您透過 USB 傳輸線將應用程式手動安裝到設有工作資料夾的裝置,則該應用程式會同時安裝在個人資料夾和工作資料夾中。安裝應用程式後,您可以在下列情況下測試應用程式:

  • 如果預設應用程式會處理意圖 (例如相機應用程式),請嘗試在工作資料夾中停用該預設應用程式,並確認應用程式會妥善處理這項作業。
  • 如果您觸發的意圖會由其他應用程式處理,請嘗試啟用及停用該意圖在不同設定檔之間跨設定檔的權限。確認應用程式在這兩種情況下都能正常運作。如果意圖無法在設定檔之間跨越多個設定檔,請在應用程式的設定檔上有合適的處理常式,以及沒有意圖時,驗證應用程式的行為。舉例來說,如果您的應用程式會觸發地圖相關意圖,請嘗試以下各種情境:
    • 裝置可讓地圖意圖從一個設定檔跨越至另一個設定檔,而另一個設定檔 (即應用程式並非執行應用程式的設定檔) 上設有合適的處理常式
    • 裝置不允許跨設定檔之間的地圖意圖跨越設定檔,但應用程式設定檔上已有合適的處理常式
    • 裝置不允許在設定檔之間跨地圖意圖互動,且裝置設定檔中沒有適合地圖意圖的處理常式
  • 如要將內容附加至意圖,請確認意圖在應用程式的設定檔中處理,以及跨設定檔之間是否能夠正常運作。

測試工作資料夾:提示與秘訣

如要在工作資料夾裝置上進行測試,以下提供幾個訣竅。

  • 如前所述,在工作資料夾裝置側載應用程式時,該應用程式會安裝在兩個設定檔中。如有需要,可以從一個設定檔中刪除應用程式,然後保留在另一個設定檔中。
  • Android Debug Bridge (ADB) 殼層中提供的大多數活動管理員指令都支援 --user 旗標,可讓您指定要以哪位使用者執行。您可以透過指定使用者,選擇是否要以非受管主要使用者或工作資料夾執行。詳情請參閱 ADB 殼層指令
  • 如要找出裝置上的活躍使用者,請使用 ADB 套件管理員的 list users 指令。輸出字串的第一個數字是使用者 ID,您可以與 --user 旗標搭配使用。詳情請參閱 ADB Shell 指令

舉例來說,如要尋找裝置上的使用者,您可以執行以下指令:

$ adb shell pm list users
UserInfo{0:Drew:13} running
UserInfo{10:Work profile:30} running

在這種情況下,主要使用者 (「Drew」) 的使用者 ID 為 0,工作資料夾的使用者 ID 則為 10。如要在工作資料夾中執行應用程式,請使用類似下方的指令:

$ adb shell am start --user 10 \
-n "com.example.myapp/com.example.myapp.testactivity" \
-a android.intent.action.MAIN -c android.intent.category.LAUNCHER