Android 利用 Managed Profile 確保兼容性

2018-08-02 18:03 更新

編寫:zenlynn 原文:http://developer.android.com/training/enterprise/app-compatibility.html

Android 平臺(tái)允許設(shè)備有 managed profile。managed profile 由管理員控制,它的功能和用戶原本的 profile 的功能是分別設(shè)置的。通過(guò)這種方法,在用戶設(shè)備上運(yùn)行的企業(yè)所定制應(yīng)用程序和數(shù)據(jù)的環(huán)境就在企業(yè)的控制之下,同時(shí)用戶還能使用私人的應(yīng)用程序和 profile。

本節(jié)課展示了如何修改你的應(yīng)用程序,使之能夠在有 managed profile 的設(shè)備上可靠運(yùn)行。除了一般應(yīng)用開發(fā)的最佳實(shí)踐外,你不用做任何事。然而,在有 managed profile 的設(shè)備上,最佳實(shí)踐的其中一些規(guī)范變得尤為重要。本文件強(qiáng)調(diào)了你所需要了解的問題。

概述

用戶經(jīng)常想在企業(yè)環(huán)境中使用他們的私人設(shè)備。這種情況可能讓企業(yè)陷入困境。如果用戶使用他們的私人設(shè)備,企業(yè)不得不擔(dān)心在這個(gè)不受控制的設(shè)備上的機(jī)密信息(例如員工的電子郵件和通訊錄)。

為了處理這種情況,Android 5.0(API 21)允許企業(yè)設(shè)置 managed profile。如果設(shè)備有 managed profile,這個(gè) profile 的設(shè)置是在企業(yè)管理員的控制之下的。管理員可以選擇在這個(gè) profile 之下,什么應(yīng)用程序可以運(yùn)行,什么設(shè)備功能可以允許。

如果一個(gè)設(shè)備有 managed profile,那么,無(wú)論應(yīng)用程序在哪個(gè) profile 之下運(yùn)行,都意味著:

  • 默認(rèn)情況下,大部分的 intent 無(wú)法從一個(gè) profile 跨越到另一個(gè)。如果在某個(gè) profile 之下的一個(gè)應(yīng)用程序創(chuàng)建了 intent,而這個(gè) profile 無(wú)法響應(yīng),又因?yàn)?profile 的限制這個(gè) intent 不允許跨越到其他 profile,那么,這個(gè)請(qǐng)求就失敗了,應(yīng)用程序可能意外關(guān)閉。
  • profile 管理員可以在 managed profile 中限制哪個(gè)系統(tǒng)應(yīng)用程序可以運(yùn)行。這個(gè)限制可能導(dǎo)致在 managed profile 中一些常見的 intent 無(wú)法處理。
  • 因?yàn)?managed profile 和非 managed profile 有各自的存儲(chǔ)區(qū)域,導(dǎo)致文件 URI 在一個(gè) profile 中有效,但在其他 profile 中無(wú)效。在一個(gè) profile 中創(chuàng)建的 intent 可能在其他 profile(取決于 profile 設(shè)置)中被響應(yīng),所以在 intent 中放置文件 URI 是不安全的。

防止失敗的 intent

在一個(gè)有 managed profile 的設(shè)備上,intent 是否能從一個(gè) profile 跨越到另一個(gè),存在著限制。大多情況下,一個(gè) intent 在哪個(gè) profile 中創(chuàng)建,就在哪個(gè) profile 中響應(yīng)。如果那個(gè) profile 中無(wú)法響應(yīng),就算在其他 profile 中可以響應(yīng),這個(gè) intent 也不會(huì)被響應(yīng),而且創(chuàng)建這個(gè) intent 的應(yīng)用程序會(huì)意外關(guān)閉。

profile 管理員可以選擇哪個(gè) intent 可以從一個(gè) profile 跨越到另一個(gè)。因?yàn)槭怯晒芾韱T做決定,所以你無(wú)法預(yù)先知道哪個(gè) intent 可以跨越邊界。管理員設(shè)置了這個(gè)策略,而且可以在任何時(shí)候自由更改。

