最近有个需求,在一个定制设备上,我们的app需要跟厂商的一个app进行通信,在一方挂了的情况下,可以相互拉起。
需求很简单,实现的方案也要很多种。我第一想到是通过aidl 进行通信,监听是否终止连接,具体实现例子如下。
1 AIDL 通信
因为双方需要互拉,所以两个app 即属于客户端,又可以称为服务端,aidl的文件路径要保证一致,直接整个文件夹复制就可以了。
public class LocalService extends Service {
SreenAidlInterface sreenAidlInterface;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return stub;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent mIntent=new Intent();
mIntent.setAction("com.example.remoteservice.LocalService");
mIntent.setPackage("com.example.remoteservice");
bindService(mIntent,serviceConnection,BIND_AUTO_CREATE);
startService(mIntent);
return START_STICKY;
}
private Binder stub=new SreenAidlInterface.Stub() {
@Override
public String getServiceName() throws RemoteException {
return "guardservice欢迎你";
}
};
private ServiceConnection serviceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
sreenAidlInterface = SreenAidlInterface.Stub.asInterface(service);
try {
Log.i("LocalService", "connected with " + sreenAidlInterface.getServiceName());
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(LocalService.this,"链接断开,重新启动 RemoteService app",Toast.LENGTH_LONG).show();
Log.d("LocalService","链接断开,重新启动 RemoteService app");
PackageManager packageManager = getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage("com.example.remoteservice");
startActivity(intent);
}
};
}
然后另一个app上的service 操作一致。上面是demo写的比较简单,并没有进行app是否安装,进程是否在运行进行判断。
2 广播通信
这种方案更简单,对接的成本也更低。
广播接收器中如果另外一个app的广播后,过3秒后进行广播的答复并且修改一个全局变量的值,然后另外一个app收到答复后再次进行反馈,然后一直保持这个过程,则表示进行了连接。
if (intent.getAction().equals("com.example.connectdemo.MY_BROADCAST")) {
MyApplication.connectTIme=System.currentTimeMillis();
if(mObservable==null){
mObservable=Observable.timer(3, TimeUnit.SECONDS).subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
context.sendBroadcast(new Intent("com.arcvideo.arcscreen.MY_BROADCAST"));
}
});
}
}
通过一个轮询去检查app一个变量是否被修改,如果5秒没有被修改,判断为断线,重启另外一个app.
private void setConnect() {
sendBroadcast(new Intent("com.example.demo.MY_BROADCAST"));
Observable.interval(10, 5, TimeUnit.SECONDS).subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
if (oldTime == MyApplication.connectTIme) {
//断开了连接
Log.d(TAG, "setConnect 不正常" + "oldTime:" + oldTime + " connectTIme:" + MyApplication.connectTIme);
try {
RestartAppUtil.restartApp(MainActivity.this, "com.example.connectdemo");
} catch (Exception e) {
Log.d(TAG, "Exception:" + e.getMessage());
}
} else {
//连接正常
Log.d(TAG, "setConnect 正常" + "oldTime:" + oldTime + " connectTIme:" + MyApplication.connectTIme);
}
oldTime = MyApplication.connectTIme;
}
});
}
下面是一个启动另外一个应用的工具类,补充了上文说到一些基本的判断。
public class RestartAppUtil {
private static final String TAG="RestartAppUtil";
public static void restartApp(Context context, String packageName){
if(isApkInstalled(context,packageName)&&!isAppRunning(context,packageName)){
startApp(context,packageName);
Log.d(TAG,"restartApp true");
}else{
Log.d(TAG,"restartApp false");
}
}
//判断应用是否安装
public static boolean isApkInstalled(Context context, String packageName) {
if (TextUtils.isEmpty(packageName)) {
Log.d(TAG,"isApkInstalled false");
return false;
}
try {
ApplicationInfo info = context.getPackageManager().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
Log.d(TAG,"isApkInstalled true");
return true;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
Log.d(TAG,"isApkInstalled false");
return false;
}
}
//判断应用是否运行
public static boolean isAppRunning(Context context,String packageName) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> list = null;
if (activityManager != null) {
list = activityManager.getRunningTasks(100);
}
if (list == null || list.size() <= 0) {
Log.d(TAG,"isAppRunning false");
return false;
}
for (ActivityManager.RunningTaskInfo info : list) {
if (info.baseActivity.getPackageName().equals(packageName)) {
Log.d(TAG,"isAppRunning true");
return true;
}
}
Log.d(TAG,"isAppRunning false");
return false;
}
//启动应用
public static void startApp(Context context,String packageName){
PackageManager packageManager = context.getPackageManager();
Intent intent = packageManager.getLaunchIntentForPackage(packageName);
context.startActivity(intent);
}
}