bindService из другого приложения, но тот же идентификатор пользователя / процесс

Речь идет о IPC на основе памяти (как в примере с LocalService), но для двух приложений, работающих в одном процессе:

У меня есть два приложения (App1, App2) и общий проект (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()");
        }
    }
 }

Когда я пытаюсь связать с myService (App2) из ​​моего 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
}

Я получаю исключение:

DEBUG / 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 объединены в библиотеку с App2 а также App3 запуск Activity из этой библиотеки и ожидание результата)? Однако данные не могут быть отправлены (сетевые подключения), и я понятия не имею, как эта библиотека может распространяться независимо на рынке Android (например, App2 а также App3 там публикуются, но просят установить библиотеку тоже). Это решило бы эту проблему вообще?

3 ответа

Решение

Вы правы, вы получаете это исключение, потому что задействованы два загрузчика классов.

Я добавил следующие две строки кода:

@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]

Из журналов ясно, что был использован другой загрузчик классов. Это на самом деле имеет смысл, как вы могли бы установить App1 приложение через неделю с другой версией myBinder класс (или любой другой класс, который передается через myBinder интерфейс прямо или косвенно).



Обновлено:
Вы должны придерживаться библиотек Android в вашем сценарии. Обратите внимание, что библиотеки Android напрямую встроены в приложение, которое на них ссылается. Они не распространяются отдельно. Вот мой пост, объясняющий, как библиотеки Android отличаются от простых jar-файлов, и другие важные нюансы.

Вы по-прежнему имеете высокую степень модульности в библиотеке Android, поскольку окончательное приложение Android включает только модули, которые оно использует. Но это модульность во время компиляции, а не модульность во время выполнения.

Однако есть некоторые проблемы с библиотеками Android:

  1. Вам необходимо скопировать объявления всех компонентов в библиотеки AndroidManifest.xml в приложения для Android AndroidManifest.xml,
  2. В настоящее время библиотеки не поддерживают пользовательские атрибуты XML (см. Мои сообщения здесь и здесь).
  3. В настоящее время библиотеки не поддерживают ресурсы (см. Мой пост здесь).

#1 планируется исправить в ближайшее время (в соответствии с дорожной картой поддержки сборки). #2 и #3 могут быть исправлены в следующем выпуске инструментов платформы SDK.

Попробовал это сам некоторое время назад: подобные вопросы ранее задавались в ClassCastException при привязке к локальному сервису из другого Activity и https://stackru.com/questions/3162538/2-apks-running-in-1-process-sharing-code-and-data. Конечный результат в значительной степени тот же: процесс совместного использования НЕ похож на обмен кодом из-за природы иерархии загрузчиков классов (аналогично тому, как разделены загрузчики классов J2EE).

Классы происходят из разных файлов DEX, так что с технической точки зрения классы разные, даже если интерфейсы одинаковы. Я не верю, что то, что вы хотите сделать, возможно: я вижу AIDL в вашем будущем.

У вас есть класс myBinder в пространстве имен com.www.shared? Потому что это то, что он ищет и говорит, что там нет. Я вижу, у вас есть класс, но в каком пространстве имен он находится?

Другие вопросы по тегам