본문 바로가기
안드로이드 공부 & 앱

안드로이드 인앱 시스템 구축[1편] 앱 소유자(Owner) 권한 얻기

by 문톰 2023. 7. 28.

 

Intro

테블릿 안에 앱을 설치해서 테블릿을 사용자에게 판매해야(인앱 시스템) 할 때가 있습니다. 

하지만 PlayStore에 앱을 등록하지 않았기 때문에 여러가지 문제가 발생합니다.

 

예를 들면 사용자가 앱을  삭제했거나 아니면 업데이트 하는 경우 등 추후 유지보수에 대해

문제가 발생할 수 있습니다.

 

그래서 이번에는 제가 회사에서 인앱 시스템을 구축하면서 알게된 것들에 대해서 정리하겠습니다.

 

 

1.Device policy Manager

https://developer.android.com/reference/android/app/admin/DevicePolicyManager

-안드로이드 앱 소유자 권한을 가져야만 사용할 수 있는 기능들을 제공해주는 클래스 입니다.

-앱 삭제 방지, 공장초기화, 개발자 모드 비활성화 등의 기능들을 제공해줍니다.

-Device Policy Manger를 사용하기 위해서는 최상위 앱 권한인 소유자(Owner)

권한이 필요합니다.

 

2.안드로이드 소유자(Owner) 권한

-안드로이드 앱 권한 중 가장 상위에 있는 권한입니다.

-이 권한을 얻기 위해서는 관리자 권한이 먼저 필요합니다.

 

1)관리자 권한(Admin)을 얻는 방법

예제 

 https://github.com/mcsong/SimpleKioskDemo

 

GitHub - mcsong/SimpleKioskDemo: Simple Kiosk Android demo

Simple Kiosk Android demo. Contribute to mcsong/SimpleKioskDemo development by creating an account on GitHub.

github.com

 

1. MainActivity

-DevicePolicyManager 객체를 생성합니다.

private DevicePolicyManager devicePolicyManager;
devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);

-관리자 권한을 얻을 화면으로 이동하는 코드를 작성합니다.

private void adminActive() {
    ComponentName componentName = new ComponentName(this, AppDeviceAdminReceiver.class);
    Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, componentName);
    startActivityForResult(intent, DEVICE_ADMIN_ADD_RESULT_ENABLE);
}
   @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        if (requestCode == DEVICE_ADMIN_ADD_RESULT_ENABLE) {
//            setCameraDisabled(true);
        }

        if (requestCode == 10 && resultCode == RESULT_OK) {
            // 앱이 기기 소유자로 설정됨
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

3. AppDeviceAdminReceiver 

public class AppDeviceAdminReceiver extends DeviceAdminReceiver {
    private static final String TAG = AppDeviceAdminReceiver.class.getSimpleName();

    @Override
    public void onEnabled(Context context, Intent intent) {
        super.onEnabled(context, intent);
        Log.d(TAG, "Admin onEnabled");
    }

    @Override
    public void onDisabled(Context context, Intent intent) {
        super.onDisabled(context, intent);
        Log.d(TAG, "Admin onDisabled");
    }
}

3-1)manifest

<receiver
    android:name=".AppDeviceAdminReceiver"
    android:description="@string/device_admin_description"
    android:directBootAware="true"
    android:exported="true"
    android:label="@string/app_name"
    android:permission="android.permission.BIND_DEVICE_ADMIN"
    tools:targetApi="26">
    <meta-data
        android:name="android.app.device_admin"
        android:resource="@xml/device_admin_receiver" />
    <intent-filter>
        <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    </intent-filter>
</receiver>

4. device_admin_receiver.xml

<device-admin>
    <uses-policies>
        <limit-password />
        <watch-login />
        <reset-password />
        <force-lock />
        <wipe-data />
        <expire-password />
        <encrypted-storage />
        <disable-camera />
    </uses-policies>
</device-admin>

 

1-2)소유자 권한(Admin)을 얻는 방법

-관리자 권한을 얻어야만 소유자 권한을 얻을 수 있습니다.

-소유자 권한을 얻기 위해서는 adb 설정을 해야 합니다.

 

 

안드로이드 터미널로 이동 후 adb shell dpm set-device-owner 패키지이름/.리시버이름 이 명령어를 입력합니다.

소유자 권한을 얻는데 성공하면 위와 같은 메세지를 받게된다.

 

* 에러 케이스 

1. java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device

-이미 등록된 계정이 있어서 발생하는 에러 입니다.

-설정 -> 계정 -> 등록된 계정 삭제를 진행해주세요.

 

2.java.lang.RuntimeException: Can't set package ComponentInfo{app.example.deviceadmin/app.example.deviceadmin.AppDeviceAdminReceiver} as device owner.

-앱의 컴포넌트 이름이 맞지 않아서 발생하는 오류일 확률이 높습니다. 

-저의 경우에는 디바이스를 공장 초기화 하니 해결되었습니다.

 

* 주의 사항

- 소유자 권한을 얻은 상태에서 안드로이드 스튜디오로 앱을 빌드 할 수 없습니다.

- 왠만하면 개발용 폰으로 하시는 것을 추천합니다.

 

1-3)소유자 권한(Admin)을 해제 하는 방법

-안드로이드 터미널로 이동 후 adb shell dpm remove-active-admin 패키지이름/.리시버이름 이 명령어를 입력합니다.

 

 

인앱 시스템 구축 시 필요한 기능

1)테블릿의 고유한 키 값 

- 테블릿의 WIFI-Mac 주소를 저는 키 값으로 사용했습니다.

- 이 주소는 테블릿 내의 고유한 16진수로된 주소로 Device Policy Manager를 통해 앱에서도 사용할 수 있습니다.

-이 Unique한 Key 값을 앱에서 조회할 수 있음으로써 고객의 현재 보유한 테블릿의 개수를 알 수

있었습니다. 

btnWifiMac.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                btnWifiMac.setText(devicePolicyManager.getWifiMacAddress(componentName));
            }
        }
    }
});

 

 

2)앱 삭제 방지

-사용자가 실수로 앱을 삭제하는 상황을 방지하기 위해서 사용했습니다.

findViewById(R.id.btnStopUninstall).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            devicePolicyManager.setUninstallBlocked(componentName, "패키지이름", true);
        }
    }
});

 

 

- 소유자 권한이 있는 앱의 다운 링크를 QRCODE에 담은 후 디바이스 초기 환경 세팅 시 이 앱을 시스템 앱으로 만드는 방법에 대해서 포스팅 하겠습니다.

 

 

참고

https://daisyleh.blogspot.com/2019/03/devicepolicymanager.html

https://developer.android.com/reference/android/app/admin/DevicePolicyManager

http://sjava.net/2020/05/%ec%95%88%eb%93%9c%eb%a1%9c%ec%9d%b4%eb%93%9c-%ed%82%a4%ec%98%a4%ec%8a%a4%ed%81%ackiosk-%ec%95%b1-%ea%b0%9c%eb%b0%9c-2-3/

댓글