직장 프로필에서 실행되는 앱 빌드

직장 프로필이란 무엇인가요?

직장 프로필은 회사에서 개인 기기를 업무용으로 사용할 수 있도록 직원에게 허용한 경우 사용자의 개인 기기에서 사용할 수 있는 보조 프로필입니다.

직장 프로필은 IT 관리자가 제어할 수 있으며, 직장 프로필에 사용 가능한 기능은 사용자 기본 프로필의 기능과 별개로 설정됩니다. 이 접근 방식을 통해 조직은 기기에서 회사 앱과 데이터가 실행되는 환경을 제어하면서도 사용자에게 개인 앱과 프로필을 사용할 수 있도록 허용할 수 있습니다.

직장 프로필은 앱에 어떠한 영향을 주나요? 직장 프로필에는 모든 앱을 설치할 수 있습니다. 이는 앱이 런타임 제한과 동작 변경에 놓일 수 있다는 의미입니다. 앱이 업무용으로 사용되는 경우 안전한지 확인하는 것도 좋습니다. 앱이 개인 프로필에서 실행 중이더라도 직장 프로필이 앱의 작동 방식에 영향을 줄 수 있습니다.

기본 요건

이 Codelab은 기초부터 중급 수준의 기술을 갖춘 Android 개발자를 대상으로 만들었습니다.

또한 이전에 앱을 빌드하고 Android 스튜디오를 사용한 적이 있으며 기기나 에뮬레이터에서 앱을 테스트해 본 적도 있다고 가정하고 진행됩니다.

실행할 작업

이 Codelab에서는 직장 프로필이 있는 기기에 앱을 설치할 때 최적의 사용자 환경을 제공하도록 앱을 수정합니다. 또한 다음이 가능하도록 앱을 만드는 방법을 배웁니다.

  • 개인 연락처와 직장 연락처를 동시에 처리합니다.
  • 앱 자체에서 직장 프로필과 개인 프로필 간에 전환합니다.

e69c26cfc305d675.png

필요한 항목

  • 관리되지 않는 Android 기기(조직에서 소유하거나 관리되지 않음)

테스트 기기 설정

이 Codelab에서는 실제 기기를 사용하는 것이 좋습니다. 하지만 에뮬레이터에서도 아래와 동일한 설정을 진행할 수 있습니다.

TestDPC

Google에서 빌드한 TestDPC 앱은 개발자가 자신의 기기에서 관리 환경을 시뮬레이션하고 테스트하는 데 도움이 됩니다. 이 앱은 직장 프로필을 설정하고, IT 관리자처럼 기기에서 특정 기능을 사용 설정/중지할 수 있는 컨트롤도 제공합니다.

TestDPC 앱 설치

기기에서 Google Play 스토어를 열고 TestDPC 앱을 다운로드합니다.

직장 프로필 설정

TestDPC 앱이 설치되면 2가지 아이콘 즉, 설정 아이콘과 TestDPC 앱 아이콘이 기기에 표시됩니다. 설정 아이콘을 탭하고 단계를 따릅니다.

이제 두 개의 별개 프로필 즉, 개인 앱용 프로필과 직장 앱용 프로필이 생겼습니다. 앱 목록 상단의 탭을 통해 두 프로필 간에 전환할 수 있습니다.

각 프로필에 자체 Play 스토어 앱이 있습니다. 런처 아이콘 위에 있는 작은 서류 가방 사진을 통해 직장 앱을 식별할 수 있습니다.

153e3b8dbfb4a86e.gif

평소대로 Play 스토어를 통해 앱을 설치할 수 있습니다. 어떤 Play 스토어(개인인지 직장인지)를 실행하는지에 따라 그 프로필에만 앱이 설치됩니다. 두 Play 스토어에서 앱을 모두 설치할 경우 양쪽 프로필에 앱이 생깁니다. 이 경우 앱의 각 버전은 완전히 분리된 저장공간과 구성 공간을 갖게 됩니다.

Android 스튜디오에서 앱을 실행하여 설치하면 기본적으로 앱은 두 프로필에 모두 설치됩니다.

데모 앱에서 사용할 테스트 연락처를 설정합니다.

  1. 개인 프로필에서 기기의 연락처 앱을 실행합니다.
  2. 개인 연락처로 식별 가능한 테스트 연락처를 추가합니다.
  3. 직장 프로필에서 연락처 앱을 실행합니다. 방금 추가한 개인 연락처는 표시되지 않습니다.
  4. 직장 연락처로 식별 가능한 테스트 연락처를 추가합니다.

연락처가 만족스럽게 제대로 설정되면 데모 앱의 시작 코드를 사용해 보세요.

  1. 샘플 앱을 가져오려면 다음 중 하나를 진행합니다.
  • GitHub에서 저장소를 클론합니다.
