Я хотел получить некоторый опыт использования android IPC с помощью AIDL. Я хотел посмотреть, можно ли общаться между двумя отдельными приложениями для Android.bindService() в клиентском приложении терпит неудачу при попытке сделать IPC с другим приложением
Моя проблема заключается в том, что при вызове bindService
во втором приложении для связи с первым приложением FactorialService
служба всегда терпит неудачу. Моя первая активность приложения MainActivity
, которая пытается позвонить bindService
, всегда регистрирует тот факт, что bindService
возвращает false
. Плюс MainActivity
(который реализует ServiceConnection
) этого второго приложения (клиентское приложение) никогда не получает вызываемый метод обратного вызова onServiceConnected
.
Так, в первого приложения который проходит службу под названием FactorialService
Я определил
интерфейс,IFactorialService.aidl
:package com.simonlbc.factorialcommon; import com.simonlbc.factorialcommon.FactorialRequest; import com.simonlbc.factorialcommon.FactorialResponse; interface IFactorialService { FactorialResponse fact(in FactorialRequest r); }
FactorialRequest
содержит номер входа (n). fact
возвращает n!
вместе с другой информацией.
В одном приложении я создал класс
IFactorialServiceImplem
реализующий что aidl интерфейс.package com.example.simonlbc.factorialservice; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.SystemClock; import com.simonlbc.factorialcommon.FactorialResponse; import com.simonlbc.factorialcommon.FactorialRequest; public class IFactorialServiceImplem extends com.simonlbc.factorialcommon.IFactorialService.Stub { public long recursiveFact(int n) { if (n < 0) throw new IllegalArgumentException("input fa"); if (n == 1 || n == 0) return 1; else { return n * recursiveFact(n-1); } } public long iterativeFact(int n) { long res = 1; for (int i = 1; i <= n; i++) res *= i; return res; } public FactorialResponse fact(FactorialRequest r) { long timeInMillis = SystemClock.uptimeMillis(); long result = 0; switch(r.getChoice()) { case RECURSIVE: result = recursiveFact(r.getInNb()); break; case ITERATIVE: result = iterativeFact(r.getInNb()); } timeInMillis = SystemClock.uptimeMillis() - timeInMillis; return new FactorialResponse(result, timeInMillis); } }
Затем я создал
Service
, который будет использоваться для связи сIFactorialService
экземпляра возможных клиентов:package com.example.simonlbc.factorialservice; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; import com.simonlbc.factorialcommon.IFactorialService; public class FactorialService extends Service { private IFactorialServiceImplem s = null; private static final String TAG = "FactorialService"; @Override public void onCreate() { super.onCreate(); s = new IFactorialServiceImplem(); Log.d(TAG, "onCreate'd"); } @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind()'d"); return this.s; } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "onUnbind()'d"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.d(TAG, "onDestroy()'d"); s = null; super.onDestroy(); } }
- манифест этой первой «сервис» приложение является следующее:
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <service android:name=".FactorialService"> <!-- android:enabled="true" android:exported="true" android:process=":remote" --> <intent-filter> <action android:name="com.example.simonlbc.factorialservice.FactorialService" /> </intent-filter> </service> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>
первое приложение содержит деятельность Launcher, который просто запускает услугу, как так:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_service); curPackage = getString(R.string.packageService); MainActivity.this.startService( new Intent() .setAction(curPackage + ".FactorialService") .setPackage(curPackage) ); }
Мой второй пусковой активности приложений «ы такой как:
public class MainActivity extends Activity implements View.OnClickListener, ServiceConnection
Я хочу
MainActivity
этого второго приложения к
общаться с первым приложениемIFactorialService
-х. В onResume я пытаются связать с обслуживанием первого приложения:@Override protected void onResume() { super.onResume(); Intent i = new Intent(); i.setAction("com.example.simonlbc.factorialservice.FactorialService"); i.setPackage("com.example.simonlbc"); if (!super.bindService(i, this, BIND_AUTO_CREATE)) Log.w(TAG, "Failed to bind our service!!!"); }
Но, похоже bindService
терпит неудачу. Действительно каждый раз, когда я приостанавливаю приложение и возвращаюсь к нему, или начинаю его. «Не удалось связать наш сервис !!!» отображается.
Обратите внимание, что два приложения совместно используют модуль библиотеки Android, содержащий определения необходимых файлов помощи.
Вы видите что-нибудь, что позволило бы bindService()
работать?
Спасибо, положил 'this' или' getApplicationContext'. Мне все еще нужен i.setPackage («com.example.simonlbc.factorialService»), иначе я бы получил это RuntimeError: «Назначение службы должно быть явным». В этот момент я тоже сделал опечатку! Вместо 'com.example.simonlbc.factorialService' я написал' com.example.simonlbc' в 'i.setPackage'.Это указывает на родительский пакет службы в первом приложении, а не на точный пакет службы в первом приложении. – Simonlbc
Также кажется, что добавление 'if (getApplicationContext(). StartService (i)! = Null) {' необходимо только. У меня нет двух приложений, работающих одновременно. Но очень приятно видеть, что если я не запускаю приложение «Сервис», приложение «Клиент», похоже, сможет запустить службу! И если оба приложения работают одновременно, клиентское приложение может общаться с уже запущенной службой в приложении «Сервис». – Simonlbc
Еще одно примечание для меня или других, возможно, других людей. Я не решался помещать следующие теги в манифест приложения Service рядом с: 'android: enabled =" true " android: exported =" true " android: process =": remote "' 'exported' уже defaulted to true, что делает услугу полезной извне приложения. 'android: process =": remote "' из [doc] (https://developer.android.com/guide/topics/manifest/service-element.html) бесполезен для меня (я думал, что это говорит о том, что сервис был полезен вне приложения, это не так). По умолчанию значение 'enabled' равно true. –
Simonlbc