봄날은 갔다. 이제 그 정신으로 공부하자

Android 12를 타겟으로 빌드하기 본문

학습

Android 12를 타겟으로 빌드하기

길재의 그 정신으로 공부하자 2022. 2. 8. 20:20

Android 12는 구글이 주도하는 안드로이드 모바일 운영체계의 12번째 주요 릴리즈로 19번째 버전으로 2021년 2월 18일 안드로이드 블로그에 최초로 발표되고 5월부터 꾸준한 베타 릴리즈가 계획되었고 8월에 플랫폼이 안정되어 정식 버전이 2021년 10월 4일에 AOSP를 통해 최초로 공개 되었습니다.

이후 구글 픽셀폰을 시작으로 삼성, 화웨이, LG 등의 핸드폰 벤더들이 android 12를 지원하고 있습니다.

 

이렇게 android 12가 공식적으로 공개되고 지원되는 기기들이 늘어감에 따라 개발자들은 android 12가 기존 11에 비해 어느 부분이 변경되었으며 무슨 차이가 있는지 파악하고 이에 대비해야 합니다.

자세한 변경 사항은 이전 글 참고 -> https://als2019.tistory.com/90

 

이번 글에서는 Android 12 타켓으로 빌드하는 방법에 대해 설명합니다.

 

 

[Step 1] Android 12로 빌드하기

Android 12로 빌드하기위해서는 우선 app의 build.gradle의 compileSdkVersion과 targetSdkVersion을 아래와 같이 31로 변경해 android 12를 타겟으로 빌드 될 수 있도록 합니다.

android {
	compileSdkVersion 31
	...

	defaultConfig{
		targetSdkVersion 31
		...

	}

	...
}

 

 

[Step 2] AndroidManifest.xml 수정

이렇게 수정한 후 빌드하면 아래와 같은 에러가 발생하게 됩니다.

Manifest merger failed : android:exported needs to be explicitly specified for . Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

 

에러가 발생하는 이유는 android 12에서는 다른 애플리케이션의 구성요소로 Activity를 시작할 수 있는지 설정하는 요소인 android:exported 속성을 명시적으로 선언해야 하기 때문으로, 이 속성은 default가 false인데 activity가 intent-filter를 가지고 있으면 true로 설정되어 있어야 해서 에러를 발생하는 것 입니다.

 

즉, 에러 해결을 위해 intent-filter를 가지고 있는 activity는 아래와 같이 선언해 주어야 합니다.

<activity
    android:name=".view.ActIntro"
    android:label="@string/app_name"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

activity 뿐만이 아니라 receiver 그리고 service도 intent-filter를 포함하고 있다면 android:exported="true"로 선언되어 있어야 합니다.

 

[Step 3] 외부 라이브러리 대응.

AndroidManifest.xml를 수정했는데도 불구하고 계속 아래와 같은 에러가 발생한다면...

매우 당황스럽게 됩니다.

아무리 AndroidManifest.xml를 둘러봐도 activity, receiver, service를 모두 다 수정했는데 에러가 발생하다니...

Manifest merger failed : android:exported needs to be explicitly specified for . Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.

 

이 경우는 엡에서 사용하는 외부 라이브러리가 android 12를 대응해주지 못해 발생하는 문제 입니다.

일단 라이브러리를 android 12 지원해주는 버전으로 업데이트해주면 해결 되지만, 일부 라이브러리는 지원이 늦어질 수 있습니다. 

그럴 경우에는 아래와 같은 대응이 필요합니다.

 

우선 현재 앱에서 사용하는 외부 라이브러리가 android:exported를 어떻게 지원하는지 확인하기 위해서는 아래 그림과 같이 프로젝트의 External Libraries를 선택해 라이브러리를 하나 하나 확인해봐야 합니다.

이렇게 하나 하나 확인하는 과정에서 intent-filter를 사용하지만 android:exported가 선언되지 않은 activity를 찾았다면 다음과 같이 android:exported를 재정의해주는 처리가 필요합니다.

 

[예시. 외부 라이브러리 대응] 

예를 들어 네이버 ID로 로그인을 들어보겠습니다.

엡에서 "com.naver.nid:naveridlogin-android-sdk:4.4.1" 라이브러리를 사용한다면 External Libraries를 통해 확인해보면 아래와 같이 라이브러리의 AndroidManifest.xml에 android:exported가 설정되어 있지 않아 android 12 빌드시 에러가 발생합니다.

<activity
    android:name="com.nhn.android.naverlogin.ui.OAuthCustomTabActivity"
    android:configChanges="orientation|screenSize"
    android:launchMode="singleTask"
    android:screenOrientation="behind"
    android:theme="@android:style/Theme.Translucent.NoTitleBar" >
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <!-- Intent URL 에서 로그인 액티비티를 실행하기 위해 설정 -->
        <data
            android:host="authorize"
            android:path="/"
            android:scheme="naver3rdpartylogin" />
    </intent-filter>
</activity>

 

이런 경우 앱의 AndroidManifest.xml에서 tools:replace="android:exported" 사용해 문제가 되는 activity의 android:exported true 재정의해주어야 합니다.

<activity
    android:name="com.nhn.android.naverlogin.ui.OAuthCustomTabActivity"
    android:exported="true"
    tools:replace="android:exported"/>

 

이런식으로 외부 라이브러리를 찾아서 수정해주면 이제 빌드가 되고 앱을 실행 할 수 있게 됩니다.

 

[Step 4] 마무리...

그런데 아뿔사

앱을 실행했더니 잘 동작하다가 갑자기 아래와 같은 에러를 뱉으면서 죽네요... ㅠ_ㅠ

java.lang.RuntimeException: Unable to create service 000.000.000.MyService: java.lang.IllegalArgumentException: com.seeon.hotplace: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
    Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.

 

이 에러는 android 12에서는 PendingIntent 인스턴스를 만들기 위해서는 플래그에 FLAG_IMMUTABLE or FLAG_MUTABLE를 사용해야 한다는 말이므로  아래와 같이 수정해주면 간단히 해결됩니다.

PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);

 

정리

이번 글에서는 앱을 android 12를 타겟으로 빌드하는 방법에 대해 설명하였습니다.

간단히 요약하면 다음과 같습니다.

1. Build.gradle를 수정해 android 12빌드하기

      - compileSdkVersion 31

      - targetSdkVersion 31

2. AndroidManifest.xml 파일의 activity, receiver, service android:exported 명시적으로 선언하기

3. 외부 라이브러리가 아직 android 12 대응이 안되어 있을 tools:replace="android:exported" 사용해 재정의하기

4. PendingIntent 인스턴스 생성 플래그 사용해주기

Comments