$  git clone https://github.com/a-samak/work-profile-codelab
  • 또는 저장소를 ZIP 파일로 다운로드합니다.

ZIP 파일 다운로드

  1. 다운로드되면 프로젝트 폴더로 이동하고 시작 분기로 전환합니다.
$  git checkout starter
  1. Android 스튜디오에서 앱을 열고 실행합니다.

앱을 처음 실행할 때의 모습은 다음과 같습니다.

f9779ab476511718.png

직접 해 보기

기기 또는 에뮬레이터의 Android 스튜디오에서 앱을 실행하면 앱은 두 프로필에 모두 설치됩니다. 원하는 경우 한 프로필에서는 앱을 삭제하고 다른 프로필에는 그대로 둘 수 있습니다.

개인 프로필에서 앱을 실행해 봅니다. 개인 연락처는 모두 표시되지만 직장 연락처는 아무것도 표시되지 않습니다. 이제 직장 프로필에서 앱을 실행해 봅니다. 직장 연락처만 표시되고 개인 연락처는 아무것도 표시되지 않습니다.

이 Codelab의 마지막 부분에서는 앱을 개인 프로필에서 실행할 때 직장 연락처와 개인 연락처가 함께 표시됩니다. 앱 자체 내의 다른 프로필에서 앱의 다른 인스턴스를 실행하여 프로필 간에 전환할 수도 있습니다.

ContactsContract.Contacts.CONTENT_URI를 사용하여 연락처를 로드하면 앱은 실행 중인 프로필에 따라 표시할 연락처를 결정합니다. 그러나 대부분의 경우 앱에서 두 연락처 목록을 동시에 로드하고자 할 수 있습니다. 예를 들어 사용자가 직장 동료와 개인 항목(사진, 문서)을 공유하고 싶을 수 있습니다. 그렇게 하려면 두 연락처 목록을 모두 가져와야 합니다.

MainActivity.kt 열기

onCreateLoader() 메서드는 연락처를 가져오고 로드하기 위한 커서 로더를 만듭니다. 현재 이 메서드는 기본 ContentURI를 사용하는 방법으로만 CursorLoader를 반환합니다. 이 메서드는 두 번 호출하게 됩니다. 한 번은 개인 연락처를 위해, 다른 한 번은 직장 연락처를 위해 호출할 것입니다. 연락처를 구분하기 위해 각 경우에 서로 다른 ID를 onCreateLoader()에 전달합니다. 사용할 ContentURI를 정하려면 이 메서드에 전달된 ID를 확인해야 합니다.

먼저, 이 메서드에 전달된 ID 값에 따라 ContentURI 변수의 값을 변경합니다. PERSONAL_CONTACTS_LOADER_ID의 경우 이를 기본 ContactsContract.Contacts.CONTENT_URI에 할당합니다. 그러지 않으면 여기에 설명된 대로 ENTERPRISE_CONTENT_FILTER_URI를 빌드하게 됩니다.

ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
                    .buildUpon()
                    .appendPath(nameFilter)
                    .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY,
                        ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
                    )
                    .build()

이는 콘텐츠 필터 URI이므로 빌더에는 연락처를 검색하거나 로드할 때 사용할 검색 필터(검색구문)가 필요합니다.

우선은 이름이 문자 'a'로 시작하도록 검색구문을 하드코딩합니다.

val nameFilter = Uri.encode("a") // names that start with a

검색할 연락처 디렉터리도 지정해야 합니다. 기기에 로컬로 저장된 연락처를 검색하는 ENTERPRISE_DEFAULT 디렉터리를 사용할 것입니다.

onCreateLoader() 메서드는 다음과 같습니다.

override fun onCreateLoader(id: Int, args: Bundle?): Loader<Cursor> {
        val nameFilter = Uri.encode("a") // names that start with W
        val contentURI = when (id) {
            PERSONAL_CONTACTS_LOADER_ID -> ContactsContract.Contacts.CONTENT_URI
            else -> {
                ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
                    .buildUpon()
                    .appendPath(nameFilter)
                    .appendQueryParameter(
                        ContactsContract.DIRECTORY_PARAM_KEY,
                        ContactsContract.Directory.ENTERPRISE_DEFAULT.toString()
                    )
                    .build()
            }
        }
        return CursorLoader(
            this, contentURI, arrayOf(
                ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
            ), null, null, null
        )
    }

이제 위 메서드를 트리거하려면 새 ID 값으로 다른 Loader를 초기화해야 합니다.

먼저 MainActivity의 맨 위에서 직장 연락처의 새 상수 ID 값을 만듭니다.

const val WORK_CONTACTS_LOADER_ID = 1

