AIDL 实现了进程间的通讯,但是每个进程都需要复制AIDL文件以及封装对象,这样用起来很麻烦所以就想办法把通讯的过程封装成jar包 方便其他进程调用
思路
- 封装调用Sdk(服务连接管理,AIDL,监听,消息发送,消息接收)
- SDK 生成Jar
- 服务端引用Jar 通过jar中的AIDL文件创建服务
- 客户端引用jar 传入服务端的包名,类名,Action 然后调用Jar中的方法开启服务
- 服务端调用Jar中方法和服务端通讯
1. 创建SDK
sdk目录.png1.创建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 关联服务就可以了
网友评论