在你的應(yīng)用程序啟動(dòng)一個(gè) activity 之前,你應(yīng)該驗(yàn)證這是可行的。你可以調(diào)用 Intent.resolveActivity() 方法來(lái)驗(yàn)證。如果無(wú)法處理,方法會(huì)返回 null。如果方法返回值非空,那么至少有一個(gè)方法可以處理這個(gè) intent,所以創(chuàng)建這個(gè) intent 是安全的。這種情況下,或者是因?yàn)樵诋?dāng)前 profile 中可以響應(yīng),或者是因?yàn)?intent 被允許跨越到可以處理的其他 profile 中,intent 可以被處理。(更多關(guān)于響應(yīng) intent 的信息,請(qǐng)查看 Common Intents。)

例如,如果你的應(yīng)用程序需要設(shè)置定時(shí)器,就需要檢查是否能響應(yīng) ACTION_SET_TIMER intent。如果應(yīng)用程序無(wú)法響應(yīng)這個(gè) intent,就需要采取恰當(dāng)?shù)男袆?dòng)(例如顯示一個(gè)錯(cuò)誤信息)。

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

    }
}

跨越 profile 共享文件

有時(shí)候應(yīng)用程序需要授權(quán)其他運(yùn)用程序訪問自己的文件。例如,一個(gè)圖片庫(kù)應(yīng)用可能想與圖片編輯器共享它的圖片。一般共享文件有兩種方法:通過(guò)文件 URI 或者內(nèi)容 URI。

一個(gè)文件 URI 是由前綴 file: 和文件在設(shè)備中存儲(chǔ)的絕對(duì)路徑組成的。然而,因?yàn)?managed profile 和私人 profile 有各自的存儲(chǔ)區(qū)域,所以一個(gè)文件 URI 在一個(gè) profile 中是有效的,在其他 profile 中是無(wú)效的。這種情況意味著,如果你要在 intent 中放置一個(gè)文件 URI,而這個(gè) intent 要在其他 profile 中響應(yīng),那么響應(yīng)方是不能訪問這個(gè)文件的。

你應(yīng)該取而代之用內(nèi)容 URI 共享文件。內(nèi)容 URI 用一種更安全、更易于分享的方式來(lái)識(shí)別文件。內(nèi)容 URI 包括了文件路徑,文件提供者,以及文件 ID。你可以通過(guò) FileProvider 為任何文件生成內(nèi)容 ID。然后,你就可以和(甚至在其他 profile 中的)其他應(yīng)用程序共享內(nèi)容 ID。響應(yīng)方可以使用內(nèi)容 ID 來(lái)訪問實(shí)際文件。

例如,這里展示了你怎么獲得一個(gè)指定文件 URI 的內(nèi)容 URI:

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

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

當(dāng)你調(diào)用 getUriForFile() 方法時(shí),必須包括文件提供者的權(quán)限(在這個(gè)例子里是"com.example.myapp.fileprovider"),在應(yīng)用程序的 manifest 中,用 \ 元素設(shè)定這個(gè)權(quán)限。更多關(guān)于用內(nèi)容 URI 共享文件的信息,請(qǐng)查看共享文件。

在 managed profile 環(huán)境測(cè)試你的應(yīng)用程序的兼容性

你要在有 managed profile 的環(huán)境中測(cè)試你的應(yīng)用程序,以發(fā)現(xiàn)會(huì)引起運(yùn)行失敗的問題。在一個(gè)有 managed profile 的設(shè)備中測(cè)試是一個(gè)驗(yàn)證你的應(yīng)用程序正確響應(yīng) intent 的好辦法:無(wú)法響應(yīng)的時(shí)候不創(chuàng)建 intent,不使用無(wú)法跨越 profile 的 URI 等等。

我們提供了一個(gè)示例應(yīng)用程序,BasicManagedProfile,你可以用它在一個(gè)運(yùn)行 Android 5.0 或者更高系統(tǒng)的 Android 設(shè)備上設(shè)置一個(gè) managed profile。這個(gè)應(yīng)用程序?yàn)樵谟?managed profile 的環(huán)境中來(lái)測(cè)試你的應(yīng)用程序提供了一個(gè)簡(jiǎn)單的方法。你也可以按照下面的方法用這個(gè)應(yīng)用程序來(lái)設(shè)置你的 managed profile:

  • 在 managed profile 中設(shè)定哪些默認(rèn)應(yīng)用程序可以使用
  • 設(shè)定哪些 intent 被允許從一個(gè) profile 跨越到另一個(gè)

