美文网首页
AndroidIPC跨进程通讯AIDL封装(三)

AndroidIPC跨进程通讯AIDL封装(三)

作者: 没有了遇见 | 来源:发表于2023-07-29 17:07 被阅读0次

    AIDL 实现了进程间的通讯,但是每个进程都需要复制AIDL文件以及封装对象,这样用起来很麻烦所以就想办法把通讯的过程封装成jar包 方便其他进程调用

    思路

    • 封装调用Sdk(服务连接管理,AIDL,监听,消息发送,消息接收)
    • SDK 生成Jar
    • 服务端引用Jar 通过jar中的AIDL文件创建服务
    • 客户端引用jar 传入服务端的包名,类名,Action 然后调用Jar中的方法开启服务
    • 服务端调用Jar中方法和服务端通讯

    1. 创建SDK

    sdk目录.png

    1.创建aidl文件

    1.1 创建 IShareDataInterface.aidl文件

    // IShareDataInterface.aidl
    package com.wu.ipc;
    
    import com.wu.ipc.IShareDataListener;
    //import com.wu.ipc.ShareDataInfo;
    
    // 服务连接的操作的主AIDL文件
    interface IShareDataInterface {
    //发送消息
        void sendShareData(int key, String values);
        //获取指定的消息
        String getShareData(int key) ;
        //注册消息监听
        void registerCallback(int id, IShareDataListener callback) ;
        //解绑消息监听
        void unregisterCallback(IShareDataListener callback) ;
    
    }
    

    1.2 创建 IShareDataListener.aidl

    package com.wu.ipc;
    
    // 消息变化的aidl 文件
    interface IShareDataListener {
        void notifyShareData(int key, String values);
    }
    
    

    2. 创建SDK

    2.1 创建Sdk基类

    package com.wu.ipc.base;
    
    import android.app.Application;
    import android.content.ComponentName;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Handler;
    import android.os.HandlerThread;
    import android.os.IBinder;
    import android.os.IInterface;
    import android.text.TextUtils;
    import com.wu.ipc.utils.Remote;
    import com.wu.ipc.utils.SdkAppGlobal;
    
    import java.util.concurrent.LinkedBlockingQueue;
    
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途:Sdk 基类封装
     */
    
    
    public abstract class Sdk<T extends IInterface> {
        private T mProxy;
        private Application mApplication;
        private static final String THREAD_NAME = "bindServiceThread";
        private Handler mChildThread;
        private final Runnable mBindServiceTask = this::bindService;
        private final LinkedBlockingQueue<Runnable> mTaskQueue = new LinkedBlockingQueue();
        private final ServiceConnection mServiceConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName name, IBinder service) {
                Sdk.this.mProxy = Sdk.this.asInterface(service);
                Remote.tryExec(() -> {
                    if (service != null) {
                        service.linkToDeath(Sdk.this.mDeathRecipient, 0);
                    }
    
                });
                if (Sdk.this.mServiceStateListener != null) {
                    Sdk.this.mServiceStateListener.onServiceConnected();
                }
    
                Sdk.this.handleTask();
                Sdk.this.mChildThread.removeCallbacks(Sdk.this.mBindServiceTask);
            }
    
            public void onServiceDisconnected(ComponentName name) {
                Sdk.this.mProxy = null;
                if (Sdk.this.mServiceStateListener != null) {
                    Sdk.this.mServiceStateListener.onServiceDisconnected();
                }
    
            }
        };
        private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
            public void binderDied() {
                if (Sdk.this.mServiceStateListener != null) {
                    Sdk.this.mServiceStateListener.onBinderDied();
                }
    
                if (Sdk.this.mProxy != null) {
                    Sdk.this.mProxy.asBinder().unlinkToDeath(Sdk.this.mDeathRecipient, 0);
                    Sdk.this.mProxy = null;
                }
    
                Sdk.this.toRebindService();
            }
        };
        ShareDataServiceStateListener mServiceStateListener;
        //    service Name
        String pageName;
        //Service ClassName
        String className;
        //    Service Action
        String action;
        //断开连接 重连的时间
        long mRetryBindTimeMillTime = 2000;
    
        public void init(String pageName, String className, String action, long mRetryBindTimeMillTime) {
            if (mApplication == null) {
                this.mApplication = SdkAppGlobal.getApplication();
                HandlerThread thread = new HandlerThread("bindServiceThread", 6);
                thread.start();
                this.mChildThread = new Handler(thread.getLooper());
                this.pageName = pageName;
                this.className = className;
                this.action = action;
                this.mRetryBindTimeMillTime = mRetryBindTimeMillTime;
            }
            if (!isServiceConnected()) {
                this.bindService();
            }
        }
    
    
        private void bindService() {
            if (TextUtils.isEmpty(pageName) || TextUtils.isEmpty(className)) return;
            if (this.mProxy == null) {
                ComponentName name = new ComponentName(pageName, className);
                Intent intent = new Intent();
                if (!TextUtils.isEmpty(action))
                    intent.setAction(action);
                intent.setComponent(name);
    //            if (Build.VERSION.SDK_INT >= 26) {
    //                this.mApplication.startForegroundService(intent);
    //            } else {
    //                this.mApplication.startService(intent);
    //            }
                boolean connected = this.mApplication.bindService(intent, this.mServiceConnection, mApplication.BIND_AUTO_CREATE);
                if (!connected) {
                    this.toRebindService();
                }
            }
    
        }
    
        protected void toRebindService() {
            if (this.mChildThread != null && this.mBindServiceTask != null) {
                this.mChildThread.postDelayed(this.mBindServiceTask, mRetryBindTimeMillTime);
            }
    
        }
    
        protected void handleTask() {
            Runnable task;
            while ((task = (Runnable) this.mTaskQueue.poll()) != null) {
                if (this.mChildThread != null) {
                    this.mChildThread.post(task);
                }
            }
    
        }
    
        protected T getProxy() {
            return this.mProxy;
        }
    
        protected LinkedBlockingQueue<Runnable> getTaskQueue() {
            return this.mTaskQueue;
        }
    
        public void addServiceStateListener(ShareDataServiceStateListener serviceStateListener) {
            this.mServiceStateListener = serviceStateListener;
        }
    
        public void removeServiceStateListener() {
            this.mServiceStateListener = null;
        }
    
        public void release() {
            if (this.isServiceConnected()) {
                if (this.mProxy != null) {
                    this.mProxy.asBinder().unlinkToDeath(this.mDeathRecipient, 0);
                }
    
                this.mProxy = null;
                if (this.mApplication != null) {
                    this.mApplication.unbindService(this.mServiceConnection);
                }
    
                this.mServiceStateListener = null;
            }
    
        }
    
        public boolean isServiceConnected() {
            return this.mProxy != null;
        }
    
        public void isRetryConnected() {
            this.toRebindService();
        }
    
        protected abstract T asInterface(IBinder service);
    
    
    }
    
    

    2.2 创建Sdk 调用类

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.wu.ipc;
    
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.text.TextUtils;
    
    import com.wu.ipc.base.Sdk;
    import com.wu.ipc.base.SdkInterface;
    import com.wu.ipc.listener.ShareDataListener;
    import com.wu.ipc.utils.Remote;
    
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途: 进程通讯操作的工具类
     */
    public class IpcSdk extends Sdk<IShareDataInterface> implements SdkInterface {
        private static IpcSdk instance;
        Set<ShareDataListener> listener = new HashSet();
        IShareDataListener.Stub mCallBackImpl = new IShareDataListener.Stub() {
            public void notifyShareData(int key, String values) {
                if (IpcSdk.this.listener != null) {
                    Iterator var3 = IpcSdk.this.listener.iterator();
    
                    while (var3.hasNext()) {
                        ShareDataListener shareDataListener = (ShareDataListener) var3.next();
                        shareDataListener.notifyShareData(key, values);
                    }
                }
    
            }
        };
    
    
        public static IpcSdk getInstance() {
            synchronized (IpcSdk.class) {
                if (instance == null) {
                    instance = new IpcSdk();
                }
            }
    
            return instance;
        }
    
        protected IShareDataInterface asInterface(IBinder service) {
            return IShareDataInterface.Stub.asInterface(service);
        }
    
        /**
         * 发送消息
         *
         * @param key
         * @param values
         */
        public void sendShareData(int key, String values) {
            Remote.exec(() -> {
                if (!TextUtils.isEmpty(values)) {
                    getProxy().sendShareData(key, values);
                    return true;
                } else {
                    return false;
                }
            });
        }
    
        /**
         * 指定ID 获取发送的消息
         *
         * @param key
         * @return
         */
        public String getShareData(int key) {
            try {
                return getProxy().getShareData(key);
            } catch (RemoteException var3) {
                var3.printStackTrace();
                return "";
            }
        }
    
        /**
         * 注册监听
         *
         * @param id≤
         * @param callback
         */
        public void registerCallback(int id, ShareDataListener callback) {
            Remote.exec(() -> {
                if (this.isServiceConnected()) {
                    this.listener.add(callback);
                    getProxy().registerCallback(id, this.mCallBackImpl);
                    return true;
                } else {
                    this.isRetryConnected();
                    this.getTaskQueue().offer(() -> {
                        this.registerCallback(id, callback);
                    });
                    return false;
                }
            });
        }
    
        /**
         * 解除监听
         *
         * @param callback
         */
        public void unregisterCallback(ShareDataListener callback) {
            if (this.listener != null) {
                this.listener.remove(callback);
            }
    
        }
    }
    
    

    2.3 其他工具类
    Application 工具类

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.wu.ipc.utils;
    
    import android.app.Application;
    import android.util.Log;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途: Application 工具类
     */
    public class SdkAppGlobal {
        public static final String TAG_SDK = "TAG_SDK";
        private static final String TAG = "TAG_SDK" + SdkAppGlobal.class.getSimpleName();
        public static final String CLASS_FOR_NAME = "android.app.ActivityThread";
        public static final String CURRENT_APPLICATION = "currentApplication";
        public static final String GET_INITIAL_APPLICATION = "getInitialApplication";
    
        private SdkAppGlobal() {
        }
    
        public static Application getApplication() {
            Application application = null;
    
            Class atClass;
            Method method;
            try {
                atClass = Class.forName("android.app.ActivityThread");
                method = atClass.getDeclaredMethod("currentApplication");
                method.setAccessible(true);
                application = (Application)method.invoke((Object)null);
            } catch (IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | ClassNotFoundException | IllegalAccessException var4) {
                Log.w(TAG, "getApplication: " + var4);
            }
    
            if (application != null) {
                return application;
            } else {
                try {
                    atClass = Class.forName("android.app.ActivityThread");
                    method = atClass.getDeclaredMethod("getInitialApplication");
                    method.setAccessible(true);
                    application = (Application)method.invoke((Object)null);
                } catch (IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | ClassNotFoundException | IllegalAccessException var3) {
                    Log.w(TAG, "getApplication: " + var3);
                }
    
                return application;
            }
        }
    }
    
    

    异常处理类

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by FernFlower decompiler)
    //
    
    package com.wu.ipc.utils;
    
    import android.os.RemoteException;
    import android.util.Log;
    
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途:异常处理类
     */
    public abstract class Remote {
        public Remote() {
        }
    
        public static <V> V exec(Remote.RemoteFunction<V> func) {
            try {
                return func.call();
            } catch (RemoteException var2) {
                throw new IllegalArgumentException("Failed to execute remote call" + var2);
            }
        }
    
        public static void tryExec(Remote.RemoteVoidFunction func) {
            try {
                func.call();
            } catch (RemoteException var2) {
                Log.e("IPC服务异常:", var2.toString());
            }
    
        }
    
        public interface RemoteFunction<V> {
            V call() throws RemoteException;
        }
    
        public interface RemoteVoidFunction {
            void call() throws RemoteException;
        }
    }
    
    

    消息更新的接口

    package com.wu.ipc.listener;
    
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途:消息更新的接口
     */
    
    
    public interface ShareDataListener {
        void notifyShareData(int id, String content);
    }
    

    服务连接状态的接口

    package com.wu.ipc.base;
    
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途: 服务连接状态的接口
     */
    
    
    public interface ShareDataServiceStateListener {
        void onServiceConnected();
    
        void onServiceDisconnected();
    
        void onUnbindService();
    
        void onBinderDied();
    }
    

    基类接口

    package com.wu.ipc.base;
    
    import com.wu.ipc.listener.ShareDataListener;
    
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途: 基类接口
     */
    
    
    public interface SdkInterface {
        void sendShareData(int key, String values);
    
        String getShareData(int key);
    
        void registerCallback(int id, ShareDataListener callback);
    
        void unregisterCallback(ShareDataListener callback);
    }
    

    2.生成SDK

    apply plugin: 'com.android.library'
    
    android {
        compileSdkVersion 30
        buildToolsVersion "30.0.3"
    
        defaultConfig {
            minSdkVersion 19
            targetSdkVersion 30
            versionCode 1
            versionName "1.0"
    
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    
      // 配置任务
        buildFeatures {
            aidl true
        }
    
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
        implementation 'androidx.appcompat:appcompat:1.1.0'
    
    }
    
    // makeJar
    def zipFile = file('build/intermediates/aar_main_jar/release/classes.jar')
    task makeJar(type: Jar) {
        from zipTree(zipFile)
        archiveBaseName =  "IpcSdk"
        destinationDirectory = file("build/outputs/")
        manifest {
            attributes(
                    'Implementation-Title': "${project.name}",
                    'Built-Date': new Date().getDateTimeString(),
                    'Built-With':
                            "gradle-${project.getGradle().getGradleVersion()},groovy-${GroovySystem.getVersion()}",
                    'Created-By':
                            'Java ' + System.getProperty('java.version') + ' (' + System.getProperty('java.vendor') + ')')
        }
    }
    makeJar.dependsOn(build)
    
    

    3. 服务端调用

    3.1 引用生成的 IpcSdk.jar

    3.2 创建服务

    创建 ShareDataBinder

    package com.wu.ipcservice;
    
    import android.os.RemoteException;
    
    import com.wu.ipc.IShareDataInterface;
    import com.wu.ipc.IShareDataListener;
    
    import java.util.HashMap;
    
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途:
     */
    
    
    public class ShareDataBinder extends IShareDataInterface.Stub {
    
        IShareDataListener mCallBack;
    
        HashMap<Integer,String> mCacheMap= new HashMap<>();
    
        @Override
        public void sendShareData(int key, String values) {
            if (mCallBack!=null){
                try {
                    mCallBack.notifyShareData(key,values);
                    mCacheMap.put(key,values);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        @Override
        public String getShareData(int key)  {
            try {
                String content= mCacheMap.get(key);
                return content;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        public void registerCallback(int id, IShareDataListener callback) {
            mCallBack=callback;
        }
    
        @Override
        public void unregisterCallback(IShareDataListener callback) {
    
        }
    }
    
    

    创建ShareDataService.java 服务类

    package com.wu.ipcservice;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    
    import androidx.annotation.Nullable;
    
    /**
     * 作者:吴奎庆
     * <p>
     * 时间:2023/7/30
     * <p>
     * 用途:
     */
    
    
    public class ShareDataService  extends Service {
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return new ShareDataBinder();
        }
    }
    
    

    配置服务

    <service
                android:name=".ShareDataService"
                android:process=":ipc_service"
                android:exported="true" >
                <intent-filter>
                    <action android:name="com.wu.ipc.service" />
                </intent-filter>
            </service>
    

    4. 客户端调用

    4.1 引用生成的 IpcSdk.jar

    4.2 调用Sdk方法发送接收消息

    package com.wu.ipcsdk;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.util.Log;
    
    import com.wu.ipc.IpcSdk;
    import com.wu.ipc.listener.ShareDataListener;
    
    public class MainActivity extends AppCompatActivity implements ShareDataListener {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
    
        private void initView() {
            IpcSdk.getInstance().init(IpcSdkConstant.PKG,IpcSdkConstant.CLASS_NAME,IpcSdkConstant.ACTION,2000);
            findViewById(R.id.bt_connected).setOnClickListener(v -> {
                IpcSdk.getInstance().registerCallback(10086, this);
            });
    
            findViewById(R.id.bt_send).setOnClickListener(v -> {
                IpcSdk.getInstance().sendShareData(10086, "ClientA 消息");
            });
            findViewById(R.id.bt_get).setOnClickListener(v -> {
              String content= IpcSdk.getInstance().getShareData(10086);
                Log.e("IPCClientA:", " 获取Content:" + content);
            });
            findViewById(R.id.bt_un_register).setOnClickListener(v -> {
                IpcSdk.getInstance().unregisterCallback(this);
            });
        }
    
        @Override
        public void notifyShareData(int id, String content) {
            Log.e("IPCClientA:", "ID:" + id + " Content:" + content);
        }
    }
    
    
    客户端调用.png

    总结

    将AIDL 和服务连接的管理封装到Sdk中方便多个进程调用,主进程只需要启动一个服务,其他的支线进程引用Jar 关联服务就可以了

    源码

    服务源码

    Sdk源码

    相关文章

      网友评论

          本文标题:AndroidIPC跨进程通讯AIDL封装(三)

          本文链接:https://www.haomeiwen.com/subject/qscjpdtx.html