三。实现 aidl 步骤
新建 aidl 文件,添加自己的接口,sayHello,这个方法返回的是基础数据类型,sayMsg返回的是 HMessage 类型,需要先用 Parcelable 方式实现序列化。aidl 中引用了自定义类型的时候需要在头部导入该类。 ``` // IRemoteService.aidl package com.chris_jason.pluginlibrary; //这里导入自定义类型,不然 aidl 文件会构建失败 import com.chris_jason.pluginlibrary.HMessage; interface IRemoteService { void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); String sayHello(); HMessage sayMsg(); } ```编写 Service 类,实现 aidl 接口中的方法
package com.chris_jason.pluginlibrary; import android.app.Service; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.support.annotation.Nullable; import android.util.Log; /** * Created by mayikang on 17/8/31. */ public class RemoteService extends Service { private String TAG="RemoteService"; @Nullable @Override public IBinder onBind(Intent intent) { Log.e(TAG,"onBind"); //这里代理了 binder return mBinder; } @Override public void onCreate() { Log.e(TAG,"onCreate"); super.onCreate(); } @Override public void unbindService(ServiceConnection conn) { Log.e(TAG,"unbindService"); super.unbindService(conn); } @Override public boolean onUnbind(Intent intent) { Log.e(TAG,"onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.e(TAG,"onDestroy"); super.onDestroy(); } //在这里实例化了 aidl 接口,返回一个自定义的 binder public IRemoteService.Stub mBinder=new IRemoteService.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public String sayHello() throws RemoteException { return "hello-aidl"; } @Override public HMessage sayMsg() throws RemoteException { HMessage msg=new HMessage(); msg.setContent("AIDL-MSG"); msg.setPid(Process.myPid()); return msg; } }; }在 manifest 中注册该 service,并且为该 service 开启了一个新的进程:remote,exported:true 表示在其他进程中允许调用该组件,intent 中的 action 是用来过滤请求的 “`
package com.chris_jason.pluginlibrary; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import com.sctjsj.basemodule.base.ui.act.BaseAppcompatActivity; public class MainActivity extends BaseAppcompatActivity { private IRemoteService remoteService; private String TAG="MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); findViewById(R.id.say).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(); intent.setPackage("com.chris_jason.pluginlibrary"); intent.setAction("com.chris_jason.pluginlibrary.RemoteService"); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } }); findViewById(R.id.disconnect).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(mServiceConnection!=null ){ try{ unbindService(mServiceConnection); }catch (Exception e){ Log.e("excep",e.toString()); } } } }); } @Override public int initLayout() { return R.layout.activity_main; } @Override public void reloadData() { } ServiceConnection mServiceConnection=new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.e(TAG,"onServiceConnected"); remoteService=IRemoteService.Stub.asInterface(service); try { String str=remoteService.sayHello(); HMessage msg=remoteService.sayMsg(); Log.e(TAG,str); Log.e(TAG,msg.toString()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG,"onServiceDisconnected"); } }; }在 logcat 可以看到输出结果,日志会在不同的进程中输出,证明了这次通信是在两个进程之间进行通信的
四。除了这种玩法,还可以在一个工程中建两个 module,并且都指定为 android 工程,而不是 library,这种场景就像 apk1调用 apk2一样。Service 和 Client 的区别在于 Client 中没有 Service 类,Service 的实现 aidl 接口还是在服务端中,其他没有区别。
五。在 Service 和 Client两端进行通信的时候,如果有自定义类型的数据,aidl 文件夹中必须包含和该类同名的 aidl 文件,并且要在使用了该类的aidl 文件中手动导入该类,而且必须要保证两个端中该类的包结构和类名一致,不然会找不到该类