如果你通過(guò) USB 線手動(dòng)安裝一個(gè)有 managed profile 的應(yīng)用程序,那么在 managed profile 和非 managed profile 之中都安裝有這個(gè)應(yīng)用程序。只要你安裝了應(yīng)用程序,你就能在以下條件下進(jìn)行測(cè)試:

  • 如果一個(gè) intent 可以被一個(gè)默認(rèn)的應(yīng)用程序(例如相機(jī)應(yīng)用程序)響應(yīng),試試 managed profile 中禁用這個(gè)默認(rèn)應(yīng)用程序,然后驗(yàn)證這個(gè)應(yīng)用程序可以做出恰當(dāng)?shù)男袨椤?/li>
  • 如果你創(chuàng)建了一個(gè) intent 希望被其他應(yīng)用程序響應(yīng),試試啟用以及禁用這個(gè) intent 從一個(gè) profile 跨越到另一個(gè)的權(quán)限。驗(yàn)證在這兩種情況下應(yīng)用程序都能做出恰當(dāng)?shù)男袨?。如?intent 不允許在 profile 之間跨越,無(wú)論當(dāng)前 profile 是否能做出響應(yīng),都要驗(yàn)證應(yīng)用程序能做出恰當(dāng)?shù)男袨椤@?,如果你的?yīng)用程序創(chuàng)建了一個(gè)地圖相關(guān)的 intent,試試以下每一種情況:
    • 設(shè)備允許地圖 intent 從一個(gè) profile 跨越到另一個(gè),并且在另一個(gè)(并非應(yīng)用程序所運(yùn)行的) profile 之中有恰當(dāng)?shù)捻憫?yīng)
    • 設(shè)備不允許地圖 intent 在 profile 之間跨越,但是在應(yīng)該程序所運(yùn)行的 profile 之中有恰當(dāng)?shù)捻憫?yīng)
    • 設(shè)備不允許地圖 intent 在 profile 之間跨越,并且在設(shè)備的 profile 之中沒有恰當(dāng)?shù)捻憫?yīng)
  • 如果你在 intent 里放置了內(nèi)容,不管是在當(dāng)前 profile 之中,還是在跨越 profile 之后,都要驗(yàn)證 intent 能有恰當(dāng)?shù)男袨椤?/li>

在 managed profile 環(huán)境測(cè)試:提示與技巧

你會(huì)發(fā)現(xiàn)在有 managed profile 的設(shè)備里進(jìn)行測(cè)試有一些技巧。

  • 如前所述,當(dāng)你側(cè)載一個(gè)應(yīng)用程序到一個(gè)有 managed profile 的設(shè)備里,是在 managed profile 和非 managed profile 之中都安裝了。如果你愿意,你可以從一個(gè) profile 之中刪除,在另一個(gè) profile 之中留下。
  • 安卓調(diào)試橋(adb)shell 端可用的 activity manager 命令大部分都支持 --user 標(biāo)識(shí),你可以用之設(shè)定運(yùn)行應(yīng)用程序的用戶。通過(guò)設(shè)定一個(gè)用戶,你可以選擇是在 managed profile 之中運(yùn)行,還是在非 managed profile 之中運(yùn)行。更多信息,請(qǐng)查看 ADB Shell Commands。
  • 為了找到設(shè)備上的活躍用戶,使用 adb 包管理器的 list users 命令。輸出的字符串中第一個(gè)數(shù)字是用戶 ID,你可以用于 --user 標(biāo)識(shí)。更多信息,請(qǐng)查看 ADB Shell Commands

例如,為了找到一個(gè)設(shè)備上的用戶,你會(huì)運(yùn)行這個(gè)命令:

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

在這里,非 managed profile("Drew")有個(gè) ID 為 0 的用戶,而 managed profile 有個(gè) ID 為 10 的用戶。要在工作 profile 之中運(yùn)行一個(gè)應(yīng)用程序,你會(huì)用到這樣的命令:

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


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)