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

Posted

技术标签:

【中文标题】bindService 来自其他应用程序但相同的用户 ID/进程【英文标题】:bindService from other app but same userid/process 【发布时间】:2011-07-08 21:34:46 【问题描述】:

这是关于基于内存的 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,在<application> 中定义), 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>

这是myAbstractService 的摘要(myService 还没有添加任何新内容):

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

我得到一个例外:

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

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

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

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

再想一想,我认为这也可以通过 android 库来解决(App1 和 Shared 合并为库,App2App3 启动该库的 Activity 并等待结果)?但是数据是不可打包的(网络连接),我不知道这个库如何在 android 市场上独立分布(比如 App2App3 在那里发布,但也要求安装该库)。这能解决这个问题吗?

【问题讨论】:

【参考方案1】:

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

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

@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 应用程序。



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

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

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

    您需要将库的AndroidManifest.xml 中所有组件的声明复制到Android 应用程序的AndroidManifest.xml 中。 目前库不支持自定义 xml 属性(请参阅我的帖子 here 和 here)。 目前库不支持资产(参见我的帖子here)。

#1 计划很快修复(根据Build Support roadmap)。 #2 和 #3 可能会在下一版本的 SDK 平台工具中得到修复。

【讨论】:

感谢您的澄清。我为可能的解决方法添加了更多详细信息。另一个想法是在运行时从另一个包(DexClassLoader)加载类。但我想这也行不通。 谢谢 :) 这意味着我想我不能再将以前的 App1 用作启动应用程序(除了 App2 启动 App1 之外,它可以启动 App3(再次启动 App1 以返回 App3)完成)并且我以前的 App1 将与每个应用程序(或模块,可能导致它的两个不同版本)一起部署? 您将不再拥有 App1、App2 和 App3。您将拥有 Lib1 和 Lib2,并将创建使用 Lib1 和 Lib2 的 AppX。因此,您将发布虚拟的应用程序 (Lib1+Lib2+AppX)。如果您决定创建使用 Lib2 的 AppY,您将获得虚拟 (Lib2+AppY) 的应用程序。希望我正确理解了您的问题。 啊。我希望它反过来:就像 App1 是必备组件,而 App2/App3 是 App1 的可选(稍后可安装)扩展。在我的例子中,App1 初始化一些网络连接并将它们交给用户选择的(取决于安装的应用程序)应用程序(如 App2、App3)。 App2,3 用这些连接做一些花哨(但不同)的事情。但这取决于用户他想要的功能(通过安装相应的应用程序来决定)。因此,在编译时我不知道终端系统有哪些可用。 因此您基本上需要动态时间模块化(类似于插件)。 Android 目前不支持这个,除了远程绑定的服务、内容提供者、活动和广播。换句话说,您需要序列化和反序列化要在不同包(应用程序)的组件之间交换的数据。【参考方案2】:

不久前我自己尝试过:之前在 ClassCastException when binding to local service from another Activity 和 https://***.com/questions/3162538/2-apks-running-in-1-process-sharing-code-and-data 上提出过类似的问题。最终结果几乎相同:共享过程与共享代码不同,因为类加载器层次结构的性质(类似于 J2EE 类加载器的拆分方式)。

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

【讨论】:

在mylifewithandroid.blogspot.com/2009/06/… 上写了一篇较长的文章(从过去开始),基本上捕捉到了相同的论点。 感谢您的文献 :) 已经知道您评论中的链接(给了我使用 sharedProcess 的提示)。请参阅我的评论@inazaruk 答案以了解可能的“解决方法?” :)【参考方案3】:

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

【讨论】:

当然(位于共享项目中)。否则项目将无法编译。 已编辑以反映我的意思...抱歉。 myBinder 和 myAbstractService 都在 com.www.shared 中,由我的 MainActivity(App1,命名空间 com.www.app1)和 myService(App2,命名空间 com.www.app2)导入跨度>

以上是关于bindService 来自其他应用程序但相同的用户 ID/进程的主要内容,如果未能解决你的问题,请参考以下文章

Android - 调用 bindservice 但无法访问该服务中的任何方法

深入理解Android的startservice和bindservice

深入理解Android的startservice和bindservice

理解Android的startservice和bindservice(转)

Liferay,来自搜索的 Freemarker 错误模板,但不是来自其他链接

跨app执行bindservice