그런 다음 initLoaders()에서 LoaderManager를 사용하여 위에서 만든 새 ID로 새 Loader를 초기화합니다.

private fun initLoaders() {
        LoaderManager.getInstance(this).
            initLoader(PERSONAL_CONTACTS_LOADER_ID, null, this)
        LoaderManager.getInstance(this).
            initLoader(WORK_CONTACTS_LOADER_ID, null, this)
    }

두 로더의 데이터 커서가 동일한 구조를 가지고 있으므로 다른 모든 메서드가 동일하게 기능해야 합니다.

직접 해 보기

개인 프로필에서 앱을 실행하면 이제 직장 연락처와 개인 연락처가 모두 표시됩니다!

f9779ab476511718.png 7e4846e179664d66.png

직장 프로필은 어떻게 되나요?

직장 프로필에서 앱을 실행하는 경우 직장 연락처는 계속 표시되지만 개인 연락처는 아무것도 표시되지 않습니다. 직장 프로필의 주요 목표 중 하나가 사용자의 개인 정보를 보호하는 데 있으므로 직장 앱에서는 개인 프로필의 개인 정보에 액세스할 수 없기 때문입니다.

9b7ddeec64957963.png

Android에는 다른 프로필에서 앱의 다른 인스턴스를 시작할 수 있는 API가 포함되어 있어 사용자가 손쉽게 계정을 서로 전환할 수 있습니다. 예를 들어 이메일 앱에 있는 UI에서는 사용자가 개인 프로필과 직장 프로필을 서로 전환하여 두 이메일 계정에 액세스할 수 있습니다.

어떤 앱이라도 다른 프로필에 이미 설치되어 있다면 이 API를 호출하여 동일한 앱의 주요 활동을 시작할 수 있습니다.

앱에 교차 프로필 계정 전환을 추가하기 위해 먼저 사용자가 프로필을 전환할 수 있는 버튼을 기본 활동 레이아웃에 추가해야 합니다.

activity_main.xml을 열고 recycler-view 위젯 아래에 버튼 위젯을 추가합니다.

<androidx.appcompat.widget.AppCompatButton
        android:id="@+id/button"
        app:layout_constraintTop_toBottomOf="@+id/contacts_rv"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

MainActivity.kt로 돌아가서 프로필을 전환하도록 버튼의 클릭 이벤트를 설정합니다.

이를 위해 먼저 CrossProfileApps 시스템 서비스를 가져옵니다.

val crossProfileApps = getSystemService(CrossProfileApps::class.java)

이 클래스는 프로필 전환 기능을 구현하는 데 필요한 모든 API를 제공합니다. 이 앱이 설치된 다른 모든 프로필을 반환하는 targetUserProfiles를 호출하여 사용자 프로필 목록을 가져올 수 있습니다.

val userHandles = crossProfileApps.targetUserProfiles

이제 반환된 userHandle의 첫 번째 항목을 사용하여 다른 프로필에서 앱을 실행할 수 있습니다.

crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )

또한 프로필 전환 메시지를 사용자에게 표시하는 현지화된 텍스트도 가져올 수 있으며 이를 사용하여 버튼의 텍스트 값을 설정할 수 있습니다.

val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())

이제 이러한 모든 부분을 합칩니다. MainActivity.kt에 추가하는 항목이 됩니다.

val crossProfileApps = getSystemService(CrossProfileApps::class.java)
        val userHandles = crossProfileApps.targetUserProfiles
        val label = crossProfileApps.getProfileSwitchingLabel(userHandles.first())
        button = findViewById<AppCompatButton>(R.id.button).apply {
            text = label
            setOnClickListener {
                crossProfileApps.startMainActivity(
                    componentName,
                    userHandles.first()
                )
            }
        }

직접 해 보기

지금 앱을 실행하면 앱을 실행한 위치에 따라 직장 프로필 또는 개인 프로필 간에 전환할 수 있음을 나타내는 버튼이 하단에 표시됩니다.

버튼을 클릭하면 다른 프로필에서 앱이 실행됩니다.

d904de4fdc0d091b.png 4835ce56fcf10ea1.png

지금까지 개인 프로필은 물론 직장 프로필에서도 작동하도록 앱을 수정했습니다. 이는 직장 프로필이 설치되어 있을 때 개인 모드에서 실행하더라도 직장 연락처를 가져오는 것으로 알 수 있습니다.

또한 사용자가 앱을 실행하는 중에 앱을 닫고 원하는 프로필에서 다시 실행하지 않더라도 동일한 앱의 직장 프로필과 개인 프로필 간에 전환할 수 있는 방법을 구현했습니다. 이는 별도로 다른 프로필에서 앱을 사용하는 사용자에게 유용한 방법입니다.

자세히 알아보기