###简介

AIDL适用于跨进程的通信,以下实现了跨APP通信的功能,包括服务端和客户端。

其中服务端提供AIDL服务访问的接口,客户端根据这个接口去访问服务,获取信息。

源代码的地址:

经过测试,程序在谷歌平板上能够正确的运行,但是在魅族手机上无法连接到服务。

###实现

####1.服务端

1)新建项目AIDL_Server,并在main文件夹下创建aidl文件,新建ICat.aidl文件

iOS 应用程序间通信 app之间的通信支持_iOS 应用程序间通信

其中ICat.aidl代码如下

interface ICat {

    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    String getColor();
    double getWeight();
}

2)build project,项目会自动根据AIDL文件生成对应的Java文件。
其中,生成ICat.java 类当中会包含一个Stub的内部类,它是Binder和ICat的子类。

3)创建CatServer
当有客户端来连接的时候,会调用onBind()函数,这时候返回一个mBinder对象,它是Stub的实例,包含了服务端返回给客户端的消息。

public class CatServer extends Service{

    private String tag = "CatServer";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(tag,"开启CatServer服务");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(tag,"销毁CatServer服务");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }


    private Binder mBinder = new ICat.Stub() {
        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public String getColor() throws RemoteException {
            return "红色";
        }

        @Override
        public double getWeight() throws RemoteException {
            return 5;
        }
    };
}

4)在AndroidManifest.xml文件当中注册Service
其中设置process属性,能够允许远程访问服务;action属性,指定访问的服务。

<service
            android:name=".CatServer"
            android:process=":remote">
            <intent-filter>
                <action android:name="com.example.huangbei.aidl_server.CatServer"/>
            </intent-filter>
        </service>

这样,服务端的工作就完成了,不需要有界面,也不需要手动去开启关闭服务。

####2.客户端

1)新建项目AIDL_Client

并将服务端的AIDL文件夹复制到客户端对应的位置,也可以自己新建,但是要保证包名和aidl文件一致,否则访问会出现异常。

服务端的aidl路径:

iOS 应用程序间通信 app之间的通信支持_iOS 应用程序间通信_02


客户端的aidl路径:

iOS 应用程序间通信 app之间的通信支持_服务端_03

2)build project
同样,这时候build project会自动生成ICat.java文件。

3)服务连接监听
当服务连接成功之后,服务端返回的IBinder对象,我们可以将其转化为ICat对象,这样就可以获取到我们想要的信息了。

private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.i(tag,"连接成功!");
            ICat cat = ICat.Stub.asInterface(iBinder);
            try{
                String color = cat.getColor();
                double weight = cat.getWeight();
                Log.i(tag,color+","+weight);
            }catch(Exception e){
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
           Log.i(tag,"断开连接");
        }
    };

4)访问服务
Android5.0之后,不能再使用隐式的intent,可以使用createExplicitFromImplicitIntent函数,将其转化为显式的intent。

@Override
    public void onClick(View view) {
        if(get_server_btn == view){
            Log.i(tag,"获取服务");
            Intent intent = new Intent("com.example.huangbei.aidl_server.CatServer");
            final Intent eintent = new Intent(createExplicitFromImplicitIntent(this,intent));
            bindService(eintent,mConnection, Service.BIND_AUTO_CREATE);
        }
    }

//将隐式intent转化为显式的intent
    public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
        // Retrieve all services that can match the given intent
        PackageManager pm = context.getPackageManager();
        List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);

        // Make sure only one match was found
        if (resolveInfo == null || resolveInfo.size() != 1) {
            return null;
        }

        // Get component info and create ComponentName
        ResolveInfo serviceInfo = resolveInfo.get(0);
        String packageName = serviceInfo.serviceInfo.packageName;
        String className = serviceInfo.serviceInfo.name;
        ComponentName component = new ComponentName(packageName, className);

        // Create a new intent. Use the old one for extras and such reuse
        Intent explicitIntent = new Intent(implicitIntent);

        // Set the component to be explicit
        explicitIntent.setComponent(component);

        return explicitIntent;
    }

访问结果如下:

iOS 应用程序间通信 app之间的通信支持_ci_04

###总结
学习AIDL让我想到,如果有流氓软件A和B,A开启一个AIDL服务。然后当B启动的时候,去访问这个服务,当A收到访问服务的请求之后,打开自己的后台服务,并返回。这样用户只想要开启一个APP,结果相当于开启了两个。