Notification에서 앱 실행 with Service

안드로이드 노티피케이션에서 앱 바로가기를 만들어 보자. 

노티피케이션이 없어지지 않기 위해 서비스를 사용한다.

핵심은 서비스로 Notification을 Foreground로 실행 한다. 

그리고 View에서 버튼을 누르면 해당 패키지명을 intent로 날린다. 

이 intent를 받은 브로드케스트를 등록하여 앱을 실행 하도록 처리 하면 된다.

예제 코드 다운로드-


svn checkout –username anonsvn

The password is ‘anonsvn’

Service 구현 내용 

package com.kmshack.qinker.service;

import java.lang.reflect.Method;

import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.RemoteViews;

import com.kmshack.qinker.MainActivity;
import com.kmshack.qinker.R;
import com.kmshack.qinker.utils.GraphicUtils;

public class QinkerService extends Service {
    public static final String UPDATE = "com.kmshack.qinker.service.update";
    public static final String CMD = "com.kmshack.qinker.service.cmd";
    public static final int SERVICE_STATUS = 1;
    private Notification mNotification;
    private final IQinkerService.Stub mBinder = new IQinkerService.Stub() {
        public boolean stopService() throws RemoteException {
            return false;
        public boolean startService() throws RemoteException {
            return false;
        public boolean isStart() throws RemoteException {
            return false;

    public IBinder onBind(Intent arg0) {
        return mBinder;
    public void onCreate() {
        IntentFilter commandFilter = new IntentFilter();
        registerReceiver(mIntentReceiver, commandFilter);
    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
    private void handleCommand(Intent intent){

        if (intent != null) {
            String action = intent.getAction();
            if(action == null)
                String packageName = intent.getStringExtra("package_name");
     * 앱을 실행한다.
     * @param packageName
    private void startActivityForPackageName(String packageName){
        PackageManager pm = getPackageManager();
        Intent app = pm.getLaunchIntentForPackage(packageName);
     *  상태바를 올린다.
    private void disableStatusBar(){
            Object service  = getSystemService("statusbar");
            Class statusbarManager = Class.forName("");
            Method collapse = null;
            if (Build.VERSION.SDK_INT  < 17) {
                collapse = statusbarManager.getMethod("collapse");
            } else {
                collapse = statusbarManager.getMethod("collapsePanels");
        }catch(Exception ex){
     * 노티피케이션을 표시한다.
    private void showNotification(){
        Intent contentsIntent = new Intent(getApplicationContext(), MainActivity.class);
         mNotification =  new Notification.Builder(getApplicationContext())
                                         .setContentIntent(PendingIntent.getActivity(getApplicationContext(), 0, contentsIntent, 0))
         RemoteViews views = new RemoteViews(this.getPackageName(), com.kmshack.qinker.R.layout.notification);

         Intent intent = new Intent(CMD);
         intent.setComponent(new ComponentName(getApplicationContext(), QinkerService.class));
         intent.putExtra("package_name", "com.kmshack.BusanBus");
         PendingIntent contentIntent = PendingIntent.getService(getApplicationContext(), 0, intent, 0);
         views.setOnClickPendingIntent(, contentIntent);
         views.setImageViewBitmap(, getAppIconResource("com.kmshack.BusanBus"));
         mNotification.contentView = views;
         mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
        startForeground(SERVICE_STATUS, mNotification);
    private Bitmap getAppIconResource(String packageName){
        PackageManager pm = getPackageManager();
        try {
            Drawable icon =  pm.getApplicationIcon(packageName);
            return GraphicUtils.getBitmapForDrawable(icon);
        } catch (NameNotFoundException e) {
        return null;
    public void onDestroy() {

    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);

    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);


Start Service at Boot Time

안드로이드 폰은 부팅이 끝나면 액션이 ‘android.intent.action.BOOT_COMPLETED’인 인텐트를 브로드캐스트 한다. 그러므로 이 인텐트 브로트캐스트를 받을 수 있는 BroadcastReceiver가 필요하다.

public class GPSLoggerServiceManager extends BroadcastReceiver {
  public void onReceive(Context ctx, Intent intent) {
   if (intent.getAction().equals(“android.intent.action.BOOT_COMPLETED”)) {
     ComponentName cName = new ComponentName(ctx.getPackageName(), GPSLogger);
     ComponentName svcName = ctx.startService(new Intent().setComponent(cName);
     if (svc == null) {
       Log.e(TAG, “Could not start service ” + cName.toString());
   } else {
     Log.e(TAG, “Received unexpected intent ” + intent.toString());

여기서 가장 핵심은 onReceive() 메소드이다. 원하는 인텐트가 브로드캐스트 되면 onReceive() 메소드가 호출된다.

그리고 리시버는 manifest 파일에 선언되어 있어야 한다.

<receiver android:name=”.LocationLoggerServiceManager
   android:label=”LocationLoggerServiceManager” >
   <action android:name=”android.intent.action.BOOT_COMPLETED” />

또한 이 클래스는 보안 설정에 선언할 필요가 있는 특정 이벤트 브로드캐스트를 들어야 하기 때문에 manifest 파일에 RECEIVE_BOOT_COMPLETED 퍼미션이 있어야 한다.

<uses-permission android:name=”android.permission.RECEIVE_BOOT_COMPLETED” />

위와 같이 추가해주면 부팅이 끝나고 서비스가 자동으로 실행되게 된다.

On current Android devices, we can keep only a small handful of applications
running at the same time.  Having your application do this is going to going
to take resources from other things that at any particular point in time
would be better used elsewhere.  And in fact, you can be guaranteed that
your service will -not- stay running all of the time, because there is so
much other stuff that wants to run (other background services that are only
running when needed will be prioritized over yours), or needs more memory
for what the user is actually doing (running the web browser on complicated
web pages is a great way to kick background stuff out of memory).

We have lots of facilities for implementing applications so they don’t need
to do this, such as alarms, and various broadcasts from events going on in
the system.  Please please please use them if at all possible.  Having a
service run forever is pretty close to the side of evil.

지나치게 긴 작업의 경우 작업도중 죽게 된다고하네요. 이럴경우 쓰레드로 빼서 구현해야 될것 같네요..