绑定到另一个应用程序的服务

我写了两个应用程序(目标姜饼)。 假设说app1和app2。 App1有两个以“BOOT_COMPLETED”开头的服务,它们以返回值START_STICKY开始。 他们在不同的线程中运行。 使长话短说。 其中一项服务是在串口(一种用于与串口另一端的接口进行通信的应用代理)上观察input数据。 另一个有一个监听者看一些系统状态,并等待来自其他应用程序的一些“指令”。 我知道他们运行良好,因为他们列在正在运行的服务,我添加了一些代码,迫使他们做一些东西,当一些特定的数据来自串行端口。

现在的问题:我写了app2。 它试图绑定到app1中的一个服务。 我使用了android-developper文档,并在app1和app2中的服务之间实现了双向通信。 由于我只有less量非常简单的数据发送,所以我使用了一个信使,就像build议的那样。 我基本上只是使用“什么,arg1和arg2”,我没有使用AIDL接口的文档build议。

这里是androidmanifest中声明app1中服务的部分,我也尝试绑定。

<service android:name=".ModemWatcherService" android:label="@string/app_name" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <!-- Service name --> <action android:name="com.admetric.modemwatcher.Service" /> </intent-filter> </service> 

那么,下面是在app1中处理这个问题的几个方法:

  @Override public IBinder onBind(Intent intent) { Log.d(TAG, "entering onBind"); return mMessenger.getBinder(); } /** * Handler of incoming messages from clients. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { String logMessage = "Received meaasge what= %d, arg1= %d, arg2= %d" + String.valueOf(msg.what) + String.valueOf(msg.arg1) + String.valueOf( msg.arg2); Log.d(TAG, logMessage); switch (msg.what) { case MSG_REGISTER_CLIENT: mClients.add(msg.replyTo); break; case MSG_UNREGISTER_CLIENT: mClients.remove(msg.replyTo); break; case ..... more code here for the application default: super.handleMessage(msg); } } } @Override public void onCreate() { mHandler = new Handler(); startSignalLevelListener(); Log.i(TAG, "Just did onCreated"); // Display a notification about us starting. We put an icon in the status bar. // showNotification(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "Received start id " + startId + ": " + intent); // We want this service to continue running until it is explicitly // stopped, so return sticky. return START_STICKY; } 

对于app2,下面是与双向通信build立绑定的相关代码:

 public final class ComWithIoMcu extends Service { private static final String TAG = "ComWithIoMcu"; /** Messenger for communicating with service. */ static Messenger mServiceMcu = null; /** Flag indicating whether we have called bind on the service. */ boolean mIsBound; /** * Command to the service to register a client, receiving callbacks * from the service. The Message's replyTo field must be a Messenger of * the client where callbacks should be sent. */ static final int MSG_REGISTER_CLIENT = 1; /** * Command to the service to unregister a client, ot stop receiving callbacks * from the service. The Message's replyTo field must be a Messenger of * the client as previously given with MSG_REGISTER_CLIENT. */ static final int MSG_UNREGISTER_CLIENT = 2; /** * Command to forward a string command to the I/O MCU */ public static final int MSG_SEND_STRING_TO_IOMCU = 3; /** List of supported commands * */ ...... more code .... /** * Handler of incoming messages from service. */ class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_UNSOL_MESSAGE: Log.d(TAG, "Received from service: " + msg.arg1); break; default: super.handleMessage(msg); } } } /** * Target we publish for clients to send messages to IncomingHandler. */ final Messenger mMessenger = new Messenger(new IncomingHandler()); boolean mBound; /** * Class for interacting with the main interface of the service. */ private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. We are communicating with our // service through an IDL interface, so get a client-side // representation of that from the raw service object. mServiceMcu = new Messenger(service); Log.d(TAG, "Attached."); // We want to monitor the service for as long as we are // connected to it. try { Message msg = Message.obtain(null, MSG_REGISTER_CLIENT); msg.replyTo = mMessenger; mServiceMcu.send(msg); } catch (RemoteException e) { // In this case the service has crashed before we could even // do anything with it; we can count on soon being // disconnected (and then reconnected if it can be restarted) // so there is no need to do anything here. Log.e(TAG, "ModemWatcherService is not running"); } } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. mServiceMcu = null; mBound = false; } }; void doBindService() { // Establish a connection with the service. We use an explicit // class name because there is no reason to be able to let other // applications replace our component. //bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE); try { Intent intentForMcuService = new Intent(); Log.d(TAG, "Before init intent.componentName"); intentForMcuService.setComponent(new ComponentName("com.admetric.modemwatcher", "ModemWatcherService")); Log.d(TAG, "Before bindService"); if (bindService(intentForMcuService, mConnection, 0)){ Log.d(TAG, "Binding to Modem Watcher returned true"); } else { Log.d(TAG, "Binding to Modem Watcher returned false"); } } catch (SecurityException e) { Log.e(TAG, "can't bind to ModemWatcherService, check permission in Manifest"); } mIsBound = true; Log.d(TAG, "Binding."); } void doUnbindService() { if (mIsBound) { // If we have received the service, and hence registered with // it, then now is the time to unregister. if (mServiceMcu != null) { try { Message msg = Message.obtain(null, MSG_UNREGISTER_CLIENT); msg.replyTo = mMessenger; mServiceMcu.send(msg); } catch (RemoteException e) { // There is nothing special we need to do if the service // has crashed. } } // Detach our existing connection. unbindService(mConnection); mIsBound = false; Log.d(TAG, "Unbinding."); } } 

看着正在运行的服务,我可以看到我在app2中创build的服务正在运行。 Logcat告诉我,我试图绑定ModemWatcherService,但没有find。 这里是logcat有趣的部分

 12-05 17:22:59.884 D/ComWithIoMcu( 547): Before init intent.componentName 12-05 17:22:59.884 D/ComWithIoMcu( 547): Before bindService 12-05 17:22:59.888 D/ComWithIoMcu( 547): Binding to Modem Watcher returned false 12-05 17:22:59.888 D/ComWithIoMcu( 547): Binding. 12-05 17:22:59.888 W/ActivityManager( 89): Unable to start service Intent { cmp=com.admetric.modemwatcher/ModemWatcherService }: not found 

我的第一个想法是,我错过了一个权限,但bindService()可以剔除安全exception,在这种情况下,它不这样做,我检查,并返回false为一个未知的原因。 另外,我知道在app1中,onBind永远不会被certificate绑定从未发生。 所以logcat消息“找不到”是有道理的,但是我宣称这个服务是公开的。 这可能是一个简单的错误,但我已经在这个问题上有一段时间了,我不明白为什么。 任何想法为什么app2无法在app1中find服务? 我只是用剪切和粘贴的名字,所以我不会在名字上做愚蠢的错误的错误。 我是否缺less某种权限? 我需要做一些额外的步骤来发布整个系统的服务吗? 这是我第一次尝试从另一个应用程序访问一个应用程序中的东西,所以我可能错过了一些东西。

Solutions Collecting From Web of "绑定到另一个应用程序的服务"

您的ComponentName构造不正确。 传入类名时必须是完全合格的,如下所示:

 intentForMcuService.setComponent(new ComponentName("com.admetric.modemwatcher", "com.admetric.modemwatcher.ModemWatcherService")); 

另一件事,如果你在应用程序边界之外引用一个Service ,最好不要使用ComponentName来引用它,即使它能正常工作。 更常见的方法是为您的Intent创build一个自定义的ACTIONstring,并让Service过滤该操作。