Android - hasSystemFeature(), 지원되는 Feature 확인

JS · 15 Nov 2020

안드로이드는 System Feature라는 것을 정의하고, 이 디바이스가 어떤 기능을 지원하는지 App들이 알 수 있도록 합니다.

예를 들어, 안드로이드 디바이스가 카메라를 지원하지 않을 수 있습니다. SmartPhone은 대부분 카메라를 지원하지만 Watch는 지원하지 않을 수 있기 때문입니다. 어떤 카메라 앱이 Watch에 설치되었을 때 카메라 관련 코드를 수행하면 Exception이 발생하여 앱이 죽을 수 있습니다. 이럴 때 System Feature를 확인하여 카메라를 지원하는지 확인할 수 있습니다.

예제 코드는 kotlin으로 작성되었습니다.

PackageManager.hasSystemFeature()

hasSystemFeature(String featureName)는 인자로 전달된 Feature가 정의되어있는지 결과를 boolean으로 리턴합니다.

public abstract boolean hasSystemFeature(@NonNull String featureName);

다음과 같이 디바이스에 카메라 Feature가 정의되어있는지 확인할 수 있습니다.

if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
    Log.d("Test", "Camera is available in this device")
}

다음과 같이 true를 리턴하면 이 디바이스는 카메라 Feature가 정의되어있고, 실제로 카메라가 디바이스에 지원된다는 것을 의미합니다.

11-15 11:13:04.280  5002  5002 D Test    : Camera is available in this device

FEATURE_WATCH는 SmartPhone에 정의되어있지 않고, Watch device에만 정의되어있습니다. 따라서 이 Feature로 이 디바이스가 Watch인지 SmartPhone인지 구분할 수 있습니다.

if (packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
    Log.d("Test", "It's a watch device")
}

Feature 종류

Android에서 정의한 Feature는 Framework 코드인 PackageManager.java에 정의되어있습니다.

정의된 내용은 Android developer - PackageManager에서 확인하실 수 있습니다.

위 사이트에서 이런식으로 보이는데 코드에서 PackageManager.FEATURE_LOCATION_NETWORK처럼 사용할 수 있습니다.

public static final String FEATURE_LOCATION_NETWORK
Constant Value: "android.hardware.location.network"

PackageManager.getSystemAvailableFeatures()

getSystemAvailableFeatures()는 현재 디바이스에 정의된 모든 Feature를 FeatureInfo[] 배열로 리턴합니다.

public abstract FeatureInfo[] getSystemAvailableFeatures();

다음과 같이 모든 Feature의 이름과 버전 정보를 출력할 수 있습니다.

val featureInfoArray = packageManager.systemAvailableFeatures
for (feature: FeatureInfo in featureInfoArray) {
    Log.d("Test", "name: ${feature.name}, version: ${feature.version}")
}

결과는 다음과 같습니다. 내용을 보시면 디바이스가 Touchscreen을 지원하는지도 Feature로 정의되어 있습니다.

11-15 11:13:04.281  5002  5002 D Test    : name: android.software.adoptable_storage, version: 0
11-15 11:13:04.281  5002  5002 D Test    : name: android.hardware.sensor.accelerometer, version: 0
11-15 11:13:04.281  5002  5002 D Test    : name: android.hardware.faketouch, version: 0
11-15 11:13:04.281  5002  5002 D Test    : name: android.software.backup, version: 0
11-15 11:13:04.282  5002  5002 D Test    : name: android.hardware.touchscreen, version: 0
11-15 11:13:04.282  5002  5002 D Test    : name: android.hardware.touchscreen.multitouch, version: 0
....
11-15 11:13:04.283  5002  5002 D Test    : name: android.hardware.location, version: 0
11-15 11:13:04.283  5002  5002 D Test    : name: android.hardware.vulkan.level, version: 1
11-15 11:13:04.283  5002  5002 D Test    : name: android.software.secure_lock_screen, version: 0
11-15 11:13:04.283  5002  5002 D Test    : name: android.hardware.telephony, version: 0
11-15 11:13:04.283  5002  5002 D Test    : name: android.software.file_based_encryption, version: 0

이 메소드는 API 24 이상에서 제공합니다.

hasSystemFeature(String featureName, int version)

hasSystemFeature(featureName)와 다르게, version 정보도 인자로 전달합니다. Feature를 등록할 때 version도 함께 설정할 수 있습니다. 어떤 버전 이상의 Feature가 등록되어있는지 확인할 때 이 메소드를 사용할 수 있습니다.

/**
 * Check whether the given feature name and version is one of the available
 * features as returned by {@link #getSystemAvailableFeatures()}. Since
 * features are defined to always be backwards compatible, this returns true
 * if the available feature version is greater than or equal to the
 * requested version.
 *
 * @return Returns true if the devices supports the feature, else false.
 */
public abstract boolean hasSystemFeature(@NonNull String featureName, int version);

예를 들어, 위에서 FEATURE_VULKAN_HARDWARE_LEVEL는 version이 1로 설정되어 있는 것을 확인하였습니다. 만약 version 2를 지원하는 디바이스가 있고, 버전마다 다른 API를 호출해야 한다면 이 메소드를 사용하여 구분할 수 있습니다.

11-15 11:13:04.283  5002  5002 D Test    : name: android.hardware.vulkan.level, version: 1

다음과 같이 버전에 따라서 다른 동작을 하도록 할 수 있습니다.

if (packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 1)) {
    Log.d("Test", "FEATURE_VULKAN_HARDWARE_LEVEL >= 1")
}

if (packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_LEVEL, 2)) {
    Log.d("Test", "Has FEATURE_VULKAN_HARDWARE_LEVEL >= 2")
}

실행해보면, 이 디바이스는 version 1을 지원하기 때문에 아래와 같이 출력됩니다.

11-15 11:34:32.375  5606  5606 D Test    : FEATURE_VULKAN_HARDWARE_LEVEL >= 1

이 메소드는 API 24 이상에서 제공합니다.

adb shell로 feature 확인

adb shell pm has-feature [feature name]으로 어떤 피쳐가 디바이스에 정의되어있는지 확인할 수 있습니다. Feature의 String을 입력해야 합니다.

$ adb shell pm has-feature android.hardware.vulkan.level
true

$ adb shell pm has-feature android.hardware.location
true

디바이스에 정의된 모든 Feature를 확인하고 싶다면 adb shell pm list features 명령어를 사용하시면 됩니다.

$ adb shell pm list features

feature:reqGlEsVersion=0x20000
feature:android.hardware.audio.output
feature:android.hardware.bluetooth
feature:android.hardware.bluetooth_le
feature:android.hardware.camera
feature:android.hardware.camera.any
feature:android.hardware.camera.ar
feature:android.hardware.camera.autofocus
feature:android.hardware.camera.capability.manual_post_processing
feature:android.hardware.camera.capability.manual_sensor
feature:android.hardware.camera.capability.raw
feature:android.hardware.camera.concurrent
feature:android.hardware.camera.flash
feature:android.hardware.camera.front
feature:android.hardware.camera.level.full
feature:android.hardware.faketouch
feature:android.hardware.fingerprint
feature:android.hardware.location
feature:android.hardware.vulkan.level=1
....

버전이 0이라면 버전 정보는 생략되며, 0을 초과하면 아래와 같이 feature_name=1처럼 버전이 표시됩니다.

feature:android.hardware.vulkan.level=1
댓글을 보거나 쓰려면 이 버튼을 눌러주세요.
codechachaCopyright ©2019 codechacha