메인 액티비티 실행이 안돼요

일반적으로 앱은 아이콘이 있다. 아이콘을 누르면 진입점 역할의 액티비티가 실행된다. 이 액티비티를 편의상 메인 액티비티라고 부르자.

메인 액티비티를 만드는 법은 간단하다. AndroidManifest.xml에 선언된 액티비티 중 메인으로 만들고 싶은 것을 골라 아래와 같이 MAIN 액션LAUNCHER 카테고리가 포함된 인텐트 필터를 추가하면 된다.

<intent-filter>
     <action android:name="android.intent.action.MAIN" /> 
     <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

위와 같이 인텐트 필터를 선언하면, 런쳐는 메인 액티비티로 판단하여 앱 슬롯에 아이콘을 표시한다.

그럼, 코드로 메인 액티비티를 실행해보자. 내 앱이라면 패키지 이름과 컴포넌트 이름으로 명시적 호출도 가능하다. 여기서는 암시적 인텐트를 이용해 보자.

adb shell am start <패키지이름>

패키지 이름만 건네면 앱의 메인 액티비티를 찾아 실행하는 명령어다. 위 명령어로 앱들을 실행해보면 어떤 앱은 실행되고 어떤 앱은 실행되지 않는다. 왜 그럴까?

실행여부는 <intent-filter>에 android.intent.category.DEFAULT가 있어야 있느냐에 따라 달라진다. DEFAULT 카테고리가 있어야 패키지 이름만으로 실행할 수 있는 것이다.

숨겨진 액티비티도 아니고 아이콘이 노출된 앱인데 코드로 실행할 수는 없다니 이상하다. 게다가, 메인 액티비티는 공개된 액티비티이므로 android:exported=”true”도 강제라고 한다. 그럼 외부에서 실행하는 것을 보장하겠다는 뜻이 아닌가?

이런 앞뒤가 맞지 않는 상황 때문인지 안드로이드의 PackageManager 클래스는  API3부터 getLaunchIntentForPackage()라는 설명이 재미있는 API를 제공한다.

Returns a "good" intent to launch a front-door activity in a package. 
...(이하 생략)

메인 액티비티를 실행하는 “좋은” 인텐트를 만들어 반환한다고 API 설명이 되어 있다. 하지만, 이 API도 MAIN 액션, LAUNCHER 카테고리를 가진 액티비티를 찾아 반환하는 것이므로 여전히 인텐트 필터는 필요하다.

메인 액티지티를 만들 때 DEFAULT 카테고리도 잊지 말고 추가하도록 하자. 다른 앱이 내 앱을 한 번이라도 더 실행하도록 말이다.

그 밖에

  • 한 앱에서 MAIN, LAUNCHER 속성을 2개 이상의 액티비티에 동시에 선언할 수 있으며, 이 때 아이콘이 각각 생긴다.
  • 아이콘의 레이블은 액티비티의 레이블을 따라간다. 그러므로, 아이콘을 다르게 여러 개 만들 수도 있다.

참조