【问题标题】:bindService() in client app fails when trying to do IPC with another app尝试与另一个应用程序进行 IPC 时,客户端应用程序中的 bindService() 失败
【发布时间】:2017-01-02 21:55:25
【问题描述】:

我想获得一些使用 AIDL 的 android IPC 的经验。我想看看是否可以在两个不同的 Android 应用程序之间进行通信。

我的问题是在第二个应用程序中调用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>
      

    • 第一个应用程序包含一个启动器活动,它简单地启动服务:

          @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 失败了。确实,每次我暂停应用程序并返回它或启动它时。 “绑定我们的服务失败!!!”显示出来。

请注意,这两个应用共享一个包含所需aidl 文件定义的Android 库模块。

您是否看到任何可以让bindService() 工作的东西?

【问题讨论】:

    标签: android aidl


    【解决方案1】:

    您为什么使用 super.bindservice() ?相反,你可以试试这个getApplicationContext().bindservice()

    另外,如果这也不起作用,请尝试对您的代码进行以下修改:

       Intent i = new Intent("com.example.simonlbc.factorialservice.FactorialService");
       if(getApplicationContext().startService(i) != null){
           if (!getApplicationContext().bindService(i, serviceConnection, 0))
               Log.w(TAG, "Failed to bind our service!!!");
       }
    

    其中seriveConnection 是服务连接的对象(我不喜欢将this 用于ServiceConnection)。此外,您的服务应设置正确的Action,否则将无法启动

    【讨论】:

    • 谢谢,把thisgetApplicationContext 帮助。我仍然需要 i.setPackage("com.example.simonlbc.factorialService") 否则我会得到这个 RuntimeError:Service Intent must be explicit。在这一点上,我也打错了!我在i.setPackage 中写了com.example.simonlbc 而不是com.example.simonlbc.factorialService。这将指向第一个应用中服务的父包,而不是第一个应用中服务的确切包。
    • 另外,似乎只需要添加if(getApplicationContext().startService(i) != null){ 我没有同时运行这两个应用程序。但是很高兴看到如果我不运行“服务”应用程序,“客户端”应用程序似乎能够运行服务!如果这两个应用程序同时运行,客户端应用程序能够与“服务”应用程序中已经运行的服务进行通信。
    • 给我自己或其他可能其他人的另一条笔记。我曾犹豫是否将以下标签放在 旁边的服务应用程序清单中:`android:enabled="true" android:exported="true" android:process=":remote"`exported 已经默认为true 这使得该服务可以从应用程序外部使用。来自docandroid:process=":remote" 对我来说毫无用处(我认为这是说该服务在应用程序之外可用,但事实并非如此)。 enabled 默认为真。
    • 还有 Ankur Aggarwal bindService 中的 0 标志是什么?
    • @Simonlbc 对0 的解释:stackoverflow.com/questions/14746245/…
    猜你喜欢
    • 1970-01-01
    • 2020-01-11
    • 2014-05-06
    • 1970-01-01
    • 2014-11-02
    • 2010-09-23
    • 2021-08-28
    • 2021-12-02
    • 1970-01-01
    相关资源
    最近更新 更多