안녕하세요. 이번 포스팅에서는 Bound Service 를 사용하여 2개의 앱이 서로 상호작용 하는 방법을 포스팅하겠습니다.
Bound Service는 4대 컴포넌트 중 하나인 Service 사용을 기본으로 하며 aidl 이라는 파일 형식으로 된 코드를 2개의 앱에 동일하게 추가하여 해당 함수들을 호출하여 연결하여 상호작용 하는 방식입니다.
아래 구조도와 함께 간단히 구조를 먼저 설명 드리겠습니다.
1. 구조도

사용자에게 보여지는 앱의 실행중인 Activity 와 Background에서 기능을 동작할 앱의 Service 그리고 aidl을 통한 IService 와 ICallback 이렇게 최소 4개의 Class가 필요하게 됩니다.
Activity는 Iservice를 통해 연결되어 ICallback을 통해 값을 가져와 UI 갱신 혹은 값을 가져와 사용할 수 있게 됩니다.
Service는 IService를 통해 트리거 역할이 되어 Activity 에서 특정 동작을 했을때를 감지할 수 있으며 ICallback을 통해 전달 할 값을 넣어 보낼수있습니다.
이 2개의 앱의 연결다리가 되는 aidl 파일인 IService와 ICallback은 두 앱의 프로젝트에 동일한 코드로 짜여져 있어야만 정상적으로 동작하게 됩니다. 각 항목별로 보자면 아래와 같습니다.
2. 수신 받는 activity 의 service 및 callback 사용
먼저 ICallback을 선언하여 수신받은 정보를 처리할 수 있습니다. 이때 aidl의 내부 함수를 가져오기 위해서 Stub()를 사용하여 컴파일러가 읽을수있도록 합니다.
이후 aidl의 ICallback 내부 함수를 Override하여 가져옵니다. 이때 예외 처리로 RemoteException을 통해 연결이 안될경우에 대한 try catch를 대응해야합니다. 이후 처리 방식에 따라 주로 UI 갱신일 경우 runOnUiThread를 사용하여 mainThread 관련 오류를 방지합니다.
그 아래 serviceConnection 을 통해 connected 와 Disconnected에 대한 처리를 추가합니다.
private IService monitorService;
private boolean isServiceBind = false;
private final ICallBack callback = new ICallBack.Stub() {
@Override
public void onStatusChanged(String result) throws RemoteException {
runOnUiThread(new Runnable() {
@Override
public void run() {
}
});
}
};
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isServiceBind = true;
monitorService = IDoorSensorService.Stub.asInterface(service);
try {
monitorService.registerCallback(callback);
String current = monitorService.getCurrentStatus();
Log.d("Monitor", "현재 상태: " + current);
} catch (RemoteException e) {
Log.d("Monitor", "서비스 생성 실패");
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isServiceBind = false;
monitorService = null;
}
};
3. Background에서 동작하는 App의 service 코드
아래 코드는 Background에서 동작할 Service 내부에 포함되는 코드입니다. 여기서는 Activity에서 호출시 동작할 IService를 aidl파일이므로 마찬가지로 Stub() 로 생성합니다. 이후 연결시 callback 등록을 위한 registerCallback과 해제를 위한 unRegisterCallback을 선언합니다. 그리고 Background에서 동작하므로 onBind 및 onUnbind에 대해서 해제해야할 각종 동작에 대한 처리를 확실히 해줄 수 있도록 합니다. 그리고 값을 보내야할 경우 callback. 메소드를 통해 값을 전달하며 이때 RemoteException에 대한 try catch 문을 통해 대응할 수 있도록합니다.
private ICallBack callback;
private final IService.Stub binder = new IService.Stub() {
@Override
public String getCurrentStatus() throws RemoteException {
return "Success Connect";
}
@Override
public void registerCallback(ICallBack registerCallback) throws RemoteException {
callback = registerCallback;
}
@Override
public void unRegisterCallback(ICallBack unRegisterCallback) throws RemoteException {
callback = null;
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
private void sendResult(String result) {
try {
callback.onStatusChanged(result);
} catch (RemoteException e) {
e.printStackTrace();
}
}
4. aidl
aidl의 경우 별도 파일로 생성하게되며 아래와 같이 생성을 위해서는 gradle에서 buildFeatures 블록 내 aidl을 true로 설정해야 합니다.

이후 파일 생성시 아래와 같은 구조로 interface를 생성하여 사용합니다.
package android.example.aidl
import [위에 정의되지 않은 TYPE들]
interface IService{
void getCurrentStatus();
int [FUNCTION명]( [PARAMETERS] );
}
이상으로 두개의 앱을 상호작용하여 하나의 앱에서 기능을 사용하여 다른 앱은 ui만 보여주며 그 기능을 사용하는 BoundService 에 대해서 알아보았습니다.
이 기능을 통해 여러 앱이 설치되어있는 기기에서 특정 앱의 기능을 쓰고싶을때 사용하기 좋은 기능인것 같습니다.
긴글 읽어주셔서 감사합니다.
'안드로이드 > component' 카테고리의 다른 글
| [앱 상호작용]Broadcast Receiver를 사용하여 2개 앱 정보 전달 (0) | 2025.09.10 |
|---|