来自其他应用程序但相同的用户ID/进程的bindService

发布于 2024-11-19 07:31:51 字数 2875 浏览 3 评论 0原文

这是关于基于内存的 IPC(类似于 LocalService例如),但对于在同一进程中运行的两个应用程序:

我有两个应用程序(App1App2)和一个共享项目(Shared),为两个应用程序定义了一些接口和抽象类:

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

两个应用程序都在同一进程中运行(my.process,在 中定义), App2 发布 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>

这是抽象的 myAbstractServicemyService 不添加任何内容新的):

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()");
        }
    }
 }

当我尝试从我的 MainActivity (App1) 绑定到 myService (App2) 时:

public void onServiceConnected(ComponentName name, IBinder service) 
{
    Log.d("MS", service.getClass().toString());
    main.this.t = (myBinder) service; // Exception in this line of course
}

我收到一个异常:

DEBUG/MS(5464):类 com.www.shared.myBinder
错误/AndroidRuntime(5464): java.lang.ClassCastException: com.www.shared.myBinder

由于两个应用程序在同一进程中运行,内存耦合通信应该可以工作(至少我认为)。我真的不想使用基于消息或基于广播的通信,因为我会发送相当多的消息。
我怀疑这个异常是由于同一个类使用两个不同的类加载器而发生的?这种方法根本不可能/错误,还是我错过了一些东西?

更新:
我的目标是编写一个非常模块化的应用程序,其中 App1 用作其他模块(应用程序)的委托和启动应用程序。由于我不想将 App1 与每个依赖于它的应用程序一起发送,因此我将其设为自己的应用程序。

假设我有第三个应用程序(App3,Android 项目)。应用程序2 & App3 都是由 App1 启动的(负责建立连接,而 App2 和 App3 提供不同的应用程序逻辑(但具有相同的界面)。

再一想,我认为这也可以通过 Android 库来解决(App1 和共享)与 App2App3 合并为库,启动该库的活动并等待结果)但是数据不可分割(网络连接),我不知道这个图书馆怎么能在 android 市场上独立分发(例如 App2App3 在那里发布,但也要求安装该库)。

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

失与倦" 2024-11-26 07:31:51

您是对的,您收到此异常是因为涉及两个类加载器。

我添加了接下来的两行代码:

@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());
    ...
}

并收到了这些日志:

Expected class loader: java.lang.BootClassLoader@4001bdb0
Class loader: dalvik.system.PathClassLoader[/data/app/com.inazaruk.shared.service-2.apk]

从日志中可以清楚地看出使用了另一个类加载器。这实际上是有道理的,因为您可以在一周后使用不同版本的 myBinder 类(或通过 myBinder< 传递的任何其他类)安装 App1 应用程序/code> 直接或间接接口)。



更新
在您的场景中,您应该坚持使用 Android 库。请注意,Android 库直接嵌入到引用它们的应用程序中。它们不单独分发。 这是我的帖子解释 Android 库与简单 jar 的不同之处,以及其他相关的细微差别。

Android 库仍然具有高度的模块化,因为最终的 Android 应用程序仅包含它使用的模块。但这是编译时模块化,而不是运行时模块化。

不过,Android 库存在一些问题:

  1. 您需要将库的 AndroidManifest.xml 中的所有组件声明复制到 Android 应用程序的 AndroidManifest.xml 中。
  2. 目前库不支持自定义 xml 属性(请参阅我的帖子 此处此处< /a>)。
  3. 目前库不支持资源(请参阅我的帖子此处< /a>)。

#1 计划很快修复(根据构建支持路线图)。 #2 和 #3 可能会在下一版本的 SDK 平台工具中得到修复。

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:

  1. You need to copy all components' declarations in library's AndroidManifest.xml into Android Application's AndroidManifest.xml.
  2. Currently libraries do not support custom xml attributes (see my posts here and here).
  3. Currently libraries do not support assets (see my post here).

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.

春花秋月 2024-11-26 07:31:51

不久前我自己尝试过:类似的问题之前曾在 ClassCastException 中提出过从另一个 Activity 绑定到本地服务时https://stackoverflow.com/questions/3162538/2- apks-running-in-1-process-sharing-code-and-data。最终结果几乎相同:由于类加载器层次结构的性质(类似于 J2EE 类加载器的拆分方式),共享过程与共享代码不同。

这些类来自不同的 DEX 文件,因此从技术上讲,即使接口相同,这些类也是不同的。我不相信你想做的事情是可能的:我在你的未来看到了 AIDL。

Tried this myself a while back: similar questions were previously asked at ClassCastException when binding to local service from another Activity and https://stackoverflow.com/questions/3162538/2-apks-running-in-1-process-sharing-code-and-data. The end result is pretty much the same: sharing process is NOT the same as sharing code because of the nature of the class loader hierarchy (similar to how J2EE class loaders are split).

The classes are coming from different DEX files so technically speaking the classes are different, even if the interfaces are the same. I don't believe what you want to do is possible: I see AIDL in your future.

深巷少女 2024-11-26 07:31:51

您在命名空间“com.www.shared”中有一个名为“myBinder”的类吗?因为这就是它正在寻找的东西,但说不存在。我看到你有这个类,但它在哪个命名空间中?

Do you have a class called "myBinder" in the namespace "com.www.shared"? Because that is what it is looking for and saying isn't there. I see you have the class but what namespace is it in?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文