This is about memory-based IPC (like to LocalService example) but for two apps running in the same process:
I have two apps (App1
, App2
) and a shared project (Shared
) which defines some interfaces and abstract classes for both apps:
Shared (regular Java project, references android.jar)
- abstract myAbstractService
- Binder myBinder
App1 (Android Project, references Shared)
- MainActivity
App2 (Android Project, references Shared)
- myService extends myAbstractService
Both apps run within the same process (my.process
, defined in <application>
),
App2
publishes com.www.app2.myService
:
<-- Both Apps run in the same process -->
<manifest <!-- *snip* --> android:sharedUserId="my.shareduser">
<!-- ... -->
<application <!-- *snip* --> android:process="my.process">
<-- App2 exports the service -->
<service android:name="com.www.app2.myService" android:exported="true">
<intent-filter>
<action android:name="com.www.app2.myService" />
</intent-filter>
</service>
This is the abstract myAbstractService
(myService
doesn't add anything new yet):
abstract public class GameClient extends Service
{
private static final String LOGTAG = "GameClient";
private myBinder binder = new myBinder();
public IBinder onBind(Intent intent)
{
Log.d(LOGTAG, "onBind()");
return this.binder;
}
public class myBinder extends Binder
{
public void sendMessage()
{
Log.d(LOGTAG, "sendMessage()");
}
}
}
When I try to bind to myService
(App2) from my MainActivity
(App1):
public void onServiceConnected(ComponentName name, IBinder service)
{
Log.d("MS", service.getClass().toString());
main.this.t = (myBinder) service; // Exception in this line of course
}
I get an exception:
DEBUG/MS(5464): class com.www.shared.myBinder
ERROR/AndroidRuntime(5464): java.lang.ClassCastException: com.www.shared.myBinder
As both apps run in the same process, memory-coupled communication should work (at least I thought). I really don't want to use the message-based or broadcast-based communication as I'll send quite some messages around.
I suspect this exception happens due two different classloaders being used for the same class? Is this approach simply not possible/wrong or am I missing something?
Update:
My aim is to write a very modular application, where App1 is used as a delegating and starting application of other modules (apps). As I don't want to ship App1
with every app depending on it, I made it it's own app.
Let's say I have a third app (App3, Android project). App2 & App3 are both started by App1 (responsible for setting up connections while App2 & App3 provide different application logic (but having the same interface).
On a second thought I think this could be solved with an android library as well (App1 & Shared merged as the library with App2
and App3
starting an Activity of this library and waiting for the result)? However the data is not parcelable (network connections) and I have no idea how this library could be distributed independently over the android market (like App2
and App3
are published there but ask for the library to be installed too). Would this resolve that problem at all?
You are correct, you receive this exception because there are two class loaders involved.
I've added next two lines of code:
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
...
Log.e(TAG, "Expected class loader: "+myBinder.class.getClass().getClassLoader());
Log.e(TAG, "Class loader: "+service.getClass().getClassLoader());
...
}
And received these logs:
Expected class loader: java.lang.BootClassLoader@4001bdb0
Class loader: dalvik.system.PathClassLoader[/data/app/com.inazaruk.shared.service-2.apk]
From logs its clear that another class loader was used. This actually makes sense, as you could've installed App1
application one week later with different version of myBinder
class (or any other class that is passed via myBinder
interface directly or indirectly).
Updated:
You should stick with Android Libraries in your scenario. Note that Android Libraries are directly embedded in the application that references them. They are not distributed separately. Here is my post explaining how Android Libraries are different from simple jars, and other relevant nuances.
You still have a high degree of modularity in Android Library, as final Android Application only includes modules it uses. But this is compile-time modularity, not runtime modularity.
There are some issues with Android Libraries though:
AndroidManifest.xml
into Android Application's AndroidManifest.xml
.The #1 is planned to be fixed soon (according to Build Support roadmap ). The #2 and #3 might get fixed in next release of SDK platform tools.