最近有个需求,在一个定制设备上,我们的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); } }